summaryrefslogtreecommitdiff
path: root/BBB_GOFILES/tablemodel.go
blob: b4ca7a4c1fcb7180dd38bee9d29a66a02a17d893 (plain)
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
// 24 august 2018

package ui

// #include "ui.h"
// extern int doTableModelNumColumns(uiTableModelHandler *, uiTableModel *);
// extern uiTableValueType doTableModelColumnType(uiTableModelHandler *, uiTableModel *, int);
// extern int doTableModelNumRows(uiTableModelHandler *, uiTableModel *);
// extern uiTableValue *doTableModelCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column);
// extern void doTableModelSetCellValue(uiTableModelHandler *, uiTableModel *, int, int, uiTableValue *);
// // deal with cgo being dumb
// static inline void realDoTableModelSetCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, const uiTableValue *value)
// {
// 	doTableModelSetCellValue(mh, m, row, column, (uiTableValue *) value);
// }
// // TODO why can't this be static?
// const uiTableModelHandler pkguiTableModelHandler = {
// 	.NumColumns = doTableModelNumColumns,
// 	.ColumnType = doTableModelColumnType,
// 	.NumRows = doTableModelNumRows,
// 	.CellValue = doTableModelCellValue,
// 	.SetCellValue = realDoTableModelSetCellValue,
// };
import "C"

// TableValue is a type that represents a piece of data that can come
// out of a TableModel.
type TableValue interface {
	toLibui() *C.uiTableValue
}

// TableString is a TableValue that stores a string. TableString is
// used for displaying text in a Table.
type TableString string

func (s TableString) toLibui() *C.uiTableValue {
	cs := C.CString(string(s))
	defer freestr(cs)
	return C.uiNewTableValueString(cs)
}

// TableImage is a TableValue that represents an Image. Ownership
// of the Image is not copied; you must keep it alive alongside the
// TableImage.
type TableImage struct {
	I	*Image
}

func (i TableImage) toLibui() *C.uiTableValue {
	return C.uiNewTableValueImage(i.I.i)
}

// TableInt is a TableValue that stores integers. These are used for
// progressbars. Due to current limitations of libui, they also
// represent checkbox states, via TableFalse and TableTrue.
type TableInt int

// TableFalse and TableTrue are the Boolean constants for TableInt.
const (
	TableFalse TableInt = 0
	TableTrue TableInt = 1
)

func (i TableInt) toLibui() *C.uiTableValue {
	return C.uiNewTableValueInt(C.int(i))
}

// TableColor is a TableValue that represents a color.
type TableColor struct {
	R	float64
	G	float64
	B	float64
	A	float64
}

func (c TableColor) toLibui() *C.uiTableValue {
	return C.uiNewTableValueColor(C.double(c.R), C.double(c.G), C.double(c.B), C.double(c.A))
}

func tableValueFromLibui(value *C.uiTableValue) TableValue {
	if value == nil {
		return nil
	}
	switch C.uiTableValueGetType(value) {
	case C.uiTableValueTypeString:
		cs := C.uiTableValueString(value)
		return TableString(C.GoString(cs))
	case C.uiTableValueTypeImage:
		panic("TODO")
	case C.uiTableValueTypeInt:
		return TableInt(C.uiTableValueInt(value))
	case C.uiTableValueTypeColor:
		panic("TODO")
	}
	panic("unreachable")
}

// no need to lock these; only the GUI thread can access them
var modelhandlers = make(map[*C.uiTableModel]TableModelHandler)
var models = make(map[*C.uiTableModel]*TableModel)

// TableModel is an object that provides the data for a Table.
// This data is returned via methods you provide in the
// TableModelHandler interface.
//
// TableModel represents data using a table, but this table does
// not map directly to Table itself. Instead, you can have data
// columns which provide instructions for how to render a given
// Table's column — for instance, one model column can be used
// to give certain rows of a Table a different background color.
// Row numbers DO match with uiTable row numbers.
//
// Once created, the number and data types of columns of a
// TableModel cannot change.
//
// Row and column numbers start at 0. A TableModel can be
// associated with more than one Table at a time.
type TableModel struct {
	m	*C.uiTableModel
}

// TableModelHandler defines the methods that TableModel
// calls when it needs data.
type TableModelHandler interface {
	// ColumnTypes returns a slice of value types of the data
	// stored in the model columns of the TableModel.
	// Each entry in the slice should ideally be a zero value for
	// the TableValue type of the column in question; the number
	// of elements in the slice determines the number of model
	// columns in the TableModel. The returned slice must remain
	// constant through the lifetime of the TableModel. This
	// method is not guaranteed to be called depending on the
	// system.
	ColumnTypes(m *TableModel) []TableValue

	// NumRows returns the number or rows in the TableModel.
	// This value must be non-negative.
	NumRows(m *TableModel) int

	// CellValue returns a TableValue corresponding to the model
	// cell at (row, column). The type of the returned TableValue
	// must match column's value type. Under some circumstances,
	// nil may be returned; refer to the various methods that add
	// columns to Table for details.
	CellValue(m *TableModel, row, column int) TableValue

	// SetCellValue changes the model cell value at (row, column)
	// in the TableModel. Within this function, either do nothing
	// to keep the current cell value or save the new cell value as
	// appropriate. After SetCellValue is called, the Table will
	// itself reload the table cell. Under certain conditions, the
	// TableValue passed in can be nil; refer to the various
	// methods that add columns to Table for details.
	SetCellValue(m *TableModel, row, column int, value TableValue)
}

//export doTableModelNumColumns
func doTableModelNumColumns(umh *C.uiTableModelHandler, um *C.uiTableModel) C.int {
	mh := modelhandlers[um]
	return C.int(len(mh.ColumnTypes(models[um])))
}

//export doTableModelColumnType
func doTableModelColumnType(umh *C.uiTableModelHandler, um *C.uiTableModel, n C.int) C.uiTableValueType {
	mh := modelhandlers[um]
	c := mh.ColumnTypes(models[um])
	switch c[n].(type) {
	case TableString:
		return C.uiTableValueTypeString
	case TableImage:
		return C.uiTableValueTypeImage
	case TableInt:
		return C.uiTableValueTypeInt
	case TableColor:
		return C.uiTableValueTypeColor
	}
	panic("unreachable")
}

//export doTableModelNumRows
func doTableModelNumRows(umh *C.uiTableModelHandler, um *C.uiTableModel) C.int {
	mh := modelhandlers[um]
	return C.int(mh.NumRows(models[um]))
}

//export doTableModelCellValue
func doTableModelCellValue(umh *C.uiTableModelHandler, um *C.uiTableModel, row, column C.int) *C.uiTableValue {
	mh := modelhandlers[um]
	v := mh.CellValue(models[um], int(row), int(column))
	if v == nil {
		return nil
	}
	return v.toLibui()
}

//export doTableModelSetCellValue
func doTableModelSetCellValue(umh *C.uiTableModelHandler, um *C.uiTableModel, row, column C.int, value *C.uiTableValue) {
	mh := modelhandlers[um]
	v := tableValueFromLibui(value)
	mh.SetCellValue(models[um], int(row), int(column), v)
}

// NewTableModel creates a new TableModel.
func NewTableModel(handler TableModelHandler) *TableModel {
	m := &TableModel{
		m:	C.uiNewTableModel(&C.pkguiTableModelHandler),
	}
	modelhandlers[m.m] = handler
	models[m.m] = m
	return m
}

// Free frees m. It is an error to Free any models associated with a
// Table.
func (m *TableModel) Free() {
	delete(models, m.m)
	delete(modelhandlers, m.m)
	C.uiFreeTableModel(m.m)
}

// RowInserted tells any Tables associated with m that a new row
// has been added to m at index index. You call this method when
// the number of rows in your model has changed; after calling it,
// NumRows should returm the new row count.
func (m *TableModel) RowInserted(index int) {
	C.uiTableModelRowInserted(m.m, C.int(index))
}

// RowChanged tells any Tables associated with m that the data in
// the row at index has changed. You do not need to call this in
// your SetCellValue handlers, but you do need to call this if your
// data changes at some other point.
func (m *TableModel) RowChanged(index int) {
	C.uiTableModelRowChanged(m.m, C.int(index))
}

// RowDeleted tells any Tables associated with m that the row at
// index index has been deleted. You call this function when the
// number of rows in your model has changed; after calling it,
// NumRows should returm the new row count.
func (m *TableModel) RowDeleted(index int) {
	C.uiTableModelRowDeleted(m.m, C.int(index))
}