-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathLV_HeaderCustomDraw.ahk
224 lines (212 loc) · 10.1 KB
/
LV_HeaderCustomDraw.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
; Title: colored listview headers
; Link: autohotkey.com/boards/viewtopic.php?f=76&t=87318
; Author: just me & Bugz000
; Date: 07.03.2021
; for: AHK_L
; rem: in progress?
/*
#NoEnv
SetBatchLines, -1
; MsgBox, % Format("{:06X}", DllCall("GetSysColor", "Int", 15, "UInt"))
; Create a GUI with a ListView
Gui, +hwndHGUI
Gui, Margin, 10, 10
Gui, Color, 0xFFFFAA, 0xFFFFEE
Gui, Font, s12, Roboto
Gui, Add, ListView, w600 r20 hwndHLV Grid NoSort gSubLV AltSubmit ; BackgroundFFFFAA
, Message|State|Item|HickCount ; C0000FF
; Get the HWND of the ListView's Header control
HHDR := DllCall("SendMessage", "Ptr", HLV, "UInt", 0x101F, "Ptr", 0, "Ptr", 0, "UPtr") ; LVM_GETHEADER
; Create an object containing the color for each Header control
HeaderColors := {}
HeaderColors[HHDR] := {Txt: 0xFFFFFF, Bkg: 0x384337, Grid: 1} ; Note: It's BGR instead of RGB!
SubClassControl(HLV, "LV_HeaderCustomDraw")
; LV_ModifyCol(0, "AutoHdr")
LV_ModifyCol(1, "Right 150")
LV_ModifyCol(2, "Center 150")
LV_ModifyCol(3, "Right 150")
LV_ModifyCol(4, "100")
Loop 40 {
arr := []
Loop 4 {
Random, val, 1, 365
arr.Push((A_Index=1 ? Format("0x{:04X}",val) : val))
}
LV_Add("", arr*)
}
LV_ModifyCol("AutoHdr")
; ----------------------------------------------------------------------------------------------------------------------
; DllCall("UxTheme.dll\SetWindowTheme", "Ptr", HHEADER, "Ptr", 0, "Str", "") ; Win XP
; Control, Style, +0x0200, , ahk_id %HHEADER% ; Win XP (HDS_FLAT = 0x0200)
; ----------------------------------------------------------------------------------------------------------------------
Gui, Show, , Colored LV Header
; Redraw the Header to get the notfications for all Header items
WinSet, Redraw, , ahk_id %HHEADER%
Return
GuiClose:
GuiEscape:
ExitApp
SubLV:
; ToolTip, %A_GuiEvent% - %ErrorLevel%
Return
*/
LV_HeaderCustomDraw(H, M, W, L, IdSubclass, RefData) {
Static DC_Brush := DllCall("GetStockObject", "UInt", 18, "UPtr") ; DC_BRUSH = 18
Static DC_Pen := DllCall("GetStockObject", "UInt", 19, "UPtr") ; DC_PEN = 19
Static DefGridClr := DllCall("GetSysColor", "Int", 15, "UInt") ; COLOR_3DFACE
Static HDM_GETITEM := (A_IsUnicode ? 0x120B : 0x1203) ; ? HDM_GETITEMW : HDM_GETITEMA
Static OHWND := 0
Static OCode := (2 * A_PtrSize)
Static ODrawStage := OCode + A_PtrSize
Static OHDC := ODrawStage + A_PtrSize
static ORect := OHDC + A_PtrSize
Static OItemSpec := ORect + 16
Static OItemState := OItemSpec + A_PtrSize
Static LM := 0 ; left margin of the first column (determined experimentally)
Static TM := 6 ; left and right text margins (determined experimentally)
Global HeaderColors
;
Critical 1000 ; ?
;
If (M = 0x004E) && (NumGet(L + OCode, "Int") = -12) { ; WM_NOTIFY -> NM_CUSTOMDRAW
; Get sending control's HWND
HHD := NumGet(L + OHWND, "UPtr")
; If HeaderColors contains an appropriate key ...
If HeaderColors.HasKey(HHD) {
HC := HeaderColors[HHD]
DrawStage := NumGet(L + ODrawStage, "UInt")
; -------------------------------------------------------------------------------------------------------------
If (DrawStage = 0x00010001) { ; CDDS_ITEMPREPAINT
; Get the item's text, format and column order
Item := NumGet(L + OItemSpec, "Ptr")
, VarSetCapacity(HDITEM, 24 + (6 * A_PtrSize), 0)
, VarSetCapacity(ItemTxt, 520, 0)
, NumPut(0x86, HDITEM, "UInt") ; HDI_TEXT (0x02) | HDI_FORMAT (0x04) | HDI_ORDER (0x80)
, NumPut(&ItemTxt, HDITEM, 8, "Ptr")
, NumPut(260, HDITEM, 8 + (2 * A_PtrSize), "Int")
, DllCall("SendMessage", "Ptr", HHD, "UInt", HDM_GETITEM, "Ptr", Item, "Ptr", &HDITEM)
, VarSetCapacity(ItemTxt, -1)
, Fmt := NumGet(HDITEM, 12 + (2 * A_PtrSize), "UInt") & 3
, Order := NumGet(HDITEM, 20 + (3 * A_PtrSize), "Int")
; Get the device context
, HDC := NumGet(L + OHDC, "Ptr")
; Draw a solid rectangle for the background
, VarSetCapacity(RC, 16, 0)
, DllCall("CopyRect", "Ptr", &RC, "Ptr", L + ORect)
, NumPut(NumGet(RC, "Int") + (!(Item | Order) ? LM : 0), RC, "Int")
, NumPut(NumGet(RC, 8, "Int") + 1, RC, 8, "Int")
, DllCall("SetDCBrushColor", "Ptr", HDC, "UInt", HC.Bkg)
, DllCall("FillRect", "Ptr", HDC, "Ptr", &RC, "Ptr", DC_Brush)
; Draw the text
DllCall("SetBkMode", "Ptr", HDC, "UInt", 0)
, DllCall("SetTextColor", "Ptr", HDC, "UInt", HC.Txt)
, DllCall("InflateRect", "Ptr", L + ORect, "Int", -TM, "Int", 0)
; DT_EXTERNALLEADING (0x0200) | DT_SINGLELINE (0x20) | DT_VCENTER (0x04)
; HDF_LEFT (0) -> DT_LEFT (0), HDF_CENTER (2) -> DT_CENTER (1), HDF_RIGHT (1) -> DT_RIGHT (2)
, DT_ALIGN := 0x0224 + ((Fmt & 1) ? 2 : (Fmt & 2) ? 1 : 0)
, DllCall("DrawText", "Ptr", HDC, "Ptr", &ItemTxt, "Int", -1, "Ptr", L + ORect, "UInt", DT_ALIGN)
; Draw a 'grid' line at the left edge of the item if required
If (HC.Grid) && (Order) {
DllCall("SelectObject", "Ptr", HDC, "Ptr", DC_Pen, "UPtr")
, DllCall("SetDCPenColor", "Ptr", HDC, "UInt", DefGridClr)
, NumPut(NumGet(RC, 0, "Int"), RC, 8, "Int")
, DllCall("Polyline", "Ptr", HDC, "Ptr", &RC, "Int", 2)
}
Return 4 ; CDRF_SKIPDEFAULT
}
; -------------------------------------------------------------------------------------------------------------
If (DrawStage = 1) { ; CDDS_PREPAINT
Return 0x30 ; CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT
}
; -------------------------------------------------------------------------------------------------------------
If (DrawStage = 2) { ; CDDS_POSTPAINT
VarSetCapacity(RC, 16, 0)
, DllCall("GetClientRect", "Ptr", HHD, "Ptr", &RC, "UInt")
, Cnt := DllCall("SendMessage", "Ptr", HHD, "UInt", 0x1200, "Ptr", 0, "Ptr", 0, "Int") ; HDM_GETITEMCOUNT
, VarSetCapacity(RCI, 16, 0)
, DllCall("SendMessage", "Ptr", HHD, "UInt", 0x1207, "Ptr", Cnt - 1, "Ptr", &RCI) ; HDM_GETITEMRECT
, R1 := NumGet(RC, 8, "Int")
, R2 := NumGet(RCI, 8, "Int")
If (R2 < R1) {
HDC := NumGet(L + OHDC, "UPtr")
, NumPut(R2, RC, 0, "Int")
, DllCall("SetDCBrushColor", "Ptr", HDC, "UInt", HC.Bkg)
, DllCall("FillRect", "Ptr", HDC, "Ptr", &RC, "Ptr", DC_Brush)
If (HC.Grid) {
DllCall("SelectObject", "Ptr", HDC, "Ptr", DC_Pen, "UPtr")
, DllCall("SetDCPenColor", "Ptr", HDC, "UInt", DefGridClr)
, NumPut(NumGet(RC, 0, "Int"), RC, 8, "Int")
, DllCall("Polyline", "Ptr", HDC, "Ptr", &RC, "Int", 2)
}
}
Return 4 ; CDRF_SKIPDEFAULT
}
; All other drawing stages ------------------------------------------------------------------------------------
Return 0 ; CDRF_DODEFAULT
}
}
Else If (M = 0x0002) { ; WM_DESTROY
SubclassControl(H, "") ; remove the subclass procedure
}
; All messages not completely handled by the function must be passed to the DefSubclassProc:
Return DllCall("DefSubclassProc", "Ptr", H, "UInt", M, "Ptr", W, "Ptr", L, "Ptr")
}
; ======================================================================================================================
; SubclassControl Installs, updates, or removes the subclass callback for the specified control.
; Parameters: HCTL - Handle to the control.
; FuncName - Name of the callback function as string.
; If you pass an empty string, the subclass callback will be removed.
; Data - Optional integer value passed as dwRefData to the callback function.
; Return value: Non-zero if the subclass callback was successfully installed, updated, or removed;
; otherwise, False.
; Remarks: The callback function must have exactly six parameters, see
; SUBCLASSPROC -> msdn.microsoft.com/en-us/library/bb776774(v=vs.85).aspx
; MSDN: Subclassing Controls -> msdn.microsoft.com/en-us/library/bb773183(v=vs.85).aspx
; ======================================================================================================================
SubclassControl(HCTL, FuncName, Data := 0) {
Static ControlCB := []
If ControlCB.HasKey(HCTL) {
DllCall("RemoveWindowSubclass", "Ptr", HCTL, "Ptr", ControlCB[HCTL], "Ptr", HCTL)
DllCall("GlobalFree", "Ptr", ControlCB[HCTL], "Ptr")
ControlCB.Delete(HCTL)
If !FuncName
Return True
}
If !DllCall("IsWindow", "Ptr", HCTL, "UInt")
|| !IsFunc(FuncName) || (Func(FuncName).MaxParams <> 6)
|| !(CB := RegisterCallback(FuncName, , 6))
Return False
If !DllCall("SetWindowSubclass", "Ptr", HCTL, "Ptr", CB, "Ptr", HCTL, "Ptr", Data)
Return (DllCall("GlobalFree", "Ptr", CB, "Ptr") & 0)
Return (ControlCB[HCTL] := CB)
}
; ======================================================================================================================
/*
SubclassProc(hWnd, uMsg, wParam, lParam, uIdSubclass, dwRefData) {
...
...
...
; All messages not completely handled by the function must be passed to the DefSubclassProc:
Return DllCall("DefSubclassProc", "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam, "Ptr")
}
*/
/*
typedef struct _HD_ITEMA {
UINT mask;
int cxy;
LPSTR pszText;
HBITMAP hbm;
int cchTextMax;
int fmt;
LPARAM lParam;
int iImage;
int iOrder;
UINT type;
void *pvFilter;
UINT state;
} HDITEMA, *LPHDITEMA;
#define DT_LEFT 0x00000000
#define DT_CENTER 0x00000001
#define DT_RIGHT 0x00000002
#define DT_VCENTER 0x00000004
*/