Skip to content

Commit

Permalink
[libwin32darkmode] NppDarkMode: Adjust tab drawing for DPI.
Browse files Browse the repository at this point in the history
This uses libwin32ui's HiDPI functions.

Get rid of separate X/Y DPI values. At one point, Windows supported
non-square pixels (e.g. Win16 supported Hercules graphics cards),
but modern Windows only supports square pixels. The old LOGPIXELSX
and LOGPIXELSY values are usually equal nowadays.

[libwin32ui] HiDPI.h: New inline function rp_AdjustSizeForWindow().
This basically wraps rp_AdjustSizeForDpi() by calling
rp_GetDpiForWindow() to get the specified window's DPI first.

TODO:
- Adjust Tab Control border and edge line widths for DPI?
- Verify that nothing breaks at 96dpi.
  • Loading branch information
GerbilSoft committed Nov 18, 2023
1 parent 24e0e06 commit 1416533
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 32 deletions.
1 change: 1 addition & 0 deletions src/libwin32darkmode/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ INCLUDE(SetMSVCDebugPath)
SET_MSVC_DEBUG_PATH(${PROJECT_NAME})
# Exclude from ALL builds.
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE win32ui)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE gdiplus comctl32 uxtheme)

IF(RP_LIBROMDATA_IS_DLL AND MSVC)
Expand Down
66 changes: 38 additions & 28 deletions src/libwin32darkmode/NppDarkMode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include "libwin32common/sdk/windowsx_ts.h"
#include <tchar.h>

// High DPI support
#include "libwin32ui/HiDPI.h"

static const COLORREF colorEdge = RGB(100,100,100);
static HPEN hpenEdge = nullptr;
static HBRUSH hbrEdge = nullptr;
Expand Down Expand Up @@ -58,17 +61,18 @@ static void NppDarkMode_TabControl_drawItem(HWND hWnd, const DRAWITEMSTRUCT *pDr
DeleteBrush(hBrush);

// equalize drawing areas of active and inactive tabs
// TODO: DPI manager
int paddingDynamicTwoX = 2;
int paddingDynamicTwoY = 2;
// NOTE: Notepad++ had separate X and Y values, since Windows
// technically supports non-square pixels (e.g. Hercules on
// 16-bit Windows), but modern Windows only supports square.
const int paddingDynamicTwo = rp_AdjustSizeForWindow(hWnd, 2);
// Based on the Dark Mode path; for Light Mode, we use regular tabs.
rect.left -= paddingDynamicTwoX;
rect.right += paddingDynamicTwoX;
//rect.top += paddingDynamicTwoY; // NOTE: Cancelled out below.
rect.bottom += paddingDynamicTwoY;
rect.left -= paddingDynamicTwo;
rect.right += paddingDynamicTwo;
//rect.top += paddingDynamicTwo; // NOTE: Cancelled out below.
rect.bottom += paddingDynamicTwo;

// No multiple lines support.
//rect.top -= paddingDynamicTwoY; // NOTE: Cancels out the above, so just commented out.
//rect.top -= paddingDynamicTwo; // NOTE: Cancels out the above, so just commented out.

// Draw highlights on tabs.
if (isSelected) {
Expand All @@ -82,12 +86,11 @@ static void NppDarkMode_TabControl_drawItem(HWND hWnd, const DRAWITEMSTRUCT *pDr
// (using the edge color)
{
RECT barRect = rect;
// TODO: DPI adjustments
if (isSelected) {
barRect.bottom = barRect.top + 2;
barRect.bottom = barRect.top + paddingDynamicTwo;
} else {
barRect.top += 2;
barRect.bottom = barRect.top + 1;
barRect.top += paddingDynamicTwo;
barRect.bottom = barRect.top + (paddingDynamicTwo / 2);
}

if (!hbrEdge) {
Expand Down Expand Up @@ -126,15 +129,15 @@ static void NppDarkMode_TabControl_drawItem(HWND hWnd, const DRAWITEMSTRUCT *pDr
*out = '\0';

// Center text vertically and horizontally
// TODO: DPI adjustments?
const int Flags = DT_SINGLELINE | DT_NOPREFIX | DT_CENTER | DT_TOP;
const int paddingText = ((pDrawItemStruct->rcItem.bottom - pDrawItemStruct->rcItem.top) - (textHeight + textDescent)) / 2;
const int paddingDescent = (textDescent / 2) - (isSelected ? 2 : 0); // NOTE: Changed from NPP.
const int paddingDescent = (textDescent / 2) - (isSelected ? paddingDynamicTwo : 0); // NOTE: Changed from NPP.
rect.top = pDrawItemStruct->rcItem.top + paddingText + paddingDescent;
rect.bottom = pDrawItemStruct->rcItem.bottom - paddingText + paddingDescent;
rect.bottom -= (paddingDynamicTwo / 2); // text is too low...

// isDarkMode || !isSelected || _drawTopBar
rect.top += paddingDynamicTwoY;
rect.top += paddingDynamicTwo;

const COLORREF textColor = isSelected ? colorActiveText : colorInactiveText;
SetTextColor(hDC, textColor);
Expand Down Expand Up @@ -212,25 +215,28 @@ LRESULT WINAPI NppDarkMode_TabControlSubclassProc(
// Clipping region
HRGN holdClip = CreateRectRgn(0, 0, 0, 0);
if (GetClipRgn(hDC, holdClip) != 1) {
// Unable to get the clipping region.
DeleteObject(holdClip);
holdClip = nullptr;
// Unable to get the clipping region.
DeleteObject(holdClip);
holdClip = nullptr;
}

// TODO: DPI handling
int paddingDynamicTwoX = 2;
int paddingDynamicTwoY = 2;
// NOTE: Notepad++ had separate X and Y values, since Windows
// technically supports non-square pixels (e.g. Hercules on
// 16-bit Windows), but modern Windows only supports square.
const int paddingDynamicTwo = rp_AdjustSizeForWindow(hWnd, 2);

const int nTabs = TabCtrl_GetItemCount(hWnd);
const int nFocusTab = TabCtrl_GetCurFocus(hWnd);
const int nSelTab = TabCtrl_GetCurSel(hWnd);

// Draw the right edge lines of each tab.
// TODO: Adjust edge line width for DPI?
for (int i = 0; i < nTabs; i++) {
DRAWITEMSTRUCT dis = { ODT_TAB, id, static_cast<UINT>(i), ODA_DRAWENTIRE, ODS_DEFAULT, hWnd, hDC, {}, 0 };
TabCtrl_GetItemRect(hWnd, i, &dis.rcItem);
// FIXME: GetItemRect is slightly too small.
// TODO: Adjust for DPI.
dis.rcItem.top -= 2;
dis.rcItem.top = 0; // may be 2; subtracting paddingDynamicTwo only works at 96dpi
dis.rcItem.bottom += (paddingDynamicTwo / 2);

// Determine if this tab is focused and/or selected.
if (i == nFocusTab) {
Expand All @@ -245,11 +251,11 @@ LRESULT WINAPI NppDarkMode_TabControlSubclassProc(
if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem)) {
// Rectangles intersect.
POINT edges[] = {
{dis.rcItem.right - 1, dis.rcItem.top}, // left edge
{dis.rcItem.right - 1, dis.rcItem.bottom} // right edge
{dis.rcItem.right - 1, dis.rcItem.top},
{dis.rcItem.right - 1, dis.rcItem.bottom}
};
if (i != nSelTab && (i != nSelTab - 1)) {
edges[0].y += paddingDynamicTwoY;
edges[0].y += paddingDynamicTwo;
}

Polyline(hDC, edges, _countof(edges));
Expand All @@ -263,15 +269,18 @@ LRESULT WINAPI NppDarkMode_TabControlSubclassProc(
SelectClipRgn(hDC, holdClip);
}

// Left edge of the first tab.
{
RECT rcFirstTab;
TabCtrl_GetItemRect(hWnd, 0, &rcFirstTab);
rcFirstTab.top = 0; // may be 2; subtracting paddingDynamicTwo only works at 96dpi
rcFirstTab.bottom += (paddingDynamicTwo / 2);
POINT edges[] = {
{rcFirstTab.left, rcFirstTab.top},
{rcFirstTab.left, rcFirstTab.bottom}
};
if (nSelTab != 0) {
edges[0].y += paddingDynamicTwoY;
edges[0].y += paddingDynamicTwo;
}

Polyline(hDC, edges, _countof(edges));
Expand All @@ -284,10 +293,11 @@ LRESULT WINAPI NppDarkMode_TabControlSubclassProc(
rcFrame.top += (rcItem.bottom - rcItem.top);
rcFrame.left += rcItem.left; // to match light mode
rcFrame.right -= rcItem.left; // to match light mode
rcFrame.top += paddingDynamicTwoY;
rcFrame.top += paddingDynamicTwo;
if (!hbrEdge) {
hbrEdge = CreateSolidBrush(colorEdge);
}
// TODO: Adjust frame width for DPI?
FrameRect(hDC, &rcFrame, hbrEdge);

SelectClipRgn(hDC, holdClip);
Expand Down
19 changes: 15 additions & 4 deletions src/libwin32ui/HiDPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#pragma once

#include "RpWin32_sdk.h"
#include "libwin32common/RpWin32_sdk.h"

#ifdef __cplusplus
extern "C" {
Expand All @@ -29,9 +29,9 @@ UINT rp_GetDpiForWindow(HWND hWnd);

/**
* Adjust any size for DPI.
* @param px Size, in pixels.
* @param dpi DPI. (96dpi == 1x)
* @return Adjusted size.
* @param px Size, in pixels
* @param dpi DPI (96dpi == 1x)
* @return Adjusted size
*/
static inline int rp_AdjustSizeForDpi(int px, UINT dpi)
{
Expand All @@ -43,6 +43,17 @@ static inline int rp_AdjustSizeForDpi(int px, UINT dpi)
return (px * dpi) / 96;
}

/**
* Adjust any size for the specified window's DPI.
* @param px Size, in pixels
* @param hWnd Window
* @return Adjusted size
*/
static inline int rp_AdjustSizeForWindow(HWND hWnd, int px)
{
return rp_AdjustSizeForDpi(px, rp_GetDpiForWindow(hWnd));
}

/**
* GetSystemMetricsForDpi() implementation.
* This function was first implemented in Windows 10 v1607,
Expand Down

0 comments on commit 1416533

Please sign in to comment.