From b964c564e7a7d7a460dbcf922f4ceeb5368def50 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 20 Aug 2014 21:21:45 -0400 Subject: [PATCH] Added Table.OnSelected() and implemented it on Windows. --- redo/future | 1 + redo/table.go | 3 +++ redo/table_windows.c | 39 +++++++++------------------------------ redo/table_windows.go | 12 ++++++++++++ redo/zz_test.go | 10 ++++++++++ 5 files changed, 35 insertions(+), 30 deletions(-) diff --git a/redo/future b/redo/future index 637f0ec..2dca786 100644 --- a/redo/future +++ b/redo/future @@ -62,6 +62,7 @@ windows - OpenFile() not modal - OpenFile() won't stop Do() - labels draw over themselves + - fine-tune Table checkbox behavior (especially with regards to selection) gtk+ - Area: figure out how Enter is processed in Entry https://git.gnome.org/browse/gtk+/tree/gtk/gtkwindow.c#n1229 diff --git a/redo/table.go b/redo/table.go index 2b69d6a..83baadd 100644 --- a/redo/table.go +++ b/redo/table.go @@ -47,6 +47,9 @@ type Table interface { // TODO bounds checking Selected() int Select(index int) + + // OnSelected is an event that gets triggered after the selection in the Table changes in whatever way (item selected or item deselected). + OnSelected(func()) } type tablebase struct { diff --git a/redo/table_windows.c b/redo/table_windows.c index a8bbfa3..4c646c6 100644 --- a/redo/table_windows.c +++ b/redo/table_windows.c @@ -25,39 +25,11 @@ static void handle(HWND hwnd, WPARAM wParam, LPARAM lParam, void (*handler)(void (*handler)(data, ht.iItem, ht.iSubItem); } -static struct {int code; char *name;} lvnnames[] = { -{ LVN_ITEMCHANGING, "LVN_ITEMCHANGING" }, -{ LVN_ITEMCHANGED, "LVN_ITEMCHANGED" }, -{ LVN_INSERTITEM, "LVN_INSERTITEM" }, -{ LVN_DELETEITEM, "LVN_DELETEITEM" }, -{ LVN_DELETEALLITEMS, "LVN_DELETEALLITEMS" }, -{ LVN_BEGINLABELEDITA, "LVN_BEGINLABELEDITA" }, -{ LVN_BEGINLABELEDITW, "LVN_BEGINLABELEDITW" }, -{ LVN_ENDLABELEDITA, "LVN_ENDLABELEDITA" }, -{ LVN_ENDLABELEDITW, "LVN_ENDLABELEDITW" }, -{ LVN_COLUMNCLICK, "LVN_COLUMNCLICK" }, -{ LVN_BEGINDRAG, "LVN_BEGINDRAG" }, -{ LVN_BEGINRDRAG, "LVN_BEGINRDRAG" }, -//{ LVN_ODCACHEHINT, "LVN_ODCACHEHINT" }, -{ LVN_ODFINDITEMA, "LVN_ODFINDITEMA" }, -{ LVN_ODFINDITEMW, "LVN_ODFINDITEMW" }, -{ LVN_ITEMACTIVATE, "LVN_ITEMACTIVATE" }, -{ LVN_ODSTATECHANGED, "LVN_ODSTATECHANGED" }, -{ LVN_SETDISPINFOA, "LVN_SETDISPINFOA" }, -{ LVN_SETDISPINFOW, "LVN_SETDISPINFOW" }, -//{ LVN_KEYDOWN, "LVN_KEYDOWN" }, -{ LVN_MARQUEEBEGIN, "LVN_MARQUEEBEGIN" }, -{ LVN_GETINFOTIPA, "LVN_GETINFOTIPA" }, -{ LVN_GETINFOTIPW, "LVN_GETINFOTIPW" }, -{ LVN_BEGINSCROLL, "LVN_BEGINSCROLL" }, -{ LVN_ENDSCROLL, "LVN_ENDSCROLL" }, -{ 0, NULL }, -}; - static LRESULT CALLBACK tableSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data) { NMHDR *nmhdr = (NMHDR *) lParam; NMLVDISPINFOW *fill = (NMLVDISPINFO *) lParam; + NMLISTVIEW *nlv = (NMLISTVIEW *) lParam; switch (uMsg) { case msgNOTIFY: @@ -65,8 +37,15 @@ static LRESULT CALLBACK tableSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM case LVN_GETDISPINFO: tableGetCell((void *) data, &(fill->item)); return 0; + case LVN_ITEMCHANGED: + if ((nlv->uChanged & LVIF_STATE) == 0) + break; + // if both old and new states have the same value for the selected bit, then the selection state did not change, regardless of selected or deselected + if ((nlv->uOldState & LVIS_SELECTED) == (nlv->uNewState & LVIS_SELECTED)) + break; + tableOnSelected((void *) data); + return 0; } -for(int i=0;lvnnames[i].code!=0;i++)if(lvnnames[i].code==nmhdr->code)printf("%s\n",lvnnames[i].name); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); case WM_MOUSEMOVE: handle(hwnd, wParam, lParam, tableSetHot, (void *) data); diff --git a/redo/table_windows.go b/redo/table_windows.go index 1ed09b8..2976011 100644 --- a/redo/table_windows.go +++ b/redo/table_windows.go @@ -20,6 +20,7 @@ type table struct { hotcol C.int pushedrow C.int pushedcol C.int + selected *event } func finishNewTable(b *tablebase, ty reflect.Type) Table { @@ -32,6 +33,7 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table { hotcol: -1, pushedrow: -1, pushedcol: -1, + selected: newEvent(), } C.setTableSubclass(t._hwnd, unsafe.Pointer(t)) // LVS_EX_FULLROWSELECT gives us selection across the whole row, not just the leftmost column; this makes the list view work like on other platforms @@ -74,6 +76,10 @@ func (t *table) Select(index int) { C.tableSelectItem(t._hwnd, C.intptr_t(index)) } +func (t *table) OnSelected(f func()) { + t.selected.set(f) +} + //export tableGetCell func tableGetCell(data unsafe.Pointer, item *C.LVITEMW) { t := (*table)(data) @@ -181,6 +187,12 @@ func tableToggled(data unsafe.Pointer, row C.int, col C.int) { panic(fmt.Errorf("tableSetHot() on non-checkbox at (%d, %d)", row, col)) } +//export tableOnSelected +func tableOnSelected(data unsafe.Pointer) { + t := (*table)(data) + t.selected.fire() +} + func (t *table) hwnd() C.HWND { return t._hwnd } diff --git a/redo/zz_test.go b/redo/zz_test.go index e1eb8fc..f3392ad 100644 --- a/redo/zz_test.go +++ b/redo/zz_test.go @@ -140,6 +140,16 @@ func (tw *testwin) make(done chan struct{}) { *idq = tw.icons tw.icontbl.Unlock() tw.icontbl.LoadImageList(tw.il) + tw.icontbl.OnSelected(func() { + s := fmt.Sprintf("%d ", tw.icontbl.Selected()) + tw.icontbl.RLock() + defer tw.icontbl.RUnlock() + idq := tw.icontbl.Data().(*[]icon) + for _, v := range *idq { + s += strings.ToUpper(fmt.Sprintf("%v", v.Bool)[0:1]) + " " + } + tw.w.SetTitle(s) + }) tw.t.Append("Image List Table", tw.icontbl) tw.group2 = NewGroup("Group", NewButton("Button in Group")) tw.t.Append("Filled Group", tw.group2)