summaryrefslogtreecommitdiff
path: root/wintable
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2015-12-11 20:37:59 -0500
committerPietro Gagliardi <[email protected]>2015-12-11 20:37:59 -0500
commitf8e3f12ab02b528f2a05a4f713d7af7ea8e44b42 (patch)
tree82dedf4d37f0f6d31e88ebb2ca1ce6499dead261 /wintable
parente34c561ed5bedeb180437ec165882b98d70d38c1 (diff)
LET'S GET THIS FINAL REWRITE EVER STARTED
Diffstat (limited to 'wintable')
-rw-r--r--wintable/accessibility.h1081
-rw-r--r--wintable/api.h110
-rw-r--r--wintable/checkboxes.h247
-rw-r--r--wintable/children.h19
-rw-r--r--wintable/coord.h164
-rw-r--r--wintable/draw.h215
-rw-r--r--wintable/events.h62
-rw-r--r--wintable/header.h80
-rw-r--r--wintable/hscroll.h52
-rw-r--r--wintable/includethis.h73
-rw-r--r--wintable/links3
-rw-r--r--wintable/main.h165
-rw-r--r--wintable/resize.h21
-rw-r--r--wintable/scroll.h137
-rw-r--r--wintable/scrollbarseries24
-rw-r--r--wintable/select.h269
-rw-r--r--wintable/test.c198
-rw-r--r--wintable/update.h53
-rw-r--r--wintable/util.h119
-rw-r--r--wintable/vscroll.h65
20 files changed, 0 insertions, 3157 deletions
diff --git a/wintable/accessibility.h b/wintable/accessibility.h
deleted file mode 100644
index ff7364b..0000000
--- a/wintable/accessibility.h
+++ /dev/null
@@ -1,1081 +0,0 @@
-// 24 december 2014
-
-// implement MSAA-conformant accessibility
-// we need to use MSAA because UI Automation is too new for us
-// unfortunately, MSAA's documentation is... very poor. very ambiguous, very inconsistent (just run through this file's commit history and watch the TODO progression to see)
-// resources:
-// http://msdn.microsoft.com/en-us/library/ms971338.aspx
-// http://msdn.microsoft.com/en-us/library/windows/desktop/cc307844.aspx
-// http://msdn.microsoft.com/en-us/library/windows/desktop/cc307847.aspx
-// http://blogs.msdn.com/b/saraford/archive/2004/08/20/which-controls-support-which-msaa-properties-and-how-these-controls-implement-msaa-properties.aspx
-// http://msdn.microsoft.com/en-us/library/ms971325
-// http://msdn.microsoft.com/en-us/library/windows/desktop/dd318017%28v=vs.85%29.aspx
-// http://msdn.microsoft.com/en-us/library/windows/desktop/dd373624%28v=vs.85%29.aspx
-
-// notes:
-// - TODO figure out what to do about header
-// - a row extends as far right as the right edge of the last cell in the row; anything to the right of that is treated as table space (just like with mouse selection)
-// - this has the added effect that hit-testing can only ever return either the table or a cell, never a row
-// - cells have no children; checkbox cells are themselves the accessible object
-// - TODO if we ever add combobox columns, this will need to change somehow
-// - only Table and Cell can have focus; only Row can have selection
-// - TODO allow selecting a cell?
-
-// TODOs:
-// - make sure E_POINTER and RPC_E_DISCONNECTED are correct returns for IAccessible
-// - return last error on newTableAcc() in all accessible functions
-// - figure out what should be names and what should be values
-// - figure out what to do about that header row
-// - http://acccheck.codeplex.com/
-
-// uncomment this to debug table linked list management
-//#define TABLE_DEBUG_LINKEDLIST
-
-// TODO get rid of this
-typedef struct tableAccWhat tableAccWhat;
-
-struct tableAccWhat {
- LONG role;
- intptr_t row;
- intptr_t column;
-};
-
-struct tableAcc {
- const IAccessibleVtbl *vtbl;
- ULONG refcount;
- struct table *t;
- IAccessible *std;
- tableAccWhat what;
-
- // the list of currently active accessibility objects is a doubly linked list
- struct tableAcc *prev;
- struct tableAcc *next;
-};
-
-#ifdef TABLE_DEBUG_LINKEDLIST
-void list(struct table *t)
-{
- struct tableAcc *ta;
-
- printf("\n");
- if (t->firstAcc == NULL) {
- printf("\tempty\n");
- return;
- }
- printf("\t-> ");
- for (ta = t->firstAcc; ta != NULL; ta = ta->next)
- printf("%p ", ta);
- printf("\n\t<- ");
- for (ta = t->firstAcc; ta->next != NULL; ta = ta->next)
- ;
- for (; ta != NULL; ta = ta->prev)
- printf("%p ", ta);
- printf("\n");
-}
-#endif
-
-// called after each allocation
-static struct tableAcc *newTableAcc(struct table *t, LONG role, intptr_t row, intptr_t column);
-
-// common validation for accessibility functions that take varChild
-// also normalizes what as if varChild == CHILDID_SELF
-static HRESULT normalizeWhat(struct tableAcc *ta, VARIANT varChild, tableAccWhat *what)
-{
- LONG cid;
-
- if (varChild.vt != VT_I4)
- return E_INVALIDARG;
- cid = varChild.lVal;
- if (cid == CHILDID_SELF)
- return S_OK;
- cid--;
- if (cid < 0)
- return E_INVALIDARG;
- switch (what->role) {
- case ROLE_SYSTEM_TABLE:
- // TODO +1?
- if (cid >= ta->t->count)
- return E_INVALIDARG;
- what->role = ROLE_SYSTEM_ROW;
- what->row = (intptr_t) cid;
- what->column = -1;
- break;
- case ROLE_SYSTEM_ROW:
- case ROLE_SYSTEM_CELL:
- // TODO
- // TODO also figure out what to do if the current row/cell become invalid (rows being removed, etc.)
- break;
- }
- return S_OK;
-}
-
-#define TA ((struct tableAcc *) this)
-
-static HRESULT STDMETHODCALLTYPE tableAccQueryInterface(IAccessible *this, REFIID riid, void **ppvObject)
-{
- if (ppvObject == NULL)
- return E_POINTER;
- if (IsEqualIID(riid, &IID_IUnknown) ||
- IsEqualIID(riid, &IID_IDispatch) ||
- IsEqualIID(riid, &IID_IAccessible)) {
- IAccessible_AddRef(this);
- *ppvObject = (void *) this;
- return S_OK;
- }
- *ppvObject = NULL;
- return E_NOINTERFACE;
-}
-
-// TODO use InterlockedIncrement()/InterlockedDecrement() for these?
-
-static ULONG STDMETHODCALLTYPE tableAccAddRef(IAccessible *this)
-{
- TA->refcount++;
- // TODO correct?
- return TA->refcount;
-}
-
-static ULONG STDMETHODCALLTYPE tableAccRelease(IAccessible *this)
-{
- TA->refcount--;
- if (TA->refcount == 0) {
- struct tableAcc *prev, *next;
-
-#ifdef TABLE_DEBUG_LINKEDLIST
-if (TA->t != NULL) { printf("before delete:"); list(TA->t); }
-#endif
- if (TA->t != NULL && TA->t->firstAcc == TA)
- TA->t->firstAcc = TA->next;
- prev = TA->prev;
- next = TA->next;
- if (prev != NULL)
- prev->next = next;
- if (next != NULL)
- next->prev = prev;
-#ifdef TABLE_DEBUG_LINKEDLIST
-if (TA->t != NULL) { printf("after delete:"); list(TA->t); }
-#endif
- if (TA->std != NULL)
- IAccessible_Release(TA->std);
- tableFree(TA, "error freeing Table accessibility object");
- return 0;
- }
- return TA->refcount;
-}
-
-// IDispatch
-// TODO make sure relegating these to the standard accessibility object is harmless
-
-static HRESULT STDMETHODCALLTYPE tableAccGetTypeInfoCount(IAccessible *this, UINT *pctinfo)
-{
- if (TA->t == NULL || TA->std == NULL) {
- // TODO set values on error
- return RPC_E_DISCONNECTED;
- }
- return IAccessible_GetTypeInfoCount(TA->std, pctinfo);
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccGetTypeInfo(IAccessible *this, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
-{
- if (TA->t == NULL || TA->std == NULL) {
- // TODO set values on error
- return RPC_E_DISCONNECTED;
- }
- return IAccessible_GetTypeInfo(TA->std, iTInfo, lcid, ppTInfo);
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccGetIDsOfNames(IAccessible *this, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
-{
- if (TA->t == NULL || TA->std == NULL) {
- // TODO set values on error
- return RPC_E_DISCONNECTED;
- }
- return IAccessible_GetIDsOfNames(TA->std, riid, rgszNames, cNames, lcid, rgDispId);
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccInvoke(IAccessible *this, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
-{
- if (TA->t == NULL || TA->std == NULL) {
- // TODO set values on error
- return RPC_E_DISCONNECTED;
- }
- return IAccessible_Invoke(TA->std, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
-}
-
-// IAccessible
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accParent(IAccessible *this, IDispatch **ppdispParent)
-{
- if (ppdispParent == NULL)
- return E_POINTER;
- // TODO set ppdispParent to zero?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- // TODO check if row/column is still valid
- switch (TA->what.role) {
- case ROLE_SYSTEM_TABLE:
- // defer to standard accessible object
- // TODO [EDGE CASE/POOR DOCUMENTATION?] https://msdn.microsoft.com/en-us/library/ms971325 says "Returns the IDispatch interface of the Table object."; isn't that just returning self?
- return IAccessible_get_accParent(TA->std, ppdispParent);
- case ROLE_SYSTEM_ROW:
- *ppdispParent = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_TABLE, -1, -1);
- return S_OK;
- case ROLE_SYSTEM_CELL:
- *ppdispParent = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_ROW, TA->what.row, -1);
- return S_OK;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accChildCount(IAccessible *this, long *pcountChildren)
-{
- if (pcountChildren == NULL)
- return E_POINTER;
- // TODO set pcountChildren to zero?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- switch (TA->what.role) {
- case ROLE_SYSTEM_TABLE:
- // TODO header row
- *pcountChildren = (long) (TA->t->count);
- return S_OK;
- case ROLE_SYSTEM_ROW:
- *pcountChildren = (long) (TA->t->nColumns);
- return S_OK;
- case ROLE_SYSTEM_CELL:
- *pcountChildren = 0;
- return S_OK;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-}
-
-// TODO [EDGE CASE/NOT DOCUMENTED/CHECK SAMPLE] what happens if CHILDID_SELF is passed?
-// TODO [EDGE CASE/NOT DOCUMENTED/CHECK SAMPLE] what SHOULD happen if an out of bounds ID is passed?
-static HRESULT STDMETHODCALLTYPE tableAccget_accChild(IAccessible *this, VARIANT varChild, IDispatch **ppdispChild)
-{
- LONG cid;
-
- if (ppdispChild == NULL)
- return E_POINTER;
- *ppdispChild = NULL;
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- if (varChild.vt != VT_I4)
- return E_INVALIDARG;
- cid = varChild.lVal;
- if (cid < 0)
- // TODO really?
- return E_INVALIDARG;
- if (cid == CHILDID_SELF)
- return E_FAIL; // TODO
- cid--;
- switch (TA->what.role) {
- case ROLE_SYSTEM_TABLE:
- // TODO table header
- if (TA->t->count == 0)
- return S_FALSE;
- if (cid > TA->t->count - 1)
- // TODO really?
- return E_INVALIDARG;
- *ppdispChild = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_ROW, cid, -1);
- return S_OK;
- case ROLE_SYSTEM_ROW:
- // TODO verify that row is still valid
- if (TA->t->nColumns == 0)
- return S_FALSE;
- if (cid > TA->t->nColumns - 1)
- // TODO really?
- return E_INVALIDARG;
- *ppdispChild = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_CELL, TA->what.row, cid);
- case ROLE_SYSTEM_CELL:
- // TODO verify that row/column are still valid?
- return S_FALSE;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accName(IAccessible *this, VARIANT varChild, BSTR *pszName)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (pszName == NULL)
- return E_POINTER;
- // TODO double-check that this must be set to zero
- *pszName = NULL;
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- switch (what.role) {
- case ROLE_SYSTEM_TABLE:
- // defer to standard accessible object
- return IAccessible_get_accName(TA->std, varChild, pszName);
- case ROLE_SYSTEM_ROW:
- // TODO
- return S_FALSE;
- case ROLE_SYSTEM_CELL:
- // TODO
- return S_FALSE;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-}
-
-// this differs quite much from what is described at https://msdn.microsoft.com/en-us/library/ms971325
-static HRESULT STDMETHODCALLTYPE tableAccget_accValue(IAccessible *this, VARIANT varChild, BSTR *pszValue)
-{
- HRESULT hr;
- tableAccWhat what;
- WCHAR *text;
-
- if (pszValue == NULL)
- return E_POINTER;
- // TODO set pszValue to zero?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- switch (what.role) {
- case ROLE_SYSTEM_TABLE:
- // TODO really?
- return IAccessible_get_accValue(TA->std, varChild, pszValue);
- case ROLE_SYSTEM_ROW:
- // TODO
- return DISP_E_MEMBERNOTFOUND;
- case ROLE_SYSTEM_CELL:
- switch (TA->t->columnTypes[what.column]) {
- case tableColumnText:
- text = getCellText(TA->t, what.row, what.column);
- // TODO check for error
- *pszValue = SysAllocString(text);
- returnCellData(TA->t, what.row, what.column, text);
- return S_OK;
- case tableColumnImage:
- // TODO
- return DISP_E_MEMBERNOTFOUND;
- case tableColumnCheckbox:
- // TODO!!!!!!
- return DISP_E_MEMBERNOTFOUND;
- }
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accDescription(IAccessible *this, VARIANT varChild, BSTR *pszDescription)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (pszDescription == NULL)
- return E_POINTER;
- *pszDescription = NULL;
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- // don't support descriptions anyway; do return the above errors just to be safe
- return DISP_E_MEMBERNOTFOUND;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accRole(IAccessible *this, VARIANT varChild, VARIANT *pvarRole)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (pvarRole == NULL)
- return E_POINTER;
- pvarRole->vt = VT_EMPTY;
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- pvarRole->vt = VT_I4;
- pvarRole->lVal = what.role;
- return S_OK;
-}
-
-// TODO reason about STATE_SYSTEM_INVISIBLE and STATE_SYSTEM_OFFSCREEN
-static HRESULT STDMETHODCALLTYPE tableAccget_accState(IAccessible *this, VARIANT varChild, VARIANT *pvarState)
-{
- HRESULT hr;
- tableAccWhat what;
- LONG state;
-
- if (pvarState == NULL)
- return E_POINTER;
- pvarState->vt = VT_EMPTY;
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
-
- state = 0;
- switch (what.role) {
- case ROLE_SYSTEM_TABLE:
- hr = IAccessible_get_accState(TA->std, varChild, pvarState);
- if (hr != S_OK)
- return hr;
- // TODO make sure pvarState->vt == VT_I4 (what to return otherwise?)
- state |= pvarState->lVal;
- break;
- case ROLE_SYSTEM_ROW:
- state |= STATE_SYSTEM_SELECTABLE;
- if (TA->t->selectedRow == what.row)
- state |= STATE_SYSTEM_SELECTED;
- break;
- case ROLE_SYSTEM_CELL:
- if (TA->t->columnTypes[what.column] == tableColumnCheckbox) {
- // TODO is there no STATE_SYSTEM_CHECKABLE?
- if (isCheckboxChecked(TA->t, what.row, what.column))
- state |= STATE_SYSTEM_CHECKED;
- }
- state |= STATE_SYSTEM_FOCUSABLE;
- if (TA->t->selectedRow == what.row && TA->t->selectedColumn == what.column)
- state |= STATE_SYSTEM_FOCUSED;
- if (TA->t->columnTypes[what.column] != tableColumnCheckbox)
- state |= STATE_SYSTEM_READONLY;
- break;
- }
- pvarState->vt = VT_I4;
- pvarState->lVal = state;
- return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accHelp(IAccessible *this, VARIANT varChild, BSTR *pszHelp)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (pszHelp == NULL)
- return E_POINTER;
- *pszHelp = NULL;
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- // don't support help anyway; do return the above errors just to be safe
- return DISP_E_MEMBERNOTFOUND;
-}
-
-// TODO Inspect.exe seems to ignore the DISP_E_MEMBERNOTFOUND and just tells us the help topic is the empty string; make sure this works right
-static HRESULT STDMETHODCALLTYPE tableAccget_accHelpTopic(IAccessible *this, BSTR *pszHelpFile, VARIANT varChild, long *pidTopic)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (pszHelpFile == NULL || pidTopic == NULL)
- return E_POINTER;
- // TODO set pszHelpFile and pidTopic to zero?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- // don't support Windows Help (the super-old .hlp help files) topics anyway; do return the above errors just to be safe
- // TODO [EDGE CASE??] or should we defer back to the standard accessible object? get_accHelp() was explicitly documented as not being supported by the standard/common controls, but this one isn't...
- return DISP_E_MEMBERNOTFOUND;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accKeyboardShortcut(IAccessible *this, VARIANT varChild, BSTR *pszKeyboardShortcut)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (pszKeyboardShortcut == NULL)
- return E_POINTER;
- // TODO set pszKeyboardShortcut to zero?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- // defer to the standard accessible object for the table itself in case a program assigns an access key somehow (adjacent label?); MSDN says to, anyway
- if (what.role == ROLE_SYSTEM_TABLE)
- return IAccessible_get_accKeyboardShortcut(TA->std, varChild, pszKeyboardShortcut);
- if (what.role == ROLE_SYSTEM_CELL)
- ; // TODO implement this for checkbox cells?
- return DISP_E_MEMBERNOTFOUND;
-}
-
-// TODO TEST THIS
-// TODO [EDGE CASE??] no parents?
-static HRESULT STDMETHODCALLTYPE tableAccget_accFocus(IAccessible *this, VARIANT *pvarChild)
-{
- HRESULT hr;
-
- if (pvarChild == NULL)
- return E_POINTER;
- // TODO set pvarChild to empty?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- // TODO verify that TA is still pointing to a valid row/column
-
- // first see if the control has the focus
- // this is why a standard accessible object is needed on all accessible objects
- hr = IAccessible_get_accFocus(TA->std, pvarChild);
- // check the pvarChild type instead of hr
- // https://msdn.microsoft.com/en-us/library/windows/desktop/dd318479%28v=vs.85%29.aspx does this
- // TODO [EDGE CASE] figure out why
- if (pvarChild->vt != VT_I4)
- return hr;
-
- switch (TA->what.role) {
- case ROLE_SYSTEM_TABLE:
- if (TA->t->selectedRow != -1 && TA->t->selectedColumn != -1)
- goto selectedCell;
- goto self;
- case ROLE_SYSTEM_ROW:
- if (TA->t->selectedRow != TA->what.row)
- goto nothing;
- goto selectedCell;
- case ROLE_SYSTEM_CELL:
- if (TA->t->selectedRow != TA->what.row)
- goto nothing;
- if (TA->t->selectedColumn != TA->what.column)
- goto nothing;
- goto self;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-
-nothing:
- pvarChild->vt = VT_EMPTY;
- // TODO really this one?
- return S_FALSE;
-
-self:
- pvarChild->vt = VT_I4;
- pvarChild->lVal = CHILDID_SELF;
- return S_OK;
-
-selectedCell:
- pvarChild->vt = VT_I4;
- pvarChild->pdispVal = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_CELL, TA->what.row, TA->what.column);
- return S_OK;
-}
-
-// note: https://msdn.microsoft.com/en-us/library/ms971325 is geared toward cell-based selection
-// we have row-based selection, so only Tables implement this method, and they return a row
-static HRESULT STDMETHODCALLTYPE tableAccget_accSelection(IAccessible *this, VARIANT *pvarChildren)
-{
- if (pvarChildren == NULL)
- return E_POINTER;
- // TOOD set pvarChildren to VT_EMPTY?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- if (TA->what.role != ROLE_SYSTEM_TABLE)
- // TODO [EDGE CASE] implement this for row anyway? how?
- return DISP_E_MEMBERNOTFOUND;
- if (TA->t->selectedRow == -1) {
- pvarChildren->vt = VT_EMPTY;
- return S_OK;
- }
- pvarChildren->vt = VT_DISPATCH;
- pvarChildren->pdispVal = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_ROW, TA->t->selectedRow, -1);
- return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccget_accDefaultAction(IAccessible *this, VARIANT varChild, BSTR *pszDefaultAction)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (pszDefaultAction == NULL)
- return E_POINTER;
- *pszDefaultAction = NULL;
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- if (what.role == ROLE_SYSTEM_CELL)
- ; // TODO implement this for checkbox cells?
- return DISP_E_MEMBERNOTFOUND;
-}
-
-// TODO should this method result in an event?
-// TODO [EDGE CASE] how do we deselect? in the table or in the row? wouldn't this go against multiple selection?
-// TODO require cell rows to be selected before focusing?
-static HRESULT STDMETHODCALLTYPE tableAccaccSelect(IAccessible *this, long flagsSelect, VARIANT varChild)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- if (what.role == ROLE_SYSTEM_TABLE) // defer to the standard accessible object
- return IAccessible_accSelect(TA->std, flagsSelect, varChild);
- // reject flags that are only applicable to multiple selection
- if ((flagsSelect & (SELFLAG_EXTENDSELECTION | SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION)) != 0)
- return E_INVALIDARG;
- // and do nothing if a no-op
- if (flagsSelect == SELFLAG_NONE)
- return S_FALSE;
- // TODO cast ~ expressions to the correct type
- switch (what.role) {
- case ROLE_SYSTEM_ROW:
- // reject any other flag
- if ((flagsSelect & (~SELFLAG_TAKESELECTION)) != 0)
- return E_INVALIDARG;
- if ((flagsSelect & SELFLAG_TAKESELECTION) != 0) {
- if (TA->t->nColumns == 0) // can't select
- return S_FALSE;
- // if no column selected, select first (congruent to behavior of certain keyboard events)
- // TODO handle GetLastError()
- if (TA->t->selectedColumn == -1)
- doselect(TA->t, what.row, TA->t->selectedColumn);
- else
- doselect(TA->t, what.row, 0);
- return S_OK;
- }
- return S_FALSE;
- case ROLE_SYSTEM_CELL:
- // reject any other flag
- if ((flagsSelect & (~SELFLAG_TAKEFOCUS)) != 0)
- return E_INVALIDARG;
- if ((flagsSelect & SELFLAG_TAKEFOCUS) != 0) {
- doselect(TA->t, what.row, what.column);
- return S_OK;
- }
- return S_FALSE;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccaccLocation(IAccessible *this, long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
-{
- HRESULT hr;
- tableAccWhat what;
- RECT r;
- POINT pt;
- struct rowcol rc;
-
- if (pxLeft == NULL || pyTop == NULL || pcxWidth == NULL || pcyHeight == NULL)
- return E_POINTER;
- // TODO set the out parameters to zero?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- switch (what.role) {
- case ROLE_SYSTEM_TABLE:
- return IAccessible_accLocation(TA->std, pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
- case ROLE_SYSTEM_ROW:
- // TODO actually write this
- return E_FAIL;
- case ROLE_SYSTEM_CELL:
- rc.row = what.row;
- rc.column = what.column;
- if (!rowColumnToClientRect(TA->t, rc, &r)) {
- // TODO [EDGE CASE] what do we do here?
- // TODO we have to return something indicating that the object is off-screen
- }
- // TODO [EDGE CASE] intersect with client rect?
- break;
- }
- pt.x = r.left;
- pt.y = r.top;
- if (ClientToScreen(TA->t->hwnd, &pt) == 0)
- return HRESULT_FROM_WIN32(GetLastError());
- *pxLeft = pt.x;
- *pyTop = pt.y;
- *pcxWidth = r.right - r.left;
- *pcyHeight = r.bottom - r.top;
- return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccaccNavigate(IAccessible *this, long navDir, VARIANT varStart, VARIANT *pvarEndUpAt)
-{
- HRESULT hr;
- tableAccWhat what;
- intptr_t row = -1;
- intptr_t column = -1;
-
- if (pvarEndUpAt == NULL)
- return E_POINTER;
- // TODO set pvarEndUpAt to an invalid value?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varStart, &what);
- if (hr != S_OK)
- return hr;
- switch (what.role) {
- case ROLE_SYSTEM_TABLE:
- switch (navDir) {
- case NAVDIR_FIRSTCHILD:
- // TODO header row
- if (TA->t->count == 0)
- goto nowhere;
- row = 0;
- goto specificRow;
- case NAVDIR_LASTCHILD:
- // TODO header row
- if (TA->t->count == 0)
- goto nowhere;
- row = TA->t->count - 1;
- goto specificRow;
- }
- // otherwise, defer to the standard accessible object
- return IAccessible_accNavigate(TA->std, navDir, varStart, pvarEndUpAt);
- case ROLE_SYSTEM_ROW:
- row = what.row;
- switch (navDir) {
- case NAVDIR_UP:
- case NAVDIR_PREVIOUS:
- if (row == 0) // can't go up
- goto nowhere;
- row--;
- // row should still be valid because normalizeWhat() returns an error if the current row is no longer valid, and if that's valid, the row above it should also be valid
- goto specificRow;
- case NAVDIR_DOWN:
- case NAVDIR_NEXT:
- if (row == TA->t->count - 1) // can't go down
- goto nowhere;
- row++;
- // row should still be valid by the above conjecture
- goto specificRow;
- case NAVDIR_LEFT:
- case NAVDIR_RIGHT:
- goto nowhere;
-// TODO this doesn't actually exist yet https://msdn.microsoft.com/en-us/library/ms971325 talks about it
-// case NAVDIR_PARENT:
-// goto tableItself;
- case NAVDIR_FIRSTCHILD:
- if (TA->t->nColumns == 0)
- goto nowhere;
- column = 0;
- goto specificCell;
- case NAVDIR_LASTCHILD:
- if (TA->t->nColumns == 0)
- goto nowhere;
- column = TA->t->nColumns - 1;
- goto specificCell;
- }
- // TODO differentiate between unsupported navigation directions and invalid navigation directions
- goto nowhere;
- case ROLE_SYSTEM_CELL:
- row = what.row;
- column = what.column;
- switch (navDir) {
- case NAVDIR_UP:
- if (row == 0) // can't go up
- goto nowhere;
- row--;
- goto specificCell;
- case NAVDIR_DOWN:
- if (row == TA->t->count - 1) // can't go down
- goto nowhere;
- row++;
- goto specificCell;
- case NAVDIR_LEFT:
- case NAVDIR_PREVIOUS:
- if (column == 0) // can't go left
- goto nowhere;
- column--;
- goto specificCell;
- case NAVDIR_RIGHT:
- case NAVDIR_NEXT:
- if (column == TA->t->nColumns - 1) // can't go right
- goto nowhere;
- column++;
- goto specificCell;
-// TODO this doesn't actually exist yet https://msdn.microsoft.com/en-us/library/ms971325 talks about it
-// case NAVDIR_PARENT:
-// goto specificRow;
- case NAVDIR_FIRSTCHILD:
- case NAVDIR_LASTCHILD:
- goto nowhere;
- }
- // TODO differentiate between unsupported navigation directions and invalid navigation directions
- goto nowhere;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-
-nowhere:
- pvarEndUpAt->vt = VT_EMPTY;
- return S_FALSE;
-
-tableItself:
- pvarEndUpAt->vt = VT_DISPATCH;
- pvarEndUpAt->pdispVal = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_TABLE, -1, -1);
- return S_OK;
-
-specificRow:
- pvarEndUpAt->vt = VT_DISPATCH;
- pvarEndUpAt->pdispVal = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_ROW, row, -1);
- return S_OK;
-
-specificCell:
- pvarEndUpAt->vt = VT_DISPATCH;
- pvarEndUpAt->pdispVal = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_CELL, row, column);
- return S_OK;
-}
-
-// TODO [EDGE CASE??] should this ever return parents?
-static HRESULT STDMETHODCALLTYPE tableAccaccHitTest(IAccessible *this, long xLeft, long yTop, VARIANT *pvarChild)
-{
- POINT pt;
- struct rowcol rc;
- RECT r;
-
- if (pvarChild == NULL)
- return E_POINTER;
- // TODO set pvarChild to an invalid value?
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
-
- pt.x = xLeft;
- pt.y = yTop;
- if (ScreenToClient(TA->t->hwnd, &pt) == 0)
- return HRESULT_FROM_WIN32(GetLastError());
-
- // first see if the point is even IN the table
- if (GetClientRect(TA->t->hwnd, &r) == 0)
- return HRESULT_FROM_WIN32(GetLastError());
- r.top += TA->t->headerHeight;
- if (PtInRect(&r, pt) == 0)
- goto outside;
-
- // now see if we're in a cell or in the table
- // TODO also handle GetLastError() here
- rc = clientCoordToRowColumn(TA->t, pt);
- switch (TA->what.role) {
- case ROLE_SYSTEM_TABLE:
- // either the table or the cell
- if (rc.row == -1 || rc.column == -1)
- goto self;
- goto specificCell;
- case ROLE_SYSTEM_ROW:
- // a specific cell, but only if in the same row
- // TODO actually do we really need these spurious rc.column ==/!= -1 checks?
- if (rc.row == TA->what.row) {
- if (rc.column == -1)
- // TODO de-GetLastError() this
- panic("impossible situation TODO write this");
- goto specificCell;
- }
- goto outside;
- case ROLE_SYSTEM_CELL:
- if (rc.row == TA->what.row && rc.column == TA->what.column)
- goto self;
- goto outside;
- }
- // TODO actually do this right
- // TODO un-GetLastError() this
- panic("impossible blah blah blah TODO write this");
- return E_FAIL;
-
-outside:
- pvarChild->vt = VT_EMPTY;
- return S_FALSE;
-
-self:
- pvarChild->vt = VT_I4;
- pvarChild->lVal = CHILDID_SELF;
- return S_OK;
-
-specificCell:
- pvarChild->vt = VT_DISPATCH;
- // TODO GetLastError() here too
- pvarChild->pdispVal = (IDispatch *) newTableAcc(TA->t, ROLE_SYSTEM_CELL, rc.row, rc.column);
- return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccaccDoDefaultAction(IAccessible *this, VARIANT varChild)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- if (what.role == ROLE_SYSTEM_CELL)
- ; // TODO implement this for checkbox cells?
- return DISP_E_MEMBERNOTFOUND;
-}
-
-// inconsistencies, inconsistencies
-// https://msdn.microsoft.com/en-us/library/windows/desktop/dd318491%28v=vs.85%29.aspx says to just return E_NOTIMPL and not even bother with an implementation; in fact it doesn't even *have* the documentation anymore
-// http://blogs.msdn.com/b/saraford/archive/2004/08/20/which-controls-support-which-msaa-properties-and-how-these-controls-implement-msaa-properties.aspx says never to return E_NOTIMPL from an IAccessible method (but it also discounts RPC_E_DISCONNECTED (not explicitly), so I'm guessing this is a much older document)
-// let's just do what our put_accValue() does and do full validation, then just return DISP_E_MEMBERNOTFOUND
-// I really hope UI Automation isn't so ambiguous and inconsistent... too bad I'm still choosing to support Windows XP while its market share (compared to *every other OS ever*) is still as large as it is
-static HRESULT STDMETHODCALLTYPE tableAccput_accName(IAccessible *this, VARIANT varChild, BSTR szName)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- // don't support setting values anyway; do return the above errors just to be safe
- return DISP_E_MEMBERNOTFOUND;
-}
-
-static HRESULT STDMETHODCALLTYPE tableAccput_accValue(IAccessible *this, VARIANT varChild, BSTR szValue)
-{
- HRESULT hr;
- tableAccWhat what;
-
- if (TA->t == NULL || TA->std == NULL)
- return RPC_E_DISCONNECTED;
- what = TA->what;
- hr = normalizeWhat(TA, varChild, &what);
- if (hr != S_OK)
- return hr;
- // don't support setting values anyway; do return the above errors just to be safe
- // TODO defer ROW_SYSTEM_TABLE to the standard accessible object?
- // TODO implement for checkboxes?
- return DISP_E_MEMBERNOTFOUND;
-}
-
-static const IAccessibleVtbl tableAccVtbl = {
- .QueryInterface = tableAccQueryInterface,
- .AddRef = tableAccAddRef,
- .Release = tableAccRelease,
- .GetTypeInfoCount = tableAccGetTypeInfoCount,
- .GetTypeInfo = tableAccGetTypeInfo,
- .GetIDsOfNames = tableAccGetIDsOfNames,
- .Invoke = tableAccInvoke,
- .get_accParent = tableAccget_accParent,
- .get_accChildCount = tableAccget_accChildCount,
- .get_accChild = tableAccget_accChild,
- .get_accName = tableAccget_accName,
- .get_accValue = tableAccget_accValue,
- .get_accDescription = tableAccget_accDescription,
- .get_accRole = tableAccget_accRole,
- .get_accState = tableAccget_accState,
- .get_accHelp = tableAccget_accHelp,
- .get_accHelpTopic = tableAccget_accHelpTopic,
- .get_accKeyboardShortcut = tableAccget_accKeyboardShortcut,
- .get_accFocus = tableAccget_accFocus,
- .get_accSelection = tableAccget_accSelection,
- .get_accDefaultAction = tableAccget_accDefaultAction,
- .accSelect = tableAccaccSelect,
- .accLocation = tableAccaccLocation,
- .accNavigate = tableAccaccNavigate,
- .accHitTest = tableAccaccHitTest,
- .accDoDefaultAction = tableAccaccDoDefaultAction,
- .put_accName = tableAccput_accName,
- .put_accValue = tableAccput_accValue,
-};
-
-static struct tableAcc *newTableAcc(struct table *t, LONG role, intptr_t row, intptr_t column)
-{
- struct tableAcc *ta;
- HRESULT hr;
- IAccessible *std;
-
- ta = (struct tableAcc *) tableAlloc(sizeof (struct tableAcc), "error creating Table accessibility object");
- ta->vtbl = &tableAccVtbl;
- ta->refcount = 1;
- ta->t = t;
- // TODO adjust last argument
- hr = CreateStdAccessibleObject(t->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **) (&std));
- if (hr != S_OK)
- // TODO panichresult
- panic("error creating standard accessible object for Table");
- ta->std = std;
- ta->what.role = role;
- ta->what.row = row;
- ta->what.column = column;
-
-#ifdef TABLE_DEBUG_LINKEDLIST
-printf("before add:"); list(t);
-#endif
- ta->next = t->firstAcc;
- if (t->firstAcc != NULL)
- t->firstAcc->prev = ta;
- t->firstAcc = ta;
-#ifdef TABLE_DEBUG_LINKEDLIST
-printf("after add:"); list(t);
-#endif
-
- return ta;
-}
-
-static void invalidateTableAccs(struct table *t)
-{
- struct tableAcc *ta;
-
- for (ta = t->firstAcc; ta != NULL; ta = ta->next) {
- ta->t = NULL;
- IAccessible_Release(ta->std);
- ta->std = NULL;
- }
- t->firstAcc = NULL;
- NotifyWinEvent(EVENT_OBJECT_DESTROY, t->hwnd, OBJID_CLIENT, CHILDID_SELF);
-}
-
-HANDLER(accessibilityHandler)
-{
- struct tableAcc *ta;
-
- if (uMsg != WM_GETOBJECT)
- return FALSE;
- // OBJID_CLIENT evaluates to an expression of type LONG
- // the documentation for WM_GETOBJECT says to cast "it" to a DWORD before comparing
- // https://msdn.microsoft.com/en-us/library/windows/desktop/dd373624%28v=vs.85%29.aspx casts them both to DWORDs; let's do that
- // its two siblings only cast lParam, resulting in an erroneous DWORD to LONG comparison
- // The Old New Thing book does not cast anything
- // Microsoft's MSAA sample casts lParam to LONG instead!
- // (As you can probably tell, the biggest problem with MSAA is that its documentation is ambiguous and/or self-contradictory...)
- if (((DWORD) lParam) != ((DWORD) OBJID_CLIENT))
- return FALSE;
- ta = newTableAcc(t, ROLE_SYSTEM_TABLE, -1, -1);
- *lResult = LresultFromObject(&IID_IAccessible, wParam, (LPUNKNOWN) (ta));
- // TODO check *lResult
- // TODO adjust pointer
- IAccessible_Release((IAccessible *) ta);
- return TRUE;
-}
diff --git a/wintable/api.h b/wintable/api.h
deleted file mode 100644
index 09552e5..0000000
--- a/wintable/api.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// 8 december 2014
-
-static void addColumn(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- t->nColumns++;
- t->columnTypes = (int *) tableRealloc(t->columnTypes, t->nColumns * sizeof (int), "adding the new column type to the current Table's list of column types");
- t->columnTypes[t->nColumns - 1] = (int) wParam;
- // TODO make a panicNoErrCode() or panicArg() for this
- if (t->columnTypes[t->nColumns - 1] >= nTableColumnTypes)
- panic("invalid column type passed to tableAddColumn");
- headerAddColumn(t, (WCHAR *) lParam);
- update(t, TRUE);
- // TODO only redraw the part of the client area where the new client went, if any
- // (TODO when — if — adding autoresize, figure this one out)
-
- // TODO send a notification for all rows?
-}
-
-// TODO what happens if the currently selected row is lost?
-static void setRowCount(struct table *t, intptr_t rc)
-{
- intptr_t old, i;
-
- old = t->count;
- t->count = rc;
- // we DO redraw everything because we don't want any rows that should no longer be there to remain on screen!
- updateAll(t); // DONE
- // TODO reset checkbox and selection logic if the current row for both no longer exists
- // TODO really send all these notifications?
- if (old < t->count) // rows added
- for (i = old; i < t->count; i++)
- NotifyWinEvent(EVENT_OBJECT_CREATE, t->hwnd, OBJID_CLIENT, i);
- else if (old > t->count) // rows removed
- for (i = old; i > t->count; i++)
- NotifyWinEvent(EVENT_OBJECT_DESTROY, t->hwnd, OBJID_CLIENT, i);
- // TODO update existing rows?
-}
-
-HANDLER(apiHandlers)
-{
- intptr_t *rcp;
- intptr_t row;
-
- switch (uMsg) {
- case WM_SETFONT:
- // don't free the old font; see http://blogs.msdn.com/b/oldnewthing/archive/2008/09/12/8945692.aspx
- t->font = (HFONT) wParam;
- SendMessageW(t->header, WM_SETFONT, wParam, lParam);
- // if we redraw, we have to redraw ALL of it; after all, the font changed!
- if (LOWORD(lParam) != FALSE)
- updateAll(t); // DONE
- else
- update(t, FALSE); // DONE
- *lResult = 0;
- return TRUE;
- case WM_GETFONT:
- *lResult = (LRESULT) (t->font);
- return TRUE;
- case tableAddColumn:
- addColumn(t, wParam, lParam);
- *lResult = 0;
- return TRUE;
- case tableSetRowCount:
- rcp = (intptr_t *) lParam;
- setRowCount(t, *rcp);
- *lResult = 0;
- return TRUE;
- case tableGetSelection:
- rcp = (intptr_t *) wParam;
- if (rcp != NULL)
- *rcp = t->selectedRow;
- rcp = (intptr_t *) lParam;
- if (rcp != NULL)
- *rcp = t->selectedColumn;
- *lResult = 0;
- return TRUE;
- case tableSetSelection:
- // TODO does doselect() do validation?
- rcp = (intptr_t *) wParam;
- row = *rcp;
- rcp = (intptr_t *) lParam;
- if (rcp == NULL)
- if (row == -1)
- doselect(t, -1, -1);
- else // select column 0, just like keyboard selections; TODO what if there aren't any columns?
- doselect(t, row, 0);
- else
- doselect(t, row, *rcp);
- *lResult = 0;
- return TRUE;
- }
- return FALSE;
-}
-
-static LRESULT notify(struct table *t, UINT code, intptr_t row, intptr_t column, uintptr_t data)
-{
- tableNM nm;
-
- ZeroMemory(&nm, sizeof (tableNM));
- nm.nmhdr.hwndFrom = t->hwnd;
- // TODO check for error from here? 0 is a valid ID (IDCANCEL)
- nm.nmhdr.idFrom = GetDlgCtrlID(t->hwnd);
- nm.nmhdr.code = code;
- nm.row = row;
- nm.column = column;
- nm.columnType = t->columnTypes[nm.column];
- nm.data = data;
- // TODO check for error from GetParent()?
- return SendMessageW(GetParent(t->hwnd), WM_NOTIFY, (WPARAM) (nm.nmhdr.idFrom), (LPARAM) (&nm));
-}
diff --git a/wintable/checkboxes.h b/wintable/checkboxes.h
deleted file mode 100644
index b44a0d0..0000000
--- a/wintable/checkboxes.h
+++ /dev/null
@@ -1,247 +0,0 @@
-// 16 august 2014
-
-enum {
- checkboxStateChecked = 1 << 0,
- checkboxStateHot = 1 << 1,
- checkboxStatePushed = 1 << 2,
- checkboxnStates = 1 << 3,
-};
-
-// TODO actually make this
-#define panichresult(a, b) panic(a)
-
-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 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 getFrameControlCheckboxSize(HDC dc, int *width, int *height)
-{
- // 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)
- panichresult("error getting theme part size for Table checkboxes", res);
- return s;
-}
-
-static void drawThemeCheckbox(HDC dc, RECT *r, int cbState, HTHEME theme)
-{
- HRESULT res;
-
- res = DrawThemeBackground(theme, dc, BP_CHECKBOX, themestates[cbState], r, NULL);
- if (res != S_OK)
- panichresult("error drawing Table checkbox image from theme", res);
-}
-
-static void getThemeCheckboxSize(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)
- // TODO make this use a no-information (or two ints) panic()
- panic("size mismatch in Table checkbox states");
- }
- *width = (int) size.cx;
- *height = (int) size.cy;
-}
-
-static void drawCheckbox(struct table *t, HDC dc, RECT *r, int cbState)
-{
- if (t->theme != NULL) {
- drawThemeCheckbox(dc, r, cbState, t->theme);
- return;
- }
- drawFrameControlCheckbox(dc, r, cbState);
-}
-
-static void freeCheckboxThemeData(struct table *t)
-{
- if (t->theme != NULL) {
- HRESULT res;
-
- res = CloseThemeData(t->theme);
- if (res != S_OK)
- 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
- getThemeCheckboxSize(dc, &(t->checkboxWidth), &(t->checkboxHeight), t->theme);
- else // couldn't open; fall back
- getFrameControlCheckboxSize(dc, &(t->checkboxWidth), &(t->checkboxHeight));
- if (ReleaseDC(t->hwnd, dc) == 0)
- panic("error releasing Table DC for loading checkbox theme data");
-}
-
-static void redrawCheckboxRect(struct table *t, LPARAM lParam)
-{
- struct rowcol rc;
- RECT r;
-
- rc = lParamToRowColumn(t, lParam);
- if (rc.row == -1 && rc.column == -1)
- return;
- if (t->columnTypes[rc.column] != tableColumnCheckbox)
- return;
- if (!rowColumnToClientRect(t, rc, &r))
- return;
- // TODO only the checkbox rect?
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- panic("error redrawing Table checkbox rect for mouse events");
-}
-
-HANDLER(checkboxMouseMoveHandler)
-{
- // don't actually check to see if the mouse is in the checkbox rect
- // if there's scrolling without mouse movement, that will change
- // instead, drawCell() will handle it
- if (!t->checkboxMouseOverLast) {
- t->checkboxMouseOverLast = TRUE;
- retrack(t);
- } else
- redrawCheckboxRect(t, t->checkboxMouseOverLastPoint);
- t->checkboxMouseOverLastPoint = lParam;
- redrawCheckboxRect(t, t->checkboxMouseOverLastPoint);
- *lResult = 0;
- return TRUE;
-}
-
-HANDLER(checkboxMouseLeaveHandler)
-{
- if (t->checkboxMouseOverLast)
- redrawCheckboxRect(t, t->checkboxMouseOverLastPoint);
- // TODO remember what I wanted to do here in the case of a held mouse button
- t->checkboxMouseOverLast = FALSE;
- *lResult = 0;
- return TRUE;
-}
-
-HANDLER(checkboxMouseDownHandler)
-{
- struct rowcol rc;
- RECT r;
- POINT pt;
-
- rc = lParamToRowColumn(t, lParam);
- if (rc.row == -1 || rc.column == -1)
- return FALSE;
- if (t->columnTypes[rc.column] != tableColumnCheckbox)
- return FALSE;
- if (!rowColumnToClientRect(t, rc, &r))
- return FALSE;
- toCheckboxRect(t, &r, 0);
- pt.x = GET_X_LPARAM(lParam);
- pt.y = GET_Y_LPARAM(lParam);
- if (PtInRect(&r, pt) == 0)
- return FALSE;
- t->checkboxMouseDown = TRUE;
- t->checkboxMouseDownRow = rc.row;
- t->checkboxMouseDownColumn = rc.column;
- // TODO redraw the whole cell?
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- panic("error redrawing Table checkbox after mouse down");
- *lResult = 0;
- return TRUE;
-}
-
-HANDLER(checkboxMouseUpHandler)
-{
- struct rowcol rc;
- RECT r;
- POINT pt;
-
- if (!t->checkboxMouseDown)
- return FALSE;
- // the logic behind goto wrongUp is that the mouse must be released on the same checkbox
- rc = lParamToRowColumn(t, lParam);
- if (rc.row == -1 || rc.column == -1)
- goto wrongUp;
- if (rc.row != t->checkboxMouseDownRow || rc.column != t->checkboxMouseDownColumn)
- goto wrongUp;
- if (t->columnTypes[rc.column] != tableColumnCheckbox)
- goto wrongUp;
- if (!rowColumnToClientRect(t, rc, &r))
- goto wrongUp;
- toCheckboxRect(t, &r, 0);
- pt.x = GET_X_LPARAM(lParam);
- pt.y = GET_Y_LPARAM(lParam);
- if (PtInRect(&r, pt) == 0)
- goto wrongUp;
- notify(t, tableNotificationCellCheckboxToggled, rc.row, rc.column, 0);
- t->checkboxMouseDown = FALSE;
- // TODO redraw the whole cell?
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- panic("error redrawing Table checkbox after mouse up");
- // TODO really only the row? no way to specify column too?
- NotifyWinEvent(EVENT_OBJECT_STATECHANGE, t->hwnd, OBJID_CLIENT, rc.row);
- *lResult = 0;
- return TRUE;
-wrongUp:
- if (t->checkboxMouseDown) {
- rc.row = t->checkboxMouseDownRow;
- rc.column = t->checkboxMouseDownColumn;
- if (rowColumnToClientRect(t, rc, &r))
- // TODO only the checkbox rect?
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- panic("error redrawing Table checkbox rect for aborted mouse up event");
- }
- // if we landed on another checkbox, be sure to draw that one too
- if (t->checkboxMouseOverLast)
- redrawCheckboxRect(t, t->checkboxMouseOverLastPoint);
- t->checkboxMouseDown = FALSE;
- return FALSE; // TODO really?
-}
diff --git a/wintable/children.h b/wintable/children.h
deleted file mode 100644
index 6a3aff3..0000000
--- a/wintable/children.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 7 december 2014
-
-static const handlerfunc commandHandlers[] = {
- NULL,
-};
-
-static const handlerfunc notifyHandlers[] = {
- headerNotifyHandler,
- NULL,
-};
-
-HANDLER(childrenHandlers)
-{
- if (uMsg == WM_COMMAND)
- return runHandlers(commandHandlers, t, uMsg, wParam, lParam, lResult);
- if (uMsg == WM_NOTIFY)
- return runHandlers(notifyHandlers, t, uMsg, wParam, lParam, lResult);
- return FALSE;
-}
diff --git a/wintable/coord.h b/wintable/coord.h
deleted file mode 100644
index 52a70c9..0000000
--- a/wintable/coord.h
+++ /dev/null
@@ -1,164 +0,0 @@
-// 4 december 2014
-
-// TODO find a better place for these (metrics.h?)
-static LONG textHeight(struct table *t, HDC dc, BOOL select)
-{
- BOOL release;
- HFONT prevfont, newfont;
- TEXTMETRICW tm;
-
- release = FALSE;
- if (dc == NULL) {
- dc = GetDC(t->hwnd);
- if (dc == NULL)
- panic("error getting Table DC for rowHeight()");
- release = TRUE;
- }
- if (select)
- prevfont = selectFont(t, dc, &newfont);
- if (GetTextMetricsW(dc, &tm) == 0)
- panic("error getting text metrics for rowHeight()");
- if (select)
- deselectFont(dc, prevfont, newfont);
- if (release)
- if (ReleaseDC(t->hwnd, dc) == 0)
- panic("error releasing Table DC for rowHeight()");
- return tm.tmHeight;
-}
-
-#define tableImageWidth() GetSystemMetrics(SM_CXSMICON)
-#define tableImageHeight() GetSystemMetrics(SM_CYSMICON)
-
-// TODO omit column types that are not present?
-static LONG rowHeight(struct table *t, HDC dc, BOOL select)
-{
- LONG height;
- LONG tmHeight;
-
- height = tableImageHeight(); // start with this to avoid two function calls
- tmHeight = textHeight(t, dc, select);
- if (height < tmHeight)
- height = tmHeight;
- if (height < t->checkboxHeight)
- height = t->checkboxHeight;
- return height;
-}
-
-#define rowht(t) rowHeight(t, NULL, TRUE)
-
-struct rowcol {
- intptr_t row;
- intptr_t column;
-};
-
-static struct rowcol clientCoordToRowColumn(struct table *t, POINT pt)
-{
- RECT r;
- struct rowcol rc;
- intptr_t i;
-
- if (GetClientRect(t->hwnd, &r) == 0)
- panic("error getting Table client rect in clientCoordToRowColumn()");
- r.top += t->headerHeight;
- if (PtInRect(&r, pt) == 0)
- goto outside;
-
- // the row is easy
- pt.y -= t->headerHeight;
- rc.row = (pt.y / rowht(t)) + t->vscrollpos;
- if (rc.row >= t->count)
- goto outside;
-
- // the column... not so much
- // we scroll p.x, then subtract column widths until we cross the left edge of the control
- pt.x += t->hscrollpos;
- rc.column = 0;
- for (i = 0; i < t->nColumns; i++) {
- pt.x -= columnWidth(t, i);
- // use <, not <=, here:
- // assume r.left and t->hscrollpos == 0;
- // given the first column is 100 wide,
- // pt.x == 0 (first pixel of col 0) -> p.x - 100 == -100 < 0 -> break
- // pt.x == 99 (last pixel of col 0) -> p.x - 100 == -1 < 0 -> break
- // pt.x == 100 (first pixel of col 1) -> p.x - 100 == 0 >= 0 -> next column
- if (pt.x < r.left)
- break;
- rc.column++;
- }
- if (rc.column >= t->nColumns)
- goto outside;
-
- return rc;
-
-outside:
- rc.row = -1;
- rc.column = -1;
- return rc;
-}
-
-// same as client coordinates, but stored in a lParam (like the various mouse messages provide)
-static struct rowcol lParamToRowColumn(struct table *t, LPARAM lParam)
-{
- POINT pt;
-
- pt.x = GET_X_LPARAM(lParam);
- pt.y = GET_Y_LPARAM(lParam);
- return clientCoordToRowColumn(t, pt);
-}
-
-// returns TRUE if the row is visible (even partially visible) and thus has a rectangle in the client area; FALSE otherwise
-static BOOL rowColumnToClientRect(struct table *t, struct rowcol rc, RECT *r)
-{
- RECT client;
- RECT out; // don't change r if we return FALSE
- LONG height;
- intptr_t xpos;
- intptr_t i;
-
- if (rc.row < t->vscrollpos)
- return FALSE;
- rc.row -= t->vscrollpos; // align with client.top
-
- if (GetClientRect(t->hwnd, &client) == 0)
- panic("error getting Table client rect in rowColumnToClientRect()");
- client.top += t->headerHeight;
-
- height = rowht(t);
- out.top = client.top + (rc.row * height);
- if (out.top >= client.bottom) // >= because RECT.bottom is the first pixel outside the rectangle
- return FALSE;
- out.bottom = out.top + height;
-
- // and again the columns are the hard part
- // so we start with client.left - t->hscrollpos, then keep adding widths until we get to the column we want
- xpos = client.left - t->hscrollpos;
- for (i = 0; i < rc.column; i++)
- xpos += columnWidth(t, i);
- // did we stray too far to the right? if so it's not visible
- if (xpos >= client.right) // >= because RECT.right is the first pixel outside the rectangle
- return FALSE;
- out.left = xpos;
- out.right = xpos + columnWidth(t, rc.column);
- // and is this too far to the left?
- if (out.right < client.left) // < because RECT.left is the first pixel inside the rect
- return FALSE;
-
- *r = out;
- return TRUE;
-}
-
-// TODO idealCoordToRowColumn/rowColumnToIdealCoord?
-
-static void toCellContentRect(struct table *t, RECT *r, LRESULT xoff, intptr_t width, intptr_t height)
-{
- if (xoff == 0)
- xoff = SendMessageW(t->header, HDM_GETBITMAPMARGIN, 0, 0);
- r->left += xoff;
- if (width != 0)
- r->right = r->left + width;
- if (height != 0)
- // TODO vertical center
- r->bottom = r->top + height;
-}
-
-#define toCheckboxRect(t, r, xoff) toCellContentRect(t, r, xoff, t->checkboxWidth, t->checkboxHeight)
diff --git a/wintable/draw.h b/wintable/draw.h
deleted file mode 100644
index 3aeb300..0000000
--- a/wintable/draw.h
+++ /dev/null
@@ -1,215 +0,0 @@
-// 8 december 2014
-
-// TODO move to api.h? definitely move somewhere
-static WCHAR *getCellText(struct table *t, intptr_t row, intptr_t column)
-{
- return (WCHAR *) notify(t, tableNotificationGetCellData, row, column, 0);
-}
-static void returnCellData(struct table *t, intptr_t row, intptr_t column, void *what)
-{
- notify(t, tableNotificationFinishedWithCellData, row, column, (uintptr_t) what);
-}
-static int isCheckboxChecked(struct table *t, intptr_t row, intptr_t column)
-{
- return notify(t, tableNotificationGetCellData, row, column, 0) != 0;
-}
-
-struct drawCellParams {
- intptr_t row;
- intptr_t column;
- LONG x;
- LONG y;
- LONG width; // of column
- LONG height; // rowHeight()
- LRESULT xoff; // result of HDM_GETBITMAPMARGIN
-};
-
-static void drawTextCell(struct table *t, HDC dc, struct drawCellParams *p, RECT *r, int textColor)
-{
- WCHAR *text;
-
- toCellContentRect(t, r, p->xoff, 0, 0); // TODO get the text height
- if (SetTextColor(dc, GetSysColor(textColor)) == CLR_INVALID)
- panic("error setting Table cell text color");
- if (SetBkMode(dc, TRANSPARENT) == 0)
- panic("error setting transparent text drawing mode for Table cell");
- text = getCellText(t, p->row, p->column);
- if (DrawTextExW(dc, text, -1, r, DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE, NULL) == 0)
- panic("error drawing Table cell text");
- returnCellData(t, p->row, p->column, text);
-}
-
-static void drawImageCell(struct table *t, HDC dc, struct drawCellParams *p, RECT *r)
-{
- HBITMAP bitmap;
- BITMAP bi;
- HDC idc;
- HBITMAP previbitmap;
- BLENDFUNCTION bf;
-
- // only call tableImageWidth() and tableImageHeight() here in case it changes partway through
- // we can get the values back out with basic subtraction (r->right - r->left/r->bottom - r->top)
- toCellContentRect(t, r, p->xoff, tableImageWidth(), tableImageHeight());
-
- bitmap = (HBITMAP) notify(t, tableNotificationGetCellData, p->row, p->column, 0);
- ZeroMemory(&bi, sizeof (BITMAP));
- if (GetObject(bitmap, sizeof (BITMAP), &bi) == 0)
- panic("error getting Table cell image dimensions for drawing");
- // is it even possible to enforce the type of bitmap we need here based on the contents of the BITMAP (or even the DIBSECTION) structs?
-
- idc = CreateCompatibleDC(dc);
- if (idc == NULL)
- panic("error creating compatible DC for Table image cell drawing");
- previbitmap = SelectObject(idc, bitmap);
- if (previbitmap == NULL)
- panic("error selecting Table cell image into compatible DC for image drawing");
-
- ZeroMemory(&bf, sizeof (BLENDFUNCTION));
- bf.BlendOp = AC_SRC_OVER;
- bf.BlendFlags = 0;
- bf.SourceConstantAlpha = 255; // per-pixel alpha values
- bf.AlphaFormat = AC_SRC_ALPHA;
- if (AlphaBlend(dc, r->left, r->top, r->right - r->left, r->bottom - r->top,
- idc, 0, 0, bi.bmWidth, bi.bmHeight, bf) == FALSE)
- panic("error drawing image into Table cell");
-
- if (SelectObject(idc, previbitmap) != bitmap)
- panic("error deselecting Table cell image for drawing image");
- if (DeleteDC(idc) == 0)
- panic("error deleting Table compatible DC for image cell drawing");
-
- returnCellData(t, p->row, p->column, bitmap);
-}
-
-static void drawCheckboxCell(struct table *t, HDC dc, struct drawCellParams *p, RECT *r)
-{
- POINT pt;
- int cbState;
-
- toCheckboxRect(t, r, p->xoff);
- cbState = 0;
- if (isCheckboxChecked(t, p->row, p->column))
- cbState |= checkboxStateChecked;
- if (t->checkboxMouseDown)
- if (p->row == t->checkboxMouseDownRow && p->column == t->checkboxMouseDownColumn)
- cbState |= checkboxStatePushed;
- if (t->checkboxMouseOverLast) {
- pt.x = GET_X_LPARAM(t->checkboxMouseOverLastPoint);
- pt.y = GET_Y_LPARAM(t->checkboxMouseOverLastPoint);
- if (PtInRect(r, pt) != 0)
- cbState |= checkboxStateHot;
- }
- drawCheckbox(t, dc, r, cbState);
-}
-
-static void drawCell(struct table *t, HDC dc, struct drawCellParams *p)
-{
- RECT r;
- HBRUSH background;
- int textColor;
- RECT cellrect;
-
- // TODO verify these two
- background = (HBRUSH) (COLOR_WINDOW + 1);
- textColor = COLOR_WINDOWTEXT;
- if (t->selectedRow == p->row) {
- // 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;
- }
- // TODO disabled
- }
-
- r.left = p->x;
- r.right = p->x + p->width;
- r.top = p->y;
- r.bottom = p->y + p->height;
- if (FillRect(dc, &r, background) == 0)
- panic("error filling Table cell background");
- cellrect = r; // save for drawing the focus rect
-
- switch (t->columnTypes[p->column]) {
- case tableColumnText:
- drawTextCell(t, dc, p, &r, textColor);
- break;
- case tableColumnImage:
- drawImageCell(t, dc, p, &r);
- break;
- case tableColumnCheckbox:
- drawCheckboxCell(t, dc, p, &r);
- break;
- }
-
- // TODO in front of or behind the cell contents?
- if (t->selectedRow == p->row && t->selectedColumn == p->column)
- if (DrawFocusRect(dc, &cellrect) == 0)
- panic("error drawing focus rect on current Table cell");
-}
-
-// TODO use cliprect
-static void draw(struct table *t, HDC dc, RECT cliprect, RECT client)
-{
- intptr_t i, j;
- HFONT prevfont, newfont;
- struct drawCellParams p;
-
- prevfont = selectFont(t, dc, &newfont);
-
- client.top += t->headerHeight;
-
- ZeroMemory(&p, sizeof (struct drawCellParams));
- p.height = rowHeight(t, dc, FALSE);
- p.xoff = SendMessageW(t->header, HDM_GETBITMAPMARGIN, 0, 0);
-
- p.y = client.top;
- for (i = t->vscrollpos; i < t->count; i++) {
- p.row = i;
- p.x = client.left - t->hscrollpos;
- for (j = 0; j < t->nColumns; j++) {
- p.column = j;
- p.width = columnWidth(t, p.column);
- drawCell(t, dc, &p);
- p.x += p.width;
- }
- p.y += p.height;
- if (p.y >= client.bottom) // >= because RECT.bottom is the first pixel outside the rect
- break;
- }
-
- deselectFont(dc, prevfont, newfont);
-}
-
-HANDLER(drawHandlers)
-{
- HDC dc;
- PAINTSTRUCT ps;
- RECT client;
- RECT r;
-
- if (uMsg != WM_PAINT && uMsg != WM_PRINTCLIENT)
- return FALSE;
- if (GetClientRect(t->hwnd, &client) == 0)
- panic("error getting client rect for Table painting");
- if (uMsg == WM_PAINT) {
- dc = BeginPaint(t->hwnd, &ps);
- if (dc == NULL)
- panic("error beginning Table painting");
- r = ps.rcPaint;
- } else {
- dc = (HDC) wParam;
- r = client;
- }
- draw(t, dc, r, client);
- if (uMsg == WM_PAINT)
- EndPaint(t->hwnd, &ps);
- // this is correct for WM_PRINTCLIENT; see http://stackoverflow.com/a/27362258/3408572
- *lResult = 0;
- return TRUE;
-}
-
-// TODO redraw selected row on focus change
-// TODO here or in select.h?
diff --git a/wintable/events.h b/wintable/events.h
deleted file mode 100644
index fbd1522..0000000
--- a/wintable/events.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 5 december 2014
-
-// TODO handler functions don't work here because you can't have more than one for the mouse ones...
-
-static const handlerfunc keyDownHandlers[] = {
- keyDownSelectHandler,
- NULL,
-};
-
-static const handlerfunc keyUpHandlers[] = {
- NULL,
-};
-
-static const handlerfunc charHandlers[] = {
- NULL,
-};
-
-static const handlerfunc mouseMoveHandlers[] = {
- checkboxMouseMoveHandler,
- NULL,
-};
-
-static const handlerfunc mouseLeaveHandlers[] = {
- checkboxMouseLeaveHandler,
- NULL,
-};
-
-static const handlerfunc lbuttonDownHandlers[] = {
- mouseDownSelectHandler,
- NULL,
-};
-
-static const handlerfunc lbuttonUpHandlers[] = {
- checkboxMouseUpHandler,
- NULL,
-};
-
-// TODO remove or something? depends on if we implement combobox and how
-static const handlerfunc mouseWheelHandlers[] = {
- NULL,
-};
-
-// TODO WM_MOUSEHOVER, other mouse buttons
-
-HANDLER(eventHandlers)
-{
- switch (uMsg) {
-#define eventHandler(msg, array) \
- case msg: \
- return runHandlers(array, t, uMsg, wParam, lParam, lResult);
- eventHandler(WM_KEYDOWN, keyDownHandlers)
- eventHandler(WM_KEYUP, keyUpHandlers)
- eventHandler(WM_CHAR, charHandlers)
- eventHandler(WM_MOUSEMOVE, mouseMoveHandlers)
- eventHandler(WM_MOUSELEAVE, mouseLeaveHandlers)
- eventHandler(WM_LBUTTONDOWN, lbuttonDownHandlers)
- eventHandler(WM_LBUTTONUP, lbuttonUpHandlers)
- eventHandler(WM_MOUSEWHEEL, mouseWheelHandlers)
-#undef eventHandler
- }
- return FALSE;
-}
diff --git a/wintable/header.h b/wintable/header.h
deleted file mode 100644
index b87f7c6..0000000
--- a/wintable/header.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// 7 december 2014
-
-// TODO verify header events (double-clicking on a divider, for example)
-
-static void makeHeader(struct table *t, HINSTANCE hInstance)
-{
- t->header = CreateWindowExW(0,
- WC_HEADERW, L"",
- // don't set WS_VISIBLE; according to MSDN we create the header hidden as part of setting the initial position (http://msdn.microsoft.com/en-us/library/windows/desktop/ff485935%28v=vs.85%29.aspx)
- // TODO WS_BORDER?
- // TODO is HDS_HOTTRACK needed?
- WS_CHILD | HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK,
- 0, 0, 0, 0, // no initial size
- t->hwnd, (HMENU) 100, hInstance, NULL);
- if (t->header == NULL)
- panic("error creating Table header");
-}
-
-static void destroyHeader(struct table *t)
-{
- if (DestroyWindow(t->header) == 0)
- panic("error destroying Table header");
-}
-
-// to avoid weird bugs, the only functions allowed to call this one are the horizontal scroll functions
-// when we need to reposition the header in a situation other than a user-initiated scroll, we use a dummy scroll (hscrollby(t, 0))
-// see update() in update.h
-static void repositionHeader(struct table *t)
-{
- RECT r;
- WINDOWPOS wp;
- HDLAYOUT l;
-
- if (GetClientRect(t->hwnd, &r) == 0)
- panic("error getting client rect for Table header repositioning");
- // we fake horizontal scrolling here by extending the client rect to the left by the scroll position
- r.left -= t->hscrollpos;
- l.prc = &r;
- l.pwpos = &wp;
- if (SendMessageW(t->header, HDM_LAYOUT, 0, (LPARAM) (&l)) == FALSE)
- panic("error getting new Table header position");
- if (SetWindowPos(t->header, wp.hwndInsertAfter,
- wp.x, wp.y, wp.cx, wp.cy,
- // see above on showing the header here instead of in the CreateWindowExW() call
- wp.flags | SWP_SHOWWINDOW) == 0)
- panic("error repositioning Table header");
- t->headerHeight = wp.cy;
-}
-
-static void headerAddColumn(struct table *t, WCHAR *name)
-{
- HDITEMW item;
-
- ZeroMemory(&item, sizeof (HDITEMW));
- item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT;
- item.cxy = 200; // TODO
- item.pszText = name;
- item.fmt = HDF_LEFT | HDF_STRING;
- // TODO replace 100 with (t->nColumns - 1)
- if (SendMessage(t->header, HDM_INSERTITEM, (WPARAM) (100), (LPARAM) (&item)) == (LRESULT) (-1))
- panic("error adding column to Table header");
-}
-
-// TODO is this triggered if we programmatically move headers (for autosizing)?
-HANDLER(headerNotifyHandler)
-{
- NMHDR *nmhdr = (NMHDR *) lParam;
-
- if (nmhdr->hwndFrom != t->header)
- return FALSE;
- if (nmhdr->code != HDN_ITEMCHANGED)
- return FALSE;
- update(t, TRUE);
- // TODO make more intelligent
- // to do this, we have to redraw the column to the left of the divider that was dragged and scroll everything to the right normally (leaving the hole that was scrolled invalidated as well)
- // of course, this implies that dragging a divider only resizes the column of which it is the right side of and moves all others
- InvalidateRect(t->hwnd, NULL, TRUE);
- *lResult = 0;
- return TRUE;
-}
diff --git a/wintable/hscroll.h b/wintable/hscroll.h
deleted file mode 100644
index 1560490..0000000
--- a/wintable/hscroll.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 9 december 2014
-
-// forward declaration needed here
-static void repositionHeader(struct table *);
-
-static struct scrollParams hscrollParams(struct table *t)
-{
- struct scrollParams p;
-
- ZeroMemory(&p, sizeof (struct scrollParams));
- p.pos = &(t->hscrollpos);
- p.pagesize = t->hpagesize;
- p.length = t->width;
- p.scale = 1;
- p.post = repositionHeader;
- p.wheelCarry = &(t->hwheelCarry);
- return p;
-}
-
-static void hscrollto(struct table *t, intptr_t pos)
-{
- struct scrollParams p;
-
- p = hscrollParams(t);
- scrollto(t, SB_HORZ, &p, pos);
-}
-
-static void hscrollby(struct table *t, intptr_t delta)
-{
- struct scrollParams p;
-
- p = hscrollParams(t);
- scrollby(t, SB_HORZ, &p, delta);
-}
-
-static void hscroll(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- struct scrollParams p;
-
- p = hscrollParams(t);
- scroll(t, SB_HORZ, &p, wParam, lParam);
-}
-
-// TODO find out if we can indicriminately check for WM_WHEELHSCROLL
-HANDLER(hscrollHandler)
-{
- if (uMsg != WM_HSCROLL)
- return FALSE;
- hscroll(t, wParam, lParam);
- *lResult = 0;
- return TRUE;
-}
diff --git a/wintable/includethis.h b/wintable/includethis.h
deleted file mode 100644
index 422b101..0000000
--- a/wintable/includethis.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// 17 february 2015
-
-#ifndef __GO_UI_WINTABLE_INCLUDETHIS_H__
-#define __GO_UI_WINTABLE_INCLUDETHIS_H__
-
-#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)
-// each of these returns nothing unless otherwise indicated
-enum {
- // wParam - one of the type constants
- // lParam - column name as a Unicode string
- tableAddColumn = WM_USER + 20,
- // wParam - 0
- // lParam - pointer to intptr_t containing new count
- tableSetRowCount,
- // wParam - pointer to intptr_t where selected row will be stored
- // lParam - pointer to intptr_t where selected column will be stored
- // both will be -1 for no selection
- // if either is NULL, that value is not written
- tableGetSelection,
- // wParam - pointer to intptr_t containing selected row
- // lParam - pointer to intptr_t containing selected column
- // if lParam is NULL, do not change selected column (selects column 0 if nothing previously selected; TODO explicitly document this?)
- // TODO allow wParam to be NULL too; should both being NULL select nothing or keep the current selection?
- // this WILL result in a selection changed notification (TODO work into the package ui Table)
- tableSetSelection,
-};
-
-enum {
- tableColumnText,
- tableColumnImage,
- tableColumnCheckbox,
- nTableColumnTypes,
-};
-
-// notification codes
-// note that these are positive; see http://blogs.msdn.com/b/oldnewthing/archive/2009/08/21/9877791.aspx
-// each of these is of type tableNM
-// all fields except data will always be set
-enum {
- // data parameter is always 0
- // for tableColumnText return should be WCHAR *
- // for tableColumnImage return should be HBITMAP
- // for tableColumnCheckbox return is nonzero for checked, zero for unchecked
- tableNotificationGetCellData,
- // data parameter is pointer, same as tableNotificationGetCellData
- // not sent for checkboxes
- // no return
- tableNotificationFinishedWithCellData,
- // data is zero
- // no return
- tableNotificationCellCheckboxToggled,
- // sent even on deselection (in that case, row == -1 and column == -1)
- // data is zero
- // no return
- tableNotificationSelectionChanged,
-};
-
-typedef struct tableNM tableNM;
-
-struct tableNM {
- NMHDR nmhdr;
- intptr_t row;
- intptr_t column;
- int columnType;
- uintptr_t data;
-};
-
-// TODO have hInstance passed in
-extern void initTable(void (*panicfunc)(const char *msg, DWORD lastError), BOOL (*WINAPI tme)(LPTRACKMOUSEEVENT));
-
-#endif
diff --git a/wintable/links b/wintable/links
deleted file mode 100644
index f0c9523..0000000
--- a/wintable/links
+++ /dev/null
@@ -1,3 +0,0 @@
-default list view message processing
- http://msdn.microsoft.com/en-us/library/windows/desktop/bb774734%28v=vs.85%29.aspx
- includes information on handling the edit control and event messages
diff --git a/wintable/main.h b/wintable/main.h
deleted file mode 100644
index fe49d77..0000000
--- a/wintable/main.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// 7 january 2015
-
-// TODO remove
-#include <stdio.h>
-
-// TODO
-// - should tablePanic be CALLBACK or some other equivalent macro? and definitely export initTable somehow, but which alias macro to use?
-// - make panic messages grammatically correct ("Table error: adding...")
-// - make access to column widths consistent; see whether HDITEMW.cxy == (ITEMRECT.right - ITEMRECT.left)
-// - make sure all uses of t->headerHeight are ADDED to RECT.top
-// - WM_THEMECHANGED, etc.
-// - see if vertical centering is really what we want or if we just want to offset by a few pixels or so
-// - going right from column 0 to column 2 with the right arrow key deselects
-// - make sure all error messages involving InvalidateRect() are consistent with regards to "redrawing" and "queueing for redraw"
-// - collect all resize-related tasks in a single function (so things like adding columns will refresh everything, not just horizontal scrolls; also would fix initial coordinates)
-// - checkbox columns don't clip to the column width
-// - send standard notification codes
-// - seriously figure out how we're going to update everything about the table in one place
-// - redraw on focus change
-// - draw themed WS_EX_CLIENTEDGE (and WS_EX_WINDOWEDGE?)
-// - in-place tooltips for text columns
-// - checkboxes: use capture instead of manual tracking logic? http://blogs.msdn.com/b/oldnewthing/archive/2015/02/25/10595729.aspx
-
-#include "includethis.h"
-
-static void (*tablePanic)(const char *, DWORD) = NULL;
-#define panic(...) (*tablePanic)(__VA_ARGS__, GetLastError())
-#define abort $$$$ // prevent accidental use of abort()
-
-static BOOL (*WINAPI tableTrackMouseEvent)(LPTRACKMOUSEEVENT);
-
-// forward declaration
-struct tableAcc;
-
-struct table {
- HWND hwnd;
- HWND header;
- HFONT font;
- intptr_t nColumns;
- int *columnTypes;
- intptr_t width;
- intptr_t headerHeight;
- intptr_t hscrollpos; // in logical units
- intptr_t hpagesize; // in logical units
- intptr_t count;
- intptr_t vscrollpos; // in rows
- intptr_t vpagesize; // in rows
- int hwheelCarry;
- int vwheelCarry;
- intptr_t selectedRow;
- intptr_t selectedColumn;
- HTHEME theme;
- int checkboxWidth;
- int checkboxHeight;
- BOOL checkboxMouseOverLast;
- LPARAM checkboxMouseOverLastPoint;
- BOOL checkboxMouseDown;
- intptr_t checkboxMouseDownRow;
- intptr_t checkboxMouseDownColumn;
- struct tableAcc *firstAcc;
-};
-
-// forward declaration (TODO needed?)
-static LRESULT notify(struct table *, UINT, intptr_t, intptr_t, uintptr_t);
-
-// necessary forward declarations
-static void update(struct table *, BOOL);
-static void updateAll(struct table *);
-
-#include "util.h"
-#include "coord.h"
-#include "scroll.h"
-#include "hscroll.h"
-#include "vscroll.h"
-#include "select.h"
-#include "checkboxes.h"
-#include "events.h"
-#include "header.h"
-#include "children.h"
-#include "resize.h"
-#include "draw.h"
-#include "api.h"
-#include "accessibility.h"
-#include "update.h"
-
-static const handlerfunc handlers[] = {
- eventHandlers,
- childrenHandlers,
- resizeHandler,
- drawHandlers,
- apiHandlers,
- hscrollHandler,
- vscrollHandler,
- accessibilityHandler,
- NULL,
-};
-
-static LRESULT CALLBACK tableWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- struct table *t;
- LRESULT lResult;
-
- 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)
- // we use WM_CREATE because we have to use WM_DESTROY to destroy the header; we can't do it in WM_NCDESTROY because Windows will have destroyed it for us by then, and let's match message pairs to be safe
- if (uMsg == WM_CREATE) {
- CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
-
- t = (struct table *) tableAlloc(sizeof (struct table), "error allocating internal Table data structure");
- t->hwnd = hwnd;
- makeHeader(t, cs->hInstance);
- t->selectedRow = -1;
- t->selectedColumn = -1;
- loadCheckboxThemeData(t);
- SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) t);
- }
- // even if we did the above, fall through
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- if (uMsg == WM_DESTROY) {
-printf("destroy\n");
- // TODO free appropriate (after figuring this part out) components of t
- invalidateTableAccs(t);
- freeCheckboxThemeData(t);
- destroyHeader(t);
- tableFree(t, "error allocating internal Table data structure");
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- if (runHandlers(handlers, t, uMsg, wParam, lParam, &lResult))
- return lResult;
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-}
-
-static void deftablePanic(const char *msg, DWORD lastError)
-{
- fprintf(stderr, "Table error: %s (last error %I32u)\n", msg, lastError);
- fprintf(stderr, "This is the default Table error handler function; programs that use Table should provide their own instead.\nThe program will now break into the debugger.\n");
- DebugBreak();
-}
-
-// TODO have hInstance passed in
-void initTable(void (*panicfunc)(const char *msg, DWORD lastError), BOOL (*WINAPI tme)(LPTRACKMOUSEEVENT))
-{
- WNDCLASSW wc;
-
- tablePanic = panicfunc;
- if (tablePanic == NULL)
- tablePanic = deftablePanic;
- if (tme == NULL)
- // TODO errorless version
- panic("must provide a TrackMouseEvent() to initTable()");
- tableTrackMouseEvent = tme;
- 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)
- panic("error registering Table window class");
-}
diff --git a/wintable/resize.h b/wintable/resize.h
deleted file mode 100644
index 7805bd9..0000000
--- a/wintable/resize.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// 7 december 2014
-
-// TODO why doesn't this trigger on first show?
-// TODO see if there's anything not metaphor related in the last bits of the scrollbar series
-// TODO rename this to boot
-// TODO merge with update.h?
-
-HANDLER(resizeHandler)
-{
- WINDOWPOS *wp;
-
- if (uMsg != WM_WINDOWPOSCHANGED)
- return FALSE;
- wp = (WINDOWPOS *) lParam;
- if ((wp->flags & SWP_NOSIZE) != 0)
- return FALSE;
- // TODO redraw everything?
- update(t, TRUE);
- *lResult = 0;
- return TRUE;
-}
diff --git a/wintable/scroll.h b/wintable/scroll.h
deleted file mode 100644
index ba5a9f8..0000000
--- a/wintable/scroll.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// 9 december 2014
-
-struct scrollParams {
- intptr_t *pos;
- intptr_t pagesize;
- intptr_t length;
- intptr_t scale;
- void (*post)(struct table *);
- int *wheelCarry;
-};
-
-static void scrollto(struct table *t, int which, struct scrollParams *p, intptr_t pos)
-{
- RECT scrollArea;
- SCROLLINFO si;
- intptr_t xamount, yamount;
-
- if (pos < 0)
- pos = 0;
- if (pos > p->length - p->pagesize)
- pos = p->length - p->pagesize;
- // TODO this shouldn't have been necessary but alas
- // TODO the logic is really intended for the whole y origin thing in the scrollbar series; fix that
- if (pos < 0)
- pos = 0;
-
- // we don't want to scroll the header
- if (GetClientRect(t->hwnd, &scrollArea) == 0)
- panic("error getting Table client rect for scrollto()");
- scrollArea.top += t->headerHeight;
-
- // negative because ScrollWindowEx() is "backwards"
- xamount = -(pos - *(p->pos)) * p->scale;
- yamount = 0;
- if (which == SB_VERT) {
- yamount = xamount;
- xamount = 0;
- }
-
- if (ScrollWindowEx(t->hwnd, xamount, yamount,
- &scrollArea, &scrollArea, NULL, NULL,
- SW_ERASE | SW_INVALIDATE) == ERROR)
-;// TODO failure case ignored for now; see https://bugs.winehq.org/show_bug.cgi?id=37706
-// panic("error scrolling Table");
- // TODO call UpdateWindow()?
-
- *(p->pos) = pos;
-
- // now commit our new scrollbar setup...
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
- si.nPage = p->pagesize;
- si.nMin = 0;
- si.nMax = p->length - 1; // endpoint inclusive
- si.nPos = *(p->pos);
- SetScrollInfo(t->hwnd, which, &si, TRUE);
-
- if (p->post != NULL)
- (*(p->post))(t);
-
- // EVENT_OBJECT_CONTENTSCROLLED is Vista and up only
- // TODO send state changes for all affected rows/cells?
-}
-
-static void scrollby(struct table *t, int which, struct scrollParams *p, intptr_t delta)
-{
- scrollto(t, which, p, *(p->pos) + delta);
-}
-
-static void scroll(struct table *t, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
-{
- intptr_t pos;
- SCROLLINFO si;
-
- pos = *(p->pos);
- switch (LOWORD(wParam)) {
- case SB_LEFT: // also SB_TOP
- pos = 0;
- break;
- case SB_RIGHT: // also SB_BOTTOM
- pos = p->length - p->pagesize;
- break;
- case SB_LINELEFT: // also SB_LINEUP
- pos--;
- break;
- case SB_LINERIGHT: // also SB_LINEDOWN
- pos++;
- break;
- case SB_PAGELEFT: // also SB_PAGEUP
- pos -= p->pagesize;
- break;
- case SB_PAGERIGHT: // also SB_PAGEDOWN
- pos += p->pagesize;
- break;
- case SB_THUMBPOSITION:
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS;
- if (GetScrollInfo(t->hwnd, which, &si) == 0)
- panic("error getting thumb position for scroll() in Table");
- pos = si.nPos;
- break;
- case SB_THUMBTRACK:
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_TRACKPOS;
- if (GetScrollInfo(t->hwnd, which, &si) == 0)
- panic("error getting thumb track position for scroll() in Table");
- pos = si.nTrackPos;
- break;
- }
- scrollto(t, which, p, pos);
-}
-
-static void wheelscroll(struct table *t, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
-{
- int delta;
- int lines;
- UINT scrollAmount;
-
- delta = GET_WHEEL_DELTA_WPARAM(wParam);
- // TODO make a note of what the appropriate hscroll constant is
- if (SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &scrollAmount, 0) == 0)
- // TODO use scrollAmount == 3 instead?
- panic("error getting wheel scroll amount in wheelscroll()");
- if (scrollAmount == WHEEL_PAGESCROLL)
- scrollAmount = p->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 += *(p->wheelCarry);
- lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
- *(p->wheelCarry) = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
- scrollby(t, which, p, -lines);
-}
diff --git a/wintable/scrollbarseries b/wintable/scrollbarseries
deleted file mode 100644
index 818b6a8..0000000
--- a/wintable/scrollbarseries
+++ /dev/null
@@ -1,24 +0,0 @@
-
- http://blogs.msdn.com/b/oldnewthing/archive/2003/07/23/54576.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/07/25/54582.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/07/29/54591.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/07/30/54600.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/07/31/54601.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/05/54602.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/05/54610.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/07/54615.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/07/54617.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/11/54624.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/11/54629.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/13/54639.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/15/54647.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/08/18/54668.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/09/09/54826.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/09/11/54885.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/09/13/54917.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/09/15/54925.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/09/17/54944.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/09/17/54945.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/09/17/54946.aspx
- http://blogs.msdn.com/b/oldnewthing/archive/2003/10/16/55344.aspx
- not really part of, so to speak, but still http://blogs.msdn.com/b/oldnewthing/archive/2004/05/10/129068.aspx
diff --git a/wintable/select.h b/wintable/select.h
deleted file mode 100644
index 6ece240..0000000
--- a/wintable/select.h
+++ /dev/null
@@ -1,269 +0,0 @@
-// 13 december 2014
-
-// damn winsock
-static void doselect(struct table *t, intptr_t row, intptr_t column)
-{
- RECT r, client;
- intptr_t oldrow;
- LONG width, height;
- struct rowcol rc;
- BOOL dovscroll;
- intptr_t i;
- intptr_t xpos;
- LONG clientWidth;
-
- // check existing selection to see if it's valid
- if (t->selectedRow == -1 && t->selectedColumn != -1)
- panic("sanity check failure: old Table selection invalid (row == -1, column != -1)");
- if (t->selectedRow != -1 && t->selectedColumn == -1)
- panic("sanity check failure: old Table selection invalid (row != -1, column == -1)");
- if (t->selectedRow >= t->count)
- panic("sanity check failure: old Table selection invalid (row out of range)");
- if (t->selectedColumn >= t->nColumns)
- panic("sanity check failure: old Table selection invalid (column out of range)");
-
- oldrow = t->selectedRow;
- t->selectedRow = row;
- t->selectedColumn = column;
-
- // check new selection to see if it's valid
- if (t->selectedRow == -1 && t->selectedColumn != -1)
- panic("sanity check failure: new Table selection invalid (row == -1, column != -1)");
- if (t->selectedRow != -1 && t->selectedColumn == -1)
- panic("sanity check failure: new Table selection invalid (row != -1, column == -1)");
- if (t->selectedRow >= t->count)
- panic("sanity check failure: new Table selection invalid (row out of range)");
- if (t->selectedColumn >= t->nColumns)
- panic("sanity check failure: new Table selection invalid (column out of range)");
-
- // do this even if we don't scroll before; noScroll depends on it
- if (GetClientRect(t->hwnd, &client) == 0)
- panic("error getting Table client rect in doselect()");
- client.top += t->headerHeight;
- height = rowht(t);
-
- // only scroll if we selected something
- if (t->selectedRow == -1 || t->selectedColumn == -1)
- goto noScroll;
-
- // first vertically scroll to the new row to make it fully visible (or as visible as possible)
- if (t->selectedRow < t->vscrollpos)
- vscrollto(t, t->selectedRow);
- else {
- rc.row = t->selectedRow;
- rc.column = t->selectedColumn;
- // first assume entirely outside the client area
- dovscroll = TRUE;
- if (rowColumnToClientRect(t, rc, &r))
- // partially outside the client area?
- if (r.bottom <= client.bottom) // <= here since we are comparing bottoms (which are the first pixels outside the rectangle)
- dovscroll = FALSE;
- if (dovscroll)
- vscrollto(t, t->selectedRow - t->vpagesize + 1); // + 1 because apparently just t->selectedRow - t->vpagesize results in no scrolling (t->selectedRow - t->vpagesize == t->vscrollpos)...
- }
-
- // now see if the cell we want is to the left of offscreen, in which case scroll to its x-position
- xpos = 0;
- for (i = 0; i < t->selectedColumn; i++)
- xpos += columnWidth(t, i);
- if (xpos < t->hscrollpos)
- hscrollto(t, xpos);
- else {
- // if the full cell is not visible, scroll to the right just enough to make it fully visible (or as visible as possible)
- width = columnWidth(t, t->selectedColumn);
- clientWidth = client.right - client.left;
- if (xpos + width > t->hscrollpos + clientWidth) // > because both sides deal with the first pixel outside
- // if the column is too wide, then just make it occupy the whole visible area (left-aligned)
- if (width > clientWidth) // TODO >= ?
- hscrollto(t, xpos);
- else
- // TODO don't use t->hpagesize here? depends if other code uses it
- hscrollto(t, (xpos + width) - t->hpagesize);
- }
-
-noScroll:
- // now redraw the old and new /rows/
- // we do this after scrolling so the rectangles to be invalidated make sense
- r.left = client.left;
- r.right = client.right;
- if (oldrow != -1 && oldrow >= t->vscrollpos) {
- r.top = client.top + ((oldrow - t->vscrollpos) * height);
- r.bottom = r.top + height;
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- panic("error queueing previously selected row for redraw in doselect()");
- }
- // t->selectedRow must be visible by this point; we scrolled to it
- if (t->selectedRow != -1 && t->selectedRow != oldrow) {
- r.top = client.top + ((t->selectedRow - t->vscrollpos) * height);
- r.bottom = r.top + height;
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- panic("error queueing newly selected row for redraw in doselect()");
- }
-
- // TODO what about deselect/defocus?
- // TODO notify on the old row too?
- NotifyWinEvent(EVENT_OBJECT_SELECTION, t->hwnd, OBJID_CLIENT, t->selectedRow);
- // TODO send EVENT_OBJECT_STATECHANGED too?
- // TODO send EVENT_OBJECT_FOCUS
-
- // TODO before or after NotifyWinEvent()? (see what other things I'm doing)
- notify(t, tableNotificationSelectionChanged, t->selectedRow, t->selectedColumn, 0);
-}
-
-// TODO make this needless
-HANDLER(checkboxMouseDownHandler);
-
-// TODO which WM_xBUTTONDOWNs?
-HANDLER(mouseDownSelectHandler)
-{
- struct rowcol rc;
-
- // TODO separate this from here
- // TODO other mouse buttons?
- // don't check SetFocus()'s error (http://stackoverflow.com/questions/24073695/winapi-can-setfocus-return-null-without-an-error-because-thats-what-im-see)
- // TODO NotifyWinEvent() here?
- SetFocus(t->hwnd);
- rc = lParamToRowColumn(t, lParam);
- // don't check if lParamToRowColumn() returned row -1 or column -1; we want deselection behavior
- doselect(t, rc.row, rc.column);
- // TODO separate this from here
- checkboxMouseDownHandler(t, uMsg, wParam, lParam, lResult);
- *lResult = 0;
- return TRUE;
-}
-
-/*
-the routine below is intended to simulate the comctl32.dll listview keyboard navigation rules, at least as far as vertical navigation is concerned.
-horizontal scrolling is different because unlike the comctl32 listview, we say that a single column in each row has the keyboard focus, so left and right navigate between columns here, instead of scrolling left/right by pixels.
- TODO provide an override for scrolling by pixels?
- TODO any other keyboard shortcuts?
- TODO browser keys
- TODO media navigation keys
- TODO XBUTTON1/2?
- TODO clear keys?
-
-keyboard selection behaviors of the windows 7 listview:
-with 100 items (0-99), the window currently shows items 30 through 47 as well as having item 48 partially visible
-- item 30:
- - page up -> item 13
- - page down -> item 47
-- item 31:
- - page up -> item 30
- - page down -> item 47
-- item 42:
- - page up -> item 30
- - page down -> item 47
-- item 46:
- - page up -> item 30
- - page down -> item 47
-- item 47:
- - page up: -> item 30
- - page down: -> item 64
-
-when nothing is selected:
-- down selects item 0 regardless of scroll
-- up selects nothing regardless of scroll
-- page down selects the last fully visible item depending on scroll
- - so with the above configuration:
- - item 0 -> item 17
- - item 30 -> item 47
- - item 80 -> item 97
-- page up selects item 0 regardless of scroll
-- home selects item 0 regardless of scroll
-- end selects the last item regardless of scroll
-
-for left and right we will simulate up and down, respectively (so right selects row 0 column 0); remember that you can't have either row or column be -1 but not both
-
-TODO what happens if page up and page down are pressed with an item selected and the scroll in a different position?
-*/
-
-HANDLER(keyDownSelectHandler)
-{
- intptr_t row;
- intptr_t column;
-
- if (t->count == 0 || t->nColumns == 0) // no items to select
- return FALSE;
- row = t->selectedRow;
- column = t->selectedColumn;
- switch (wParam) {
- case VK_UP:
- if (row == -1)
- return FALSE;
- row--;
- if (row < 0)
- row = 0;
- break;
- case VK_DOWN:
- if (row == -1) {
- row = 0;
- column = 0;
- } else {
- row++;
- if (row >= t->count)
- row = t->count - 1;
- }
- break;
- case VK_LEFT:
- if (column == -1)
- return FALSE;
- column--;
- if (column < 0)
- column = 0;
- break;
- case VK_RIGHT:
- if (column == -1) {
- row = 0;
- column = 0;
- } else {
- column++;
- if (column >= t->nColumns)
- column = t->nColumns - 1;
- }
- break;
- case VK_HOME:
- row = 0;
- if (column == -1)
- column = 0;
- break;
- case VK_END:
- row = t->count - 1;
- if (column == -1)
- column = 0;
- break;
- case VK_PRIOR:
- if (row == -1) {
- row = 0;
- column = 0;
- } else {
- row = t->vscrollpos;
- if (row == t->selectedRow)
- // TODO investigate why the - 1 is needed here and below
- // TODO if this is a misunderstanding of how t->vpagesize works, figure out what happens if there is no partially visible row, and what is supposed to happen
- row -= t->vpagesize - 1;
- if (row < 0)
- row = 0;
- }
- break;
- case VK_NEXT:
- if (row == -1) {
- row = t->vscrollpos + t->vpagesize - 1;
- // TODO ensusre this is the case with the real list view
- if (row >= t->count)
- row = t->count - 1;
- column = 0;
- } else {
- row = t->vscrollpos + t->vpagesize - 1;
- if (row == t->selectedRow)
- row += t->vpagesize - 1;
- if (row >= t->count)
- row = t->count - 1;
- }
- break;
- default:
- return FALSE;
- }
- doselect(t, row, column);
- *lResult = 0;
- return TRUE;
-}
diff --git a/wintable/test.c b/wintable/test.c
deleted file mode 100644
index 942860c..0000000
--- a/wintable/test.c
+++ /dev/null
@@ -1,198 +0,0 @@
-// 19 october 2014
-#include "../wininclude_windows.h"
-
-// #qo LIBS: user32 kernel32 gdi32 comctl32 uxtheme ole32 oleaut32 oleacc uuid msimg32
-
-#include "main.h"
-
-HWND tablehwnd = NULL;
-BOOL msgfont = FALSE;
-
-HBITMAP mkbitmap(void);
-
-BOOL mainwinCreate(HWND hwnd, LPCREATESTRUCT lpcs)
-{
- intptr_t c;
- intptr_t row, col;
-
- tablehwnd = CreateWindowExW(0,
- tableWindowClass, L"Main Window",
- WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 400, 400,
- hwnd, NULL, lpcs->hInstance, NULL);
- if (tablehwnd == NULL)
- panic("(test program) error creating Table");
- SendMessageW(tablehwnd, tableAddColumn, tableColumnText, (LPARAM) L"Column");
- SendMessageW(tablehwnd, tableAddColumn, tableColumnImage, (LPARAM) L"Column 2");
- SendMessageW(tablehwnd, tableAddColumn, tableColumnCheckbox, (LPARAM) L"Column 3");
- if (msgfont) {
- NONCLIENTMETRICSW ncm;
- HFONT font;
-
- ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW));
- ncm.cbSize = sizeof (NONCLIENTMETRICSW);
- if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0)
- panic("(test program) error getting non-client metrics");
- font = CreateFontIndirectW(&ncm.lfMessageFont);
- if (font == NULL)
- panic("(test program) error creating lfMessageFont HFONT");
- SendMessageW(tablehwnd, WM_SETFONT, (WPARAM) font, TRUE);
- }
- c = 100;
- SendMessageW(tablehwnd, tableSetRowCount, 0, (LPARAM) (&c));
- row = 2;
- col = 1;
- SendMessageW(tablehwnd, tableSetSelection, (WPARAM) (&row), (LPARAM) (&col));
- SetFocus(tablehwnd);
- return TRUE;
-}
-
-void mainwinDestroy(HWND hwnd)
-{
- DestroyWindow(tablehwnd);
- PostQuitMessage(0);
-}
-
-void mainwinResize(HWND hwnd, UINT state, int cx, int cy)
-{
- if (tablehwnd != NULL)
- MoveWindow(tablehwnd, 0, 0, cx, cy, TRUE);
-}
-
-BOOL checkboxstates[100];
-
-LRESULT CALLBACK mainwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- NMHDR *nmhdr = (NMHDR *) lParam;
- tableNM *nm = (tableNM *) lParam;
- WCHAR *text;
- int n;
-
- if (uMsg == WM_CREATE)
- ZeroMemory(checkboxstates, 100 * sizeof (BOOL));
- switch (uMsg) {
- HANDLE_MSG(hwnd, WM_CREATE, mainwinCreate);
- HANDLE_MSG(hwnd, WM_SIZE, mainwinResize);
- HANDLE_MSG(hwnd, WM_DESTROY, mainwinDestroy);
- case WM_NOTIFY:
- if (nmhdr->hwndFrom != tablehwnd)
- break;
- switch (nmhdr->code) {
- case tableNotificationGetCellData:
- switch (nm->columnType) {
- case tableColumnText:
- n = _scwprintf(L"mainwin (%d,%d)", nm->row, nm->column);
- text = (WCHAR *) malloc((n + 1) * sizeof (WCHAR));
- if (text == NULL)
- panic("(table program) error allocating string");
- _swprintf(text, L"mainwin (%d,%d)", nm->row, nm->column);
- return (LRESULT) text;
- case tableColumnImage:
- return (LRESULT) mkbitmap();
- case tableColumnCheckbox:
- return (LRESULT) (checkboxstates[nm->row]);
- }
- panic("(test program) unreachable");
- case tableNotificationFinishedWithCellData:
- switch (nm->columnType) {
- case tableColumnText:
- free((void *) (nm->data));
- break;
- case tableColumnImage:
- if (DeleteObject((HBITMAP) (nm->data)) == 0)
- panic("(test program) error deleting cell image");
- break;
- }
- return 0;
- case tableNotificationCellCheckboxToggled:
- checkboxstates[nm->row] = !checkboxstates[nm->row];
- return 0;
- }
- break;
- }
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-}
-
-int main(int argc, char *argv[])
-{
- HWND mainwin;
- MSG msg;
- INITCOMMONCONTROLSEX icc;
- WNDCLASSW wc;
-
- if (argc != 1)
- msgfont = TRUE;
- ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
- icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
- icc.dwICC = ICC_LISTVIEW_CLASSES;
- if (InitCommonControlsEx(&icc) == 0)
- panic("(test program) error initializing comctl32.dll");
- initTable(NULL, _TrackMouseEvent);
- ZeroMemory(&wc, sizeof (WNDCLASSW));
- wc.lpszClassName = L"mainwin";
- wc.lpfnWndProc = mainwndproc;
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
- wc.hInstance = GetModuleHandle(NULL);
- if (RegisterClassW(&wc) == 0)
- panic("(test program) error registering main window class");
- mainwin = CreateWindowExW(0,
- L"mainwin", L"Main Window",
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 400, 400,
- NULL, NULL, GetModuleHandle(NULL), NULL);
- if (mainwin == NULL)
- panic("(test program) error creating main window");
- ShowWindow(mainwin, SW_SHOWDEFAULT);
- if (UpdateWindow(mainwin) == 0)
- panic("(test program) error updating window");
- while (GetMessageW(&msg, NULL, 0, 0) > 0) {
- TranslateMessage(&msg);
- DispatchMessageW(&msg);
- }
- return 0;
-}
-
-// from tango-icon-theme-0.8.90/16x16/status/audio-volume-high.png (public domain)
-COLORREF iconpix[] = {
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1003060A, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34101210, 0x5020202, 0x0, 0x0, 0x0, 0x0, 0x9E203E66, 0x78182F4D, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x32111110, 0xF051534F, 0x8030303, 0x0, 0x0, 0x0, 0x0, 0x1C050B12, 0xE92F5C96, 0x2B08111B, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x32111110, 0xF1575855, 0xFE545652, 0x8030303, 0x0, 0x0, 0x67152942, 0x440E1B2C, 0x0, 0x6214263F, 0xCB295083, 0x4000102,
- 0xF3525450, 0xFB545653, 0xF0555653, 0x8830302E, 0xF1575855, 0xFFBEBFBC, 0xFC565854, 0x8030303, 0x0, 0x0, 0x420C192A, 0xE12E5991, 0xF03060A, 0x0, 0xC6284E7F, 0x52102034,
- 0xFB555653, 0xFFE5E5E3, 0xFFD1D2CF, 0xFE585A56, 0xFFC7C8C5, 0xFFF7F7F6, 0xFC5A5C58, 0x8030303, 0x68142943, 0x1C060B12, 0x0, 0x9A1E3D63, 0x81193353, 0x0, 0x831A3454, 0x891C3658,
- 0xFB545653, 0xFFFAFAF9, 0xFFFAFAFA, 0xFF585A56, 0xFFF8F8F8, 0xFFFFFFFF, 0xFC5B5D59, 0x8030303, 0x7B19314F, 0xAB23436E, 0x0, 0x4A0F1D30, 0xBA264978, 0x0, 0x4F101F33, 0xBD264B7A,
- 0xFB545653, 0xFFCFD0CD, 0xFFD3D4D1, 0xFF585A56, 0xFFD2D2D0, 0xFFD7D7D5, 0xFC565854, 0x8030303, 0x1C060B12, 0xEF305F9A, 0x1000001, 0x19050A10, 0xEF305F9A, 0x1000001, 0x1B050A11, 0xF0315F9A,
- 0xFB545653, 0xFFC2C3C0, 0xFFC6C7C4, 0xFF585A56, 0xFFCDCECB, 0xFFD1D2CF, 0xFC565854, 0x8030303, 0x19050A10, 0xF231609C, 0x1000001, 0x1603090E, 0xF1315F9B, 0x1000001, 0x1804090F, 0xF231609C,
- 0xFB545653, 0xFFB5B7B3, 0xFFB9BBB7, 0xFF575955, 0xFFC8C8C6, 0xFFCCCCCA, 0xFC565854, 0x8030303, 0x71172D49, 0xB2244772, 0x0, 0x470D1C2E, 0xBE264B7A, 0x0, 0x4C0F1E31, 0xC0274C7B,
- 0xFB545653, 0xFFA9ABA7, 0xFFA0A29E, 0xFF575955, 0xFFA9ABA8, 0xFFC6C7C4, 0xFC565854, 0x8030303, 0x75172E4B, 0x23070E17, 0x0, 0x921D3A5E, 0x861A3556, 0x0, 0x801A3252, 0x8C1C375A,
- 0xFA535551, 0xFC555753, 0xF7545652, 0x98353534, 0xF3565854, 0xFFA8A8A6, 0xFC565854, 0x8030303, 0x0, 0x0, 0x390C1725, 0xE62F5B94, 0x1404080D, 0x0, 0xC0274C7B, 0x57112238,
- 0x7020202, 0x8020202, 0x3010100, 0x0, 0x3C141414, 0xF3565854, 0xFE545652, 0x8030303, 0x0, 0x0, 0x70162C48, 0x4E0F1F32, 0x0, 0x57112238, 0xD32B5388, 0x6010203,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x3C141414, 0xF5515350, 0x8030303, 0x0, 0x0, 0x0, 0x0, 0x1604080E, 0xE72F5B95, 0x330A1420, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3F151515, 0x5020202, 0x0, 0x0, 0x0, 0x0, 0x991F3C62, 0x831A3454, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1B050A11, 0x4000102, 0x0, 0x0,
-};
-
-HBITMAP mkbitmap(void)
-{
- BITMAPINFO bi;
- void *ppvBits;
- HBITMAP b;
-
- ZeroMemory(&bi, sizeof (BITMAPINFO));
- bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
- bi.bmiHeader.biWidth = 16;
- bi.bmiHeader.biHeight = -16; // negative height to force top-down drawing
- bi.bmiHeader.biPlanes = 1;
- bi.bmiHeader.biBitCount = 32;
- bi.bmiHeader.biCompression = BI_RGB;
- bi.bmiHeader.biSizeImage = 16 * 16 * 4;
- b = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0);
- if (b == 0)
- panic("test bitmap creation failed");
- memcpy(ppvBits, iconpix, bi.bmiHeader.biSizeImage);
- return b;
-}
diff --git a/wintable/update.h b/wintable/update.h
deleted file mode 100644
index dae4811..0000000
--- a/wintable/update.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 8 january 2015
-
-// Whenever a number of things in the Table changes, the update() function needs to be called to update any metrics and scrolling positions.
-// The control font changing is the big one, as that comes with a flag that decides whether or not to redraw everything. We'll need to respect that here.
-
-// For my personal convenience, each invocation of update() and updateAll() will be suffixed with a DONE comment once I have reasoned that the chosen function is correct and that no additional redrawing is necessary.
-
-// TODO actually use redraw here
-static void update(struct table *t, BOOL redraw)
-{
- RECT client;
- intptr_t i;
- intptr_t height;
-
- // before we do anything we need the client rect
- if (GetClientRect(t->hwnd, &client) == 0)
- panic("error getting Table client rect in update()");
-
- // the first step is to figure out how wide the whole table is
- // TODO count dividers?
- t->width = 0;
- for (i = 0; i < t->nColumns; i++)
- t->width += columnWidth(t, i);
-
- // now we need to figure out how much of the width of the table can be seen at once
- t->hpagesize = client.right - client.left;
- // this part is critical: if we resize the columns to less than the client area width, then the following hscrollby() will make t->hscrollpos negative, which does very bad things
- // we do this regardless of which of the two has changed, just to be safe
- if (t->hpagesize > t->width)
- t->hpagesize = t->width;
-
- // now we do a dummy horizontal scroll to apply the new width and horizontal page size
- // this will also reposition and resize the header (the latter in case the font changed), which will be important for the next step
- hscrollby(t, 0);
-
- // now that we have the new height of the header, we can fix up vertical scrolling
- // so let's take the header height away from the client area
- client.top += t->headerHeight;
- // and update our page size appropriately
- height = client.bottom - client.top;
- t->vpagesize = height / rowht(t);
- // and do a dummy vertical scroll to apply that
- vscrollby(t, 0);
-}
-
-// this is the same as update(), but also redraws /everything/
-// as such, redraw is TRUE
-static void updateAll(struct table *t)
-{
- update(t, TRUE);
- if (InvalidateRect(t->hwnd, NULL, TRUE) == 0)
- panic("error queueing all of Table for redraw in updateAll()");
-}
diff --git a/wintable/util.h b/wintable/util.h
deleted file mode 100644
index 164ca72..0000000
--- a/wintable/util.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// 4 december 2014
-
-typedef BOOL (*handlerfunc)(struct table *, UINT, WPARAM, LPARAM, LRESULT *);
-#define HANDLER(name) static BOOL name(struct table *t, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
-
-static BOOL runHandlers(const handlerfunc list[], struct table *t, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
-{
- const handlerfunc *p;
-
- for (p = list; *p != NULL; p++)
- if ((*(*p))(t, uMsg, wParam, lParam, lResult))
- return TRUE;
- return FALSE;
-}
-
-// memory allocation stuff
-// each of these functions do an implicit ZeroMemory()
-// these also make tableRealloc(NULL, ...)/tableFree(NULL) act like realloc(NULL, ...)/free(NULL) (that is, same as tableAlloc(...)/malloc(...) and a no-op, respectively)
-// we /would/ use LocalAlloc() here because
-// - whether the malloc() family supports the last-error code is undefined
-// - the HeapAlloc() family DOES NOT support the last-error code; you're supposed to use Windows exceptions, and I can't find a clean way to do this with MinGW-w64 that doesn't rely on inline assembly or external libraries (unless they added __try/__except blocks)
-// - there's no VirtualReAlloc() to complement VirtualAlloc() and I'm not sure if we can even get the original allocated size back out reliably to write it ourselves (http://blogs.msdn.com/b/oldnewthing/archive/2012/03/16/10283988.aspx)
-// alas, LocalAlloc() doesn't want to work on real Windows 7 after a few times, throwing up ERROR_NOT_ENOUGH_MEMORY after three (3) ints or so :|
-// we'll use malloc() until then
-// needless to say, TODO
-
-static void *tableAlloc(size_t size, const char *panicMessage)
-{
-// HLOCAL out;
- void *out;
-
-// out = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, size);
- out = malloc(size);
- if (out == NULL)
- panic(panicMessage);
- ZeroMemory(out, size);
- return (void *) out;
-}
-
-static void *tableRealloc(void *p, size_t size, const char *panicMessage)
-{
-// HLOCAL out;
- void *out;
-
- if (p == NULL)
- return tableAlloc(size, panicMessage);
-// out = LocalReAlloc((HLOCAL) p, size, LMEM_ZEROINIT);
- out = realloc(p, size);
- if (out == NULL)
- panic(panicMessage);
- // TODO zero the extra memory
- return (void *) out;
-}
-
-static void tableFree(void *p, const char *panicMessage)
-{
- if (p == NULL)
- return;
-// if (LocalFree((HLOCAL) p) != NULL)
-// panic(panicMessage);
- free(p);
-}
-
-// font selection
-
-static HFONT selectFont(struct table *t, HDC dc, HFONT *newfont)
-{
- HFONT prevfont;
-
- // copy it in casse we get a WM_SETFONT before this call's respective deselectFont() call
- *newfont = t->font;
- if (*newfont == NULL) {
- // get it on demand in the (unlikely) event it changes while this Table is alive
- *newfont = GetStockObject(SYSTEM_FONT);
- if (*newfont == NULL)
- panic("error getting default font for selecting into Table DC");
- }
- prevfont = (HFONT) SelectObject(dc, *newfont);
- if (prevfont == NULL)
- panic("error selecting Table font into Table DC");
- return prevfont;
-}
-
-static void deselectFont(HDC dc, HFONT prevfont, HFONT newfont)
-{
- if (SelectObject(dc, prevfont) != newfont)
- panic("error deselecting Table font from Table DC");
- // doin't delete newfont here, even if it is the system font (see http://msdn.microsoft.com/en-us/library/windows/desktop/dd144925%28v=vs.85%29.aspx)
-}
-
-// and back to other functions
-
-static LONG columnWidth(struct table *t, intptr_t n)
-{
- RECT r;
-
- if (SendMessageW(t->header, HDM_GETITEMRECT, (WPARAM) n, (LPARAM) (&r)) == 0)
- panic("error getting Table column width");
- return r.right - r.left;
-}
-
-/* TODO:
-http://blogs.msdn.com/b/oldnewthing/archive/2003/10/13/55279.aspx
-http://blogs.msdn.com/b/oldnewthing/archive/2003/10/14/55286.aspx
-we'll need to make sure that initial edge case works properly
-(TODO get the linked article in the latter)
-also implement retrack() as so, in the WM_MOUSEMOVE handler
-*/
-static void retrack(struct table *t)
-{
- TRACKMOUSEEVENT tm;
-
- ZeroMemory(&tm, sizeof (TRACKMOUSEEVENT));
- tm.cbSize = sizeof (TRACKMOUSEEVENT);
- tm.dwFlags = TME_LEAVE; // TODO TME_NONCLIENT as well?
- tm.hwndTrack = t->hwnd;
- if ((*tableTrackMouseEvent)(&tm) == 0)
- panic("error retracking Table mouse events");
-}
diff --git a/wintable/vscroll.h b/wintable/vscroll.h
deleted file mode 100644
index ca34957..0000000
--- a/wintable/vscroll.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// 9 december 2014
-
-// forward declaration needed here
-static void repositionHeader(struct table *);
-
-static struct scrollParams vscrollParams(struct table *t)
-{
- struct scrollParams p;
-
- ZeroMemory(&p, sizeof (struct scrollParams));
- p.pos = &(t->vscrollpos);
- p.pagesize = t->vpagesize;
- p.length = t->count;
- p.scale = rowht(t);
- p.post = NULL;
- p.wheelCarry = &(t->vwheelCarry);
- return p;
-}
-
-static void vscrollto(struct table *t, intptr_t pos)
-{
- struct scrollParams p;
-
- p = vscrollParams(t);
- scrollto(t, SB_VERT, &p, pos);
-}
-
-static void vscrollby(struct table *t, intptr_t delta)
-{
- struct scrollParams p;
-
- p = vscrollParams(t);
- scrollby(t, SB_VERT, &p, delta);
-}
-
-static void vscroll(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- struct scrollParams p;
-
- p = vscrollParams(t);
- scroll(t, SB_VERT, &p, wParam, lParam);
-}
-
-static void vwheelscroll(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- struct scrollParams p;
-
- p = vscrollParams(t);
- wheelscroll(t, SB_VERT, &p, wParam, lParam);
-}
-
-HANDLER(vscrollHandler)
-{
- switch (uMsg) {
- case WM_VSCROLL:
- vscroll(t, wParam, lParam);
- *lResult = 0;
- return TRUE;
- case WM_MOUSEWHEEL:
- vwheelscroll(t, wParam, lParam);
- *lResult = 0;
- return TRUE;
- }
- return FALSE;
-}