Example #1
0
File: list.go Project: nelsam/gxui
func (l *List) LayoutChildren() {
	if l.adapter == nil {
		l.outer.RemoveAll()
		return
	}

	if !l.RelayoutSuspended() {
		// Disable relayout on AddChild / RemoveChild as we're performing layout here.
		l.SetRelayoutSuspended(true)
		defer l.SetRelayoutSuspended(false)
	}

	s := l.outer.Size().Contract(l.Padding())
	o := l.Padding().LT()

	var itemSize math.Size
	if l.orientation.Horizontal() {
		itemSize = math.Size{W: l.itemSize.W, H: s.H}
	} else {
		itemSize = math.Size{W: s.W, H: l.itemSize.H}
	}

	startIndex, endIndex := l.VisibleItemRange(true)
	majorAxisItemSize := l.MajorAxisItemSize()

	d := startIndex*majorAxisItemSize - l.scrollOffset

	mark := l.layoutMark
	l.layoutMark++

	for idx := startIndex; idx < endIndex; idx++ {
		item := l.adapter.ItemAt(idx)

		details, found := l.details[item]
		if found {
			if details.mark == mark {
				panic(fmt.Errorf("Adapter for control '%s' returned duplicate item (%v) for indices %v and %v",
					gxui.Path(l.outer), item, details.index, idx))
			}
		} else {
			control := l.adapter.Create(l.theme, idx)
			details.onClickSubscription = control.OnClick(func(ev gxui.MouseEvent) {
				l.ItemClicked(ev, item)
			})
			details.child = l.AddChildAt(0, control)
		}
		details.mark = mark
		details.index = idx
		l.details[item] = details

		c := details.child
		cm := c.Control.Margin()
		cs := itemSize.Contract(cm).Max(math.ZeroSize)
		if l.orientation.Horizontal() {
			c.Layout(math.CreateRect(d, cm.T, d+cs.W, cm.T+cs.H).Offset(o))
		} else {
			c.Layout(math.CreateRect(cm.L, d, cm.L+cs.W, d+cs.H).Offset(o))
		}
		d += majorAxisItemSize
	}

	// Reap unused items
	for item, details := range l.details {
		if details.mark != mark {
			details.onClickSubscription.Unlisten()
			l.RemoveChild(details.child.Control)
			delete(l.details, item)
		}
	}

	if l.scrollBarEnabled {
		ss := l.scrollBar.DesiredSize(math.ZeroSize, s)
		if l.Orientation().Horizontal() {
			l.scrollBarChild.Layout(math.CreateRect(0, s.H-ss.H, s.W, s.H).Canon().Offset(o))
		} else {
			l.scrollBarChild.Layout(math.CreateRect(s.W-ss.W, 0, s.W, s.H).Canon().Offset(o))
		}

		// Only show the scroll bar if needed
		entireContentVisible := startIndex == 0 && endIndex == l.itemCount
		l.scrollBar.SetVisible(!entireContentVisible)
	}

	l.UpdateItemMouseOver()
}