111 lines
2.3 KiB
Go
111 lines
2.3 KiB
Go
|
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"))
|
||
|
}
|