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
|
// 16 august 2014
enum {
checkboxStateChecked = 1 << 0,
checkboxStateHot = 1 << 1,
checkboxStatePushed = 1 << 2,
checkboxnStates = 1 << 3,
};
// TODO actually make this
#define panichresult(a, b) panic(a)
static UINT dfcState(int cbstate)
{
UINT ret;
ret = DFCS_BUTTONCHECK;
if ((cbstate & checkboxStateChecked) != 0)
ret |= DFCS_CHECKED;
if ((cbstate & checkboxStateHot) != 0)
ret |= DFCS_HOT;
if ((cbstate & checkboxStatePushed) != 0)
ret |= DFCS_PUSHED;
return ret;
}
static void drawFrameControlCheckbox(HDC dc, RECT *r, int cbState)
{
if (DrawFrameControl(dc, r, DFC_BUTTON, dfcState(cbState)) == 0)
panic("error drawing Table checkbox image with DrawFrameControl()");
}
static void getFrameControlCheckboxSize(HDC dc, int *width, int *height)
{
// there's no real metric around
// let's use SM_CX/YSMICON and hope for the best
*width = GetSystemMetrics(SM_CXSMICON);
*height = GetSystemMetrics(SM_CYSMICON);
}
static int themestates[checkboxnStates] = {
CBS_UNCHECKEDNORMAL, // 0
CBS_CHECKEDNORMAL, // checked
CBS_UNCHECKEDHOT, // hot
CBS_CHECKEDHOT, // checked | hot
CBS_UNCHECKEDPRESSED, // pushed
CBS_CHECKEDPRESSED, // checked | pushed
CBS_UNCHECKEDPRESSED, // hot | pushed
CBS_CHECKEDPRESSED, // checked | hot | pushed
};
static SIZE getStateSize(HDC dc, int cbState, HTHEME theme)
{
SIZE s;
HRESULT res;
res = GetThemePartSize(theme, dc, BP_CHECKBOX, themestates[cbState], NULL, TS_DRAW, &s);
if (res != S_OK)
panichresult("error getting theme part size for Table checkboxes", res);
return s;
}
static void drawThemeCheckbox(HDC dc, RECT *r, int cbState, HTHEME theme)
{
HRESULT res;
res = DrawThemeBackground(theme, dc, BP_CHECKBOX, themestates[cbState], r, NULL);
if (res != S_OK)
panichresult("error drawing Table checkbox image from theme", res);
}
static void getThemeCheckboxSize(HDC dc, int *width, int *height, HTHEME theme)
{
SIZE size;
int cbState;
size = getStateSize(dc, 0, theme);
for (cbState = 1; cbState < checkboxnStates; cbState++) {
SIZE against;
against = getStateSize(dc, cbState, theme);
if (size.cx != against.cx || size.cy != against.cy)
// TODO make this use a no-information (or two ints) panic()
panic("size mismatch in Table checkbox states");
}
*width = (int) size.cx;
*height = (int) size.cy;
}
static void drawCheckbox(struct table *t, HDC dc, int x, int y, int cbState)
{
RECT r;
r.left = x;
r.top = y;
r.right = r.bottom + t->checkboxWidth;
r.bottom = r.top + t->checkboxHeight;
if (t->theme != NULL) {
drawThemeCheckbox(dc, &r, cbState, t->theme);
return;
}
drawFrameControlCheckbox(dc, &r, cbState);
}
static void freeCheckboxThemeData(struct table *t)
{
if (t->theme != NULL) {
HRESULT res;
res = CloseThemeData(t->theme);
if (res != S_OK)
panichresult("error closing Table checkbox theme", res);
t->theme = NULL;
}
}
static void loadCheckboxThemeData(struct table *t)
{
HDC dc;
freeCheckboxThemeData(t);
dc = GetDC(t->hwnd);
if (dc == NULL)
panic("error getting Table DC for loading checkbox theme data");
// ignore error; if it can't be done, we can fall back to DrawFrameControl()
if (t->theme == NULL) // try to open the theme
t->theme = OpenThemeData(t->hwnd, L"button");
if (t->theme != NULL) // use the theme
getThemeCheckboxSize(dc, &(t->checkboxWidth), &(t->checkboxHeight), t->theme);
else // couldn't open; fall back
getFrameControlCheckboxSize(dc, &(t->checkboxWidth), &(t->checkboxHeight));
if (ReleaseDC(t->hwnd, dc) == 0)
panic("error releasing Table DC for loading checkbox theme data");
}
|