Applied the new Control system to the GTK+ backend.

This commit is contained in:
Pietro Gagliardi 2014-07-30 10:21:23 -04:00
parent 210102fe95
commit 4740f72efb
5 changed files with 133 additions and 124 deletions

View File

@ -16,38 +16,8 @@ import "C"
// TODOs: // TODOs:
// - standalone label on its own: should it be centered or not? // - standalone label on its own: should it be centered or not?
type widgetbase struct {
widget *C.GtkWidget
}
func newWidget(w *C.GtkWidget) *widgetbase {
return &widgetbase{
widget: w,
}
}
// these few methods are embedded by all the various Controls since they all will do the same thing
type controlParent struct {
c *C.GtkContainer
}
func (w *widgetbase) setParent(c *controlParent) {
C.gtk_container_add(c.c, w.widget)
// make sure the new widget is shown
C.gtk_widget_show_all(w.widget)
}
func (w *widgetbase) containerShow() {
C.gtk_widget_show_all(w.widget)
}
func (w *widgetbase) containerHide() {
C.gtk_widget_hide(w.widget)
}
type button struct { type button struct {
*widgetbase *controlbase
button *C.GtkButton button *C.GtkButton
clicked *event clicked *event
} }
@ -55,7 +25,7 @@ type button struct {
// shared code for setting up buttons, check boxes, etc. // shared code for setting up buttons, check boxes, etc.
func finishNewButton(widget *C.GtkWidget, event string, handler unsafe.Pointer) *button { func finishNewButton(widget *C.GtkWidget, event string, handler unsafe.Pointer) *button {
b := &button{ b := &button{
widgetbase: newWidget(widget), controlbase: newControl(widget),
button: (*C.GtkButton)(unsafe.Pointer(widget)), button: (*C.GtkButton)(unsafe.Pointer(widget)),
clicked: newEvent(), clicked: newEvent(),
} }
@ -129,14 +99,14 @@ func (c *checkbox) SetChecked(checked bool) {
} }
type textField struct { type textField struct {
*widgetbase *controlbase
entry *C.GtkEntry entry *C.GtkEntry
} }
func startNewTextField() *textField { func startNewTextField() *textField {
w := C.gtk_entry_new() w := C.gtk_entry_new()
return &textField{ return &textField{
widgetbase: newWidget(w), controlbase: newControl(w),
entry: (*C.GtkEntry)(unsafe.Pointer(w)), entry: (*C.GtkEntry)(unsafe.Pointer(w)),
} }
} }
@ -162,22 +132,26 @@ func (t *textField) SetText(text string) {
} }
type label struct { type label struct {
*widgetbase *controlbase
misc *C.GtkMisc misc *C.GtkMisc
label *C.GtkLabel label *C.GtkLabel
standalone bool standalone bool
supercommitResize func(c *allocation, d *sizing)
} }
func finishNewLabel(text string, standalone bool) *label { func finishNewLabel(text string, standalone bool) *label {
ctext := togstr(text) ctext := togstr(text)
defer freegstr(ctext) defer freegstr(ctext)
widget := C.gtk_label_new(ctext) widget := C.gtk_label_new(ctext)
return &label{ l := &label{
widgetbase: newWidget(widget), controlbase: newControl(widget),
misc: (*C.GtkMisc)(unsafe.Pointer(widget)), misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
label: (*C.GtkLabel)(unsafe.Pointer(widget)), label: (*C.GtkLabel)(unsafe.Pointer(widget)),
standalone: standalone, standalone: standalone,
} }
l.supercommitResize = l.fcommitResize
l.fcommitResize = l.labelcommitResize
return l
} }
func newLabel(text string) Label { func newLabel(text string) Label {
@ -198,7 +172,7 @@ func (l *label) SetText(text string) {
C.gtk_label_set_text(l.label, ctext) C.gtk_label_set_text(l.label, ctext)
} }
func (l *label) commitResize(c *allocation, d *sizing) { func (l *label) labelcommitResize(c *allocation, d *sizing) {
if !l.standalone && c.neighbor != nil { if !l.standalone && c.neighbor != nil {
c.neighbor.getAuxResizeInfo(d) c.neighbor.getAuxResizeInfo(d)
if d.shouldVAlignTop { if d.shouldVAlignTop {
@ -208,5 +182,5 @@ func (l *label) commitResize(c *allocation, d *sizing) {
C.gtk_misc_set_alignment(l.misc, 0, 0.5) C.gtk_misc_set_alignment(l.misc, 0, 0.5)
} }
} }
l.widgetbase.commitResize(c, d) l.supercommitResize(c, d)
} }

View File

@ -13,7 +13,7 @@ import (
import "C" import "C"
type tab struct { type tab struct {
*widgetbase *controlbase
notebook *C.GtkNotebook notebook *C.GtkNotebook
containers []*container containers []*container
@ -25,7 +25,7 @@ type tab struct {
func newTab() Tab { func newTab() Tab {
widget := C.gtk_notebook_new() widget := C.gtk_notebook_new()
t := &tab{ t := &tab{
widgetbase: newWidget(widget), controlbase: newControl(widget),
notebook: (*C.GtkNotebook)(unsafe.Pointer(widget)), notebook: (*C.GtkNotebook)(unsafe.Pointer(widget)),
} }
// there are no scrolling arrows by default; add them in case there are too many tabs // there are no scrolling arrows by default; add them in case there are too many tabs
@ -58,10 +58,7 @@ func (t *tab) Append(name string, control Control) {
} }
} }
func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation { // no need to override Control.allocate() as only prepared the tabbed control; its children will be reallocated when that one is resized
// only prepared the tabbed control; its children will be reallocated when that one is resized
return t.widgetbase.allocate(x, y, width, height, d)
}
//export layoutResizing //export layoutResizing
func layoutResizing(wid *C.GtkWidget, r *C.GdkRectangle, data C.gpointer) { func layoutResizing(wid *C.GtkWidget, r *C.GdkRectangle, data C.gpointer) {

112
redo/control_unix.go Normal file
View File

@ -0,0 +1,112 @@
// +build !windows,!darwin
// 30 july 2014
package ui
import (
"unsafe"
)
// #include "gtk_unix.h"
import "C"
type controlbase struct {
*controldefs
widget *C.GtkWidget
}
type controlParent struct {
c *C.GtkContainer
}
func newControl(widget *C.GtkWidget) *controlbase {
c := new(controlbase)
c.widget = widget
c.controldefs = new(controldefs)
c.fsetParent = func(p *controlParent) {
C.gtk_container_add(p.c, c.widget)
// make sure the new widget is shown if not explicitly hidden
c.containerShow()
}
c.fcontainerShow = func() {
C.gtk_widget_show_all(c.widget)
}
c.fcontainerHide = func() {
C.gtk_widget_hide(c.widget)
}
c.fallocate = func(x int, y int, width int, height int, d *sizing) []*allocation {
// TODO split into its own function
return []*allocation{&allocation{
x: x,
y: y,
width: width,
height: height,
this: c,
}}
}
c.fpreferredSize = func(d *sizing) (int, int) {
// GTK+ 3 makes this easy: controls can tell us what their preferred size is!
// ...actually, it tells us two things: the "minimum size" and the "natural size".
// The "minimum size" is the smallest size we /can/ display /anything/. The "natural size" is the smallest size we would /prefer/ to display.
// The difference? Minimum size takes into account things like truncation with ellipses: the minimum size of a label can allot just the ellipses!
// So we use the natural size instead.
// There is a warning about height-for-width controls, but in my tests this isn't an issue.
// For Areas, we manually save the Area size and use that, just to be safe.
//TODO
/*
if s.ctype == c_area {
return s.areawidth, s.areaheight
}
*/
var r C.GtkRequisition
C.gtk_widget_get_preferred_size(c.widget, nil, &r)
return int(r.width), int(r.height)
}
c.fcommitResize = func(a *allocation, d *sizing) {
// as we resize on size-allocate, we have to also use size-allocate on our children
// this is fine anyway; in fact, this allows us to move without knowing what the container is!
// this is what GtkBox does anyway
// thanks to tristan in irc.gimp.net/#gtk+
var r C.GtkAllocation
r.x = C.int(a.x)
r.y = C.int(a.y)
r.width = C.int(a.width)
r.height = C.int(a.height)
C.gtk_widget_size_allocate(c.widget, &r)
}
c.fgetAuxResizeInfo = func(d *sizing) {
//TODO
// d.shouldVAlignTop = (s.ctype == c_listbox) || (s.ctype == c_area)
d.shouldVAlignTop = false
}
return c
}
type scrolledcontrol struct {
*controlbase
scroller *controlbase
scrollcontainer *C.GtkContainer
scrollwindow *C.GtkScrolledWindow
}
func newScrolledControl(widget *C.GtkWidget, native bool) *scrolledcontrol {
scroller := C.gtk_scrolled_window_new(nil, nil)
s := &scrolledcontrol{
controlbase: newControl(widget),
scroller: newControl(scroller),
scrollcontainer: (*C.GtkContainer)(unsafe.Pointer(scroller)),
scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scroller)),
}
// give the scrolled window a border (thanks to jlindgren in irc.gimp.net/#gtk+)
C.gtk_scrolled_window_set_shadow_type(s.scrollwindow, C.GTK_SHADOW_IN)
C.gtk_container_add(s.scrollcontainer, s.widget)
s.fsetParent = s.scroller.fsetParent
s.fcommitResize = s.scroller.fcommitResize
return s
}

View File

@ -38,58 +38,3 @@ func (c *container) beginResize() (d *sizing) {
func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) { func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
// no need for coordinate conversion with gtk+ // no need for coordinate conversion with gtk+
} }
func (w *widgetbase) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
return []*allocation{&allocation{
x: x,
y: y,
width: width,
height: height,
this: w,
}}
}
func (w *widgetbase) commitResize(c *allocation, d *sizing) {
// as we resize on size-allocate, we have to also use size-allocate on our children
// this is fine anyway; in fact, this allows us to move without knowing what the container is!
// this is what GtkBox does anyway
// thanks to tristan in irc.gimp.net/#gtk+
var r C.GtkAllocation
r.x = C.int(c.x)
r.y = C.int(c.y)
r.width = C.int(c.width)
r.height = C.int(c.height)
C.gtk_widget_size_allocate(w.widget, &r)
}
func (w *widgetbase) getAuxResizeInfo(d *sizing) {
//TODO
// d.shouldVAlignTop = (s.ctype == c_listbox) || (s.ctype == c_area)
d.shouldVAlignTop = false
}
// GTK+ 3 makes this easy: controls can tell us what their preferred size is!
// ...actually, it tells us two things: the "minimum size" and the "natural size".
// The "minimum size" is the smallest size we /can/ display /anything/. The "natural size" is the smallest size we would /prefer/ to display.
// The difference? Minimum size takes into account things like truncation with ellipses: the minimum size of a label can allot just the ellipses!
// So we use the natural size instead.
// There is a warning about height-for-width controls, but in my tests this isn't an issue.
// For Areas, we manually save the Area size and use that, just to be safe.
// We don't need to worry about y-offset because label alignment is "vertically center", which GtkLabel does for us.
func (w *widgetbase) preferredSize(d *sizing) (width int, height int) {
//TODO
/*
if s.ctype == c_area {
return s.areawidth, s.areaheight
}
*/
var r C.GtkRequisition
C.gtk_widget_get_preferred_size(w.widget, nil, &r)
return int(r.width), int(r.height)
}

View File

@ -14,15 +14,11 @@ import (
import "C" import "C"
type table struct { type table struct {
*widgetbase *scrolledcontrol
*tablebase *tablebase
treewidget *C.GtkWidget
treeview *C.GtkTreeView treeview *C.GtkTreeView
scrollc *C.GtkContainer
scrollwindow *C.GtkScrolledWindow
model *C.goTableModel model *C.goTableModel
modelgtk *C.GtkTreeModel modelgtk *C.GtkTreeModel
@ -33,19 +29,11 @@ type table struct {
func finishNewTable(b *tablebase, ty reflect.Type) Table { func finishNewTable(b *tablebase, ty reflect.Type) Table {
widget := C.gtk_tree_view_new() widget := C.gtk_tree_view_new()
scroller := C.gtk_scrolled_window_new(nil, nil)
t := &table{ t := &table{
// TODO kludge scrolledcontrol: newScrolledControl(widget, true),
widgetbase: newWidget(scroller),
tablebase: b, tablebase: b,
treewidget: widget,
treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)), treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)),
scrollc: (*C.GtkContainer)(unsafe.Pointer(scroller)),
scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scroller)),
} }
// give the scrolled window a border (thanks to jlindgren in irc.gimp.net/#gtk+)
C.gtk_scrolled_window_set_shadow_type(t.scrollwindow, C.GTK_SHADOW_IN)
C.gtk_container_add(t.scrollc, t.treewidget)
model := C.newTableModel(unsafe.Pointer(t)) model := C.newTableModel(unsafe.Pointer(t))
t.model = model t.model = model
t.modelgtk = (*C.GtkTreeModel)(unsafe.Pointer(model)) t.modelgtk = (*C.GtkTreeModel)(unsafe.Pointer(model))
@ -60,13 +48,6 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
return t return t
} }
func (t *table) preferredSize(d *sizing) (width int, height int) {
var r C.GtkRequisition
C.gtk_widget_get_preferred_size(t.treewidget, nil, &r)
return int(r.width), int(r.height)
}
func (t *table) Lock() { func (t *table) Lock() {
t.tablebase.Lock() t.tablebase.Lock()
d := reflect.Indirect(reflect.ValueOf(t.data)) d := reflect.Indirect(reflect.ValueOf(t.data))