diff options
Diffstat (limited to 'wintable/new/checkboximages.h')
| -rw-r--r-- | wintable/new/checkboximages.h | 166 |
1 files changed, 166 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"); +} |
