summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-12-17 21:56:37 -0500
committerPietro Gagliardi <[email protected]>2014-12-17 21:56:37 -0500
commitf22812ff0eff3d639773628a877360d3f76bfd50 (patch)
tree6ac4f24be2bab7b55766b2cd65bbc9b343c15211
parentb6340bd349dd78ff30f4a942a77fa4800ba6c579 (diff)
Brought back the code to build checkbox images.
-rw-r--r--wintable/new/checkboximages.h166
-rw-r--r--wintable/new/main.c14
2 files changed, 180 insertions, 0 deletions
diff --git a/wintable/new/checkboximages.h b/wintable/new/checkboximages.h
new file mode 100644
index 0000000..efef2dc
--- /dev/null
+++ b/wintable/new/checkboximages.h
@@ -0,0 +1,166 @@
+// 16 august 2014
+
+// 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 dfcImage(HDC dc, RECT *r, int cbState, HTHEME theme)
+{
+ if (DrawFrameControl(dc, r, DFC_BUTTON, dfcState(cbState)) == 0)
+ panic("error drawing Table checkbox image with DrawFrameControl()");
+}
+
+static void dfcSize(HDC dc, int *width, int *height, HTHEME theme)
+{
+ // 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 themeImage(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 themeSize(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 makeCheckboxImage(struct table *t, HDC dc, int cbState, void (*drawfunc)(HDC, RECT *, int, HTHEME))
+{
+ BITMAPINFO bi;
+ VOID *ppvBits;
+ HBITMAP bitmap;
+ RECT r;
+ HDC drawDC;
+ HBITMAP prevbitmap;
+
+ r.left = 0;
+ r.top = 0;
+ r.right = t->checkboxWidth;
+ r.bottom = t->checkboxHeight;
+ ZeroMemory(&bi, sizeof (BITMAPINFO));
+ bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+ bi.bmiHeader.biWidth = (LONG) (t->checkboxWidth);
+ bi.bmiHeader.biHeight = -((LONG) (t->checkboxHeight)); // negative height to force top-down drawing;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = 32;
+ bi.bmiHeader.biCompression = BI_RGB;
+ bi.bmiHeader.biSizeImage = (DWORD) (t->checkboxWidth * t->checkboxHeight * 4);
+ bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0);
+ if (bitmap == NULL)
+ panic("error creating HBITMAP for Table checkbox image");
+
+ drawDC = CreateCompatibleDC(dc);
+ if (drawDC == NULL)
+ panic("error getting DC for drawing Table checkbox image");
+ prevbitmap = SelectObject(drawDC, bitmap);
+ if (prevbitmap == NULL)
+ panic("error selecting Table checkbox image list bitmap into DC");
+ (*drawfunc)(drawDC, &r, cbState, t->theme);
+ if (SelectObject(drawDC, prevbitmap) != bitmap)
+ panic("error selecting previous bitmap into Table checkbox image's DC");
+ if (DeleteDC(drawDC) == 0)
+ panic("error deleting Table checkbox image's DC");
+
+ t->checkboxImages[cbState] = bitmap;
+}
+
+static void getCheckboxImages(struct table *t, void (*sizefunc)(HDC, int *, int *, HTHEME), void (*drawfunc)(HDC, RECT *, int, HTHEME))
+{
+ int cbState;
+ HDC dc;
+
+ dc = GetDC(t->hwnd);
+ if (dc == NULL)
+ panic("error getting DC for making Table checkbox images");
+ (*sizefunc)(dc, &(t->checkboxWidth), &(t->checkboxHeight), t->theme);
+ for (cbState = 0; cbState < checkboxnStates; cbState++)
+ makeCheckboxImage(t, dc, cbState, drawfunc);
+ if (ReleaseDC(t->hwnd, dc) == 0)
+ panic("error deleting Table DC for making checkbox images");
+}
+
+static void makeCheckboxImages(struct table *t)
+{
+ if (t->theme != NULL) {
+ HRESULT res;
+
+ res = CloseThemeData(t->theme);
+ if (res != S_OK)
+ panichresult("error closing theme", res);
+ t->theme = NULL;
+ }
+ // 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
+ getCheckboxImages(t, themeSize, themeImage);
+ return;
+ }
+ // couldn't open; fall back
+ getCheckboxImages(t, dfcSize, dfcImage);
+}
+
+static void freeCheckboxImages(struct table *t)
+{
+ int cbState;
+
+ for (cbState = 0; cbState < checkboxnStates; cbState++)
+ if (DeleteObject(t->checkboxImages[cbState]) == 0)
+ panic("error freeing Table checkbox image");
+}
diff --git a/wintable/new/main.c b/wintable/new/main.c
index 347e181..0c23767 100644
--- a/wintable/new/main.c
+++ b/wintable/new/main.c
@@ -50,6 +50,13 @@ static void (*tablePanic)(const char *, DWORD) = NULL;
#define panic(...) (*tablePanic)(__VA_ARGS__, GetLastError())
#define abort $$$$ // prevent accidental use of abort()
+enum {
+ checkboxStateChecked = 1 << 0,
+ checkboxStateHot = 1 << 1,
+ checkboxStatePushed = 1 << 2,
+ checkboxnStates = 1 << 3,
+};
+
struct table {
HWND hwnd;
HWND header;
@@ -67,6 +74,10 @@ struct table {
int vwheelCarry;
intptr_t selectedRow;
intptr_t selectedColumn;
+ HTHEME theme;
+ HBITMAP checkboxImages[checkboxnStates];
+ int checkboxWidth;
+ int checkboxHeight;
};
#include "util.h"
@@ -81,6 +92,7 @@ struct table {
#include "resize.h"
#include "draw.h"
#include "api.h"
+#include "checkboximages.h"
static const handlerfunc handlers[] = {
eventHandlers,
@@ -118,6 +130,7 @@ static LRESULT CALLBACK tableWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
makeHeader(t, cs->hInstance);
t->selectedRow = -1;
t->selectedColumn = -1;
+ makeCheckboxImages(t);
initDummyTableStuff(t);
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) t);
}
@@ -128,6 +141,7 @@ initDummyTableStuff(t);
printf("destroy\n");
// TODO free appropriate (after figuring this part out) components of t
// TODO send EVENT_OBJECT_DESTROY events to accessibility listeners (when appropriate); see the note on proxy objects as well
+ freeCheckboxImages(t);
destroyHeader(t);
tableFree(t, "error allocating internal Table data structure");
return DefWindowProcW(hwnd, uMsg, wParam, lParam);