Refactor docking panel tab bar to improve dpi compatibility

- reduce flickering when resizing panels

Ref #14959

Close #15282
pull/15285/head^2
ozone10 2024-06-12 18:31:15 +02:00 committed by Don Ho
parent 7a6768b029
commit f2fbeadfea
5 changed files with 67 additions and 128 deletions

View File

@ -768,10 +768,8 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
RECT rcIntersect {}; RECT rcIntersect {};
if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem)) if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem))
{ {
dis.rcItem.top += NppParameters::getInstance()._dpiManager.scaleY(1);
dis.rcItem.right -= 1; dis.rcItem.right -= 1;
dis.rcItem.bottom += 2; ::OffsetRect(&dis.rcItem, 0, _dpiManager.scale(CAPTION_GAP * 2));
if (i == 0) if (i == 0)
{ {
POINT edges[] = { POINT edges[] = {
@ -1012,9 +1010,9 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
return ::CallWindowProc(_hDefaultTabProc, hwnd, Message, wParam, lParam); return ::CallWindowProc(_hDefaultTabProc, hwnd, Message, wParam, lParam);
} }
void DockingCont::drawTabItem(DRAWITEMSTRUCT *pDrawItemStruct) void DockingCont::drawTabItem(DRAWITEMSTRUCT* pDrawItemStruct)
{ {
TCITEM tcItem {}; TCITEM tcItem{};
RECT rc = pDrawItemStruct->rcItem; RECT rc = pDrawItemStruct->rcItem;
int nTab = pDrawItemStruct->itemID; int nTab = pDrawItemStruct->itemID;
@ -1026,41 +1024,29 @@ void DockingCont::drawTabItem(DRAWITEMSTRUCT *pDrawItemStruct)
if (!tcItem.lParam) if (!tcItem.lParam)
return; return;
const TCHAR *text = reinterpret_cast<tTbData*>(tcItem.lParam)->pszName; auto tbData = reinterpret_cast<tTbData*>(tcItem.lParam);
int length = lstrlen(reinterpret_cast<tTbData*>(tcItem.lParam)->pszName);
const TCHAR* text = tbData->pszName;
int length = lstrlen(tbData->pszName);
// get drawing context // get drawing context
HDC hDc = pDrawItemStruct->hDC; HDC hDc = pDrawItemStruct->hDC;
int nSavedDC = ::SaveDC(hDc); int nSavedDC = ::SaveDC(hDc);
// For some bizarre reason the rcItem you get extends above the actual
// drawing area. We have to workaround this "feature".
rc.top += ::GetSystemMetrics(SM_CYEDGE);
::SetBkMode(hDc, TRANSPARENT); ::SetBkMode(hDc, TRANSPARENT);
const int onePadding = _dpiManager.scale(1);
if (NppDarkMode::isEnabled()) if (NppDarkMode::isEnabled())
{ {
RECT selectedRect = rc; ::FillRect(hDc, &rc, isSelected ? NppDarkMode::getSofterBackgroundBrush() : NppDarkMode::getBackgroundBrush());
selectedRect.top -= 2; ::OffsetRect(&rc, 0, -onePadding);
selectedRect.bottom += 2;
if (isSelected)
{
::FillRect(hDc, &selectedRect, NppDarkMode::getSofterBackgroundBrush());
} }
else else if (isSelected) // draw orange bar
{
::FillRect(hDc, &selectedRect, NppDarkMode::getBackgroundBrush());
}
}
// draw orange bar
if (!NppDarkMode::isEnabled() && _bDrawOgLine && isSelected)
{ {
RECT barRect = rc; RECT barRect = rc;
barRect.top += rc.bottom - 4; barRect.top = rc.bottom - _dpiManager.scale(4);
HBRUSH hBrush = ::CreateSolidBrush(RGB(250, 170, 60)); HBRUSH hBrush = ::CreateSolidBrush(RGB(250, 170, 60));
::FillRect(hDc, &barRect, hBrush); ::FillRect(hDc, &barRect, hBrush);
@ -1068,42 +1054,34 @@ void DockingCont::drawTabItem(DRAWITEMSTRUCT *pDrawItemStruct)
} }
// draw icon if enabled // draw icon if enabled
if (((tTbData*)tcItem.lParam)->uMask & DWS_ICONTAB) if ((tbData->uMask & DWS_ICONTAB) == DWS_ICONTAB)
{ {
HIMAGELIST hImageList = (HIMAGELIST)::SendMessage(_hParent, DMM_GETIMAGELIST, 0, 0); const int wPadding = _dpiManager.scale(g_dockingContTabIconPadding);
int iPosImage = static_cast<int32_t>(::SendMessage(_hParent, DMM_GETICONPOS, 0, reinterpret_cast<LPARAM>(reinterpret_cast<tTbData*>(tcItem.lParam)->hClient))); const int iconSize = _dpiManager.scale(g_dockingContTabIconSize);
if ((hImageList != NULL) && (iPosImage >= 0)) const int iconDpiDynamicalX = rc.left + (isSelected ? wPadding : (rc.right - rc.left - iconSize + 1) / 2);
{ const int iconDpiDynamicalY = rc.top + (rc.bottom - rc.top - iconSize - onePadding) / 2;
// Get height of image so we
IMAGEINFO info {};
const RECT& imageRect = info.rcImage;
ImageList_GetImageInfo(hImageList, iPosImage, &info); ::DrawIconEx(hDc, iconDpiDynamicalX, iconDpiDynamicalY, tbData->hIconTab, 0, 0, 0, nullptr, DI_NORMAL);
int darkPaddingX = NppDarkMode::isEnabled() ? 1 : 0;
int darkPaddingY = NppDarkMode::isEnabled() ? 2 : (isSelected ? 1 : 0);
int iconDpiDynamicalX = isSelected ? rc.left + 3
: rc.left + (rc.right - rc.left - imageRect.right + imageRect.left) / 2 + darkPaddingX;
int iconDpiDynamicalY = NppParameters::getInstance()._dpiManager.scaleY(5) + darkPaddingY;
ImageList_Draw(hImageList, iPosImage, hDc, iconDpiDynamicalX, iconDpiDynamicalY, ILD_NORMAL);
if (isSelected) if (isSelected)
{ {
rc.left += imageRect.right - imageRect.left + 5; rc.left += iconSize + wPadding * 2;
}
} }
} }
if (isSelected) if (isSelected)
{ {
if (NppDarkMode::isEnabled())
{
const int textOffset = 3 * onePadding / 2 - 1;
::OffsetRect(&rc, 0, -textOffset);
}
COLORREF _unselectedColor = RGB(0, 0, 0); COLORREF _unselectedColor = RGB(0, 0, 0);
::SetTextColor(hDc, NppDarkMode::isEnabled() ? NppDarkMode::getTextColor() : _unselectedColor); ::SetTextColor(hDc, NppDarkMode::isEnabled() ? NppDarkMode::getTextColor() : _unselectedColor);
// draw text // draw text
rc.top -= ::GetSystemMetrics(SM_CYEDGE);
::SelectObject(hDc, _hFont); ::SelectObject(hDc, _hFont);
::DrawText(hDc, text, length, &rc, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX); ::DrawText(hDc, text, length, &rc, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);
} }
@ -1142,8 +1120,10 @@ intptr_t CALLBACK DockingCont::run_dlgProc(UINT Message, WPARAM wParam, LPARAM l
_hDefaultTabProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hContTab, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndTabProc))); _hDefaultTabProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hContTab, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndTabProc)));
// set min tab width // set min tab width
int tabDpiDynamicalMinWidth = NppParameters::getInstance()._dpiManager.scaleX(24); const int tabDpiPadding = _dpiManager.scale(g_dockingContTabIconSize + g_dockingContTabIconPadding * 2);
::SendMessage(_hContTab, TCM_SETMINTABWIDTH, 0, tabDpiDynamicalMinWidth); ::SendMessage(_hContTab, TCM_SETMINTABWIDTH, 0, tabDpiPadding);
TabCtrl_SetPadding(_hContTab, tabDpiPadding / 2, 0);
TabCtrl_SetItemSize(_hContTab, 2 * tabDpiPadding, tabDpiPadding);
return TRUE; return TRUE;
} }
@ -1165,15 +1145,28 @@ intptr_t CALLBACK DockingCont::run_dlgProc(UINT Message, WPARAM wParam, LPARAM l
} }
break; break;
} }
case WM_ERASEBKGND: case WM_ERASEBKGND:
{ {
if (!NppDarkMode::isEnabled()) HDC hDC = reinterpret_cast<HDC>(wParam);
{
break; RECT rc{};
}
RECT rc {};
getClientRect(rc); getClientRect(rc);
::FillRect(reinterpret_cast<HDC>(wParam), &rc, NppDarkMode::getDarkerBackgroundBrush());
RECT rcTab{};
getMappedChildRect(_hContTab, rcTab);
RECT rcClientTab{};
getMappedChildRect(IDC_CLIENT_TAB, rcClientTab);
RECT rcCap{};
getMappedChildRect(_hCaption, rcCap);
::ExcludeClipRect(hDC, rcTab.left, rcTab.top, rcTab.right, rcTab.bottom);
::ExcludeClipRect(hDC, rcClientTab.left, rcClientTab.top, rcClientTab.right, rcClientTab.bottom);
::ExcludeClipRect(hDC, rcCap.left, rcCap.top, rcCap.right, rcCap.bottom);
::FillRect(hDC, &rc, NppDarkMode::isEnabled() ? NppDarkMode::getDarkerBackgroundBrush() : ::GetSysColorBrush(COLOR_3DFACE));
return TRUE; return TRUE;
} }
@ -1266,7 +1259,7 @@ void DockingCont::onSize()
if (iItemCnt >= 1) if (iItemCnt >= 1)
{ {
// resize to docked window // resize to docked window
int tabDpiDynamicalHeight = NppParameters::getInstance()._dpiManager.scaleY(16) + 8; const int tabDpiDynamicalHeight = _dpiManager.scale(g_dockingContTabIconSize + (g_dockingContTabIconPadding) * 2 + CAPTION_GAP);
if (_isFloating == false) if (_isFloating == false)
{ {
// draw caption // draw caption
@ -1359,7 +1352,6 @@ void DockingCont::onSize()
SWP_NOZORDER | SWP_NOACTIVATE); SWP_NOZORDER | SWP_NOACTIVATE);
} }
// get active item data // get active item data
size_t iItemCnt2 = static_cast<size_t>(::SendMessage(_hContTab, TCM_GETITEMCOUNT, 0, 0)); size_t iItemCnt2 = static_cast<size_t>(::SendMessage(_hContTab, TCM_GETITEMCOUNT, 0, 0));

View File

@ -43,6 +43,7 @@ enum eMousePos {
#define CLOSEBTN_POS_TOP 3 #define CLOSEBTN_POS_TOP 3
constexpr int g_dockingContTabIconSize = 14; constexpr int g_dockingContTabIconSize = 14;
constexpr int g_dockingContTabIconPadding = 3;
class DockingCont : public StaticDialog class DockingCont : public StaticDialog
{ {
@ -118,15 +119,11 @@ public:
updateCaption(); updateCaption();
}; };
void setTabStyle(const BOOL & bDrawOgLine) {
_bDrawOgLine = bDrawOgLine;
::RedrawWindow(_hContTab, nullptr, nullptr, RDW_INVALIDATE);
};
void destroy() override{ void destroy() override{
for (int iTb = static_cast<int>(_vTbData.size()); iTb > 0; iTb--) for (auto& tTbData : _vTbData)
{ {
delete _vTbData[iTb-1]; ::DestroyIcon(tTbData->hIconTab);
delete tTbData;
} }
::DestroyWindow(_hSelf); ::DestroyWindow(_hSelf);
}; };
@ -192,9 +189,6 @@ private:
BOOL _isMouseOver = FALSE; BOOL _isMouseOver = FALSE;
RECT _rcCaption{}; RECT _rcCaption{};
// tab style
BOOL _bDrawOgLine = TRUE;
// Important value for DlgMoving class // Important value for DlgMoving class
BOOL _dragFromTab = FALSE; BOOL _dragFromTab = FALSE;

View File

@ -260,12 +260,6 @@ LRESULT DockingManager::runProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM l
hWndServer = NULL; hWndServer = NULL;
} }
// destroy imagelist if it exists
if (_hImageList != NULL)
{
::ImageList_Destroy(_hImageList);
}
// destroy containers // destroy containers
for (int32_t i = static_cast<int32_t>(_vContainer.size()); i > 0; i--) for (int32_t i = static_cast<int32_t>(_vContainer.size()); i > 0; i--)
{ {
@ -395,21 +389,7 @@ LRESULT DockingManager::runProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM l
toggleVisTb(reinterpret_cast<DockingCont*>(lParam), DMM_DOCK); toggleVisTb(reinterpret_cast<DockingCont*>(lParam), DMM_DOCK);
return FALSE; return FALSE;
} }
case DMM_GETIMAGELIST:
{
return reinterpret_cast<LPARAM>(_hImageList);
}
case DMM_GETICONPOS:
{
for (size_t uImageCnt = 0, len = _vImageList.size(); uImageCnt < len; ++uImageCnt)
{
if (reinterpret_cast<HWND>(lParam) == _vImageList[uImageCnt])
{
return uImageCnt;
}
}
return -1;
}
default : default :
break; break;
} }
@ -585,23 +565,6 @@ void DockingManager::reSizeTo(RECT & rc)
void DockingManager::createDockableDlg(tTbData data, int iCont, bool isVisible) void DockingManager::createDockableDlg(tTbData data, int iCont, bool isVisible)
{ {
// add icons
if ((data.uMask & DWS_ICONTAB) && data.hIconTab != NULL)
{
// create image list if not exist
if (_hImageList == NULL)
{
const int iconDpiDynamicalSize = DPIManagerV2::scale(g_dockingContTabIconSize, data.hClient);
_hImageList = ::ImageList_Create(iconDpiDynamicalSize, iconDpiDynamicalSize, ILC_COLOR32 | ILC_MASK, 0, 0);
}
// add icon
::ImageList_AddIcon(_hImageList, data.hIconTab);
// do the reference here to find later the correct position
_vImageList.push_back(data.hClient);
}
if ((data.uMask & DWS_USEOWNDARKMODE) != DWS_USEOWNDARKMODE && NppDarkMode::isEnabledForPlugins()) if ((data.uMask & DWS_USEOWNDARKMODE) != DWS_USEOWNDARKMODE && NppDarkMode::isEnabledForPlugins())
{ {
NppDarkMode::autoSubclassAndThemePluginDockWindow(data.hClient); NppDarkMode::autoSubclassAndThemePluginDockWindow(data.hClient);

View File

@ -35,7 +35,7 @@ public :
~DockingManager(); ~DockingManager();
void init(HINSTANCE hInst, HWND hWnd, Window ** ppWin); void init(HINSTANCE hInst, HWND hWnd, Window ** ppWin);
virtual void reSizeTo(RECT & rc); void reSizeTo(RECT & rc) override;
void setClientWnd(Window ** ppWin) { void setClientWnd(Window ** ppWin) {
_ppWindow = ppWin; _ppWindow = ppWin;
@ -73,14 +73,9 @@ public :
_vContainer[CONT_BOTTOM]->setCaptionTop(captionOnTop); _vContainer[CONT_BOTTOM]->setCaptionTop(captionOnTop);
}; };
void setTabStyle(BOOL orangeLine) {
for (size_t i = 0; i < _vContainer.size(); ++i)
_vContainer[i]->setTabStyle(orangeLine);
};
int getDockedContSize(int iCont); int getDockedContSize(int iCont);
void setDockedContSize(int iCont, int iSize); void setDockedContSize(int iCont, int iSize);
virtual void destroy(); void destroy() override;
void resize(); void resize();
private : private :
@ -88,8 +83,6 @@ private :
RECT _rcWork = {}; RECT _rcWork = {};
RECT _rect = {}; RECT _rect = {};
Window **_ppMainWindow = nullptr; Window **_ppMainWindow = nullptr;
std::vector<HWND> _vImageList;
HIMAGELIST _hImageList = nullptr;
std::vector<DockingCont*> _vContainer; std::vector<DockingCont*> _vContainer;
tDockMgr _dockData; tDockMgr _dockData;
static BOOL _isRegistered; static BOOL _isRegistered;
@ -107,7 +100,4 @@ private :
BOOL ContExists(size_t iCont); BOOL ContExists(size_t iCont);
int FindEmptyContainer(); int FindEmptyContainer();
LRESULT SendNotify(HWND hWnd, UINT message); LRESULT SendNotify(HWND hWnd, UINT message);
}; };

View File

@ -39,8 +39,8 @@
#define DMM_FLOATALL (DMM_MSG + 5) #define DMM_FLOATALL (DMM_MSG + 5)
#define DMM_MOVE (DMM_MSG + 6) #define DMM_MOVE (DMM_MSG + 6)
#define DMM_UPDATEDISPINFO (DMM_MSG + 7) #define DMM_UPDATEDISPINFO (DMM_MSG + 7)
#define DMM_GETIMAGELIST (DMM_MSG + 8) //#define DMM_GETIMAGELIST (DMM_MSG + 8)
#define DMM_GETICONPOS (DMM_MSG + 9) //#define DMM_GETICONPOS (DMM_MSG + 9)
#define DMM_DROPDATA (DMM_MSG + 10) #define DMM_DROPDATA (DMM_MSG + 10)
#define DMM_MOVE_SPLITTER (DMM_MSG + 11) #define DMM_MOVE_SPLITTER (DMM_MSG + 11)
#define DMM_CANCEL_MOVE (DMM_MSG + 12) #define DMM_CANCEL_MOVE (DMM_MSG + 12)