summaryrefslogtreecommitdiff
path: root/experiments
diff options
context:
space:
mode:
Diffstat (limited to 'experiments')
-rw-r--r--experiments/hscrolllistbox.go178
1 files changed, 178 insertions, 0 deletions
diff --git a/experiments/hscrolllistbox.go b/experiments/hscrolllistbox.go
new file mode 100644
index 0000000..3975a56
--- /dev/null
+++ b/experiments/hscrolllistbox.go
@@ -0,0 +1,178 @@
+// WINDOWS (works)
+
+ style: _LBS_NOTIFY | _LBS_NOINTEGRALHEIGHT | _WS_HSCROLL | _WS_VSCROLL | controlstyle,
+ xstyle: _WS_EX_CLIENTEDGE | controlxstyle,
+ altStyle: _LBS_EXTENDEDSEL | _LBS_NOTIFY | _LBS_NOINTEGRALHEIGHT | _WS_HSCROLL | _WS_VSCROLL | controlstyle,
+
+(call recalcListboxWidth() from sysData.append(), sysData.insertBefore(), and sysData.delete())
+
+// List Boxes do not dynamically handle horizontal scrollbars.
+// We have to manually handle this ourselves.
+// TODO make this run on the main thread when we switch to uitask taking function literals
+// TODO this is inefficient; some caching would be nice
+func recalcListboxWidth(hwnd _HWND) {
+ var size _SIZE
+
+ ret := make(chan uiret)
+ defer close(ret)
+ uitask <- &uimsg{
+ call: _sendMessage,
+ p: []uintptr{
+ uintptr(hwnd),
+ uintptr(_LB_GETCOUNT),
+ uintptr(0),
+ uintptr(0),
+ },
+ ret: ret,
+ }
+ r := <-ret
+ if r.ret == uintptr(_LB_ERR) { // failure
+ panic(fmt.Errorf("error getting number of items for Listbox width calculations: %v", r.err))
+ }
+ n := int(r.ret)
+ uitask <- &uimsg{
+ call: _getWindowDC,
+ p: []uintptr{uintptr(hwnd)},
+ ret: ret,
+ }
+ r = <-ret
+ if r.ret == 0 { // failure
+ panic(fmt.Errorf("error getting DC for Listbox width calculations: %v", r.err))
+ }
+ dc := _HANDLE(r.ret)
+ uitask <- &uimsg{
+ call: _selectObject,
+ p: []uintptr{
+ uintptr(dc),
+ uintptr(controlFont),
+ },
+ ret: ret,
+ }
+ r = <-ret
+ if r.ret == 0 { // failure
+ panic(fmt.Errorf("error loading control font into device context for Listbox width calculation: %v", r.err))
+ }
+ hextent := uintptr(0)
+ for i := 0; i < n; i++ {
+ uitask <- &uimsg{
+ call: _sendMessage,
+ p: []uintptr{
+ uintptr(hwnd),
+ uintptr(_LB_GETTEXTLEN),
+ uintptr(_WPARAM(i)),
+ uintptr(0),
+ },
+ ret: ret,
+ }
+ r := <-ret
+ if r.ret == uintptr(_LB_ERR) {
+ panic("UI library internal error: LB_ERR from LB_GETTEXTLEN in what we know is a valid listbox index (came from LB_GETSELITEMS)")
+ }
+ str := make([]uint16, r.ret)
+ uitask <- &uimsg{
+ call: _sendMessage,
+ p: []uintptr{
+ uintptr(hwnd),
+ uintptr(_LB_GETTEXT),
+ uintptr(_WPARAM(i)),
+ uintptr(_LPARAM(unsafe.Pointer(&str[0]))),
+ },
+ ret: ret,
+ }
+ r = <-ret
+ if r.ret == uintptr(_LB_ERR) {
+ panic("UI library internal error: LB_ERR from LB_GETTEXT in what we know is a valid listbox index (came from LB_GETSELITEMS)")
+ }
+ // r.ret is still the length of the string; this time without the null terminator
+ uitask <- &uimsg{
+ call: _getTextExtentPoint32,
+ p: []uintptr{
+ uintptr(dc),
+ uintptr(unsafe.Pointer(&str[0])),
+ r.ret,
+ uintptr(unsafe.Pointer(&size)),
+ },
+ ret: ret,
+ }
+ r = <-ret
+ if r.ret == 0 { // failure
+ panic(fmt.Errorf("error getting width of item %d text for Listbox width calculation: %v", i, r.err))
+ }
+ if hextent < uintptr(size.cx) {
+ hextent = uintptr(size.cx)
+ }
+ }
+ uitask <- &uimsg{
+ call: _releaseDC,
+ p: []uintptr{
+ uintptr(hwnd),
+ uintptr(dc),
+ },
+ ret: ret,
+ }
+ r = <-ret
+ if r.ret == 0 { // failure
+ panic(fmt.Errorf("error releasing DC for Listbox width calculations: %v", r.err))
+ }
+ uitask <- &uimsg{
+ call: _sendMessage,
+ p: []uintptr{
+ uintptr(hwnd),
+ uintptr(_LB_SETHORIZONTALEXTENT),
+ hextent,
+ uintptr(0),
+ },
+ ret: ret,
+ }
+ <-ret
+}
+
+// DARWIN (does not work)
+
+// NSTableView is actually in a NSScrollView so we have to get it out first
+// NSTableView and NSTableColumn both provide sizeToFit methods, but they don't do what we want (NSTableView's sizes to fit the parent; NSTableColumn's sizes to fit the column header)
+// We have to get the width manually; see also http://stackoverflow.com/questions/4674163/nstablecolumn-size-to-fit-contents
+// We can use the NSTableView sizeToFit to get the height, though.
+// TODO this is inefficient!
+// TODO move this to listbox_darwin.go
+var (
+ _dataCellForRow = sel_getUid("dataCellForRow:")
+ _cellSize = sel_getUid("cellSize")
+ _setMinWidth = sel_getUid("setMinWidth:")
+ _setWidth = sel_getUid("setWidth:")
+)
+
+func listboxPrefSize(control C.id) (width int, height int) {
+ var maxwidth C.int64_t
+
+ listbox := listboxInScrollView(control)
+ _, height = controlPrefSize(listbox)
+ column := listboxTableColumn(listbox)
+ n := C.objc_msgSend_intret_noargs(listbox, _numberOfRows)
+ for i := C.intptr_t(0); i < n; i++ {
+ cell := C.objc_msgSend_int(column, _dataCellForRow, i)
+ csize := C.objc_msgSend_stret_size_noargs(cell, _cellSize)
+ if maxwidth < csize.width {
+ maxwidth = csize.width
+ }
+ }
+ // and in order for horizontal scrolling to work, we need to set the column width to this
+ C.objc_msgSend_cgfloat(column, _setMinWidth, C.double(maxwidth))
+ C.objc_msgSend_cgfloat(column, _setWidth, C.double(maxwidth))
+ return int(maxwidth), height
+}
+
+func (s *sysData) setRect(x int, y int, width int, height int, winheight int) error {
+ // winheight - y because (0,0) is the bottom-left corner of the window and not the top-left corner
+ // (winheight - y) - height because (x, y) is the bottom-left corner of the control and not the top-left
+ C.objc_msgSend_rect(s.id, _setFrame,
+ C.int64_t(x), C.int64_t((winheight - y) - height), C.int64_t(width), C.int64_t(height))
+ // TODO having this here is a hack; split it into a separate function in listbox_darwin.go
+ // the NSTableView:NSTableColumn ratio is what determines horizontal scrolling; see http://stackoverflow.com/questions/7050497/enable-scrolling-for-nstableview
+ if s.ctype == c_listbox {
+ listbox := listboxInScrollView(s.id)
+ C.objc_msgSend_rect(listbox, _setFrame,
+ 0, 0, C.int64_t(width), C.int64_t(height))
+ }
+ return nil
+}