func (l *BoxLayout) Update(reset bool) error { if l.container == nil { return nil } if reset { l.resetNeeded = true } if l.container.Suspended() { return nil } if l.resetNeeded { l.resetNeeded = false // Make GC happy. l.cleanupStretchFactors() } // Begin by finding out which widgets we care about. widgets := l.widgets() // Prepare some useful data. var greedyNonSpacerCount int var greedySpacerCount int var stretchFactorsTotal [3]int stretchFactors := make([]int, len(widgets)) var minSizesRemaining int minSizes := make([]int, len(widgets)) maxSizes := make([]int, len(widgets)) sizes := make([]int, len(widgets)) prefSizes2 := make([]int, len(widgets)) growable2 := make([]bool, len(widgets)) sortedWidgetInfo := widgetInfoList(make([]widgetInfo, len(widgets))) for i, widget := range widgets { sf := l.hwnd2StretchFactor[widget.Handle()] if sf == 0 { sf = 1 } stretchFactors[i] = sf flags := widget.LayoutFlags() min := widget.MinSize() max := widget.MaxSize() minHint := widget.MinSizeHint() pref := widget.SizeHint() if l.orientation == Horizontal { growable2[i] = flags&GrowableVert > 0 minSizes[i] = maxi(min.Width, minHint.Width) if max.Width > 0 { maxSizes[i] = max.Width } else if pref.Width > 0 && flags&GrowableHorz == 0 { maxSizes[i] = pref.Width } else { maxSizes[i] = 32768 } prefSizes2[i] = pref.Height sortedWidgetInfo[i].greedy = flags&GreedyHorz > 0 } else { growable2[i] = flags&GrowableHorz > 0 minSizes[i] = maxi(min.Height, minHint.Height) if max.Height > 0 { maxSizes[i] = max.Height } else if pref.Height > 0 && flags&GrowableVert == 0 { maxSizes[i] = pref.Height } else { maxSizes[i] = 32768 } prefSizes2[i] = pref.Width sortedWidgetInfo[i].greedy = flags&GreedyVert > 0 } sortedWidgetInfo[i].index = i sortedWidgetInfo[i].minSize = minSizes[i] sortedWidgetInfo[i].maxSize = maxSizes[i] sortedWidgetInfo[i].stretch = sf sortedWidgetInfo[i].widget = widget minSizesRemaining += minSizes[i] if sortedWidgetInfo[i].greedy { if _, isSpacer := widget.(*Spacer); !isSpacer { greedyNonSpacerCount++ stretchFactorsTotal[0] += sf } else { greedySpacerCount++ stretchFactorsTotal[1] += sf } } else { stretchFactorsTotal[2] += sf } } sort.Sort(sortedWidgetInfo) cb := l.container.ClientBounds() var start1, start2, space1, space2 int if l.orientation == Horizontal { start1 = cb.X + l.margins.HNear start2 = cb.Y + l.margins.VNear space1 = cb.Width - l.margins.HNear - l.margins.HFar space2 = cb.Height - l.margins.VNear - l.margins.VFar } else { start1 = cb.Y + l.margins.VNear start2 = cb.X + l.margins.HNear space1 = cb.Height - l.margins.VNear - l.margins.VFar space2 = cb.Width - l.margins.HNear - l.margins.HFar } // Now calculate widget primary axis sizes. spacingRemaining := l.spacing * (len(widgets) - 1) offsets := [3]int{0, greedyNonSpacerCount, greedyNonSpacerCount + greedySpacerCount} counts := [3]int{greedyNonSpacerCount, greedySpacerCount, len(widgets) - greedyNonSpacerCount - greedySpacerCount} for i := 0; i < 3; i++ { stretchFactorsRemaining := stretchFactorsTotal[i] for j := 0; j < counts[i]; j++ { info := sortedWidgetInfo[offsets[i]+j] k := info.index stretch := stretchFactors[k] min := info.minSize max := info.maxSize size := min if min < max { excessSpace := float64(space1 - minSizesRemaining - spacingRemaining) size += int(excessSpace * float64(stretch) / float64(stretchFactorsRemaining)) if size < min { size = min } else if size > max { size = max } } sizes[k] = size minSizesRemaining -= min stretchFactorsRemaining -= stretch space1 -= (size + l.spacing) spacingRemaining -= l.spacing } } // Finally position widgets. hdwp := win.BeginDeferWindowPos(int32(len(widgets))) if hdwp == 0 { return lastError("BeginDeferWindowPos") } excessTotal := space1 - minSizesRemaining - spacingRemaining excessShare := excessTotal / (len(widgets) + 1) p1 := start1 for i, widget := range widgets { p1 += excessShare s1 := sizes[i] var s2 int if growable2[i] { s2 = space2 } else { s2 = prefSizes2[i] } p2 := start2 + (space2-s2)/2 var x, y, w, h int if l.orientation == Horizontal { x, y, w, h = p1, p2, s1, s2 } else { x, y, w, h = p2, p1, s2, s1 } if hdwp = win.DeferWindowPos( hdwp, widget.Handle(), 0, int32(x), int32(y), int32(w), int32(h), win.SWP_NOACTIVATE|win.SWP_NOOWNERZORDER|win.SWP_NOZORDER); hdwp == 0 { return lastError("DeferWindowPos") } p1 += s1 + l.spacing } if !win.EndDeferWindowPos(hdwp) { return lastError("EndDeferWindowPos") } return nil }
func (l *GridLayout) Update(reset bool) error { if l.container == nil { return nil } if reset { l.resetNeeded = true } if l.container.Suspended() { return nil } if l.resetNeeded { l.resetNeeded = false l.cleanup() } widths := l.sectionSizes(Horizontal) heights := l.sectionSizes(Vertical) hdwp := win.BeginDeferWindowPos(int32(l.container.Children().Len())) if hdwp == 0 { return lastError("BeginDeferWindowPos") } for widget, info := range l.widget2Info { x := l.margins.HNear for i := 0; i < info.cell.column; i++ { x += widths[i] + l.spacing } y := l.margins.VNear for i := 0; i < info.cell.row; i++ { y += heights[i] + l.spacing } w := 0 for i := info.cell.column; i < info.cell.column+info.spanHorz; i++ { w += widths[i] if i > info.cell.column { w += l.spacing } } h := 0 for i := info.cell.row; i < info.cell.row+info.spanVert; i++ { h += heights[i] if i > info.cell.row { h += l.spacing } } if lf := widget.LayoutFlags(); lf&GrowableHorz == 0 || lf&GrowableVert == 0 { hint := widget.SizeHint() if lf&GrowableHorz == 0 { w = hint.Width } if lf&GrowableVert == 0 { h = hint.Height } } if hdwp = win.DeferWindowPos( hdwp, widget.Handle(), 0, int32(x), int32(y), int32(w), int32(h), win.SWP_NOACTIVATE|win.SWP_NOOWNERZORDER|win.SWP_NOZORDER); hdwp == 0 { return lastError("DeferWindowPos") } } if !win.EndDeferWindowPos(hdwp) { return lastError("EndDeferWindowPos") } return nil }
func (l *splitterLayout) Update(reset bool) error { if l.container == nil { return newError("container required") } if reset { l.resetNeeded = true } if l.container.Suspended() { return nil } if l.resetNeeded { l.resetNeeded = false l.reset() } widgets := l.container.Children().items splitter := l.container.(*Splitter) handleWidth := splitter.HandleWidth() sizes := make([]int, len(widgets)) cb := splitter.ClientBounds() space1 := l.spaceForRegularWidgets() var space2 int if l.orientation == Horizontal { space2 = cb.Height } else { space2 = cb.Width } for i := range widgets { j := i/2 + i%2 if i%2 == 0 { sizes[i] = int(float64(space1) * l.fractions[j]) } else { sizes[i] = handleWidth } } hdwp := win.BeginDeferWindowPos(int32(len(widgets))) if hdwp == 0 { return lastError("BeginDeferWindowPos") } p1 := 0 for i, widget := range widgets { var s1 int if i == len(widgets)-1 { s1 = space1 + len(widgets)/2*handleWidth - p1 } else { s1 = sizes[i] } var x, y, w, h int if l.orientation == Horizontal { x, y, w, h = p1, 0, s1, space2 } else { x, y, w, h = 0, p1, space2, s1 } if hdwp = win.DeferWindowPos( hdwp, widget.Handle(), 0, int32(x), int32(y), int32(w), int32(h), win.SWP_NOACTIVATE|win.SWP_NOOWNERZORDER|win.SWP_NOZORDER); hdwp == 0 { return lastError("DeferWindowPos") } p1 += s1 } if !win.EndDeferWindowPos(hdwp) { return lastError("EndDeferWindowPos") } return nil }