type sysSizeData struct { // for size calculations // all platforms margin int // windows: calculated spacing int // gtk+, cocoa: constants // windows baseX int baseY int // gtk, mac os x: nothing // for the actual resizing // windows // possibly also the HDWP // gtk shouldVAlignTop bool // mac os x // neighbor control alignment rect/baseline info } func (s *sysData) beginResize() *sysSizeData { // windows: get baseX/baseY for window and compute margin and spacing // gtk, mac: return zero } func (s *sysData) endResize(d *sysSizeData) { // redraw } type allocation struct { x int y int width int height int this Control neighbor Control } func (s *sysData) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) { // windows, gtk: nothing // mac for _, a := range allocations { // 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 a.y = (winheight - a.y) - a.height } } func (s *sysData) resizeWindow(width, height int) { d := s.beginResize() allocations := s.allocate(0, 0, width, height, d) s.translateAllocationCoords(allocations, width, height) for _, c := range s.allocations { c.this.doResize(c, d) } s.endResize(d) } // setSize() becomes allocate() // each allocate on a non-layout control should just return a one-element slice // each doResize and getAuxResizeInfo on a control should just defer to sysData type Control interface { // ... allocate(x int, y int, width int, height int, d *sysSizeData) []*allocation preferredSize(d *sysSizeData) (width, height int) doResize(c *allocation, d *sysSizeData) getAuxResizeInfo(d *sysSizeData) } // vertical stack: no concept of neighbor, but not too hard to add a vertical neighbor // horizontal stack: var current *allocation // ... as := s.controls[i].allocate(...) if current != nil { current.neighbor = as[0].self } current = as[0] // append all of as // grid: // same as above, except current is set to nil on each new row // adding a vertical neighbor would require storing an extra list // windows func (s *sysData) doResize(c *allocation, d *sysSizeData) { if s.ctype == c_label { // add additional offset of 4 dialog units } // resize } func (s *sysData) getAuxResizeInfo(d *sysSizeData) { // do nothing } // gtk+ func (s *sysData) doResize(c *allocation, d *sysSizeData) { if s.ctype == c_label && !s.alternate && c.neighbor != nil { c.neighbor.getAuxResizeInfo(d) if d.shouldVAlignTop { // TODO should it be center-aligned to the first line or not gtk_misc_set_align(s.widget, 0, 0) } else { gtk_misc_set_align(s.widget, 0, 0.5) } } // resize } func (s *sysData) getAuxResizeInfo(d *sysSizeData) { d.shouldVAlignTop = (s.ctype == c_listbox) || (s.ctype == c_area) } // cocoa func (s *sysData) doResize(c *allocation, d *sysSizeData) { if s.ctype == c_label && !s.alternate && c.neighbor != nil { c.neighbor.getAuxResizeInfo(d) // get this control's alignment rect and baseline // align } // resize } func (s *sysData) getAuxResizeInfo(d *sysSizeData) { // get this control's alignment rect and baseline }