summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-08-03 16:28:21 -0400
committerPietro Gagliardi <[email protected]>2014-08-03 16:28:21 -0400
commitb6d07237b423b690570e105e5f0810d35693b0d0 (patch)
treefdf2f0ec2a66f217080dfeb0b60de9e763a9bd95
parentfd48be68ee957e936c272348d3f0b0bddaba5c92 (diff)
Migrated the GTK+ backend to the new Control system. Added controlParent to deal with interface issues; need to apply this to the Windows backend too.
-rw-r--r--redo/button_unix.go65
-rw-r--r--redo/checkbox_unix.go72
-rw-r--r--redo/control_unix.go138
-rwxr-xr-xredo/controlbase.sh36
-rw-r--r--redo/label_unix.go45
-rw-r--r--redo/tab_unix.go35
-rw-r--r--redo/table_unix.go45
-rw-r--r--redo/textfield_unix.go40
8 files changed, 360 insertions, 116 deletions
diff --git a/redo/button_unix.go b/redo/button_unix.go
index 9811bda..73514b8 100644
--- a/redo/button_unix.go
+++ b/redo/button_unix.go
@@ -10,41 +10,46 @@ import (
// #include "gtk_unix.h"
// extern void buttonClicked(GtkButton *, gpointer);
-// extern void checkboxToggled(GtkToggleButton *, gpointer);
import "C"
type button struct {
- *controlbase
+ _widget *C.GtkWidget
button *C.GtkButton
clicked *event
}
// shared code for setting up buttons, check boxes, etc.
-func finishNewButton(widget *C.GtkWidget, event string, handler unsafe.Pointer) *button {
+func newButton(text string) *button {
+ ctext := togstr(text)
+ defer freegstr(ctext)
+ widget := C.gtk_button_new_with_label(ctext)
b := &button{
- controlbase: newControl(widget),
+ _widget: widget,
button: (*C.GtkButton)(unsafe.Pointer(widget)),
clicked: newEvent(),
}
g_signal_connect(
C.gpointer(unsafe.Pointer(b.button)),
- event,
- C.GCallback(handler),
+ "clicked",
+ C.GCallback(C.buttonClicked),
C.gpointer(unsafe.Pointer(b)))
return b
}
-func newButton(text string) *button {
- ctext := togstr(text)
- defer freegstr(ctext)
- widget := C.gtk_button_new_with_label(ctext)
- return finishNewButton(widget, "clicked", C.buttonClicked)
-}
-
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))
@@ -52,12 +57,34 @@ func buttonClicked(bwid *C.GtkButton, data C.gpointer) {
println("button clicked")
}
-func (b *button) Text() string {
- return fromgstr(C.gtk_button_get_label(b.button))
+func (b *button) widget() *C.GtkWidget {
+ return b._widget
}
-func (b *button) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_button_set_label(b.button, ctext)
+func (b *button) setParent(p *controlParent) {
+ basesetParent(b, p)
+}
+
+func (b *button) containerShow() {
+ basecontainerShow(b)
+}
+
+func (b *button) containerHide() {
+ basecontainerHide(b)
+}
+
+func (b *button) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(b, x, y, width, height, d)
+}
+
+func (b *button) preferredSize(d *sizing) (width, height int) {
+ return basepreferredSize(b, d)
+}
+
+func (b *button) commitResize(a *allocation, d *sizing) {
+ basecommitResize(b, a, d)
+}
+
+func (b *button) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
}
diff --git a/redo/checkbox_unix.go b/redo/checkbox_unix.go
index 45048d1..070b84f 100644
--- a/redo/checkbox_unix.go
+++ b/redo/checkbox_unix.go
@@ -9,33 +9,48 @@ import (
)
// #include "gtk_unix.h"
-// extern void buttonClicked(GtkButton *, gpointer);
// extern void checkboxToggled(GtkToggleButton *, gpointer);
import "C"
type checkbox struct {
- // embed button so its methods and events carry over
- *button
+ _widget *C.GtkWidget
+ 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)
- return &checkbox{
- button: finishNewButton(widget, "toggled", C.checkboxToggled),
+ c := &checkbox{
+ _widget: 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
}
-//export checkboxToggled
-func checkboxToggled(bwid *C.GtkToggleButton, data C.gpointer) {
- // note that the finishNewButton() call uses the embedded *button as data
- // this is fine because we're only deferring to buttonClicked() anyway
- buttonClicked(nil, data)
+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 {
@@ -46,3 +61,40 @@ 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()
+}
+
+func (c *checkbox) widget() *C.GtkWidget {
+ return c._widget
+}
+
+func (c *checkbox) setParent(p *controlParent) {
+ basesetParent(c, p)
+}
+
+func (c *checkbox) containerShow() {
+ basecontainerShow(c)
+}
+
+func (c *checkbox) containerHide() {
+ basecontainerHide(c)
+}
+
+func (c *checkbox) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(c, x, y, width, height, d)
+}
+
+func (c *checkbox) preferredSize(d *sizing) (width, height int) {
+ return basepreferredSize(c, d)
+}
+
+func (c *checkbox) commitResize(a *allocation, d *sizing) {
+ basecommitResize(c, a, d)
+}
+
+func (c *checkbox) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}
diff --git a/redo/control_unix.go b/redo/control_unix.go
index d0a4c18..490d5a2 100644
--- a/redo/control_unix.go
+++ b/redo/control_unix.go
@@ -11,92 +11,102 @@ import (
// #include "gtk_unix.h"
import "C"
-type controlbase struct {
- *controldefs
- widget *C.GtkWidget
+// all Controls that call base methods must be this
+type controlPrivate interface {
+ widget() *C.GtkWidget
+ Control
}
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 = baseallocate(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.
+func basesetParent(c controlPrivate, p *controlParent) {
+ C.gtk_container_add(p.c, c.widget())
+ // make sure the new widget is shown if not explicitly hidden
+ c.containerShow()
+}
+
+func basecontainerShow(c controlPrivate) {
+ C.gtk_widget_show_all(c.widget())
+}
+
+func basecontainerHide(c controlPrivate) {
+ C.gtk_widget_hide(c.widget())
+}
+
+func basepreferredSize(c controlPrivate, 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
- }
+ if s.ctype == c_area {
+ return s.areawidth, s.areaheight
+ }
*/
- var r C.GtkRequisition
+ 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+
+ C.gtk_widget_get_preferred_size(c.widget(), nil, &r)
+ return int(r.width), int(r.height)
+}
- var r C.GtkAllocation
+func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
+ dobasecommitResize(c.widget(), a, d)
+}
- 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) {
- // controls set this to true if a Label to its left should be vertically aligned to the control's top
- d.shouldVAlignTop = false
- }
- return c
+func dobasecommitResize(w *C.GtkWidget, 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, &r)
}
-type scrolledcontrol struct {
- *controlbase
- scroller *controlbase
+func basegetAuxResizeInfo(d *sizing) {
+ // controls set this to true if a Label to its left should be vertically aligned to the control's top
+ d.shouldVAlignTop = false
+}
+
+type scroller struct {
+ scrollwidget *C.GtkWidget
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)),
+func newScroller(widget *C.GtkWidget, native bool) *scroller {
+ scrollwidget := C.gtk_scrolled_window_new(nil, nil)
+ s := &scroller{
+ scrollwidget: scrollwidget,
+ scrollcontainer: (*C.GtkContainer)(unsafe.Pointer(scrollwidget)),
+ scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scrollwidget)),
}
// 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
+ // TODO use native here
+ C.gtk_container_add(s.scrollcontainer, widget)
return s
}
+
+func (s *scroller) setParent(p *controlParent) {
+ C.gtk_container_add(p.c, s.scrollwidget)
+ // TODO for when hiding/showing is implemented
+ C.gtk_widget_show_all(s.scrollwidget)
+}
+
+func (s *scroller) commitResize(c *allocation, d *sizing) {
+ dobasecommitResize(s.scrollwidget, c, d)
+}
diff --git a/redo/controlbase.sh b/redo/controlbase.sh
new file mode 100755
index 0000000..24930c9
--- /dev/null
+++ b/redo/controlbase.sh
@@ -0,0 +1,36 @@
+sed "s/AAA/$1/g
+s/BBB/$2/g
+s/CCC/$3/g
+s/DDD/$4/g" <<\END
+func (AAA *BBB) CCC() DDD {
+ return AAA._CCC
+}
+
+func (AAA *BBB) setParent(p *controlParent) {
+ basesetParent(AAA, p)
+}
+
+func (AAA *BBB) containerShow() {
+ basecontainerShow(AAA)
+}
+
+func (AAA *BBB) containerHide() {
+ basecontainerHide(AAA)
+}
+
+func (AAA *BBB) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(AAA, x, y, width, height, d)
+}
+
+func (AAA *BBB) preferredSize(d *sizing) (width, height int) {
+ return basepreferredSize(AAA, d)
+}
+
+func (AAA *BBB) commitResize(a *allocation, d *sizing) {
+ basecommitResize(AAA, a, d)
+}
+
+func (AAA *BBB) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}
+END
diff --git a/redo/label_unix.go b/redo/label_unix.go
index 1776b73..7ff6c1d 100644
--- a/redo/label_unix.go
+++ b/redo/label_unix.go
@@ -17,11 +17,10 @@ import "C"
// - standalone label on its own: should it be centered or not?
type label struct {
- *controlbase
- misc *C.GtkMisc
- label *C.GtkLabel
- standalone bool
- supercommitResize func(c *allocation, d *sizing)
+ _widget *C.GtkWidget
+ misc *C.GtkMisc
+ label *C.GtkLabel
+ standalone bool
}
func finishNewLabel(text string, standalone bool) *label {
@@ -29,13 +28,11 @@ func finishNewLabel(text string, standalone bool) *label {
defer freegstr(ctext)
widget := C.gtk_label_new(ctext)
l := &label{
- controlbase: newControl(widget),
+ _widget: widget,
misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
label: (*C.GtkLabel)(unsafe.Pointer(widget)),
standalone: standalone,
}
- l.supercommitResize = l.fcommitResize
- l.fcommitResize = l.labelcommitResize
return l
}
@@ -57,7 +54,31 @@ func (l *label) SetText(text string) {
C.gtk_label_set_text(l.label, ctext)
}
-func (l *label) labelcommitResize(c *allocation, d *sizing) {
+func (l *label) widget() *C.GtkWidget {
+ return l._widget
+}
+
+func (l *label) setParent(p *controlParent) {
+ basesetParent(l, p)
+}
+
+func (l *label) containerShow() {
+ basecontainerShow(l)
+}
+
+func (l *label) containerHide() {
+ basecontainerHide(l)
+}
+
+func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(l, x, y, width, height, d)
+}
+
+func (l *label) preferredSize(d *sizing) (width, height int) {
+ return basepreferredSize(l, d)
+}
+
+func (l *label) commitResize(c *allocation, d *sizing) {
if !l.standalone && c.neighbor != nil {
c.neighbor.getAuxResizeInfo(d)
if d.shouldVAlignTop {
@@ -67,5 +88,9 @@ func (l *label) labelcommitResize(c *allocation, d *sizing) {
C.gtk_misc_set_alignment(l.misc, 0, 0.5)
}
}
- l.supercommitResize(c, d)
+ basecommitResize(l, c, d)
+}
+
+func (l *label) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
}
diff --git a/redo/tab_unix.go b/redo/tab_unix.go
index 60978ea..ba7d106 100644
--- a/redo/tab_unix.go
+++ b/redo/tab_unix.go
@@ -12,7 +12,7 @@ import (
import "C"
type tab struct {
- *controlbase
+ _widget *C.GtkWidget
notebook *C.GtkNotebook
tabs []*layout
@@ -21,7 +21,7 @@ type tab struct {
func newTab() Tab {
widget := C.gtk_notebook_new()
t := &tab{
- controlbase: newControl(widget),
+ _widget: widget,
notebook: (*C.GtkNotebook)(unsafe.Pointer(widget)),
}
// there are no scrolling arrows by default; add them in case there are too many tabs
@@ -42,4 +42,35 @@ func (t *tab) Append(name string, control Control) {
}
}
+func (t *tab) widget() *C.GtkWidget {
+ return t._widget
+}
+
+func (t *tab) setParent(p *controlParent) {
+ basesetParent(t, p)
+}
+
+func (t *tab) containerShow() {
+ basecontainerShow(t)
+}
+
+func (t *tab) containerHide() {
+ basecontainerHide(t)
+}
+
+func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(t, x, y, width, height, d)
+}
+
+func (t *tab) preferredSize(d *sizing) (width, height int) {
+ return basepreferredSize(t, d)
+}
+
// no need to override Control.commitResize() as only prepared the tabbed control; its children will be reallocated when that one is resized
+func (t *tab) commitResize(a *allocation, d *sizing) {
+ basecommitResize(t, a, d)
+}
+
+func (t *tab) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}
diff --git a/redo/table_unix.go b/redo/table_unix.go
index 2fd2418..05baa57 100644
--- a/redo/table_unix.go
+++ b/redo/table_unix.go
@@ -14,10 +14,11 @@ import (
import "C"
type table struct {
- *scrolledcontrol
*tablebase
+ _widget *C.GtkWidget
treeview *C.GtkTreeView
+ scroller *scroller
model *C.goTableModel
modelgtk *C.GtkTreeModel
@@ -30,15 +31,11 @@ type table struct {
func finishNewTable(b *tablebase, ty reflect.Type) Table {
widget := C.gtk_tree_view_new()
t := &table{
- scrolledcontrol: newScrolledControl(widget, true),
+ scroller: newScroller(widget, true),
tablebase: b,
+ _widget: widget,
treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)),
}
- t.fgetAuxResizeInfo = func(d *sizing) {
- // a Label to the left of a Table should be vertically aligned to the top
- // TODO do the same with Area
- d.shouldVAlignTop = true
- }
model := C.newTableModel(unsafe.Pointer(t))
t.model = model
t.modelgtk = (*C.GtkTreeModel)(unsafe.Pointer(model))
@@ -96,3 +93,37 @@ func goTableModel_getRowCount(data unsafe.Pointer) C.gint {
d := reflect.Indirect(reflect.ValueOf(t.data))
return C.gint(d.Len())
}
+
+func (t *table) widget() *C.GtkWidget {
+ return t._widget
+}
+
+func (t *table) setParent(p *controlParent) {
+ t.scroller.setParent(p)
+}
+
+func (t *table) containerShow() {
+ basecontainerShow(t)
+}
+
+func (t *table) containerHide() {
+ basecontainerHide(t)
+}
+
+func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(t, x, y, width, height, d)
+}
+
+func (t *table) preferredSize(d *sizing) (width, height int) {
+ return basepreferredSize(t, d)
+}
+
+func (t *table) commitResize(c *allocation, d *sizing) {
+ t.scroller.commitResize(c, d)
+}
+
+func (t *table) getAuxResizeInfo(d *sizing) {
+ // a Label to the left of a Table should be vertically aligned to the top
+ // TODO do the same with Area
+ d.shouldVAlignTop = true
+}
diff --git a/redo/textfield_unix.go b/redo/textfield_unix.go
index 4d710b1..fa79347 100644
--- a/redo/textfield_unix.go
+++ b/redo/textfield_unix.go
@@ -14,15 +14,15 @@ import (
import "C"
type textField struct {
- *controlbase
+ _widget *C.GtkWidget
entry *C.GtkEntry
}
func startNewTextField() *textField {
- w := C.gtk_entry_new()
+ widget := C.gtk_entry_new()
return &textField{
- controlbase: newControl(w),
- entry: (*C.GtkEntry)(unsafe.Pointer(w)),
+ _widget: widget,
+ entry: (*C.GtkEntry)(unsafe.Pointer(widget)),
}
}
@@ -45,3 +45,35 @@ func (t *textField) SetText(text string) {
defer freegstr(ctext)
C.gtk_entry_set_text(t.entry, ctext)
}
+
+func (t *textField) widget() *C.GtkWidget {
+ return t._widget
+}
+
+func (t *textField) setParent(p *controlParent) {
+ basesetParent(t, p)
+}
+
+func (t *textField) containerShow() {
+ basecontainerShow(t)
+}
+
+func (t *textField) containerHide() {
+ basecontainerHide(t)
+}
+
+func (t *textField) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(t, x, y, width, height, d)
+}
+
+func (t *textField) preferredSize(d *sizing) (width, height int) {
+ return basepreferredSize(t, d)
+}
+
+func (t *textField) commitResize(a *allocation, d *sizing) {
+ basecommitResize(t, a, d)
+}
+
+func (t *textField) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}