From f4bb7360d4060d9c62c30d6b5508683a4fb6c472 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 29 Jul 2014 13:48:31 -0400 Subject: [PATCH] Added Label and implemented it on all platforms. --- redo/controls.go | 27 +++++++++++++++++++- redo/controls_darwin.go | 37 ++++++++++++++++++++++++---- redo/controls_darwin.m | 24 ++++++++++++++---- redo/controls_unix.go | 53 ++++++++++++++++++++++++++++++++++++++++ redo/controls_windows.go | 40 ++++++++++++++++++++++++++++++ redo/objc_darwin.h | 1 + redo/sizing_unix.go | 13 ---------- redo/zz_test.go | 3 +++ 8 files changed, 174 insertions(+), 24 deletions(-) diff --git a/redo/controls.go b/redo/controls.go index f047e7f..ef97ed1 100644 --- a/redo/controls.go +++ b/redo/controls.go @@ -38,7 +38,7 @@ type Checkbox interface { // TODO change to OnToggled() or OnChecked()? OnClicked(func()) - // Text and SetText are Requests that get and set the Checkbox's label text. + // Text and SetText get and set the Checkbox's label text. Text() string SetText(text string) @@ -73,3 +73,28 @@ func NewTextField() TextField { func NewPasswordField() TextField { return newPasswordField() } + + +// Label is a Control that shows a static line of text. +// Label shows one line of text; any text that does not fit is truncated. +// A Label can either have smart vertical alignment relative to the control to its right or just be vertically aligned to the top (standalone). +type Label interface { + Control + + // Text and SetText get and set the Label's text. + Text() string + SetText(text string) +} + +// NewLabel creates a new Label with the given text. +// The Label will smartly vertically position itself relative to the control to its immediate right. +// TODO Grids on GTK+ will not respect this unless SetFilling() +func NewLabel(text string) Label { + return newLabel(text) +} + +// NewStandaloneLabel creates a new Label with the given text. +// The Label will be vertically positioned at the top of its allocated space. +func NewStandaloneLabel(text string) Label { + return newStandaloneLabel(text) +} diff --git a/redo/controls_darwin.go b/redo/controls_darwin.go index a4e6c29..d6968fc 100644 --- a/redo/controls_darwin.go +++ b/redo/controls_darwin.go @@ -101,16 +101,18 @@ type textField struct { *widgetbase } -func newTextField() *textField { +func finishNewTextField(id C.id) *textField { return &textField{ - widgetbase: newWidget(C.newTextField()), + widgetbase: newWidget(id), } } +func newTextField() *textField { + return finishNewTextField(C.newTextField()) +} + func newPasswordField() *textField { - return &textField{ - widgetbase: newWidget(C.newPasswordField()), - } + return finishNewTextField(C.newPasswordField()) } func (t *textField) Text() string { @@ -122,3 +124,28 @@ func (t *textField) SetText(text string) { defer C.free(unsafe.Pointer(ctext)) C.textFieldSetText(t.id, ctext) } + +// cheap trick +type label struct { + *textField + standalone bool +} + +func finishNewLabel(text string, standalone bool) *label { + l := &label{ + textField: finishNewTextField(C.newLabel()), + standalone: standalone, + } + l.SetText(text) + return l +} + +func newLabel(text string) Label { + return finishNewLabel(text, false) +} + +func newStandaloneLabel(text string) Label { + return finishNewLabel(text, true) +} + +// TODO label commitResize diff --git a/redo/controls_darwin.m b/redo/controls_darwin.m index 23d15e2..c482e5e 100644 --- a/redo/controls_darwin.m +++ b/redo/controls_darwin.m @@ -101,17 +101,20 @@ void checkboxSetChecked(id c, BOOL checked) [toNSButton(c) setState:state]; } -static id finishNewTextField(NSTextField *t) +static id finishNewTextField(NSTextField *t, BOOL bordered) { - // same for text fields and password fields + // same for text fields, password fields, and labels setStandardControlFont((id) t); - // TODO border (Interface Builder setting is confusing) + // TODO text field/password field border (Interface Builder setting is confusing) + if (!bordered) + [t setBordered:NO]; // smart quotes and other autocorrect features are handled by the window; see newWindow() in window_darwin.m for details // Interface Builder does this to make the text box behave properly // this disables both word wrap AND ellipsizing in one fell swoop // however, we need to send it to the control's cell, not to the control directly [[t cell] setLineBreakMode:NSLineBreakByClipping]; // Interface Builder also sets this to allow horizontal scrolling + // it also sets this for labels, despite those not being scrollable [[t cell] setScrollable:YES]; return (id) t; } @@ -121,7 +124,7 @@ id newTextField(void) NSTextField *t; t = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; - return finishNewTextField(t); + return finishNewTextField(t, YES); } id newPasswordField(void) @@ -129,7 +132,7 @@ id newPasswordField(void) NSSecureTextField *t; t = [[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; - return finishNewTextField(toNSTextField(t)); + return finishNewTextField(toNSTextField(t), YES); } const char *textFieldText(id t) @@ -141,3 +144,14 @@ void textFieldSetText(id t, char *text) { [toNSTextField(t) setStringValue:[NSString stringWithUTF8String:text]]; } + +id newLabel(void) +{ + NSTextField *l; + + l = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; + [l setEditable:NO]; + [l setSelectable:NO]; + [l setDrawsBackground:NO]; + return finishNewTextField(l, NO); +} diff --git a/redo/controls_unix.go b/redo/controls_unix.go index 0761fa1..8e13767 100644 --- a/redo/controls_unix.go +++ b/redo/controls_unix.go @@ -13,6 +13,9 @@ import ( // extern void checkboxToggled(GtkToggleButton *, gpointer); import "C" +// TODOs: +// - standalone label on its own: should it be centered or not? + type widgetbase struct { widget *C.GtkWidget } @@ -153,3 +156,53 @@ func (t *textField) SetText(text string) { defer freegstr(ctext) C.gtk_entry_set_text(t.entry, ctext) } + +type label struct { + *widgetbase + misc *C.GtkMisc + label *C.GtkLabel + standalone bool +} + +func finishNewLabel(text string, standalone bool) *label { + ctext := togstr(text) + defer freegstr(ctext) + widget := C.gtk_label_new(ctext) + return &label{ + widgetbase: newWidget(widget), + misc: (*C.GtkMisc)(unsafe.Pointer(widget)), + label: (*C.GtkLabel)(unsafe.Pointer(widget)), + standalone: standalone, + } +} + +func newLabel(text string) Label { + return finishNewLabel(text, false) +} + +func newStandaloneLabel(text string) Label { + return finishNewLabel(text, true) +} + +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) +} + +func (l *label) commitResize(c *allocation, d *sizing) { + if !l.standalone && c.neighbor != nil { + c.neighbor.getAuxResizeInfo(d) + if d.shouldVAlignTop { + // TODO should it be center-aligned to the first line or not + C.gtk_misc_set_alignment(l.misc, 0, 0) + } else { + C.gtk_misc_set_alignment(l.misc, 0, 0.5) + } + } + l.widgetbase.commitResize(c, d) +} diff --git a/redo/controls_windows.go b/redo/controls_windows.go index 882c15d..b9c69ed 100644 --- a/redo/controls_windows.go +++ b/redo/controls_windows.go @@ -157,3 +157,43 @@ func (t *textField) Text() string { func (t *textField) SetText(text string) { t.settext(text) } + +type label struct { + *widgetbase + standalone bool +} + +var labelclass = toUTF16("STATIC") + +func finishNewLabel(text string, standalone bool) *label { + w := newWidget(labelclass, + // SS_NOPREFIX avoids accelerator translation; SS_LEFTNOWORDWRAP clips text past the end + // controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi) + C.SS_NOPREFIX | C.SS_LEFTNOWORDWRAP, + 0) + C.setWindowText(w.hwnd, toUTF16(text)) + C.controlSetControlFont(w.hwnd) + l := &label{ + widgetbase: w, + standalone: standalone, + } + return l +} + +func newLabel(text string) Label { + return finishNewLabel(text, false) +} + +func newStandaloneLabel(text string) Label { + return finishNewLabel(text, true) +} + +func (l *label) Text() string { + return l.text() +} + +func (l *label) SetText(text string) { + l.settext(text) +} + +// TODO label commitResize diff --git a/redo/objc_darwin.h b/redo/objc_darwin.h index 3a4cc6f..299c9b5 100644 --- a/redo/objc_darwin.h +++ b/redo/objc_darwin.h @@ -46,6 +46,7 @@ extern id newTextField(void); extern id newPasswordField(void); extern const char *textFieldText(id); extern void textFieldSetText(id, char *); +extern id newLabel(void); /* sizing_darwin.m */ extern void moveControl(id, intptr_t, intptr_t, intptr_t, intptr_t); diff --git a/redo/sizing_unix.go b/redo/sizing_unix.go index d94bc01..abca80d 100644 --- a/redo/sizing_unix.go +++ b/redo/sizing_unix.go @@ -50,19 +50,6 @@ func (w *widgetbase) allocate(x int, y int, width int, height int, d *sizing) [] } func (w *widgetbase) commitResize(c *allocation, d *sizing) { -// TODO -/* - if s.ctype == c_label && !s.alternate && c.neighbor != nil { - c.neighbor.getAuxResizeInfo(d) - if d.shouldVAlignTop { - // TODO should it be center-aligned to the first line or not - gtk_misc_set_alignment(s.widget, 0, 0) - } else { - gtk_misc_set_alignment(s.widget, 0, 0.5) - } - } -*/ - // 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 diff --git a/redo/zz_test.go b/redo/zz_test.go index f6791a0..d20eabf 100644 --- a/redo/zz_test.go +++ b/redo/zz_test.go @@ -28,6 +28,7 @@ var ddata = []dtype{ type testwin struct { t Tab w Window + l Label table Table b Button c Checkbox @@ -47,6 +48,8 @@ func (tw *testwin) make(done chan struct{}) { done <- struct{}{} return true }) + tw.l = NewStandaloneLabel("hello") + tw.t.Append("Label", tw.l) tw.table = NewTable(reflect.TypeOf(ddata[0])) tw.table.Lock() dq := tw.table.Data().(*[]dtype)