Migrated the Mac OS X backend to the new Control setup.

This commit is contained in:
Pietro Gagliardi 2014-08-03 20:08:25 -04:00
parent b6d07237b4
commit 8c4cd789ca
10 changed files with 352 additions and 110 deletions

View File

@ -47,6 +47,11 @@ void setSmallControlFont(id control)
buttonClicked(self->gocontrol);
}
- (IBAction)checkboxToggled:(id)sender
{
checkboxChecked(self->gocontrol);
}
@end
id newButton(void)
@ -93,6 +98,16 @@ id newCheckbox(void)
return (id) c;
}
void checkboxSetDelegate(id checkbox, void *b)
{
goControlDelegate *d;
d = [goControlDelegate new];
d->gocontrol = b;
[toNSButton(checkbox) setTarget:d];
[toNSButton(checkbox) setAction:@selector(checkboxToggled:)];
}
BOOL checkboxChecked(id c)
{
if ([toNSButton(c) state] == NSOnState)
@ -110,6 +125,7 @@ void checkboxSetChecked(id c, BOOL checked)
[toNSButton(c) setState:state];
}
// also good for labels
static id finishNewTextField(NSTextField *t, BOOL bordered)
{
// same for text fields, password fields, and labels
@ -144,11 +160,13 @@ id newPasswordField(void)
return finishNewTextField(toNSTextField(t), YES);
}
// also good for labels
const char *textFieldText(id t)
{
return [[toNSTextField(t) stringValue] UTF8String];
}
// also good for labels
void textFieldSetText(id t, char *text)
{
[toNSTextField(t) setStringValue:[NSString stringWithUTF8String:text]];

View File

@ -10,30 +10,36 @@ import (
import "C"
type button struct {
*controlbase
clicked *event
}
func finishNewButton(id C.id, text string) *button {
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
b := &button{
controlbase: newControl(id),
clicked: newEvent(),
}
C.buttonSetText(b.id, ctext)
C.buttonSetDelegate(b.id, unsafe.Pointer(b))
return b
_id C.id
clicked *event
}
func newButton(text string) *button {
return finishNewButton(C.newButton(), text)
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
b := &button{
_id: C.newButton(),
clicked: newEvent(),
}
C.buttonSetText(b._id, ctext)
C.buttonSetDelegate(b._id, unsafe.Pointer(b))
return b
}
func (b *button) OnClicked(e func()) {
b.clicked.set(e)
}
func (b *button) Text() string {
return C.GoString(C.buttonText(b._id))
}
func (b *button) SetText(text string) {
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
C.buttonSetText(b._id, ctext)
}
//export buttonClicked
func buttonClicked(xb unsafe.Pointer) {
b := (*button)(unsafe.Pointer(xb))
@ -41,12 +47,34 @@ func buttonClicked(xb unsafe.Pointer) {
println("button clicked")
}
func (b *button) Text() string {
return C.GoString(C.buttonText(b.id))
func (b *button) id() C.id {
return b._id
}
func (b *button) SetText(text string) {
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
C.buttonSetText(b.id, 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(b, d)
}

View File

@ -2,26 +2,86 @@
package ui
import (
"unsafe"
)
// #include "objc_darwin.h"
import "C"
type checkbox struct {
*button
_id C.id
toggled *event
}
func newCheckbox(text string) *checkbox {
return &checkbox{
button: finishNewButton(C.newCheckbox(), text),
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
c := &checkbox{
_id: C.newCheckbox(),
toggled: newEvent(),
}
C.buttonSetText(c._id, ctext)
C.checkboxSetDelegate(c._id, unsafe.Pointer(c))
return c
}
// we don't need to define our own event here; we can just reuse Button's
// (it's all target-action anyway)
func (c *checkbox) OnToggled(e func()) {
c.toggled.set(e)
}
func (c *checkbox) Text() string {
return C.GoString(C.buttonText(c._id))
}
func (c *checkbox) SetText(text string) {
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
C.buttonSetText(c._id, ctext)
}
func (c *checkbox) Checked() bool {
return fromBOOL(C.checkboxChecked(c.id))
return fromBOOL(C.checkboxChecked(c._id))
}
func (c *checkbox) SetChecked(checked bool) {
C.checkboxSetChecked(c.id, toBOOL(checked))
C.checkboxSetChecked(c._id, toBOOL(checked))
}
//export checkboxToggled
func checkboxToggled(xc unsafe.Pointer) {
c := (*checkbox)(unsafe.Pointer(xc))
c.toggled.fire()
}
func (c *checkbox) id() C.id {
return c._id
}
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(c, d)
}

View File

@ -5,55 +5,63 @@ package ui
// #include "objc_darwin.h"
import "C"
type controlbase struct {
*controldefs
id C.id
// all Controls that call base methods must be this
type controlPrivate interface {
id() C.id
Control
}
type controlParent struct {
id C.id
}
func newControl(id C.id) *controlbase {
c := new(controlbase)
c.id = id
c.controldefs = new(controldefs)
c.fsetParent = func(p *controlParent) {
// redrawing the new window handled by C.parent()
C.parent(c.id, p.id)
}
c.fcontainerShow = func() {
C.controlSetHidden(c.id, C.NO)
}
c.fcontainerHide = func() {
C.controlSetHidden(c.id, C.YES)
}
c.fallocate = baseallocate(c)
c.fpreferredSize = func(d *sizing) (int, int) {
s := C.controlPrefSize(c.id)
return int(s.width), int(s.height)
}
c.fcommitResize = func(a *allocation, d *sizing) {
C.moveControl(c.id, C.intptr_t(a.x), C.intptr_t(a.y), C.intptr_t(a.width), C.intptr_t(a.height))
}
c.fgetAuxResizeInfo = func(d *sizing) {
d.neighborAlign = C.alignmentInfo(c.id, C.frame(c.id))
}
return c
func basesetParent(c controlPrivate, p *controlParent) {
// redrawing the new window handled by C.parent()
C.parent(c.id(), p.id)
}
type scrolledcontrol struct {
*controlbase
scroller *controlbase
func basecontainerShow(c controlPrivate) {
C.controlSetHidden(c.id(), C.NO)
}
func newScrolledControl(id C.id) *scrolledcontrol {
scroller := C.newScrollView(id)
s := &scrolledcontrol{
controlbase: newControl(id),
scroller: newControl(scroller),
func basecontainerHide(c controlPrivate) {
C.controlSetHidden(c.id(), C.YES)
}
func basepreferredSize(c controlPrivate, d *sizing) (int, int) {
s := C.controlPrefSize(c.id())
return int(s.width), int(s.height)
}
func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
dobasecommitResize(c.id(), a, d)
}
func dobasecommitResize(id C.id, c *allocation, d *sizing) {
C.moveControl(id, C.intptr_t(c.x), C.intptr_t(c.y), C.intptr_t(c.width), C.intptr_t(c.height))
}
func basegetAuxResizeInfo(c controlPrivate, d *sizing) {
id := c.id()
d.neighborAlign = C.alignmentInfo(id, C.frame(id))
}
type scroller struct {
id C.id
}
func newScroller(child C.id) *scroller {
id := C.newScrollView(child)
s := &scroller{
id: id,
}
s.fsetParent = s.scroller.fsetParent
s.fcommitResize = s.scroller.fcommitResize
return s
}
func (s *scroller) setParent(p *controlParent) {
C.parent(s.id, p.id)
}
func (s *scroller) commitResize(c *allocation, d *sizing) {
dobasecommitResize(s.id, c, d)
}

View File

@ -31,6 +31,6 @@ func (AAA *BBB) commitResize(a *allocation, d *sizing) {
}
func (AAA *BBB) getAuxResizeInfo(d *sizing) {
basegetAuxResizeInfo(d)
basegetAuxResizeInfo(AAA, d)
}
END

View File

@ -2,24 +2,24 @@
package ui
import (
"unsafe"
)
// #include "objc_darwin.h"
import "C"
// cheap trick
type label struct {
*textField
standalone bool
supercommitResize func(c *allocation, d *sizing)
_id C.id
standalone bool
}
func finishNewLabel(text string, standalone bool) *label {
l := &label{
textField: finishNewTextField(C.newLabel()),
_id: C.newLabel(),
standalone: standalone,
}
l.SetText(text)
l.supercommitResize = l.fcommitResize
l.fcommitResize = l.labelcommitResize
return l
}
@ -31,13 +31,47 @@ func newStandaloneLabel(text string) Label {
return finishNewLabel(text, true)
}
func (l *label) labelcommitResize(c *allocation, d *sizing) {
func (l *label) Text() string {
return C.GoString(C.textFieldText(l._id))
}
func (l *label) SetText(text string) {
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
C.textFieldSetText(l._id, ctext)
}
func (l *label) id() C.id {
return l._id
}
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.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline
// in order for the baseline value to be correct, the label MUST BE AT THE HEIGHT THAT OS X WANTS IT TO BE!
// otherwise, the baseline calculation will be relative to the bottom of the control, and everything will be wrong
origsize := C.controlPrefSize(l.id)
origsize := C.controlPrefSize(l._id)
c.height = int(origsize.height)
newrect := C.struct_xrect{
x: C.intptr_t(c.x),
@ -45,7 +79,7 @@ func (l *label) labelcommitResize(c *allocation, d *sizing) {
width: C.intptr_t(c.width),
height: C.intptr_t(c.height),
}
ourAlign := C.alignmentInfo(l.id, newrect)
ourAlign := C.alignmentInfo(l._id, newrect)
// we need to find the exact Y positions of the baselines
// fortunately, this is easy now that (x,y) is the bottom-left corner
thisbasey := ourAlign.rect.y + ourAlign.baseline
@ -57,5 +91,9 @@ func (l *label) labelcommitResize(c *allocation, d *sizing) {
}
// TODO if there's no baseline, the alignment should be to the top /of the alignment rect/, not the frame
}
l.supercommitResize(c, d)
basecommitResize(l, c, d)
}
func (l *label) getAuxResizeInfo(d *sizing) {
basegetAuxResizeInfo(l, d)
}

View File

@ -41,6 +41,7 @@ extern void buttonSetDelegate(id, void *);
extern const char *buttonText(id);
extern void buttonSetText(id, char *);
extern id newCheckbox(void);
extern void checkboxSetDelegate(id, void *);
extern BOOL checkboxChecked(id);
extern void checkboxSetChecked(id, BOOL);
extern id newTextField(void);

View File

@ -10,16 +10,13 @@ import (
import "C"
type tab struct {
*controlbase
tabs []*sizer
_id C.id
tabs []*sizer
}
func newTab() Tab {
t := new(tab)
id := C.newTab(unsafe.Pointer(t))
t.controlbase = newControl(id)
t.fpreferredSize = t.tabpreferredSize
t._id = C.newTab(unsafe.Pointer(t))
return t
}
@ -28,18 +25,11 @@ func (t *tab) Append(name string, control Control) {
t.tabs = append(t.tabs, s)
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
tabview := C.tabAppend(t.id, cname)
tabview := C.tabAppend(t._id, cname)
s.child = control
s.child.setParent(&controlParent{tabview})
}
func (t *tab) tabpreferredSize(d *sizing) (width, height int) {
s := C.tabPrefSize(t.id)
return int(s.width), int(s.height)
}
// no need to override Control.commitResize() as only prepared the tabbed control; its children will be reallocated when that one is resized
//export tabResized
func tabResized(data unsafe.Pointer, width C.intptr_t, height C.intptr_t) {
t := (*tab)(unsafe.Pointer(data))
@ -48,3 +38,37 @@ func tabResized(data unsafe.Pointer, width C.intptr_t, height C.intptr_t) {
s.resize(0, 0, int(width), int(height))
}
}
func (t *tab) id() C.id {
return t._id
}
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) {
s := C.tabPrefSize(t._id)
return int(s.width), int(s.height)
}
// 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(t, d)
}

View File

@ -12,20 +12,23 @@ import (
import "C"
type table struct {
*scrolledcontrol
*tablebase
_id C.id
scroller *scroller
}
func finishNewTable(b *tablebase, ty reflect.Type) Table {
id := C.newTable()
t := &table{
scrolledcontrol: newScrolledControl(id),
tablebase: b,
_id: id,
scroller: newScroller(id),
tablebase: b,
}
C.tableMakeDataSource(t.id, unsafe.Pointer(t))
C.tableMakeDataSource(t._id, unsafe.Pointer(t))
for i := 0; i < ty.NumField(); i++ {
cname := C.CString(ty.Field(i).Name)
C.tableAppendColumn(t.id, cname)
C.tableAppendColumn(t._id, cname)
C.free(unsafe.Pointer(cname)) // free now (not deferred) to conserve memory
}
return t
@ -37,7 +40,7 @@ func (t *table) Unlock() {
// not sure about this one...
t.RLock()
defer t.RUnlock()
C.tableUpdate(t.id)
C.tableUpdate(t._id)
}
//export goTableDataSource_getValue
@ -59,3 +62,35 @@ func goTableDataSource_getRowCount(data unsafe.Pointer) C.intptr_t {
d := reflect.Indirect(reflect.ValueOf(t.data))
return C.intptr_t(d.Len())
}
func (t *table) id() C.id {
return t._id
}
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) {
basegetAuxResizeInfo(t, d)
}

View File

@ -10,29 +10,59 @@ import (
import "C"
type textField struct {
*controlbase
}
func finishNewTextField(id C.id) *textField {
return &textField{
controlbase: newControl(id),
}
_id C.id
}
func newTextField() *textField {
return finishNewTextField(C.newTextField())
return &textField{
_id: C.newTextField(),
}
}
func newPasswordField() *textField {
return finishNewTextField(C.newPasswordField())
return &textField{
_id: C.newPasswordField(),
}
}
func (t *textField) Text() string {
return C.GoString(C.textFieldText(t.id))
return C.GoString(C.textFieldText(t._id))
}
func (t *textField) SetText(text string) {
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
C.textFieldSetText(t.id, ctext)
C.textFieldSetText(t._id, ctext)
}
func (t *textField) id() C.id {
return t._id
}
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(t, d)
}