From 01bb817eee24099196760666b0826d5f7d9808bf Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Wed, 27 Feb 2019 16:27:53 +0100 Subject: Add support for specifying widget alignment on layout level --- boxlayout.go | 106 +++++++++++++++++++++++++++++++++++++++++++++---- declarative/layouts.go | 20 ++++++++++ flowlayout.go | 25 ++++++++++-- gridlayout.go | 46 ++++++++++++++++++++- 4 files changed, 184 insertions(+), 13 deletions(-) diff --git a/boxlayout.go b/boxlayout.go index d84a7bc0..a8b7dfdb 100644 --- a/boxlayout.go +++ b/boxlayout.go @@ -24,6 +24,7 @@ type BoxLayout struct { margins Margins spacing int orientation Orientation + alignment Alignment2D hwnd2StretchFactor map[win.HWND]int size2MinSize map[Size]Size resetNeeded bool @@ -104,6 +105,24 @@ func (l *BoxLayout) SetOrientation(value Orientation) error { return nil } +func (l *BoxLayout) Alignment() Alignment2D { + return l.alignment +} + +func (l *BoxLayout) SetAlignment(alignment Alignment2D) error { + if alignment != l.alignment { + if alignment < AlignHVDefault || alignment > AlignHFarVFar { + return newError("invalid Alignment value") + } + + l.alignment = alignment + + l.Update(false) + } + + return nil +} + func (l *BoxLayout) Spacing() int { return l.spacing } @@ -230,7 +249,7 @@ func (l *BoxLayout) MinSizeForSize(size Size) Size { bounds := Rectangle{Width: size.Width, Height: size.Height} - items, err := boxLayoutItems(widgetsToLayout(l.Container().Children()), l.orientation, bounds, l.margins, l.spacing, l.hwnd2StretchFactor) + items, err := boxLayoutItems(widgetsToLayout(l.Container().Children()), l.orientation, l.alignment, bounds, l.margins, l.spacing, l.hwnd2StretchFactor) if err != nil { return Size{} } @@ -302,7 +321,7 @@ func (l *BoxLayout) Update(reset bool) error { ifContainerIsScrollViewDoCoolSpecialLayoutStuff(l) - items, err := boxLayoutItems(widgetsToLayout(l.Container().Children()), l.orientation, l.container.ClientBounds(), l.margins, l.spacing, l.hwnd2StretchFactor) + items, err := boxLayoutItems(widgetsToLayout(l.Container().Children()), l.orientation, l.alignment, l.container.ClientBounds(), l.margins, l.spacing, l.hwnd2StretchFactor) if err != nil { return err } @@ -360,7 +379,11 @@ func boxLayoutFlags(orientation Orientation, children *WidgetList) LayoutFlags { return flags } -func boxLayoutItems(widgets []Widget, orientation Orientation, bounds Rectangle, margins Margins, spacing int, hwnd2StretchFactor map[win.HWND]int) ([]layoutResultItem, error) { +func boxLayoutItems(widgets []Widget, orientation Orientation, alignment Alignment2D, bounds Rectangle, margins Margins, spacing int, hwnd2StretchFactor map[win.HWND]int) ([]layoutResultItem, error) { + if len(widgets) == 0 { + return nil, nil + } + var greedyNonSpacerCount int var greedySpacerCount int var stretchFactorsTotal [3]int @@ -498,10 +521,10 @@ func boxLayoutItems(widgets []Widget, orientation Orientation, bounds Rectangle, results := make([]layoutResultItem, 0, len(widgets)) excessTotal := space1 - minSizesRemaining - spacingRemaining - excessShare := excessTotal / (len(widgets) + 1) + excessShare := excessTotal / len(widgets) + halfExcessShare := excessTotal / (len(widgets) * 2) p1 := start1 for i, widget := range widgets { - p1 += excessShare s1 := sizes[i] var s2 int @@ -511,15 +534,82 @@ func boxLayoutItems(widgets []Widget, orientation Orientation, bounds Rectangle, s2 = prefSizes2[i] } - p2 := start2 + (space2-s2)/2 - - var x, y, w, h int + var x, y, w, h, p2 int if orientation == Horizontal { + switch alignment { + case AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar: + // nop + + case AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar: + p1 += excessShare + + default: + p1 += halfExcessShare + } + + switch alignment { + case AlignHNearVNear, AlignHCenterVNear, AlignHFarVNear: + p2 = start2 + + case AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar: + p2 = start2 + space2 - s2 + + default: + p2 = start2 + (space2-s2)/2 + } + x, y, w, h = p1, p2, s1, s2 } else { + switch alignment { + case AlignHNearVNear, AlignHCenterVNear, AlignHFarVNear: + // nop + + case AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar: + p1 += excessShare + + default: + p1 += halfExcessShare + } + + switch alignment { + case AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar: + p2 = start2 + + case AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar: + p2 = start2 + space2 - s2 + + default: + p2 = start2 + (space2-s2)/2 + } + x, y, w, h = p2, p1, s2, s1 } + if orientation == Horizontal { + switch alignment { + case AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar: + p1 += excessShare + + case AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar: + // nop + + default: + p1 += halfExcessShare + } + + } else { + switch alignment { + case AlignHNearVNear, AlignHCenterVNear, AlignHFarVNear: + p1 += excessShare + + case AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar: + // nop + + default: + p1 += halfExcessShare + } + } + p1 += s1 + spacing results = append(results, layoutResultItem{widget: widget, bounds: Rectangle{X: x, Y: y, Width: w, Height: h}}) diff --git a/declarative/layouts.go b/declarative/layouts.go index 601c3ffb..158a0cbb 100644 --- a/declarative/layouts.go +++ b/declarative/layouts.go @@ -61,6 +61,7 @@ func setLayoutSpacing(layout walk.Layout, spacing int, spacingZero bool) error { type HBox struct { Margins Margins + Alignment Alignment2D Spacing int MarginsZero bool SpacingZero bool @@ -77,11 +78,16 @@ func (hb HBox) Create() (walk.Layout, error) { return nil, err } + if err := l.SetAlignment(walk.Alignment2D(hb.Alignment)); err != nil { + return nil, err + } + return l, nil } type VBox struct { Margins Margins + Alignment Alignment2D Spacing int MarginsZero bool SpacingZero bool @@ -98,6 +104,10 @@ func (vb VBox) Create() (walk.Layout, error) { return nil, err } + if err := l.SetAlignment(walk.Alignment2D(vb.Alignment)); err != nil { + return nil, err + } + return l, nil } @@ -105,6 +115,7 @@ type Grid struct { Rows int Columns int Margins Margins + Alignment Alignment2D Spacing int MarginsZero bool SpacingZero bool @@ -125,11 +136,16 @@ func (g Grid) Create() (walk.Layout, error) { return nil, err } + if err := l.SetAlignment(walk.Alignment2D(g.Alignment)); err != nil { + return nil, err + } + return l, nil } type Flow struct { Margins Margins + Alignment Alignment2D Spacing int MarginsZero bool SpacingZero bool @@ -146,5 +162,9 @@ func (f Flow) Create() (walk.Layout, error) { return nil, err } + if err := l.SetAlignment(walk.Alignment2D(f.Alignment)); err != nil { + return nil, err + } + return l, nil } diff --git a/flowlayout.go b/flowlayout.go index e85ef820..1cf2ec4e 100644 --- a/flowlayout.go +++ b/flowlayout.go @@ -16,6 +16,7 @@ type FlowLayout struct { margins Margins size2MinSize map[Size]Size spacing int + alignment Alignment2D resetNeeded bool } @@ -86,6 +87,24 @@ func (l *FlowLayout) SetSpacing(value int) error { return nil } +func (l *FlowLayout) Alignment() Alignment2D { + return l.alignment +} + +func (l *FlowLayout) SetAlignment(alignment Alignment2D) error { + if alignment != l.alignment { + if alignment < AlignHVDefault || alignment > AlignHFarVFar { + return newError("invalid Alignment value") + } + + l.alignment = alignment + + l.Update(false) + } + + return nil +} + func (l *FlowLayout) StretchFactor(widget Widget) int { if factor, ok := l.hwnd2StretchFactor[widget.Handle()]; ok { return factor @@ -176,7 +195,7 @@ func (l *FlowLayout) MinSizeForSize(size Size) Size { margins.VFar = 0 } - layoutItems, err := boxLayoutItems(widgets, Horizontal, bounds, margins, l.spacing, l.hwnd2StretchFactor) + layoutItems, err := boxLayoutItems(widgets, Horizontal, l.alignment, bounds, margins, l.spacing, l.hwnd2StretchFactor) if err != nil { return Size{} } @@ -258,7 +277,7 @@ func (l *FlowLayout) Update(reset bool) error { margins.VFar = 0 } - layoutItems, err := boxLayoutItems(widgets, Horizontal, bounds, margins, l.spacing, l.hwnd2StretchFactor) + layoutItems, err := boxLayoutItems(widgets, Horizontal, l.alignment, bounds, margins, l.spacing, l.hwnd2StretchFactor) if err != nil { return err } @@ -277,7 +296,7 @@ func (l *FlowLayout) Update(reset bool) error { bounds.Height = maxSecondary + margins.VNear + margins.VFar - if layoutItems, err = boxLayoutItems(widgets, Horizontal, bounds, margins, l.spacing, l.hwnd2StretchFactor); err != nil { + if layoutItems, err = boxLayoutItems(widgets, Horizontal, l.alignment, bounds, margins, l.spacing, l.hwnd2StretchFactor); err != nil { return err } diff --git a/gridlayout.go b/gridlayout.go index 313c8e60..5a3032b9 100644 --- a/gridlayout.go +++ b/gridlayout.go @@ -33,6 +33,7 @@ type GridLayout struct { container Container margins Margins spacing int + alignment Alignment2D resetNeeded bool rowStretchFactors []int columnStretchFactors []int @@ -102,6 +103,24 @@ func (l *GridLayout) SetSpacing(value int) error { return nil } +func (l *GridLayout) Alignment() Alignment2D { + return l.alignment +} + +func (l *GridLayout) SetAlignment(alignment Alignment2D) error { + if alignment != l.alignment { + if alignment < AlignHVDefault || alignment > AlignHFarVFar { + return newError("invalid Alignment value") + } + + l.alignment = alignment + + l.Update(false) + } + + return nil +} + func (l *GridLayout) sufficientStretchFactors(stretchFactors []int, required int) []int { oldLen := len(stretchFactors) if oldLen < required { @@ -595,8 +614,11 @@ func (l *GridLayout) Update(reset bool) error { } } - w := l.spannedWidth(info, widths) - h := l.spannedHeight(info, heights) + width := l.spannedWidth(info, widths) + height := l.spannedHeight(info, heights) + + w := width + h := height if lf := widget.LayoutFlags(); lf&GrowableHorz == 0 || lf&GrowableVert == 0 { s := widget.SizeHint() @@ -616,6 +638,26 @@ func (l *GridLayout) Update(reset bool) error { } } + if w != width { + switch l.alignment { + case AlignHCenterVNear, AlignHCenterVCenter, AlignHCenterVFar: + x += (width - w) / 2 + + case AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar: + x += width - w + } + } + + if h != height { + switch l.alignment { + case AlignHNearVCenter, AlignHCenterVCenter, AlignHFarVCenter: + y += (height - h) / 2 + + case AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar: + y += height - h + } + } + items = append(items, layoutResultItem{widget: widget, bounds: Rectangle{X: x, Y: y, Width: w, Height: h}}) } -- cgit v1.2.3-59-g8ed1b