summaryrefslogtreecommitdiff
path: root/prefsize_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'prefsize_windows.go')
-rw-r--r--prefsize_windows.go156
1 files changed, 156 insertions, 0 deletions
diff --git a/prefsize_windows.go b/prefsize_windows.go
new file mode 100644
index 0000000..3ccc781
--- /dev/null
+++ b/prefsize_windows.go
@@ -0,0 +1,156 @@
+// 24 february 2014
+package ui
+
+import (
+// "syscall"
+ "unsafe"
+)
+
+// For Windows, Microsoft just hands you a list of preferred control sizes as part of the MSDN documentation and tells you to roll with it.
+// These sizes are given in "dialog units", which are independent of the font in use.
+// We need to convert these into standard pixels, which requires we get the device context of the OS window.
+// References:
+// - http://msdn.microsoft.com/en-us/library/windows/desktop/aa511279.aspx#controlsizing for control sizes
+// - http://msdn.microsoft.com/en-us/library/ms645502%28VS.85%29.aspx - the calculation needed
+// - http://support.microsoft.com/kb/125681 - to get the base X and Y
+
+// As we are left with incomplete data, an arbitrary size will be chosen
+const (
+ defaultWidth = 100 // 2 * preferred width of buttons
+)
+
+type dlgunits struct {
+ width int
+ height int
+ longest bool // TODO actually use this
+}
+
+var stdDlgSizes = [nctypes]dlgunits{
+ c_button: dlgunits{
+ width: 50,
+ height: 14,
+ },
+ c_checkbox: dlgunits{
+ // widtdh is not defined here so assume longest
+ longest: true,
+ height: 10,
+ },
+ c_combobox: dlgunits{
+ longest: true,
+ height: 14,
+ },
+ c_lineedit: dlgunits{
+ longest: true,
+ height: 14,
+ },
+ c_label: dlgunits{
+ longest: true,
+ height: 8,
+ },
+ c_listbox: dlgunits{
+ longest: true,
+ // height is not clearly defined here ("an integral number of items (3 items minimum)") so just use a three-line edit control
+ height: 14 + 10 + 10,
+ },
+}
+
+var (
+ _getTextMetrics = user32.NewProc("GetTextMetricsW")
+ _getWindowDC = user32.NewProc("GetWindowDC")
+ _releaseDC = user32.NewProc("ReleaseDC")
+)
+
+func (s *sysData) preferredSize() (width int, height int) {
+println("size of control", s.ctype)
+ var dc _HANDLE
+ var tm _TEXTMETRICS
+ var baseX, baseY int
+
+ ret := make(chan uiret)
+ defer close(ret)
+println("calling getWindowDC")
+ uitask <- &uimsg{
+ call: _getWindowDC,
+ p: []uintptr{uintptr(s.hwnd)},
+ ret: ret,
+ }
+ r := <-ret
+println("getWindowDC",r.ret,r.err)
+ if r.ret == 0 { // failure
+ panic(r.err) // TODO return it instead
+ }
+ dc = _HANDLE(r.ret)
+println("getTextMetrics")
+ uitask <- &uimsg{
+ call: _getTextMetrics,
+ p: []uintptr{
+ uintptr(dc),
+ uintptr(unsafe.Pointer(&tm)),
+ },
+ ret: ret,
+ }
+ r = <-ret
+println("getTextMetrics",r.ret,r.err)
+ if r.ret == 0 { // failure
+ panic(r.err) // TODO return it instead
+ }
+ baseX = int(tm.tmAveCharWidth) // TODO not optimal; third reference has better way
+ baseY = int(tm.tmHeight)
+println("releaseDC")
+ uitask <- &uimsg{
+ call: _releaseDC,
+ p: []uintptr{
+ uintptr(s.hwnd),
+ uintptr(dc),
+ },
+ ret: ret,
+ }
+ r = <-ret
+println("releaseDC",r.ret,r.err)
+ if r.ret == 0 { // failure
+ panic(r.err) // TODO return it instead
+ }
+
+ // now that we have the conversion factors...
+ width = stdDlgSizes[s.ctype].width
+ if width == 0 {
+ width = defaultWidth
+ }
+ height = stdDlgSizes[s.ctype].height
+ width = muldiv(width, baseX, 4) // equivalent to right of rect
+ height = muldiv(height, baseY, 8) // equivalent to bottom of rect
+println("result:", width, height)
+ return width, height
+}
+
+// attempts to mimic the behavior of kernel32.MulDiv()
+// caling it directly would be better (TODO)
+// alternatively TODO make sure the rounding is correct
+func muldiv(ma int, mb int, div int) int {
+ xa := int64(ma) * int64(mb)
+ xa /= int64(div)
+ return int(xa)
+}
+
+type _TEXTMETRICS struct {
+ tmHeight int32
+ tmAscent int32
+ tmDescent int32
+ tmInternalLeading int32
+ tmExternalLeading int32
+ tmAveCharWidth int32
+ tmMaxCharWidth int32
+ tmWeight int32
+ tmOverhang int32
+ tmDigitizedAspectX int32
+ tmDigitizedAspectY int32
+ tmFirstChar uint16
+ tmLastChar uint16
+ tmDefaultChar uint16
+ tmBreakChar uint16
+ tmItalic byte
+ tmUnderlined byte
+ tmStruckOut byte
+ tmPitchAndFamily byte
+ tmCharSet byte
+}