From d7cf4fa7c555c0f34247104c0575ea43d650b948 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Thu, 18 Dec 2014 19:24:32 -0500 Subject: [PATCH] New checkbox plan: because DrawThemeBackground() /might/ do AlphaBlend(), we'll just draw checkboxes on the fly. --- wintable/new/checkboximages.h | 110 ++++++++++++---------------------- wintable/new/main.c | 12 +--- 2 files changed, 40 insertions(+), 82 deletions(-) diff --git a/wintable/new/checkboximages.h b/wintable/new/checkboximages.h index 302cc90..87c6c9a 100644 --- a/wintable/new/checkboximages.h +++ b/wintable/new/checkboximages.h @@ -1,6 +1,11 @@ // 16 august 2014 -// TODO instead of caching checkbox images, draw them on the fly, because they could be transparent +enum { + checkboxStateChecked = 1 << 0, + checkboxStateHot = 1 << 1, + checkboxStatePushed = 1 << 2, + checkboxnStates = 1 << 3, +}; // TODO actually make this #define panichresult(a, b) panic(a) @@ -19,13 +24,13 @@ static UINT dfcState(int cbstate) return ret; } -static void dfcImage(HDC dc, RECT *r, int cbState, HTHEME theme) +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 dfcSize(HDC dc, int *width, int *height, HTHEME theme) +static void getFrameControlCheckboxSize(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 @@ -55,7 +60,7 @@ static SIZE getStateSize(HDC dc, int cbState, HTHEME theme) return s; } -static void themeImage(HDC dc, RECT *r, int cbState, HTHEME theme) +static void drawThemeCheckbox(HDC dc, RECT *r, int cbState, HTHEME theme) { HRESULT res; @@ -64,7 +69,7 @@ static void themeImage(HDC dc, RECT *r, int cbState, HTHEME theme) panichresult("error drawing Table checkbox image from theme", res); } -static void themeSize(HDC dc, int *width, int *height, HTHEME theme) +static void getThemeCheckboxSize(HDC dc, int *width, int *height, HTHEME theme) { SIZE size; int cbState; @@ -82,87 +87,48 @@ static void themeSize(HDC dc, int *width, int *height, HTHEME theme) *height = (int) size.cy; } -static void makeCheckboxImage(struct table *t, HDC dc, int cbState, void (*drawfunc)(HDC, RECT *, int, HTHEME)) +static void drawCheckbox(struct table *t, HDC dc, int x, int y, int cbState) { - 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; + 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 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) +static void freeCheckboxThemeData(struct table *t) { if (t->theme != NULL) { HRESULT res; res = CloseThemeData(t->theme); if (res != S_OK) - panichresult("error closing theme", res); + 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 - 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"); + 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), t->theme); + if (ReleaseDC(t->hwnd, dc) == 0) + panic("error releasing Table DC for loading checkbox theme data"); } diff --git a/wintable/new/main.c b/wintable/new/main.c index 0c23767..b08a655 100644 --- a/wintable/new/main.c +++ b/wintable/new/main.c @@ -50,13 +50,6 @@ 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; @@ -75,7 +68,6 @@ struct table { intptr_t selectedRow; intptr_t selectedColumn; HTHEME theme; - HBITMAP checkboxImages[checkboxnStates]; int checkboxWidth; int checkboxHeight; }; @@ -130,7 +122,7 @@ static LRESULT CALLBACK tableWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM makeHeader(t, cs->hInstance); t->selectedRow = -1; t->selectedColumn = -1; - makeCheckboxImages(t); + loadCheckboxThemeData(t); initDummyTableStuff(t); SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) t); } @@ -141,7 +133,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); + freeCheckboxThemeData(t); destroyHeader(t); tableFree(t, "error allocating internal Table data structure"); return DefWindowProcW(hwnd, uMsg, wParam, lParam);