aboutsummaryrefslogtreecommitdiff
path: root/lib/ui
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ui')
-rw-r--r--lib/ui/grid.go1
-rw-r--r--lib/ui/list.go110
2 files changed, 111 insertions, 0 deletions
diff --git a/lib/ui/grid.go b/lib/ui/grid.go
index 3c375ee..5fe6ab2 100644
--- a/lib/ui/grid.go
+++ b/lib/ui/grid.go
@@ -5,6 +5,7 @@ import (
"math"
)
+// A container which arranges its children on a grid.
type Grid struct {
rows []GridSpec
rowLayout []gridLayout
diff --git a/lib/ui/list.go b/lib/ui/list.go
new file mode 100644
index 0000000..58f304f
--- /dev/null
+++ b/lib/ui/list.go
@@ -0,0 +1,110 @@
+package ui
+
+import (
+ "fmt"
+)
+
+// A container which arranges its children in a list.
+type List struct {
+ Items []*ListItem
+ itemHeight int
+ onInvalidate func(d Drawable)
+ selected int
+}
+
+type ListItem struct {
+ Content Drawable
+ invalid bool
+}
+
+type SelectableDrawable interface {
+ Drawable
+ DrawWithSelected(ctx *Context, selected bool)
+}
+
+func NewList() *List {
+ return &List{itemHeight: 1, selected: -1}
+}
+
+func (list *List) OnInvalidate(onInvalidate func(d Drawable)) {
+ list.onInvalidate = onInvalidate
+}
+
+func (list *List) Invalidate() {
+ for _, item := range list.Items {
+ item.Content.Invalidate()
+ }
+ if list.onInvalidate != nil {
+ list.onInvalidate(list)
+ }
+}
+
+func (list *List) Draw(ctx *Context) {
+ for i, item := range list.Items {
+ if !item.invalid {
+ continue
+ }
+ subctx := ctx.Subcontext(0, i, ctx.Width(), list.itemHeight)
+ if content, ok := item.Content.(SelectableDrawable); ok {
+ content.DrawWithSelected(subctx, i == list.selected)
+ } else {
+ item.Content.Draw(subctx)
+ }
+ }
+}
+
+func (list *List) Add(child Drawable) {
+ list.Items = append(list.Items, &ListItem{Content: child, invalid: true})
+ child.OnInvalidate(list.childInvalidated)
+ list.Invalidate()
+}
+
+func (list *List) Remove(child Drawable) {
+ for i, item := range list.Items {
+ if item.Content == child {
+ list.Items = append(list.Items[:i], list.Items[i+1:]...)
+ child.OnInvalidate(nil)
+ list.Invalidate()
+ return
+ }
+ }
+ panic(fmt.Errorf("Attempted to remove unknown child"))
+}
+
+func (list *List) Set(items []Drawable) {
+ for _, item := range list.Items {
+ item.Content.OnInvalidate(nil)
+ }
+ list.Items = make([]*ListItem, len(items))
+ for i, item := range items {
+ list.Items[i] = &ListItem{Content: item, invalid: true}
+ item.OnInvalidate(list.childInvalidated)
+ }
+ list.Invalidate()
+}
+
+func (list *List) Select(index int) {
+ if index >= len(list.Items) || index < 0 {
+ panic(fmt.Errorf("Attempted to select unknown child"))
+ }
+ list.selected = index
+ list.Invalidate()
+}
+
+func (list *List) ItemHeight(height int) {
+ list.itemHeight = height
+ list.Invalidate()
+}
+
+func (list *List) childInvalidated(child Drawable) {
+ for _, item := range list.Items {
+ if item.Content == child {
+ item.invalid = true
+ if list.onInvalidate != nil {
+ list.onInvalidate(list)
+ }
+ return
+ }
+ }
+ panic(fmt.Errorf("Attempted to invalidate unknown child"))
+}