forked from andlabs/ui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
table.go
90 lines (76 loc) · 3.08 KB
/
table.go
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
// 28 july 2014
package ui
import (
"fmt"
"reflect"
"sync"
)
// Table is a Control that displays a list of like-structured data in a grid where each row represents an item and each column represents a bit of data.
// Tables store and render a slice of struct values.
// Each field of the struct of type *image.RGBA is rendered as an icon.
// The Table itself will resize the image to an icon size if needed; the original *image.RGBA will not be modified and the icon size is implementation-defined.
// Each field whose type is bool or equivalent to bool is rendered as a checkbox.
// All other fields are rendered as strings formatted with package fmt's %v format specifier.
//
// Tables are read-only by default, except for checkboxes, which are user-settable.
//
// Tables have headers on top of all columns.
// By default, the name of the header is the same as the name of the field.
// If the struct field has a tag "uicolumn", its value is used as the header string instead.
//
// Tables maintain their own storage behind a sync.RWMutex-compatible sync.Locker; use Table.Lock()/Table.Unlock() to make changes and Table.RLock()/Table.RUnlock() to merely read values.
type Table interface {
Control
// Lock and Unlock lock and unlock Data for reading or writing.
// RLock and RUnlock lock and unlock Data for reading only.
// These methods have identical semantics to the analogous methods of sync.RWMutex.
// In addition, Unlock() will request an update of the Table to account for whatever was changed.
Lock()
Unlock()
RLock()
RUnlock()
// Data returns the internal data.
// The returned value will contain an object of type pointer to slice of some structure; use a type assertion to get the properly typed object out.
// Do not call this outside a Lock()..Unlock() or RLock()..RUnlock() pair.
Data() interface{}
// Selected and Select get and set the currently selected item in the Table.
// Selected returns -1 if no item is selected.
// Pass -1 to Select to deselect all items.
Selected() int
Select(index int)
// OnSelected is an event that gets triggered after the selection in the Table changes in whatever way (item selected or item deselected).
OnSelected(func())
}
type tablebase struct {
lock sync.RWMutex
data interface{}
}
// NewTable creates a new Table.
// Currently, the argument must be a reflect.Type representing the structure that each item in the Table will hold, and the Table will be initially empty.
// This will change in the future.
func NewTable(ty reflect.Type) Table {
if ty.Kind() != reflect.Struct {
panic(fmt.Errorf("unknown or unsupported type %v given to NewTable()", ty))
}
b := new(tablebase)
// we want a pointer to a slice
b.data = reflect.New(reflect.SliceOf(ty)).Interface()
return finishNewTable(b, ty)
}
func (b *tablebase) Lock() {
b.lock.Lock()
}
// Unlock() is defined on each backend implementation of Table
// they should all call this, however
func (b *tablebase) unlock() {
b.lock.Unlock()
}
func (b *tablebase) RLock() {
b.lock.RLock()
}
func (b *tablebase) RUnlock() {
b.lock.RUnlock()
}
func (b *tablebase) Data() interface{} {
return b.data
}