Added Label and implemented it on all platforms.

This commit is contained in:
Pietro Gagliardi 2014-07-29 13:48:31 -04:00
parent 8d7f0c9a62
commit f4bb7360d4
8 changed files with 174 additions and 24 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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);
}

View File

@ -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)
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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)