예제 #1
0
파일: boxlayout.go 프로젝트: kumakichi/walk
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
}
예제 #2
0
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
}
예제 #3
0
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
}