summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wintable/accessibility_darwin.c117
-rw-r--r--wintable/api.h54
-rw-r--r--wintable/draw.h166
-rw-r--r--wintable/hscroll.h125
-rw-r--r--wintable/imagelist_windows.c195
-rw-r--r--wintable/main.c303
-rw-r--r--wintable/selection.h83
-rw-r--r--wintable/util.h136
-rw-r--r--wintable/vscroll.h112
9 files changed, 0 insertions, 1291 deletions
diff --git a/wintable/accessibility_darwin.c b/wintable/accessibility_darwin.c
deleted file mode 100644
index d72524c..0000000
--- a/wintable/accessibility_darwin.c
+++ /dev/null
@@ -1,117 +0,0 @@
-// 9 november 2014
-#define UNICODE
-#define _UNICODE
-#define STRICT
-#define STRICT_TYPED_ITEMIDS
-#define CINTERFACE
-// get Windows version right; right now Windows XP
-#define WINVER 0x0501
-#define _WIN32_WINNT 0x0501
-#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
-#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
-#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
-#include <windows.h>
-#include <commctrl.h>
-#include <stdint.h>
-#include <uxtheme.h>
-#include <string.h>
-#include <wchar.h>
-#include <windowsx.h>
-#include <vsstyle.h>
-#include <vssym32.h>
-#include <oleacc.h>
-
-struct tableAccessible {
- IAccessibleVtbl vtbl;
- volatile ULONG refcount; // TODO ensure this is aligned
- struct table *t;
-};
-
-static IAccessibleVtbl aaccessible = {
- // IUnknkown
- .QueryInterface = taQueryInterface,
- .AddRef = taAddRef,
- .Release = taRelease,
- // IDispatch
- .GetTypeInfoCount = taGetTypeInfoCount,
- .GetTypeInfo = taGetTypeInfo,
- .GetIDsOfNames = taGetIDsOfNames,
- .Invoke = taInvoke,
- // IAccessible
- ...
-};
-
-HRESULT STDMETHODCALLTYPE taQueryInterface(IUnknown *this, REFIID riid, void **ppvObject)
-{
- if (ppvObject == NULL)
- return E_POINTER;
- // we're required to return the same pointer for IUnknown
- // since this is a straight singly-derived interface inheritance, we can exploit the structure layout and just return the same pointer for everything
- // at least I hope... (TODO)
- if (IsEqualIID(riid, IID_IUnknown) ||
- IsEqualIID(riid, IID_IDispatch) ||
- IsEqualIID(riid, IID_IAccessible)) {
- this->AddRef(this);
- *ppvObject = (void *) this;
- return S_OK;
- }
- // we're not making a special class for this
- *ppvObject = NULL;
- return E_NOINTERFACE;
-}
-
-ULONG STDMETHODCALLTYPE taAddRef(IUnknown *this)
-{
- // TODO is the signed conversion safe?
- return (ULONG) InterlockedIncrement((volatile LONG *) (&(((tableAccessible *) this)->refcount)));
-}
-
-ULONG STDMETHODCALLTYPE taRelease(IUnknown *this)
-{
- ULONG rc;
-
- rc = (ULONG) InterlockedDecrement((volatile LONG *) (&(((tableAccessible *) this)->refcount)));
- // don't pull the refcount back out (see http://blogs.msdn.com/b/oldnewthing/archive/2013/04/25/10413997.aspx)
- if (rc == 0)
- free((tableAccessible *) this);
- return rc;
-}
-
-// here's the IDispatch member functions
-// we actually /don't/ need to define any of these!
-// see also http://msdn.microsoft.com/en-us/library/windows/desktop/cc307844.aspx
-
-HRESULT STDMETHODCALLTYPE taGetTypeInfoCount(IDispatch *this, UINT *pctinfo)
-{
- if (pctinfo == NULL)
- return E_INVALIDARG;
- // TODO really set this to zero?
- *pctinfo = 0;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE taGetTypeInfo(IDispatch *this, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
-{
- if (pctinfo == NULL)
- return E_INVALIDARG;
- *ppTInfo = NULL;
- // let's do this just to be safe
- if (iTInfo == 0)
- return DISP_E_BADINDEX;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE taGetIDsOfNames(IDispatch *this, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
-{
- // rgDispId is an array of LONGs; setting it to NULL is useless
- // TODO should we clear the array?
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE taInvoke(IDispatch *this, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
-{
- // TODO set anything to NULL or 0?
- return E_NOTIMPL;
-}
-
-// ok that's it for IDispatch; now for IAccessible!
diff --git a/wintable/api.h b/wintable/api.h
deleted file mode 100644
index 5fdf599..0000000
--- a/wintable/api.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// 29 november 2014
-
-static void addColumn(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- HDITEMW item;
-
- if (((int) wParam) >= nTableColumnTypes)
- abort();
-
- t->nColumns++;
- t->columnTypes = (int *) realloc(t->columnTypes, t->nColumns * sizeof (int));
- if (t->columnTypes == NULL)
- abort();
- t->columnTypes[t->nColumns - 1] = (int) wParam;
-
- ZeroMemory(&item, sizeof (HDITEMW));
- item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT;
- item.cxy = 200; // TODO
- item.pszText = (WCHAR *) lParam;
- item.fmt = HDF_LEFT | HDF_STRING;
- if (SendMessage(t->header, HDM_INSERTITEM, (WPARAM) (t->nColumns - 1), (LPARAM) (&item)) == (LRESULT) (-1))
- abort();
- // TODO resize(t)?
- redrawAll(t);
-}
-
-HANDLER(API)
-{
- switch (uMsg) {
- case WM_SETFONT:
- t->font = (HFONT) wParam;
- if (t->font == NULL)
- t->font = t->defaultFont;
- // also set the header font
- SendMessageW(t->header, WM_SETFONT, wParam, lParam);
- if (LOWORD(lParam) != FALSE) {
- // the scrollbar page size will change so redraw that too
- // also recalculate the header height
- // TODO do that when this is FALSE too somehow
- resize(t);
- redrawAll(t);
- }
- *lResult = 0;
- return TRUE;
- case WM_GETFONT:
- *lResult = (LRESULT) t->font;
- return TRUE;
- case tableAddColumn:
- addColumn(t, wParam, lParam);
- *lResult = 0;
- return TRUE;
- }
- return FALSE;
-}
diff --git a/wintable/draw.h b/wintable/draw.h
deleted file mode 100644
index adc1e68..0000000
--- a/wintable/draw.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// 30 november 2014
-
-static void resize(struct table *t)
-{
- RECT r;
- SCROLLINFO si;
-
- // do this first so our scrollbar calculations can be correct
- repositionHeader(t);
-
- // now adjust the scrollbars
- r = realClientRect(t);
- t->pagesize = (r.bottom - r.top) / rowHeight(t);
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_RANGE | SIF_PAGE;
- si.nMin = 0;
- si.nMax = t->count - 1;
- si.nPage = t->pagesize;
- SetScrollInfo(t->hwnd, SB_VERT, &si, TRUE);
-
- recomputeHScroll(t);
-}
-
-// TODO alter this so that only the visible columns are redrawn
-// TODO this means rename controlSize to clientRect
-static void drawItem(struct table *t, HDC dc, intptr_t i, LONG y, LONG height, RECT controlSize)
-{
- RECT rsel;
- HBRUSH background;
- int textColor;
- WCHAR msg[100];
- RECT headeritem;
- intptr_t j;
- LRESULT xoff;
- IMAGELISTDRAWPARAMS ip;
- POINT pt;
-
- // TODO verify these two
- background = (HBRUSH) (COLOR_WINDOW + 1);
- textColor = COLOR_WINDOWTEXT;
- if (t->selected == i) {
- // these are the colors wine uses (http://source.winehq.org/source/dlls/comctl32/listview.c)
- // the two for unfocused are also suggested by http://stackoverflow.com/questions/10428710/windows-forms-inactive-highlight-color
- background = (HBRUSH) (COLOR_HIGHLIGHT + 1);
- textColor = COLOR_HIGHLIGHTTEXT;
- if (GetFocus() != t->hwnd) {
- background = (HBRUSH) (COLOR_BTNFACE + 1);
- textColor = COLOR_BTNTEXT;
- }
- }
-
- // first fill the selection rect
- // note that this already only draws the visible area
- rsel.left = controlSize.left;
- rsel.top = y;
- rsel.right = controlSize.right - controlSize.left;
- rsel.bottom = y + height;
- if (FillRect(dc, &rsel, background) == 0)
- abort();
-
- // TODO double-check to see if this takes any parameters
- xoff = SendMessageW(t->header, HDM_GETBITMAPMARGIN, 0, 0);
- // now adjust for horizontal scrolling
- xoff -= t->hpos;
-
- // now draw the cells
- if (SetTextColor(dc, GetSysColor(textColor)) == CLR_INVALID)
- abort();
- if (SetBkMode(dc, TRANSPARENT) == 0)
- abort();
- for (j = 0; j < t->nColumns; j++) {
- if (SendMessageW(t->header, HDM_GETITEMRECT, (WPARAM) j, (LPARAM) (&headeritem)) == 0)
- abort();
- switch (t->columnTypes[j]) {
- case tableColumnText:
- rsel.left = headeritem.left + xoff;
- rsel.top = y;
- rsel.right = headeritem.right;
- rsel.bottom = y + height;
- // TODO vertical center in case the height is less than the icon height?
- if (DrawTextExW(dc, msg, wsprintf(msg, L"Item %d", i), &rsel, DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE, NULL) == 0)
- abort();
- break;
- case tableColumnImage:
- // TODO vertically center if image is smaller than text height
- // TODO same for checkboxes
- ZeroMemory(&ip, sizeof (IMAGELISTDRAWPARAMS));
- ip.cbSize = sizeof (IMAGELISTDRAWPARAMS);
- ip.himl = t->checkboxes;//t->imagelist;
- ip.i = (i%8);//0;
- ip.hdcDst = dc;
- ip.x = headeritem.left + xoff;
- ip.y = y;
- ip.cx = 0; // draw whole image
- ip.cy = 0;
- ip.xBitmap = 0;
- ip.yBitmap = 0;
- ip.rgbBk = CLR_NONE;
- ip.fStyle = ILD_NORMAL | ILD_SCALE; // TODO alpha-blend; ILD_DPISCALE?
- // TODO ILS_ALPHA?
- if (ImageList_DrawIndirect(&ip) == 0)
- abort();
- break;
- case tableColumnCheckbox:
- // TODO
- break;
- }
- if (t->selected == i && t->focusedColumn == j) {
- rsel.left = headeritem.left;
- rsel.top = y;
- rsel.right = headeritem.right;
- rsel.bottom = y + height;
- if (DrawFocusRect(dc, &rsel) == 0)
- abort();
- }
- }
-}
-
-static void drawItems(struct table *t, HDC dc, RECT cliprect)
-{
- HFONT thisfont, prevfont;
- LONG height;
- LONG y;
- intptr_t i;
- RECT controlSize; // for filling the entire selected row
- intptr_t first, last;
-
- if (GetClientRect(t->hwnd, &controlSize) == 0)
- abort();
-
- height = rowHeight(t);
-
- thisfont = t->font; // in case WM_SETFONT happens before we return
- prevfont = (HFONT) SelectObject(dc, thisfont);
- if (prevfont == NULL)
- abort();
-
- // ignore anything beneath the header
- if (cliprect.top < t->headerHeight)
- cliprect.top = t->headerHeight;
- // now let's pretend the header isn't there
- // we only need it in (or rather, before) the drawItem() calls below
- cliprect.top -= t->headerHeight;
- cliprect.bottom -= t->headerHeight;
-
- // see http://blogs.msdn.com/b/oldnewthing/archive/2003/07/29/54591.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/07/30/54600.aspx
- // we need to add t->firstVisible here because cliprect is relative to the visible area
- first = (cliprect.top / height) + t->firstVisible;
- if (first < 0)
- first = 0;
- last = lastVisible(t, cliprect, height);
-
- // now for the first y, discount firstVisible
- y = (first - t->firstVisible) * height;
- // and offset by the header height
- y += t->headerHeight;
- for (i = first; i < last; i++) {
- drawItem(t, dc, i, y, height, controlSize);
- y += height;
- }
-
- // reset everything
- if (SelectObject(dc, prevfont) != (HGDIOBJ) (thisfont))
- abort();
-}
diff --git a/wintable/hscroll.h b/wintable/hscroll.h
deleted file mode 100644
index f4c3b0f..0000000
--- a/wintable/hscroll.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// 29 november 2014
-
-static void hscrollto(struct table *t, intptr_t newpos)
-{
- SCROLLINFO si;
- RECT scrollArea;
-
- if (newpos < 0)
- newpos = 0;
- if (newpos > (t->width - t->hpagesize))
- newpos = (t->width - t->hpagesize);
-
- scrollArea = realClientRect(t);
-
- // negative because ScrollWindowEx() is "backwards"
- if (ScrollWindowEx(t->hwnd, -(newpos - t->hpos), 0,
- &scrollArea, &scrollArea, NULL, NULL,
- SW_ERASE | SW_INVALIDATE) == ERROR)
- abort();
- t->hpos = newpos;
- // TODO text in header controls doesn't redraw?
-
- // TODO put this in a separate function? same for vscroll?
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
- si.nPage = t->hpagesize;
- si.nMin = 0;
- si.nMax = t->width - 1; // nMax is inclusive
- si.nPos = t->hpos;
- SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
-
- // and finally reposition the header
- repositionHeader(t);
-}
-
-static void hscrollby(struct table *t, intptr_t n)
-{
- hscrollto(t, t->hpos + n);
-}
-
-// unfortunately horizontal wheel scrolling was only added in Vista
-
-static void hscroll(struct table *t, WPARAM wParam)
-{
- SCROLLINFO si;
- intptr_t newpos;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS | SIF_TRACKPOS;
- if (GetScrollInfo(t->hwnd, SB_HORZ, &si) == 0)
- abort();
-
- newpos = t->hpos;
- switch (LOWORD(wParam)) {
- case SB_LEFT:
- newpos = 0;
- break;
- case SB_RIGHT:
- newpos = t->width - t->hpagesize;
- break;
- case SB_LINELEFT:
- newpos--;
- break;
- case SB_LINERIGHT:
- newpos++;
- break;
- case SB_PAGELEFT:
- newpos -= t->hpagesize;
- break;
- case SB_PAGERIGHT:
- newpos += t->hpagesize;
- break;
- case SB_THUMBPOSITION:
- newpos = (intptr_t) (si.nPos);
- break;
- case SB_THUMBTRACK:
- newpos = (intptr_t) (si.nTrackPos);
- }
-
- hscrollto(t, newpos);
-}
-
-static void recomputeHScroll(struct table *t)
-{
- HDITEMW item;
- intptr_t i;
- int width = 0;
- RECT r;
- SCROLLINFO si;
-
- // TODO count dividers
- for (i = 0; i < t->nColumns; i++) {
- ZeroMemory(&item, sizeof (HDITEMW));
- item.mask = HDI_WIDTH;
- if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
- abort();
- width += item.cxy;
- }
- t->width = (intptr_t) width;
-
- if (GetClientRect(t->hwnd, &r) == 0)
- abort();
- t->hpagesize = r.right - r.left;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_RANGE;
- si.nPage = t->hpagesize;
- si.nMin = 0;
- si.nMax = t->width - 1; // - 1 because endpoints inclusive
- SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
-}
-
-HANDLER(hscroll)
-{
- switch (uMsg) {
- case WM_HSCROLL:
- hscroll(t, wParam);
- *lResult = 0;
- return TRUE;
- }
- return FALSE;
-}
diff --git a/wintable/imagelist_windows.c b/wintable/imagelist_windows.c
deleted file mode 100644
index e194f49..0000000
--- a/wintable/imagelist_windows.c
+++ /dev/null
@@ -1,195 +0,0 @@
-// 16 august 2014
-
-#define UNICODE
-#define _UNICODE
-#define STRICT
-#define STRICT_TYPED_ITEMIDS
-#define CINTERFACE
-// get Windows version right; right now Windows XP
-#define WINVER 0x0501
-#define _WIN32_WINNT 0x0501
-#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
-#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
-#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
-#include <windows.h>
-#include <commctrl.h>
-#include <stdint.h>
-#include <uxtheme.h>
-#include <string.h>
-#include <wchar.h>
-#include <windowsx.h>
-#include <vsstyle.h>
-#include <vssym32.h>
-#include <oleacc.h>
-
-enum {
- checkboxStateChecked = 1 << 0,
- checkboxStateHot = 1 << 1,
- checkboxStatePushed = 1 << 2,
- checkboxnStates = 1 << 3,
-};
-
-#define xpanic(...) abort()
-#define xpanichresult(...) abort()
-
-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, int *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 = 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 (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, int *width, int *height)
-{
- 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, width, height);
- // couldn't open; fall back
- return newCheckboxImageList(hwnddc, dfcSize, dfcImage, *theme, width, height);
-}
diff --git a/wintable/main.c b/wintable/main.c
deleted file mode 100644
index 4f1b3e2..0000000
--- a/wintable/main.c
+++ /dev/null
@@ -1,303 +0,0 @@
-// 19 october 2014
-#define UNICODE
-#define _UNICODE
-#define STRICT
-#define STRICT_TYPED_ITEMIDS
-#define CINTERFACE
-// get Windows version right; right now Windows XP
-#define WINVER 0x0501
-#define _WIN32_WINNT 0x0501
-#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
-#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
-#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
-#include <windows.h>
-#include <commctrl.h>
-#include <stdint.h>
-#include <uxtheme.h>
-#include <string.h>
-#include <wchar.h>
-extern HIMAGELIST makeCheckboxImageList(HWND hwnddc, HTHEME *theme, int *, int *);
-enum {
- checkboxStateChecked = 1 << 0,
- checkboxStateHot = 1 << 1,
- checkboxStatePushed = 1 << 2,
- checkboxnStates = 1 << 3,
-};
-#include <windowsx.h>
-#include <vsstyle.h>
-#include <vssym32.h>
-#include <oleacc.h>
-
-// #qo LIBS: user32 kernel32 gdi32 comctl32 uxtheme
-
-// TODO
-// - http://blogs.msdn.com/b/oldnewthing/archive/2003/09/09/54826.aspx (relies on the integrality parts? IDK)
-// - might want to http://blogs.msdn.com/b/oldnewthing/archive/2003/09/17/54944.aspx instead
-// - http://msdn.microsoft.com/en-us/library/windows/desktop/bb775574%28v=vs.85%29.aspx
-// - hscroll
-// - keyboard navigation
-// - how will this affect hot-tracking?
-// - automatic hscroll when scrolling columns
-// - accessibility
-// - must use MSAA as UI Automation is not included by default on Windows XP (and apparently requires SP3?)
-// - try horizontally scrolling the initail window and watch the selection rect corrupt itself *sometimes*
-// - preallocate t->columnTypes instead of keeping it at exactly the right size
-// - checkbox events
-// - space to toggle (TODO); + or = to set; - to clear (see http://msdn.microsoft.com/en-us/library/windows/desktop/bb775941%28v=vs.85%29.aspx)
-// - TODO figure out which notification is needed
-// - http://blogs.msdn.com/b/oldnewthing/archive/2006/01/03/508694.aspx
-// - free all allocated resources on WM_DESTROY
-// - rename lastmouse
-// - or perhaps do a general cleanup of the checkbox and mouse event code...
-// - figure out why initial draw pretends there is no header
-// - find places where the top-left corner of the client rect is assumed to be (0, 0)
-// - rewrite a lot of this crap to make better sense of coordinates and item counts, get rid of needless resizing and redrawing, etc.
-
-#define tableWindowClass L"gouitable"
-
-// start at WM_USER + 20 just in case for whatever reason we ever get the various dialog manager messages (see also http://blogs.msdn.com/b/oldnewthing/archive/2003/10/21/55384.aspx)
-enum {
- // wParam - one of the type constants
- // lParam - column name as a Unicode string
- tableAddColumn = WM_USER + 20,
-};
-
-enum {
- tableColumnText,
- tableColumnImage,
- tableColumnCheckbox,
- nTableColumnTypes,
-};
-
-struct table {
- HWND hwnd;
- HFONT defaultFont;
- HFONT font;
- intptr_t selected;
- intptr_t count;
- intptr_t firstVisible;
- intptr_t pagesize; // in rows
- int wheelCarry;
- HWND header;
- int headerHeight;
- intptr_t nColumns;
- HIMAGELIST imagelist;
- int imagelistHeight;
- intptr_t width;
- intptr_t hpagesize;
- intptr_t hpos;
- HIMAGELIST checkboxes;
- HTHEME theme;
- int *columnTypes;
- intptr_t focusedColumn;
- int checkboxWidth;
- int checkboxHeight;
-};
-
-#define HANDLER(what) static BOOL what ## Handler(struct table *t, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
-#include "util.h"
-#include "hscroll.h"
-#include "vscroll.h"
-#include "selection.h"
-#include "draw.h"
-#include "api.h"
-
-typedef BOOL (*handlerfunc)(struct table *, UINT, WPARAM, LPARAM, LRESULT *);
-
-const handlerfunc handlerfuncs[] = {
- hscrollHandler,
- vscrollHandler,
- APIHandler,
- NULL,
-};
-
-// TODO create a system where each of the above modules provide their own window procedures
-static LRESULT CALLBACK tableWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- struct table *t;
- handlerfunc *hf;
- LRESULT lResult;
- HDC dc;
- PAINTSTRUCT ps;
- NMHDR *nmhdr = (NMHDR *) lParam;
- NMHEADERW *nm = (NMHEADERW *) lParam;
-
- t = (struct table *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
- if (t == NULL) {
- // we have to do things this way because creating the header control will fail mysteriously if we create it first thing
- // (which is fine; we can get the parent hInstance this way too)
- if (uMsg == WM_NCCREATE) {
- CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
-
- t = (struct table *) malloc(sizeof (struct table));
- if (t == NULL)
- abort();
- ZeroMemory(t, sizeof (struct table));
- t->hwnd = hwnd;
- // TODO this should be a global
- t->defaultFont = (HFONT) GetStockObject(SYSTEM_FONT);
- if (t->defaultFont == NULL)
- abort();
- t->font = t->defaultFont;
-t->selected = 5;t->count=100;//TODO
- t->header = CreateWindowExW(0,
- WC_HEADERW, L"",
- // TODO is HOTTRACK needed?
- WS_CHILD | HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK,
- 0, 0, 0, 0,
- t->hwnd, (HMENU) 100, cs->hInstance, NULL);
- if (t->header == NULL)
- abort();
-{t->imagelist = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32, 1, 1);
-if(t->imagelist==NULL)abort();
-{
-HICON icon;
-int unused;
-icon = LoadIconW(NULL, IDI_ERROR);
-if(icon == NULL)abort();
-if (ImageList_AddIcon(t->imagelist, icon) == -1)abort();
-if (ImageList_GetIconSize(t->imagelist, &unused, &(t->imagelistHeight)) == 0)abort();
-}
-}
- t->checkboxes = makeCheckboxImageList(t->hwnd, &(t->theme), &(t->checkboxWidth), &(t->checkboxHeight));
- t->focusedColumn = -1;
-//TODO retrack(t);
- SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) t);
- }
- // even if we did the above, fall through
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- for (hf = handlerfuncs; *hf != NULL; hf++)
- if ((*hf)(t, uMsg, wParam, lParam, &lResult))
- return lResult;
- switch (uMsg) {
- case WM_PAINT:
- dc = BeginPaint(hwnd, &ps);
- if (dc == NULL)
- abort();
- drawItems(t, dc, ps.rcPaint);
- EndPaint(hwnd, &ps);
- return 0;
- case WM_SIZE:
- resize(t);
- return 0;
- case WM_LBUTTONDOWN:
- selectItem(t, wParam, lParam);
- return 0;
- case WM_SETFOCUS:
- case WM_KILLFOCUS:
- // all we need to do here is redraw the highlight
- // TODO ensure giving focus works right
- // TODO figure out hwat I meant by this
- redrawRow(t, t->selected);
- return 0;
- case WM_KEYDOWN:
- keySelect(t, wParam, lParam);
- return 0;
- // TODO header double-click
- case WM_NOTIFY:
- if (nmhdr->hwndFrom == t->header)
- switch (nmhdr->code) {
- // I could use HDN_TRACK but wine doesn't emit that
- case HDN_ITEMCHANGING:
- case HDN_ITEMCHANGED: // TODO needed?
- recomputeHScroll(t);
- redrawAll(t);
- return FALSE;
- }
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- // TODO others?
- case WM_WININICHANGE:
- case WM_SYSCOLORCHANGE:
- case WM_THEMECHANGED:
- if (ImageList_Destroy(t->checkboxes) == 0)
- abort();
- t->checkboxes = makeCheckboxImageList(t->hwnd, &(t->theme), &(t->checkboxWidth), &(t->checkboxHeight));
- resize(t); // TODO needed?
- redrawAll(t);
- // now defer back to DefWindowProc() in case other things are needed
- // TODO needed?
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- case WM_GETOBJECT: // accessibility
-/*
- if (((DWORD) lParam) == OBJID_CLIENT) {
- TODO *server;
- LRESULT lResult;
-
- // TODO create the server object
- lResult = LresultFromObject(IID_IAccessible, wParam, server);
- if (/* TODO failure *|/)
- abort();
- // TODO release object
- return lResult;
- }
-*/
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- default:
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- abort();
- return 0; // unreached
-}
-
-void makeTableWindowClass(void)
-{
- WNDCLASSW wc;
-
- ZeroMemory(&wc, sizeof (WNDCLASSW));
- wc.lpszClassName = tableWindowClass;
- wc.lpfnWndProc = tableWndProc;
- wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
- wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
- wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // TODO correct?
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.hInstance = GetModuleHandle(NULL);
- if (RegisterClassW(&wc) == 0)
- abort();
-}
-
-int main(int argc, char *argv[])
-{
- HWND mainwin;
- MSG msg;
- INITCOMMONCONTROLSEX icc;
-
- ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
- icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
- icc.dwICC = ICC_LISTVIEW_CLASSES;
- if (InitCommonControlsEx(&icc) == 0)
- abort();
- makeTableWindowClass();
- mainwin = CreateWindowExW(0,
- tableWindowClass, L"Main Window",
- WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 400, 400,
- NULL, NULL, GetModuleHandle(NULL), NULL);
- if (mainwin == NULL)
- abort();
- SendMessageW(mainwin, tableAddColumn, tableColumnText, (LPARAM) L"Column");
- SendMessageW(mainwin, tableAddColumn, tableColumnImage, (LPARAM) L"Column 2");
- SendMessageW(mainwin, tableAddColumn, tableColumnCheckbox, (LPARAM) L"Column 3");
- if (argc > 1) {
- NONCLIENTMETRICSW ncm;
- HFONT font;
-
- ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW));
- ncm.cbSize = sizeof (NONCLIENTMETRICSW);
- if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0)
- abort();
- font = CreateFontIndirectW(&ncm.lfMessageFont);
- if (font == NULL)
- abort();
- SendMessageW(mainwin, WM_SETFONT, (WPARAM) font, TRUE);
- }
- ShowWindow(mainwin, SW_SHOWDEFAULT);
- if (UpdateWindow(mainwin) == 0)
- abort();
- while (GetMessageW(&msg, NULL, 0, 0) > 0) {
- TranslateMessage(&msg);
- DispatchMessageW(&msg);
- }
- return 0;
-}
diff --git a/wintable/selection.h b/wintable/selection.h
deleted file mode 100644
index 12c30d5..0000000
--- a/wintable/selection.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// 30 november 2014
-
-static void finishSelect(struct table *t, intptr_t prev)
-{
- if (t->selected < 0)
- t->selected = 0;
- if (t->selected >= t->count)
- t->selected = t->count - 1;
-
- // always redraw the old and new rows to avoid artifacts when scrolling, even if they are the same (since the focused column may have changed)
- redrawRow(t, prev);
- if (prev != t->selected)
- redrawRow(t, t->selected);
-
- // if we need to scroll, the scrolling will force a redraw, so we don't have to worry about doing so ourselves
- if (t->selected < t->firstVisible)
- vscrollto(t, t->selected);
- // note that this is not lastVisible(t) because the last visible row may only be partially visible and we want selections to make them fully visible
- else if (t->selected >= (t->firstVisible + t->pagesize))
- vscrollto(t, t->selected - t->pagesize + 1);
-}
-
-// TODO isolate functionality so other keyboard event handlers can run
-static void keySelect(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- intptr_t prev;
-
- // TODO figure out correct behavior with nothing selected
- if (t->count == 0) // don't try to do anything if there's nothing to do
- return;
- prev = t->selected;
- switch (wParam) {
- case VK_UP:
- t->selected--;
- break;
- case VK_DOWN:
- t->selected++;
- break;
- case VK_PRIOR:
- t->selected -= t->pagesize;
- break;
- case VK_NEXT:
- t->selected += t->pagesize;
- break;
- case VK_HOME:
- t->selected = 0;
- break;
- case VK_END:
- t->selected = t->count - 1;
- break;
- case VK_LEFT:
- t->focusedColumn--;
- if (t->focusedColumn < 0)
- if (t->nColumns == 0) // peg at -1
- t->focusedColumn = -1;
- else
- t->focusedColumn = 0;
- break;
- case VK_RIGHT:
- t->focusedColumn++;
- if (t->focusedColumn >= t->nColumns)
- if (t->nColumns == 0) // peg at -1
- t->focusedColumn = -1;
- else
- t->focusedColumn = t->nColumns - 1;
- break;
- // TODO keyboard shortcuts for going to the first/last column?
- default:
- // don't touch anything
- return;
- }
- finishSelect(t, prev);
-}
-
-// TODO rename
-static void selectItem(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- intptr_t prev;
-
- prev = t->selected;
- lParamToRowColumn(t, lParam, &(t->selected), &(t->focusedColumn));
- finishSelect(t, prev);
-}
diff --git a/wintable/util.h b/wintable/util.h
deleted file mode 100644
index c12435f..0000000
--- a/wintable/util.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// 29 november 2014
-
-static LONG rowHeight(struct table *t)
-{
- HFONT thisfont, prevfont;
- TEXTMETRICW tm;
- HDC dc;
- LONG ret;
-
- dc = GetDC(t->hwnd);
- if (dc == NULL)
- abort();
- thisfont = t->font; // in case WM_SETFONT happens before we return
- prevfont = (HFONT) SelectObject(dc, thisfont);
- if (prevfont == NULL)
- abort();
- if (GetTextMetricsW(dc, &tm) == 0)
- abort();
- if (SelectObject(dc, prevfont) != (HGDIOBJ) (thisfont))
- abort();
- if (ReleaseDC(t->hwnd, dc) == 0)
- abort();
- ret = tm.tmHeight;
- if (ret < t->imagelistHeight)
- ret = t->imagelistHeight;
- if (ret < t->checkboxHeight)
- ret = t->checkboxHeight;
- return ret;
-}
-
-static void redrawAll(struct table *t)
-{
- if (InvalidateRect(t->hwnd, NULL, TRUE) == 0)
- abort();
- if (UpdateWindow(t->hwnd) == 0)
- abort();
-}
-
-static RECT realClientRect(struct table *t)
-{
- RECT r;
-
- if (GetClientRect(t->hwnd, &r) == 0)
- abort();
- r.top += t->headerHeight;
- return r;
-}
-
-static void repositionHeader(struct table *t)
-{
- RECT r;
- HDLAYOUT headerlayout;
- WINDOWPOS headerpos;
-
- if (GetClientRect(t->hwnd, &r) == 0) // use the whole client rect
- abort();
- // grow the rectangle to the left to fake scrolling
- r.left -= t->hpos;
- headerlayout.prc = &r;
- headerlayout.pwpos = &headerpos;
- if (SendMessageW(t->header, HDM_LAYOUT, 0, (LPARAM) (&headerlayout)) == FALSE)
- abort();
- if (SetWindowPos(t->header, headerpos.hwndInsertAfter, headerpos.x, headerpos.y, headerpos.cx, headerpos.cy, headerpos.flags | SWP_SHOWWINDOW) == 0)
- abort();
- t->headerHeight = headerpos.cy;
-}
-
-// this counts partially visible rows
-// for all fully visible rows use t->pagesize
-// cliprect and rowHeight must be specified here to avoid recomputing things multiple times
-static intptr_t lastVisible(struct table *t, RECT cliprect, LONG rowHeight)
-{
- intptr_t last;
-
- last = ((cliprect.bottom + rowHeight - 1) / rowHeight) + t->firstVisible;
- if (last >= t->count)
- last = t->count;
- return last;
-}
-
-static void redrawRow(struct table *t, intptr_t row)
-{
- RECT r;
- intptr_t height;
-
- r = realClientRect(t);
- height = rowHeight(t);
- if (row < t->firstVisible || row > lastVisible(t, r, height)) // not visible; don't bother
- return;
- r.top = (row - t->firstVisible) * height + t->headerHeight;
- r.bottom = r.top + height;
- // keep the width and height the same; it spans the client area anyway
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- abort();
- if (UpdateWindow(t->hwnd) == 0)
- abort();
-}
-
-static intptr_t hitTestColumn(struct table *t, int x)
-{
- HDITEMW item;
- intptr_t i;
-
- // TODO count dividers
- for (i = 0; i < t->nColumns; i++) {
- ZeroMemory(&item, sizeof (HDITEMW));
- item.mask = HDI_WIDTH;
- if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
- abort();
- if (x < item.cxy)
- return i;
- x -= item.cxy; // not yet
- }
- // no column
- return -1;
-}
-
-static void lParamToRowColumn(struct table *t, LPARAM lParam, intptr_t *row, intptr_t *column)
-{
- int x, y;
- LONG h;
-
- x = GET_X_LPARAM(lParam);
- y = GET_Y_LPARAM(lParam);
- h = rowHeight(t);
- y += t->firstVisible * h;
- y -= t->headerHeight;
- y /= h;
- if (row != NULL) {
- *row = y;
- if (*row >= t->count)
- *row = -1;
- }
- if (column != NULL)
- *column = hitTestColumn(t, x);
-}
diff --git a/wintable/vscroll.h b/wintable/vscroll.h
deleted file mode 100644
index 326d853..0000000
--- a/wintable/vscroll.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// 29 november 2014
-
-static void vscrollto(struct table *t, intptr_t newpos)
-{
- SCROLLINFO si;
- RECT scrollArea;
-
- if (newpos < 0)
- newpos = 0;
- if (newpos > (t->count - t->pagesize))
- newpos = (t->count - t->pagesize);
-
- scrollArea = realClientRect(t);
-
- // negative because ScrollWindowEx() is "backwards"
- if (ScrollWindowEx(t->hwnd, 0, (-(newpos - t->firstVisible)) * rowHeight(t),
- &scrollArea, &scrollArea, NULL, NULL,
- SW_ERASE | SW_INVALIDATE) == ERROR)
- abort();
- t->firstVisible = newpos;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
- si.nPage = t->pagesize;
- si.nMin = 0;
- si.nMax = t->count - 1; // nMax is inclusive
- si.nPos = t->firstVisible;
- SetScrollInfo(t->hwnd, SB_VERT, &si, TRUE);
-}
-
-static void vscrollby(struct table *t, intptr_t n)
-{
- vscrollto(t, t->firstVisible + n);
-}
-
-static void wheelscroll(struct table *t, WPARAM wParam)
-{
- int delta;
- int lines;
- UINT scrollAmount;
-
- delta = GET_WHEEL_DELTA_WPARAM(wParam);
- if (SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &scrollAmount, 0) == 0)
- abort();
- if (scrollAmount == WHEEL_PAGESCROLL)
- scrollAmount = t->pagesize;
- if (scrollAmount == 0) // no mouse wheel scrolling (or t->pagesize == 0)
- return;
- // the rest of this is basically http://blogs.msdn.com/b/oldnewthing/archive/2003/08/07/54615.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/08/11/54624.aspx
- // see those pages for information on subtleties
- delta += t->wheelCarry;
- lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
- t->wheelCarry = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
- vscrollby(t, -lines);
-}
-
-static void vscroll(struct table *t, WPARAM wParam)
-{
- SCROLLINFO si;
- intptr_t newpos;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS | SIF_TRACKPOS;
- if (GetScrollInfo(t->hwnd, SB_VERT, &si) == 0)
- abort();
-
- newpos = t->firstVisible;
- switch (LOWORD(wParam)) {
- case SB_TOP:
- newpos = 0;
- break;
- case SB_BOTTOM:
- newpos = t->count - t->pagesize;
- break;
- case SB_LINEUP:
- newpos--;
- break;
- case SB_LINEDOWN:
- newpos++;
- break;
- case SB_PAGEUP:
- newpos -= t->pagesize;
- break;
- case SB_PAGEDOWN:
- newpos += t->pagesize;
- break;
- case SB_THUMBPOSITION:
- newpos = (intptr_t) (si.nPos);
- break;
- case SB_THUMBTRACK:
- newpos = (intptr_t) (si.nTrackPos);
- }
-
- vscrollto(t, newpos);
-}
-
-HANDLER(vscroll)
-{
- switch (uMsg) {
- case WM_VSCROLL:
- vscroll(t, wParam);
- *lResult = 0;
- return TRUE;
- case WM_MOUSEWHEEL:
- wheelscroll(t, wParam);
- *lResult = 0;
- return TRUE;
- }
- return FALSE;
-}