Align edge with tab (dark mode)

1. Draw frame around tabs in multi-line state (dark mode).
2. Adjust padding for hiDPI.
3. Add initializers.

Fix #12737, close #12738
This commit is contained in:
ozone10 2022-12-28 22:28:33 +01:00 committed by Don Ho
parent c63c0035f3
commit 3da880b4f8
1 changed files with 97 additions and 44 deletions

View File

@ -532,12 +532,12 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
} }
else if (!_isMultiLine) // don't scroll if in multi-line mode else if (!_isMultiLine) // don't scroll if in multi-line mode
{ {
RECT rcTabCtrl, rcLastTab; RECT rcTabCtrl{}, rcLastTab{};
::SendMessage(_hSelf, TCM_GETITEMRECT, lastTabIndex, reinterpret_cast<LPARAM>(&rcLastTab)); ::SendMessage(_hSelf, TCM_GETITEMRECT, lastTabIndex, reinterpret_cast<LPARAM>(&rcLastTab));
::GetClientRect(_hSelf, &rcTabCtrl); ::GetClientRect(_hSelf, &rcTabCtrl);
// get index of the first visible tab // get index of the first visible tab
TC_HITTESTINFO hti; TC_HITTESTINFO hti{};
LONG xy = NppParameters::getInstance()._dpiManager.scaleX(12); // an arbitrary coordinate inside the first visible tab LONG xy = NppParameters::getInstance()._dpiManager.scaleX(12); // an arbitrary coordinate inside the first visible tab
hti.pt = { xy, xy }; hti.pt = { xy, xy };
int scrollTabIndex = static_cast<int32_t>(::SendMessage(_hSelf, TCM_HITTEST, 0, reinterpret_cast<LPARAM>(&hti))); int scrollTabIndex = static_cast<int32_t>(::SendMessage(_hSelf, TCM_HITTEST, 0, reinterpret_cast<LPARAM>(&hti)));
@ -659,7 +659,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
} }
} }
POINT p; POINT p{};
p.x = LOWORD(lParam); p.x = LOWORD(lParam);
p.y = HIWORD(lParam); p.y = HIWORD(lParam);
@ -864,7 +864,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
break; break;
} }
RECT rc = {}; RECT rc{};
GetClientRect(hwnd, &rc); GetClientRect(hwnd, &rc);
FillRect((HDC)wParam, &rc, NppDarkMode::getDarkerBackgroundBrush()); FillRect((HDC)wParam, &rc, NppDarkMode::getDarkerBackgroundBrush());
@ -884,7 +884,9 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
break; break;
} }
PAINTSTRUCT ps; const bool hasMultipleLines = ((dwStyle & TCS_BUTTONS) == TCS_BUTTONS);
PAINTSTRUCT ps{};
HDC hdc = BeginPaint(hwnd, &ps); HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, NppDarkMode::getDarkerBackgroundBrush()); FillRect(hdc, &ps.rcPaint, NppDarkMode::getDarkerBackgroundBrush());
@ -899,7 +901,9 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
holdClip = nullptr; holdClip = nullptr;
} }
int topBarHeight = NppParameters::getInstance()._dpiManager.scaleX(4); auto& dpiManager = NppParameters::getInstance()._dpiManager;
int paddingDynamicTwoX = dpiManager.scaleX(2);
int paddingDynamicTwoY = dpiManager.scaleY(2);
int nTabs = TabCtrl_GetItemCount(hwnd); int nTabs = TabCtrl_GetItemCount(hwnd);
int nFocusTab = TabCtrl_GetCurFocus(hwnd); int nFocusTab = TabCtrl_GetCurFocus(hwnd);
@ -920,41 +924,48 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
dis.itemState |= ODS_NOFOCUSRECT; // maybe, does it handle it already? dis.itemState |= ODS_NOFOCUSRECT; // maybe, does it handle it already?
RECT rcIntersect = {}; RECT rcIntersect{};
if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem)) if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem))
{ {
if (dwStyle & TCS_VERTICAL) if (!hasMultipleLines)
{ {
POINT edges[] = { if (_isVertical)
{dis.rcItem.left, dis.rcItem.bottom - 1},
{dis.rcItem.right, dis.rcItem.bottom - 1}
};
if (i != nSelTab && (i != nSelTab - 1))
{ {
edges[0].x += topBarHeight; POINT edges[] = {
{dis.rcItem.left, dis.rcItem.bottom - 1},
{dis.rcItem.right, dis.rcItem.bottom - 1}
};
if (i != nSelTab && (i != nSelTab - 1))
{
edges[0].x += paddingDynamicTwoX;
}
::Polyline(hdc, edges, _countof(edges));
dis.rcItem.bottom -= 1;
} }
Polyline(hdc, edges, _countof(edges)); else
dis.rcItem.bottom -= 1;
}
else
{
POINT edges[] = {
{dis.rcItem.right - 1, dis.rcItem.top},
{dis.rcItem.right - 1, dis.rcItem.bottom}
};
if (i != nSelTab && (i != nSelTab - 1))
{ {
edges[0].y += topBarHeight; POINT edges[] = {
{dis.rcItem.right - 1, dis.rcItem.top},
{dis.rcItem.right - 1, dis.rcItem.bottom}
};
if (i != nSelTab && (i != nSelTab - 1))
{
edges[0].y += paddingDynamicTwoY;
}
::Polyline(hdc, edges, _countof(edges));
dis.rcItem.right -= 1;
} }
Polyline(hdc, edges, _countof(edges));
dis.rcItem.right -= 1;
} }
HRGN hClip = CreateRectRgnIndirect(&dis.rcItem); HRGN hClip = CreateRectRgnIndirect(&dis.rcItem);
SelectClipRgn(hdc, hClip); SelectClipRgn(hdc, hClip);
drawItem(&dis, true); drawItem(&dis, NppDarkMode::isEnabled());
DeleteObject(hClip); DeleteObject(hClip);
@ -962,6 +973,41 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
} }
} }
if (!hasMultipleLines)
{
RECT rcFirstTab{};
TabCtrl_GetItemRect(hwnd, 0, &rcFirstTab);
if (_isVertical)
{
POINT edges[] = {
{rcFirstTab.left, rcFirstTab.top},
{rcFirstTab.right, rcFirstTab.top}
};
if (nSelTab != 0)
{
edges[0].x += paddingDynamicTwoX;
}
::Polyline(hdc, edges, _countof(edges));
}
else
{
POINT edges[] = {
{rcFirstTab.left, rcFirstTab.top},
{rcFirstTab.left, rcFirstTab.bottom}
};
if (nSelTab != 0)
{
edges[0].y += paddingDynamicTwoY;
}
::Polyline(hdc, edges, _countof(edges));
}
}
SelectClipRgn(hdc, holdClip); SelectClipRgn(hdc, holdClip);
if (holdClip) if (holdClip)
{ {
@ -1048,8 +1094,9 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
::DeleteObject((HGDIOBJ)hBrush); ::DeleteObject((HGDIOBJ)hBrush);
// equalize drawing areas of active and inactive tabs // equalize drawing areas of active and inactive tabs
int paddingDynamicTwoX = NppParameters::getInstance()._dpiManager.scaleX(2); auto& dpiManager = NppParameters::getInstance()._dpiManager;
int paddingDynamicTwoY = NppParameters::getInstance()._dpiManager.scaleY(2); int paddingDynamicTwoX = dpiManager.scaleX(2);
int paddingDynamicTwoY = dpiManager.scaleY(2);
if (isSelected && !isDarkMode) if (isSelected && !isDarkMode)
{ {
// the drawing area of the active tab extends on all borders by default // the drawing area of the active tab extends on all borders by default
@ -1088,15 +1135,16 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
} }
// the active tab's text with TCS_BUTTONS is lower than normal and gets clipped // the active tab's text with TCS_BUTTONS is lower than normal and gets clipped
if (::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS) const bool hasMultipleLines = ((::GetWindowLongPtr(_hSelf, GWL_STYLE) & TCS_BUTTONS) == TCS_BUTTONS);
if (hasMultipleLines)
{ {
if (_isVertical) if (_isVertical)
{ {
rect.left -= 2; rect.left -= isDarkMode ? paddingDynamicTwoX : 2;
} }
else else
{ {
rect.top -= 2; rect.top -= isDarkMode ? paddingDynamicTwoY : 2;
} }
} }
@ -1112,15 +1160,15 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
if (_drawTopBar) if (_drawTopBar)
{ {
int topBarHeight = NppParameters::getInstance()._dpiManager.scaleX(4); int topBarHeight = dpiManager.scaleX(4);
if (_isVertical) if (_isVertical)
{ {
barRect.left -= NppParameters::getInstance()._dpiManager.scaleX(2); barRect.left -= (hasMultipleLines && isDarkMode) ? 0 : paddingDynamicTwoX;
barRect.right = barRect.left + topBarHeight; barRect.right = barRect.left + topBarHeight;
} }
else else
{ {
barRect.top -= NppParameters::getInstance()._dpiManager.scaleY(2); barRect.top -= (hasMultipleLines && isDarkMode) ? 0 : paddingDynamicTwoY;
barRect.bottom = barRect.top + topBarHeight; barRect.bottom = barRect.top + topBarHeight;
} }
@ -1142,7 +1190,7 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
} }
else // inactive tabs else // inactive tabs
{ {
RECT rect = _isCtrlMultiLine ? pDrawItemStruct->rcItem : barRect; RECT rect = hasMultipleLines ? pDrawItemStruct->rcItem : barRect;
COLORREF brushColour{}; COLORREF brushColour{};
if (_drawInactiveTab && individualColourId == -1) if (_drawInactiveTab && individualColourId == -1)
@ -1163,6 +1211,11 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
::DeleteObject((HGDIOBJ)hBrush); ::DeleteObject((HGDIOBJ)hBrush);
} }
if (isDarkMode && hasMultipleLines)
{
::FrameRect(hDC, &pDrawItemStruct->rcItem, NppDarkMode::getEdgeBrush());
}
// draw close button // draw close button
if (_drawTabCloseButton) if (_drawTabCloseButton)
{ {
@ -1182,8 +1235,8 @@ void TabBarPlus::drawItem(DRAWITEMSTRUCT *pDrawItemStruct, bool isDarkMode)
BITMAP bmp{}; BITMAP bmp{};
::GetObject(hBmp, sizeof(bmp), &bmp); ::GetObject(hBmp, sizeof(bmp), &bmp);
int bmDpiDynamicalWidth = NppParameters::getInstance()._dpiManager.scaleX(bmp.bmWidth); int bmDpiDynamicalWidth = dpiManager.scaleX(bmp.bmWidth);
int bmDpiDynamicalHeight = NppParameters::getInstance()._dpiManager.scaleY(bmp.bmHeight); int bmDpiDynamicalHeight = dpiManager.scaleY(bmp.bmHeight);
RECT buttonRect = _closeButtonZone.getButtonRectFrom(rect, _isVertical); RECT buttonRect = _closeButtonZone.getButtonRectFrom(rect, _isVertical);
@ -1309,7 +1362,7 @@ void TabBarPlus::draggingCursor(POINT screenPoint)
::SetCursor(::LoadCursor(NULL, IDC_ARROW)); ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
else else
{ {
TCHAR className[256]; TCHAR className[256] = { '\0' };
::GetClassName(hWin, className, 256); ::GetClassName(hWin, className, 256);
if ((!lstrcmp(className, TEXT("Scintilla"))) || (!lstrcmp(className, WC_TABCONTROL))) if ((!lstrcmp(className, TEXT("Scintilla"))) || (!lstrcmp(className, WC_TABCONTROL)))
{ {
@ -1341,11 +1394,11 @@ void TabBarPlus::setActiveTab(int tabIndex)
void TabBarPlus::exchangeTabItemData(int oldTab, int newTab) void TabBarPlus::exchangeTabItemData(int oldTab, int newTab)
{ {
//1. shift their data, and insert the source //1. shift their data, and insert the source
TCITEM itemData_nDraggedTab, itemData_shift; TCITEM itemData_nDraggedTab{}, itemData_shift{};
itemData_nDraggedTab.mask = itemData_shift.mask = TCIF_IMAGE | TCIF_TEXT | TCIF_PARAM; itemData_nDraggedTab.mask = itemData_shift.mask = TCIF_IMAGE | TCIF_TEXT | TCIF_PARAM;
const int stringSize = 256; const int stringSize = 256;
TCHAR str1[stringSize]; TCHAR str1[stringSize] = { '\0' };
TCHAR str2[stringSize]; TCHAR str2[stringSize] = { '\0' };
itemData_nDraggedTab.pszText = str1; itemData_nDraggedTab.pszText = str1;
itemData_nDraggedTab.cchTextMax = (stringSize); itemData_nDraggedTab.cchTextMax = (stringSize);
@ -1436,7 +1489,7 @@ bool CloseButtonZone::isHit(int x, int y, const RECT & tabRect, bool isVertical)
RECT CloseButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical) const RECT CloseButtonZone::getButtonRectFrom(const RECT & tabRect, bool isVertical) const
{ {
RECT buttonRect; RECT buttonRect{};
int fromBorder; int fromBorder;
if (isVertical) if (isVertical)