diff --git a/redo/comctl32_windows.c b/redo/comctl32_windows.c index 6af4f30..9dd67c1 100644 --- a/redo/comctl32_windows.c +++ b/redo/comctl32_windows.c @@ -9,6 +9,8 @@ static HMODULE comctl32; BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); +HIMAGELIST (*WINAPI fv_ImageList_Create)(int, int, UINT, int, int); +int (*WINAPI fv_ImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP); #define wantedICCClasses ( \ ICC_PROGRESS_CLASS | /* progress bars */ \ @@ -115,6 +117,11 @@ DWORD initCommonControls(char **errmsg) fv_RemoveWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR)) f; LOAD("DefSubclassProc"); fv_DefSubclassProc = (LRESULT (*WINAPI)(HWND, UINT, WPARAM, LPARAM)) f; + LOAD("ImageList_Create"); + fv_ImageList_Create = (HIMAGELIST (*WINAPI)(int, int, UINT, int, int)) f; + LOAD("ImageList_Add"); + fv_ImageList_Add = (int (*WINAPI)(HIMAGELIST, HBITMAP, HBITMAP)) f; + if ((*ficc)(&icc) == FALSE) { *errmsg = "error initializing Common Controls (comctl32.dll)"; diff --git a/redo/imagelist.go b/redo/imagelist.go new file mode 100644 index 0000000..6b34b28 --- /dev/null +++ b/redo/imagelist.go @@ -0,0 +1,29 @@ +// 16 august 2014 + +package ui + +import ( + "image" +) + +// ImageList is a list of images that can be used in the rows of a Table or Tree. +// ImageList maintains a copy of each image added. +// Images in an ImageList will be automatically scaled to the needed size. +type ImageList interface { + // Append inserts an image into the ImageList. + Append(i *image.RGBA) + + // Len returns the number of images in the ImageList. + Len() ImageIndex + + imageListApply +} + +// NewImageList creates a new ImageList. +// The ImageList is initially empty. +func NewImageList() ImageList { + return newImageList() +} + +// ImageIndex is a special type used to denote an entry in a Table or Tree's ImageList. +type ImageIndex int diff --git a/redo/imagelist_windows.c b/redo/imagelist_windows.c new file mode 100644 index 0000000..434190c --- /dev/null +++ b/redo/imagelist_windows.c @@ -0,0 +1,86 @@ +// 16 august 2014 + +#include "winapi_windows.h" +#include "_cgo_export.h" + +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()); + dotoARGB(i, (void *) ppvBits); + return bitmap; +} + +HIMAGELIST newImageList(int width, int height) +{ + HIMAGELIST il; + + // TODO does this strip alpha? + // sinni800 in irc.freenode.net/#go-nuts suggests our use of *image.RGBA makes this not so much of an issue + 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, HBITMAP bitmap, int origwid, int oright, int width, int height) +{ + BOOL wasScaled = FALSE; + HDC 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; + scaledDC = GetDC(NULL); + if (scaledDC == NULL) + xpanic("error getting screen DC for scaled ImageList bitmap", GetLastError()); + scaled = CreateCompatibleBitmap(scaledDC, 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 screen DC", GetLastError()); + origDC = GetDC(NULL); + if (origDC == NULL) + xpanic("error getting screen DC for original ImageList bitmap", GetLastError()); + prevorig = SelectObject(origDC, bitmap); + if (prevorig == NULL) + xpanic("error selecting original ImageList bitmap into screen DC", 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 screen DC", GetLastError()); + if (DeleteDC(origDC) == 0) + xpanic("error deleting original image's screen DC", GetLastError()); + if (SelectObject(scaledDC, prevscaled) != scaled) + xpanic("error selecting previous bitmap into scaled image's screen DC", GetLastError()); + if (DeleteDC(scaledDC) == 0) + xpanic("error deleting scaled image's screen 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()); +} diff --git a/redo/imagelist_windows.go b/redo/imagelist_windows.go new file mode 100644 index 0000000..389c553 --- /dev/null +++ b/redo/imagelist_windows.go @@ -0,0 +1,45 @@ +// 16 august 2014 + +package ui + +import ( + "image" + "unsafe" +) + +// #include "winapi_windows.h" +import "C" + +type imagelist struct { + list []C.HBITMAP + width []int + height []int +} + +func newImageList() ImageList { + return new(imagelist) +} + +func (i *imagelist) Append(img *image.RGBA) { + i.list = append(i.list, C.unscaledBitmap(unsafe.Pointer(img), C.intptr_t(img.Rect.Dx()), C.intptr_t(img.Rect.Dy()))) + i.width = append(i.width, img.Rect.Dx()) + i.height = append(i.height, img.Rect.Dy()) +} + +func (i *imagelist) Len() ImageIndex { + return ImageIndex(len(i.list)) +} + +type imageListApply interface { + apply() +} + +func (i *imagelist) apply() { + width := C.GetSystemMetrics(C.SM_CXSMICON) + height := C.GetSystemMetrics(C.SM_CYSMICON) + il := C.newImageList(width, height) + for index := range i.list { + C.addImage(il, i.list[index], C.int(i.width[index]), C.int(i.height[index]), width, height) + } + // TODO do stuff +} diff --git a/redo/winapi_windows.h b/redo/winapi_windows.h index 028f3c3..c6a2c63 100644 --- a/redo/winapi_windows.h +++ b/redo/winapi_windows.h @@ -44,6 +44,8 @@ extern DWORD initCommonControls(char **); extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); +extern HIMAGELIST (*WINAPI fv_ImageList_Create)(int, int, UINT, int, int); +extern int (*WINAPI fv_ImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP); // control_windows.c extern HWND newControl(LPWSTR, DWORD, DWORD); @@ -112,4 +114,9 @@ extern void repaintArea(HWND); extern DWORD makeAreaWindowClass(char **); extern HWND newArea(void *); +// imagelist_windows.c +extern HBITMAP unscaledBitmap(void *, intptr_t, intptr_t); +extern HIMAGELIST newImageList(int, int); +extern void addImage(HIMAGELIST, HBITMAP, int, int, int, int); + #endif