Skip to content

Commit e9938db

Browse files
committed
The border width of the button is now customisable.
1 parent 7461656 commit e9938db

File tree

1 file changed

+52
-30
lines changed

1 file changed

+52
-30
lines changed

ColorButton.ahk

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
* @file ColorButton.ahk
44
* @author Nikola Perovic
55
* @link (https://github.com/nperovic/ColorButton.ahk)
6-
* @date 2024/06/06
7-
* @version 1.3.0
6+
* @date 2024/06/08
7+
* @version 1.3.1
88
***********************************************************************/
99
10-
#Requires AutoHotkey v2.0.15
10+
#Requires AutoHotkey v2.0.16
1111
#SingleInstance
1212
1313
; ================================================================================
@@ -257,13 +257,13 @@ class _BtnColor extends Gui.Button
257257
return dwTextFlags | DT_WORDBREAK
258258
}
259259

260-
/** Set/ Get the Button Text Color (RGB). (To set the text colour, you must have used `SetColor()`, `SetBackColor()`, or `BackColor` to set the background colour at least once beforehand.) */
260+
/** @prop {Integer} TextColor Set/ Get the Button Text Color (RGB). (To set the text colour, you must have used `SetColor()`, `SetBackColor()`, or `BackColor` to set the background colour at least once beforehand.) */
261261
TextColor {
262262
Get => this.HasProp("_textColor") && _BtnColor.RgbToBgr(this._textColor)
263263
Set => this._textColor := _BtnColor.RgbToBgr(value)
264264
}
265265
266-
/** Set/ Get the Button background Color (RGB). */
266+
/** @prop {Integer} BackColor Set/ Get the Button background Color (RGB). */
267267
BackColor {
268268
Get => this.HasProp("_clr") && _BtnColor.RgbToBgr(this._clr)
269269
Set {
@@ -281,30 +281,33 @@ class _BtnColor extends Gui.Button
281281
}
282282
}
283283
284-
/** Button border color (RGB). (To set the border colour, you must have used `SetColor()`, `SetBackColor()`, or `BackColor` to set the background colour at least once beforehand.)*/
284+
/** @prop {Integer} BorderColor Button border color (RGB). (To set the border colour, you must have used `SetColor()`, `SetBackColor()`, or `BackColor` to set the background colour at least once beforehand.)*/
285285
BorderColor {
286286
Get => this.HasProp("_borderColor") && _BtnColor.RgbToBgr(this._borderColor)
287287
Set => this._borderColor := _BtnColor.RgbToBgr(value)
288288
}
289289
290-
/** Rounded corner preference for the button. (To set the rounded corner preference, you must have used `SetColor()`, `SetBackColor()`, or `BackColor` to set the background colour at least once beforehand.) */
290+
/** @prop {Integer} RoundedCorner Rounded corner preference for the button. (To set the rounded corner preference, you must have used `SetColor()`, `SetBackColor()`, or `BackColor` to set the background colour at least once beforehand.) */
291291
RoundedCorner {
292-
Get => this.HasProp("_roundedCorner") && _BtnColor.RgbToBgr(this._roundedCorner)
292+
Get => this.HasProp("_roundedCorner") && this._roundedCorner
293293
Set => this._roundedCorner := value
294294
}
295295
296296
/**
297+
* @prop {Integer} ShowBorder
297298
* Border preference. (To set the border preference, you must have used `SetColor()`, `SetBackColor()`, or `BackColor` to set the background colour at least once beforehand.)
299+
* - `n` : The higher the value, the thicker the button's border when focused.
298300
* - `1` : Highlight when focused.
299301
* - `0` : No border displayed.
300302
* - `-1`: Border always visible.
303+
* - `-n`: The lower the value, the thicker the button's border when always visible.
301304
*/
302305
ShowBorder {
303-
Get => this.HasProp("_showBorder") && _BtnColor.RgbToBgr(this._showBorder)
306+
Get => this.HasProp("_showBorder") && this._showBorder
304307
Set {
305-
if ((value >= -1) && (value <= 1))
308+
if IsNumber(Value)
306309
this._showBorder := value
307-
else throw ValueError("The value must be -1, 0 or 1.", "ShowBorder")
310+
else throw TypeError("The value must be a number.", "ShowBorder")
308311
}
309312
}
310313

@@ -316,9 +319,11 @@ class _BtnColor extends Gui.Button
316319
* - For Windows 11: Enabled (value: 9).
317320
* - For Windows 10: Disabled.
318321
* @param {boolean} [showBorder=1]
319-
* - `1` : Highlight when focused.
320-
* - `0` : No border displayed.
322+
* - `n` : The higher the value, the thicker the button's border when focused.
323+
* - `1`: Highlight when focused.
324+
* - `0`: No border displayed.
321325
* - `-1`: Border always visible.
326+
* - `-n`: The lower the value, the thicker the button's border when always visible.
322327
* @param {number} [borderColor=0xFFFFFF] - Button border color (RGB).
323328
* @param {number} [txColor] - Button text color (RGB). If omitted, the text colour will be automatically set to white or black depends on the background colour.
324329
*/
@@ -329,9 +334,11 @@ class _BtnColor extends Gui.Button
329334
* @param {number} bgColor - Button's background color (RGB).
330335
* @param {number} [txColor] - Button text color (RGB). If omitted, the text colour will be automatically set to white or black depends on the background colour.
331336
* @param {boolean} [showBorder=1]
337+
* - `n` : The higher the value, the thicker the button's border when focused.
332338
* - `1` : Highlight when focused.
333339
* - `0` : No border displayed.
334340
* - `-1`: Border always visible.
341+
* - `-n`: The lower the value, the thicker the button's border when always visible.
335342
* @param {number} [borderColor=0xFFFFFF] - Button border color (RGB).
336343
* @param {number} [roundedCorner] - Rounded corner preference for the button. If omitted,
337344
* - For Windows 11: Enabled (value: 9).
@@ -349,7 +356,7 @@ class _BtnColor extends Gui.Button
349356
static BTN_STYLE := (WS_CLIPSIBLINGS | BS_FLAT | BS_BITMAP)
350357

351358
this._first := 1
352-
this._roundedCorner := roundedCorner ?? unset
359+
this._roundedCorner := roundedCorner ?? (IS_WIN11 ? 9 : 0)
353360
this._showBorder := showBorder
354361
this._clr := ColorHex(bgColor)
355362
this._isDark := _BtnColor.IsColorDark(this._clr)
@@ -387,6 +394,7 @@ class _BtnColor extends Gui.Button
387394
static DC_PEN := GetStockObject(19)
388395
static DT_CALCRECT := 0x400
389396
static DT_WORDBREAK := 0x10
397+
static PS_SOLID := 0
390398

391399
nmcd := NMCUSTOMDRAWINFO(lParam)
392400

@@ -396,30 +404,32 @@ class _BtnColor extends Gui.Button
396404
return CDRF_DODEFAULT
397405

398406
; Determine the background colour based on the button's status.
399-
isPressed := GetKeyState("LButton", "P")
400-
isHot := (nmcd.uItemState & CDIS_HOT)
407+
isPressed := GetKeyState("LButton", "P")
408+
isHot := (nmcd.uItemState & CDIS_HOT)
401409
brushColor := penColor := (!isHot || this._first ? this._clr : isPressed ? this._pushedColor : this._hoverColor)
402-
403-
SelectObject(nmcd.hdc, DC_PEN)
404-
SelectObject(nmcd.hdc, DC_BRUSH)
405410

406411
; Set Rounded Corner Preference ----------------------------------------------
407412

408413
rc := nmcd.rc
409-
corner := (this._roundedCorner ?? (IS_WIN11 ? 9 : 0))
414+
corner := this._roundedCorner
410415
SetWindowRgn(gCtrl.hwnd, CreateRoundRectRgn(rc.left, rc.top, rc.right, rc.bottom, corner, corner), 1)
411416
GetWindowRgn(gCtrl.hwnd, rcRgn := CreateRectRgn())
412417

413418
; Draw Border ----------------------------------------------------------------
414419

415-
if ((this._showBorder = -1) || (this._showBorder && !this._first && gCtrl.Focused && !isPressed)) {
416-
SetDCPenColor(nmcd.hdc, this._borderColor)
417-
FrameRect(nmcd.hdc, rc, DC_PEN)
418-
} else
420+
if ((this._showBorder < 0) || (this._showBorder > 0 && gCtrl.Focused)) {
421+
penColor := this._showBorder > 0 && !gCtrl.Focused ? penColor : this._borderColor
422+
hpen := CreatePen(PS_SOLID, this._showBorder, penColor)
423+
SelectObject(nmcd.hdc, hpen)
424+
FrameRect(nmcd.hdc, rc, DC_PEN)
425+
} else {
426+
SelectObject(nmcd.hdc, DC_PEN)
419427
SetDCPenColor(nmcd.hdc, penColor)
428+
}
420429

421430
; Draw Background ------------------------------------------------------------
422431

432+
SelectObject(nmcd.hdc, DC_BRUSH)
423433
SetDCBrushColor(nmcd.hdc, brushColor)
424434
RoundRect(nmcd.hdc, rc.left, rc.top, rc.right-1, rc.bottom-1, corner, corner)
425435

@@ -429,7 +439,8 @@ class _BtnColor extends Gui.Button
429439
dwTextFlags := this.GetTextFlags(&hCenter, &vCenter, &right, &bottom)
430440
SetBkMode(nmcd.hdc, 0)
431441
SetTextColor(nmcd.hdc, this._textColor)
432-
CopyRect(rcT := RECT(), nmcd.rc)
442+
443+
CopyRect(rcT := !NMCUSTOMDRAWINFO.HasProp("RECT") && IsSet(RECT) ? RECT() : NMCUSTOMDRAWINFO.RECT(), nmcd.rc)
433444

434445
; Calculate the text rect.
435446
DrawText(nmcd.hdc, textPtr, -1, rcT, DT_CALCRECT | dwTextFlags)
@@ -447,6 +458,10 @@ class _BtnColor extends Gui.Button
447458
this._first := 0
448459

449460
DeleteObject(rcRgn)
461+
462+
if (pen??0)
463+
DeleteObject(hpen)
464+
450465
SetWindowPos(this.hwnd, 0, 0, 0, 0, 0, 0x4043)
451466

452467
return CDRF_SKIPDEFAULT
@@ -478,6 +493,8 @@ class _BtnColor extends Gui.Button
478493

479494
CreateRoundRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, nWidthEllipse, nHeightEllipse) => DllCall('Gdi32\CreateRoundRectRgn', 'int', nLeftRect, 'int', nTopRect, 'int', nRightRect, 'int', nBottomRect, 'int', nWidthEllipse, 'int', nHeightEllipse, 'ptr')
480495

496+
CreatePen(fnPenStyle, nWidth, crColor) => DllCall('Gdi32\CreatePen', 'int', fnPenStyle, 'int', nWidth, 'uint', crColor, 'ptr')
497+
481498
CreateSolidBrush(crColor) => DllCall('Gdi32\CreateSolidBrush', 'uint', crColor, 'ptr')
482499

483500
DefWindowProc(hWnd, Msg, wParam, lParam) => DllCall("User32\DefWindowProc", "ptr", hWnd, "uint", Msg, "uptr", wParam, "uptr", lParam, "ptr")
@@ -539,33 +556,38 @@ myGui.BackColor := 0x202020
539556
/** @type {_BtnColor} */
540557
btn := btn2 := btn3 := btn4 := unset
541558
559+
; Rounded (Windows 11) or rectangle (Windows 10) button that will get its border on show when it's focused.
542560
btn := myGui.AddButton("xm w300", "Rounded Button")
543561
btn.SetColor("0xaa2031", "FFFFCC",, "fff5cc", 9)
544-
btn.OnEvent("Click", btnClicked)
545562
563+
; When you press the button each time, the background and text colours of the button swap around.
564+
btn.OnEvent("Click", btnClicked)
546565
btnClicked(btn, *) {
547566
static toggle := 0
548567
static textColor := btn.TextColor
549568
static backColor := btn.BackColor
550569
551570
if (toggle^=1) {
552-
btn.TextColor := backColor
571+
btn.TextColor := btn.BorderColor := backColor
553572
btn.backColor := textColor
554573
} else {
555-
btn.TextColor := TextColor
574+
btn.TextColor := btn.BorderColor := TextColor
556575
btn.backColor := backColor
557576
}
558577
}
559578
579+
; Rounded (Windows 11) or rectangle (Windows 10) button that’s got its border on show all the time.
560580
btn2 := myGui.AddButton("yp wp", "Border Always Visible")
561581
btn2.SetColor(myGui.BackColor, "fff5cc")
562582
btn2.BorderColor := btn2.TextColor
563-
btn2.ShowBorder := -1
583+
btn2.ShowBorder := -5
564584
585+
; Rectangle Button and show border outline when the button's focused.
565586
btn3 := myGui.AddButton("xm wp", "Rectangle Button")
566-
btn3.SetColor("4e479a", "c6c1f7")
587+
btn3.SetColor("4e479a", "c6c1f7", 2)
567588
btn3.RoundedCorner := 0
568589
590+
; Rectangle Button with no border outline.
569591
btn4 := myGui.AddButton("yp wp", "No Focused Outline")
570592
btn4.SetBackColor("008080",, 0, 0,, "AFEEEE")
571593

0 commit comments

Comments
 (0)