|
|
|
@ -1560,13 +1560,17 @@ namespace NppDarkMode
|
|
|
|
|
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//窗口子类化的示例,它为指定的窗口处理了自定义的边框绘制逻辑。
|
|
|
|
|
void subclassTabControl(HWND hwnd)
|
|
|
|
|
{
|
|
|
|
|
SetWindowSubclass(hwnd, TabSubclass, g_tabSubclassID, 0);
|
|
|
|
|
SetWindowSubclass(hwnd, TabSubclass, g_tabSubclassID, 0); //将窗口 hwnd 子类化为 TabSubclass,并分配一个唯一的子类 ID g_tabSubclassID。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr UINT_PTR g_customBorderSubclassID = 42;
|
|
|
|
|
|
|
|
|
|
//这个函数是一个回调函数,用于处理窗口消息。它被用作窗口子类的回调函数。
|
|
|
|
|
//当窗口接收到消息时,该函数会被调用来处理消息。
|
|
|
|
|
//注意,该函数的签名必须与 SUBCLASSPROC 类型匹配。
|
|
|
|
|
LRESULT CALLBACK CustomBorderSubclass(
|
|
|
|
|
HWND hWnd,
|
|
|
|
|
UINT uMsg,
|
|
|
|
@ -1580,6 +1584,9 @@ namespace NppDarkMode
|
|
|
|
|
|
|
|
|
|
static bool isHotStatic = false;
|
|
|
|
|
|
|
|
|
|
//在这个函数中,根据不同的消息类型进行不同的处理。
|
|
|
|
|
//其中,WM_NCPAINT 消息用于非客户区绘制,即窗口的边框绘制。
|
|
|
|
|
//在这里,通过重绘窗口的边框,实现了自定义的边框绘制效果。
|
|
|
|
|
switch (uMsg)
|
|
|
|
|
{
|
|
|
|
|
case WM_NCPAINT:
|
|
|
|
@ -1635,19 +1642,25 @@ namespace NppDarkMode
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
//以上部分代码使用 GetWindowDC 函数获取窗口的设备上下文,然后根据窗口的样式和状态计算绘制边框所需的相关信息。
|
|
|
|
|
//通过调用 NppDarkMode::paintRoundFrameRect 函数来绘制圆角矩形边框,使用不同的画笔来绘制不同的边框样式。
|
|
|
|
|
//绘制完成后,通过 ReleaseDC 函数释放设备上下文。最后,返回值为 0,表示消息已经被处理完毕。
|
|
|
|
|
|
|
|
|
|
case WM_NCCALCSIZE:
|
|
|
|
|
{
|
|
|
|
|
if (!NppDarkMode::isEnabled())
|
|
|
|
|
if (!NppDarkMode::isEnabled()) //检查是否启用了 NppDarkMode,如果没有启用,则直接跳过。
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto lpRect = reinterpret_cast<LPRECT>(lParam);
|
|
|
|
|
::InflateRect(lpRect, -(::GetSystemMetrics(SM_CXEDGE)), -(::GetSystemMetrics(SM_CYEDGE)));
|
|
|
|
|
auto lpRect = reinterpret_cast<LPRECT>(lParam); //通过将 lParam 强制转换为 LPRECT 类型,获取指向窗口矩形结构的指针。
|
|
|
|
|
::InflateRect(lpRect, -(::GetSystemMetrics(SM_CXEDGE)), -(::GetSystemMetrics(SM_CYEDGE))); //利用 InflateRect 函数扩展客户区矩形的尺寸,将其减去窗口边框的宽度和高度(使用 SM_CXEDGE 和 SM_CYEDGE 系统度量值)。这样可以得到去除边框后的客户区矩形。
|
|
|
|
|
|
|
|
|
|
auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
|
|
|
|
|
bool hasVerScrollbar = (style & WS_VSCROLL) == WS_VSCROLL;
|
|
|
|
|
|
|
|
|
|
//根据窗口的样式,检查是否有垂直和水平滚动条。如果有垂直滚动条,则将客户区矩形的右边减去垂直滚动条的宽度(使用 SM_CXVSCROLL 系统度量值)。
|
|
|
|
|
//如果有水平滚动条,则将客户区矩形的底部减去水平滚动条的高度(使用 SM_CYHSCROLL 系统度量值)。
|
|
|
|
|
if (hasVerScrollbar)
|
|
|
|
|
{
|
|
|
|
|
lpRect->right -= ::GetSystemMetrics(SM_CXVSCROLL);
|
|
|
|
@ -1659,10 +1672,14 @@ namespace NppDarkMode
|
|
|
|
|
lpRect->bottom -= ::GetSystemMetrics(SM_CYHSCROLL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
return 0; //返回值为 0,表示已经处理完 WM_NCCALCSIZE 消息。
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
//在这个代码块中,首先检查是否启用了 NppDarkMode,如果没有启用,则直接跳过。
|
|
|
|
|
//然后,通过调用 GetFocus 函数检查窗口是否具有焦点,如果有焦点则跳过。
|
|
|
|
|
//接下来,创建一个 TRACKMOUSEEVENT 结构体,并设置其中的成员变量。这个结构体用于跟踪鼠标离开窗口的消息。通过调用 TrackMouseEvent 函数,将该结构体传递给系统,以便在鼠标离开窗口时收到 WM_MOUSELEAVE 消息。
|
|
|
|
|
//然后,检查 isHotStatic 变量的值。如果它为假,则将其设置为真,并通过调用 SetWindowPos 函数更新窗口的位置和大小。这里使用了 SWP_NOMOVE、SWP_NOSIZE 和 SWP_NOZORDER 标志,表示不改变窗口的位置、大小和层次关系,只刷新窗口的边框样式(使用 SWP_FRAMECHANGED 标志)。
|
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
|
{
|
|
|
|
|
if (!NppDarkMode::isEnabled())
|
|
|
|
@ -1690,6 +1707,10 @@ namespace NppDarkMode
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
//在这个代码块中,首先检查是否启用了 NppDarkMode,如果没有启用,则直接跳过。
|
|
|
|
|
//然后,检查 isHotStatic 变量的值。如果它为真,则将其设置为假,并通过调用 SetWindowPos 函数更新窗口的位置和大小。
|
|
|
|
|
//接下来,同样创建一个 TRACKMOUSEEVENT 结构体,并设置其中的成员变量。
|
|
|
|
|
//然后,通过调用 TrackMouseEvent 函数,取消对鼠标离开窗口的跟踪,并清除鼠标悬停时间。
|
|
|
|
|
case WM_MOUSELEAVE:
|
|
|
|
|
{
|
|
|
|
|
if (!NppDarkMode::isEnabled())
|
|
|
|
@ -1714,20 +1735,21 @@ namespace NppDarkMode
|
|
|
|
|
|
|
|
|
|
case WM_NCDESTROY:
|
|
|
|
|
{
|
|
|
|
|
RemoveWindowSubclass(hWnd, CustomBorderSubclass, uIdSubclass);
|
|
|
|
|
RemoveWindowSubclass(hWnd, CustomBorderSubclass, uIdSubclass); //调用 RemoveWindowSubclass 函数,将窗口子类移除,以确保在窗口销毁时不再收到自定义边框的消息。
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
|
return DefSubclassProc(hWnd, uMsg, wParam, lParam); //通过调用 DefSubclassProc 函数,将消息传递给默认的窗口过程进行处理。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void subclassCustomBorderForListBoxAndEditControls(HWND hwnd)
|
|
|
|
|
void subclassCustomBorderForListBoxAndEditControls(HWND hwnd) //hwnd为要进行子类化的窗口句柄。
|
|
|
|
|
{
|
|
|
|
|
SetWindowSubclass(hwnd, CustomBorderSubclass, g_customBorderSubclassID, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr UINT_PTR g_comboBoxSubclassID = 42;
|
|
|
|
|
constexpr UINT_PTR g_comboBoxSubclassID = 42; //标识子类化的ID
|
|
|
|
|
|
|
|
|
|
//子类函数 ComboBoxSubclass,它是一个回调函数,用于处理窗口消息。
|
|
|
|
|
LRESULT CALLBACK ComboBoxSubclass(
|
|
|
|
|
HWND hWnd,
|
|
|
|
|
UINT uMsg,
|
|
|
|
@ -1736,6 +1758,7 @@ namespace NppDarkMode
|
|
|
|
|
UINT_PTR uIdSubclass,
|
|
|
|
|
DWORD_PTR dwRefData
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto hwndEdit = reinterpret_cast<HWND>(dwRefData);
|
|
|
|
|
|
|
|
|
@ -1747,13 +1770,15 @@ namespace NppDarkMode
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//定义一个名为 rc 的 RECT 结构体,并使用 ::GetClientRect 函数获取窗口客户区的矩形区域信息。
|
|
|
|
|
RECT rc{};
|
|
|
|
|
::GetClientRect(hWnd, &rc);
|
|
|
|
|
|
|
|
|
|
//定义一个名为 ps 的 PAINTSTRUCT 结构体,并调用 ::BeginPaint 函数开始绘制操作,将得到的设备上下文句柄保存在 hdc 变量中。
|
|
|
|
|
PAINTSTRUCT ps{};
|
|
|
|
|
auto hdc = ::BeginPaint(hWnd, &ps);
|
|
|
|
|
|
|
|
|
|
//选择关联字体
|
|
|
|
|
::SelectObject(hdc, reinterpret_cast<HFONT>(::SendMessage(hWnd, WM_GETFONT, 0, 0)));
|
|
|
|
|
::SetBkColor(hdc, NppDarkMode::getBackgroundColor());
|
|
|
|
|
|
|
|
|
@ -1761,11 +1786,16 @@ namespace NppDarkMode
|
|
|
|
|
|
|
|
|
|
auto& dpiManager = NppParameters::getInstance()._dpiManager;
|
|
|
|
|
|
|
|
|
|
//定义一个名为 rcArrow 的 RECT 结构体变量,用于存储组合框箭头的位置和尺寸信息。
|
|
|
|
|
RECT rcArrow{};
|
|
|
|
|
|
|
|
|
|
//定义一个名为 cbi 的 COMBOBOXINFO 结构体,并设置其 cbSize 成员为结构体的大小。
|
|
|
|
|
//然后通过调用 ::GetComboBoxInfo 函数获取与指定组合框窗口相关的信息,并将结果存储在 cbi 变量中。
|
|
|
|
|
COMBOBOXINFO cbi{};
|
|
|
|
|
cbi.cbSize = sizeof(COMBOBOXINFO);
|
|
|
|
|
const bool resultCbi = ::GetComboBoxInfo(hWnd, &cbi) != FALSE;
|
|
|
|
|
|
|
|
|
|
//根据获取到的组合框信息或者客户区的尺寸,动态地确定箭头区域的位置和尺寸
|
|
|
|
|
if (resultCbi)
|
|
|
|
|
{
|
|
|
|
|
rcArrow = cbi.rcButton;
|
|
|
|
@ -1779,12 +1809,16 @@ namespace NppDarkMode
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool hasFocus = false;
|
|
|
|
|
bool hasFocus = false; //定义了一个 hasFocus 变量,并且获取了窗口是否启用的状态。
|
|
|
|
|
|
|
|
|
|
const bool isWindowEnabled = ::IsWindowEnabled(hWnd) == TRUE;
|
|
|
|
|
|
|
|
|
|
// CBS_DROPDOWN text is handled by parent by WM_CTLCOLOREDIT
|
|
|
|
|
auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
|
|
|
|
|
|
|
|
|
|
//如果组合框是下拉列表框(CBS_DROPDOWNLIST),则根据获取到的组合框信息或者客户区的尺寸,确定文本背景的矩形区域 rcTextBg,并使用 FillRect 函数擦除文本背景。
|
|
|
|
|
//然后根据当前选中的项来设置文本颜色和背景颜色,并绘制文本到指定的位置上。
|
|
|
|
|
//最后,如果组合框有焦点且未展开下拉列表,则使用 DrawFocusRect 函数绘制焦点矩形框。
|
|
|
|
|
if ((style & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
|
|
|
|
|
{
|
|
|
|
|
hasFocus = ::GetFocus() == hWnd;
|
|
|
|
@ -1828,6 +1862,8 @@ namespace NppDarkMode
|
|
|
|
|
::DrawFocusRect(hdc, &rcTextBg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//如果组合框是可编辑的下拉框(CBS_DROPDOWN),则判断编辑框是否拥有焦点,并根据情况设置 hasFocus 变量的值。
|
|
|
|
|
else if ((style & CBS_DROPDOWN) == CBS_DROPDOWN && hwndEdit != nullptr)
|
|
|
|
|
{
|
|
|
|
|
hasFocus = ::GetFocus() == hwndEdit;
|
|
|
|
@ -1852,10 +1888,10 @@ namespace NppDarkMode
|
|
|
|
|
auto holdPen = static_cast<HPEN>(::SelectObject(hdc, hSelectedPen));
|
|
|
|
|
|
|
|
|
|
POINT edge[] = {
|
|
|
|
|
{rcArrow.left - 1, rcArrow.top},
|
|
|
|
|
{rcArrow.left - 1, rcArrow.bottom}
|
|
|
|
|
{rcArrow.left - 1, rcArrow.top}, //箭头区域左侧顶部
|
|
|
|
|
{rcArrow.left - 1, rcArrow.bottom} //箭头区域左侧底部
|
|
|
|
|
};
|
|
|
|
|
::Polyline(hdc, edge, _countof(edge));
|
|
|
|
|
::Polyline(hdc, edge, _countof(edge)); //绘制连线(边框线)
|
|
|
|
|
|
|
|
|
|
int roundCornerValue = NppDarkMode::isWindows11() ? dpiManager.scaleX(4) : 0;
|
|
|
|
|
NppDarkMode::paintRoundFrameRect(hdc, rc, hSelectedPen, roundCornerValue, roundCornerValue);
|
|
|
|
@ -1875,7 +1911,10 @@ namespace NppDarkMode
|
|
|
|
|
}
|
|
|
|
|
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
// 以上代码用于自定义列表框和编辑控件的边框和外观,通过调用 SetWindowSubclass 函数将子类函数与窗口句柄关联起来,实现自定义的绘制效果。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//给组合框控件设置子类化
|
|
|
|
|
void subclassComboBoxControl(HWND hwnd)
|
|
|
|
|
{
|
|
|
|
|
DWORD_PTR hwndEditData = 0;
|
|
|
|
|