~pierrec/giox

ref: c164e218831e giox/widgetx/select.go -rw-r--r-- 2.4 KiB
c164e218Pierre Curto cm/iconx: update the set of icons 10 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package widgetx

import (
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/widget"
)

// Select displays a single value that can be selected from a set of values.
type Select struct {
	// Above displays the list above the selected item.
	// By default it is displayed below.
	Above bool

	opened   bool
	selected int
	click    widget.Clickable // open/close list
	list     layout.List      // drop down list
	clicks   []widget.Clickable
}

func (s *Select) init(n int) {
	s.list.Axis = layout.Vertical
	s.clicks = initClicks(s.clicks, n)
}

func (s *Select) update() {
	if s.click.Clicked() {
		s.opened = !s.opened
	}
	if s.opened {
		for i := range s.clicks {
			for s.clicks[i].Clicked() {
				s.selected = i
				s.opened = false
			}
		}
	}
}

func (s *Select) layoutSelection(gtx layout.Context, el ClickElement) layout.Dimensions {
	return s.click.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
		return el(gtx, s.selected, &s.click)
	})
}

func (s *Select) layoutList(gtx layout.Context, n int, el ClickElement) layout.Dimensions {
	return s.list.Layout(gtx, n, func(gtx layout.Context, i int) layout.Dimensions {
		gtx.Constraints.Min.X = gtx.Constraints.Max.X
		click := &s.clicks[i]
		return click.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
			return el(gtx, i, click)
		})
	})
}

// Layout displays the currently selected element within the minimum constraints and
// the list of elements within the maximum constraints if opened.
func (s *Select) Layout(gtx layout.Context, n int, el ClickElement) layout.Dimensions {
	s.init(n)
	s.update()
	if n == 0 {
		return layout.Dimensions{Size: gtx.Constraints.Min}
	}
	if !s.opened {
		return s.layoutSelection(gtx, el)
	}

	// When the list is opened, defer the layout so that it is written
	// on top of the window.
	child1 := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
		return s.layoutSelection(gtx, el)
	})
	child2 := layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
		return s.layoutList(gtx, n, el)
	})
	if s.Above {
		child1, child2 = child2, child1
	}

	macro := op.Record(gtx.Ops)
	layout.Flex{
		Axis: layout.Vertical,
	}.Layout(gtx, child1, child2)
	op.Defer(gtx.Ops, macro.Stop())

	return layout.Dimensions{Size: gtx.Constraints.Min}
}

// Selected returns the index of the selected entry.
func (s *Select) Selected() int {
	return s.selected
}

func (s *Select) Opened() bool {
	s.update()
	return s.opened
}