From d65ae64b9ae346fb46972035109e7c898838d37d Mon Sep 17 00:00:00 2001 From: chen <2863222635@qq.com> Date: Sun, 3 Dec 2023 23:30:23 +0800 Subject: [PATCH 1/5] d'f --- .../src/ScintillaComponent/DocTabView.cpp | 26 +++++++------- .../src/ScintillaComponent/DocTabView.h | 35 ++++++++++++------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp b/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp index 5fbc09e..371460e 100644 --- a/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp +++ b/src/PowerEditor/src/ScintillaComponent/DocTabView.cpp @@ -25,7 +25,7 @@ bool DocTabView::_hideTabBarStatus = false; - +//向标签视图添加新的缓冲区,首先检查缓冲区是否有效(不是无效的缓冲区),然后检查是否已经存在相同的缓冲区。如果缓冲区有效且尚未存在,则将其添加到标签页视图中,并更新父窗口的大小。 void DocTabView::addBuffer(BufferID buffer) { if (buffer == BUFFER_INVALID) //valid only @@ -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,14 +77,14 @@ bool DocTabView::activateBuffer(BufferID buffer) return true; } - +//获取当前激活的缓冲区。 BufferID DocTabView::activeBuffer() { int index = getCurrentTabIndex(); return getBufferByIndex(index); } - +//遍历所有标签页,根据文件名查找匹配的缓冲区,找到则返回其ID,否则返回BUFFER_INVALID。 BufferID DocTabView::findBufferByName(const TCHAR * fullfilename) //-1 if not found, something else otherwise { TCITEM tie{}; @@ -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,7 +129,7 @@ BufferID DocTabView::getBufferByIndex(size_t index) return reinterpret_cast(tie.lParam); } - +//根据mask中的标志位,更新与缓冲区相关的信息,例如文件名变化、只读状态变化等。 void DocTabView::bufferUpdated(Buffer * buffer, int mask) { int index = getIndexByBuffer(buffer->getID()); @@ -183,7 +183,7 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask) *out = '\0'; } } - + ::SendMessage(_hSelf, TCM_SETITEM, index, reinterpret_cast(&tie)); // send WM_SIZE only when change tab @@ -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,7 +208,7 @@ void DocTabView::setBuffer(size_t index, BufferID id) ::SendMessage(_hParent, WM_SIZE, 0, 0); } - +//根据隐藏/显示标签栏状态,调整标签页视图和文本编辑器视图的大小,并根据需要发送消息以更新可点击链接。 void DocTabView::reSizeTo(RECT & rc) { int borderWidth = ((NppParameters::getInstance()).getSVP())._borderWidth; diff --git a/src/PowerEditor/src/ScintillaComponent/DocTabView.h b/src/PowerEditor/src/ScintillaComponent/DocTabView.h index 2f8f78c..a0b9894 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; @@ -33,7 +37,7 @@ public : void destroy() override { TabBarPlus::destroy(); }; - + //初始化函数,传入实例句柄、父窗口句柄、ScintillaEditView指针、以及图片列表和选择的图片索引 void init(HINSTANCE hInst, HWND parent, ScintillaEditView * pView, std::vector pIconListVector, unsigned char indexChoice) { TabBarPlus::init(hInst, parent); _pView = pView; @@ -52,45 +56,50 @@ 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); - + // 激活缓冲区 bool activateBuffer(BufferID buffer); - + // 获取当前激活的缓冲区 BufferID activeBuffer(); + // 根据文件名查找缓冲区,返回索引值,如果未找到则返回-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; }; - + // 重写父类的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 : -- 2.34.1 From d77a96a9f5ad7073cf016a602b63813c6084e37b Mon Sep 17 00:00:00 2001 From: chen <2863222635@qq.com> Date: Sun, 3 Dec 2023 23:39:17 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=B3=9B=E8=AF=BB=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/娉涜鎶ュ憡.docx | Bin 19259 -> 14187 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/娉涜鎶ュ憡.docx b/doc/娉涜鎶ュ憡.docx index 2f3f22c6e75794a8c45eebe825fd06994120e8a2..042fd344bfca13200dd7716d2ac277270311f03b 100644 GIT binary patch literal 14187 zcmb7rb9`pY(rzZUZQHhOYhv5BZQHhui6-X6b~2gRm?Sr|_c>?pJ>U86@8167MX!3g z3v1QtuC9`o0s@8v_|-yXclm#P|GPna{4laLly|VTbEK31AVdD>0RMxGyzB>?@h1QP zS3m#&_`j3s+u6~&SzBc%Ov(<>!v|f6cL^nV?haZ%2eycke1Q-sF1Zb(HeFLEZZXCZ z-oi~)CeUg>I~~a#?hIM0t%>HH;yoR=k8?bJ6+S_Zq{_SDj5xvziQgD7=JxO$!Xa_?QXz4EP8oGloFC<+GfO}*W|&0P5FKZUV}R(lXeH;Zx+P2b zgfULPs^52t^-q&1e>sFy{4h!2he;6rZW2RV2jgEhiB8a#8lXoGxd3?=8u3o`k&mBo z$!nkj3qTs`jLWL-^GYKAtmfNoy|fUnLU%htf@`-T89g3W!$xvWyHv&RuDjGbjXc*BvI~N#ugQ zyRBKaaVFJ94D&1BGORe}Fq^QDUI2(FsNVd9FgF26Zv5nCIRZZWClE~OOJWV;{WYvF z=I^EhWm@db(AwWFn1{NJpnMQbA7;l_mRrsWCcmP4zXf$wLO-`A)0DW~X7~199=oPJ=`^~>2-v|5J*yS{h=2j}F*oil zQUgk5P-yw}w5wM=W+aQY$*I+im()fBXA9|T&{!|Qjg{(LZL|c^%xx)*r&&`4qU%vUaa*Jov(~66QHupJy19EQ` ztQGq!+7D?_coG8A_+I^>@6|W=x&!&Dz_!8;XPkK%?zCNAf{lF!+WUBFoUO({( zM8XC21<5u3XuR?Dbwampc|7NmL~47SL(Y&cbo|zb?|$x~@*rn=uQ)Zdksk79_;shR zFTQgAGQ3kVk*U~#4)!(4)GG%no{2X%lvfEaShxeKCdq5+Rb?Up8{t6-)gOj?6m^G@ zs%c2sdS*~0f4^@&ER>xx=ko<%%b|Ilbo+Dzv=^e-+~YD-qT;09y1cT>I?{2Q_sUQ2 ze8@pCut&9_m_GkegM~A}4!?;4P=m^8=l7+io2` z4Z21$pMr@RH*5OU&{|f(8l)G~+H<5Fk4EqSM;`RfX?#YYb3Ri?Ta<(JHfdW$=kl7% zJrcR=35{I$bi5Fx2ihotwAz(b_W?sVPFL?1cDaUo+qBe!BMop>-{+g@_orCh@Y2_+ za-;W^Z{CA+yi_jKQkDBkEQJK@1j@Dt=s;&)$@@sIZoojum?MXLKH+;7yQplNq>=P` zy432|tcIVWjPJH-A_vCl!PC&UPBz!n*vvcHcZv*AD@xn<8W*8n%bP za%qOxKP~4Xr6p=n@kI$S#WaON40~~f;}3QYvlRlN*^w(b14mQbUAo0}_~w}+$3Ys` zUkKBxICbFts1?|aIjWSZ{KnNKSF(!hMhsMUll=-P!uo?aMk#YNJUqT{B<`ytZqMXv zd=~!<*Tu-*rP2ehv_8YgZveNLrCKxEev~E}K#N@4KM|uGulOU zxl|zTN@*DuRqcVT(2=MCByyiEWR{RX+$1f5h*?GqahB9m(xfDTxLW@4TRGwEtg5)F zhUMr>({UHn%}9)MDFWIWt!ke;)+QNlQK${EmgqQl87pWO7Tw*sl5M-);9C&NIS3qX zHrHCXB!x&i-VS?KK)!y%iH(gRJ8D7_KaDX&zUCNWKy#8coEpwjZ%BEFcu{H{QNF~N zmiU<2!j;E1?Ma6pdcAiA$ytq>LpWAjD^EU14s-*^jF|ccn>GE6F*QRII_!fkLAEnz zjH9Acv}SA$4VBbuEAXwtv3iCxIqI}{sno#|N1l~>9;1a}wHkUUE!dO;`RaDZA(A-` zFavA-X%5qoZta&1^o=Lc1{Z7YXEfEowuH-Otq&`aJj;2pSsP61$#V;gFP^$}D-YFC z-CdsE2U!DET<%d20YT2#gt9_Xn+b~Cb%tC?0k^oMb*MWomZC|o1fE&;a6VqN^;HQ(=}i|n+rXQiPvq98?U z@V08n>?yy$4lBJ;5q6kuf+uZmgC}K47pr6+EmJL|o;6E4Gh~{T3A1DyPoaGizyvLd z5fqT5%f~N{l#iR^BNso%pDeF%}aW;MMsqcF$-(@UqsH=X`x?mv!7)=sB_*l<~c|wJnV7=XNGQZlifB7x~H(Y|CC3tHVU=E-9 z>=_qS{?dAk)Kcxmt}IvrnMlXVy^1!p9|MzrFT%i4JXPggZ$;ihw>YI`3EGgYmX;B= zuJfiWJ`u#_*wwC`J?t0jLi*Cf&(-Loo0t8)mu$wyJ&!IdJV=sN1tOm=B|Jis8v4R# z!o$j-5E0zbi7#)XbX8MkRGuQjq>wDW2rvD^sEdca^Iz?#qDu{|~zOlYglh%T!`h896a9V_!yu!Cg#j zQ<)m_gNJ`{ri^cST>_|)$c8eK(G||`@-a_-92?5`APh;V>OWar#7=n37|o0@aF9>z zDkmqsI3CH25FxOoO!=Fn{}~TqB&MqzANjh(AiXVrf1dI~8Pd1%fFELm8_8{E1X}1a z{gM*)PmytOK3F2(ml^t9$Y0};05l%+}Xq1

$vjGTBKRbxat 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 literal 19259 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 XVaOzN^EdFk)03 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 J7XA6{{{yW~PGSH6 -- 2.34.1 From 45c8aab648547d97eb125bac31b91bf7277a9b83 Mon Sep 17 00:00:00 2001 From: chen <2863222635@qq.com> Date: Mon, 4 Dec 2023 21:26:10 +0800 Subject: [PATCH 3/5] TarBar --- .../src/WinControls/TabBar/TabBar.cpp | 74 ++++++++++--------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp b/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp index 578a0c0..319ebd3 100644 --- a/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp +++ b/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp @@ -40,7 +40,7 @@ COLORREF TabBarPlus::_inactiveBgColour = RGB(192, 192, 192); 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); @@ -49,7 +49,7 @@ void TabBar::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMultiLin _isVertical = isVertical; _isMultiLine = isMultiLine; - INITCOMMONCONTROLSEX icce{}; + INITCOMMONCONTROLSEX icce{};//初始化通用控件库 icce.dwSize = sizeof(icce); icce.dwICC = ICC_TAB_CLASSES; InitCommonControlsEx(&icce); @@ -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,13 +106,13 @@ void TabBar::destroy() _hSelf = nullptr; } - +//在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; @@ -120,7 +120,7 @@ int TabBar::insertAtEnd(const TCHAR *subTabName) return int(::SendMessage(_hSelf, TCM_INSERTITEM, _nbItem++, reinterpret_cast(&tie))); } - +//获取当前选定选项卡的标题。 void TabBar::getCurrentTitle(TCHAR *title, int titleLen) { TCITEM tci{}; @@ -130,7 +130,7 @@ void TabBar::getCurrentTitle(TCHAR *title, int titleLen) ::SendMessage(_hSelf, TCM_GETITEM, getCurrentTabIndex(), reinterpret_cast(&tci)); } - +//为TabBar中的选项卡设置字体。根据提供的参数创建新字体,并发送消息为TabBar设置该字体 void TabBar::setFont(const TCHAR *fontName, int fontSize) { if (_hFont) @@ -147,7 +147,7 @@ void TabBar::setFont(const TCHAR *fontName, int fontSize) ::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,14 +192,14 @@ 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)); } - +//调整TabBar的大小以适应给定的矩形区域。调整TabBar的显示方式并计算新的大小,然后调整提供的矩形区域。 void TabBar::reSizeTo(RECT & rc2Ajust) { RECT rowRect{}; @@ -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,15 +250,19 @@ 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); @@ -290,7 +295,7 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult { 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) if (!_hwndArray[i]) found = true; + //满了未找到,销毁 if (!found) { _ctrlID = -1; @@ -354,7 +360,7 @@ 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)); @@ -363,6 +369,7 @@ void TabBarPlus::doOwnerDrawTab() if (_hwndArray[i]) { LONG_PTR style = ::GetWindowLongPtr(_hwndArray[i], GWL_STYLE); + //检查是否需要自定义 if (isOwnerDrawTab()) style |= TCS_OWNERDRAWFIXED; else @@ -378,7 +385,7 @@ void TabBarPlus::doOwnerDrawTab() } } - +//根据给定的索引为选项卡栏设置不同的颜色(如活动文本颜色、背景颜色等)。在更新颜色之后,它调用doOwnerDrawTab()来刷新显示。 void TabBarPlus::setColour(COLORREF colour2Set, tabColourIndex i) { switch (i) @@ -404,7 +411,7 @@ void TabBarPlus::setColour(COLORREF colour2Set, tabColourIndex i) doOwnerDrawTab(); } - +//设置垂直选项卡 void TabBarPlus::doVertical() { for (int i = 0 ; i < _nbCtrl ; ++i) @@ -414,7 +421,7 @@ void TabBarPlus::doVertical() } } - +//显示多行选项卡 void TabBarPlus::doMultiLine() { for (int i = 0 ; i < _nbCtrl ; ++i) @@ -423,7 +430,7 @@ void TabBarPlus::doMultiLine() 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,12 +449,13 @@ 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); @@ -465,13 +473,13 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara return TRUE; } - + //深色模式 case NPPM_INTERNAL_REFRESHDARKMODE: { NppDarkMode::setDarkTooltips(hwnd, NppDarkMode::ToolTipsType::tabbar); return TRUE; } - + //鼠标滚轮 case WM_MOUSEWHEEL: { // .............................................................................. @@ -489,7 +497,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara // CTRL + SHIFT + MOUSEWHEEL: // will switch to the first/last tab // .............................................................................. - + //是否被拖动 if (_isDragging) return TRUE; -- 2.34.1 From f378694a3270191242ec8e98bd7c7acba7b4ce75 Mon Sep 17 00:00:00 2001 From: chen <2863222635@qq.com> Date: Tue, 26 Dec 2023 19:54:02 +0800 Subject: [PATCH 4/5] =?UTF-8?q?19=EF=BC=9A53?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/WinControls/TabBar/TabBar.cpp | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp b/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp index 319ebd3..20b6c3d 100644 --- a/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp +++ b/src/PowerEditor/src/WinControls/TabBar/TabBar.cpp @@ -497,7 +497,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara // CTRL + SHIFT + MOUSEWHEEL: // will switch to the first/last tab // .............................................................................. - //是否被拖动 + //是否被拖动,如是,会交换当前鼠标所在位置和目标位置的数据 if (_isDragging) return TRUE; @@ -589,7 +589,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara } return TRUE; } - + //左键按下 case WM_LBUTTONDOWN : { if (::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS) @@ -600,7 +600,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara setActiveTab(nTab); } } - + //是否关闭 if (_drawTabCloseButton) { int xPos = LOWORD(lParam); @@ -629,7 +629,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara return TRUE; } - + //右键按下,处理选项 case WM_RBUTTONDOWN : //rightclick selects tab aswell { // TCS_BUTTONS doesn't select the tab @@ -645,7 +645,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara ::CallWindowProc(_tabBarDefaultProc, hwnd, WM_LBUTTONDOWN, wParam, lParam); return TRUE; } - + //鼠标移动 case WM_MOUSEMOVE : { if (_mightBeDragging && !_isDragging) @@ -678,7 +678,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara POINT p{}; p.x = LOWORD(lParam); p.y = HIWORD(lParam); - + //是否拖动tag,是,光标移动,tab数据交换,否,判断并进行相关操作 if (_isDragging) { exchangeItemData(p); @@ -766,7 +766,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara break; } - + //鼠标移开,重绘鼠标区域,重置相关变量 case WM_MOUSELEAVE: { if (_isCloseHover) @@ -780,7 +780,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara notify(TCN_MOUSELEAVING, _currentHoverTabItem); break; } - + //释放左键,告知操作结束 case WM_LBUTTONUP : { _mightBeDragging = false; @@ -828,7 +828,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara break; } - + //抓取鼠标输入的改变 case WM_CAPTURECHANGED : { if (_isDragging) @@ -838,20 +838,20 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara } 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); @@ -860,7 +860,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara notify(TCN_TABDELETE, currentTabOn); return TRUE; } - + //双击鼠标左键 case WM_LBUTTONDBLCLK: { if (_isDbClk2Close) @@ -872,7 +872,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara } return TRUE; } - + //如果程序正在使用暗黑模式,将会用指定的画刷填充整个Tab的客户区,代替了系统默认的橡皮擦背景操作。 case WM_ERASEBKGND: { if (!NppDarkMode::isEnabled()) @@ -886,7 +886,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara return 1; } - + //在Tab控件需要重绘时调用,这里会进行大量的绘制操作,内容包括Tab本身和每一个Tab的文字、关闭按钮等元素。 case WM_PAINT: { if (!NppDarkMode::isEnabled()) @@ -1057,7 +1057,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara return ::CallWindowProc(_tabBarDefaultProc, hwnd, Message, wParam, lParam); } - +//实现了Tab的绘制过程,包括对Tab背景颜色、文字颜色的调整,判断并处理当前Tab的激活状态,处理Tab的图标和标题等。 void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode) { RECT rect = pDrawItemStruct->rcItem; @@ -1379,7 +1379,7 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode) ::RestoreDC(hDC, nSavedDC); } - +//用于改变鼠标光标的形状,根据用户托拽标签的不同位置(是否在同一应用中、是否在一个有效的放置位置等)表现为不同的光标形状。 void TabBarPlus::draggingCursor(POINT screenPoint) { HWND hWin = ::WindowFromPoint(screenPoint); @@ -1402,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... @@ -1415,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 @@ -1457,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... @@ -1494,7 +1494,7 @@ void TabBarPlus::exchangeItemData(POINT point) } - +//用于处理与关闭按钮相关的操作,如获取关闭按钮的大小及位置,判断是否点击到了关闭按钮等。 CloseButtonZone::CloseButtonZone() { // TODO: get width/height of close button dynamically -- 2.34.1 From 2eb8ad44d132b8c83df16a2cf3bc0251acac143d Mon Sep 17 00:00:00 2001 From: chen <2863222635@qq.com> Date: Fri, 29 Dec 2023 08:22:16 +0800 Subject: [PATCH 5/5] 1 --- .../src/MISC/Exception/MiniDumper.cpp | 12 +- .../WinControls/FileBrowser/fileBrowser.cpp | 126 ++++++++++-------- 2 files changed, 73 insertions(+), 65 deletions(-) diff --git a/src/PowerEditor/src/MISC/Exception/MiniDumper.cpp b/src/PowerEditor/src/MISC/Exception/MiniDumper.cpp index f073d76..f5d03e8 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) { 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" ); if (pDump) - { + {//获取当前模块的文件路径 ::GetModuleFileName(NULL, szDumpPath, MAX_PATH); ::PathRemoveFileSpec(szDumpPath); wcscat_s(szDumpPath, TEXT("\\NppDump.dmp")); @@ -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/WinControls/FileBrowser/fileBrowser.cpp b/src/PowerEditor/src/WinControls/FileBrowser/fileBrowser.cpp index 3f17025..aa5690d 100644 --- a/src/PowerEditor/src/WinControls/FileBrowser/fileBrowser.cpp +++ b/src/PowerEditor/src/WinControls/FileBrowser/fileBrowser.cpp @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - +//fileBrowser类的具体实现 #include "fileBrowser.h" #include "resource.h" #include "tinyxml.h" @@ -41,7 +41,7 @@ #define FB_CMD_FOLDALL 2 #define FB_CMD_EXPANDALL 3 - +//停止所有文件监视器 FileBrowser::~FileBrowser() { for (const auto folder : _folderUpdaters) @@ -55,7 +55,7 @@ FileBrowser::~FileBrowser() delete cd; } } - +//将一个字符串分割成多个子字符串,函数使用了for循环依次检查字符串中的每个字符,当找到等于`sep`或者空字符的字符时,就把这之前的字符作为一个子字符串存储在`splitedStrings`向量中。 vector split(const generic_string & string2split, TCHAR sep) { vector splitedStrings; @@ -71,7 +71,7 @@ vector split(const generic_string & string2split, TCHAR sep) } return splitedStrings; } - +//检查子文件夹是否与根文件相关 bool isRelatedRootFolder(const generic_string & relatedRoot, const generic_string & subFolder) { if (relatedRoot.empty()) @@ -91,11 +91,11 @@ bool isRelatedRootFolder(const generic_string & relatedRoot, const generic_strin return relatedRootArray[index2Compare] == subFolderArray[index2Compare]; } - +//消息处理 intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) - { + {//会话框初始化,包括创建工具条,树状视图的初始化等。 case WM_INITDIALOG : { NppParameters& nppParam = NppParameters::getInstance(); @@ -175,7 +175,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l return TRUE; } - + //处理黑暗模式刷新的消息 case NPPM_INTERNAL_REFRESHDARKMODE: { if (static_cast(lParam) != TRUE) @@ -185,7 +185,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l NppDarkMode::setTreeViewStyle(_treeView.getHSelf()); return TRUE; } - + //鼠标消息 case WM_MOUSEMOVE: if (_treeView.isDragging()) _treeView.dragItem(_hSelf, LOWORD(lParam), HIWORD(lParam)); @@ -197,13 +197,13 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l } break; - + //通知消息 case WM_NOTIFY: { notified((LPNMHDR)lParam); } return TRUE; - + //得到窗体的新宽度和高度,然后调整工具条和树形视图的位置和大小。 case WM_SIZE: { int width = LOWORD(lParam); @@ -220,28 +220,28 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l ::MoveWindow(hwnd, 0, toolbarMenuRect.bottom + extraValue, width, height - toolbarMenuRect.bottom - extraValue, TRUE); break; } - + //文本菜单 case WM_CONTEXTMENU: if (!_treeView.isDragging()) showContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return TRUE; - + //来自菜单的选择 case WM_COMMAND: { switch (LOWORD(wParam)) - { + {//选择当前正在编辑的文件。 case FB_CMD_AIMFILE: { selectCurrentEditingFile(); break; } - + //折叠 case FB_CMD_FOLDALL: { _treeView.foldAll(); break; } - + //展开 case FB_CMD_EXPANDALL: { _treeView.expandAll(); @@ -253,7 +253,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l } break; } - + //销毁 case WM_DESTROY: { ::DestroyWindow(_hToolbarMenu); @@ -261,7 +261,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l destroyMenus(); break; } - + //添加 case FB_ADDFILE: { @@ -274,7 +274,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l break; } - + //移除 case FB_RMFILE: { @@ -287,7 +287,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l break; } - + //重命名 case FB_RNFILE: { const std::vector file2Change = *(std::vector *)lParam; @@ -324,7 +324,7 @@ intptr_t CALLBACK FileBrowser::run_dlgProc(UINT message, WPARAM wParam, LPARAM l } return DockingDlgInterface::run_dlgProc(message, wParam, lParam); } - +//创建一个文件浏览器的时候,初始化弹出菜单。首先收集各种与菜单项相关的字符串,然后创建三种不同的菜单:全局菜单、根菜单、文件夹菜单和文件菜单,向这些菜单中插入各种菜单项。 void FileBrowser::initPopupMenus() { NativeLangSpeaker* pNativeSpeaker = NppParameters::getInstance().getNativeLangSpeaker(); @@ -370,7 +370,7 @@ void FileBrowser::initPopupMenus() ::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_FILEBROWSER_EXPLORERHERE, explorerHere.c_str()); ::InsertMenu(_hFileMenu, 0, MF_BYCOMMAND, IDM_FILEBROWSER_CMDHERE, cmdHere.c_str()); } - +//通过一个给定的路径选中文件浏览器中的一个项目。它首先检查路径是否为空,然后通过遍历所有的文件夹来寻找对应的项目。 bool FileBrowser::selectItemFromPath(const generic_string& itemPath) const { if (itemPath.empty()) @@ -409,7 +409,7 @@ bool FileBrowser::selectItemFromPath(const generic_string& itemPath) const } return false; } - +//选择当前正在编辑的文件。 bool FileBrowser::selectCurrentEditingFile() const { TCHAR currentDocPath[MAX_PATH] = { '\0' }; @@ -418,7 +418,7 @@ bool FileBrowser::selectCurrentEditingFile() const return selectItemFromPath(currentDocPathStr); } - +//摧毁创建的菜单 void FileBrowser::destroyMenus() { ::DestroyMenu(_hGlobalMenu); @@ -426,7 +426,7 @@ void FileBrowser::destroyMenus() ::DestroyMenu(_hFolderMenu); ::DestroyMenu(_hFileMenu); } - +//返回一个给定节点的完整路径。 generic_string FileBrowser::getNodePath(HTREEITEM node) const { if (!node) return TEXT(""); @@ -460,12 +460,12 @@ generic_string FileBrowser::getNodePath(HTREEITEM node) const return fullPath; } - +//返回一个给定节点的名称。 generic_string FileBrowser::getNodeName(HTREEITEM node) const { return node ? _treeView.getItemDisplayName(node) : TEXT(""); } - +//打开选定的文件。如果选定的项目是一个文件,那么就打开它;否则,不执行任何操作。 void FileBrowser::openSelectFile() { // Get the selected item @@ -483,7 +483,7 @@ void FileBrowser::openSelectFile() ::PostMessage(_hParent, NPPM_DOOPEN, 0, reinterpret_cast(_selectedNodeFullPath.c_str())); } - +//处理各种菜单操作的事件。例如,如果一个菜单项被双击,那么就调用函数进行对应的处理;如果一个节点标签被编辑,那么函数就保存新的标签。 void FileBrowser::notified(LPNMHDR notification) { if (notification->code == DMN_CLOSE) @@ -673,7 +673,7 @@ void FileBrowser::notified(LPNMHDR notification) } } } - +//获取给定项目(`hItem`)的节点类型。函数首先获取项目的索引(`iImage`),如果索引为`INDEX_LEAF`,则节点类型为文件;如果项目的参数(`lParam`)不为空并且`SortingData4lParam`类中`_rootPath`成员不为空,那么节点类型为根;否则,节点类型为文件夹。 BrowserNodeType FileBrowser::getNodeType(HTREEITEM hItem) { TVITEM tvItem; @@ -697,7 +697,7 @@ BrowserNodeType FileBrowser::getNodeType(HTREEITEM hItem) return browserNodeType_folder; } } - +//(x, y)位置显示上下文菜单。函数首先检测给定位置是否在一个元素上,如果是的话就选中该元素,并获取该元素的节点类型,然后根据节点类型显示相应的上下文菜单。 void FileBrowser::showContextMenu(int x, int y) { TVHITTESTINFO tvHitInfo{}; @@ -735,7 +735,7 @@ void FileBrowser::showContextMenu(int x, int y) x, y, 0, _hSelf, NULL); } } - +//执行与给定命令ID(`cmdID`)关联的上下文菜单命令。例如,如果命令ID为`IDM_FILEBROWSER_REMOVEROOTFOLDER`,则函数将删除选定的根文件夹。 void FileBrowser::popupMenuCmd(int cmdID) { // get selected item handle @@ -872,7 +872,7 @@ void FileBrowser::popupMenuCmd(int cmdID) } - +//在目录`dir`中获取符合`patterns`模式的所有文件和子目录的结构信息,并将其保存到`directoryStructure`中。`isRecursive`参数指定是否递归遍历子目录,`isInHiddenDir`参数指示当前目录是否为隐藏目录。 void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector & patterns, FolderInfo & directoryStructure, bool isRecursive, bool isInHiddenDir) { if (directoryStructure._parent == nullptr) // Root! @@ -954,12 +954,13 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector_rootFolder._rootPath == rootFolderPath) return; else - { + { // 检查是否存在相关的根文件夹,以便选择目录 if (isRelatedRootFolder(f->_rootFolder._rootPath, rootFolderPath)) { //do nothing, go down to select the dir @@ -987,9 +988,9 @@ void FileBrowser::addRootFolder(generic_string rootFolderPath) _treeView.selectItem(foundItem); return; } - + // 检查是否存在相对于要添加的根文件夹的子文件夹 if (isRelatedRootFolder(rootFolderPath, f->_rootFolder._rootPath)) - { + {// 显示消息框,指示存在子文件夹,需要先移除 NppParameters::getInstance().getNativeLangSpeaker()->messageBox("FolderAsWorspaceSubfolderExists", _hParent, TEXT("A sub-folder of the folder you want to add exists.\rPlease remove its root from the panel before you add folder \"$STR_REPLACE$\"."), @@ -1001,10 +1002,10 @@ void FileBrowser::addRootFolder(generic_string rootFolderPath) } } } - + // 设置要匹配的文件模式 std::vector patterns2Match; patterns2Match.push_back(TEXT("*.*")); - + // 获取根文件夹的名称并创建相应的文件夹信息对象 TCHAR *label = ::PathFindFileName(rootFolderPath.c_str()); TCHAR rootLabel[MAX_PATH] = {'\0'}; wcscpy_s(rootLabel, label); @@ -1019,10 +1020,11 @@ void FileBrowser::addRootFolder(generic_string rootFolderPath) _folderUpdaters.push_back(new FolderUpdater(directoryStructure, this)); _folderUpdaters[_folderUpdaters.size() - 1]->startWatcher(); } - +//创建文件夹项目从目录结构 HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, const FolderInfo & directoryStructure) { HTREEITEM hFolderItem = nullptr; + // 如果是根目录,则创建根节点 if (directoryStructure._parent == nullptr && hParentItem == nullptr) { TCHAR rootPath[MAX_PATH] = { '\0' }; @@ -1033,14 +1035,14 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con SortingData4lParam* customData = new SortingData4lParam(rootPath, TEXT(""), true); sortingDataArray.push_back(customData); - + // 添加根节点到树视图 hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), TVI_ROOT, INDEX_CLOSE_ROOT, reinterpret_cast(customData)); } else { SortingData4lParam* customData = new SortingData4lParam(TEXT(""), directoryStructure._name, true); sortingDataArray.push_back(customData); - + // 添加节点到树视图 hFolderItem = _treeView.addItem(directoryStructure._name.c_str(), hParentItem, INDEX_CLOSE_NODE, reinterpret_cast(customData)); } @@ -1053,7 +1055,7 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con { SortingData4lParam* customData = new SortingData4lParam(TEXT(""), file._name, false); sortingDataArray.push_back(customData); - + // 添加文件节点到树视图 _treeView.addItem(file._name.c_str(), hFolderItem, INDEX_LEAF, reinterpret_cast(customData)); } @@ -1061,7 +1063,7 @@ HTREEITEM FileBrowser::createFolderItemsFromDirStruct(HTREEITEM hParentItem, con return hFolderItem; } - +//根据路径找到根目录 HTREEITEM FileBrowser::getRootFromFullPath(const generic_string & rootPath) const { HTREEITEM node = nullptr; @@ -1080,7 +1082,7 @@ HTREEITEM FileBrowser::getRootFromFullPath(const generic_string & rootPath) cons } return node; } - +//在指定父节点下查找具有特定名称的子节点。 HTREEITEM FileBrowser::findChildNodeFromName(HTREEITEM parent, const generic_string& label) const { for (HTREEITEM hItemNode = _treeView.getChildFrom(parent); @@ -1102,7 +1104,7 @@ HTREEITEM FileBrowser::findChildNodeFromName(HTREEITEM parent, const generic_str } return nullptr; } - +//得到所有根节点的路径 vector FileBrowser::getRoots() const { vector roots; @@ -1121,7 +1123,7 @@ vector FileBrowser::getRoots() const } return roots; } - +//获取选中文件的路径 generic_string FileBrowser::getSelectedItemPath() const { generic_string itemPath; @@ -1132,7 +1134,7 @@ generic_string FileBrowser::getSelectedItemPath() const } return itemPath; } - +//将传递的文件路径信息分组,按照共同路径和根路径进行分类。 std::vector FileBrowser::getFilesFromParam(LPARAM lParam) const { const std::vector filesToChange = *(std::vector*)lParam; @@ -1189,7 +1191,7 @@ std::vector FileBrowser::getFilesFromParam(LPARAM lP return groupedFiles; } - +//将文件组添加到树中,根据文件类型在树中创建相应的节点。 bool FileBrowser::addToTree(FilesToChange & group, HTREEITEM node) { if (node == nullptr) // it's a root. Search the right root with rootPath @@ -1266,7 +1268,7 @@ bool FileBrowser::addToTree(FilesToChange & group, HTREEITEM node) } } - +//在树中查找并删除指定的文件组。 bool FileBrowser::deleteFromTree(FilesToChange & group) { std::vector foundItems = findInTree(group, nullptr); @@ -1283,7 +1285,7 @@ bool FileBrowser::deleteFromTree(FilesToChange & group) return true; } - +//在树形结构中查找指定路径,首先判断当前节点是否为根节点,若是则根据根路径查找对应的根节点。然后根据路径数组的大小,判断是否继续查找子节点或者返回当前节点。 HTREEITEM FileBrowser::findInTree(const generic_string& rootPath, HTREEITEM node, std::vector linarPathArray) const { if (node == nullptr) // it's a root. Search the right root with rootPath @@ -1326,7 +1328,7 @@ HTREEITEM FileBrowser::findInTree(const generic_string& rootPath, HTREEITEM node return nullptr; } } - +//该函数也用于在树形结构中查找指定路径,但参数不同。参数group是一个包含文件信息和路径的对象,node表示当前节点。函数首先判断当前节点是否为根节点,若是则根据路径信息查找对应的根节点。然后根据路径信息的大小,判断是否继续查找子节点或者返回找到的节点集合。 std::vector FileBrowser::findInTree(FilesToChange & group, HTREEITEM node) const { if (node == nullptr) // it's a root. Search the right root with rootPath @@ -1367,7 +1369,7 @@ std::vector FileBrowser::findInTree(FilesToChange & group, HTREEITEM return {}; } } - +//找到指定父节点的子节点 std::vector FileBrowser::findChildNodesFromNames(HTREEITEM parent, std::vector & labels) const { std::vector itemNodes; @@ -1394,6 +1396,7 @@ std::vector FileBrowser::findChildNodesFromNames(HTREEITEM parent, st } return itemNodes; } +//移除已经在父节点中的名字。它遍历父节点的所有子节点,并将与给定标签集合中名字相匹配的标签清除。 void FileBrowser::removeNamesAlreadyInNode(HTREEITEM parent, std::vector & labels) const { @@ -1418,7 +1421,7 @@ void FileBrowser::removeNamesAlreadyInNode(HTREEITEM parent, std::vector& linarPathArrayFrom, const generic_string & renameTo) { HTREEITEM foundItem = findInTree(rootPath, node, linarPathArrayFrom); @@ -1433,7 +1436,7 @@ bool FileBrowser::renameInTree(const generic_string& rootPath, HTREEITEM node, c return true; } - +//排序回调函数,按照文件夹和文件名进行排序。首先是文件夹,然后是文件。如果两者都是文件夹或文件,那么比较它们的名字。 int CALLBACK FileBrowser::categorySortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM /*lParamSort*/) { SortingData4lParam* item1 = reinterpret_cast(lParam1); @@ -1449,7 +1452,7 @@ int CALLBACK FileBrowser::categorySortFunc(LPARAM lParam1, LPARAM lParam2, LPARA else return lstrcmpi(item1->_label.c_str(), item2->_label.c_str()); } - +//将给定的完整路径添加到文件夹信息结构中。该路径可能是文件或目录,如果该路径已经存在于结构中,则返回false,如果成功添加,则返回true。 bool FolderInfo::addToStructure(generic_string & fullpath, std::vector linarPathArray) { if (linarPathArray.size() == 1) // could be file or folder @@ -1494,7 +1497,7 @@ bool FolderInfo::addToStructure(generic_string & fullpath, std::vector linarPathArray) { if (linarPathArray.size() == 1) // could be file or folder @@ -1532,7 +1535,7 @@ bool FolderInfo::removeFromStructure(std::vector linarPathArray) } return false; } - +//在文件夹信息结构中重命名给定的线性路径。它将 "linarPathArrayFrom" 指定的路径的名字更改为 "linarPathArrayTo" 指定的名字。 bool FolderInfo::renameInStructure(std::vector linarPathArrayFrom, std::vector linarPathArrayTo) { if (linarPathArrayFrom.size() == 1) // could be file or folder @@ -1572,6 +1575,7 @@ bool FolderInfo::renameInStructure(std::vector linarPathArrayFro return false; } } +//打开监视器,创建一个事件对象并开启一个新的线程,线程开始运行 `watching` 函数。 void FolderUpdater::startWatcher() { @@ -1579,6 +1583,7 @@ void FolderUpdater::startWatcher() _EventHandle = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); _watchThreadHandle = ::CreateThread(NULL, 0, watching, this, 0, NULL); } +//停止监视器。它通过设定事件和关闭对应的线程实现。 void FolderUpdater::stopWatcher() { @@ -1586,6 +1591,7 @@ void FolderUpdater::stopWatcher() ::CloseHandle(_watchThreadHandle); ::CloseHandle(_EventHandle); } +//根据动作类型的代码返回相应的动作名字。 LPCWSTR explainAction(DWORD dwAction) { @@ -1606,6 +1612,7 @@ LPCWSTR explainAction(DWORD dwAction) } } +//负责监视目录下的文件变化。当有文件被创建、删除、重命名等操作时,就会将这个改动放入改动队列,并通过事件提醒主线程进行处理。 DWORD WINAPI FolderUpdater::watching(void *params) { @@ -1704,6 +1711,7 @@ DWORD WINAPI FolderUpdater::watching(void *params) //printStr(L"Quit watching thread"); return EXIT_SUCCESS; } +//根据改动的类型,调用不同的文件浏览器的方法,例如文件创建、删除、重命名等。 void FolderUpdater::processChange(DWORD dwAction, std::vector filesToChange, FolderUpdater* thisFolderUpdater) { -- 2.34.1