Skip to content

Commit

Permalink
Update ColorButton.ahk
Browse files Browse the repository at this point in the history
**New Features:**
    - You can now customize the background color around buttons to give rounded buttons a smoother appearance.
    - Windows 10 users can also enable rounded buttons now.  
**Changes:**  
    - Our previous approach of using `RoundRect` to create rounded corners has been replaced with `CreateRoundRectRgn` + `SetWindowRgn` + `FillRect` for a higher-quality.

---

**新增:**
    - 現在可以設定按鈕周圍的背景顏色,使圓角按鈕的外觀更圓潤。
    - 現在 Windows 10 使用者也可以啟用圓角按鈕了。
**變更**
    - 原本使用 `RoundRect` 繪製圓角,但由於品質不佳,現已改用 `CreateRoundRectRgn` + `SetWindowRgn` + `FillRect` 來繪製圓角。
  • Loading branch information
nperovic authored Apr 29, 2024
1 parent 0ff45b0 commit 26ca136
Showing 1 changed file with 36 additions and 22 deletions.
58 changes: 36 additions & 22 deletions ColorButton.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* @file ColorButton.ahk
* @author Nikola Perovic
* @link https://github.com/nperovic/ColorButton.ahk
* @date 2024/04/28
* @version 1.0.1
* @date 2024/04/29
* @version 1.1.0
***********************************************************************/
#Requires AutoHotkey v2.1-alpha.9
Expand Down Expand Up @@ -37,14 +37,19 @@ class NMCUSTOMDRAWINFO {
* btn := myGui.AddButton(, "SUPREME")
* btn.SetBackColor(0xaa2031)
*/
class _BtnColor extends Gui.Button {
class _BtnColor extends Gui.Button
{
static __New() => super.Prototype.SetBackColor := ObjBindMethod(this, "SetBackColor")

/**
* @param {Gui.Button} myBtn
* @param {integer} bkColor
* @param {Gui.Button} myBtn omitted.
* @param {integer} btnBgColor Button's background color.
* @param {integer} [colorBehindBtn] The color of the button's surrounding area. If omitted, if will be the same as `myGui.BackColor`.
* @param {integer} [roundedCorner] Specifies the rounded corner preference for the button. If omitted, :
* > For Windows 11: Enabled. (value: 9)
* > For Windows 10: Disabled.
*/
static SetBackColor(myBtn, bkColor)
static SetBackColor(myBtn, btnBgColor, colorBehindBtn?, roundedCorner?)
{
static IS_WIN11 := (VerCompare(A_OSVersion, "10.0.22200") >= 0)
static WM_CTLCOLORBTN := 0x0135
Expand All @@ -54,57 +59,64 @@ class _BtnColor extends Gui.Button {
static WS_CLIPCHILDREN := 0x02000000
static WS_CLIPSIBLINGS := 0x04000000

clr := (IsNumber(bkColor) ? bkColor : Number((!InStr(bkColor, "0x") ? "0x" : "") bkColor))
clr := (IsNumber(btnBgColor) ? btnBgColor : Number((!InStr(btnBgColor, "0x") ? "0x" : "") btnBgColor))
hoverColor := BrightenColor(clr, 10)
hbrush := CreateSolidBrush(ColorHex(myBtn.Gui.BackColor))
btnBkColr := ColorHex(colorBehindBtn ?? myBtn.Gui.BackColor)
hbrush := CreateSolidBrush(btnBkColr)

myBtn.Gui.Opt("+E" WS_EX_COMPOSITED " +" WS_CLIPCHILDREN)
myBtn.Gui.Opt("+E" WS_EX_COMPOSITED )
myBtn.Gui.OnEvent("Close", (*) => (DeleteObject(hbrush), unset))

myBtn.Opt("+" WS_CLIPSIBLINGS)
SetWindowTheme(myBtn.hwnd, IsColorDark(clr) ? "DarkMode_Explorer" : "Explorer")
myBtn.Redraw()

myBtn.Gui.OnMessage(WM_CTLCOLORBTN, (GuiObj, wParam, *) {
Critical(-1)
SelectObject(wParam, hbrush)
SetBkMode(wParam, 0)
SetBkColor(wParam, ColorHex(GuiObj.BackColor))
SelectObject(wParam, hbrush)
SetBkColor(wParam, btnBkColr)
return hbrush
})
}, -1)

myBtn.OnNotify(NM_CUSTOMDRAW, (gCtrl, lParam) {
static CDDS_PREPAINT := 1
static CDDS_PREERASE := 0x3
static CDIS_HOT := 0x0040
static DC_BRUSH := 18
static DC_PEN := 19

Critical(-1)

/** @type {NMCUSTOMDRAWINFO} */
lpnmCD := StructFromPtr(NMCUSTOMDRAWINFO, lParam)
if (lpnmCD.hdr.code != NM_CUSTOMDRAW || lpnmCD.hdr.hwndFrom != gCtrl.hwnd || lpnmCD.dwDrawStage != CDDS_PREPAINT)
if (lpnmCD.hdr.code != NM_CUSTOMDRAW || lpnmCD.hdr.hwndFrom != gCtrl.hwnd || (lpnmCD.dwDrawStage != CDDS_PREPAINT))
return
Critical()
brushColor := RgbToBgr(GetKeyState("LButton", "P") || !(lpnmCD.uItemState & CDIS_HOT) ? clr : hoverColor )
if (IS_WIN11 || IsSet(roundedCorner)) {
rcRgn := CreateRoundRectRgn(lpnmCD.rc.left, lpnmCD.rc.top, lpnmCD.rc.right, lpnmCD.rc.bottom, roundedCorner ?? 9, roundedCorner ?? 9)
SetWindowRgn(lpnmCD.hdr.hwndFrom, rcRgn, 0)
}
SetBkMode(lpnmCD.hdc, 0)
SetDCBrushColor(lpnmCD.hdc, brushColor)
SelectObject(lpnmCD.hdc, bru := GetStockObject(DC_BRUSH))
SetDCPenColor(lpnmCD.hdc, brushColor)
SelectObject(lpnmCD.hdc, bru := GetStockObject(DC_BRUSH))
SelectObject(lpnmCD.hdc, GetStockObject(DC_PEN))
if IS_WIN11
RoundRect(lpnmCD.hdc, lpnmCD.rc.left, lpnmCD.rc.top, lpnmCD.rc.right, lpnmCD.rc.bottom, 8, 8)
else
FillRect(lpnmCD.hdc, lpnmCD.rc, bru)
FillRect(lpnmCD.hdc, lpnmCD.rc, bru)
if IsSet(rcRgn)
DeleteObject(rcRgn)
return true
})
RgbToBgr(color) => (IsInteger(color) ? ((Color >> 16) & 0xFF) | (Color & 0x00FF00) | ((Color & 0xFF) << 16) : NUMBER(RegExReplace(STRING(color), "Si)c?(?:0x)?(?<R>\w{2})(?<G>\w{2})(?<B>\w{2})", "0x${B}${G}${R}")))
CreateRoundRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, nWidthEllipse, nHeightEllipse) => DllCall('Gdi32\CreateRoundRectRgn', 'int', nLeftRect, 'int', nTopRect, 'int', nRightRect, 'int', nBottomRect, 'int', nWidthEllipse, 'int', nHeightEllipse, 'ptr')
CreateSolidBrush(crColor) => DllCall('Gdi32\CreateSolidBrush', 'uint', crColor, 'ptr')
ColorHex(clr) => Number((!InStr(clr, "0x") ? "0x" : "") clr)
Expand All @@ -115,6 +127,8 @@ class _BtnColor extends Gui.Button {
SetDCBrushColor(hdc, crColor) => DllCall('Gdi32\SetDCBrushColor', 'ptr', hdc, 'uint', crColor, 'uint')
SetWindowRgn(hWnd, hRgn, bRedraw) => DllCall("User32\SetWindowRgn", "ptr", hWnd, "ptr", hRgn, "int", bRedraw, "int")
DeleteObject(hObject) => DllCall('Gdi32\DeleteObject', 'ptr', hObject, 'int')
FillRect(hDC, lprc, hbr) => DllCall("User32\FillRect", "ptr", hDC, "ptr", lprc, "ptr", hbr, "int")
Expand Down

0 comments on commit 26ca136

Please sign in to comment.