diff options
| -rw-r--r-- | prefsize_windows.go | 122 | ||||
| -rw-r--r-- | sysdata_windows.go | 13 |
2 files changed, 130 insertions, 5 deletions
diff --git a/prefsize_windows.go b/prefsize_windows.go index cb44f2c..07a633f 100644 --- a/prefsize_windows.go +++ b/prefsize_windows.go @@ -71,6 +71,7 @@ var stdDlgSizes = [nctypes]dlgunits{ var ( _selectObject = gdi32.NewProc("SelectObject") + _getTextExtentPoint32 = gdi32.NewProc("GetTextExtentPoint32W") _getTextMetrics = gdi32.NewProc("GetTextMetricsW") _getWindowDC = user32.NewProc("GetWindowDC") _releaseDC = user32.NewProc("ReleaseDC") @@ -149,6 +150,127 @@ func muldiv(ma int, mb int, div int) int { return int(int32(r1)) } +// 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 +} + type _SIZE struct { cx int32 // originally LONG cy int32 diff --git a/sysdata_windows.go b/sysdata_windows.go index 35d246f..5fcd742 100644 --- a/sysdata_windows.go +++ b/sysdata_windows.go @@ -91,9 +91,9 @@ var classTypes = [nctypes]*classData{ // we don't use _LBS_STANDARD because it sorts (and has WS_BORDER; see above) // _LBS_NOINTEGRALHEIGHT gives us exactly the size we want // TODO say why we don't use LBS_MULTISEL (listbox docs and http://msdn.microsoft.com/en-us/library/windows/desktop/aa511485.aspx) - style: _LBS_NOTIFY | _LBS_NOINTEGRALHEIGHT | _WS_VSCROLL | controlstyle, + style: _LBS_NOTIFY | _LBS_NOINTEGRALHEIGHT | _WS_HSCROLL | _WS_VSCROLL | controlstyle, xstyle: _WS_EX_CLIENTEDGE | controlxstyle, - altStyle: _LBS_EXTENDEDSEL | _LBS_NOTIFY | _LBS_NOINTEGRALHEIGHT | _WS_VSCROLL | controlstyle, + altStyle: _LBS_EXTENDEDSEL | _LBS_NOTIFY | _LBS_NOINTEGRALHEIGHT | _WS_HSCROLL | _WS_VSCROLL | controlstyle, appendMsg: _LB_ADDSTRING, insertBeforeMsg: _LB_INSERTSTRING, deleteMsg: _LB_DELETESTRING, @@ -355,6 +355,7 @@ func (s *sysData) append(what string) { } else if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) { panic(fmt.Errorf("failed to add item to combobox/listbox (last error: %v)", r.err)) } + recalcListboxWidth(s.hwnd) } func (s *sysData) insertBefore(what string, index int) { @@ -376,6 +377,7 @@ func (s *sysData) insertBefore(what string, index int) { } else if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) { panic(fmt.Errorf("failed to add item to combobox/listbox (last error: %v)", r.err)) } + recalcListboxWidth(s.hwnd) } func (s *sysData) selectedIndex() int { @@ -462,7 +464,7 @@ func (s *sysData) selectedTexts() []string { } 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") + 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{ @@ -475,9 +477,9 @@ func (s *sysData) selectedTexts() []string { }, ret: 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") + panic("UI library internal error: LB_ERR from LB_GETTEXT in what we know is a valid listbox index (came from LB_GETSELITEMS)") } strings[i] = syscall.UTF16ToString(str) } @@ -526,6 +528,7 @@ func (s *sysData) delete(index int) { if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) { panic(fmt.Errorf("failed to delete item from combobox/listbox (last error: %v)", r.err)) } + recalcListboxWidth(s.hwnd) } func (s *sysData) setIndeterminate() { |
