diff --git a/src/PowerEditor/src/MISC/Exception/MiniDumper.cpp b/src/PowerEditor/src/MISC/Exception/MiniDumper.cpp index f073d76..b9e12f3 100644 --- a/src/PowerEditor/src/MISC/Exception/MiniDumper.cpp +++ b/src/PowerEditor/src/MISC/Exception/MiniDumper.cpp @@ -16,31 +16,31 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see . - +//该cpp文件实现了处理崩溃的类MiniDumper.h #include #include "MiniDumper.h" - +//消息标题 LPCTSTR msgTitle = TEXT("Notepad++ crash analysis"); MiniDumper::MiniDumper() { } - -bool MiniDumper::writeDump(EXCEPTION_POINTERS * pExceptionInfo) +//写入崩溃转储的函数 +bool MiniDumper::writeDump(EXCEPTION_POINTERS* pExceptionInfo) { TCHAR szDumpPath[MAX_PATH]; TCHAR szScratch[MAX_PATH]; LPCTSTR szResult = NULL; bool retval = false; - + //加载动态链接库 HMODULE hDll = ::LoadLibraryEx(TEXT("DBGHELP.DLL"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); //that wont work on older windows version than XP, #care :) if (hDll) { - MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" ); + MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump"); if (pDump) - { + {//获取当前模块的文件路径 ::GetModuleFileName(NULL, szDumpPath, MAX_PATH); ::PathRemoveFileSpec(szDumpPath); wcscat_s(szDumpPath, TEXT("\\NppDump.dmp")); @@ -50,10 +50,10 @@ bool MiniDumper::writeDump(EXCEPTION_POINTERS * pExceptionInfo) if (msgret == IDYES) { // create the file - HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL ); + HANDLE hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile!=INVALID_HANDLE_VALUE) + if (hFile != INVALID_HANDLE_VALUE) { _MINIDUMP_EXCEPTION_INFORMATION ExInfo{}; @@ -62,23 +62,23 @@ bool MiniDumper::writeDump(EXCEPTION_POINTERS * pExceptionInfo) ExInfo.ClientPointers = FALSE; // write the dump - BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL ); + BOOL bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL); if (bOK) { - wsprintf( szScratch, TEXT("Saved dump file to '%s'"), szDumpPath ); + wsprintf(szScratch, TEXT("Saved dump file to '%s'"), szDumpPath); szResult = szScratch; retval = true; } else { - wsprintf( szScratch, TEXT("Failed to save dump file to '%s' (error %d)"), szDumpPath, GetLastError() ); + wsprintf(szScratch, TEXT("Failed to save dump file to '%s' (error %d)"), szDumpPath, GetLastError()); szResult = szScratch; } ::CloseHandle(hFile); } else { - wsprintf( szScratch, TEXT("Failed to create dump file '%s' (error %d)"), szDumpPath, GetLastError() ); + wsprintf(szScratch, TEXT("Failed to create dump file '%s' (error %d)"), szDumpPath, GetLastError()); szResult = szScratch; } } @@ -93,7 +93,7 @@ bool MiniDumper::writeDump(EXCEPTION_POINTERS * pExceptionInfo) { szResult = TEXT("Unable to load the debugging DLL,\r\nfind a recent copy of dbghelp.dll and install it."); } - + //弹出消息框显示结果 if (szResult) ::MessageBox(NULL, szResult, msgTitle, MB_OK); diff --git a/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp b/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp index 5fbc09e..90bd41e 100644 --- a/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp +++ b/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp @@ -25,14 +25,14 @@ bool DocTabView::_hideTabBarStatus = false; - +//向标签视图添加新的缓冲区,首先检查缓冲区是否有效(不是无效的缓冲区),然后检查是否已经存在相同的缓冲区。如果缓冲区有效且尚未存在,则将其添加到标签页视图中,并更新父窗口的大小。 void DocTabView::addBuffer(BufferID buffer) { if (buffer == BUFFER_INVALID) //valid only return; if (getIndexByBuffer(buffer) != -1) //no duplicates return; - Buffer * buf = MainFileManager.getBufferByID(buffer); + Buffer* buf = MainFileManager.getBufferByID(buffer); TCITEM tie{}; tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; @@ -40,7 +40,7 @@ void DocTabView::addBuffer(BufferID buffer) if (_hasImgLst) index = 0; tie.iImage = index; - tie.pszText = const_cast(buf->getFileName()); + tie.pszText = const_cast(buf->getFileName()); tie.lParam = reinterpret_cast(buffer); ::SendMessage(_hSelf, TCM_INSERTITEM, _nbItem++, reinterpret_cast(&tie)); bufferUpdated(buf, BufferChangeMask); @@ -48,25 +48,25 @@ void DocTabView::addBuffer(BufferID buffer) ::SendMessage(_hParent, WM_SIZE, 0, 0); } - +//关闭指定的缓冲区,到要关闭的缓冲区的索引,然后从标签页视图中删除它,并通知父窗口进行调整。 void DocTabView::closeBuffer(BufferID buffer) { int indexToClose = getIndexByBuffer(buffer); deletItemAt((size_t)indexToClose); ::SendMessage(_hParent, WM_SIZE, 0, 0); } - +//为特定的标签设置颜色。根据提供的缓冲区ID,设置该缓冲区在标签页中的颜色。 void DocTabView::setIndividualTabColour(BufferID bufferId, int colorId) { bufferId->setDocColorId(colorId); } - +//获取特定标签的颜色,根据提供的标签索引,返回该标签的颜色。 int DocTabView::getIndividualTabColour(int tabIndex) { BufferID bufferId = getBufferByIndex(tabIndex); return bufferId->getDocColorId(); } - +//激活特定的缓冲区,通过缓冲区的ID找到其索引位置并尝试激活该缓冲区,如果成功则返回true,否则返回false。 bool DocTabView::activateBuffer(BufferID buffer) { int indexToActivate = getIndexByBuffer(buffer); @@ -77,15 +77,15 @@ bool DocTabView::activateBuffer(BufferID buffer) return true; } - +//获取当前激活的缓冲区。 BufferID DocTabView::activeBuffer() { int index = getCurrentTabIndex(); return getBufferByIndex(index); } - -BufferID DocTabView::findBufferByName(const TCHAR * fullfilename) //-1 if not found, something else otherwise +//遍历所有标签页,根据文件名查找匹配的缓冲区,找到则返回其ID,否则返回BUFFER_INVALID。 +BufferID DocTabView::findBufferByName(const TCHAR* fullfilename) //-1 if not found, something else otherwise { TCITEM tie{}; tie.lParam = -1; @@ -94,7 +94,7 @@ BufferID DocTabView::findBufferByName(const TCHAR * fullfilename) //-1 if not fo { ::SendMessage(_hSelf, TCM_GETITEM, i, reinterpret_cast(&tie)); BufferID id = reinterpret_cast(tie.lParam); - Buffer * buf = MainFileManager.getBufferByID(id); + Buffer* buf = MainFileManager.getBufferByID(id); if (OrdinalIgnoreCaseCompareStrings(fullfilename, buf->getFullPathName()) == 0) { return id; @@ -103,7 +103,7 @@ BufferID DocTabView::findBufferByName(const TCHAR * fullfilename) //-1 if not fo return BUFFER_INVALID; } - +//通过缓冲区ID找到其在标签中的索引位置,如果不存在则返回 - 1。 int DocTabView::getIndexByBuffer(BufferID id) { TCITEM tie{}; @@ -118,7 +118,7 @@ int DocTabView::getIndexByBuffer(BufferID id) return -1; } - +//通过缓冲区ID找到其在标签中的索引位置,如果不存在则返回-1。 BufferID DocTabView::getBufferByIndex(size_t index) { TCITEM tie{}; @@ -129,8 +129,8 @@ BufferID DocTabView::getBufferByIndex(size_t index) return reinterpret_cast(tie.lParam); } - -void DocTabView::bufferUpdated(Buffer * buffer, int mask) +//根据mask中的标志位,更新与缓冲区相关的信息,例如文件名变化、只读状态变化等。 +void DocTabView::bufferUpdated(Buffer* buffer, int mask) { int index = getIndexByBuffer(buffer->getID()); if (index == -1) @@ -143,7 +143,7 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask) if (mask & BufferChangeReadonly || mask & BufferChangeDirty) { tie.mask |= TCIF_IMAGE; - tie.iImage = buffer->isDirty()?UNSAVED_IMG_INDEX:SAVED_IMG_INDEX; + tie.iImage = buffer->isDirty() ? UNSAVED_IMG_INDEX : SAVED_IMG_INDEX; if (buffer->isMonitoringOn()) { tie.iImage = MONITORING_IMG_INDEX; @@ -171,15 +171,15 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask) //Tab's caption must be encoded like this because otherwise tab control would make tab too small or too big for the text. while (*in != 0) - if (*in == '&') - { - *out++ = '&'; - *out++ = '&'; - while (*(++in) == '&') + if (*in == '&') + { *out++ = '&'; - } - else - *out++ = *in++; + *out++ = '&'; + while (*(++in) == '&') + *out++ = '&'; + } + else + *out++ = *in++; *out = '\0'; } } @@ -192,7 +192,7 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask) ::SendMessage(_hParent, WM_SIZE, 0, 0); } - +//根据给定的索引设置相应的缓冲区ID,并更新标签显示的相关信息。 void DocTabView::setBuffer(size_t index, BufferID id) { if (index >= _nbItem) @@ -208,8 +208,8 @@ void DocTabView::setBuffer(size_t index, BufferID id) ::SendMessage(_hParent, WM_SIZE, 0, 0); } - -void DocTabView::reSizeTo(RECT & rc) +//根据隐藏/显示标签栏状态,调整标签页视图和文本编辑器视图的大小,并根据需要发送消息以更新可点击链接。 +void DocTabView::reSizeTo(RECT& rc) { int borderWidth = ((NppParameters::getInstance()).getSVP())._borderWidth; if (_hideTabBarStatus) @@ -221,9 +221,9 @@ void DocTabView::reSizeTo(RECT & rc) else { TabBar::reSizeTo(rc); - rc.left += borderWidth; + rc.left += borderWidth; rc.right -= borderWidth * 2; - rc.top += borderWidth; + rc.top += borderWidth; rc.bottom -= (borderWidth * 2); _pView->reSizeTo(rc); } diff --git a/src/PowerEditor/src/ScintillaComponent/DocTabView.h b/src/PowerEditor/src/ScintillaComponent/DocTabView.h index 2f8f78c..3c700fd 100644 --- a/src/PowerEditor/src/ScintillaComponent/DocTabView.h +++ b/src/PowerEditor/src/ScintillaComponent/DocTabView.h @@ -14,11 +14,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . + + + +//该类继承自TabBarPlus类。该类负责管理文档选项卡视图,并提供一系列方法用于添加、关闭、激活缓冲区以及设置选项卡的个性化选项等功能。 #pragma once #include "TabBar.h" #include "Buffer.h" - +// 定义一些常量用作图片索引 const int SAVED_IMG_INDEX = 0; const int UNSAVED_IMG_INDEX = 1; const int REDONLY_IMG_INDEX = 2; @@ -26,15 +30,15 @@ const int MONITORING_IMG_INDEX = 3; class DocTabView : public TabBarPlus { -public : - DocTabView():TabBarPlus(), _pView(NULL) {}; - virtual ~DocTabView(){}; - +public: + DocTabView() :TabBarPlus(), _pView(NULL) {}; + virtual ~DocTabView() {}; + void destroy() override { TabBarPlus::destroy(); }; - - void init(HINSTANCE hInst, HWND parent, ScintillaEditView * pView, std::vector pIconListVector, unsigned char indexChoice) { + //初始化函数,传入实例句柄、父窗口句柄、ScintillaEditView指针、以及图片列表和选择的图片索引 + void init(HINSTANCE hInst, HWND parent, ScintillaEditView* pView, std::vector pIconListVector, unsigned char indexChoice) { TabBarPlus::init(hInst, parent); _pView = pView; @@ -52,51 +56,56 @@ public : TabBar::setImageList(_pIconListVector[_iconListIndexChoice]->getHandle()); return; }; - + // 改变选中的图片列表 void changeIcons(unsigned char choice) { if (choice >= _pIconListVector.size()) return; _iconListIndexChoice = choice; TabBar::setImageList(_pIconListVector[_iconListIndexChoice]->getHandle()); }; - + // 添加缓冲区 void addBuffer(BufferID buffer); + // 关闭缓冲区 void closeBuffer(BufferID buffer); - void bufferUpdated(Buffer * buffer, int mask); - + // 缓冲区更新 + void bufferUpdated(Buffer* buffer, int mask); + // 激活缓冲区 bool activateBuffer(BufferID buffer); - + // 获取当前激活的缓冲区 BufferID activeBuffer(); - BufferID findBufferByName(const TCHAR * fullfilename); //-1 if not found, something else otherwise - + // 根据文件名查找缓冲区,返回索引值,如果未找到则返回-1 + BufferID findBufferByName(const TCHAR* fullfilename); //-1 if not found, something else otherwise + // 根据缓冲区获取索引值 int getIndexByBuffer(BufferID id); + // 根据索引值获取缓冲区 BufferID getBufferByIndex(size_t index); - + // 设置指定索引位置的缓冲区 void setBuffer(size_t index, BufferID id); - + // 静态函数,用于设置隐藏或显示选项卡栏的状态 static bool setHideTabBarStatus(bool hideOrNot) { bool temp = _hideTabBarStatus; _hideTabBarStatus = hideOrNot; return temp; }; - + // 静态函数,获取隐藏或显示选项卡栏的状态 static bool getHideTabBarStatus() { return _hideTabBarStatus; }; - - void reSizeTo(RECT & rc) override; - + // 重写父类的reSizeTo方法 + void reSizeTo(RECT& rc) override; + // 获取ScintillaEditView指针 const ScintillaEditView* getScintillaEditView() const { return _pView; }; - + // 设置指定缓冲区的个性化选项卡颜色 void setIndividualTabColour(BufferID bufferId, int colorId); + // 获取指定索引位置的个性化选项卡颜色 int getIndividualTabColour(int tabIndex) override; -private : - ScintillaEditView *_pView = nullptr; +private: + ScintillaEditView* _pView = nullptr; static bool _hideTabBarStatus; - std::vector _pIconListVector; + std::vector _pIconListVector; int _iconListIndexChoice = -1; }; diff --git a/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp b/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp index 578a0c0..f19fe8f 100644 --- a/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp +++ b/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see . - +//处理工具栏按钮 #include #include "TabBar.h" #include "Parameters.h" @@ -38,36 +38,36 @@ COLORREF TabBarPlus::_activeTopBarUnfocusedColour = RGB(250, 210, 150); COLORREF TabBarPlus::_inactiveTextColour = grey; COLORREF TabBarPlus::_inactiveBgColour = RGB(192, 192, 192); -HWND TabBarPlus::_hwndArray[nbCtrlMax] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +HWND TabBarPlus::_hwndArray[nbCtrlMax] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int TabBarPlus::_nbCtrl = 0; - +//初始化标签栏,创建窗口 void TabBar::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMultiLine) { Window::init(hInst, parent); - int vertical = isVertical?(TCS_VERTICAL | TCS_MULTILINE | TCS_RIGHTJUSTIFY):0; + int vertical = isVertical ? (TCS_VERTICAL | TCS_MULTILINE | TCS_RIGHTJUSTIFY) : 0; _isVertical = isVertical; _isMultiLine = isMultiLine; - INITCOMMONCONTROLSEX icce{}; + INITCOMMONCONTROLSEX icce{};//初始化通用控件库 icce.dwSize = sizeof(icce); icce.dwICC = ICC_TAB_CLASSES; InitCommonControlsEx(&icce); int multiLine = isMultiLine ? TCS_MULTILINE : 0; - int style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE |\ + int style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE | \ TCS_FOCUSNEVER | TCS_TABS | WS_TABSTOP | vertical | multiLine; _hSelf = ::CreateWindowEx( - 0, - WC_TABCONTROL, - TEXT("Tab"), - style, - 0, 0, 0, 0, - _hParent, - NULL, - _hInst, - 0); + 0, + WC_TABCONTROL, + TEXT("Tab"), + style, + 0, 0, 0, 0, + _hParent, + NULL, + _hInst, + 0); if (!_hSelf) { @@ -75,27 +75,27 @@ void TabBar::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMultiLin } } - +//清理与TabBar相关的资源 void TabBar::destroy() { if (_hFont) { ::DeleteObject(_hFont); _hFont = nullptr; - } + }//删除字体对象 if (_hLargeFont) { ::DeleteObject(_hLargeFont); _hLargeFont = nullptr; - } + }//删除字体大小格式 if (_hVerticalFont) { ::DeleteObject(_hVerticalFont); _hVerticalFont = nullptr; } - + //删除垂直字体对象 if (_hVerticalLargeFont) { ::DeleteObject(_hVerticalLargeFont); @@ -106,48 +106,48 @@ void TabBar::destroy() _hSelf = nullptr; } - -int TabBar::insertAtEnd(const TCHAR *subTabName) +//在TabBar末尾插入一个新的选项卡,并设置名称。使用TCITEM结构设置选项卡的属性,并发送消息将选项卡插入TabBar中 +int TabBar::insertAtEnd(const TCHAR* subTabName) { TCITEM tie{}; tie.mask = TCIF_TEXT | TCIF_IMAGE; int index = -1; - + //如果存在图像列表,那么新TabItem应该被放置在列表的开始。 if (_hasImgLst) index = 0; tie.iImage = index; - tie.pszText = (TCHAR *)subTabName; + tie.pszText = (TCHAR*)subTabName; return int(::SendMessage(_hSelf, TCM_INSERTITEM, _nbItem++, reinterpret_cast(&tie))); } - -void TabBar::getCurrentTitle(TCHAR *title, int titleLen) +//获取当前选定选项卡的标题。 +void TabBar::getCurrentTitle(TCHAR* title, int titleLen) { TCITEM tci{}; tci.mask = TCIF_TEXT; tci.pszText = title; - tci.cchTextMax = titleLen-1; + tci.cchTextMax = titleLen - 1; ::SendMessage(_hSelf, TCM_GETITEM, getCurrentTabIndex(), reinterpret_cast(&tci)); } - -void TabBar::setFont(const TCHAR *fontName, int fontSize) +//为TabBar中的选项卡设置字体。根据提供的参数创建新字体,并发送消息为TabBar设置该字体 +void TabBar::setFont(const TCHAR* fontName, int fontSize) { if (_hFont) ::DeleteObject(_hFont); - _hFont = ::CreateFont( fontSize, 0, - (_isVertical) ? 900:0, - (_isVertical) ? 900:0, - FW_NORMAL, - 0, 0, 0, 0, - 0, 0, 0, 0, - fontName); + _hFont = ::CreateFont(fontSize, 0, + (_isVertical) ? 900 : 0, + (_isVertical) ? 900 : 0, + FW_NORMAL, + 0, 0, 0, 0, + 0, 0, 0, 0, + fontName); if (_hFont) ::SendMessage(_hSelf, WM_SETFONT, reinterpret_cast(_hFont), 0); } - +//激活指定索引处的选项卡。发送消息以确保在TabBar中激活指定索引处的选项卡。 void TabBar::activateAt(int index) const { if (getCurrentTabIndex() != index) @@ -163,14 +163,14 @@ void TabBar::activateAt(int index) const } } - +//删除指定索引处的选项卡 void TabBar::deletItemAt(size_t index) { if (index == _nbItem - 1) { //prevent invisible tabs. If last visible tab is removed, other tabs are put in view but not redrawn //Therefore, scroll one tab to the left if only one tab visible - if (_nbItem > 1) + if (_nbItem > 1)//至少两个 { RECT itemRect{}; ::SendMessage(_hSelf, TCM_GETITEMRECT, index, reinterpret_cast(&itemRect)); @@ -182,7 +182,7 @@ void TabBar::deletItemAt(size_t index) //There seems to be no negative effect on any internal state of the tab control or the up/down control int wParam = MAKEWPARAM(SB_THUMBPOSITION, index - 1); ::SendMessage(_hSelf, WM_HSCROLL, wParam, 0); - + //TabBar控件向左滚动一个Tab项的位置。 wParam = MAKEWPARAM(SB_ENDSCROLL, index - 1); ::SendMessage(_hSelf, WM_HSCROLL, wParam, 0); } @@ -192,15 +192,15 @@ void TabBar::deletItemAt(size_t index) _nbItem--; } - +//设置TabBar中的图像列表。使用TCM_SETIMAGELIST消息来设置图像列表。 void TabBar::setImageList(HIMAGELIST himl) { _hasImgLst = true; ::SendMessage(_hSelf, TCM_SETIMAGELIST, 0, reinterpret_cast(himl)); } - -void TabBar::reSizeTo(RECT & rc2Ajust) +//调整TabBar的大小以适应给定的矩形区域。调整TabBar的显示方式并计算新的大小,然后调整提供的矩形区域。 +void TabBar::reSizeTo(RECT& rc2Ajust) { RECT rowRect{}; int rowCount = 0, tabsHight = 0; @@ -208,6 +208,7 @@ void TabBar::reSizeTo(RECT & rc2Ajust) // Important to do that! // Otherwise, the window(s) it contains will take all the resouce of CPU // We don't need to resize the contained windows if they are even invisible anyway + //调用display方法,根据调整矩形的右边界是否大于10来决定是否显示TabBar中的窗口 display(rc2Ajust.right > 10); RECT rc = rc2Ajust; Window::reSizeTo(rc); @@ -226,7 +227,7 @@ void TabBar::reSizeTo(RECT & rc2Ajust) if (rowCount == 1) { style &= ~TCS_BUTTONS; - } + }// 如果有多行Tab项(至少两行),则启用TabCtrl的按钮样式,并计算间距的值 else // (rowCount >= 2) { style |= TCS_BUTTONS; @@ -249,19 +250,23 @@ void TabBar::reSizeTo(RECT & rc2Ajust) } } - +//销毁TabBarPlus及其资源。 void TabBarPlus::destroy() { TabBar::destroy(); ::DestroyWindow(_tooltips); _tooltips = NULL; } - - +/* +初始化TabBarPlus。 +创建TabControl和工具提示窗口,并确保它们已成功创建。 +设置所需的样式,并根据参数创建相应的字体。 +将TabBarPlus添加到控件数组中,以便跟踪。 +*/ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMultiLine) { Window::init(hInst, parent); - int vertical = isVertical?(TCS_VERTICAL | TCS_MULTILINE | TCS_RIGHTJUSTIFY):0; + int vertical = isVertical ? (TCS_VERTICAL | TCS_MULTILINE | TCS_RIGHTJUSTIFY) : 0; _isVertical = isVertical; _isMultiLine = isMultiLine; @@ -276,21 +281,21 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult style |= TCS_OWNERDRAWFIXED; _hSelf = ::CreateWindowEx( - 0, - WC_TABCONTROL, - TEXT("Tab"), - style, - 0, 0, 0, 0, - _hParent, - NULL, - _hInst, - 0); + 0, + WC_TABCONTROL, + TEXT("Tab"), + style, + 0, 0, 0, 0, + _hParent, + NULL, + _hInst, + 0); if (!_hSelf) { throw std::runtime_error("TabBarPlus::init : CreateWindowEx() function return null"); } - + //工具提示 _tooltips = ::CreateWindowEx( 0, TOOLTIPS_CLASS, @@ -306,7 +311,7 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult { throw std::runtime_error("TabBarPlus::init : tooltip CreateWindowEx() function return null"); } - + //暗色主题 NppDarkMode::setDarkTooltips(_tooltips, NppDarkMode::ToolTipsType::tooltip); ::SendMessage(_hSelf, TCM_SETTOOLTIPS, reinterpret_cast(_tooltips), 0); @@ -317,12 +322,13 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult _ctrlID = _nbCtrl; } else - { + {//查找第一个为空的位置,并设置_ctrlID为该位置的值 int i = 0; bool found = false; - for ( ; i < nbCtrlMax && !found ; ++i) + for (; i < nbCtrlMax && !found; ++i) if (!_hwndArray[i]) found = true; + //满了未找到,销毁 if (!found) { _ctrlID = -1; @@ -354,15 +360,16 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult _hVerticalLargeFont = CreateFontIndirect(&lfVer); } - +//处理选项卡控件的自定义填充。 void TabBarPlus::doOwnerDrawTab() { ::SendMessage(_hwndArray[0], TCM_SETPADDING, 0, MAKELPARAM(6, 0)); - for (int i = 0 ; i < _nbCtrl ; ++i) + for (int i = 0; i < _nbCtrl; ++i) { if (_hwndArray[i]) { LONG_PTR style = ::GetWindowLongPtr(_hwndArray[i], GWL_STYLE); + //检查是否需要自定义 if (isOwnerDrawTab()) style |= TCS_OWNERDRAWFIXED; else @@ -378,52 +385,52 @@ void TabBarPlus::doOwnerDrawTab() } } - +//根据给定的索引为选项卡栏设置不同的颜色(如活动文本颜色、背景颜色等)。在更新颜色之后,它调用doOwnerDrawTab()来刷新显示。 void TabBarPlus::setColour(COLORREF colour2Set, tabColourIndex i) { switch (i) { - case activeText: - _activeTextColour = colour2Set; - break; - case activeFocusedTop: - _activeTopBarFocusedColour = colour2Set; - break; - case activeUnfocusedTop: - _activeTopBarUnfocusedColour = colour2Set; - break; - case inactiveText: - _inactiveTextColour = colour2Set; - break; - case inactiveBg : - _inactiveBgColour = colour2Set; - break; - default : - return; + case activeText: + _activeTextColour = colour2Set; + break; + case activeFocusedTop: + _activeTopBarFocusedColour = colour2Set; + break; + case activeUnfocusedTop: + _activeTopBarUnfocusedColour = colour2Set; + break; + case inactiveText: + _inactiveTextColour = colour2Set; + break; + case inactiveBg: + _inactiveBgColour = colour2Set; + break; + default: + return; } doOwnerDrawTab(); } - +//设置垂直选项卡 void TabBarPlus::doVertical() { - for (int i = 0 ; i < _nbCtrl ; ++i) + for (int i = 0; i < _nbCtrl; ++i) { if (_hwndArray[i]) SendMessage(_hwndArray[i], WM_TABSETSTYLE, isVertical(), TCS_VERTICAL); } } - +//显示多行选项卡 void TabBarPlus::doMultiLine() { - for (int i = 0 ; i < _nbCtrl ; ++i) + for (int i = 0; i < _nbCtrl; ++i) { if (_hwndArray[i]) SendMessage(_hwndArray[i], WM_TABSETSTYLE, isMultiLine(), TCS_MULTILINE); } } - +//向父窗口发送通知消息,其中包含有关选项卡索引和特定通知代码的信息。 void TabBarPlus::notify(int notifyCode, int tabIndex) { TBHDR nmhdr{}; @@ -433,7 +440,7 @@ void TabBarPlus::notify(int notifyCode, int tabIndex) nmhdr._tabOrigin = tabIndex; ::SendMessage(_hParent, WM_NOTIFY, 0, reinterpret_cast(&nmhdr)); } - +//启动对选项卡栏控件上的鼠标事件的跟踪,例如当鼠标进入或离开控件区域时。 void TabBarPlus::trackMouseEvent(DWORD event2check) { TRACKMOUSEEVENT tme = {}; @@ -442,615 +449,616 @@ void TabBarPlus::trackMouseEvent(DWORD event2check) tme.hwndTrack = _hSelf; TrackMouseEvent(&tme); } - +//消息处理,处理窗口消息 LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch (Message) { // Custom window message to change tab control style on the fly - case WM_TABSETSTYLE: - { - LONG_PTR style = ::GetWindowLongPtr(hwnd, GWL_STYLE); + //改变窗口样式 + case WM_TABSETSTYLE: + { + LONG_PTR style = ::GetWindowLongPtr(hwnd, GWL_STYLE); - if (wParam > 0) - style |= lParam; - else - style &= ~lParam; + if (wParam > 0) + style |= lParam; + else + style &= ~lParam; - _isVertical = ((style & TCS_VERTICAL) != 0); - _isMultiLine = ((style & TCS_MULTILINE) != 0); + _isVertical = ((style & TCS_VERTICAL) != 0); + _isMultiLine = ((style & TCS_MULTILINE) != 0); - ::SetWindowLongPtr(hwnd, GWL_STYLE, style); - ::InvalidateRect(hwnd, NULL, TRUE); + ::SetWindowLongPtr(hwnd, GWL_STYLE, style); + ::InvalidateRect(hwnd, NULL, TRUE); + return TRUE; + } + //深色模式 + case NPPM_INTERNAL_REFRESHDARKMODE: + { + NppDarkMode::setDarkTooltips(hwnd, NppDarkMode::ToolTipsType::tabbar); + return TRUE; + } + //鼠标滚轮 + case WM_MOUSEWHEEL: + { + // .............................................................................. + // MOUSEWHEEL: + // will scroll the tab bar area (similar to Firefox's tab scrolling), + // it only happens if not in multi-line mode and at least one tab is hidden + // .............................................................................. + // CTRL + MOUSEWHEEL: + // will do previous/next tab WITH scroll wrapping (endless loop) + // .............................................................................. + // SHIFT + MOUSEWHEEL: + // if _doDragNDrop is enabled, then moves the tab, otherwise switches + // to previous/next tab WITHOUT scroll wrapping (stops at first/last tab) + // .............................................................................. + // CTRL + SHIFT + MOUSEWHEEL: + // will switch to the first/last tab + // .............................................................................. + //是否被拖动,如是,会交换当前鼠标所在位置和目标位置的数据 + if (_isDragging) return TRUE; - } - case NPPM_INTERNAL_REFRESHDARKMODE: + const bool isForward = ((short)HIWORD(wParam)) < 0; // wheel rotation towards the user will be considered as forward direction + const int lastTabIndex = static_cast(::SendMessage(_hSelf, TCM_GETITEMCOUNT, 0, 0) - 1); + + if ((wParam & MK_CONTROL) && (wParam & MK_SHIFT)) { - NppDarkMode::setDarkTooltips(hwnd, NppDarkMode::ToolTipsType::tabbar); - return TRUE; + setActiveTab((isForward ? lastTabIndex : 0)); } - - case WM_MOUSEWHEEL: + else if ((wParam & MK_SHIFT) && _doDragNDrop) { - // .............................................................................. - // MOUSEWHEEL: - // will scroll the tab bar area (similar to Firefox's tab scrolling), - // it only happens if not in multi-line mode and at least one tab is hidden - // .............................................................................. - // CTRL + MOUSEWHEEL: - // will do previous/next tab WITH scroll wrapping (endless loop) - // .............................................................................. - // SHIFT + MOUSEWHEEL: - // if _doDragNDrop is enabled, then moves the tab, otherwise switches - // to previous/next tab WITHOUT scroll wrapping (stops at first/last tab) - // .............................................................................. - // CTRL + SHIFT + MOUSEWHEEL: - // will switch to the first/last tab - // .............................................................................. - - if (_isDragging) - return TRUE; - - const bool isForward = ((short)HIWORD(wParam)) < 0; // wheel rotation towards the user will be considered as forward direction - const int lastTabIndex = static_cast(::SendMessage(_hSelf, TCM_GETITEMCOUNT, 0, 0) - 1); + int oldTabIndex = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)); + int newTabIndex = oldTabIndex + (isForward ? 1 : -1); - if ((wParam & MK_CONTROL) && (wParam & MK_SHIFT)) + if (newTabIndex < 0) { - setActiveTab((isForward ? lastTabIndex : 0)); + newTabIndex = lastTabIndex; // wrap scrolling } - else if ((wParam & MK_SHIFT) && _doDragNDrop) + else if (newTabIndex > lastTabIndex) { - int oldTabIndex = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)); - int newTabIndex = oldTabIndex + (isForward ? 1 : -1); - - if (newTabIndex < 0) - { - newTabIndex = lastTabIndex; // wrap scrolling - } - else if (newTabIndex > lastTabIndex) - { - newTabIndex = 0; // wrap scrolling - } + newTabIndex = 0; // wrap scrolling + } - if (oldTabIndex != newTabIndex) - { - exchangeTabItemData(oldTabIndex, newTabIndex); - } + if (oldTabIndex != newTabIndex) + { + exchangeTabItemData(oldTabIndex, newTabIndex); } - else if (wParam & (MK_CONTROL | MK_SHIFT)) + } + else if (wParam & (MK_CONTROL | MK_SHIFT)) + { + int tabIndex = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0) + (isForward ? 1 : -1)); + if (tabIndex < 0) { - int tabIndex = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0) + (isForward ? 1 : -1)); - if (tabIndex < 0) - { - if (wParam & MK_CONTROL) - tabIndex = lastTabIndex; // wrap scrolling - else - return TRUE; - } - else if (tabIndex > lastTabIndex) - { - if (wParam & MK_CONTROL) - tabIndex = 0; // wrap scrolling - else - return TRUE; - } - setActiveTab(tabIndex); + if (wParam & MK_CONTROL) + tabIndex = lastTabIndex; // wrap scrolling + else + return TRUE; } - else if (!_isMultiLine) // don't scroll if in multi-line mode + else if (tabIndex > lastTabIndex) { - RECT rcTabCtrl{}, rcLastTab{}; - ::SendMessage(_hSelf, TCM_GETITEMRECT, lastTabIndex, reinterpret_cast(&rcLastTab)); - ::GetClientRect(_hSelf, &rcTabCtrl); - - // get index of the first visible tab - TC_HITTESTINFO hti{}; - LONG xy = NppParameters::getInstance()._dpiManager.scaleX(12); // an arbitrary coordinate inside the first visible tab - hti.pt = { xy, xy }; - int scrollTabIndex = static_cast(::SendMessage(_hSelf, TCM_HITTEST, 0, reinterpret_cast(&hti))); - - if (scrollTabIndex < 1 && (_isVertical ? rcLastTab.bottom < rcTabCtrl.bottom : rcLastTab.right < rcTabCtrl.right)) // nothing to scroll + if (wParam & MK_CONTROL) + tabIndex = 0; // wrap scrolling + else return TRUE; + } + setActiveTab(tabIndex); + } + else if (!_isMultiLine) // don't scroll if in multi-line mode + { + RECT rcTabCtrl{}, rcLastTab{}; + ::SendMessage(_hSelf, TCM_GETITEMRECT, lastTabIndex, reinterpret_cast(&rcLastTab)); + ::GetClientRect(_hSelf, &rcTabCtrl); - // maximal width/height of the msctls_updown32 class (arrow box in the tab bar), - // this area may hide parts of the last tab and needs to be excluded - LONG maxLengthUpDownCtrl = NppParameters::getInstance()._dpiManager.scaleX(44); // sufficient static value + // get index of the first visible tab + TC_HITTESTINFO hti{}; + LONG xy = NppParameters::getInstance()._dpiManager.scaleX(12); // an arbitrary coordinate inside the first visible tab + hti.pt = { xy, xy }; + int scrollTabIndex = static_cast(::SendMessage(_hSelf, TCM_HITTEST, 0, reinterpret_cast(&hti))); - // scroll forward as long as the last tab is hidden; scroll backward till the first tab - if ((_isVertical ? ((rcTabCtrl.bottom - rcLastTab.bottom) < maxLengthUpDownCtrl) : ((rcTabCtrl.right - rcLastTab.right) < maxLengthUpDownCtrl)) || !isForward) - { - if (isForward) - ++scrollTabIndex; - else - --scrollTabIndex; + if (scrollTabIndex < 1 && (_isVertical ? rcLastTab.bottom < rcTabCtrl.bottom : rcLastTab.right < rcTabCtrl.right)) // nothing to scroll + return TRUE; - if (scrollTabIndex < 0 || scrollTabIndex > lastTabIndex) - return TRUE; + // maximal width/height of the msctls_updown32 class (arrow box in the tab bar), + // this area may hide parts of the last tab and needs to be excluded + LONG maxLengthUpDownCtrl = NppParameters::getInstance()._dpiManager.scaleX(44); // sufficient static value - // clear hover state of the close button, - // WM_MOUSEMOVE won't handle this properly since the tab position will change - if (_isCloseHover) - { - _isCloseHover = false; - ::InvalidateRect(_hSelf, &_currentHoverTabRect, false); - } + // scroll forward as long as the last tab is hidden; scroll backward till the first tab + if ((_isVertical ? ((rcTabCtrl.bottom - rcLastTab.bottom) < maxLengthUpDownCtrl) : ((rcTabCtrl.right - rcLastTab.right) < maxLengthUpDownCtrl)) || !isForward) + { + if (isForward) + ++scrollTabIndex; + else + --scrollTabIndex; - ::SendMessage(_hSelf, WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, scrollTabIndex), 0); + if (scrollTabIndex < 0 || scrollTabIndex > lastTabIndex) + return TRUE; + + // clear hover state of the close button, + // WM_MOUSEMOVE won't handle this properly since the tab position will change + if (_isCloseHover) + { + _isCloseHover = false; + ::InvalidateRect(_hSelf, &_currentHoverTabRect, false); } + + ::SendMessage(_hSelf, WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, scrollTabIndex), 0); } - return TRUE; } - - case WM_LBUTTONDOWN : + return TRUE; + } + //左键按下 + case WM_LBUTTONDOWN: + { + if (::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS) { - if (::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS) + int nTab = getTabIndexAt(LOWORD(lParam), HIWORD(lParam)); + if (nTab != -1 && nTab != static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0))) { - int nTab = getTabIndexAt(LOWORD(lParam), HIWORD(lParam)); - if (nTab != -1 && nTab != static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0))) - { - setActiveTab(nTab); - } + setActiveTab(nTab); } + } + //是否关闭 + if (_drawTabCloseButton) + { + int xPos = LOWORD(lParam); + int yPos = HIWORD(lParam); - if (_drawTabCloseButton) + if (_closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical)) { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - - if (_closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical)) - { - _whichCloseClickDown = getTabIndexAt(xPos, yPos); - ::SendMessage(_hParent, WM_COMMAND, IDM_VIEW_REFRESHTABAR, 0); - return TRUE; - } - } - - ::CallWindowProc(_tabBarDefaultProc, hwnd, Message, wParam, lParam); - int currentTabOn = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)); - - if (wParam == 2) + _whichCloseClickDown = getTabIndexAt(xPos, yPos); + ::SendMessage(_hParent, WM_COMMAND, IDM_VIEW_REFRESHTABAR, 0); return TRUE; - - if (_doDragNDrop) - { - _mightBeDragging = true; } + } - notify(NM_CLICK, currentTabOn); + ::CallWindowProc(_tabBarDefaultProc, hwnd, Message, wParam, lParam); + int currentTabOn = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)); + if (wParam == 2) return TRUE; + + if (_doDragNDrop) + { + _mightBeDragging = true; } - case WM_RBUTTONDOWN : //rightclick selects tab aswell + notify(NM_CLICK, currentTabOn); + + return TRUE; + } + //右键按下,处理选项 + case WM_RBUTTONDOWN: //rightclick selects tab aswell + { + // TCS_BUTTONS doesn't select the tab + if (::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS) { - // TCS_BUTTONS doesn't select the tab - if (::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS) + int nTab = getTabIndexAt(LOWORD(lParam), HIWORD(lParam)); + if (nTab != -1 && nTab != static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0))) { - int nTab = getTabIndexAt(LOWORD(lParam), HIWORD(lParam)); - if (nTab != -1 && nTab != static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0))) - { - setActiveTab(nTab); - } + setActiveTab(nTab); } - - ::CallWindowProc(_tabBarDefaultProc, hwnd, WM_LBUTTONDOWN, wParam, lParam); - return TRUE; } - case WM_MOUSEMOVE : + ::CallWindowProc(_tabBarDefaultProc, hwnd, WM_LBUTTONDOWN, wParam, lParam); + return TRUE; + } + //鼠标移动 + case WM_MOUSEMOVE: + { + if (_mightBeDragging && !_isDragging) { - if (_mightBeDragging && !_isDragging) + // Grrr! Who has stolen focus and eaten the WM_LBUTTONUP?! + if (GetKeyState(VK_LBUTTON) >= 0) { - // Grrr! Who has stolen focus and eaten the WM_LBUTTONUP?! - if (GetKeyState(VK_LBUTTON) >= 0) - { - _mightBeDragging = false; - _dragCount = 0; - } - else if (++_dragCount > 2) + _mightBeDragging = false; + _dragCount = 0; + } + else if (++_dragCount > 2) + { + int tabSelected = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)); + + if (tabSelected >= 0) { - int tabSelected = static_cast(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)); + _nSrcTab = _nTabDragged = tabSelected; + _isDragging = true; - if (tabSelected >= 0) + // TLS_BUTTONS is already captured on Windows and will break on ::SetCapture + // However, this is not the case for WINE/ReactOS and must ::SetCapture + if (::GetCapture() != _hSelf) { - _nSrcTab = _nTabDragged = tabSelected; - _isDragging = true; - - // TLS_BUTTONS is already captured on Windows and will break on ::SetCapture - // However, this is not the case for WINE/ReactOS and must ::SetCapture - if (::GetCapture() != _hSelf) - { - ::SetCapture(hwnd); - } + ::SetCapture(hwnd); } } } + } - POINT p{}; - p.x = LOWORD(lParam); - p.y = HIWORD(lParam); + POINT p{}; + p.x = LOWORD(lParam); + p.y = HIWORD(lParam); + //是否拖动tag,是,光标移动,tab数据交换,否,判断并进行相关操作 + if (_isDragging) + { + exchangeItemData(p); - if (_isDragging) - { - exchangeItemData(p); + // Get cursor position of "Screen" + // For using the function "WindowFromPoint" afterward!!! + ::GetCursorPos(&_draggingPoint); + draggingCursor(_draggingPoint); + return TRUE; + } + else + { + bool isFromTabToTab = false; - // Get cursor position of "Screen" - // For using the function "WindowFromPoint" afterward!!! - ::GetCursorPos(&_draggingPoint); - draggingCursor(_draggingPoint); - return TRUE; + int iTabNow = getTabIndexAt(p.x, p.y); // _currentHoverTabItem keeps previous value, and it need to be updated + + if (_currentHoverTabItem == iTabNow && _currentHoverTabItem != -1) // mouse moves arround in the same tab + { + // do nothing } - else + else if (iTabNow == -1 && _currentHoverTabItem != -1) // mouse is no more on any tab, set hover -1 { - bool isFromTabToTab = false; + _currentHoverTabItem = -1; - int iTabNow = getTabIndexAt(p.x, p.y); // _currentHoverTabItem keeps previous value, and it need to be updated + // send mouse leave notif + notify(TCN_MOUSELEAVING, -1); + } + else if (iTabNow != -1 && _currentHoverTabItem == -1) // mouse is just entered in a tab zone + { + _currentHoverTabItem = iTabNow; - if (_currentHoverTabItem == iTabNow && _currentHoverTabItem != -1) // mouse moves arround in the same tab - { - // do nothing - } - else if (iTabNow == -1 && _currentHoverTabItem != -1) // mouse is no more on any tab, set hover -1 - { - _currentHoverTabItem = -1; + notify(TCN_MOUSEHOVERING, _currentHoverTabItem); + } + else if (iTabNow != -1 && _currentHoverTabItem != -1 && _currentHoverTabItem != iTabNow) // mouse is being moved from a tab and entering into another tab + { + isFromTabToTab = true; + _whichCloseClickDown = -1; - // send mouse leave notif - notify(TCN_MOUSELEAVING, -1); - } - else if (iTabNow != -1 && _currentHoverTabItem == -1) // mouse is just entered in a tab zone - { - _currentHoverTabItem = iTabNow; + // set current hovered + _currentHoverTabItem = iTabNow; - notify(TCN_MOUSEHOVERING, _currentHoverTabItem); - } - else if (iTabNow != -1 && _currentHoverTabItem != -1 && _currentHoverTabItem != iTabNow) // mouse is being moved from a tab and entering into another tab - { - isFromTabToTab = true; - _whichCloseClickDown = -1; + // send mouse enter notif + notify(TCN_MOUSEHOVERSWITCHING, _currentHoverTabItem); + } + else if (iTabNow == -1 && _currentHoverTabItem == -1) // mouse is already outside + { + // do nothing + } - // set current hovered - _currentHoverTabItem = iTabNow; + if (_drawTabCloseButton) + { + RECT currentHoverTabRectOld = _currentHoverTabRect; + bool isCloseHoverOld = _isCloseHover; - // send mouse enter notif - notify(TCN_MOUSEHOVERSWITCHING, _currentHoverTabItem); + if (_currentHoverTabItem != -1) // is hovering + { + ::SendMessage(_hSelf, TCM_GETITEMRECT, _currentHoverTabItem, reinterpret_cast(&_currentHoverTabRect)); + _isCloseHover = _closeButtonZone.isHit(p.x, p.y, _currentHoverTabRect, _isVertical); } - else if (iTabNow == -1 && _currentHoverTabItem == -1) // mouse is already outside + else { - // do nothing + SetRectEmpty(&_currentHoverTabRect); + _isCloseHover = false; } - if (_drawTabCloseButton) + if (isFromTabToTab || _isCloseHover != isCloseHoverOld) { - RECT currentHoverTabRectOld = _currentHoverTabRect; - bool isCloseHoverOld = _isCloseHover; - - if (_currentHoverTabItem != -1) // is hovering - { - ::SendMessage(_hSelf, TCM_GETITEMRECT, _currentHoverTabItem, reinterpret_cast(&_currentHoverTabRect)); - _isCloseHover = _closeButtonZone.isHit(p.x, p.y, _currentHoverTabRect, _isVertical); - } - else - { - SetRectEmpty(&_currentHoverTabRect); - _isCloseHover = false; - } - - if (isFromTabToTab || _isCloseHover != isCloseHoverOld) - { - if (isCloseHoverOld && (isFromTabToTab || !_isCloseHover)) - InvalidateRect(hwnd, ¤tHoverTabRectOld, FALSE); - - if (_isCloseHover) - InvalidateRect(hwnd, &_currentHoverTabRect, FALSE); - } + if (isCloseHoverOld && (isFromTabToTab || !_isCloseHover)) + InvalidateRect(hwnd, ¤tHoverTabRectOld, FALSE); if (_isCloseHover) - { - // Mouse moves out from close zone will send WM_MOUSELEAVE message - trackMouseEvent(TME_LEAVE); - } + InvalidateRect(hwnd, &_currentHoverTabRect, FALSE); } - // Mouse moves out from tab zone will send WM_MOUSELEAVE message - // but it doesn't track mouse moving from a tab to another - trackMouseEvent(TME_LEAVE); - } - break; + if (_isCloseHover) + { + // Mouse moves out from close zone will send WM_MOUSELEAVE message + trackMouseEvent(TME_LEAVE); + } + } + // Mouse moves out from tab zone will send WM_MOUSELEAVE message + // but it doesn't track mouse moving from a tab to another + trackMouseEvent(TME_LEAVE); } - case WM_MOUSELEAVE: - { - if (_isCloseHover) - InvalidateRect(hwnd, &_currentHoverTabRect, FALSE); + break; + } + //鼠标移开,重绘鼠标区域,重置相关变量 + case WM_MOUSELEAVE: + { + if (_isCloseHover) + InvalidateRect(hwnd, &_currentHoverTabRect, FALSE); - _currentHoverTabItem = -1; - _whichCloseClickDown = -1; - SetRectEmpty(&_currentHoverTabRect); - _isCloseHover = false; + _currentHoverTabItem = -1; + _whichCloseClickDown = -1; + SetRectEmpty(&_currentHoverTabRect); + _isCloseHover = false; - notify(TCN_MOUSELEAVING, _currentHoverTabItem); - break; - } + notify(TCN_MOUSELEAVING, _currentHoverTabItem); + break; + } + //释放左键,告知操作结束 + case WM_LBUTTONUP: + { + _mightBeDragging = false; + _dragCount = 0; - case WM_LBUTTONUP : + int xPos = LOWORD(lParam); + int yPos = HIWORD(lParam); + int currentTabOn = getTabIndexAt(xPos, yPos); + if (_isDragging) { - _mightBeDragging = false; - _dragCount = 0; - - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - int currentTabOn = getTabIndexAt(xPos, yPos); - if (_isDragging) + if (::GetCapture() == _hSelf) { - if (::GetCapture() == _hSelf) - { - ::ReleaseCapture(); - } - else - { - _isDragging = false; - } - - notify(_isDraggingInside?TCN_TABDROPPED:TCN_TABDROPPEDOUTSIDE, currentTabOn); - return TRUE; + ::ReleaseCapture(); } - - if (_drawTabCloseButton) + else { - if ((_whichCloseClickDown == currentTabOn) && _closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical)) - { - notify(TCN_TABDELETE, currentTabOn); - _whichCloseClickDown = -1; - - // Get the next tab at same position - // If valid tab is found then - // update the current hover tab RECT (_currentHoverTabRect) - // update close hover flag (_isCloseHover), so that x will be highlighted or not based on new _currentHoverTabRect - int nextTab = getTabIndexAt(xPos, yPos); - if (nextTab != -1) - { - ::SendMessage(_hSelf, TCM_GETITEMRECT, nextTab, reinterpret_cast(&_currentHoverTabRect)); - _isCloseHover = _closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical); - } - return TRUE; - } - _whichCloseClickDown = -1; + _isDragging = false; } - break; + notify(_isDraggingInside ? TCN_TABDROPPED : TCN_TABDROPPEDOUTSIDE, currentTabOn); + return TRUE; } - case WM_CAPTURECHANGED : + if (_drawTabCloseButton) { - if (_isDragging) + if ((_whichCloseClickDown == currentTabOn) && _closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical)) { - _isDragging = false; + notify(TCN_TABDELETE, currentTabOn); + _whichCloseClickDown = -1; + + // Get the next tab at same position + // If valid tab is found then + // update the current hover tab RECT (_currentHoverTabRect) + // update close hover flag (_isCloseHover), so that x will be highlighted or not based on new _currentHoverTabRect + int nextTab = getTabIndexAt(xPos, yPos); + if (nextTab != -1) + { + ::SendMessage(_hSelf, TCM_GETITEMRECT, nextTab, reinterpret_cast(&_currentHoverTabRect)); + _isCloseHover = _closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical); + } return TRUE; } - break; - } - - case WM_DRAWITEM : - { - drawItem((DRAWITEMSTRUCT *)lParam); - return TRUE; + _whichCloseClickDown = -1; } - case WM_KEYDOWN : + break; + } + //抓取鼠标输入的改变 + case WM_CAPTURECHANGED: + { + if (_isDragging) { - if (wParam == VK_LCONTROL) - ::SetCursor(::LoadCursor(_hInst, MAKEINTRESOURCE(IDC_DRAG_PLUS_TAB))); + _isDragging = false; return TRUE; } - - case WM_MBUTTONUP: + break; + } + //重绘tab + case WM_DRAWITEM: + { + drawItem((DRAWITEMSTRUCT*)lParam); + return TRUE; + } + //是否按下control键 + case WM_KEYDOWN: + { + if (wParam == VK_LCONTROL) + ::SetCursor(::LoadCursor(_hInst, MAKEINTRESOURCE(IDC_DRAG_PLUS_TAB))); + return TRUE; + } + //鼠标中键释放 + case WM_MBUTTONUP: + { + int xPos = LOWORD(lParam); + int yPos = HIWORD(lParam); + int currentTabOn = getTabIndexAt(xPos, yPos); + notify(TCN_TABDELETE, currentTabOn); + return TRUE; + } + //双击鼠标左键 + case WM_LBUTTONDBLCLK: + { + if (_isDbClk2Close) { int xPos = LOWORD(lParam); int yPos = HIWORD(lParam); int currentTabOn = getTabIndexAt(xPos, yPos); notify(TCN_TABDELETE, currentTabOn); - return TRUE; } - - case WM_LBUTTONDBLCLK: + return TRUE; + } + //如果程序正在使用暗黑模式,将会用指定的画刷填充整个Tab的客户区,代替了系统默认的橡皮擦背景操作。 + case WM_ERASEBKGND: + { + if (!NppDarkMode::isEnabled()) { - if (_isDbClk2Close) - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - int currentTabOn = getTabIndexAt(xPos, yPos); - notify(TCN_TABDELETE, currentTabOn); - } - return TRUE; + break; } - case WM_ERASEBKGND: - { - if (!NppDarkMode::isEnabled()) - { - break; - } - - RECT rc{}; - GetClientRect(hwnd, &rc); - FillRect((HDC)wParam, &rc, NppDarkMode::getDarkerBackgroundBrush()); + RECT rc{}; + GetClientRect(hwnd, &rc); + FillRect((HDC)wParam, &rc, NppDarkMode::getDarkerBackgroundBrush()); - return 1; + return 1; + } + //在Tab控件需要重绘时调用,这里会进行大量的绘制操作,内容包括Tab本身和每一个Tab的文字、关闭按钮等元素。 + case WM_PAINT: + { + if (!NppDarkMode::isEnabled()) + { + break; } - case WM_PAINT: + LONG_PTR dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE); + if (!(dwStyle & TCS_OWNERDRAWFIXED)) { - if (!NppDarkMode::isEnabled()) - { - break; - } + break; + } - LONG_PTR dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE); - if (!(dwStyle & TCS_OWNERDRAWFIXED)) - { - break; - } + const bool hasMultipleLines = ((dwStyle & TCS_BUTTONS) == TCS_BUTTONS); - const bool hasMultipleLines = ((dwStyle & TCS_BUTTONS) == TCS_BUTTONS); + PAINTSTRUCT ps{}; + HDC hdc = BeginPaint(hwnd, &ps); + FillRect(hdc, &ps.rcPaint, NppDarkMode::getDarkerBackgroundBrush()); - PAINTSTRUCT ps{}; - HDC hdc = BeginPaint(hwnd, &ps); - FillRect(hdc, &ps.rcPaint, NppDarkMode::getDarkerBackgroundBrush()); + UINT id = ::GetDlgCtrlID(hwnd); - UINT id = ::GetDlgCtrlID(hwnd); + auto holdPen = static_cast(::SelectObject(hdc, NppDarkMode::getEdgePen())); - auto holdPen = static_cast(::SelectObject(hdc, NppDarkMode::getEdgePen())); + HRGN holdClip = CreateRectRgn(0, 0, 0, 0); + if (1 != GetClipRgn(hdc, holdClip)) + { + DeleteObject(holdClip); + holdClip = nullptr; + } - HRGN holdClip = CreateRectRgn(0, 0, 0, 0); - if (1 != GetClipRgn(hdc, holdClip)) - { - DeleteObject(holdClip); - holdClip = nullptr; - } + auto& dpiManager = NppParameters::getInstance()._dpiManager; + int paddingDynamicTwoX = dpiManager.scaleX(2); + int paddingDynamicTwoY = dpiManager.scaleY(2); - auto& dpiManager = NppParameters::getInstance()._dpiManager; - int paddingDynamicTwoX = dpiManager.scaleX(2); - int paddingDynamicTwoY = dpiManager.scaleY(2); + int nTabs = TabCtrl_GetItemCount(hwnd); + int nFocusTab = TabCtrl_GetCurFocus(hwnd); + int nSelTab = TabCtrl_GetCurSel(hwnd); + for (int i = 0; i < nTabs; ++i) + { + DRAWITEMSTRUCT dis = { ODT_TAB, id, (UINT)i, ODA_DRAWENTIRE, ODS_DEFAULT, hwnd, hdc, {}, 0 }; + TabCtrl_GetItemRect(hwnd, i, &dis.rcItem); - int nTabs = TabCtrl_GetItemCount(hwnd); - int nFocusTab = TabCtrl_GetCurFocus(hwnd); - int nSelTab = TabCtrl_GetCurSel(hwnd); - for (int i = 0; i < nTabs; ++i) + if (i == nFocusTab) { - DRAWITEMSTRUCT dis = { ODT_TAB, id, (UINT)i, ODA_DRAWENTIRE, ODS_DEFAULT, hwnd, hdc, {}, 0 }; - TabCtrl_GetItemRect(hwnd, i, &dis.rcItem); - - if (i == nFocusTab) - { - dis.itemState |= ODS_FOCUS; - } - if (i == nSelTab) - { - dis.itemState |= ODS_SELECTED; - } + dis.itemState |= ODS_FOCUS; + } + if (i == nSelTab) + { + dis.itemState |= ODS_SELECTED; + } - dis.itemState |= ODS_NOFOCUSRECT; // maybe, does it handle it already? + dis.itemState |= ODS_NOFOCUSRECT; // maybe, does it handle it already? - RECT rcIntersect{}; - if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem)) + RECT rcIntersect{}; + if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem)) + { + if (!hasMultipleLines) { - if (!hasMultipleLines) + if (_isVertical) { - if (_isVertical) + POINT edges[] = { + {dis.rcItem.left, dis.rcItem.bottom - 1}, + {dis.rcItem.right, dis.rcItem.bottom - 1} + }; + + if (i != nSelTab && (i != nSelTab - 1)) { - POINT edges[] = { - {dis.rcItem.left, dis.rcItem.bottom - 1}, - {dis.rcItem.right, dis.rcItem.bottom - 1} - }; - - if (i != nSelTab && (i != nSelTab - 1)) - { - edges[0].x += paddingDynamicTwoX; - } - - ::Polyline(hdc, edges, _countof(edges)); - dis.rcItem.bottom -= 1; + edges[0].x += paddingDynamicTwoX; } - else + + ::Polyline(hdc, edges, _countof(edges)); + dis.rcItem.bottom -= 1; + } + else + { + POINT edges[] = { + {dis.rcItem.right - 1, dis.rcItem.top}, + {dis.rcItem.right - 1, dis.rcItem.bottom} + }; + + if (i != nSelTab && (i != nSelTab - 1)) { - POINT edges[] = { - {dis.rcItem.right - 1, dis.rcItem.top}, - {dis.rcItem.right - 1, dis.rcItem.bottom} - }; - - if (i != nSelTab && (i != nSelTab - 1)) - { - edges[0].y += paddingDynamicTwoY; - } - - ::Polyline(hdc, edges, _countof(edges)); - dis.rcItem.right -= 1; + edges[0].y += paddingDynamicTwoY; } + + ::Polyline(hdc, edges, _countof(edges)); + dis.rcItem.right -= 1; } + } - HRGN hClip = CreateRectRgnIndirect(&dis.rcItem); + HRGN hClip = CreateRectRgnIndirect(&dis.rcItem); - SelectClipRgn(hdc, hClip); + SelectClipRgn(hdc, hClip); - drawItem(&dis, NppDarkMode::isEnabled()); + drawItem(&dis, NppDarkMode::isEnabled()); - DeleteObject(hClip); + DeleteObject(hClip); - SelectClipRgn(hdc, holdClip); - } + SelectClipRgn(hdc, holdClip); } + } + + if (!hasMultipleLines) + { + RECT rcFirstTab{}; + TabCtrl_GetItemRect(hwnd, 0, &rcFirstTab); - if (!hasMultipleLines) + if (_isVertical) { - RECT rcFirstTab{}; - TabCtrl_GetItemRect(hwnd, 0, &rcFirstTab); + POINT edges[] = { + {rcFirstTab.left, rcFirstTab.top}, + {rcFirstTab.right, rcFirstTab.top} + }; - if (_isVertical) + if (nSelTab != 0) { - POINT edges[] = { - {rcFirstTab.left, rcFirstTab.top}, - {rcFirstTab.right, rcFirstTab.top} - }; - - if (nSelTab != 0) - { - edges[0].x += paddingDynamicTwoX; - } - - ::Polyline(hdc, edges, _countof(edges)); + edges[0].x += paddingDynamicTwoX; } - else - { - POINT edges[] = { - {rcFirstTab.left, rcFirstTab.top}, - {rcFirstTab.left, rcFirstTab.bottom} - }; - if (nSelTab != 0) - { - edges[0].y += paddingDynamicTwoY; - } + ::Polyline(hdc, edges, _countof(edges)); + } + else + { + POINT edges[] = { + {rcFirstTab.left, rcFirstTab.top}, + {rcFirstTab.left, rcFirstTab.bottom} + }; - ::Polyline(hdc, edges, _countof(edges)); + if (nSelTab != 0) + { + edges[0].y += paddingDynamicTwoY; } - } - SelectClipRgn(hdc, holdClip); - if (holdClip) - { - DeleteObject(holdClip); - holdClip = nullptr; + ::Polyline(hdc, edges, _countof(edges)); } + } - SelectObject(hdc, holdPen); - - EndPaint(hwnd, &ps); - return 0; + SelectClipRgn(hdc, holdClip); + if (holdClip) + { + DeleteObject(holdClip); + holdClip = nullptr; } - case WM_PARENTNOTIFY: + SelectObject(hdc, holdPen); + + EndPaint(hwnd, &ps); + return 0; + } + + case WM_PARENTNOTIFY: + { + switch (LOWORD(wParam)) + { + case WM_CREATE: { - switch (LOWORD(wParam)) + auto hwndUpdown = reinterpret_cast(lParam); + if (NppDarkMode::subclassTabUpDownControl(hwndUpdown)) { - case WM_CREATE: - { - auto hwndUpdown = reinterpret_cast(lParam); - if (NppDarkMode::subclassTabUpDownControl(hwndUpdown)) - { - return 0; - } - break; - } + return 0; } - return 0; + break; } + } + return 0; + } } return ::CallWindowProc(_tabBarDefaultProc, hwnd, Message, wParam, lParam); } - -void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode) +//实现了Tab的绘制过程,包括对Tab背景颜色、文字颜色的调整,判断并处理当前Tab的激活状态,处理Tab的图标和标题等。 +void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode) { RECT rect = pDrawItemStruct->rcItem; @@ -1063,9 +1071,9 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode) TCHAR label[MAX_PATH] = { '\0' }; TCITEM tci{}; - tci.mask = TCIF_TEXT|TCIF_IMAGE; + tci.mask = TCIF_TEXT | TCIF_IMAGE; tci.pszText = label; - tci.cchTextMax = MAX_PATH-1; + tci.cchTextMax = MAX_PATH - 1; if (!::SendMessage(_hSelf, TCM_GETITEM, nTab, reinterpret_cast(&tci))) { @@ -1074,7 +1082,7 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode) const COLORREF colorActiveBg = isDarkMode ? NppDarkMode::getSofterBackgroundColor() : ::GetSysColor(COLOR_BTNFACE); const COLORREF colorInactiveBgBase = isDarkMode ? NppDarkMode::getBackgroundColor() : ::GetSysColor(COLOR_BTNFACE); - + COLORREF colorInactiveBg = liteGrey; COLORREF colorActiveText = ::GetSysColor(COLOR_BTNTEXT); COLORREF colorInactiveText = grey; @@ -1247,7 +1255,7 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode) _closeButtonZone._height = dpiManager.scaleY(bmp.bmHeight); RECT buttonRect = _closeButtonZone.getButtonRectFrom(rect, _isVertical); - + // StretchBlt will crop image in RTL if there is no stretching, thus move image by -1 const bool isRTL = (::GetWindowLongPtr(::GetParent(_hSelf), GWL_EXSTYLE) & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL; const int offset = isRTL && (_closeButtonZone._width == bmp.bmWidth) ? -1 : 0; @@ -1371,7 +1379,7 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode) ::RestoreDC(hDC, nSavedDC); } - +//用于改变鼠标光标的形状,根据用户托拽标签的不同位置(是否在同一应用中、是否在一个有效的放置位置等)表现为不同的光标形状。 void TabBarPlus::draggingCursor(POINT screenPoint) { HWND hWin = ::WindowFromPoint(screenPoint); @@ -1394,7 +1402,7 @@ void TabBarPlus::draggingCursor(POINT screenPoint) ::SetCursor(::LoadCursor(_hInst, MAKEINTRESOURCE(IDC_DRAG_OUT_TAB))); } } - +//简单地把指定的标签设为活动状态。 void TabBarPlus::setActiveTab(int tabIndex) { // TCM_SETCURFOCUS is busted on WINE/ReactOS for single line (non-TCS_BUTTONS) tabs... @@ -1407,7 +1415,7 @@ void TabBarPlus::setActiveTab(int tabIndex) ::SendMessage(_hSelf, TCM_SETCURSEL, tabIndex, 0); notify(TCN_SELCHANGE, tabIndex); } - +//交换两个Tab的数据,实现两个Tab的位置交换。 void TabBarPlus::exchangeTabItemData(int oldTab, int newTab) { //1. shift their data, and insert the source @@ -1449,7 +1457,7 @@ void TabBarPlus::exchangeTabItemData(int oldTab, int newTab) //2. set to focus setActiveTab(newTab); } - +//在接收到鼠标托拽消息的时候被调用,用于各个标签的排序和交换位置。 void TabBarPlus::exchangeItemData(POINT point) { // Find the destination tab... @@ -1486,7 +1494,7 @@ void TabBarPlus::exchangeItemData(POINT point) } - +//用于处理与关闭按钮相关的操作,如获取关闭按钮的大小及位置,判断是否点击到了关闭按钮等。 CloseButtonZone::CloseButtonZone() { // TODO: get width/height of close button dynamically @@ -1494,7 +1502,7 @@ CloseButtonZone::CloseButtonZone() _height = _width; } -bool CloseButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical) const +bool CloseButtonZone::isHit(int x, int y, const RECT& tabRect, bool isVertical) const { RECT buttonRect = getButtonRectFrom(tabRect, isVertical); @@ -1504,7 +1512,7 @@ bool CloseButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical) return false; } -RECT CloseButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical) const +RECT CloseButtonZone::getButtonRectFrom(const RECT& tabRect, bool isVertical) const { RECT buttonRect{};