Did most of the GTK+ migration.
This commit is contained in:
parent
344a344abd
commit
8f1165e0c7
|
@ -34,9 +34,8 @@ import "C"
|
||||||
type area struct {
|
type area struct {
|
||||||
*areabase
|
*areabase
|
||||||
|
|
||||||
_widget *C.GtkWidget
|
*scroller
|
||||||
drawingarea *C.GtkDrawingArea
|
drawingarea *C.GtkDrawingArea
|
||||||
scroller *scroller
|
|
||||||
|
|
||||||
clickCounter *clickCounter
|
clickCounter *clickCounter
|
||||||
|
|
||||||
|
@ -59,7 +58,6 @@ func newArea(ab *areabase) Area {
|
||||||
textfieldw := C.gtk_entry_new()
|
textfieldw := C.gtk_entry_new()
|
||||||
a := &area{
|
a := &area{
|
||||||
areabase: ab,
|
areabase: ab,
|
||||||
_widget: widget,
|
|
||||||
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
||||||
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
||||||
clickCounter: new(clickCounter),
|
clickCounter: new(clickCounter),
|
||||||
|
@ -67,6 +65,7 @@ func newArea(ab *areabase) Area {
|
||||||
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
|
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
|
||||||
textfielddone: newEvent(),
|
textfielddone: newEvent(),
|
||||||
}
|
}
|
||||||
|
a.fpreferredSize = a.preferredSize
|
||||||
for _, c := range areaCallbacks {
|
for _, c := range areaCallbacks {
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
C.gpointer(unsafe.Pointer(a.drawingarea)),
|
C.gpointer(unsafe.Pointer(a.drawingarea)),
|
||||||
|
@ -492,28 +491,7 @@ var modonlykeys = map[C.guint]Modifiers{
|
||||||
C.GDK_KEY_Super_R: Super,
|
C.GDK_KEY_Super_R: Super,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) widget() *C.GtkWidget {
|
|
||||||
return a._widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) setParent(p *controlParent) {
|
|
||||||
a.scroller.setParent(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(a, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) preferredSize(d *sizing) (width, height int) {
|
func (a *area) preferredSize(d *sizing) (width, height int) {
|
||||||
// the preferred size of an Area is its size
|
// the preferred size of an Area is its size
|
||||||
return a.width, a.height
|
return a.width, a.height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) commitResize(c *allocation, d *sizing) {
|
|
||||||
a.scroller.commitResize(c, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) getAuxResizeInfo(d *sizing) {
|
|
||||||
// a Label to the left of an Area should be vertically aligned to the top
|
|
||||||
d.shouldVAlignTop = true
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
// +build !windows,!darwin
|
||||||
|
|
||||||
|
// 7 july 2014
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include "gtk_unix.h"
|
||||||
|
// extern void buttonClicked(GtkButton *, gpointer);
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type button struct {
|
||||||
|
*controlSingleWidget
|
||||||
|
button *C.GtkButton
|
||||||
|
clicked *event
|
||||||
|
}
|
||||||
|
|
||||||
|
// shared code for setting up buttons, check boxes, etc.
|
||||||
|
func newButton(text string) *button {
|
||||||
|
ctext := togstr(text)
|
||||||
|
defer freegstr(ctext)
|
||||||
|
widget := C.gtk_button_new_with_label(ctext)
|
||||||
|
b := &button{
|
||||||
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
|
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||||
|
clicked: newEvent(),
|
||||||
|
}
|
||||||
|
g_signal_connect(
|
||||||
|
C.gpointer(unsafe.Pointer(b.button)),
|
||||||
|
"clicked",
|
||||||
|
C.GCallback(C.buttonClicked),
|
||||||
|
C.gpointer(unsafe.Pointer(b)))
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *button) OnClicked(e func()) {
|
||||||
|
b.clicked.set(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *button) Text() string {
|
||||||
|
return fromgstr(C.gtk_button_get_label(b.button))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *button) SetText(text string) {
|
||||||
|
ctext := togstr(text)
|
||||||
|
defer freegstr(ctext)
|
||||||
|
C.gtk_button_set_label(b.button, ctext)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export buttonClicked
|
||||||
|
func buttonClicked(bwid *C.GtkButton, data C.gpointer) {
|
||||||
|
b := (*button)(unsafe.Pointer(data))
|
||||||
|
b.clicked.fire()
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
// +build !windows,!darwin
|
||||||
|
|
||||||
|
// 7 july 2014
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include "gtk_unix.h"
|
||||||
|
// extern void checkboxToggled(GtkToggleButton *, gpointer);
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type checkbox struct {
|
||||||
|
*controlSingleWidget
|
||||||
|
button *C.GtkButton
|
||||||
|
toggle *C.GtkToggleButton
|
||||||
|
checkbox *C.GtkCheckButton
|
||||||
|
toggled *event
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCheckbox(text string) *checkbox {
|
||||||
|
ctext := togstr(text)
|
||||||
|
defer freegstr(ctext)
|
||||||
|
widget := C.gtk_check_button_new_with_label(ctext)
|
||||||
|
c := &checkbox{
|
||||||
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
|
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||||
|
toggle: (*C.GtkToggleButton)(unsafe.Pointer(widget)),
|
||||||
|
checkbox: (*C.GtkCheckButton)(unsafe.Pointer(widget)),
|
||||||
|
toggled: newEvent(),
|
||||||
|
}
|
||||||
|
g_signal_connect(
|
||||||
|
C.gpointer(unsafe.Pointer(c.checkbox)),
|
||||||
|
"toggled",
|
||||||
|
C.GCallback(C.checkboxToggled),
|
||||||
|
C.gpointer(unsafe.Pointer(c)))
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *checkbox) OnToggled(e func()) {
|
||||||
|
c.toggled.set(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *checkbox) Text() string {
|
||||||
|
return fromgstr(C.gtk_button_get_label(c.button))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *checkbox) SetText(text string) {
|
||||||
|
ctext := togstr(text)
|
||||||
|
defer freegstr(ctext)
|
||||||
|
C.gtk_button_set_label(c.button, ctext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *checkbox) Checked() bool {
|
||||||
|
return fromgbool(C.gtk_toggle_button_get_active(c.toggle))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *checkbox) SetChecked(checked bool) {
|
||||||
|
C.gtk_toggle_button_set_active(c.toggle, togbool(checked))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export checkboxToggled
|
||||||
|
func checkboxToggled(bwid *C.GtkToggleButton, data C.gpointer) {
|
||||||
|
c := (*checkbox)(unsafe.Pointer(data))
|
||||||
|
c.toggled.fire()
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
// +build !windows,!darwin
|
||||||
|
|
||||||
|
// 23 february 2014
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include "gtk_unix.h"
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type container struct {
|
||||||
|
*controlSingleWidget
|
||||||
|
container *C.GtkContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
type sizing struct {
|
||||||
|
sizingbase
|
||||||
|
|
||||||
|
// for size calculations
|
||||||
|
// gtk+ needs nothing
|
||||||
|
|
||||||
|
// for the actual resizing
|
||||||
|
// gtk+ needs nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
func newContainer() *container {
|
||||||
|
c := new(container)
|
||||||
|
c.controlSingleWidget = newControlSingleWidget(C.newContainer(unsafe.Pointer(c)))
|
||||||
|
c.container = (*C.GtkContainer)(unsafe.Pointer(c.widget))
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *container) parent() *controlParent {
|
||||||
|
return &controlParent{c.container}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
gtkXMargin = 12
|
||||||
|
gtkYMargin = 12
|
||||||
|
gtkXPadding = 12
|
||||||
|
gtkYPadding = 6
|
||||||
|
)
|
||||||
|
|
||||||
|
func (w *window) beginResize() (d *sizing) {
|
||||||
|
d = new(sizing)
|
||||||
|
if spaced {
|
||||||
|
d.xmargin = gtkXMargin
|
||||||
|
d.ymargintop = gtkYMargin
|
||||||
|
d.ymarginbottom = d.ymargintop
|
||||||
|
d.xpadding = gtkXPadding
|
||||||
|
d.ypadding = gtkYPadding
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
// +build !windows,!darwin
|
||||||
|
|
||||||
|
// 7 july 2014
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include "gtk_unix.h"
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type label struct {
|
||||||
|
*controlSingleWidget
|
||||||
|
misc *C.GtkMisc
|
||||||
|
label *C.GtkLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLabel(text string) Label {
|
||||||
|
ctext := togstr(text)
|
||||||
|
defer freegstr(ctext)
|
||||||
|
widget := C.gtk_label_new(ctext)
|
||||||
|
l := &label{
|
||||||
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
|
misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
|
||||||
|
label: (*C.GtkLabel)(unsafe.Pointer(widget)),
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TODO
|
||||||
|
func newStandaloneLabel(text string) Label {
|
||||||
|
l := finishNewLabel(text, true)
|
||||||
|
// standalone labels are always at the top left
|
||||||
|
C.gtk_misc_set_alignment(l.misc, 0, 0)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (l *label) Text() string {
|
||||||
|
return fromgstr(C.gtk_label_get_text(l.label))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *label) SetText(text string) {
|
||||||
|
ctext := togstr(text)
|
||||||
|
defer freegstr(ctext)
|
||||||
|
C.gtk_label_set_text(l.label, ctext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TODO
|
||||||
|
func (l *label) commitResize(c *allocation, d *sizing) {
|
||||||
|
if !l.standalone && c.neighbor != nil {
|
||||||
|
c.neighbor.getAuxResizeInfo(d)
|
||||||
|
if d.shouldVAlignTop {
|
||||||
|
// don't bother aligning it to the first line of text in the control; this is harder than it's worth (thanks gregier in irc.gimp.net/#gtk+)
|
||||||
|
C.gtk_misc_set_alignment(l.misc, 0, 0)
|
||||||
|
} else {
|
||||||
|
C.gtk_misc_set_alignment(l.misc, 0, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
basecommitResize(l, c, d)
|
||||||
|
}
|
||||||
|
*/
|
|
@ -0,0 +1,222 @@
|
||||||
|
// +build !windows,!darwin
|
||||||
|
|
||||||
|
// 29 july 2014
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include "gtk_unix.h"
|
||||||
|
// extern void goTableModel_toggled(GtkCellRendererToggle *, gchar *, gpointer);
|
||||||
|
// extern void tableSelectionChanged(GtkTreeSelection *, gpointer);
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type table struct {
|
||||||
|
*tablebase
|
||||||
|
|
||||||
|
*scroller
|
||||||
|
treeview *C.GtkTreeView
|
||||||
|
|
||||||
|
model *C.goTableModel
|
||||||
|
modelgtk *C.GtkTreeModel
|
||||||
|
selection *C.GtkTreeSelection
|
||||||
|
|
||||||
|
pixbufs []*C.GdkPixbuf
|
||||||
|
|
||||||
|
selected *event
|
||||||
|
|
||||||
|
// stuff required by GtkTreeModel
|
||||||
|
nColumns C.gint
|
||||||
|
old C.gint
|
||||||
|
types []C.GType
|
||||||
|
crtocol map[*C.GtkCellRendererToggle]int
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
attribText = togstr("text")
|
||||||
|
attribPixbuf = togstr("pixbuf")
|
||||||
|
attribActive = togstr("active")
|
||||||
|
)
|
||||||
|
|
||||||
|
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||||
|
widget := C.gtk_tree_view_new()
|
||||||
|
t := &table{
|
||||||
|
scroller: newScroller(widget, true, true, false), // natively scrollable; has a border; no overlay
|
||||||
|
tablebase: b,
|
||||||
|
treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)),
|
||||||
|
crtocol: make(map[*C.GtkCellRendererToggle]int),
|
||||||
|
selected: newEvent(),
|
||||||
|
}
|
||||||
|
model := C.newTableModel(unsafe.Pointer(t))
|
||||||
|
t.model = model
|
||||||
|
t.modelgtk = (*C.GtkTreeModel)(unsafe.Pointer(model))
|
||||||
|
t.selection = C.gtk_tree_view_get_selection(t.treeview)
|
||||||
|
g_signal_connect(
|
||||||
|
C.gpointer(unsafe.Pointer(t.selection)),
|
||||||
|
"changed",
|
||||||
|
C.GCallback(C.tableSelectionChanged),
|
||||||
|
C.gpointer(unsafe.Pointer(t)))
|
||||||
|
C.gtk_tree_view_set_model(t.treeview, t.modelgtk)
|
||||||
|
for i := 0; i < ty.NumField(); i++ {
|
||||||
|
cname := togstr(ty.Field(i).Name)
|
||||||
|
switch {
|
||||||
|
case ty.Field(i).Type == reflect.TypeOf(ImageIndex(0)):
|
||||||
|
// can't use GDK_TYPE_PIXBUF here because it's a macro that expands to a function and cgo hates that
|
||||||
|
t.types = append(t.types, C.gdk_pixbuf_get_type())
|
||||||
|
C.tableAppendColumn(t.treeview, C.gint(i), cname,
|
||||||
|
C.gtk_cell_renderer_pixbuf_new(), attribPixbuf)
|
||||||
|
case ty.Field(i).Type.Kind() == reflect.Bool:
|
||||||
|
t.types = append(t.types, C.G_TYPE_BOOLEAN)
|
||||||
|
cr := C.gtk_cell_renderer_toggle_new()
|
||||||
|
crt := (*C.GtkCellRendererToggle)(unsafe.Pointer(cr))
|
||||||
|
t.crtocol[crt] = i
|
||||||
|
g_signal_connect(C.gpointer(unsafe.Pointer(cr)),
|
||||||
|
"toggled",
|
||||||
|
C.GCallback(C.goTableModel_toggled),
|
||||||
|
C.gpointer(unsafe.Pointer(t)))
|
||||||
|
C.tableAppendColumn(t.treeview, C.gint(i), cname,
|
||||||
|
cr, attribActive)
|
||||||
|
default:
|
||||||
|
t.types = append(t.types, C.G_TYPE_STRING)
|
||||||
|
C.tableAppendColumn(t.treeview, C.gint(i), cname,
|
||||||
|
C.gtk_cell_renderer_text_new(), attribText)
|
||||||
|
}
|
||||||
|
freegstr(cname) // free now (not deferred) to conserve memory
|
||||||
|
}
|
||||||
|
// and for some GtkTreeModel boilerplate
|
||||||
|
t.nColumns = C.gint(ty.NumField())
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *table) Lock() {
|
||||||
|
t.tablebase.Lock()
|
||||||
|
d := reflect.Indirect(reflect.ValueOf(t.data))
|
||||||
|
t.old = C.gint(d.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *table) Unlock() {
|
||||||
|
t.unlock()
|
||||||
|
// there's a possibility that user actions can happen at this point, before the view is updated
|
||||||
|
// alas, this is something we have to deal with, because Unlock() can be called from any thread
|
||||||
|
go func() {
|
||||||
|
Do(func() {
|
||||||
|
t.RLock()
|
||||||
|
defer t.RUnlock()
|
||||||
|
d := reflect.Indirect(reflect.ValueOf(t.data))
|
||||||
|
new := C.gint(d.Len())
|
||||||
|
C.tableUpdate(t.model, t.old, new)
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *table) LoadImageList(i ImageList) {
|
||||||
|
i.apply(&t.pixbufs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *table) Selected() int {
|
||||||
|
var iter C.GtkTreeIter
|
||||||
|
|
||||||
|
t.RLock()
|
||||||
|
defer t.RUnlock()
|
||||||
|
if C.gtk_tree_selection_get_selected(t.selection, nil, &iter) == C.FALSE {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
path := C.gtk_tree_model_get_path(t.modelgtk, &iter)
|
||||||
|
if path == nil {
|
||||||
|
panic(fmt.Errorf("invalid iter in Table.Selected()"))
|
||||||
|
}
|
||||||
|
defer C.gtk_tree_path_free(path)
|
||||||
|
return int(*C.gtk_tree_path_get_indices(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *table) Select(index int) {
|
||||||
|
t.RLock()
|
||||||
|
defer t.RUnlock()
|
||||||
|
C.gtk_tree_selection_unselect_all(t.selection)
|
||||||
|
if index == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
path := C.gtk_tree_path_new()
|
||||||
|
defer C.gtk_tree_path_free(path)
|
||||||
|
C.gtk_tree_path_append_index(path, C.gint(index))
|
||||||
|
C.gtk_tree_selection_select_path(t.selection, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *table) OnSelected(f func()) {
|
||||||
|
t.selected.set(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goTableModel_get_n_columns
|
||||||
|
func goTableModel_get_n_columns(model *C.GtkTreeModel) C.gint {
|
||||||
|
tm := (*C.goTableModel)(unsafe.Pointer(model))
|
||||||
|
t := (*table)(tm.gotable)
|
||||||
|
return t.nColumns
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goTableModel_get_column_type
|
||||||
|
func goTableModel_get_column_type(model *C.GtkTreeModel, column C.gint) C.GType {
|
||||||
|
tm := (*C.goTableModel)(unsafe.Pointer(model))
|
||||||
|
t := (*table)(tm.gotable)
|
||||||
|
return t.types[column]
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goTableModel_do_get_value
|
||||||
|
func goTableModel_do_get_value(data unsafe.Pointer, row C.gint, col C.gint, value *C.GValue) {
|
||||||
|
t := (*table)(data)
|
||||||
|
t.RLock()
|
||||||
|
defer t.RUnlock()
|
||||||
|
d := reflect.Indirect(reflect.ValueOf(t.data))
|
||||||
|
datum := d.Index(int(row)).Field(int(col))
|
||||||
|
switch {
|
||||||
|
case datum.Type() == reflect.TypeOf(ImageIndex(0)):
|
||||||
|
d := datum.Interface().(ImageIndex)
|
||||||
|
C.g_value_init(value, C.gdk_pixbuf_get_type())
|
||||||
|
C.g_value_set_object(value, C.gpointer(unsafe.Pointer(t.pixbufs[d])))
|
||||||
|
case datum.Kind() == reflect.Bool:
|
||||||
|
d := datum.Interface().(bool)
|
||||||
|
C.g_value_init(value, C.G_TYPE_BOOLEAN)
|
||||||
|
C.g_value_set_boolean(value, togbool(d))
|
||||||
|
default:
|
||||||
|
s := fmt.Sprintf("%v", datum)
|
||||||
|
str := togstr(s)
|
||||||
|
defer freegstr(str)
|
||||||
|
C.g_value_init(value, C.G_TYPE_STRING)
|
||||||
|
C.g_value_set_string(value, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goTableModel_getRowCount
|
||||||
|
func goTableModel_getRowCount(data unsafe.Pointer) C.gint {
|
||||||
|
t := (*table)(data)
|
||||||
|
t.RLock()
|
||||||
|
defer t.RUnlock()
|
||||||
|
d := reflect.Indirect(reflect.ValueOf(t.data))
|
||||||
|
return C.gint(d.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goTableModel_toggled
|
||||||
|
func goTableModel_toggled(cr *C.GtkCellRendererToggle, pathstr *C.gchar, data C.gpointer) {
|
||||||
|
t := (*table)(unsafe.Pointer(data))
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
path := C.gtk_tree_path_new_from_string(pathstr)
|
||||||
|
if len := C.gtk_tree_path_get_depth(path); len != 1 {
|
||||||
|
panic(fmt.Errorf("invalid path of depth %d given to goTableModel_toggled()", len))
|
||||||
|
}
|
||||||
|
// dereference return value to get our sole member
|
||||||
|
row := *C.gtk_tree_path_get_indices(path)
|
||||||
|
col := t.crtocol[cr]
|
||||||
|
d := reflect.Indirect(reflect.ValueOf(t.data))
|
||||||
|
datum := d.Index(int(row)).Field(int(col))
|
||||||
|
datum.SetBool(!datum.Bool())
|
||||||
|
}
|
||||||
|
|
||||||
|
//export tableSelectionChanged
|
||||||
|
func tableSelectionChanged(sel *C.GtkTreeSelection, data C.gpointer) {
|
||||||
|
t := (*table)(unsafe.Pointer(data))
|
||||||
|
t.selected.fire()
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
// +build !windows,!darwin
|
||||||
|
|
||||||
|
// 7 july 2014
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include "gtk_unix.h"
|
||||||
|
// extern void textfieldChanged(GtkEditable *, gpointer);
|
||||||
|
// /* because cgo doesn't like GTK_STOCK_DIALOG_ERROR */
|
||||||
|
// static inline void setErrorIcon(GtkEntry *entry)
|
||||||
|
// {
|
||||||
|
// gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR);
|
||||||
|
// }
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type textfield struct {
|
||||||
|
*controlSingleWidget
|
||||||
|
entry *C.GtkEntry
|
||||||
|
changed *event
|
||||||
|
}
|
||||||
|
|
||||||
|
func startNewTextField() *textfield {
|
||||||
|
widget := C.gtk_entry_new()
|
||||||
|
t := &textfield{
|
||||||
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
|
entry: (*C.GtkEntry)(unsafe.Pointer(widget)),
|
||||||
|
changed: newEvent(),
|
||||||
|
}
|
||||||
|
g_signal_connect(
|
||||||
|
C.gpointer(unsafe.Pointer(t._widget)),
|
||||||
|
"changed",
|
||||||
|
C.GCallback(C.textfieldChanged),
|
||||||
|
C.gpointer(unsafe.Pointer(t)))
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTextField() *textfield {
|
||||||
|
return startNewTextField()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPasswordField() *textfield {
|
||||||
|
t := startNewTextField()
|
||||||
|
C.gtk_entry_set_visibility(t.entry, C.FALSE)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *textfield) Text() string {
|
||||||
|
return fromgstr(C.gtk_entry_get_text(t.entry))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *textfield) SetText(text string) {
|
||||||
|
ctext := togstr(text)
|
||||||
|
defer freegstr(ctext)
|
||||||
|
C.gtk_entry_set_text(t.entry, ctext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *textfield) OnChanged(f func()) {
|
||||||
|
t.changed.set(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *textfield) Invalid(reason string) {
|
||||||
|
if reason == "" {
|
||||||
|
C.gtk_entry_set_icon_from_stock(t.entry, C.GTK_ENTRY_ICON_SECONDARY, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
C.setErrorIcon(t.entry)
|
||||||
|
creason := togstr(reason)
|
||||||
|
defer freegstr(creason)
|
||||||
|
C.gtk_entry_set_icon_tooltip_text(t.entry, C.GTK_ENTRY_ICON_SECONDARY, creason)
|
||||||
|
C.gtk_widget_error_bell(t._widget)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export textfieldChanged
|
||||||
|
func textfieldChanged(editable *C.GtkEditable, data C.gpointer) {
|
||||||
|
t := (*textfield)(unsafe.Pointer(data))
|
||||||
|
t.changed.fire()
|
||||||
|
}
|
Loading…
Reference in New Issue