Add option of pin button reposition (between icon & tabname)

After adding pin tab button beside of close tab button on tab, many users complain about clicking on the wrong button. This PR add an option of separating pin tab button from close tab button by putting pin button between the saved/edited icon and the tabname.

Fix #15963
This commit is contained in:
Don Ho 2025-03-03 00:42:42 +01:00
parent bb0ed32d40
commit 0e63f01a98
11 changed files with 178 additions and 81 deletions

View File

@ -241,7 +241,7 @@ LRESULT Notepad_plus::init(HWND hwnd)
const ScintillaViewParams & svp = nppParam.getSVP();
int tabBarStatus = nppGUI._tabStatus;
size_t tabBarStatus = nppGUI._tabStatus;
TabBarPlus::setReduced((tabBarStatus & TAB_REDUCE) != 0, &_mainDocTab);
const int tabIconSet = NppDarkMode::getTabIconSet(NppDarkMode::isEnabled());
@ -415,6 +415,7 @@ LRESULT Notepad_plus::init(HWND hwnd)
TabBarPlus::setDrawInactiveTab((tabBarStatus & TAB_DRAWINACTIVETAB) != 0, &_mainDocTab);
TabBarPlus::setDrawTabCloseButton((tabBarStatus & TAB_CLOSEBUTTON) != 0, &_mainDocTab);
TabBarPlus::setDrawTabPinButton((tabBarStatus & TAB_PINBUTTON) != 0, &_mainDocTab);
TabBarPlus::setPutTabPinButtonInFront((tabBarStatus & TAB_PUTPINBUTTONINFRONT) != 0);
TabBarPlus::setDbClk2Close((tabBarStatus & TAB_DBCLK2CLOSE) != 0);
TabBarPlus::setVertical((tabBarStatus & TAB_VERTICAL) != 0);
drawTabbarColoursFromStylerArray();
@ -913,6 +914,7 @@ bool Notepad_plus::saveGUIParams()
(TabBarPlus::isReduced() ? TAB_REDUCE : 0) | \
(TabBarPlus::drawTabCloseButton() ? TAB_CLOSEBUTTON : 0) | \
(TabBarPlus::drawTabPinButton() ? TAB_PINBUTTON : 0) | \
(TabBarPlus::pinButtonInFront() ? TAB_PUTPINBUTTONINFRONT : 0) | \
(TabBarPlus::isDbClk2Close() ? TAB_DBCLK2CLOSE : 0) | \
(TabBarPlus::isVertical() ? TAB_VERTICAL : 0) | \
(TabBarPlus::isMultiLine() ? TAB_MULTILINE : 0) |\
@ -7358,7 +7360,7 @@ void Notepad_plus::launchDocumentListPanel(bool changeFromBtnCmd)
if (!_pDocumentListPanel)
{
NppParameters& nppParams = NppParameters::getInstance();
int tabBarStatus = nppParams.getNppGUI()._tabStatus;
size_t tabBarStatus = nppParams.getNppGUI()._tabStatus;
_pDocumentListPanel = new VerticalFileSwitcher;

View File

@ -153,7 +153,7 @@ void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const wchar_t *cmdL
if (cmdLineParams->_isNoTab || (nppGUI._tabStatus & TAB_HIDE))
{
const int tabStatusOld = nppGUI._tabStatus;
const size_t tabStatusOld = nppGUI._tabStatus;
::SendMessage(_hSelf, NPPM_HIDETABBAR, 0, TRUE);
if (cmdLineParams->_isNoTab)
{

View File

@ -4099,7 +4099,11 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
}
case NPPM_INTERNAL_DRAWINACTIVETABBARBUTTON:
case NPPM_INTERNAL_PUTTABPINBUTTONINFRONT:
{
if (message == NPPM_INTERNAL_PUTTABPINBUTTONINFRONT)
TabBarPlus::setPutTabPinButtonInFront(!TabBarPlus::pinButtonInFront());
::SendMessage(_mainDocTab.getHSelf(), NPPM_INTERNAL_REFRESHDARKMODE, 0, 0);
::SendMessage(_subDocTab.getHSelf(), NPPM_INTERNAL_REFRESHDARKMODE, 0, 0);

View File

@ -4879,7 +4879,7 @@ void NppParameters::feedGUIParameters(TiXmlNode *node)
else if (!lstrcmp(nm, L"TabBar"))
{
bool isFailed = false;
int oldValue = _nppGUI._tabStatus;
size_t oldValue = _nppGUI._tabStatus;
const wchar_t* val = element->Attribute(L"dragAndDrop");
if (val)
{
@ -4950,6 +4950,17 @@ void NppParameters::feedGUIParameters(TiXmlNode *node)
_nppGUI._tabStatus |= TAB_PINBUTTON;
}
val = element->Attribute(L"putPinButtonInFront");
if (val)
{
if (!lstrcmp(val, L"yes"))
_nppGUI._tabStatus |= TAB_PUTPINBUTTONINFRONT;
else if (!lstrcmp(val, L"no"))
_nppGUI._tabStatus |= 0;
else
isFailed = true;
}
val = element->Attribute(L"buttonsOninactiveTabs");
if (val)
{
@ -7295,7 +7306,7 @@ void NppParameters::createXmlTreeFromGUIParams()
GUIConfigElement->InsertEndChild(TiXmlText(pStr));
}
// <GUIConfig name="TabBar" dragAndDrop="yes" drawTopBar="yes" drawInactiveTab="yes" reduce="yes" closeButton="yes" doubleClick2Close="no" vertical="no" multiLine="no" hide="no" quitOnEmpty="no" iconSetNumber="0" />
// <GUIConfig name="TabBar" dragAndDrop="yes" drawTopBar="yes" drawInactiveTab="yes" reduce="yes" closeButton="yes" pinButton="yes" putPinButtonInFront="no" buttonsOninactiveTabs="no" doubleClick2Close="no" vertical="no" multiLine="no" hide="no" quitOnEmpty="no" iconSetNumber="0" />
{
TiXmlElement *GUIConfigElement = (newGUIRoot->InsertEndChild(TiXmlElement(L"GUIConfig")))->ToElement();
GUIConfigElement->SetAttribute(L"name", L"TabBar");
@ -7318,6 +7329,9 @@ void NppParameters::createXmlTreeFromGUIParams()
pStr = (_nppGUI._tabStatus & TAB_PINBUTTON) ? L"yes" : L"no";
GUIConfigElement->SetAttribute(L"pinButton", pStr);
pStr = (_nppGUI._tabStatus & TAB_PUTPINBUTTONINFRONT) ? L"yes" : L"no";
GUIConfigElement->SetAttribute(L"putPinButtonInFront", pStr);
pStr = (_nppGUI._tabStatus & TAB_INACTIVETABSHOWBUTTON) ? L"yes" : L"no";
GUIConfigElement->SetAttribute(L"buttonsOninactiveTabs", pStr);

View File

@ -77,6 +77,7 @@ const int TAB_QUITONEMPTY = 512; // 0000 0010 0000 0000
const int TAB_ALTICONS = 1024; // 0000 0100 0000 0000
const int TAB_PINBUTTON = 2048; // 0000 1000 0000 0000
const int TAB_INACTIVETABSHOWBUTTON = 4096; // 0001 0000 0000 0000
const int TAB_PUTPINBUTTONINFRONT = 8192; // 0010 0000 0000 0000
const bool activeText = true;
const bool activeNumeric = false;
@ -795,7 +796,7 @@ struct NppGUI final
bool _statusBarShow = true;
bool _menuBarShow = true;
int _tabStatus = (TAB_DRAWTOPBAR | TAB_DRAWINACTIVETAB | TAB_DRAGNDROP | TAB_REDUCE | TAB_CLOSEBUTTON | TAB_PINBUTTON);
size_t _tabStatus = (TAB_DRAWTOPBAR | TAB_DRAWINACTIVETAB | TAB_DRAGNDROP | TAB_REDUCE | TAB_CLOSEBUTTON | TAB_PINBUTTON);
bool _splitterPos = POS_VERTICAL;
int _userDefineDlgStatus = UDD_DOCKED;

View File

@ -57,19 +57,20 @@ BEGIN
CONTROL "Hide",IDC_CHECK_HIDESTATUSBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,45,179,174,10
GROUPBOX "Tab Bar",IDC_TABBAR_GB_STATIC,235,0,177,195,BS_CENTER
CONTROL "Hide",IDC_CHECK_TAB_HIDE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,15,100,10
CONTROL "Multi-line",IDC_CHECK_TAB_MULTILINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,28,164,10
CONTROL "Vertical",IDC_CHECK_TAB_VERTICAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,41,164,10
CONTROL "Reduce",IDC_CHECK_REDUCE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,54,164,10
CONTROL "Alternate icons",IDC_CHECK_TAB_ALTICONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,67,164,10
CONTROL "Lock (no drag and drop)",IDC_CHECK_LOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,80,164,10
CONTROL "Change inactive tab color",IDC_CHECK_DRAWINACTIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,93,164,10
CONTROL "Draw a coloured bar on active tab",IDC_CHECK_ORANGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,106,164,10
CONTROL "Show close button",IDC_CHECK_ENABLETABCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,119,164,10
CONTROL "Enable pin tab feature",IDC_CHECK_ENABLETABPIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,132,164,10
CONTROL "Show buttons on inactive tabs",IDC_CHECK_INACTTABDRAWBUTTON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,145,164,10
CONTROL "Double click to close document",IDC_CHECK_DBCLICK2CLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,158,164,10
CONTROL "Exit on close the last tab",IDC_CHECK_TAB_LAST_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,171,164,10
CONTROL "Hide",IDC_CHECK_TAB_HIDE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,10,100,10
CONTROL "Multi-line",IDC_CHECK_TAB_MULTILINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,23,164,10
CONTROL "Vertical",IDC_CHECK_TAB_VERTICAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,36,164,10
CONTROL "Reduce",IDC_CHECK_REDUCE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,49,164,10
CONTROL "Alternate icons",IDC_CHECK_TAB_ALTICONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,62,164,10
CONTROL "Lock (no drag and drop)",IDC_CHECK_LOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,75,164,10
CONTROL "Change inactive tab color",IDC_CHECK_DRAWINACTIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,88,164,10
CONTROL "Draw a coloured bar on active tab",IDC_CHECK_ORANGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,101,164,10
CONTROL "Show close button",IDC_CHECK_ENABLETABCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,114,164,10
CONTROL "Enable pin tab feature",IDC_CHECK_ENABLETABPIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,127,164,10
CONTROL "Put pin in front",IDC_CHECK_PUTPININFRONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,140,164,10
CONTROL "Show buttons on inactive tabs",IDC_CHECK_INACTTABDRAWBUTTON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,153,164,10
CONTROL "Double click to close document",IDC_CHECK_DBCLICK2CLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,166,164,10
CONTROL "Exit on close the last tab",IDC_CHECK_TAB_LAST_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,241,179,164,10
END
IDD_PREFERENCE_SUB_EDITING DIALOGEX 115, 10, 460, 205

View File

@ -580,7 +580,7 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
{
NppGUI & nppGUI = nppParam.getNppGUI();
toolBarStatusType tbStatus = nppGUI._toolBarStatus;
int tabBarStatus = nppGUI._tabStatus;
size_t tabBarStatus = nppGUI._tabStatus;
bool showTool = nppGUI._toolbarShow;
bool showStatus = nppGUI._statusBarShow;
bool showMenu = nppGUI._menuBarShow;
@ -615,10 +615,12 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
bool showCloseButton = tabBarStatus & TAB_CLOSEBUTTON;
bool enablePinButton = tabBarStatus & TAB_PINBUTTON;
bool putPinButtonInFront = tabBarStatus & TAB_PUTPINBUTTONINFRONT;
bool showButtonOnInactiveTabs = tabBarStatus & TAB_INACTIVETABSHOWBUTTON;
::SendDlgItemMessage(_hSelf, IDC_CHECK_ENABLETABCLOSE, BM_SETCHECK, showCloseButton, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_ENABLETABPIN, BM_SETCHECK, enablePinButton, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_PUTPININFRONT, BM_SETCHECK, putPinButtonInFront, 0);
::SendDlgItemMessage(_hSelf, IDC_CHECK_INACTTABDRAWBUTTON, BM_SETCHECK, showButtonOnInactiveTabs, 0);
if (!(showCloseButton || enablePinButton))
@ -628,6 +630,11 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_INACTTABDRAWBUTTON), FALSE);
}
if (!enablePinButton)
{
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_PUTPININFRONT), FALSE);
}
::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);
@ -734,6 +741,8 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
::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_PUTPININFRONT), !toBeHidden);
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_INACTTABDRAWBUTTON), !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);
@ -800,7 +809,11 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
::SendDlgItemMessage(_hSelf, IDC_CHECK_INACTTABDRAWBUTTON, BM_SETCHECK, FALSE, 0);
::SendMessage(::GetParent(_hParent), NPPM_INTERNAL_DRAWINACTIVETABBARBUTTON, 0, 0);
}
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_INACTTABDRAWBUTTON), showCloseButton || enablePinButton);
if (wParam == IDC_CHECK_ENABLETABPIN)
{
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_PUTPININFRONT), enablePinButton);
}
return TRUE;
}
@ -818,6 +831,19 @@ intptr_t CALLBACK GeneralSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM
return TRUE;
}
case IDC_CHECK_PUTPININFRONT:
{
const bool isChecked = isCheckedOrNot(IDC_CHECK_PUTPININFRONT);
NppGUI& nppgui = nppParam.getNppGUI();
if (isChecked)
nppgui._tabStatus |= TAB_PUTPINBUTTONINFRONT;
else
nppgui._tabStatus &= ~TAB_PUTPINBUTTONINFRONT;
::SendMessage(::GetParent(_hParent), NPPM_INTERNAL_PUTTABPINBUTTONINFRONT, 0, 0);
return TRUE;
}
case IDC_CHECK_DBCLICK2CLOSE :
::SendMessage(::GetParent(_hParent), NPPM_INTERNAL_TABDBCLK2CLOSE, 0, 0);
return TRUE;

View File

@ -57,6 +57,7 @@
#define IDC_CHECK_HIDERIGHTSHORTCUTSOFMENUBAR (IDD_PREFERENCE_SUB_GENRAL + 32)
#define IDC_STATUSBAR_GB_STATIC (IDD_PREFERENCE_SUB_GENRAL + 33)
#define IDC_CHECK_HIDESTATUSBAR (IDD_PREFERENCE_SUB_GENRAL + 34)
#define IDC_CHECK_PUTPININFRONT (IDD_PREFERENCE_SUB_GENRAL + 35)
#define IDD_PREFERENCE_SUB_MULTIINSTANCE 6150 //(IDD_PREFERENCE_BOX + 150)
#define IDC_MULTIINST_GB_STATIC (IDD_PREFERENCE_SUB_MULTIINSTANCE + 1)

View File

@ -31,6 +31,7 @@ bool TabBarPlus::_drawTopBar = true;
bool TabBarPlus::_drawInactiveTab = true;
bool TabBarPlus::_drawTabCloseButton = true;
bool TabBarPlus::_drawTabPinButton = true;
bool TabBarPlus::_pinButtonInFront = false;
bool TabBarPlus::_isDbClk2Close = false;
bool TabBarPlus::_isCtrlVertical = false;
bool TabBarPlus::_isCtrlMultiLine = false;
@ -822,7 +823,15 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
if (_drawTabPinButton)
{
if (_pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical))
int imageSize = 0;
if (_pinButtonInFront)
{
RECT imageRect{};
getImageRectFromImglst(imageRect);
imageSize = imageRect.right - imageRect.left;
}
if (_pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical, imageSize))
{
_whichPinClickDown = getTabIndexAt(xPos, yPos);
::SendMessage(_hParent, WM_SIZE, 0, 0);
@ -992,8 +1001,15 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
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);
int imageSize = 0;
if (_pinButtonInFront)
{
RECT imageRect{};
getImageRectFromImglst(imageRect);
imageSize = imageRect.right - imageRect.left;
}
_isPinHover = _pinButtonZone.isHit(p.x, p.y, _currentHoverTabRect, _isVertical, imageSize);
}
else
{
@ -1094,7 +1110,15 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
if (_drawTabPinButton)
{
if ((_whichPinClickDown == currentTabOn) && _pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical))
int imageSize = 0;
if (_pinButtonInFront)
{
RECT imageRect{};
getImageRectFromImglst(imageRect);
imageSize = imageRect.right - imageRect.left;
}
if ((_whichPinClickDown == currentTabOn) && _pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical, imageSize))
{
notify(TCN_TABPINNED, currentTabOn);
_whichPinClickDown = -1;
@ -1107,7 +1131,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
if (nextTab != -1)
{
::SendMessage(_hSelf, TCM_GETITEMRECT, nextTab, reinterpret_cast<LPARAM>(&_currentHoverTabRect));
_isPinHover = _pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical);
_isPinHover = _pinButtonZone.isHit(xPos, yPos, _currentHoverTabRect, _isVertical, imageSize);
}
return TRUE;
}
@ -1346,7 +1370,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
{
RECT rect = pDrawItemStruct->rcItem;
RECT tabItemRect = pDrawItemStruct->rcItem;
int nTab = pDrawItemStruct->itemID;
assert(nTab >= 0);
@ -1383,11 +1407,11 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
HDC hDC = pDrawItemStruct->hDC;
int nSavedDC = ::SaveDC(hDC);
int savedStateId = ::SaveDC(hDC);
::SetBkMode(hDC, TRANSPARENT);
HBRUSH hBrush = ::CreateSolidBrush(colorInactiveBgBase);
::FillRect(hDC, &rect, hBrush);
::FillRect(hDC, &tabItemRect, hBrush);
::DeleteObject(static_cast<HGDIOBJ>(hBrush));
// equalize drawing areas of active and inactive tabs
@ -1398,34 +1422,34 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
// the drawing area of the active tab extends on all borders by default
const int xEdge = _dpiManager.getSystemMetricsForDpi(SM_CXEDGE);
const int yEdge = _dpiManager.getSystemMetricsForDpi(SM_CYEDGE);
::InflateRect(&rect, -xEdge, -yEdge);
::InflateRect(&tabItemRect, -xEdge, -yEdge);
// the active tab is also slightly higher by default (use this to shift the tab cotent up bx two pixels if tobBar is not drawn)
if (_isVertical)
{
rect.left += _drawTopBar ? paddingDynamicTwoX : 0;
rect.right -= _drawTopBar ? 0 : paddingDynamicTwoX;
tabItemRect.left += _drawTopBar ? paddingDynamicTwoX : 0;
tabItemRect.right -= _drawTopBar ? 0 : paddingDynamicTwoX;
}
else
{
rect.top += _drawTopBar ? paddingDynamicTwoY : 0;
rect.bottom -= _drawTopBar ? 0 : paddingDynamicTwoY;
tabItemRect.top += _drawTopBar ? paddingDynamicTwoY : 0;
tabItemRect.bottom -= _drawTopBar ? 0 : paddingDynamicTwoY;
}
}
else
{
if (_isVertical)
{
rect.left += paddingDynamicTwoX;
rect.right += paddingDynamicTwoX;
rect.top -= paddingDynamicTwoY;
rect.bottom += paddingDynamicTwoY;
tabItemRect.left += paddingDynamicTwoX;
tabItemRect.right += paddingDynamicTwoX;
tabItemRect.top -= paddingDynamicTwoY;
tabItemRect.bottom += paddingDynamicTwoY;
}
else
{
rect.left -= paddingDynamicTwoX;
rect.right += paddingDynamicTwoX;
rect.top += paddingDynamicTwoY;
rect.bottom += paddingDynamicTwoY;
tabItemRect.left -= paddingDynamicTwoX;
tabItemRect.right += paddingDynamicTwoX;
tabItemRect.top += paddingDynamicTwoY;
tabItemRect.bottom += paddingDynamicTwoY;
}
}
@ -1435,18 +1459,18 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
{
if (_isVertical)
{
rect.left -= paddingDynamicTwoX;
tabItemRect.left -= paddingDynamicTwoX;
}
else
{
rect.top -= paddingDynamicTwoY;
tabItemRect.top -= paddingDynamicTwoY;
}
}
const int individualColourId = getIndividualTabColourId(nTab);
// draw highlights on tabs (top bar for active tab / darkened background for inactive tab)
RECT barRect = rect;
RECT barRect = tabItemRect;
NppParameters& nppParam = NppParameters::getInstance();
if (isSelected)
{
@ -1539,11 +1563,19 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
idxCloseImg = (_currentHoverTabItem == nTab) ? _closeTabHoverOnTabIdx : _closeTabInactIdx;
}
RECT buttonRect = _closeButtonZone.getButtonRectFrom(rect, _isVertical);
RECT buttonRect = _closeButtonZone.getButtonRectFrom(tabItemRect, _isVertical);
::ImageList_Draw(_hCloseBtnImgLst, idxCloseImg, hDC, buttonRect.left, buttonRect.top, ILD_TRANSPARENT);
}
HIMAGELIST hImgLst = (HIMAGELIST)::SendMessage(_hSelf, TCM_GETIMAGELIST, 0, 0);
IMAGEINFO info{};
ImageList_GetImageInfo(hImgLst, tci.iImage, &info);
RECT& imageRect = info.rcImage;
RECT pinButtonRect{};
// draw pin button
Buffer* buf = reinterpret_cast<Buffer*>(tci.lParam);
if (_drawTabPinButton && _hPinBtnImgLst != nullptr && buf)
@ -1615,36 +1647,31 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
}
}
RECT buttonRect = _pinButtonZone.getButtonRectFrom(rect, _isVertical);
int imageSize = _pinButtonInFront ? imageRect.right - imageRect.left : 0;
pinButtonRect = _pinButtonZone.getButtonRectFrom(tabItemRect, _isVertical, imageSize);
::ImageList_Draw(_hPinBtnImgLst, idxPinImg, hDC, buttonRect.left, buttonRect.top, ILD_TRANSPARENT);
::ImageList_Draw(_hPinBtnImgLst, idxPinImg, hDC, pinButtonRect.left, pinButtonRect.top, ILD_TRANSPARENT);
}
// draw image
HIMAGELIST hImgLst = (HIMAGELIST)::SendMessage(_hSelf, TCM_GETIMAGELIST, 0, 0);
if (hImgLst && tci.iImage >= 0)
{
IMAGEINFO info{};
ImageList_GetImageInfo(hImgLst, tci.iImage, &info);
RECT& imageRect = info.rcImage;
int fromBorder;
int xPos, yPos;
if (_isVertical)
{
fromBorder = (rect.right - rect.left - (imageRect.right - imageRect.left) + 1) / 2;
xPos = rect.left + fromBorder;
yPos = rect.bottom - fromBorder - (imageRect.bottom - imageRect.top);
rect.bottom -= fromBorder + (imageRect.bottom - imageRect.top);
fromBorder = (tabItemRect.right - tabItemRect.left - (imageRect.right - imageRect.left) + 1) / 2;
xPos = tabItemRect.left + fromBorder;
yPos = tabItemRect.bottom - fromBorder - (imageRect.bottom - imageRect.top);
tabItemRect.bottom -= fromBorder + (imageRect.bottom - imageRect.top);
}
else
{
fromBorder = (rect.bottom - rect.top - (imageRect.bottom - imageRect.top) + 1) / 2;
yPos = rect.top + fromBorder;
xPos = rect.left + fromBorder;
rect.left += fromBorder + (imageRect.right - imageRect.left);
fromBorder = (tabItemRect.bottom - tabItemRect.top - (imageRect.bottom - imageRect.top) + 1) / 2;
yPos = tabItemRect.top + fromBorder;
xPos = tabItemRect.left + fromBorder;
tabItemRect.left += fromBorder + (imageRect.right - imageRect.left);
}
ImageList_Draw(hImgLst, tci.iImage, hDC, xPos, yPos, isSelected ? ILD_TRANSPARENT : ILD_SELECTED);
}
@ -1696,15 +1723,15 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
// center text horizontally (rotated text is positioned as if it were unrotated, therefore manual positioning is necessary)
flags |= DT_LEFT;
flags |= DT_BOTTOM;
rect.left += (rect.right - rect.left - textHeight) / 2;
rect.bottom += textHeight;
tabItemRect.left += (tabItemRect.right - tabItemRect.left - textHeight) / 2;
tabItemRect.bottom += textHeight;
// ignoring the descent when centering (text elements below the base line) is more pleasing to the eye
rect.left += textDescent / 2;
rect.right += textDescent / 2;
tabItemRect.left += textDescent / 2;
tabItemRect.right += textDescent / 2;
// 1 space distance to save icon
rect.bottom -= spaceUnit;
tabItemRect.bottom -= spaceUnit;
}
else
{
@ -1714,24 +1741,24 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT* pDrawItemStruct, bool isDarkMode)
const int paddingText = ((pDrawItemStruct->rcItem.bottom - pDrawItemStruct->rcItem.top) - (textHeight + textDescent)) / 2;
const int paddingDescent = !hasMultipleLines ? ((textDescent + ((isDarkMode || !isSelected) ? 1 : 0)) / 2) : 0;
rect.top = pDrawItemStruct->rcItem.top + paddingText + paddingDescent;
rect.bottom = pDrawItemStruct->rcItem.bottom - paddingText + paddingDescent;
tabItemRect.top = pDrawItemStruct->rcItem.top + paddingText + paddingDescent;
tabItemRect.bottom = pDrawItemStruct->rcItem.bottom - paddingText + paddingDescent;
if (isDarkMode || !isSelected || _drawTopBar)
{
rect.top += paddingDynamicTwoY;
tabItemRect.top += paddingDynamicTwoY;
}
// 1 space distance to save icon
rect.left += spaceUnit;
tabItemRect.left += _pinButtonInFront ? spaceUnit + (pinButtonRect.right - pinButtonRect.left) + spaceUnit : spaceUnit;
}
COLORREF textColor = isSelected ? colorActiveText : colorInactiveText;
::SetTextColor(hDC, textColor);
::DrawText(hDC, decodedLabel, lstrlen(decodedLabel), &rect, flags);
::RestoreDC(hDC, nSavedDC);
::DrawText(hDC, decodedLabel, lstrlen(decodedLabel), &tabItemRect, flags);
::RestoreDC(hDC, savedStateId);
}
@ -1862,9 +1889,9 @@ void TabBarPlus::exchangeItemData(POINT point)
}
bool TabButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical) const
bool TabButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical, int imageSize/* = 0 */) const
{
RECT buttonRect = getButtonRectFrom(tabRect, isVertical);
RECT buttonRect = getButtonRectFrom(tabRect, isVertical, imageSize);
if (x >= buttonRect.left && x <= buttonRect.right && y >= buttonRect.top && y <= buttonRect.bottom)
return true;
@ -1872,7 +1899,7 @@ bool TabButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical) c
return false;
}
RECT TabButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical) const
RECT TabButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical, int imageSize/* = 0 */) const
{
RECT buttonRect{};
const UINT dpi = DPIManagerV2::getDpiForWindow(_parent);
@ -1898,11 +1925,17 @@ RECT TabButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical) con
fromBorder = (tabRect.bottom - tabRect.top - _height + 1) / 2;
if (_order == 0)
{
buttonRect.left = tabRect.right - fromBorder - _width;
if (!imageSize)
buttonRect.left = tabRect.right - fromBorder - _width;
else
buttonRect.left = tabRect.left + inBetween + imageSize;
}
else if (_order == 1)
{
buttonRect.left = tabRect.right - fromBorder - _width * 2 - inBetween;
if (!imageSize)
buttonRect.left = tabRect.right - fromBorder - _width * 2 - inBetween;
else
buttonRect.left = tabRect.left + inBetween + imageSize;
}
buttonRect.top = tabRect.top + fromBorder;

View File

@ -158,8 +158,8 @@ struct TabButtonZone
_order = order;
}
bool isHit(int x, int y, const RECT & tabRect, bool isVertical) const;
RECT getButtonRectFrom(const RECT & tabRect, bool isVertical) const;
bool isHit(int x, int y, const RECT & tabRect, bool isVertical, int imageSize = 0) const;
RECT getButtonRectFrom(const RECT & tabRect, bool isVertical, int imageSize = 0) const;
void setOrder(int newOrder) { _order = newOrder; };
HWND _parent = nullptr;
@ -210,6 +210,7 @@ public :
static bool drawInactiveTab() {return _drawInactiveTab;};
static bool drawTabCloseButton() {return _drawTabCloseButton;};
static bool drawTabPinButton() {return _drawTabPinButton;};
static bool pinButtonInFront() {return _pinButtonInFront;};
static bool isDbClk2Close() {return _isDbClk2Close;};
static bool isVertical() { return _isCtrlVertical;};
static bool isMultiLine() { return _isCtrlMultiLine;};
@ -239,6 +240,10 @@ public :
_isDbClk2Close = b;
}
static void setPutTabPinButtonInFront(bool b) {
_pinButtonInFront = b;
}
static void setVertical(bool b) {
_isCtrlVertical = b;
doVertical();
@ -278,6 +283,15 @@ public :
deletItemAt(index);
}
void getImageRectFromImglst(RECT& imageRect) const {
HIMAGELIST hImgLst = (HIMAGELIST)::SendMessage(_hSelf, TCM_GETIMAGELIST, 0, 0);
IMAGEINFO info{};
TCITEM tci{};
tci.mask = TCIF_IMAGE;
ImageList_GetImageInfo(hImgLst, tci.iImage, &info);
imageRect = info.rcImage;
}
protected:
// it's the boss to decide if we do the drag N drop
static bool _doDragNDrop;
@ -335,6 +349,7 @@ protected:
static bool _drawTopBar;
static bool _drawTabCloseButton;
static bool _drawTabPinButton;
static bool _pinButtonInFront;
static bool _isDbClk2Close;
static bool _isCtrlVertical;
static bool _isCtrlMultiLine;

View File

@ -667,7 +667,7 @@
#define NPPM_INTERNAL_SCINTILLAFINDERCLEARALL (NOTEPADPLUS_USER_INTERNAL + 27)
#define NPPM_INTERNAL_CHANGETABBARICONSET (NOTEPADPLUS_USER_INTERNAL + 28)
#define NPPM_INTERNAL_SET_TAB_SETTINGS (NOTEPADPLUS_USER_INTERNAL + 29)
//#define NPPM_INTERNAL_SETTING_TAB_SIZE (NOTEPADPLUS_USER_INTERNAL + 30)
#define NPPM_INTERNAL_PUTTABPINBUTTONINFRONT (NOTEPADPLUS_USER_INTERNAL + 30)
#define NPPM_INTERNAL_RELOADSTYLERS (NOTEPADPLUS_USER_INTERNAL + 31)
#define NPPM_INTERNAL_DOCORDERCHANGED (NOTEPADPLUS_USER_INTERNAL + 32)
#define NPPM_INTERNAL_SETMULTISELCTION (NOTEPADPLUS_USER_INTERNAL + 33)