Browse Source

Add Pin tab feature

Fix #5786, close #15750
pull/15775/head
Don Ho 3 weeks ago
parent
commit
ce58b424bd
  1. 1
      PowerEditor/installer/nativeLang/english.xml
  2. 1
      PowerEditor/installer/nativeLang/french.xml
  3. 4
      PowerEditor/installer/nativeLang/taiwaneseMandarin.xml
  4. 17
      PowerEditor/src/Notepad_plus.cpp
  5. 1
      PowerEditor/src/Notepad_plus.h
  6. 9
      PowerEditor/src/Notepad_plus.rc
  7. 53
      PowerEditor/src/NppBigSwitch.cpp
  8. 40
      PowerEditor/src/NppCommands.cpp
  9. 19
      PowerEditor/src/NppIO.cpp
  10. 32
      PowerEditor/src/NppNotification.cpp
  11. 22
      PowerEditor/src/Parameters.cpp
  12. 16
      PowerEditor/src/Parameters.h
  13. 4
      PowerEditor/src/ScintillaComponent/Buffer.h
  14. 12
      PowerEditor/src/WinControls/ColourPicker/WordStyleDlg.rc
  15. 56
      PowerEditor/src/WinControls/Preference/preference.rc
  16. 6
      PowerEditor/src/WinControls/Preference/preferenceDlg.cpp
  17. 2
      PowerEditor/src/WinControls/Preference/preference_rc.h
  18. 327
      PowerEditor/src/WinControls/TabBar/TabBar.cpp
  19. 52
      PowerEditor/src/WinControls/TabBar/TabBar.h
  20. BIN
      PowerEditor/src/icons/dark/tabbar/pinTabButton.ico
  21. BIN
      PowerEditor/src/icons/dark/tabbar/pinTabButton_hover.ico
  22. BIN
      PowerEditor/src/icons/dark/tabbar/pinTabButton_pinned.ico
  23. BIN
      PowerEditor/src/icons/dark/tabbar/pinTabButton_pinnedHover.ico
  24. BIN
      PowerEditor/src/icons/standard/tabbar/pinTabButton.ico
  25. BIN
      PowerEditor/src/icons/standard/tabbar/pinTabButton_hover.ico
  26. BIN
      PowerEditor/src/icons/standard/tabbar/pinTabButton_pinned.ico
  27. BIN
      PowerEditor/src/icons/standard/tabbar/pinTabButton_pinnedHover.ico
  28. 11
      PowerEditor/src/resource.h

1
PowerEditor/installer/nativeLang/english.xml

@ -958,6 +958,7 @@ Translation note:
<Item id="6110" name="Draw a colored bar on active tab"/>
<Item id="6112" name="Show close button on each tab"/>
<Item id="6113" name="Double click to close document"/>
<Item id="6115" name="Enable pin tab feature"/>
<Item id="6118" name="Hide"/>
<Item id="6119" name="Multi-line"/>
<Item id="6120" name="Vertical"/>

1
PowerEditor/installer/nativeLang/french.xml

@ -957,6 +957,7 @@ Translation note:
<Item id="6110" name="Barre colorée sur l’onglet actif"/>
<Item id="6112" name="Bouton de fermeture sur chaque onglet"/>
<Item id="6113" name="Fermer l’onglet par double clic"/>
<Item id="6115" name="Activer l’option épingler l’onglet"/>
<Item id="6118" name="Cacher"/>
<Item id="6119" name="Multiligne"/>
<Item id="6120" name="Verticale"/>

4
PowerEditor/installer/nativeLang/taiwaneseMandarin.xml

@ -910,13 +910,15 @@
<Item id="6130" name="Filled Fluent UI: 大圖示"/>
<Item id="6105" name="標準: : 小圖示"/>
<Item id="6106" name="頁籤列"/>
<Item id="6107" name="小型"/>
<Item id="6107" name="縮小"/>
<Item id="6128" name="替代圖示"/>
<Item id="6108" name="鎖定(禁止拖曳)"/>
<Item id="6109" name="非使用中的頁籤變暗"/>
<Item id="6110" name="使用中的頁籤加色條"/>
<Item id="6111" name="顯示狀態列"/>
<Item id="6112" name="在每個頁籤顯示關閉按鈕"/>
<Item id="6113" name="雙擊滑鼠關閉文件"/>
<Item id="6115" name="啟用固定標籤頁功能"/>
<Item id="6118" name="隱藏"/>
<Item id="6119" name="多行"/>
<Item id="6120" name="直式"/>

17
PowerEditor/src/Notepad_plus.cpp

@ -405,6 +405,7 @@ LRESULT Notepad_plus::init(HWND hwnd)
TabBarPlus::setDrawTopBar((tabBarStatus & TAB_DRAWTOPBAR) != 0, &_mainDocTab);
TabBarPlus::setDrawInactiveTab((tabBarStatus & TAB_DRAWINACTIVETAB) != 0, &_mainDocTab);
TabBarPlus::setDrawTabCloseButton((tabBarStatus & TAB_CLOSEBUTTON) != 0, &_mainDocTab);
TabBarPlus::setDrawTabPinButton((tabBarStatus & TAB_PINBUTTON) != 0, &_mainDocTab);
TabBarPlus::setDbClk2Close((tabBarStatus & TAB_DBCLK2CLOSE) != 0);
TabBarPlus::setVertical((tabBarStatus & TAB_VERTICAL) != 0);
drawTabbarColoursFromStylerArray();
@ -918,6 +919,7 @@ bool Notepad_plus::saveGUIParams()
(TabBarPlus::drawInactiveTab() ? TAB_DRAWINACTIVETAB : 0) | \
(TabBarPlus::isReduced() ? TAB_REDUCE : 0) | \
(TabBarPlus::drawTabCloseButton() ? TAB_CLOSEBUTTON : 0) | \
(TabBarPlus::drawTabPinButton() ? TAB_PINBUTTON : 0) | \
(TabBarPlus::isDbClk2Close() ? TAB_DBCLK2CLOSE : 0) | \
(TabBarPlus::isVertical() ? TAB_VERTICAL : 0) | \
(TabBarPlus::isMultiLine() ? TAB_MULTILINE : 0) |\
@ -4909,6 +4911,8 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
//First put the doc in the other view if not present (if it is, activate it).
//Then if needed close in the original tab
BufferID current = _pEditView->getCurrentBufferID();
Buffer* buf = MainFileManager.getBufferByID(current);
int viewToGo = otherView();
int indexFound = _pNonDocTab->getIndexByBuffer(current);
if (indexFound != -1) //activate it
@ -4929,7 +4933,7 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
}
loadBufferIntoView(current, viewToGo);
Buffer *buf = MainFileManager.getBufferByID(current);
_pEditView->saveCurrentPos(); //allow copying of position
buf->setPosition(buf->getPosition(_pEditView), _pNonEditView);
_pNonEditView->restoreCurrentPosPreStep(); //set position
@ -4948,7 +4952,6 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
//Close the document if we transfered the document instead of cloning it
if (mode == TransferMove)
{
Buffer *buf = MainFileManager.getBufferByID(current);
monitoringWasOn = buf->isMonitoringOn();
//just close the activate document, since thats the one we moved (no search)
@ -4958,6 +4961,13 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
//Activate the other view since thats where the document went
switchEditViewTo(viewToGo);
if (buf->isPinned())
{
buf->setPinned(false);
_pDocTab->tabToStart();
buf->setPinned(true);
}
if (monitoringWasOn)
{
command(IDM_VIEW_MONITORING);
@ -4965,7 +4975,6 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
if (_pDocumentListPanel != nullptr)
{
Buffer* buf = MainFileManager.getBufferByID(current);
_pDocumentListPanel->setItemColor(buf);
}
}
@ -6333,7 +6342,7 @@ void Notepad_plus::getCurrentOpenedFiles(Session & session, bool includUntitledD
}
const wchar_t* langName = languageName.c_str();
sessionFileInfo sfi(buf->getFullPathName(), langName, buf->getEncoding(), buf->getUserReadOnly(), buf->getPosition(editView), buf->getBackupFileName().c_str(), buf->getLastModifiedTimestamp(), buf->getMapPosition());
sessionFileInfo sfi(buf->getFullPathName(), langName, buf->getEncoding(), buf->getUserReadOnly(), buf->isPinned(), buf->getPosition(editView), buf->getBackupFileName().c_str(), buf->getLastModifiedTimestamp(), buf->getMapPosition());
sfi._isMonitoring = buf->isMonitoringOn();
sfi._individualTabColour = docTab[k]->getIndividualTabColourId(static_cast<int>(i));

1
PowerEditor/src/Notepad_plus.h

@ -192,6 +192,7 @@ public:
bool fileRename(BufferID id = BUFFER_INVALID);
bool fileRenameUntitledPluginAPI(BufferID id, const wchar_t* tabNewName);
void unPinnedForAllBuffers();
bool switchToFile(BufferID buffer); //find buffer in active view then in other view.
//@}

9
PowerEditor/src/Notepad_plus.rc

@ -335,6 +335,15 @@ IDR_CLOSETAB_INACT_DM ICON "icons/dark/tabbar/closeTabButton_in
IDR_CLOSETAB_HOVER_DM ICON "icons/dark/tabbar/closeTabButton_hover.ico"
IDR_CLOSETAB_PUSH_DM ICON "icons/dark/tabbar/closeTabButton_push.ico"
IDR_PINTAB ICON "icons/standard/tabbar/pinTabButton.ico"
IDR_PINTAB_HOVER ICON "icons/standard/tabbar/pinTabButton_pinned.ico"
IDR_PINTAB_PINNED ICON "icons/standard/tabbar/pinTabButton_pinned.ico"
IDR_PINTAB_PINNEDHOVER ICON "icons/standard/tabbar/pinTabButton.ico"
IDR_PINTAB_DM ICON "icons/dark/tabbar/pinTabButton.ico"
IDR_PINTAB_HOVER_DM ICON "icons/dark/tabbar/pinTabButton_hover.ico"
IDR_PINTAB_PINNED_DM ICON "icons/dark/tabbar/pinTabButton_pinned.ico"
IDR_PINTAB_PINNEDHOVER_DM ICON "icons/dark/tabbar/pinTabButton_pinnedHover.ico"
IDR_DOCMAP_ICO ICON "icons/standard/panels/tabbar/docMap.ico"
IDR_DOCMAP_ICO2 ICON "icons/light/panels/tabbar/docMap.ico"
IDR_DOCMAP_ICO_DM ICON "icons/dark/panels/tabbar/docMap.ico"

53
PowerEditor/src/NppBigSwitch.cpp

@ -3693,6 +3693,8 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
_subDocTab.resizeIconsDpi();
_mainDocTab.setCloseBtnImageList();
_subDocTab.setCloseBtnImageList();
_mainDocTab.setPinBtnImageList();
_subDocTab.setPinBtnImageList();
::SendMessage(_pPublicInterface->getHSelf(), WM_COMMAND, IDM_VIEW_REDUCETABBAR, 0);
changeDocumentListIconSet(false);
@ -3779,6 +3781,57 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
return fileName.length();
}
case NPPM_INTERNAL_DRAWTABBARPINBOTTUN:
{
TabBarPlus::setDrawTabPinButton(!TabBarPlus::drawTabPinButton(), &_mainDocTab);
bool drawTabPinButton = TabBarPlus::drawTabPinButton();
bool drawTabCloseButton = TabBarPlus::drawTabCloseButton();
if (!drawTabPinButton)
{
unPinnedForAllBuffers();
}
if (drawTabCloseButton && drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(0);
_mainDocTab.setTabPinButtonOrder(1);
_subDocTab.setTabCloseButtonOrder(0);
_subDocTab.setTabPinButtonOrder(1);
}
else if (!drawTabCloseButton && drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(-1);
_mainDocTab.setTabPinButtonOrder(0);
_subDocTab.setTabCloseButtonOrder(-1);
_subDocTab.setTabPinButtonOrder(0);
}
else if (drawTabCloseButton && !drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(0);
_mainDocTab.setTabPinButtonOrder(-1);
_subDocTab.setTabCloseButtonOrder(0);
_subDocTab.setTabPinButtonOrder(-1);
}
else //if (!drawTabCloseButton && !drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(-1);
_mainDocTab.setTabPinButtonOrder(-1);
_subDocTab.setTabCloseButtonOrder(-1);
_subDocTab.setTabPinButtonOrder(-1);
}
// This part is just for updating (redraw) the tabs
int tabDpiDynamicalHeight = _mainDocTab.dpiManager().scale(TabBarPlus::isReduced() ? g_TabHeight : g_TabHeightLarge);
int tabDpiDynamicalWidth = _mainDocTab.dpiManager().scale(TabBarPlus::drawTabPinButton() ? g_TabWidthCloseBtn : g_TabWidth);
TabCtrl_SetItemSize(_mainDocTab.getHSelf(), tabDpiDynamicalWidth, tabDpiDynamicalHeight);
TabCtrl_SetItemSize(_subDocTab.getHSelf(), tabDpiDynamicalWidth, tabDpiDynamicalHeight);
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
return TRUE;
}
default:
{
if (message == WDN_NOTIFY)

40
PowerEditor/src/NppCommands.cpp

@ -2323,7 +2323,9 @@ void Notepad_plus::command(int id)
case IDM_VIEW_REFRESHTABAR :
{
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
::InvalidateRect(_mainDocTab.getHSelf(), NULL, TRUE);
::InvalidateRect(_subDocTab.getHSelf(), NULL, TRUE);
break;
}
case IDM_VIEW_LOCKTABBAR:
@ -2349,6 +2351,38 @@ void Notepad_plus::command(int id)
{
TabBarPlus::setDrawTabCloseButton(!TabBarPlus::drawTabCloseButton(), &_mainDocTab);
bool drawTabPinButton = TabBarPlus::drawTabPinButton();
bool drawTabCloseButton = TabBarPlus::drawTabCloseButton();
if (drawTabCloseButton && drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(0);
_mainDocTab.setTabPinButtonOrder(1);
_subDocTab.setTabCloseButtonOrder(0);
_subDocTab.setTabPinButtonOrder(1);
}
else if (!drawTabCloseButton && drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(-1);
_mainDocTab.setTabPinButtonOrder(0);
_subDocTab.setTabCloseButtonOrder(-1);
_subDocTab.setTabPinButtonOrder(0);
}
else if (drawTabCloseButton && !drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(0);
_mainDocTab.setTabPinButtonOrder(-1);
_subDocTab.setTabCloseButtonOrder(0);
_subDocTab.setTabPinButtonOrder(-1);
}
else //if (!drawTabCloseButton && !drawTabPinButton)
{
_mainDocTab.setTabCloseButtonOrder(-1);
_mainDocTab.setTabPinButtonOrder(-1);
_subDocTab.setTabCloseButtonOrder(-1);
_subDocTab.setTabPinButtonOrder(-1);
}
// This part is just for updating (redraw) the tabs
int tabDpiDynamicalHeight = _mainDocTab.dpiManager().scale(TabBarPlus::isReduced() ? g_TabHeight : g_TabHeightLarge);
int tabDpiDynamicalWidth = _mainDocTab.dpiManager().scale(TabBarPlus::drawTabCloseButton() ? g_TabWidthCloseBtn : g_TabWidth);
@ -3345,11 +3379,11 @@ void Notepad_plus::command(int id)
}
case IDM_VIEW_GOTO_START:
_pDocTab->currentTabToStart();
_pDocTab->tabToStart();
break;
case IDM_VIEW_GOTO_END:
_pDocTab->currentTabToEnd();
_pDocTab->tabToEnd();
break;
case IDM_VIEW_GOTO_ANOTHER_VIEW:

19
PowerEditor/src/NppIO.cpp

@ -1111,6 +1111,23 @@ bool Notepad_plus::fileClose(BufferID id, int curView)
return true;
}
void Notepad_plus::unPinnedForAllBuffers()
{
for (size_t i = 0; i < _mainDocTab.nbItem(); ++i)
{
BufferID id = _mainDocTab.getBufferByIndex(i);
Buffer* buf = MainFileManager.getBufferByID(id);
buf->setPinned(false);
}
for (size_t i = 0; i < _subDocTab.nbItem(); ++i)
{
BufferID id = _mainDocTab.getBufferByIndex(i);
Buffer* buf = MainFileManager.getBufferByID(id);
buf->setPinned(false);
}
}
bool Notepad_plus::fileCloseAll(bool doDeleteBackup, bool isSnapshotMode)
{
bool noSaveToAll = false;
@ -2407,6 +2424,7 @@ bool Notepad_plus::loadSession(Session & session, bool isSnapshotMode, const wch
buf->setEncoding(session._mainViewFiles[i]._encoding);
buf->setUserReadOnly(session._mainViewFiles[i]._isUserReadOnly);
buf->setPinned(session._mainViewFiles[i]._isPinned);
if (isSnapshotMode && !session._mainViewFiles[i]._backupFilePath.empty() && doesFileExist(session._mainViewFiles[i]._backupFilePath.c_str()))
buf->setDirty(true);
@ -2539,6 +2557,7 @@ bool Notepad_plus::loadSession(Session & session, bool isSnapshotMode, const wch
buf->setLangType(typeToSet, pLn);
buf->setEncoding(session._subViewFiles[k]._encoding);
buf->setUserReadOnly(session._subViewFiles[k]._isUserReadOnly);
buf->setPinned(session._subViewFiles[k]._isPinned);
if (isSnapshotMode && !session._subViewFiles[k]._backupFilePath.empty() && doesFileExist(session._subViewFiles[k]._backupFilePath.c_str()))
buf->setDirty(true);

32
PowerEditor/src/NppNotification.cpp

@ -317,7 +317,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
int index = tabNotification->_tabOrigin;
BufferID bufferToClose = notifyDocTab->getBufferByIndex(index);
Buffer * buf = MainFileManager.getBufferByID(bufferToClose);
int iView = isFromPrimary?MAIN_VIEW:SUB_VIEW;
int iView = isFromPrimary ? MAIN_VIEW : SUB_VIEW;
if (buf->isDirty())
{
activateBuffer(bufferToClose, iView);
@ -333,6 +333,36 @@ BOOL Notepad_plus::notify(SCNotification *notification)
break;
}
case TCN_TABPINNED:
{
int index = tabNotification->_tabOrigin;
BufferID bufferToBePinned = notifyDocTab->getBufferByIndex(index);
Buffer * buf = MainFileManager.getBufferByID(bufferToBePinned);
bool isPinned = buf->isPinned();
if (_mainDocTab.getHSelf() == notification->nmhdr.hwndFrom)
{
if (!isPinned)
_mainDocTab.tabToStart(index);
else
_mainDocTab.tabToEnd(index);
}
else if (_subDocTab.getHSelf() == notification->nmhdr.hwndFrom)
{
if (!isPinned)
_subDocTab.tabToStart(index);
else
_subDocTab.tabToEnd(index);
}
else
return FALSE;
buf->setPinned(!isPinned);
break;
}
case TCN_SELCHANGE:
{
int iView = -1;

22
PowerEditor/src/Parameters.cpp

@ -2440,7 +2440,12 @@ bool NppParameters::getSessionFromXmlTree(TiXmlDocument *pSessionDoc, Session& s
if (boolStrReadOnly)
isUserReadOnly = _wcsicmp(L"yes", boolStrReadOnly) == 0;
sessionFileInfo sfi(fileName, langName, encStr ? encoding : -1, isUserReadOnly, position, backupFilePath, fileModifiedTimestamp, mapPosition);
bool isPinned = false;
const wchar_t* boolStrPinned = (childNode->ToElement())->Attribute(L"tabPinned");
if (boolStrPinned)
isPinned = _wcsicmp(L"yes", boolStrPinned) == 0;
sessionFileInfo sfi(fileName, langName, encStr ? encoding : -1, isUserReadOnly, isPinned, position, backupFilePath, fileModifiedTimestamp, mapPosition);
const wchar_t* intStrTabColour = (childNode->ToElement())->Attribute(L"tabColourId");
if (intStrTabColour)
@ -3675,6 +3680,7 @@ void NppParameters::writeSession(const Session & session, const wchar_t *fileNam
(fileNameNode->ToElement())->SetAttribute(L"originalFileLastModifTimestampHigh", static_cast<int32_t>(viewSessionFiles[i]._originalFileLastModifTimestamp.dwHighDateTime));
(fileNameNode->ToElement())->SetAttribute(L"tabColourId", static_cast<int32_t>(viewSessionFiles[i]._individualTabColour));
(fileNameNode->ToElement())->SetAttribute(L"RTL", viewSessionFiles[i]._isRTL ? L"yes" : L"no");
(fileNameNode->ToElement())->SetAttribute(L"tabPinned", viewSessionFiles[i]._isPinned ? L"yes" : L"no");
// docMap
(fileNameNode->ToElement())->SetAttribute(L"mapFirstVisibleDisplayLine", _i64tot(static_cast<LONGLONG>(viewSessionFiles[i]._mapPos._firstVisibleDisplayLine), szInt64, 10));
@ -4908,6 +4914,17 @@ void NppParameters::feedGUIParameters(TiXmlNode *node)
isFailed = true;
}
val = element->Attribute(L"pinButton");
if (val)
{
if (!lstrcmp(val, L"yes"))
_nppGUI._tabStatus |= TAB_PINBUTTON;
else if (!lstrcmp(val, L"no"))
_nppGUI._tabStatus |= 0;
else
isFailed = true;
}
val = element->Attribute(L"doubleClick2Close");
if (val)
{
@ -7243,6 +7260,9 @@ void NppParameters::createXmlTreeFromGUIParams()
pStr = (_nppGUI._tabStatus & TAB_CLOSEBUTTON) ? L"yes" : L"no";
GUIConfigElement->SetAttribute(L"closeButton", pStr);
pStr = (_nppGUI._tabStatus & TAB_PINBUTTON) ? L"yes" : L"no";
GUIConfigElement->SetAttribute(L"pinButton", pStr);
pStr = (_nppGUI._tabStatus & TAB_DBCLK2CLOSE) ? L"yes" : L"no";
GUIConfigElement->SetAttribute(L"doubleClick2Close", pStr);

16
PowerEditor/src/Parameters.h

@ -75,6 +75,7 @@ const int TAB_MULTILINE = 128; //0000 1000 0000
const int TAB_HIDE = 256; //0001 0000 0000
const int TAB_QUITONEMPTY = 512; //0010 0000 0000
const int TAB_ALTICONS = 1024; //0100 0000 0000
const int TAB_PINBUTTON = 2048; //1000 0000 0000
const bool activeText = true;
const bool activeNumeric = false;
@ -216,8 +217,8 @@ public:
struct sessionFileInfo : public Position
{
sessionFileInfo(const wchar_t* fn, const wchar_t *ln, int encoding, bool userReadOnly, const Position& pos, const wchar_t *backupFilePath, FILETIME originalFileLastModifTimestamp, const MapPosition & mapPos) :
Position(pos), _encoding(encoding), _isUserReadOnly(userReadOnly), _originalFileLastModifTimestamp(originalFileLastModifTimestamp), _mapPos(mapPos)
sessionFileInfo(const wchar_t* fn, const wchar_t *ln, int encoding, bool userReadOnly,bool isPinned, const Position& pos, const wchar_t *backupFilePath, FILETIME originalFileLastModifTimestamp, const MapPosition & mapPos) :
Position(pos), _encoding(encoding), _isUserReadOnly(userReadOnly), _isPinned(isPinned), _originalFileLastModifTimestamp(originalFileLastModifTimestamp), _mapPos(mapPos)
{
if (fn) _fileName = fn;
if (ln) _langName = ln;
@ -235,6 +236,7 @@ struct sessionFileInfo : public Position
bool _isMonitoring = false;
int _individualTabColour = -1;
bool _isRTL = false;
bool _isPinned = false;
std::wstring _backupFilePath;
FILETIME _originalFileLastModifTimestamp {};
@ -791,15 +793,7 @@ struct NppGUI final
bool _statusBarShow = true;
bool _menuBarShow = true;
// 1st bit : draw top bar;
// 2nd bit : draw inactive tabs
// 3rd bit : enable drag & drop
// 4th bit : reduce the height
// 5th bit : enable vertical
// 6th bit : enable multiline
// 0:don't draw; 1:draw top bar 2:draw inactive tabs 3:draw both 7:draw both+drag&drop
int _tabStatus = (TAB_DRAWTOPBAR | TAB_DRAWINACTIVETAB | TAB_DRAGNDROP | TAB_REDUCE | TAB_CLOSEBUTTON);
int _tabStatus = (TAB_DRAWTOPBAR | TAB_DRAWINACTIVETAB | TAB_DRAGNDROP | TAB_REDUCE | TAB_CLOSEBUTTON | TAB_PINBUTTON);
bool _splitterPos = POS_VERTICAL;
int _userDefineDlgStatus = UDD_DOCKED;

4
PowerEditor/src/ScintillaComponent/Buffer.h

@ -362,6 +362,9 @@ public:
bool isRTL() const { return _isRTL; };
void setRTL(bool isRTL) { _isRTL = isRTL; };
bool isPinned() const { return _isPinned; };
void setPinned(bool isPinned) { _isPinned = isPinned; };
private:
int indexOfReference(const ScintillaEditView * identifier) const;
@ -445,4 +448,5 @@ private:
bool _isInaccessible = false;
bool _isRTL = false;
bool _isPinned = false;
};

12
PowerEditor/src/WinControls/ColourPicker/WordStyleDlg.rc

@ -64,13 +64,13 @@ BEGIN
LTEXT "User-defined keywords",IDC_USER_KEYWORDS_STATIC,350,135,126,8
EDITTEXT IDC_USER_KEYWORDS_EDIT,347,146,136,52,ES_MULTILINE | WS_VSCROLL
CONTROL "Force foreground color for all styles",IDC_GLOBAL_FG_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,191,134,132,10
CONTROL "Force background color for all styles",IDC_GLOBAL_BG_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,191,149,132,10
CONTROL "Force foreground color for all styles",IDC_GLOBAL_FG_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,191,134,153,10
CONTROL "Force background color for all styles",IDC_GLOBAL_BG_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,191,149,153,10
CONTROL "Force font choice for all styles",IDC_GLOBAL_FONT_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,134,153,10
CONTROL "Force font size choice for all styles",IDC_GLOBAL_FONTSIZE_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,149,135,10
CONTROL "Force bold choice for all styles",IDC_GLOBAL_BOLD_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,164,135,10
CONTROL "Force italic choice for all styles",IDC_GLOBAL_ITALIC_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,179,135,10
CONTROL "Force underline choice for all styles",IDC_GLOBAL_UNDERLINE_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,194,135,10
CONTROL "Force font size choice for all styles",IDC_GLOBAL_FONTSIZE_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,149, 153,10
CONTROL "Force bold choice for all styles",IDC_GLOBAL_BOLD_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,164,153,10
CONTROL "Force italic choice for all styles",IDC_GLOBAL_ITALIC_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,179,153,10
CONTROL "Force underline choice for all styles",IDC_GLOBAL_UNDERLINE_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,327,194,153,10
LTEXT "Go to settings",IDC_GLOBAL_GOTOSETTINGS_LINK,210,153,131,10,WS_TABSTOP
LTEXT "What is Global override?",IDC_GLOBAL_WHATISGLOBALOVERRIDE_LINK,191,173,132,10,WS_TABSTOP

56
PowerEditor/src/WinControls/Preference/preference.rc

@ -38,39 +38,35 @@ IDD_PREFERENCE_SUB_GENRAL DIALOGEX 115, 10, 460, 205
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
GROUPBOX "Localization",IDC_LOCALIZATION_GB_STATIC,27,3,186,30,BS_CENTER
GROUPBOX "Localization",IDC_LOCALIZATION_GB_STATIC,27,0,186,36,BS_CENTER
COMBOBOX IDC_COMBO_LOCALIZATION,60,14,125,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Status Bar",IDC_STATUSBAR_GB_STATIC,27,37,186,27,BS_CENTER
CONTROL "Hide",IDC_CHECK_HIDESTATUSBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,48,174,10
GROUPBOX "Toolbar",IDC_TOOLBAR_GB_STATIC,27,68,186,88,BS_CENTER
CONTROL "Hide",IDC_CHECK_HIDE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,76,100,10
CONTROL "Fluent UI: small",IDC_RADIO_SMALLICON,"Button",BS_AUTORADIOBUTTON,33,91,174,10
CONTROL "Fluent UI: large",IDC_RADIO_BIGICON,"Button",BS_AUTORADIOBUTTON,33,104,174,10
CONTROL "Filled Fluent UI: small",IDC_RADIO_SMALLICON2,"Button",BS_AUTORADIOBUTTON,33,117,174,10
CONTROL "Filled Fluent UI: large",IDC_RADIO_BIGICON2,"Button",BS_AUTORADIOBUTTON,33,130,174,10
CONTROL "Standard icons: small",IDC_RADIO_STANDARD,"Button",BS_AUTORADIOBUTTON,33,143,174,10
GROUPBOX "Tab Bar",IDC_TABBAR_GB_STATIC,223,3,177,153,BS_CENTER
CONTROL "Hide",IDC_CHECK_TAB_HIDE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,11,100,10
CONTROL "Multi-line",IDC_CHECK_TAB_MULTILINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,26,164,10
CONTROL "Vertical",IDC_CHECK_TAB_VERTICAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,39,164,10
CONTROL "Reduce",IDC_CHECK_REDUCE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,52,164,10
CONTROL "Alternate icons",IDC_CHECK_TAB_ALTICONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,65,164,10
CONTROL "Lock (no drag and drop)",IDC_CHECK_LOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,78,164,10
CONTROL "Darken inactive tabs",IDC_CHECK_DRAWINACTIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,91,164,10
CONTROL "Draw a coloured bar on active tab",IDC_CHECK_ORANGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,104,164,10
CONTROL "Show close button on each tab",IDC_CHECK_ENABLETABCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,117,164,10
CONTROL "Double click to close document",IDC_CHECK_DBCLICK2CLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,130,164,10
CONTROL "Exit on close the last tab",IDC_CHECK_TAB_LAST_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,143,164,10
GROUPBOX "Menu",IDC_MENU_GB_STATIC,27,160,373,34,BS_CENTER
CONTROL "Hide menu bar (use Alt or F10 key to toggle)",IDC_CHECK_HIDEMENUBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,168,218,10
CONTROL "Hide right shortcuts + ▼ ✕ from the menu bar (Need to restart Notepad++)",IDC_CHECK_HIDERIGHTSHORTCUTSOFMENUBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,181,350,10
GROUPBOX "Status Bar",IDC_STATUSBAR_GB_STATIC,27,39,186,31,BS_CENTER
CONTROL "Hide",IDC_CHECK_HIDESTATUSBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,52,174,10
GROUPBOX "Toolbar",IDC_TOOLBAR_GB_STATIC,27,75,186,91,BS_CENTER
CONTROL "Hide",IDC_CHECK_HIDE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,84,100,10
CONTROL "Fluent UI: small",IDC_RADIO_SMALLICON,"Button",BS_AUTORADIOBUTTON,33,100,174,10
CONTROL "Fluent UI: large",IDC_RADIO_BIGICON,"Button",BS_AUTORADIOBUTTON,33,113,174,10
CONTROL "Filled Fluent UI: small",IDC_RADIO_SMALLICON2,"Button",BS_AUTORADIOBUTTON,33,126,174,10
CONTROL "Filled Fluent UI: large",IDC_RADIO_BIGICON2,"Button",BS_AUTORADIOBUTTON,33,139,174,10
CONTROL "Standard icons: small",IDC_RADIO_STANDARD,"Button",BS_AUTORADIOBUTTON,33,152,174,10
GROUPBOX "Tab Bar",IDC_TABBAR_GB_STATIC,223,0,177,166,BS_CENTER
CONTROL "Hide",IDC_CHECK_TAB_HIDE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,8,100,10
CONTROL "Multi-line",IDC_CHECK_TAB_MULTILINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,21,164,10
CONTROL "Vertical",IDC_CHECK_TAB_VERTICAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,34,164,10
CONTROL "Reduce",IDC_CHECK_REDUCE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,47,164,10
CONTROL "Alternate icons",IDC_CHECK_TAB_ALTICONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,60,164,10
CONTROL "Lock (no drag and drop)",IDC_CHECK_LOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,73,164,10
CONTROL "Darken inactive tabs",IDC_CHECK_DRAWINACTIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,86,164,10
CONTROL "Draw a coloured bar on active tab",IDC_CHECK_ORANGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,99,164,10
CONTROL "Show close button on each tab",IDC_CHECK_ENABLETABCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,112,164,10
CONTROL "Enable pin tab feature", IDC_CHECK_ENABLETABPIN,"Button", BS_AUTOCHECKBOX | WS_TABSTOP, 229, 125, 164, 10
CONTROL "Double click to close document",IDC_CHECK_DBCLICK2CLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,138,164,10
CONTROL "Exit on close the last tab",IDC_CHECK_TAB_LAST_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,229,151,164,10
GROUPBOX "Menu",IDC_MENU_GB_STATIC,27,168,373,34,BS_CENTER
CONTROL "Hide menu bar (use Alt or F10 key to toggle)",IDC_CHECK_HIDEMENUBAR, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,176,218,10
CONTROL "Hide right shortcuts + ? ? from the menu bar (Need to restart Notepad++)",IDC_CHECK_HIDERIGHTSHORTCUTSOFMENUBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,189,350,10
END
IDD_PREFERENCE_SUB_EDITING DIALOGEX 115, 10, 460, 205
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x1

6
PowerEditor/src/WinControls/Preference/preferenceDlg.cpp

@ -610,6 +610,7 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
::SendDlgItemMessage(_hSelf, IDC_CHECK_ORANGE, BM_SETCHECK, tabBarStatus & TAB_DRAWTOPBAR, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_DRAWINACTIVE, BM_SETCHECK, tabBarStatus & TAB_DRAWINACTIVETAB, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_ENABLETABCLOSE, BM_SETCHECK, tabBarStatus & TAB_CLOSEBUTTON, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_ENABLETABPIN, BM_SETCHECK, tabBarStatus & TAB_PINBUTTON, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_DBCLICK2CLOSE, BM_SETCHECK, tabBarStatus & TAB_DBCLK2CLOSE, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_TAB_VERTICAL, BM_SETCHECK, tabBarStatus & TAB_VERTICAL, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_TAB_MULTILINE, BM_SETCHECK, tabBarStatus & TAB_MULTILINE, 0);
@ -699,6 +700,7 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_ORANGE), !toBeHidden);
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_DRAWINACTIVE), !toBeHidden);
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_ENABLETABCLOSE), !toBeHidden);
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_ENABLETABPIN), !toBeHidden);
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_DBCLICK2CLOSE), !toBeHidden);
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_TAB_LAST_EXIT), !toBeHidden);
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_TAB_ALTICONS), !toBeHidden);
@ -757,6 +759,10 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
::SendMessage(_hParent, WM_COMMAND, IDM_VIEW_DRAWTABBAR_CLOSEBOTTUN, 0);
return TRUE;
case IDC_CHECK_ENABLETABPIN:
::SendMessage(::GetParent(_hParent), NPPM_INTERNAL_DRAWTABBARPINBOTTUN, 0, 0);
return TRUE;
case IDC_CHECK_DBCLICK2CLOSE :
::SendMessage(_hParent, WM_COMMAND, IDM_VIEW_DRAWTABBAR_DBCLK2CLOSE, 0);
return TRUE;

2
PowerEditor/src/WinControls/Preference/preference_rc.h

@ -40,7 +40,7 @@
#define IDC_CHECK_ENABLETABCLOSE (IDD_PREFERENCE_SUB_GENRAL + 12)
#define IDC_CHECK_DBCLICK2CLOSE (IDD_PREFERENCE_SUB_GENRAL + 13)
#define IDC_CHECK_ENABLEDOCSWITCHER (IDD_PREFERENCE_SUB_GENRAL + 14)
//#define IDC_CHECK_MAINTAININDENT (IDD_PREFERENCE_SUB_GENRAL + 15)
#define IDC_CHECK_ENABLETABPIN (IDD_PREFERENCE_SUB_GENRAL + 15)
#define IDC_CHECK_KEEPINSAMEDIR (IDD_PREFERENCE_SUB_GENRAL + 16)
#define IDC_CHECK_STYLEMRU (IDD_PREFERENCE_SUB_GENRAL + 17)
#define IDC_CHECK_TAB_HIDE (IDD_PREFERENCE_SUB_GENRAL + 18)

327
PowerEditor/src/WinControls/TabBar/TabBar.cpp

@ -15,6 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <stdexcept>
#include "Buffer.h"
#include "TabBar.h"
#include "Parameters.h"
#include "DoubleBuffer/DoubleBuffer.h"
@ -28,7 +29,8 @@ bool TabBarPlus::_doDragNDrop = false;
bool TabBarPlus::_drawTopBar = true;
bool TabBarPlus::_drawInactiveTab = true;
bool TabBarPlus::_drawTabCloseButton = false;
bool TabBarPlus::_drawTabCloseButton = true;
bool TabBarPlus::_drawTabPinButton = true;
bool TabBarPlus::_isDbClk2Close = false;
bool TabBarPlus::_isCtrlVertical = false;
bool TabBarPlus::_isCtrlMultiLine = false;
@ -277,6 +279,12 @@ void TabBarPlus::destroy()
::ImageList_Destroy(_hCloseBtnImgLst);
_hCloseBtnImgLst = nullptr;
}
if (_hPinBtnImgLst != nullptr)
{
::ImageList_Destroy(_hPinBtnImgLst);
_hPinBtnImgLst = nullptr;
}
}
@ -285,7 +293,8 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult
Window::init(hInst, parent);
const UINT dpi = DPIManagerV2::getDpiForWindow(_hParent);
_closeButtonZone.setParent(_hParent);
_closeButtonZone.init(_hParent, 0);
_pinButtonZone.init(_hParent, 1);
_dpiManager.setDpi(dpi);
int vertical = isVertical ? (TCS_VERTICAL | TCS_MULTILINE | TCS_RIGHTJUSTIFY) : 0;
@ -350,6 +359,7 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult
setFont();
setCloseBtnImageList();
setPinBtnImageList();
}
void TabBar::setFont()
@ -405,9 +415,21 @@ void TabBarPlus::doOwnerDrawTab(TabBarPlus* tbpObj)
if (tbpObj)
{
const int paddingSizeDynamicW = tbpObj->_dpiManager.scale(6);
const int paddingSizePlusClosebuttonDynamicW = tbpObj->_dpiManager.scale(10);
::SendMessage(_hwndArray[i], TCM_SETPADDING, 0, MAKELPARAM(_drawTabCloseButton ? paddingSizePlusClosebuttonDynamicW : paddingSizeDynamicW, 0));
int paddingSize = 0;
if (_drawTabCloseButton && _drawTabPinButton) // 2 buttons
{
paddingSize = 16;
}
else if (!_drawTabCloseButton && !_drawTabPinButton) // no button
{
paddingSize = 6;
}
else // only 1 button
{
paddingSize = 10;
}
const int paddingSizeDynamicW = tbpObj->_dpiManager.scale(paddingSize);
::SendMessage(_hwndArray[i], TCM_SETPADDING, 0, MAKELPARAM(paddingSizeDynamicW, 0));
}
}
}
@ -439,27 +461,33 @@ void TabBarPlus::setColour(COLORREF colour2Set, tabColourIndex i, TabBarPlus* tb
doOwnerDrawTab(tbpObj);
}
void TabBarPlus::currentTabToStart()
void TabBarPlus::tabToStart(int index)
{
int currentTabIndex = getCurrentTabIndex();
if (currentTabIndex <= 0)
if (index < 0 || index >= static_cast<int>(_nbItem))
index = getCurrentTabIndex();
if (index <= 0)
return;
for (int i = currentTabIndex, j = currentTabIndex - 1; j >= 0; --i, --j)
for (int i = index, j = index - 1; j >= 0; --i, --j)
{
exchangeTabItemData(i, j);
if (!exchangeTabItemData(i, j))
break;
}
}
void TabBarPlus::currentTabToEnd()
void TabBarPlus::tabToEnd(int index)
{
int currentTabIndex = getCurrentTabIndex();
if (currentTabIndex >= static_cast<int>(_nbItem))
if (index < 0 || index >= static_cast<int>(_nbItem))
index = getCurrentTabIndex();
if (index >= static_cast<int>(_nbItem))
return;
for (int i = currentTabIndex, j = currentTabIndex + 1; j < static_cast<int>(_nbItem); ++i, ++j)
for (int i = index, j = index + 1; j < static_cast<int>(_nbItem); ++i, ++j)
{
exchangeTabItemData(i, j);
if (!exchangeTabItemData(i, j))
break;
}
}
@ -501,6 +529,45 @@ void TabBarPlus::setCloseBtnImageList()
_closeButtonZone._height = btnSize;
}
void TabBarPlus::setPinBtnImageList()
{
int iconSize = 0;
std::vector<int> ids;
if (NppDarkMode::isEnabled())
{
iconSize = g_TabPinBtnSize_DM;
ids = { IDR_PINTAB_DM, IDR_PINTAB_HOVER_DM, IDR_PINTAB_PINNED_DM, IDR_PINTAB_PINNEDHOVER_DM };
}
else
{
iconSize = g_TabPinBtnSize;
ids = { IDR_PINTAB, IDR_PINTAB_HOVER, IDR_PINTAB_PINNED, IDR_PINTAB_PINNEDHOVER };
}
if (_hPinBtnImgLst != nullptr)
{
::ImageList_Destroy(_hPinBtnImgLst);
_hPinBtnImgLst = nullptr;
}
const int btnSize = _dpiManager.scale(iconSize);
_hPinBtnImgLst = ::ImageList_Create(btnSize, btnSize, ILC_COLOR32 | ILC_MASK, static_cast<int>(ids.size()), 0);
for (const auto& id : ids)
{
HICON hIcon = nullptr;
DPIManagerV2::loadIcon(_hInst, MAKEINTRESOURCE(id), btnSize, btnSize, &hIcon);
::ImageList_AddIcon(_hPinBtnImgLst, hIcon);
::DestroyIcon(hIcon);
}
_pinButtonZone._width = btnSize;
_pinButtonZone._height = btnSize;
}
void TabBarPlus::doVertical()
{
for (int i = 0 ; i < _nbCtrl ; ++i)
@ -566,6 +633,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
{
NppDarkMode::setDarkTooltips(hwnd, NppDarkMode::ToolTipsType::tabbar);
setCloseBtnImageList();
setPinBtnImageList();
return TRUE;
}
@ -667,9 +735,10 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
// clear hover state of the close button,
// WM_MOUSEMOVE won't handle this properly since the tab position will change
if (_isCloseHover)
if (_isCloseHover || _isPinHover)
{
_isCloseHover = false;
_isPinHover = false;
::InvalidateRect(_hSelf, &_currentHoverTabRect, false);
}
@ -681,9 +750,12 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
case WM_LBUTTONDOWN :
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
if (::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS)
{
int nTab = getTabIndexAt(LOWORD(lParam), HIWORD(lParam));
int nTab = getTabIndexAt(xPos, yPos);
if (nTab != -1 && nTab != static_cast<int32_t>(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0)))
{
setActiveTab(nTab);
@ -692,9 +764,6 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
if (_drawTabCloseButton)
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
if (_closeButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical))
{
_whichCloseClickDown = getTabIndexAt(xPos, yPos);
@ -703,6 +772,16 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
}
}
if (_drawTabPinButton)
{
if (_pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical))
{
_whichPinClickDown = getTabIndexAt(xPos, yPos);
::SendMessage(_hParent, WM_COMMAND, IDM_VIEW_REFRESHTABAR, 0);
return TRUE;
}
}
::CallWindowProc(_tabBarDefaultProc, hwnd, Message, wParam, lParam);
int currentTabOn = static_cast<int32_t>(::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0));
@ -822,7 +901,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
RECT currentHoverTabRectOld = _currentHoverTabRect;
bool isCloseHoverOld = _isCloseHover;
if (_currentHoverTabItem != -1) // is hovering
if (_currentHoverTabItem != -1) // tab item is being hovered
{
::SendMessage(_hSelf, TCM_GETITEMRECT, _currentHoverTabItem, reinterpret_cast<LPARAM>(&_currentHoverTabRect));
_isCloseHover = _closeButtonZone.isHit(p.x, p.y, _currentHoverTabRect, _isVertical);
@ -848,6 +927,39 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
trackMouseEvent(TME_LEAVE);
}
}
if (_drawTabPinButton)
{
RECT currentHoverTabRectOld = _currentHoverTabRect;
bool isPinHoverOld = _isPinHover;
if (_currentHoverTabItem != -1) // tab item is being hovered
{
::SendMessage(_hSelf, TCM_GETITEMRECT, _currentHoverTabItem, reinterpret_cast<LPARAM>(&_currentHoverTabRect));
_isPinHover = _pinButtonZone.isHit(p.x, p.y, _currentHoverTabRect, _isVertical);
_isPinHover = _pinButtonZone.isHit(p.x, p.y, _currentHoverTabRect, _isVertical);
}
else
{
SetRectEmpty(&_currentHoverTabRect);
_isPinHover = false;
}
if (isFromTabToTab || _isPinHover != isPinHoverOld)
{
if (isPinHoverOld && (isFromTabToTab || !_isPinHover))
InvalidateRect(hwnd, &currentHoverTabRectOld, FALSE);
if (_isPinHover)
InvalidateRect(hwnd, &_currentHoverTabRect, FALSE);
}
if (_isPinHover)
{
// Mouse moves out from pin 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);
@ -858,13 +970,15 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
case WM_MOUSELEAVE:
{
if (_isCloseHover)
if (_isCloseHover || _isPinHover)
InvalidateRect(hwnd, &_currentHoverTabRect, FALSE);
_currentHoverTabItem = -1;
_whichCloseClickDown = -1;
_whichPinClickDown = -1;
SetRectEmpty(&_currentHoverTabRect);
_isCloseHover = false;
_isPinHover = false;
notify(TCN_MOUSELEAVING, _currentHoverTabItem);
break;
@ -915,6 +1029,28 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
_whichCloseClickDown = -1;
}
if (_drawTabPinButton)
{
if ((_whichPinClickDown == currentTabOn) && _pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical))
{
notify(TCN_TABPINNED, currentTabOn);
_whichPinClickDown = -1;
// Get the next tab at same position
// If valid tab is found then
// update the current hover tab RECT (_currentHoverTabRect)
// update pin hover flag (_isPinHover), 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<LPARAM>(&_currentHoverTabRect));
_isPinHover = _pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical);
}
return TRUE;
}
_whichPinClickDown = -1;
}
break;
}
@ -1144,29 +1280,22 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
return ::CallWindowProc(_tabBarDefaultProc, hwnd, Message, wParam, lParam);
}
void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
{
RECT rect = pDrawItemStruct->rcItem;
int nTab = pDrawItemStruct->itemID;
if (nTab < 0)
{
::MessageBox(NULL, L"nTab < 0", L"", MB_OK);
}
assert(nTab >= 0);
bool isSelected = (nTab == ::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0));
wchar_t label[MAX_PATH] = { '\0' };
TCITEM tci{};
tci.mask = TCIF_TEXT|TCIF_IMAGE;
tci.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
tci.pszText = label;
tci.cchTextMax = MAX_PATH-1;
if (!::SendMessage(_hSelf, TCM_GETITEM, nTab, reinterpret_cast<LPARAM>(&tci)))
{
std::wstring errorMessageTitle = L"TabBarPlus::drawItem wrong: ! TCM_GETITEM";
std::wstring errorMessage = GetLastErrorAsString(GetLastError());
::MessageBox(NULL, errorMessage.c_str(), errorMessageTitle.c_str(), MB_OK);
}
::SendMessage(_hSelf, TCM_GETITEM, nTab, reinterpret_cast<LPARAM>(&tci));
const COLORREF colorActiveBg = isDarkMode ? NppDarkMode::getSofterBackgroundColor() : ::GetSysColor(COLOR_BTNFACE);
const COLORREF colorInactiveBgBase = isDarkMode ? NppDarkMode::getBackgroundColor() : ::GetSysColor(COLOR_BTNFACE);
@ -1322,22 +1451,22 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
{
// 3 status for each inactive tab and selected tab close item :
// normal / hover / pushed
int idxCloseImg = 0; // selected
int idxCloseImg = _closeTabIdx; // selected
if (_isCloseHover && (_currentHoverTabItem == nTab))
{
if (_whichCloseClickDown == -1) // hover
{
idxCloseImg += 2;
idxCloseImg = _closeTabHoverIdx;
}
else if (_whichCloseClickDown == _currentHoverTabItem) // pushed
{
idxCloseImg += 3;
idxCloseImg = _closeTabPushIdx;
}
}
else if (!isSelected) // inactive
{
idxCloseImg += 1;
idxCloseImg = _closeTabInactIdx;
}
RECT buttonRect = _closeButtonZone.getButtonRectFrom(rect, _isVertical);
@ -1345,6 +1474,82 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
::ImageList_Draw(_hCloseBtnImgLst, idxCloseImg, hDC, buttonRect.left, buttonRect.top, ILD_TRANSPARENT);
}
// draw pin button
if (_drawTabPinButton && _hPinBtnImgLst != nullptr)
{
// Each tab combined with the following stats :
// (active / inactive) | (pinned / unpinned) | (hover / not hover / pushed)
bool isPinned = reinterpret_cast<Buffer*>(tci.lParam)->isPinned();
int idxPinImg = _unpinnedIdx; // current: upinned as default
if (isPinned)
{
if (!isSelected) // inactive
{
if (_isPinHover && (_currentHoverTabItem == nTab))
{
if (_whichPinClickDown == -1) // hover
{
idxPinImg = _pinnedHoverIdx;
}
else if (_whichPinClickDown == _currentHoverTabItem) // pushed
{
idxPinImg = _unpinnedIdx;
}
}
else // pinned inactive
{
idxPinImg = _pinnedIdx;
}
}
else // current
{
if (_isPinHover && (_currentHoverTabItem == nTab)) // hover
idxPinImg = _pinnedHoverIdx;
else
idxPinImg = _pinnedIdx;
}
}
else // unpinned
{
if (!isSelected) // inactive
{
if (_isPinHover && (_currentHoverTabItem == nTab))
{
if (_whichPinClickDown == -1) // hover
{
idxPinImg = _unpinnedHoverIdx;
}
else if (_whichPinClickDown == _currentHoverTabItem) // pushed
{
idxPinImg = _pinnedIdx;
}
}
else // unpinned inactive
{
idxPinImg = _unpinnedIdx;
}
}
else // current
{
if (_isPinHover && (_currentHoverTabItem == nTab)) // hover
idxPinImg = _unpinnedHoverIdx;
else
idxPinImg = _unpinnedIdx;
}
}
RECT buttonRect = _pinButtonZone.getButtonRectFrom(rect, _isVertical);
::ImageList_Draw(_hPinBtnImgLst, idxPinImg, hDC, buttonRect.left, buttonRect.top, ILD_TRANSPARENT);
}
// draw image
HIMAGELIST hImgLst = (HIMAGELIST)::SendMessage(_hSelf, TCM_GETIMAGELIST, 0, 0);
@ -1496,7 +1701,7 @@ void TabBarPlus::setActiveTab(int tabIndex)
notify(TCN_SELCHANGE, tabIndex);
}
void TabBarPlus::exchangeTabItemData(int oldTab, int newTab)
bool TabBarPlus::exchangeTabItemData(int oldTab, int newTab)
{
//1. shift their data, and insert the source
TCITEM itemData_nDraggedTab{}, itemData_shift{};
@ -1512,10 +1717,18 @@ void TabBarPlus::exchangeTabItemData(int oldTab, int newTab)
itemData_shift.cchTextMax = (stringSize);
::SendMessage(_hSelf, TCM_GETITEM, oldTab, reinterpret_cast<LPARAM>(&itemData_nDraggedTab));
Buffer* chosenBuf = reinterpret_cast<Buffer*>(itemData_nDraggedTab.lParam);
::SendMessage(_hSelf, TCM_GETITEM, newTab, reinterpret_cast<LPARAM>(&itemData_shift));
Buffer* shiftBuf = reinterpret_cast<Buffer*>(itemData_shift.lParam);
if (chosenBuf->isPinned() != shiftBuf->isPinned())
return false;
int i = oldTab;
if (oldTab > newTab)
{
for (int i = oldTab; i > newTab; i--)
for (; i > newTab; i--)
{
::SendMessage(_hSelf, TCM_GETITEM, i - 1, reinterpret_cast<LPARAM>(&itemData_shift));
::SendMessage(_hSelf, TCM_SETITEM, i, reinterpret_cast<LPARAM>(&itemData_shift));
@ -1523,12 +1736,13 @@ void TabBarPlus::exchangeTabItemData(int oldTab, int newTab)
}
else
{
for (int i = oldTab; i < newTab; ++i)
for (; i < newTab; ++i)
{
::SendMessage(_hSelf, TCM_GETITEM, i + 1, reinterpret_cast<LPARAM>(&itemData_shift));
::SendMessage(_hSelf, TCM_SETITEM, i, reinterpret_cast<LPARAM>(&itemData_shift));
}
}
::SendMessage(_hSelf, TCM_SETITEM, newTab, reinterpret_cast<LPARAM>(&itemData_nDraggedTab));
// Tell Notepad_plus to notifiy plugins that a D&D operation was done (so doc index has been changed)
@ -1536,6 +1750,8 @@ void TabBarPlus::exchangeTabItemData(int oldTab, int newTab)
//2. set to focus
setActiveTab(newTab);
return true;
}
void TabBarPlus::exchangeItemData(POINT point)
@ -1556,10 +1772,12 @@ void TabBarPlus::exchangeItemData(POINT point)
return;
}
exchangeTabItemData(_nTabDragged, nTab);
if (exchangeTabItemData(_nTabDragged, nTab))
{
_previousTabSwapped = _nTabDragged;
_nTabDragged = nTab;
}
}
else
{
_previousTabSwapped = -1;
@ -1571,11 +1789,10 @@ void TabBarPlus::exchangeItemData(POINT point)
_previousTabSwapped = -1;
_isDraggingInside = false;
}
}
bool CloseButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical) const
bool TabButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical) const
{
RECT buttonRect = getButtonRectFrom(tabRect, isVertical);
@ -1585,22 +1802,42 @@ bool CloseButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical)
return false;
}
RECT CloseButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical) const
RECT TabButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical) const
{
RECT buttonRect{};
const UINT dpi = DPIManagerV2::getDpiForWindow(_parent);
const int inBetween = DPIManagerV2::scale(NppDarkMode::isEnabled() ? 4 : 8, dpi);
int fromBorder = 0;
if (isVertical)
{
fromBorder = (tabRect.right - tabRect.left - _width + 1) / 2;
if (_order == 0)
{
buttonRect.top = tabRect.top + fromBorder;
}
else if (_order == 1)
{
buttonRect.top = tabRect.top + fromBorder + _height + inBetween;
}
buttonRect.left = tabRect.left + fromBorder;
}
else
{
fromBorder = (tabRect.bottom - tabRect.top - _height + 1) / 2;
if (_order == 0)
{
buttonRect.left = tabRect.right - fromBorder - _width;
}
else if (_order == 1)
{
buttonRect.left = tabRect.right - fromBorder - _width * 2 - inBetween;
}
buttonRect.top = tabRect.top + fromBorder;
}
buttonRect.bottom = buttonRect.top + _height;
buttonRect.right = buttonRect.left + _width;

52
PowerEditor/src/WinControls/TabBar/TabBar.h

@ -36,6 +36,7 @@
#define TCN_MOUSEHOVERING (TCN_FIRST - 13)
#define TCN_MOUSELEAVING (TCN_FIRST - 14)
#define TCN_MOUSEHOVERSWITCHING (TCN_FIRST - 15)
#define TCN_TABPINNED (TCN_FIRST - 16)
#define WM_TABSETSTYLE (WM_APP + 0x024)
@ -65,7 +66,9 @@ constexpr int g_TabHeightLarge = 25;
constexpr int g_TabWidth = 45;
constexpr int g_TabWidthCloseBtn = 60;
constexpr int g_TabCloseBtnSize = 11;
constexpr int g_TabPinBtnSize = 11;
constexpr int g_TabCloseBtnSize_DM = 16;
constexpr int g_TabPinBtnSize_DM = 16;
struct TBHDR
{
@ -148,15 +151,21 @@ protected:
};
struct CloseButtonZone
struct TabButtonZone
{
void init(HWND parent, int order) {
_parent = parent;
_order = order;
}
bool isHit(int x, int y, const RECT & tabRect, bool isVertical) const;
RECT getButtonRectFrom(const RECT & tabRect, bool isVertical) const;
void setParent(HWND parent) { _parent = parent; }
void setOrder(int newOrder) { _order = newOrder; };
HWND _parent = nullptr;
int _width = 0;
int _height = 0;
int _order = -1; // from right to left: 0, 1
};
@ -200,6 +209,7 @@ public :
static bool drawTopBar() {return _drawTopBar;};
static bool drawInactiveTab() {return _drawInactiveTab;};
static bool drawTabCloseButton() {return _drawTabCloseButton;};
static bool drawTabPinButton() {return _drawTabPinButton;};
static bool isDbClk2Close() {return _isDbClk2Close;};
static bool isVertical() { return _isCtrlVertical;};
static bool isMultiLine() { return _isCtrlMultiLine;};
@ -220,6 +230,11 @@ public :
doOwnerDrawTab(tbpObj);
}
static void setDrawTabPinButton(bool b, TabBarPlus* tbpObj) {
_drawTabPinButton = b;
doOwnerDrawTab(tbpObj);
}
static void setDbClk2Close(bool b) {
_isDbClk2Close = b;
}
@ -241,10 +256,19 @@ public :
static void setColour(COLORREF colour2Set, tabColourIndex i, TabBarPlus* tbpObj);
virtual int getIndividualTabColourId(int tabIndex) = 0;
void currentTabToStart();
void currentTabToEnd();
void tabToStart(int index = -1);
void tabToEnd(int index = -1);
void setCloseBtnImageList();
void setPinBtnImageList();
void setTabPinButtonOrder(int newOrder) {
_pinButtonZone.setOrder(newOrder);
}
void setTabCloseButtonOrder(int newOrder) {
_closeButtonZone.setOrder(newOrder);
}
protected:
// it's the boss to decide if we do the drag N drop
@ -263,10 +287,25 @@ protected:
RECT _currentHoverTabRect{};
int _currentHoverTabItem = -1; // -1 : no mouse on any tab
CloseButtonZone _closeButtonZone;
TabButtonZone _closeButtonZone;
TabButtonZone _pinButtonZone;
HIMAGELIST _hCloseBtnImgLst = nullptr;
const int _closeTabIdx = 0;
const int _closeTabInactIdx = 1;
const int _closeTabHoverIdx = 2;
const int _closeTabPushIdx = 3;
HIMAGELIST _hPinBtnImgLst = nullptr;
const int _unpinnedIdx = 0;
const int _unpinnedHoverIdx = 1;
const int _pinnedIdx = 2;
const int _pinnedHoverIdx = 3;
bool _isCloseHover = false;
bool _isPinHover = false;
int _whichCloseClickDown = -1;
int _whichPinClickDown = -1;
bool _lmbdHit = false; // Left Mouse Button Down Hit
HWND _tooltips = nullptr;
@ -276,7 +315,7 @@ protected:
return (((TabBarPlus *)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))->runProc(hwnd, Message, wParam, lParam));
};
void setActiveTab(int tabIndex);
void exchangeTabItemData(int oldTab, int newTab);
bool exchangeTabItemData(int oldTab, int newTab);
void exchangeItemData(POINT point);
@ -284,6 +323,7 @@ protected:
static bool _drawInactiveTab;
static bool _drawTopBar;
static bool _drawTabCloseButton;
static bool _drawTabPinButton;
static bool _isDbClk2Close;
static bool _isCtrlVertical;
static bool _isCtrlMultiLine;

BIN
PowerEditor/src/icons/dark/tabbar/pinTabButton.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
PowerEditor/src/icons/dark/tabbar/pinTabButton_hover.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
PowerEditor/src/icons/dark/tabbar/pinTabButton_pinned.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
PowerEditor/src/icons/dark/tabbar/pinTabButton_pinnedHover.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
PowerEditor/src/icons/standard/tabbar/pinTabButton.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
PowerEditor/src/icons/standard/tabbar/pinTabButton_hover.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
PowerEditor/src/icons/standard/tabbar/pinTabButton_pinned.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
PowerEditor/src/icons/standard/tabbar/pinTabButton_pinnedHover.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

11
PowerEditor/src/resource.h

@ -405,6 +405,15 @@
#define IDR_FIND_RESULT_ICO2 1564
#define IDR_FIND_RESULT_ICO_DM 1565
#define IDR_PINTAB 1566
#define IDR_PINTAB_HOVER 1567
#define IDR_PINTAB_PINNED 1568
#define IDR_PINTAB_PINNEDHOVER 1569
#define IDR_PINTAB_DM 1570
#define IDR_PINTAB_HOVER_DM 1571
#define IDR_PINTAB_PINNED_DM 1572
#define IDR_PINTAB_PINNEDHOVER_DM 1573
#define ID_MACRO 20000
// O .
// C .
@ -698,6 +707,8 @@
#define NPPM_INTERNAL_LINECUTCOPYWITHOUTSELECTION (NOTEPADPLUS_USER_INTERNAL + 78)
#define NPPM_INTERNAL_DOCMODIFIEDBYREPLACEALL (NOTEPADPLUS_USER_INTERNAL + 79)
#define NPPM_INTERNAL_DRAWTABBARPINBOTTUN (NOTEPADPLUS_USER_INTERNAL + 80)
// See Notepad_plus_msgs.h
//#define NOTEPADPLUS_USER (WM_USER + 1000)

Loading…
Cancel
Save