From 3099edb9c973d709f48b28ddceff0c67bcf0923c Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 17 Feb 2015 21:35:03 -0500 Subject: [PATCH] Next part of Table code: HBITMAP generation code migration. --- image_windows.c | 35 ++++++ imagelist_windows.c | 268 -------------------------------------------- winapi_windows.h | 8 +- 3 files changed, 38 insertions(+), 273 deletions(-) create mode 100644 image_windows.c delete mode 100644 imagelist_windows.c diff --git a/image_windows.c b/image_windows.c new file mode 100644 index 0000000..7e57bff --- /dev/null +++ b/image_windows.c @@ -0,0 +1,35 @@ +// 16 august 2014 + +#include "winapi_windows.h" +#include "_cgo_export.h" + +// TODO rename to images_windows.c? + +HBITMAP toBitmap(void *i, intptr_t dx, intptr_t dy) +{ + BITMAPINFO bi; + VOID *ppvBits; + HBITMAP bitmap; + + ZeroMemory(&bi, sizeof (BITMAPINFO)); + bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bi.bmiHeader.biWidth = (LONG) dx; + bi.bmiHeader.biHeight = -((LONG) dy); // negative height to force top-down drawing; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biSizeImage = (DWORD) (dx * dy * 4); + bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0); + if (bitmap == NULL) + xpanic("error creating HBITMAP in toBitmap()", GetLastError()); + // image lists use non-premultiplied RGBA - see http://stackoverflow.com/a/25578789/3408572 + // the TRUE here does the conversion + dotoARGB(i, (void *) ppvBits, TRUE); + return bitmap; +} + +void freeBitmap(void *bitmap) +{ + if (DeleteObject((HBITMAP) bitmap) == 0) + xpanic("error deleting bitmap in freeBitmap()", GetLastError()); +} diff --git a/imagelist_windows.c b/imagelist_windows.c deleted file mode 100644 index 14d33a9..0000000 --- a/imagelist_windows.c +++ /dev/null @@ -1,268 +0,0 @@ -// 16 august 2014 - -#include "winapi_windows.h" -#include "_cgo_export.h" - -// TODO top left pixel of checkbox state 0 not drawn? - -HBITMAP unscaledBitmap(void *i, intptr_t dx, intptr_t dy) -{ - BITMAPINFO bi; - VOID *ppvBits; - HBITMAP bitmap; - - ZeroMemory(&bi, sizeof (BITMAPINFO)); - bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); - bi.bmiHeader.biWidth = (LONG) dx; - bi.bmiHeader.biHeight = -((LONG) dy); // negative height to force top-down drawing; - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 32; - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = (DWORD) (dx * dy * 4); - bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0); - if (bitmap == NULL) - xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError()); - // image lists use non-premultiplied RGBA - see http://stackoverflow.com/a/25578789/3408572 - // the TRUE here does the conversion - dotoARGB(i, (void *) ppvBits, TRUE); - return bitmap; -} - -HIMAGELIST newImageList(int width, int height) -{ - HIMAGELIST il; - - // this handles alpha properly; see https://web.archive.org/web/20100512144953/http://msdn.microsoft.com/en-us/library/ms997646.aspx#xptheming_topic13 and http://stackoverflow.com/a/2640897/3408572 - il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable - if (il == NULL) - xpanic("error creating image list", GetLastError()); - return il; -} - -void addImage(HIMAGELIST il, HWND hwnd, HBITMAP bitmap, int origwid, int oright, int width, int height) -{ - BOOL wasScaled = FALSE; - HDC winDC, scaledDC, origDC; - HBITMAP scaled; - HBITMAP prevscaled, prevorig; - - // first we need to scale the bitmap - if (origwid == width && oright == height) { - scaled = bitmap; - goto noscale; - } - wasScaled = TRUE; - winDC = GetDC(hwnd); - if (winDC == NULL) - xpanic("error getting DC for window", GetLastError()); - origDC = CreateCompatibleDC(winDC); - if (origDC == NULL) - xpanic("error getting DC for original ImageList bitmap", GetLastError()); - prevorig = SelectObject(origDC, bitmap); - if (prevorig == NULL) - xpanic("error selecting original ImageList bitmap into DC", GetLastError()); - scaledDC = CreateCompatibleDC(origDC); - if (scaledDC == NULL) - xpanic("error getting DC for scaled ImageList bitmap", GetLastError()); - scaled = CreateCompatibleBitmap(origDC, width, height); - if (scaled == NULL) - xpanic("error creating scaled ImageList bitmap", GetLastError()); - prevscaled = SelectObject(scaledDC, scaled); - if (prevscaled == NULL) - xpanic("error selecting scaled ImageList bitmap into DC", GetLastError()); - if (SetStretchBltMode(scaledDC, COLORONCOLOR) == 0) - xpanic("error setting scaling mode", GetLastError()); - if (StretchBlt(scaledDC, 0, 0, width, height, - origDC, 0, 0, origwid, oright, - SRCCOPY) == 0) - xpanic("error scaling ImageList bitmap down", GetLastError()); - if (SelectObject(origDC, prevorig) != bitmap) - xpanic("error selecting previous bitmap into original image's DC", GetLastError()); - if (DeleteDC(origDC) == 0) - xpanic("error deleting original image's DC", GetLastError()); - if (SelectObject(scaledDC, prevscaled) != scaled) - xpanic("error selecting previous bitmap into scaled image's DC", GetLastError()); - if (DeleteDC(scaledDC) == 0) - xpanic("error deleting scaled image's DC", GetLastError()); - if (ReleaseDC(hwnd, winDC) == 0) - xpanic("error deleting window DC", GetLastError()); - -noscale: - if ((*fv_ImageList_Add)(il, scaled, NULL) == -1) - xpanic("error adding ImageList image to image list", GetLastError()); - if (wasScaled) // clean up - if (DeleteObject(scaled) == 0) - xpanic("error deleting scaled bitmap", GetLastError()); -} - -void applyImageList(HWND hwnd, UINT uMsg, WPARAM wParam, HIMAGELIST il, HIMAGELIST old) -{ - if (SendMessageW(hwnd, uMsg, wParam, (LPARAM) il) != (LRESULT) old) - xpanic("error setting image list", GetLastError()); - if (old != NULL && (*fv_ImageList_Destroy)(old) == 0) - xpanic("error freeing old checkbox image list", GetLastError()); - -} - -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) - xpanic("error drawing checkbox image", GetLastError()); -} - -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) - xpanichresult("error getting theme part size", 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) - xpanichresult("error drawing checkbox image", 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) - xpanic("size mismatch in checkbox states", GetLastError()); - } - *width = (int) size.cx; - *height = (int) size.cy; -} - -static HBITMAP makeCheckboxImageListEntry(HDC dc, int width, int height, int cbState, void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme) -{ - BITMAPINFO bi; - VOID *ppvBits; - HBITMAP bitmap; - RECT r; - HDC drawDC; - HBITMAP prevbitmap; - - r.left = 0; - r.top = 0; - r.right = width; - r.bottom = height; - ZeroMemory(&bi, sizeof (BITMAPINFO)); - bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); - bi.bmiHeader.biWidth = (LONG) width; - bi.bmiHeader.biHeight = -((LONG) height); // negative height to force top-down drawing; - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 32; - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = (DWORD) (width * height * 4); - bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0); - if (bitmap == NULL) - xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError()); - - drawDC = CreateCompatibleDC(dc); - if (drawDC == NULL) - xpanic("error getting DC for checkbox image list bitmap", GetLastError()); - prevbitmap = SelectObject(drawDC, bitmap); - if (prevbitmap == NULL) - xpanic("error selecting checkbox image list bitmap into DC", GetLastError()); - (*drawfunc)(drawDC, &r, cbState, theme); - if (SelectObject(drawDC, prevbitmap) != bitmap) - xpanic("error selecting previous bitmap into checkbox image's DC", GetLastError()); - if (DeleteDC(drawDC) == 0) - xpanic("error deleting checkbox image's DC", GetLastError()); - - return bitmap; -} - -static HIMAGELIST newCheckboxImageList(HWND hwnddc, void (*sizefunc)(HDC, int *, int *, HTHEME), void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme) -{ - int width, height; - int cbState; - HDC dc; - HIMAGELIST il; - - dc = GetDC(hwnddc); - if (dc == NULL) - xpanic("error getting DC for making the checkbox image list", GetLastError()); - (*sizefunc)(dc, &width, &height, theme); - il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable - if (il == NULL) - xpanic("error creating checkbox image list", GetLastError()); - for (cbState = 0; cbState < checkboxnStates; cbState++) { - HBITMAP bitmap; - - bitmap = makeCheckboxImageListEntry(dc, width, height, cbState, drawfunc, theme); - if ((*fv_ImageList_Add)(il, bitmap, NULL) == -1) - xpanic("error adding checkbox image to image list", GetLastError()); - if (DeleteObject(bitmap) == 0) - xpanic("error deleting checkbox bitmap", GetLastError()); - } - if (ReleaseDC(hwnddc, dc) == 0) - xpanic("error deleting checkbox image list DC", GetLastError()); - return il; -} - -HIMAGELIST makeCheckboxImageList(HWND hwnddc, HTHEME *theme) -{ - if (*theme != NULL) { - HRESULT res; - - res = CloseThemeData(*theme); - if (res != S_OK) - xpanichresult("error closing theme", res); - *theme = NULL; - } - // ignore error; if it can't be done, we can fall back to DrawFrameControl() - if (*theme == NULL) // try to open the theme - *theme = OpenThemeData(hwnddc, L"button"); - if (*theme != NULL) // use the theme - return newCheckboxImageList(hwnddc, themeSize, themeImage, *theme); - // couldn't open; fall back - return newCheckboxImageList(hwnddc, dfcSize, dfcImage, *theme); -} diff --git a/winapi_windows.h b/winapi_windows.h index d751aca..0f34d17 100644 --- a/winapi_windows.h +++ b/winapi_windows.h @@ -128,11 +128,9 @@ extern HWND newAreaTextField(HWND, void *); extern void areaOpenTextField(HWND, HWND, int, int, int, int); extern void areaMarkTextFieldDone(HWND); -// imagelist_windows.c -extern HBITMAP unscaledBitmap(void *, intptr_t, intptr_t); -extern HIMAGELIST newImageList(int, int); -extern void addImage(HIMAGELIST, HWND, HBITMAP, int, int, int, int); -extern void applyImageList(HWND, UINT, WPARAM, HIMAGELIST, HIMAGELIST); +// image_windows.c +extern HBITMAP toBitmap(void *, intptr_t, intptr_t); +extern void freeBitmap(void *); // dialog_windows.c extern void openFile(HWND, void *);