summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-02-24 13:22:59 -0500
committerPietro Gagliardi <[email protected]>2014-02-24 13:22:59 -0500
commit165308b81973d90d023da5254e92c6fa7ae386eb (patch)
treec7b728d2791075cd715ccbeca4dedf47ad067394
parent1d9a8834311ffc00bbd6dab1ee64f53f9e634db7 (diff)
Added Windows preferred size code. It doesn't work right now; both GetDC() and GetWindowDC() are not returning at all on both wine and Windows XP; need to debug (print guards are included).
-rw-r--r--init_windows.go4
-rw-r--r--prefsize_windows.go156
2 files changed, 158 insertions, 2 deletions
diff --git a/init_windows.go b/init_windows.go
index 5280742..eaf4816 100644
--- a/init_windows.go
+++ b/init_windows.go
@@ -66,9 +66,9 @@ func doWindowsInit() (err error) {
if err != nil {
return fmt.Errorf("error initializing standard window class auxiliary info: %v", err)
}
- err = getStandardWindowsFonts()
+ err = getStandardWindowFonts()
if err != nil {
- return fmt.Errorf("error getting standard Windows fonts: %v", err)
+ return fmt.Errorf("error getting standard window fonts: %v", err)
}
// TODO others
return nil // all ready to go
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
+}