summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--redo/imagelist_windows.c220
-rw-r--r--redo/imagelist_windows.go3
-rw-r--r--redo/uitask_windows.c4
-rw-r--r--redo/winapi_windows.h10
4 files changed, 234 insertions, 3 deletions
diff --git a/redo/imagelist_windows.c b/redo/imagelist_windows.c
index a6db91f..a84ae2e 100644
--- a/redo/imagelist_windows.c
+++ b/redo/imagelist_windows.c
@@ -3,6 +3,8 @@
#include "winapi_windows.h"
#include "_cgo_export.h"
+// TODO eliminate duplicate code
+
HBITMAP unscaledBitmap(void *i, intptr_t dx, intptr_t dy)
{
BITMAPINFO bi;
@@ -53,7 +55,7 @@ void addImage(HIMAGELIST il, HWND hwnd, HBITMAP bitmap, int origwid, int oright,
if (winDC == NULL)
xpanic("error getting DC for window", GetLastError());
origDC = CreateCompatibleDC(winDC);
- if (winDC == NULL)
+ if (origDC == NULL)
xpanic("error getting DC for original ImageList bitmap", GetLastError());
prevorig = SelectObject(origDC, bitmap);
if (prevorig == NULL)
@@ -81,7 +83,7 @@ void addImage(HIMAGELIST il, HWND hwnd, HBITMAP bitmap, int origwid, int oright,
xpanic("error selecting previous bitmap into scaled image's DC", GetLastError());
if (DeleteDC(scaledDC) == 0)
xpanic("error deleting scaled image's DC", GetLastError());
- if (DeleteDC(winDC) == 0)
+ if (ReleaseDC(hwnd, winDC) == 0)
xpanic("error deleting window DC", GetLastError());
noscale:
@@ -98,3 +100,217 @@ void applyImageList(HWND hwnd, UINT uMsg, WPARAM wParam, HIMAGELIST il)
;//TODO xpanic("error setting image list", GetLastError());
// TODO free old one here if any
}
+
+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 HBITMAP dfcImage(HDC dc, int width, int height, int cbState)
+{
+ 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());
+ if (DrawFrameControl(drawDC, &r, DFC_BUTTON, dfcState(cbState)) == 0)
+ xpanic("error drawing checkbox image", GetLastError());
+ 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;
+}
+
+HIMAGELIST checkboxImageList = NULL;
+
+void makeCheckboxImageList_DFC(HWND hwnddc)
+{
+ int width, height;
+ int cbState;
+ HDC dc;
+ HIMAGELIST il;
+
+ // 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);
+ dc = GetDC(hwnddc);
+ if (dc == NULL)
+ xpanic("error getting DC for making the checkbox image list", GetLastError());
+ checkboxImageList = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable
+ if (checkboxImageList == NULL)
+ xpanic("error creating checkbox image list", GetLastError());
+ for (cbState = 0; cbState < checkboxnStates; cbState++) {
+ HBITMAP bitmap;
+
+ bitmap = dfcImage(dc, width, height, cbState);
+ if ((*fv_ImageList_Add)(checkboxImageList, 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());
+}
+
+static HTHEME theme = NULL;
+
+static void openTheme(HWND hwnd)
+{
+ if (theme != NULL)
+ // TODO save HRESULT
+ if (CloseThemeData(theme) != S_OK)
+ xpanic("error closing theme", GetLastError());
+ // ignore error; if it can't be done, we can fall back to DrawFrameControl()
+ theme = OpenThemeData(hwnd, L"button");
+}
+
+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)
+{
+ SIZE s;
+
+ // TODO use HRESULT
+ if (GetThemePartSize(theme, dc, BP_CHECKBOX, themestates[cbState], NULL, TS_DRAW, &s) != S_OK)
+ xpanic("error getting theme part size", GetLastError());
+ return s;
+}
+
+static HBITMAP drawThemeImage(HDC dc, int width, int height, int cbState)
+{
+ 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());
+ // TODO get HRESULT
+ if (DrawThemeBackground(theme, drawDC, BP_CHECKBOX, themestates[cbState], &r, NULL) != S_OK)
+ xpanic("error drawing checkbox image", GetLastError());
+ 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;
+}
+
+
+void makeCheckboxImageList_theme(HWND hwnddc)
+{
+ int width, height;
+ int cbState;
+ SIZE size;
+ HDC dc;
+
+ // first, make sure that all things have the same size
+ dc = GetDC(hwnddc);
+ if (dc == NULL)
+ xpanic("error getting DC for making the checkbox image list", GetLastError());
+ size = getStateSize(dc, 0);
+ for (cbState = 1; cbState < checkboxnStates; cbState++) {
+ SIZE against;
+
+ against = getStateSize(dc, cbState);
+ if (size.cx != against.cx || size.cy != against.cy)
+ xpanic("size mismatch in checkbox states", GetLastError());
+ }
+ width = (int) size.cx;
+ height = (int) size.cy;
+
+ // NOW draw
+ checkboxImageList = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable
+ if (checkboxImageList == NULL)
+ xpanic("error creating checkbox image list", GetLastError());
+ for (cbState = 0; cbState < checkboxnStates; cbState++) {
+ HBITMAP bitmap;
+
+ bitmap = drawThemeImage(dc, width, height, cbState);
+ if ((*fv_ImageList_Add)(checkboxImageList, 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());
+}
+
+void makeCheckboxImageList(HWND hwnddc)
+{
+ if (theme == NULL) // try to open the theme
+ openTheme(hwnddc);
+ if (theme != NULL) { // use the theme
+ makeCheckboxImageList_theme(hwnddc);
+ return;
+ }
+ // couldn't open; fall back
+ makeCheckboxImageList_DFC(hwnddc);
+}
diff --git a/redo/imagelist_windows.go b/redo/imagelist_windows.go
index 37924bd..479e9a5 100644
--- a/redo/imagelist_windows.go
+++ b/redo/imagelist_windows.go
@@ -41,5 +41,6 @@ func (i *imagelist) apply(hwnd C.HWND, uMsg C.UINT, wParam C.WPARAM) {
for index := range i.list {
C.addImage(il, hwnd, i.list[index], C.int(i.width[index]), C.int(i.height[index]), width, height)
}
- C.applyImageList(hwnd, uMsg, wParam, il)
+// C.applyImageList(hwnd, uMsg, wParam, il)
+ C.applyImageList(hwnd, uMsg, wParam, C.checkboxImageList)
}
diff --git a/redo/uitask_windows.c b/redo/uitask_windows.c
index f80b878..7a20bbe 100644
--- a/redo/uitask_windows.c
+++ b/redo/uitask_windows.c
@@ -78,6 +78,10 @@ static LRESULT CALLBACK msgwinproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
if (sharedWndProc(hwnd, uMsg, wParam, lParam, &shared))
return shared;
switch (uMsg) {
+ case WM_CREATE:
+ // initial
+ makeCheckboxImageList(hwnd);
+ return 0;
case msgRequest:
doissue((void *) lParam);
return 0;
diff --git a/redo/winapi_windows.h b/redo/winapi_windows.h
index 589fbec..c937f64 100644
--- a/redo/winapi_windows.h
+++ b/redo/winapi_windows.h
@@ -21,6 +21,8 @@
#include <string.h>
#include <wchar.h>
#include <windowsx.h>
+#include <vsstyle.h>
+#include <vssym32.h>
// global messages unique to everything
enum {
@@ -119,5 +121,13 @@ 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);
+enum {
+ checkboxStateChecked = 1 << 0,
+ checkboxStateHot = 1 << 1,
+ checkboxStatePushed = 1 << 2,
+ checkboxnStates = 1 << 3,
+};
+extern HIMAGELIST checkboxImageList;
+extern void makeCheckboxImageList(HWND);
#endif