WildByDesign Posted Monday at 10:58 PM Posted Monday at 10:58 PM (edited) I have a Groupbox subclass that is working reasonably well, but there are some measurement/alignment issues that I really need help with. This is needed for GUIDarkTheme UDF for versions of Windows prior to Windows 11 25H2 because on those affected systems we have to remove the theme. My hope is to give those users a nice looking dark mode Groupbox. I am following along some C++ code and trying my best to understand it. Some of my variables are named the same as those just to help me follow along. Thank you. WM_PAINT: DmlibSubclassControl.cpp#L498 /** * @brief Paints a group box frame and text with custom colors. * * Handles drawing a themed group box with optional centered text, styled borders, * and font fallback. If a caption text is present, the frame is clipped to avoid overdrawing * behind the text. The function adapts layout for both centered and left-aligned titles. * * Paint logic: * - Determines current visual state (`GBS_DISABLED`, `GBS_NORMAL`). * - Retrieves themed font via `GetThemeFont` or falls back to dialog font. * - Measures caption text, computes layout and exclusion for frame clipping. * - Paints the outer rounded frame via @ref dmlib::paintRoundFrameRect * using `dmlib::getEdgePen()`. * - Restores clip region and draws text using `DrawThemeTextEx` with custom colors. * * @param[in] hWnd Handle to the group box control. * @param[in] hdc Device context to draw into. * @param[in] buttonData Reference to the theming and state info (theme handle). * * @note Ensures proper cleanup of temporary GDI objects (font, clip region). * * @see dmlib::paintRoundFrameRect() */ static void paintGroupbox(HWND hWnd, HDC hdc, const dmlib_subclass::ButtonData& buttonData) { const auto& hTheme = buttonData.m_themeData.getHTheme(); // Style part const bool isDisabled = ::IsWindowEnabled(hWnd) == FALSE; static constexpr int iPartID = BP_GROUPBOX; const int iStateID = isDisabled ? GBS_DISABLED : GBS_NORMAL; // Font part bool isFontCreated = false; HFONT hFont = nullptr; LOGFONT lf{}; if (SUCCEEDED(::GetThemeFont(hTheme, hdc, iPartID, iStateID, TMT_FONT, &lf))) { hFont = ::CreateFontIndirectW(&lf); isFontCreated = true; } if (hFont == nullptr) { hFont = reinterpret_cast<HFONT>(::SendMessage(hWnd, WM_GETFONT, 0, 0)); isFontCreated = false; } const auto holdFont = dmlib_paint::GdiObject{ hdc, hFont, !isFontCreated }; // Text rectangle part std::wstring buffer; const auto bufferLen = static_cast<size_t>(::GetWindowTextLengthW(hWnd)); if (bufferLen > 0) { buffer.resize(bufferLen + 1, L'\0'); ::GetWindowTextW(hWnd, buffer.data(), static_cast<int>(buffer.length())); } const auto nStyle = ::GetWindowLongPtr(hWnd, GWL_STYLE); const bool isCenter = (nStyle & BS_CENTER) == BS_CENTER; RECT rcClient{}; ::GetClientRect(hWnd, &rcClient); rcClient.bottom -= 1; RECT rcText{ rcClient }; RECT rcBackground{ rcClient }; if (!buffer.empty()) { SIZE szText{}; ::GetTextExtentPoint32W(hdc, buffer.c_str(), static_cast<int>(bufferLen), &szText); const int centerPosX = isCenter ? ((rcClient.right - rcClient.left - szText.cx) / 2) : 7; rcBackground.top += szText.cy / 2; rcText.left += centerPosX; rcText.bottom = rcText.top + szText.cy; rcText.right = rcText.left + szText.cx + 4; ::ExcludeClipRect(hdc, rcText.left, rcText.top, rcText.right, rcText.bottom); } else // There is no text, use "M" to get metrics to move top edge down { SIZE szText{}; ::GetTextExtentPoint32W(hdc, L"M", 1, &szText); rcBackground.top += szText.cy / 2; } RECT rcContent = rcBackground; ::GetThemeBackgroundContentRect(hTheme, hdc, BP_GROUPBOX, iStateID, &rcBackground, &rcContent); ::ExcludeClipRect(hdc, rcContent.left, rcContent.top, rcContent.right, rcContent.bottom); dmlib_paint::paintFrameRect(hdc, rcBackground, dmlib::getEdgePen()); // main frame ::SelectClipRgn(hdc, nullptr); // Text part if (!buffer.empty()) { ::InflateRect(&rcText, -2, 0); DTTOPTS dtto{}; dtto.dwSize = sizeof(DTTOPTS); dtto.dwFlags = DTT_TEXTCOLOR; dtto.crText = isDisabled ? dmlib::getDisabledTextColor() : dmlib::getTextColor(); DWORD dtFlags = isCenter ? DT_CENTER : DT_LEFT; if (::SendMessage(hWnd, WM_QUERYUISTATE, 0, 0) != 0) // NULL { dtFlags |= DT_HIDEPREFIX; } ::DrawThemeTextEx(hTheme, hdc, BP_GROUPBOX, iStateID, buffer.c_str(), -1, dtFlags | DT_SINGLELINE, &rcText, &dtto); } } And here is my partially working script: expandcollapse popup#include <ButtonConstants.au3> #include <WindowsStylesConstants.au3> #include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness ;DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Global Const $BP_RADIOBUTTON = 2 Global Const $BP_CHECKBOX = 3 ; group constants Global Const $BP_GROUPBOX = 4 Global Const $GBS_NORMAL = 1 Global Const $GBS_DISABLED = 2 Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ;GUISetFont(12) ; Register Subclassing / Window Procedure Local $hSubclass = DllCallbackRegister(__GUIDarkTheme_ButtonProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") Local $hGroupProc = DllCallbackRegister(__GUIDarkTheme_GroupProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") Local $idGroup = GUICtrlCreateGroup("Group 1", 30, 60, 140, 100) Local $hGroup = GUICtrlGetHandle(-1) Local $idRadio1 = GUICtrlCreateRadio("Radio 1", 40, 80) Local $hRadio1= GUICtrlGetHandle(-1) Local $idRadio2 = GUICtrlCreateRadio("Radio 2", 40, 110) Local $hRadio2 = GUICtrlGetHandle(-1) GUICtrlCreateGroup("", -99, -99, 1, 1) ;close group Local $idButton_Close = GUICtrlCreateButton("Close", 210, 160) _WinAPI_SetWindowTheme(GUICtrlGetHandle(-1), "DarkMode_Explorer") ; Get checkbox/radio button part size to increase width of controls plus padding Local $hTheme = _WinAPI_OpenThemeData($hGUI, "DarkMode_Explorer::Button") Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $BP_CHECKBOX, 0, Null, Null, $TS_TRUE) Local $iResize = $tSIZE.X + 3 $iResize = 3 _WinAPI_CloseThemeData($hTheme) ; subclass group _WinAPI_SetWindowSubclass($hGroup, DllCallbackGetPtr($hGroupProc), $idGroup) Local $iCount = 1 ; Subclass controls $iCount += 1 Local $sStyles = "BS_AUTORADIOBUTTON, WS_CHILD, WS_VISIBLE, WS_TABSTOP" Local $tStruct2 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct2, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct2, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1, DllStructGetPtr($tStruct2)) $iCount += 1 Local $sStyles = "BS_AUTORADIOBUTTON, WS_CHILD, WS_VISIBLE, WS_TABSTOP" Local $tStruct3 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct3, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct3, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2, DllStructGetPtr($tStruct3)) ; Display the GUI GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1) _WinAPI_RemoveWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2) _WinAPI_RemoveWindowSubclass($hGroup, DllCallbackGetPtr($hGroupProc), $idGroup) DllCallbackFree($hSubclass) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func __GUIDarkTheme_GroupProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering Case $WM_PAINT ;Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) ; Setup font Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hMemDC, $hFont) ; Get text from groupbox Local $sText = _WinAPI_GetWindowText($hWnd) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom - 1 Local $tText = _WinAPI_GetTextExtentPoint32($hMemDC, $sText) Local $rcText = _WinAPI_GetClientRect($hWnd) Local $rcBackground = _WinAPI_GetClientRect($hWnd) $rcBackground.top += $tText.y / 2 $rcText.left += 7 $rcText.bottom = $rcText.top + $tText.y $rcText.right = $rcText.left + $tText.x + 4 _WinAPI_InflateRect($rcText, -2, 0) Local $iStateID = 0 ; not sure yet Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $BP_GROUPBOX, $iStateID, $hMemDC, $rcText) _WinAPI_ExcludeClipRect($hMemDC, $tTextRect) ; Rounded frame (TODO: figure out rounded later) Local $hBrush = _WinAPI_CreateSolidBrush(_WinAPI_SwitchColor(0xFFFFFF)) ;Local $hPen =_WinAPI_CreatePen($PS_SOLID, 1, 0x000000) ;_WinAPI_SelectObject($hMemDC, $hPen) ;_WinAPI_SelectObject($hMemDC, $hBrush) ;_WinAPI_RoundRect($hMemDC, $tClient, 8, 8) _WinAPI_FrameRect($hMemDC, $rcBackground, $hBrush) _WinAPI_DeleteObject($hBrush) _WinAPI_SelectClipRgn($hMemDC, 0) ; Set flags for DTTOPTS structure Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', $DTT_TEXTCOLOR) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) Local $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_LEFT) _WinAPI_DrawThemeTextEx($hTheme, $BP_GROUPBOX, $iStateID, $hMemDC, $sText, $tTextRect, $iTextFlags, $tDTTOPTS) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; Cleanup _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkTheme_GroupProc Func __GUIDarkTheme_ButtonProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering Case $WM_PAINT Local $tStruct = DllStructCreate("struct;int;wchar[256];endstruct", $pData) Local $iPartID = DllStructGetData($tStruct, 1) Local $sStyles = DllStructGetData($tStruct, 2) Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $iStateID = 0 Local Const $BST_HOT = 0x0200 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 ; radio StateID Local Const $RBS_UNCHECKEDNORMAL = 1 Local Const $RBS_UNCHECKEDHOT = 2 Local Const $RBS_UNCHECKEDPRESSED = 3 Local Const $RBS_UNCHECKEDDISABLED = 4 Local Const $RBS_CHECKEDNORMAL = 5 Local Const $RBS_CHECKEDHOT = 6 Local Const $RBS_CHECKEDPRESSED = 7 Local Const $RBS_CHECKEDDISABLED = 8 Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) ; Determine StateID from current state Switch $iPartID Case $BP_CHECKBOX If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $CBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $CBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $CBS_UNCHECKEDHOT Else $iStateID = $CBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $CBS_CHECKEDNORMAL ElseIf BitAND($iState, $BST_INDETERMINATE) Then $iStateID = $CBS_MIXEDNORMAL EndIf Case $BP_RADIOBUTTON If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $RBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $RBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $RBS_UNCHECKEDHOT Else $iStateID = $RBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $RBS_CHECKEDNORMAL EndIf EndSwitch ; Determine DrawText $DT_* flags based on detected styles Local $iTextFlags Select Case StringInStr($sStyles, "BS_RIGHT") <> 0 $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_RIGHT) Case StringInStr($sStyles, "BS_CENTER") <> 0 $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_CENTER) Case Else $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_LEFT) EndSelect ; GetThemeBackgroundContentRect Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $iPartID, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $iPartID, 0, Null, Null, $TS_TRUE) ; Get text from control Local $sText = _WinAPI_GetWindowText($hWnd) ; DrawThemeParentBackground _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) ; DrawThemeBackground Local $iWidth = $tSIZE.X Local $iHeight = $tSIZE.Y Local $iClientHeight = $tClient.Bottom - $tClient.Top Local $iHeightPad = ($iClientHeight - $iHeight) Local $tRect = _WinAPI_CreateRectEx(0, 0, $iWidth, $iHeight + $iHeightPad) _WinAPI_DrawThemeBackground($hTheme, $iPartID, $iStateID, $hMemDC, $tRect) ; Set flags for DTTOPTS structure Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', $DTT_TEXTCOLOR) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; Setup font Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hMemDC, $hFont) $tTextRect.Left = $tTextRect.Left + $tSIZE.X + 3 $tTextRect.Right = $tTextRect.Right + $tSIZE.X + 3 _WinAPI_DrawThemeTextEx($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $sText, $tTextRect, $iTextFlags, $tDTTOPTS) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; Cleanup _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkTheme_ButtonProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc Edited Monday at 10:59 PM by WildByDesign
argumentum Posted yesterday at 03:27 AM Posted yesterday at 03:27 AM expandcollapse popup#include <ButtonConstants.au3> #include <WindowsStylesConstants.au3> #include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> Global Const $BP_RADIOBUTTON = 2 Global Const $BP_CHECKBOX = 3 Global Const $BP_GROUPBOX = 4 Global Const $GBS_NORMAL = 1 Global Const $GBS_DISABLED = 2 Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Register Subclassing / Window Procedure Local $hSubclass = DllCallbackRegister(__GUIDarkTheme_ButtonProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") Local $hGroupProc = DllCallbackRegister(__GUIDarkTheme_GroupProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") Local $idGroup = GUICtrlCreateGroup("Group 1", 30, 40, 140, 110) Local $hGroup = GUICtrlGetHandle(-1) Local $idRadio1 = GUICtrlCreateRadio("Radio 1", 40, 65) Local $hRadio1 = GUICtrlGetHandle(-1) Local $idRadio2 = GUICtrlCreateRadio("Radio 2", 40, 95) Local $hRadio2 = GUICtrlGetHandle(-1) GUICtrlCreateGroup("", -99, -99, 1, 1) ; close group Local $idButton_Close = GUICtrlCreateButton("Close", 210, 160) _WinAPI_SetWindowTheme(GUICtrlGetHandle(-1), "DarkMode_Explorer") ; Subclass group _WinAPI_SetWindowSubclass($hGroup, DllCallbackGetPtr($hGroupProc), $idGroup) ; Subclass controls Local $sStyles = "BS_AUTORADIOBUTTON, WS_CHILD, WS_VISIBLE, WS_TABSTOP" Local $tStruct2 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct2, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct2, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1, DllStructGetPtr($tStruct2)) Local $tStruct3 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct3, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct3, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2, DllStructGetPtr($tStruct3)) ; Display the GUI GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1) _WinAPI_RemoveWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2) _WinAPI_RemoveWindowSubclass($hGroup, DllCallbackGetPtr($hGroupProc), $idGroup) DllCallbackFree($hSubclass) DllCallbackFree($hGroupProc) GUIDelete($hGUI) EndFunc ;==>Example Func __GUIDarkTheme_GroupProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering Case $WM_PAINT Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) ; Setup font matching current GUI configuration Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hMemDC, $hFont) ; Ensure parent background is drawn cleanly over empty buffer _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) ; Get text from groupbox Local $sText = _WinAPI_GetWindowText($hWnd) Local $tTextSize = _WinAPI_GetTextExtentPoint32($hMemDC, $sText) Local $iTextWidth = $tTextSize.X Local $iTextHeight = $tTextSize.Y ; Compute Frame geometry (Border centers vertically across text height) Local $tFrameRect = _WinAPI_GetClientRect($hWnd) $tFrameRect.Top += Int($iTextHeight / 2) ; Compute accurately-padded exclusion rectangle for text cutout Local $tClipRect = _WinAPI_CreateRectEx(7, 0, $iTextWidth + 6, $iTextHeight) If $sText <> "" Then _WinAPI_ExcludeClipRect($hMemDC, $tClipRect) EndIf ; Draw border frame (Using a subtle dark gray frame for modern Dark mode appearance) Local $hBrush = _WinAPI_CreateSolidBrush(_WinAPI_SwitchColor(0x505050)) _WinAPI_FrameRect($hMemDC, $tFrameRect, $hBrush) _WinAPI_DeleteObject($hBrush) ; Remove clipping region restriction to render text safely _WinAPI_SelectClipRgn($hMemDC, 0) ; Draw Groupbox Label text if it exists If $sText <> "" Then Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', $DTT_TEXTCOLOR) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; Pure white text Local $iTextFlags = BitOR($DT_SINGLELINE, $DT_LEFT, $DT_TOP) Local $tDrawTextRect = _WinAPI_CreateRectEx(9, 0, $iTextWidth, $iTextHeight) _WinAPI_DrawThemeTextEx($hTheme, $BP_GROUPBOX, $GBS_NORMAL, $hMemDC, $sText, $tDrawTextRect, $iTextFlags, $tDTTOPTS) _WinAPI_CloseThemeData($hTheme) EndIf ; Blit memory buffer back to main UI thread Paint DC _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; Thorough Device Context Resource Cleanup _WinAPI_SelectObject($hMemDC, $hOldFont) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkTheme_GroupProc Func __GUIDarkTheme_ButtonProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Switch $iMsg Case $WM_ERASEBKGND Return 1 Case $WM_PAINT Local $tStruct = DllStructCreate("struct;int;wchar[256];endstruct", $pData) Local $iPartID = DllStructGetData($tStruct, 1) Local $sStyles = DllStructGetData($tStruct, 2) Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $iStateID = 0 Local Const $BST_HOT = 0x0200 Local Const $RBS_UNCHECKEDNORMAL = 1, $RBS_UNCHECKEDHOT = 2, $RBS_UNCHECKEDPRESSED = 3, $RBS_UNCHECKEDDISABLED = 4 Local Const $RBS_CHECKEDNORMAL = 5, $RBS_CHECKEDHOT = 6, $RBS_CHECKEDPRESSED = 7, $RBS_CHECKEDDISABLED = 8 Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDDISABLED : $RBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDPRESSED : $RBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDHOT : $RBS_UNCHECKEDHOT Else $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDNORMAL : $RBS_UNCHECKEDNORMAL EndIf Local $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_LEFT) If StringInStr($sStyles, "BS_RIGHT") Then $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_RIGHT) If StringInStr($sStyles, "BS_CENTER") Then $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_CENTER) Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $iPartID, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $iPartID, 0, Null, Null, $TS_TRUE) Local $sText = _WinAPI_GetWindowText($hWnd) _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) Local $iWidth = $tSIZE.X Local $iHeight = $tSIZE.Y Local $iClientHeight = $tClient.Bottom - $tClient.Top Local $iYOffset = Int(($iClientHeight - $iHeight) / 2) Local $tRect = _WinAPI_CreateRectEx(0, $iYOffset, $iWidth, $iHeight) _WinAPI_DrawThemeBackground($hTheme, $iPartID, $iStateID, $hMemDC, $tRect) Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', $DTT_TEXTCOLOR) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hMemDC, $hFont) $tTextRect.Left = $tRect.Right + 4 _WinAPI_DrawThemeTextEx($hTheme, $iPartID, $iStateID, $hMemDC, $sText, $tTextRect, $iTextFlags, $tDTTOPTS) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hMemDC, $hOldFont) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkTheme_ButtonProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
Solution argumentum Posted yesterday at 03:38 AM Solution Posted yesterday at 03:38 AM Spoiler expandcollapse popup#include <ButtonConstants.au3> #include <WindowsStylesConstants.au3> #include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <GDIPlus.au3> Global Const $BP_RADIOBUTTON = 2 Global Const $BP_CHECKBOX = 3 Global Const $BP_GROUPBOX = 4 Global Const $GBS_NORMAL = 1 Global Const $GBS_DISABLED = 2 Example() Func Example() _GDIPlus_Startup() Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") Local $hSubclass = DllCallbackRegister(__GUIDarkTheme_ButtonProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") Local $hGroupProc = DllCallbackRegister(__GUIDarkTheme_GroupProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") ; Standard default styles are preserved, but comctl32 subclass will safely separate background layers. Local $idGroup = GUICtrlCreateGroup("Group 1", 30, 40, 140, 110) Local $hGroup = GUICtrlGetHandle(-1) Local $idRadio1 = GUICtrlCreateRadio("Radio 1", 40, 65) Local $hRadio1= GUICtrlGetHandle(-1) Local $idRadio2 = GUICtrlCreateRadio("Radio 2", 40, 95) Local $hRadio2 = GUICtrlGetHandle(-1) GUICtrlCreateGroup("", -99, -99, 1, 1) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 160) _WinAPI_SetWindowTheme(GUICtrlGetHandle(-1), "DarkMode_Explorer") _WinAPI_SetWindowSubclass($hGroup, DllCallbackGetPtr($hGroupProc), $idGroup) Local $sStyles = "BS_AUTORADIOBUTTON, WS_CHILD, WS_VISIBLE, WS_TABSTOP" Local $tStruct2 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct2, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct2, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1, DllStructGetPtr($tStruct2)) Local $tStruct3 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct3, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct3, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2, DllStructGetPtr($tStruct3)) GUISetState(@SW_SHOW, $hGUI) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop EndSwitch WEnd _WinAPI_RemoveWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1) _WinAPI_RemoveWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2) _WinAPI_RemoveWindowSubclass($hGroup, DllCallbackGetPtr($hGroupProc), $idGroup) DllCallbackFree($hSubclass) DllCallbackFree($hGroupProc) GUIDelete($hGUI) _GDIPlus_Shutdown() EndFunc ;==>Example Func __GUIDarkTheme_GroupProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Switch $iMsg Case $WM_ERASEBKGND Return 1 Case $WM_PAINT Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hMemDC, $hFont) _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) Local $sText = _WinAPI_GetWindowText($hWnd) Local $tTextSize = _WinAPI_GetTextExtentPoint32($hMemDC, $sText) Local $iTextWidth = $tTextSize.X Local $iTextHeight = $tTextSize.Y Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hMemDC) _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2) Local $iRadius = 4 Local $iX = 1 Local $iY = Int($iTextHeight / 2) Local $iWidth = $iW - 1 - $iX Local $iHeight = $iH - 1 - $iY Local $hPath = _GDIPlus_PathCreate() _GDIPlus_PathAddLine($hPath, $iX + $iRadius, $iY, $iX + $iWidth - $iRadius, $iY) _GDIPlus_PathAddArc($hPath, $iX + $iWidth - ($iRadius * 2), $iY, $iRadius * 2, $iRadius * 2, 270, 90) _GDIPlus_PathAddLine($hPath, $iX + $iWidth, $iY + $iRadius, $iX + $iWidth, $iY + $iHeight - $iRadius) _GDIPlus_PathAddArc($hPath, $iX + $iWidth - ($iRadius * 2), $iY + $iHeight - ($iRadius * 2), $iRadius * 2, $iRadius * 2, 0, 90) _GDIPlus_PathAddLine($hPath, $iX + $iWidth - $iRadius, $iY + $iHeight, $iX + $iRadius, $iY + $iHeight) _GDIPlus_PathAddArc($hPath, $iX, $iY + $iHeight - ($iRadius * 2), $iRadius * 2, $iRadius * 2, 90, 90) _GDIPlus_PathAddLine($hPath, $iX, $iY + $iHeight - $iRadius, $iX, $iY + $iRadius) _GDIPlus_PathAddArc($hPath, $iX, $iY, $iRadius * 2, $iRadius * 2, 180, 90) _GDIPlus_PathCloseFigure($hPath) If $sText <> "" Then Local $hRegion = _GDIPlus_RegionCreate() _GDIPlus_RegionCombineRect($hRegion, 9, 0, $iTextWidth + 4, $iTextHeight, 0) _GDIPlus_GraphicsSetClipRegion($hGraphics, $hRegion, 3) _GDIPlus_RegionDispose($hRegion) EndIf Local $hPen = _GDIPlus_PenCreate(0xFF505050, 1) _GDIPlus_GraphicsDrawPath($hGraphics, $hPath, $hPen) _GDIPlus_GraphicsResetClip($hGraphics) _GDIPlus_PenDispose($hPen) _GDIPlus_PathDispose($hPath) If $sText <> "" Then Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', $DTT_TEXTCOLOR) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) Local $iTextFlags = BitOR($DT_SINGLELINE, $DT_LEFT, $DT_TOP) Local $tDrawTextRect = _WinAPI_CreateRectEx(11, 0, $iTextWidth, $iTextHeight) _WinAPI_DrawThemeTextEx($hTheme, $BP_GROUPBOX, $GBS_NORMAL, $hMemDC, $sText, $tDrawTextRect, $iTextFlags, $tDTTOPTS) _WinAPI_CloseThemeData($hTheme) EndIf _GDIPlus_GraphicsDispose($hGraphics) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) _WinAPI_SelectObject($hMemDC, $hOldFont) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkTheme_GroupProc Func __GUIDarkTheme_ButtonProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Switch $iMsg Case $WM_ERASEBKGND Return 1 Case $WM_PAINT Local $tStruct = DllStructCreate("struct;int;wchar[256];endstruct", $pData) Local $iPartID = DllStructGetData($tStruct, 1) Local $sStyles = DllStructGetData($tStruct, 2) Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $iStateID = 0 Local Const $BST_HOT = 0x0200 Local Const $RBS_UNCHECKEDNORMAL = 1, $RBS_UNCHECKEDHOT = 2, $RBS_UNCHECKEDPRESSED = 3, $RBS_UNCHECKEDDISABLED = 4 Local Const $RBS_CHECKEDNORMAL = 5, $RBS_CHECKEDHOT = 6, $RBS_CHECKEDPRESSED = 7, $RBS_CHECKEDDISABLED = 8 Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDDISABLED : $RBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDPRESSED : $RBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDHOT : $RBS_UNCHECKEDHOT Else $iStateID = BitAND($iState, $BST_CHECKED) ? $RBS_CHECKEDNORMAL : $RBS_UNCHECKEDNORMAL EndIf Local $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_LEFT) If StringInStr($sStyles, "BS_RIGHT") Then $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_RIGHT) If StringInStr($sStyles, "BS_CENTER") Then $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_CENTER) Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $iPartID, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $iPartID, 0, Null, Null, $TS_TRUE) Local $sText = _WinAPI_GetWindowText($hWnd) _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) Local $iWidth = $tSIZE.X Local $iHeight = $tSIZE.Y Local $iClientHeight = $tClient.Bottom - $tClient.Top Local $iYOffset = Int(($iClientHeight - $iHeight) / 2) Local $tRect = _WinAPI_CreateRectEx(0, $iYOffset, $iWidth, $iHeight) _WinAPI_DrawThemeBackground($hTheme, $iPartID, $iStateID, $hMemDC, $tRect) Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', $DTT_TEXTCOLOR) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hMemDC, $hFont) $tTextRect.Left = $tRect.Right + 4 _WinAPI_DrawThemeTextEx($hTheme, $iPartID, $iStateID, $hMemDC, $sText, $tTextRect, $iTextFlags, $tDTTOPTS) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hMemDC, $hOldFont) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__GUIDarkTheme_ButtonProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc ..rounded corners WildByDesign and donnyh13 1 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted yesterday at 09:39 AM Author Posted yesterday at 09:39 AM @argumentum This is so impressive. I go to sleep and you do some sort of magic overnight. Excellent work! Everything lines up perfectly. We've got a squared version which I suppose could work for Windows 10 users and a rounded version for Windows 11 users. And with the amount of Groupboxes that we have coming up soon, that would have been blinding for the users on those affected OS builds. You are going to save many eyes with this work. Thank you. argumentum 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now