andlabs-ui/wintable/new/checkboximages.h

169 lines
4.9 KiB
C

// 16 august 2014
// TODO instead of caching checkbox images, draw them on the fly, because they could be transparent
// 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");
}