-
Notifications
You must be signed in to change notification settings - Fork 0
/
ListBoxPlus.h
302 lines (260 loc) · 9.17 KB
/
ListBoxPlus.h
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#pragma once
#include "WindowsPlus.h"
#include <Windowsx.h>
#include "Rad/MessageHandler.h"
struct Theme
{
COLORREF clrWindow = GetSysColor(COLOR_WINDOW);
COLORREF clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
COLORREF clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
COLORREF clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
COLORREF clrGrayText = GetSysColor(COLOR_GRAYTEXT);
HBRUSH brWindow = NULL;
HBRUSH brHighlight = NULL;
};
extern Theme g_Theme;
inline void InitTheme()
{
g_Theme.brWindow = CreateSolidBrush(g_Theme.clrWindow);
g_Theme.brHighlight = CreateSolidBrush(g_Theme.clrHighlight);
}
class ListBox
{
public:
void Create(_In_ HWND hParent, _In_ DWORD dwStyle, _In_ RECT rPos, _In_ int nID)
{
const HINSTANCE hInstance = NULL;
m_hWnd = CreateWindow(WC_LISTBOX, nullptr, dwStyle, rPos.left, rPos.top, Width(rPos), Height(rPos), hParent, reinterpret_cast<HMENU>(static_cast<INT_PTR>(nID)), hInstance, NULL);
CHECK_LE(m_hWnd);
}
operator bool() const { return m_hWnd != NULL; }
operator HWND() const { return m_hWnd; }
void ResetContent() { ListBox_ResetContent(m_hWnd); }
int AddString(LPCTSTR lpsz) { return ListBox_AddString(m_hWnd, lpsz); }
int AddItemData(LPARAM data) { return ListBox_AddItemData(m_hWnd, data); }
int GetCount() const { return ListBox_GetCount(m_hWnd); }
int GetCurSel() const { return ListBox_GetCurSel(m_hWnd); }
LPARAM GetItemData(int i) const { return ListBox_GetItemData(m_hWnd, i); }
int GetItemRect(int i, LPRECT pRect) const { return ListBox_GetItemRect(m_hWnd, i, pRect); }
int GetText(int i, LPTSTR lpszBuffer) const { return ListBox_GetText(m_hWnd, i, lpszBuffer); }
int SetCurSel(int i) { return ListBox_SetCurSel(m_hWnd, i); }
int SetItemData(int i, LPARAM data) { return ListBox_SetItemData(m_hWnd, i, data); }
int SetTopIndex(int i) const { return ListBox_SetTopIndex(m_hWnd, i); }
int FindStringExact(int i, LPCTSTR lpsz) const { return ListBox_FindStringExact(m_hWnd, i, lpsz); }
int GetVisibleCount() const
{
RECT rcClient;
GetClientRect(*this, &rcClient);
RECT rcItem;
GetItemRect(0, &rcItem);
return Height(rcClient) / Height(rcItem);
}
private:
HWND m_hWnd{ NULL };
};
class ListBoxOwnerDrawnFixed : public ListBox, public MessageChain
{
private:
struct ItemData
{
LPCTSTR pStr;
LPARAM lParam;
int iIcon;
};
ItemData* GetInternalItemData(int i)
{
const LPARAM lParam = ListBox::GetItemData(i);
ItemData* pData = lParam == CB_ERR ? nullptr : reinterpret_cast<ItemData*>(lParam);
if (pData == nullptr)
{
pData = new ItemData({});
pData->iIcon = -1;
ListBox::SetItemData(i, reinterpret_cast<LPARAM>(pData));
}
return pData;
}
const ItemData* GetInternalItemData(int i) const
{
const LPARAM lParam = ListBox::GetItemData(i);
ItemData* pData = lParam == CB_ERR ? nullptr : reinterpret_cast<ItemData*>(lParam);
return pData;
}
bool HasString() const
{
const DWORD dwStyle = GetWindowStyle(*this);
return dwStyle & LBS_HASSTRINGS;
}
public:
void Create(_In_ HWND hParent, _In_ DWORD dwStyle, _In_ RECT rPos, _In_ int nID)
{
m_nID = nID;
ListBox::Create(hParent, dwStyle | LBS_OWNERDRAWFIXED, rPos, nID);
}
int GetIconMode() const
{
return m_IconMode;
}
void SetIconMode(int icon_mode)
{
m_IconMode = icon_mode;
}
SIZE GetIconSize() const
{
return { GetSystemMetrics(m_IconMode == ICON_SMALL ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(m_IconMode == ICON_SMALL ? SM_CYSMICON : SM_CYICON) };
}
HIMAGELIST SetImageList(HIMAGELIST hNewImageList)
{
HIMAGELIST hOldImageList = m_hImageList;
m_hImageList = hNewImageList;
return hOldImageList;
}
HIMAGELIST GetImageList() const
{
return m_hImageList;
}
int AddString(LPCTSTR lpsz)
{
if (HasString())
return ListBox::AddString(lpsz);
else
{
ItemData* pData = new ItemData({});
pData->iIcon = -1;
pData->pStr = lpsz;
return ListBox::AddItemData(LPARAM(pData));
}
}
int GetText(int i, LPTSTR lpszBuffer) const
{
if (HasString())
return ListBox::GetText(i, lpszBuffer);
else
{
if (i < 0 or i >= GetCount())
return LB_ERR;
const ItemData* pData = GetInternalItemData(i);
lstrcpy(lpszBuffer, pData->pStr);
return lstrlen(pData->pStr);
}
}
LPARAM GetItemData(int i) const
{
const ItemData* pData = GetInternalItemData(i);
return pData ? pData->lParam : 0;
}
void SetItemData(int i, LPARAM data)
{
ItemData* pData = GetInternalItemData(i);
pData->lParam = data;
}
int GetItemIconIndex(int i) const
{
const ItemData* pData = GetInternalItemData(i);
return pData->iIcon;
}
void SetItemIconIndex(int i, int iIcon)
{
ItemData* pData = GetInternalItemData(i);
pData->iIcon = iIcon;
InvalidateItem(i);
}
void InvalidateItem(int i)
{
if (IsWindow(*this))
{
RECT r;
GetItemRect(i, &r);
InvalidateRect(*this, &r, FALSE);
}
}
private:
void OnMeasureItem(MEASUREITEMSTRUCT* lpMeasureItem)
{
//if (lpMeasureItem->CtlType == ODT_LISTBOX and lpMeasureItem->CtlID == GetWindowLong(*this, GWL_ID))
if (lpMeasureItem->CtlType == ODT_LISTBOX and lpMeasureItem->CtlID == m_nID)
{
if (m_IconMode >= 0)
lpMeasureItem->itemHeight = GetIconSize().cy + 4;
}
}
void OnDrawItem(const DRAWITEMSTRUCT* lpDrawItem)
{
if (lpDrawItem->hwndItem == *this)
{
if (lpDrawItem->itemID == -1) // Empty item
return;
const SIZE szIcon = GetIconSize();
/*const*/ ItemData* pData = reinterpret_cast<ItemData*>(lpDrawItem->itemData);
const COLORREF clrForeground = SetTextColor(lpDrawItem->hDC,
lpDrawItem->itemState & ODS_SELECTED ? g_Theme.clrHighlightText : g_Theme.clrWindowText);
const COLORREF clrBackground = SetBkColor(lpDrawItem->hDC,
lpDrawItem->itemState & ODS_SELECTED ? g_Theme.clrHighlight : g_Theme.clrWindow);
const HBRUSH hBrBackgournd = lpDrawItem->itemState & ODS_SELECTED ? g_Theme.brHighlight : g_Theme.brWindow;
FillRect(lpDrawItem->hDC, &lpDrawItem->rcItem, hBrBackgournd);
RECT rc = lpDrawItem->rcItem;
if (m_IconMode >= 0)
rc.left += szIcon.cx + 4;
if (!pData or HasString())
{
TCHAR text[1024];
const int cch = GetText(lpDrawItem->itemID, text);
DrawText(lpDrawItem->hDC, text, cch, &rc, DT_VCENTER | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX);
}
else
DrawText(lpDrawItem->hDC, pData->pStr, -1, &rc, DT_VCENTER | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX);
SetTextColor(lpDrawItem->hDC, clrForeground);
SetBkColor(lpDrawItem->hDC, clrBackground);
if (m_hImageList != NULL and pData and pData->iIcon >= 0)
{
ImageList_DrawEx(m_hImageList, pData->iIcon, lpDrawItem->hDC,
lpDrawItem->rcItem.left + 2, lpDrawItem->rcItem.top + 2, szIcon.cx, szIcon.cy,
CLR_DEFAULT, CLR_DEFAULT, ILD_NORMAL);
}
if (lpDrawItem->itemState & ODS_FOCUS)
DrawFocusRect(lpDrawItem->hDC, &lpDrawItem->rcItem);
}
}
void OnDeleteItem(const DELETEITEMSTRUCT* lpDeleteItem)
{
if (lpDeleteItem->hwndItem == *this)
{
ItemData* pData = reinterpret_cast<ItemData*>(lpDeleteItem->itemData);
if (pData)
{
//DestroyIcon(pData->hIcon);
delete pData;
}
}
}
int OnCompareItem(const COMPAREITEMSTRUCT* lpCompareItem)
{
if (lpCompareItem->hwndItem != *this || HasString())
{
SetHandled(false);
return 0;
}
else
{
LPCTSTR pStr1 = lpCompareItem->itemID1 == -1 ? reinterpret_cast<LPCTSTR>(lpCompareItem->itemData1) : reinterpret_cast<ItemData*>(lpCompareItem->itemData1)->pStr;
LPCTSTR pStr2 = reinterpret_cast<ItemData*>(lpCompareItem->itemData2)->pStr;
return lstrcmpi(pStr1, pStr2);
}
}
protected:
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override
{
LRESULT ret = 0;
switch (uMsg)
{
HANDLE_MSG(WM_MEASUREITEM, OnMeasureItem);
HANDLE_MSG(WM_DRAWITEM, OnDrawItem);
HANDLE_MSG(WM_DELETEITEM, OnDeleteItem);
HANDLE_MSG(WM_COMPAREITEM, OnCompareItem);
}
return ret;
}
private:
int m_nID{ 0 };
int m_IconMode{ -1 };
HIMAGELIST m_hImageList{ NULL };
};