Merged new container/sizing stuff.
This commit is contained in:
parent
8c8b642adb
commit
62048303a3
|
@ -15,8 +15,7 @@ import "C"
|
||||||
type area struct {
|
type area struct {
|
||||||
*areabase
|
*areabase
|
||||||
|
|
||||||
_id C.id
|
*scroller
|
||||||
scroller *scroller
|
|
||||||
textfield C.id
|
textfield C.id
|
||||||
textfielddone *event
|
textfielddone *event
|
||||||
}
|
}
|
||||||
|
@ -26,11 +25,12 @@ func newArea(ab *areabase) Area {
|
||||||
areabase: ab,
|
areabase: ab,
|
||||||
textfielddone: newEvent(),
|
textfielddone: newEvent(),
|
||||||
}
|
}
|
||||||
a._id = C.newArea(unsafe.Pointer(a))
|
id := C.newArea(unsafe.Pointer(a))
|
||||||
a.scroller = newScroller(a._id, false) // no border on Area
|
a.scroller = newScroller(id, false) // no border on Area
|
||||||
|
a.fpreferredSize = a.xpreferredSize
|
||||||
a.SetSize(a.width, a.height)
|
a.SetSize(a.width, a.height)
|
||||||
a.textfield = C.newTextField()
|
a.textfield = C.newTextField()
|
||||||
C.areaSetTextField(a._id, a.textfield)
|
C.areaSetTextField(a.id, a.textfield)
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ func (a *area) SetSize(width, height int) {
|
||||||
a.width = width
|
a.width = width
|
||||||
a.height = height
|
a.height = height
|
||||||
// set the frame size to set the area's effective size on the Cocoa side
|
// set the frame size to set the area's effective size on the Cocoa side
|
||||||
C.moveControl(a._id, 0, 0, C.intptr_t(a.width), C.intptr_t(a.height))
|
C.moveControl(a.id, 0, 0, C.intptr_t(a.width), C.intptr_t(a.height))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) Repaint(r image.Rectangle) {
|
func (a *area) Repaint(r image.Rectangle) {
|
||||||
|
@ -52,18 +52,18 @@ func (a *area) Repaint(r image.Rectangle) {
|
||||||
s.y = C.intptr_t(r.Min.Y)
|
s.y = C.intptr_t(r.Min.Y)
|
||||||
s.width = C.intptr_t(r.Dx())
|
s.width = C.intptr_t(r.Dx())
|
||||||
s.height = C.intptr_t(r.Dy())
|
s.height = C.intptr_t(r.Dy())
|
||||||
C.areaRepaint(a._id, s)
|
C.areaRepaint(a.id, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) RepaintAll() {
|
func (a *area) RepaintAll() {
|
||||||
C.areaRepaintAll(a._id)
|
C.areaRepaintAll(a.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) OpenTextFieldAt(x, y int) {
|
func (a *area) OpenTextFieldAt(x, y int) {
|
||||||
if x < 0 || x >= a.width || y < 0 || y >= a.height {
|
if x < 0 || x >= a.width || y < 0 || y >= a.height {
|
||||||
panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
|
panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
|
||||||
}
|
}
|
||||||
C.areaTextFieldOpen(a._id, a.textfield, C.intptr_t(x), C.intptr_t(y))
|
C.areaTextFieldOpen(a.id, a.textfield, C.intptr_t(x), C.intptr_t(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) TextFieldText() string {
|
func (a *area) TextFieldText() string {
|
||||||
|
@ -238,27 +238,7 @@ func areaView_flagsChanged(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
|
||||||
return sendKeyEvent(self, ke, data)
|
return sendKeyEvent(self, ke, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) id() C.id {
|
func (a *area) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return a._id
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) setParent(p *controlParent) {
|
|
||||||
a.scroller.setParent(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(a, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) preferredSize(d *sizing) (width, height int) {
|
|
||||||
// the preferred size of an Area is its size
|
// the preferred size of an Area is its size
|
||||||
return a.width, a.height
|
return a.width, a.height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) commitResize(c *allocation, d *sizing) {
|
|
||||||
a.scroller.commitResize(c, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(a, d)
|
|
||||||
}
|
|
||||||
|
|
38
area_unix.go
38
area_unix.go
|
@ -34,9 +34,8 @@ import "C"
|
||||||
type area struct {
|
type area struct {
|
||||||
*areabase
|
*areabase
|
||||||
|
|
||||||
_widget *C.GtkWidget
|
*scroller
|
||||||
drawingarea *C.GtkDrawingArea
|
drawingarea *C.GtkDrawingArea
|
||||||
scroller *scroller
|
|
||||||
|
|
||||||
clickCounter *clickCounter
|
clickCounter *clickCounter
|
||||||
|
|
||||||
|
@ -59,7 +58,6 @@ func newArea(ab *areabase) Area {
|
||||||
textfieldw := C.gtk_entry_new()
|
textfieldw := C.gtk_entry_new()
|
||||||
a := &area{
|
a := &area{
|
||||||
areabase: ab,
|
areabase: ab,
|
||||||
_widget: widget,
|
|
||||||
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
||||||
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
||||||
clickCounter: new(clickCounter),
|
clickCounter: new(clickCounter),
|
||||||
|
@ -67,6 +65,7 @@ func newArea(ab *areabase) Area {
|
||||||
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
|
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
|
||||||
textfielddone: newEvent(),
|
textfielddone: newEvent(),
|
||||||
}
|
}
|
||||||
|
a.fpreferredSize = a.xpreferredSize
|
||||||
for _, c := range areaCallbacks {
|
for _, c := range areaCallbacks {
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
C.gpointer(unsafe.Pointer(a.drawingarea)),
|
C.gpointer(unsafe.Pointer(a.drawingarea)),
|
||||||
|
@ -75,9 +74,9 @@ func newArea(ab *areabase) Area {
|
||||||
C.gpointer(unsafe.Pointer(a)))
|
C.gpointer(unsafe.Pointer(a)))
|
||||||
}
|
}
|
||||||
a.SetSize(a.width, a.height)
|
a.SetSize(a.width, a.height)
|
||||||
C.gtk_overlay_add_overlay(a.scroller.overlay, a.textfieldw)
|
C.gtk_overlay_add_overlay(a.scroller.overlayoverlay, a.textfieldw)
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
C.gpointer(unsafe.Pointer(a.scroller.overlay)),
|
C.gpointer(unsafe.Pointer(a.scroller.overlayoverlay)),
|
||||||
"get-child-position",
|
"get-child-position",
|
||||||
area_get_child_position_callback,
|
area_get_child_position_callback,
|
||||||
C.gpointer(unsafe.Pointer(a)))
|
C.gpointer(unsafe.Pointer(a)))
|
||||||
|
@ -103,7 +102,7 @@ func newArea(ab *areabase) Area {
|
||||||
func (a *area) SetSize(width, height int) {
|
func (a *area) SetSize(width, height int) {
|
||||||
a.width = width
|
a.width = width
|
||||||
a.height = height
|
a.height = height
|
||||||
C.gtk_widget_set_size_request(a._widget, C.gint(a.width), C.gint(a.height))
|
C.gtk_widget_set_size_request(a.widget, C.gint(a.width), C.gint(a.height))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) Repaint(r image.Rectangle) {
|
func (a *area) Repaint(r image.Rectangle) {
|
||||||
|
@ -111,11 +110,11 @@ func (a *area) Repaint(r image.Rectangle) {
|
||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
C.gtk_widget_queue_draw_area(a._widget, C.gint(r.Min.X), C.gint(r.Min.Y), C.gint(r.Dx()), C.gint(r.Dy()))
|
C.gtk_widget_queue_draw_area(a.widget, C.gint(r.Min.X), C.gint(r.Min.Y), C.gint(r.Dx()), C.gint(r.Dy()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) RepaintAll() {
|
func (a *area) RepaintAll() {
|
||||||
C.gtk_widget_queue_draw(a._widget)
|
C.gtk_widget_queue_draw(a.widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) OpenTextFieldAt(x, y int) {
|
func (a *area) OpenTextFieldAt(x, y int) {
|
||||||
|
@ -492,28 +491,7 @@ var modonlykeys = map[C.guint]Modifiers{
|
||||||
C.GDK_KEY_Super_R: Super,
|
C.GDK_KEY_Super_R: Super,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) widget() *C.GtkWidget {
|
func (a *area) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return a._widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) setParent(p *controlParent) {
|
|
||||||
a.scroller.setParent(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(a, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) preferredSize(d *sizing) (width, height int) {
|
|
||||||
// the preferred size of an Area is its size
|
// the preferred size of an Area is its size
|
||||||
return a.width, a.height
|
return a.width, a.height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) commitResize(c *allocation, d *sizing) {
|
|
||||||
a.scroller.commitResize(c, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) getAuxResizeInfo(d *sizing) {
|
|
||||||
// a Label to the left of an Area should be vertically aligned to the top
|
|
||||||
d.shouldVAlignTop = true
|
|
||||||
}
|
|
||||||
|
|
|
@ -321,7 +321,7 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
|
||||||
uintptr_t heldButtons = (uintptr_t) wParam;
|
uintptr_t heldButtons = (uintptr_t) wParam;
|
||||||
LRESULT lResult;
|
LRESULT lResult;
|
||||||
|
|
||||||
data = getWindowData(hwnd, uMsg, wParam, lParam, &lResult, storeAreaHWND);
|
data = getWindowData(hwnd, uMsg, wParam, lParam, &lResult);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return lResult;
|
return lResult;
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import "C"
|
||||||
type area struct {
|
type area struct {
|
||||||
*areabase
|
*areabase
|
||||||
|
|
||||||
_hwnd C.HWND
|
*controlSingleHWND
|
||||||
|
|
||||||
clickCounter *clickCounter
|
clickCounter *clickCounter
|
||||||
|
|
||||||
|
@ -39,9 +39,10 @@ func newArea(ab *areabase) Area {
|
||||||
clickCounter: new(clickCounter),
|
clickCounter: new(clickCounter),
|
||||||
textfielddone: newEvent(),
|
textfielddone: newEvent(),
|
||||||
}
|
}
|
||||||
a._hwnd = C.newArea(unsafe.Pointer(a))
|
a.controlSingleHWND = newControlSingleHWND(C.newArea(unsafe.Pointer(a)))
|
||||||
|
a.fpreferredSize = a.xpreferredSize
|
||||||
a.SetSize(a.width, a.height)
|
a.SetSize(a.width, a.height)
|
||||||
a.textfield = C.newAreaTextField(a._hwnd, unsafe.Pointer(a))
|
a.textfield = C.newAreaTextField(a.hwnd, unsafe.Pointer(a))
|
||||||
C.controlSetControlFont(a.textfield)
|
C.controlSetControlFont(a.textfield)
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
@ -49,14 +50,14 @@ func newArea(ab *areabase) Area {
|
||||||
func (a *area) SetSize(width, height int) {
|
func (a *area) SetSize(width, height int) {
|
||||||
a.width = width
|
a.width = width
|
||||||
a.height = height
|
a.height = height
|
||||||
C.SendMessageW(a._hwnd, C.msgAreaSizeChanged, 0, 0)
|
C.SendMessageW(a.hwnd, C.msgAreaSizeChanged, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) Repaint(r image.Rectangle) {
|
func (a *area) Repaint(r image.Rectangle) {
|
||||||
var hscroll, vscroll C.int
|
var hscroll, vscroll C.int
|
||||||
var rect C.RECT
|
var rect C.RECT
|
||||||
|
|
||||||
C.SendMessageW(a._hwnd, C.msgAreaGetScroll, C.WPARAM(uintptr(unsafe.Pointer(&hscroll))), C.LPARAM(uintptr(unsafe.Pointer(&vscroll))))
|
C.SendMessageW(a.hwnd, C.msgAreaGetScroll, C.WPARAM(uintptr(unsafe.Pointer(&hscroll))), C.LPARAM(uintptr(unsafe.Pointer(&vscroll))))
|
||||||
r = r.Add(image.Pt(int(hscroll), int(vscroll))) // adjust by scroll position
|
r = r.Add(image.Pt(int(hscroll), int(vscroll))) // adjust by scroll position
|
||||||
r = image.Rect(0, 0, a.width, a.height).Intersect(r)
|
r = image.Rect(0, 0, a.width, a.height).Intersect(r)
|
||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
|
@ -66,18 +67,18 @@ func (a *area) Repaint(r image.Rectangle) {
|
||||||
rect.top = C.LONG(r.Min.Y)
|
rect.top = C.LONG(r.Min.Y)
|
||||||
rect.right = C.LONG(r.Max.X)
|
rect.right = C.LONG(r.Max.X)
|
||||||
rect.bottom = C.LONG(r.Max.Y)
|
rect.bottom = C.LONG(r.Max.Y)
|
||||||
C.SendMessageW(a._hwnd, C.msgAreaRepaint, 0, C.LPARAM(uintptr(unsafe.Pointer(&rect))))
|
C.SendMessageW(a.hwnd, C.msgAreaRepaint, 0, C.LPARAM(uintptr(unsafe.Pointer(&rect))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) RepaintAll() {
|
func (a *area) RepaintAll() {
|
||||||
C.SendMessageW(a._hwnd, C.msgAreaRepaintAll, 0, 0)
|
C.SendMessageW(a.hwnd, C.msgAreaRepaintAll, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) OpenTextFieldAt(x, y int) {
|
func (a *area) OpenTextFieldAt(x, y int) {
|
||||||
if x < 0 || x >= a.width || y < 0 || y >= a.height {
|
if x < 0 || x >= a.width || y < 0 || y >= a.height {
|
||||||
panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
|
panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
|
||||||
}
|
}
|
||||||
C.areaOpenTextField(a._hwnd, a.textfield, C.int(x), C.int(y), textfieldWidth, textfieldHeight)
|
C.areaOpenTextField(a.hwnd, a.textfield, C.int(x), C.int(y), textfieldWidth, textfieldHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) TextFieldText() string {
|
func (a *area) TextFieldText() string {
|
||||||
|
@ -96,7 +97,7 @@ func (a *area) OnTextFieldDismissed(f func()) {
|
||||||
//export areaTextFieldDone
|
//export areaTextFieldDone
|
||||||
func areaTextFieldDone(data unsafe.Pointer) {
|
func areaTextFieldDone(data unsafe.Pointer) {
|
||||||
a := (*area)(data)
|
a := (*area)(data)
|
||||||
C.areaMarkTextFieldDone(a._hwnd)
|
C.areaMarkTextFieldDone(a.hwnd)
|
||||||
a.textfielddone.fire()
|
a.textfielddone.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,39 +324,13 @@ var modonlykeys = map[C.WPARAM]Modifiers{
|
||||||
C.VK_RWIN: Super,
|
C.VK_RWIN: Super,
|
||||||
}
|
}
|
||||||
|
|
||||||
//export storeAreaHWND
|
|
||||||
func storeAreaHWND(data unsafe.Pointer, hwnd C.HWND) {
|
|
||||||
a := (*area)(data)
|
|
||||||
a._hwnd = hwnd
|
|
||||||
}
|
|
||||||
|
|
||||||
//export areaResetClickCounter
|
//export areaResetClickCounter
|
||||||
func areaResetClickCounter(data unsafe.Pointer) {
|
func areaResetClickCounter(data unsafe.Pointer) {
|
||||||
a := (*area)(data)
|
a := (*area)(data)
|
||||||
a.clickCounter.reset()
|
a.clickCounter.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) hwnd() C.HWND {
|
func (a *area) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return a._hwnd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) setParent(p *controlParent) {
|
|
||||||
basesetParent(a, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(a, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) preferredSize(d *sizing) (width, height int) {
|
|
||||||
// the preferred size of an Area is its size
|
// the preferred size of an Area is its size
|
||||||
return a.width, a.height
|
return a.width, a.height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *area) commitResize(c *allocation, d *sizing) {
|
|
||||||
basecommitResize(a, c, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *area) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(a, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -87,31 +87,20 @@ func NewTab() Tab {
|
||||||
|
|
||||||
// Label is a Control that shows a static line of text.
|
// 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.
|
// 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).
|
// Labels are left-aligned. [FUTURE PLANS: For platform-specific horizontal alignment rules, use a Form.]
|
||||||
// The effect of placing a non-standalone Label in any context other than to the immediate left of a Control is undefined.
|
|
||||||
// Both types of labels are left-aligned. [FUTURE PLANS: For platform-specific horizontal alignment rules, use a Form.]
|
|
||||||
type Label interface {
|
type Label interface {
|
||||||
Control
|
Control
|
||||||
|
|
||||||
// Text and SetText get and set the Label's text.
|
// Text and SetText get and set the Label's text.
|
||||||
Text() string
|
Text() string
|
||||||
SetText(text string)
|
SetText(text string)
|
||||||
|
|
||||||
isStandalone() bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLabel creates a new Label with the given text.
|
// NewLabel creates a new Label with the given text.
|
||||||
// The Label will smartly vertically position itself relative to the control to its immediate right.
|
|
||||||
func NewLabel(text string) Label {
|
func NewLabel(text string) Label {
|
||||||
return newLabel(text)
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group is a Control that holds a single Control; if that Control also contains other Controls, then the Controls will appear visually grouped together.
|
// Group is a Control that holds a single Control; if that Control also contains other Controls, then the Controls will appear visually grouped together.
|
||||||
// The appearance of a Group varies from system to system; for the most part a Group consists of a thin frame.
|
// The appearance of a Group varies from system to system; for the most part a Group consists of a thin frame.
|
||||||
// All Groups have a text label indicating what the Group is for.
|
// All Groups have a text label indicating what the Group is for.
|
||||||
|
@ -121,6 +110,11 @@ type Group interface {
|
||||||
// Text and SetText get and set the Group's label text.
|
// Text and SetText get and set the Group's label text.
|
||||||
Text() string
|
Text() string
|
||||||
SetText(text string)
|
SetText(text string)
|
||||||
|
|
||||||
|
// Margined and SetMargined get and set whether the contents of the Group have a margin around them.
|
||||||
|
// The size of the margin is platform-dependent.
|
||||||
|
Margined() bool
|
||||||
|
SetMargined(margined bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGroup creates a new Group with the given text label and child Control.
|
// NewGroup creates a new Group with the given text label and child Control.
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type button struct {
|
type button struct {
|
||||||
_id C.id
|
*controlSingleObject
|
||||||
clicked *event
|
clicked *event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,11 +18,11 @@ func newButton(text string) *button {
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
b := &button{
|
b := &button{
|
||||||
_id: C.newButton(),
|
controlSingleObject: newControlSingleObject(C.newButton()),
|
||||||
clicked: newEvent(),
|
clicked: newEvent(),
|
||||||
}
|
}
|
||||||
C.buttonSetText(b._id, ctext)
|
C.buttonSetText(b.id, ctext)
|
||||||
C.buttonSetDelegate(b._id, unsafe.Pointer(b))
|
C.buttonSetDelegate(b.id, unsafe.Pointer(b))
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,13 +31,13 @@ func (b *button) OnClicked(e func()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *button) Text() string {
|
func (b *button) Text() string {
|
||||||
return C.GoString(C.buttonText(b._id))
|
return C.GoString(C.buttonText(b.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *button) SetText(text string) {
|
func (b *button) SetText(text string) {
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
C.buttonSetText(b._id, ctext)
|
C.buttonSetText(b.id, ctext)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export buttonClicked
|
//export buttonClicked
|
||||||
|
@ -45,27 +45,3 @@ func buttonClicked(xb unsafe.Pointer) {
|
||||||
b := (*button)(unsafe.Pointer(xb))
|
b := (*button)(unsafe.Pointer(xb))
|
||||||
b.clicked.fire()
|
b.clicked.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *button) id() C.id {
|
|
||||||
return b._id
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) setParent(p *controlParent) {
|
|
||||||
basesetParent(b, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type button struct {
|
type button struct {
|
||||||
_widget *C.GtkWidget
|
*controlSingleWidget
|
||||||
button *C.GtkButton
|
button *C.GtkButton
|
||||||
clicked *event
|
clicked *event
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func newButton(text string) *button {
|
||||||
defer freegstr(ctext)
|
defer freegstr(ctext)
|
||||||
widget := C.gtk_button_new_with_label(ctext)
|
widget := C.gtk_button_new_with_label(ctext)
|
||||||
b := &button{
|
b := &button{
|
||||||
_widget: widget,
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||||
clicked: newEvent(),
|
clicked: newEvent(),
|
||||||
}
|
}
|
||||||
|
@ -55,27 +55,3 @@ func buttonClicked(bwid *C.GtkButton, data C.gpointer) {
|
||||||
b := (*button)(unsafe.Pointer(data))
|
b := (*button)(unsafe.Pointer(data))
|
||||||
b.clicked.fire()
|
b.clicked.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *button) widget() *C.GtkWidget {
|
|
||||||
return b._widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) setParent(p *controlParent) {
|
|
||||||
basesetParent(b, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type button struct {
|
type button struct {
|
||||||
_hwnd C.HWND
|
*controlSingleHWNDWithText
|
||||||
_textlen C.LONG
|
|
||||||
clicked *event
|
clicked *event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +21,13 @@ func newButton(text string) *button {
|
||||||
C.BS_PUSHBUTTON|C.WS_TABSTOP,
|
C.BS_PUSHBUTTON|C.WS_TABSTOP,
|
||||||
0)
|
0)
|
||||||
b := &button{
|
b := &button{
|
||||||
_hwnd: hwnd,
|
controlSingleHWNDWithText: newControlSingleHWNDWithText(hwnd),
|
||||||
clicked: newEvent(),
|
clicked: newEvent(),
|
||||||
}
|
}
|
||||||
|
b.fpreferredSize = b.xpreferredSize
|
||||||
b.SetText(text)
|
b.SetText(text)
|
||||||
C.controlSetControlFont(b._hwnd)
|
C.controlSetControlFont(b.hwnd)
|
||||||
C.setButtonSubclass(b._hwnd, unsafe.Pointer(b))
|
C.setButtonSubclass(b.hwnd, unsafe.Pointer(b))
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +36,11 @@ func (b *button) OnClicked(e func()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *button) Text() string {
|
func (b *button) Text() string {
|
||||||
return baseText(b)
|
return b.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *button) SetText(text string) {
|
func (b *button) SetText(text string) {
|
||||||
baseSetText(b, text)
|
b.setText(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export buttonClicked
|
//export buttonClicked
|
||||||
|
@ -49,51 +49,23 @@ func buttonClicked(data unsafe.Pointer) {
|
||||||
b.clicked.fire()
|
b.clicked.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *button) hwnd() C.HWND {
|
|
||||||
return b._hwnd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) textlen() C.LONG {
|
|
||||||
return b._textlen
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) settextlen(len C.LONG) {
|
|
||||||
b._textlen = len
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) setParent(p *controlParent) {
|
|
||||||
basesetParent(b, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(b, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
||||||
buttonHeight = 14
|
buttonHeight = 14
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *button) preferredSize(d *sizing) (width, height int) {
|
func (b *button) xpreferredSize(d *sizing) (width, height int) {
|
||||||
// comctl32.dll version 6 thankfully provides a method to grab this...
|
// comctl32.dll version 6 thankfully provides a method to grab this...
|
||||||
var size C.SIZE
|
var size C.SIZE
|
||||||
|
|
||||||
size.cx = 0 // explicitly ask for ideal size
|
size.cx = 0 // explicitly ask for ideal size
|
||||||
size.cy = 0
|
size.cy = 0
|
||||||
if C.SendMessageW(b._hwnd, C.BCM_GETIDEALSIZE, 0, C.LPARAM(uintptr(unsafe.Pointer(&size)))) != C.FALSE {
|
if C.SendMessageW(b.hwnd, C.BCM_GETIDEALSIZE, 0, C.LPARAM(uintptr(unsafe.Pointer(&size)))) != C.FALSE {
|
||||||
return int(size.cx), int(size.cy)
|
return int(size.cx), int(size.cy)
|
||||||
}
|
}
|
||||||
// that failed, fall back
|
// that failed, fall back
|
||||||
println("message failed; falling back")
|
println("message failed; falling back")
|
||||||
// don't worry about the error return from GetSystemMetrics(); there's no way to tell (explicitly documented as such)
|
// don't worry about the error return from GetSystemMetrics(); there's no way to tell (explicitly documented as such)
|
||||||
xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE))
|
xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE))
|
||||||
return xmargins + int(b._textlen), fromdlgunitsY(buttonHeight, d)
|
return xmargins + int(b.textlen), fromdlgunitsY(buttonHeight, d)
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) commitResize(a *allocation, d *sizing) {
|
|
||||||
basecommitResize(b, a, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *button) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(b, d)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type checkbox struct {
|
type checkbox struct {
|
||||||
_id C.id
|
*controlSingleObject
|
||||||
toggled *event
|
toggled *event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,11 +18,11 @@ func newCheckbox(text string) *checkbox {
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
c := &checkbox{
|
c := &checkbox{
|
||||||
_id: C.newCheckbox(),
|
controlSingleObject: newControlSingleObject(C.newCheckbox()),
|
||||||
toggled: newEvent(),
|
toggled: newEvent(),
|
||||||
}
|
}
|
||||||
C.buttonSetText(c._id, ctext)
|
C.buttonSetText(c.id, ctext)
|
||||||
C.checkboxSetDelegate(c._id, unsafe.Pointer(c))
|
C.checkboxSetDelegate(c.id, unsafe.Pointer(c))
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,21 +31,21 @@ func (c *checkbox) OnToggled(e func()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) Text() string {
|
func (c *checkbox) Text() string {
|
||||||
return C.GoString(C.buttonText(c._id))
|
return C.GoString(C.buttonText(c.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) SetText(text string) {
|
func (c *checkbox) SetText(text string) {
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
C.buttonSetText(c._id, ctext)
|
C.buttonSetText(c.id, ctext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) Checked() bool {
|
func (c *checkbox) Checked() bool {
|
||||||
return fromBOOL(C.checkboxChecked(c._id))
|
return fromBOOL(C.checkboxChecked(c.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) SetChecked(checked bool) {
|
func (c *checkbox) SetChecked(checked bool) {
|
||||||
C.checkboxSetChecked(c._id, toBOOL(checked))
|
C.checkboxSetChecked(c.id, toBOOL(checked))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export checkboxToggled
|
//export checkboxToggled
|
||||||
|
@ -53,27 +53,3 @@ func checkboxToggled(xc unsafe.Pointer) {
|
||||||
c := (*checkbox)(unsafe.Pointer(xc))
|
c := (*checkbox)(unsafe.Pointer(xc))
|
||||||
c.toggled.fire()
|
c.toggled.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) id() C.id {
|
|
||||||
return c._id
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checkbox) setParent(p *controlParent) {
|
|
||||||
basesetParent(c, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type checkbox struct {
|
type checkbox struct {
|
||||||
_widget *C.GtkWidget
|
*controlSingleWidget
|
||||||
button *C.GtkButton
|
button *C.GtkButton
|
||||||
toggle *C.GtkToggleButton
|
toggle *C.GtkToggleButton
|
||||||
checkbox *C.GtkCheckButton
|
checkbox *C.GtkCheckButton
|
||||||
|
@ -25,7 +25,7 @@ func newCheckbox(text string) *checkbox {
|
||||||
defer freegstr(ctext)
|
defer freegstr(ctext)
|
||||||
widget := C.gtk_check_button_new_with_label(ctext)
|
widget := C.gtk_check_button_new_with_label(ctext)
|
||||||
c := &checkbox{
|
c := &checkbox{
|
||||||
_widget: widget,
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||||
toggle: (*C.GtkToggleButton)(unsafe.Pointer(widget)),
|
toggle: (*C.GtkToggleButton)(unsafe.Pointer(widget)),
|
||||||
checkbox: (*C.GtkCheckButton)(unsafe.Pointer(widget)),
|
checkbox: (*C.GtkCheckButton)(unsafe.Pointer(widget)),
|
||||||
|
@ -66,27 +66,3 @@ func checkboxToggled(bwid *C.GtkToggleButton, data C.gpointer) {
|
||||||
c := (*checkbox)(unsafe.Pointer(data))
|
c := (*checkbox)(unsafe.Pointer(data))
|
||||||
c.toggled.fire()
|
c.toggled.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) widget() *C.GtkWidget {
|
|
||||||
return c._widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checkbox) setParent(p *controlParent) {
|
|
||||||
basesetParent(c, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type checkbox struct {
|
type checkbox struct {
|
||||||
_hwnd C.HWND
|
*controlSingleHWNDWithText
|
||||||
_textlen C.LONG
|
|
||||||
toggled *event
|
toggled *event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +21,13 @@ func newCheckbox(text string) *checkbox {
|
||||||
C.BS_CHECKBOX|C.WS_TABSTOP,
|
C.BS_CHECKBOX|C.WS_TABSTOP,
|
||||||
0)
|
0)
|
||||||
c := &checkbox{
|
c := &checkbox{
|
||||||
_hwnd: hwnd,
|
controlSingleHWNDWithText: newControlSingleHWNDWithText(hwnd),
|
||||||
toggled: newEvent(),
|
toggled: newEvent(),
|
||||||
}
|
}
|
||||||
|
c.fpreferredSize = c.xpreferredSize
|
||||||
c.SetText(text)
|
c.SetText(text)
|
||||||
C.controlSetControlFont(c._hwnd)
|
C.controlSetControlFont(c.hwnd)
|
||||||
C.setCheckboxSubclass(c._hwnd, unsafe.Pointer(c))
|
C.setCheckboxSubclass(c.hwnd, unsafe.Pointer(c))
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,23 +36,23 @@ func (c *checkbox) OnToggled(e func()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) Text() string {
|
func (c *checkbox) Text() string {
|
||||||
return baseText(c)
|
return c.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) SetText(text string) {
|
func (c *checkbox) SetText(text string) {
|
||||||
baseSetText(c, text)
|
c.setText(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) Checked() bool {
|
func (c *checkbox) Checked() bool {
|
||||||
return C.checkboxChecked(c._hwnd) != C.FALSE
|
return C.checkboxChecked(c.hwnd) != C.FALSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) SetChecked(checked bool) {
|
func (c *checkbox) SetChecked(checked bool) {
|
||||||
if checked {
|
if checked {
|
||||||
C.checkboxSetChecked(c._hwnd, C.TRUE)
|
C.checkboxSetChecked(c.hwnd, C.TRUE)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
C.checkboxSetChecked(c._hwnd, C.FALSE)
|
C.checkboxSetChecked(c.hwnd, C.FALSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export checkboxToggled
|
//export checkboxToggled
|
||||||
|
@ -61,26 +61,6 @@ func checkboxToggled(data unsafe.Pointer) {
|
||||||
c.toggled.fire()
|
c.toggled.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) hwnd() C.HWND {
|
|
||||||
return c._hwnd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checkbox) textlen() C.LONG {
|
|
||||||
return c._textlen
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checkbox) settextlen(len C.LONG) {
|
|
||||||
c._textlen = len
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checkbox) setParent(p *controlParent) {
|
|
||||||
basesetParent(c, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checkbox) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(c, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
||||||
checkboxHeight = 10
|
checkboxHeight = 10
|
||||||
|
@ -88,15 +68,7 @@ const (
|
||||||
checkboxXFromLeftOfBoxToLeftOfLabel = 12
|
checkboxXFromLeftOfBoxToLeftOfLabel = 12
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *checkbox) preferredSize(d *sizing) (width, height int) {
|
func (c *checkbox) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return fromdlgunitsX(checkboxXFromLeftOfBoxToLeftOfLabel, d) + int(c._textlen),
|
return fromdlgunitsX(checkboxXFromLeftOfBoxToLeftOfLabel, d) + int(c.textlen),
|
||||||
fromdlgunitsY(checkboxHeight, d)
|
fromdlgunitsY(checkboxHeight, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkbox) commitResize(a *allocation, d *sizing) {
|
|
||||||
basecommitResize(c, a, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checkbox) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(c, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ void updateWindow(HWND hwnd)
|
||||||
xpanic("error calling UpdateWindow()", GetLastError());
|
xpanic("error calling UpdateWindow()", GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getWindowData(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult, void (*storeHWND)(void *, HWND))
|
void *getWindowData(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
|
||||||
{
|
{
|
||||||
CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
|
CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -37,11 +37,8 @@ void *getWindowData(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT
|
||||||
data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
// the lpParam is available during WM_NCCREATE and WM_CREATE
|
// the lpParam is available during WM_NCCREATE and WM_CREATE
|
||||||
if (uMsg == WM_NCCREATE) {
|
if (uMsg == WM_NCCREATE)
|
||||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams));
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams));
|
||||||
data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
|
||||||
(*storeHWND)(data, hwnd);
|
|
||||||
}
|
|
||||||
// act as if we're not ready yet, even during WM_NCCREATE (nothing important to the switch statement below happens here anyway)
|
// act as if we're not ready yet, even during WM_NCCREATE (nothing important to the switch statement below happens here anyway)
|
||||||
*lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
*lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
@ -106,21 +103,20 @@ void paintControlBackground(HWND hwnd, HDC dc)
|
||||||
WCHAR classname[128] = L""; // more than enough to avoid collisions
|
WCHAR classname[128] = L""; // more than enough to avoid collisions
|
||||||
|
|
||||||
parent = hwnd;
|
parent = hwnd;
|
||||||
do {
|
for (;;) {
|
||||||
parent = GetParent(parent);
|
|
||||||
if (parent == NULL)
|
|
||||||
xpanic("error getting parent container of control in paintControlBackground()", GetLastError());
|
|
||||||
// wine sends these messages early, yay...
|
|
||||||
if (parent == msgwin)
|
|
||||||
return;
|
|
||||||
parent = GetParent(parent);
|
parent = GetParent(parent);
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
xpanic("error getting parent control of control in paintControlBackground()", GetLastError());
|
xpanic("error getting parent control of control in paintControlBackground()", GetLastError());
|
||||||
|
// wine sends these messages early, yay...
|
||||||
if (parent == msgwin)
|
if (parent == msgwin)
|
||||||
return;
|
return;
|
||||||
if (GetClassNameW(parent, classname, 128) == 0)
|
if (GetClassNameW(parent, classname, 128) == 0)
|
||||||
xpanic("error getting name of focused window class in paintControlBackground()", GetLastError());
|
xpanic("error getting name of focused window class in paintControlBackground()", GetLastError());
|
||||||
} while (_wcsicmp(classname, L"button") == 0); // skip groupboxes
|
// skip container and groupboxes
|
||||||
|
if (_wcsicmp(classname, containerclass) != 0) // container
|
||||||
|
if (_wcsicmp(classname, L"button") != 0) // groupbox
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (GetWindowRect(hwnd, &r) == 0)
|
if (GetWindowRect(hwnd, &r) == 0)
|
||||||
xpanic("error getting control's window rect in paintControlBackground()", GetLastError());
|
xpanic("error getting control's window rect in paintControlBackground()", GetLastError());
|
||||||
// the above is a window rect; convert to client rect
|
// the above is a window rect; convert to client rect
|
||||||
|
|
32
container.go
32
container.go
|
@ -2,41 +2,14 @@
|
||||||
|
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
type allocation struct {
|
|
||||||
x int
|
|
||||||
y int
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
this Control
|
|
||||||
neighbor Control
|
|
||||||
}
|
|
||||||
|
|
||||||
type sizingbase struct {
|
type sizingbase struct {
|
||||||
xmargin int
|
|
||||||
ymargintop int
|
|
||||||
ymarginbottom int
|
|
||||||
xpadding int
|
xpadding int
|
||||||
ypadding int
|
ypadding int
|
||||||
}
|
}
|
||||||
|
|
||||||
type controlSizing interface {
|
// The container type, which is defined per-platform, is an internal Control that is only used to house other Controls from the underlying UI toolkit's point of view
|
||||||
allocate(x int, y int, width int, height int, d *sizing) []*allocation
|
|
||||||
preferredSize(*sizing) (int, int)
|
|
||||||
commitResize(*allocation, *sizing)
|
|
||||||
getAuxResizeInfo(*sizing)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A container hosts a Control and resizes that Control based on changes in size to the parent Window.
|
|
||||||
// container is used by Window, Tab, and Group to contain and control their respective Controls.
|
|
||||||
// Tab and Group use containers for their content; as such, their commitResize() functions should only change the size of the Tab and Group themselves, and have their containers do the real work.
|
|
||||||
// All containers must embed containerbase.
|
|
||||||
type containerbase struct {
|
|
||||||
child Control
|
|
||||||
}
|
|
||||||
|
|
||||||
// set to true to apply spacing to all windows
|
|
||||||
var spaced bool = false
|
|
||||||
|
|
||||||
|
/* TODO
|
||||||
func (c *container) resize(x, y, width, height int) {
|
func (c *container) resize(x, y, width, height int) {
|
||||||
if c.child == nil { // no children; nothing to do
|
if c.child == nil { // no children; nothing to do
|
||||||
return
|
return
|
||||||
|
@ -50,3 +23,4 @@ func (c *container) resize(x, y, width, height int) {
|
||||||
allocations[i].this.commitResize(allocations[i], d)
|
allocations[i].this.commitResize(allocations[i], d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -10,33 +10,44 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type container struct {
|
type container struct {
|
||||||
containerbase
|
*controlSingleObject
|
||||||
id C.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type sizing struct {
|
type sizing struct {
|
||||||
sizingbase
|
sizingbase
|
||||||
|
|
||||||
// for size calculations
|
// for size calculations
|
||||||
// nothing for mac
|
// nothing on Mac OS X
|
||||||
|
|
||||||
// for the actual resizing
|
// for the actual resizing
|
||||||
neighborAlign C.struct_xalignment
|
neighborAlign C.struct_xalignment
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContainer(child Control) *container {
|
func newContainer() *container {
|
||||||
c := new(container)
|
c := new(container)
|
||||||
c.id = C.newContainerView(unsafe.Pointer(c))
|
c.controlSingleObject = newControlSingleObject(C.newContainerView(unsafe.Pointer(c)))
|
||||||
c.child = child
|
|
||||||
c.child.setParent(&controlParent{c.id})
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
//export containerResized
|
func (c *container) parent() *controlParent {
|
||||||
func containerResized(data unsafe.Pointer, width C.intptr_t, height C.intptr_t) {
|
return &controlParent{c.id}
|
||||||
c := (*container)(unsafe.Pointer(data))
|
}
|
||||||
// the origin of a view's content area is always (0, 0)
|
|
||||||
c.resize(0, 0, int(width), int(height))
|
func (c *container) allocation(margined bool) C.struct_xrect {
|
||||||
|
b := C.containerBounds(c.id)
|
||||||
|
if margined {
|
||||||
|
b.x += C.intptr_t(macXMargin)
|
||||||
|
b.y += C.intptr_t(macYMargin)
|
||||||
|
b.width -= C.intptr_t(macXMargin) * 2
|
||||||
|
b.height -= C.intptr_t(macYMargin) * 2
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can just return these values as is
|
||||||
|
func (c *container) bounds(d *sizing) (int, int, int, int) {
|
||||||
|
b := C.containerBounds(c.id)
|
||||||
|
return int(b.x), int(b.y), int(b.width), int(b.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are based on measurements from Interface Builder.
|
// These are based on measurements from Interface Builder.
|
||||||
|
@ -47,18 +58,14 @@ const (
|
||||||
macYPadding = 8
|
macYPadding = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *container) beginResize() (d *sizing) {
|
func (w *window) beginResize() (d *sizing) {
|
||||||
d = new(sizing)
|
d = new(sizing)
|
||||||
if spaced {
|
d.xpadding = macXPadding
|
||||||
d.xmargin = macXMargin
|
d.ypadding = macYPadding
|
||||||
d.ymargintop = macYMargin
|
|
||||||
d.ymarginbottom = d.ymargintop
|
|
||||||
d.xpadding = macXPadding
|
|
||||||
d.ypadding = macYPadding
|
|
||||||
}
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*TODO
|
||||||
func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
|
func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
|
||||||
for _, a := range allocations {
|
for _, a := range allocations {
|
||||||
// winheight - y because (0,0) is the bottom-left corner of the window and not the top-left corner
|
// winheight - y because (0,0) is the bottom-left corner of the window and not the top-left corner
|
||||||
|
@ -66,3 +73,4 @@ func (c *container) translateAllocationCoords(allocations []*allocation, winwidt
|
||||||
a.y = (winheight - a.y) - a.height
|
a.y = (winheight - a.y) - a.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
|
|
||||||
@implementation goContainerView
|
@implementation goContainerView
|
||||||
|
|
||||||
- (void)setFrameSize:(NSSize)s
|
|
||||||
{
|
|
||||||
[super setFrameSize:s];
|
|
||||||
containerResized(self->gocontainer, (intptr_t) s.width, (intptr_t) s.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
id newContainerView(void *gocontainer)
|
id newContainerView(void *gocontainer)
|
||||||
|
@ -40,5 +34,25 @@ id newContainerView(void *gocontainer)
|
||||||
|
|
||||||
void moveControl(id c, intptr_t x, intptr_t y, intptr_t width, intptr_t height)
|
void moveControl(id c, intptr_t x, intptr_t y, intptr_t width, intptr_t height)
|
||||||
{
|
{
|
||||||
[toNSView(c) setFrame:NSMakeRect((CGFloat) x, (CGFloat) y, (CGFloat) width, (CGFloat) height)];
|
NSView *v;
|
||||||
|
NSRect frame;
|
||||||
|
|
||||||
|
frame = NSMakeRect((CGFloat) x, (CGFloat) y, (CGFloat) width, (CGFloat) height);
|
||||||
|
// mac os x coordinate system has (0,0) in the lower-left
|
||||||
|
v = toNSView(c);
|
||||||
|
frame.origin.y = ([[v superview] bounds].size.height - frame.size.height) - frame.origin.y;
|
||||||
|
[v setFrame:frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct xrect containerBounds(id view)
|
||||||
|
{
|
||||||
|
NSRect b;
|
||||||
|
struct xrect r;
|
||||||
|
|
||||||
|
b = [toNSView(view) bounds];
|
||||||
|
r.x = (intptr_t) b.origin.x;
|
||||||
|
r.y = (intptr_t) b.origin.y;
|
||||||
|
r.width = (intptr_t) b.size.width;
|
||||||
|
r.height = (intptr_t) b.size.height;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,6 @@ static void goContainer_remove(GtkContainer *container, GtkWidget *widget)
|
||||||
static void goContainer_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
static void goContainer_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
||||||
{
|
{
|
||||||
gtk_widget_set_allocation(widget, allocation);
|
gtk_widget_set_allocation(widget, allocation);
|
||||||
containerResizing(GOCONTAINER(widget)->gocontainer, allocation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct forall {
|
struct forall {
|
||||||
|
|
|
@ -12,9 +12,8 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type container struct {
|
type container struct {
|
||||||
containerbase
|
*controlSingleWidget
|
||||||
layoutwidget *C.GtkWidget
|
container *C.GtkContainer
|
||||||
layoutcontainer *C.GtkContainer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type sizing struct {
|
type sizing struct {
|
||||||
|
@ -24,27 +23,40 @@ type sizing struct {
|
||||||
// gtk+ needs nothing
|
// gtk+ needs nothing
|
||||||
|
|
||||||
// for the actual resizing
|
// for the actual resizing
|
||||||
shouldVAlignTop bool
|
// gtk+ needs nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContainer(child Control) *container {
|
func newContainer() *container {
|
||||||
c := new(container)
|
c := new(container)
|
||||||
widget := C.newContainer(unsafe.Pointer(c))
|
c.controlSingleWidget = newControlSingleWidget(C.newContainer(unsafe.Pointer(c)))
|
||||||
c.layoutwidget = widget
|
c.container = (*C.GtkContainer)(unsafe.Pointer(c.widget))
|
||||||
c.layoutcontainer = (*C.GtkContainer)(unsafe.Pointer(widget))
|
|
||||||
c.child = child
|
|
||||||
c.child.setParent(&controlParent{c.layoutcontainer})
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *container) setParent(p *controlParent) {
|
func (c *container) parent() *controlParent {
|
||||||
C.gtk_container_add(p.c, c.layoutwidget)
|
return &controlParent{c.container}
|
||||||
}
|
}
|
||||||
|
|
||||||
//export containerResizing
|
func (c *container) allocation(margined bool) C.GtkAllocation {
|
||||||
func containerResizing(data unsafe.Pointer, r *C.GtkAllocation) {
|
var a C.GtkAllocation
|
||||||
c := (*container)(data)
|
|
||||||
c.resize(int(r.x), int(r.y), int(r.width), int(r.height))
|
C.gtk_widget_get_allocation(c.widget, &a)
|
||||||
|
if margined {
|
||||||
|
a.x += C.int(gtkXMargin)
|
||||||
|
a.y += C.int(gtkYMargin)
|
||||||
|
a.width -= C.int(gtkXMargin) * 2
|
||||||
|
a.height -= C.int(gtkYMargin) * 2
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can just return these values as is
|
||||||
|
// note that allocations of a widget on GTK+ have their origin in the /window/ origin
|
||||||
|
func (c *container) bounds(d *sizing) (int, int, int, int) {
|
||||||
|
var a C.GtkAllocation
|
||||||
|
|
||||||
|
C.gtk_widget_get_allocation(c.widget, &a)
|
||||||
|
return int(a.x), int(a.y), int(a.width), int(a.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -54,18 +66,9 @@ const (
|
||||||
gtkYPadding = 6
|
gtkYPadding = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *container) beginResize() (d *sizing) {
|
func (w *window) beginResize() (d *sizing) {
|
||||||
d = new(sizing)
|
d = new(sizing)
|
||||||
if spaced {
|
d.xpadding = gtkXPadding
|
||||||
d.xmargin = gtkXMargin
|
d.ypadding = gtkYPadding
|
||||||
d.ymargintop = gtkYMargin
|
|
||||||
d.ymarginbottom = d.ymargintop
|
|
||||||
d.xpadding = gtkXPadding
|
|
||||||
d.ypadding = gtkYPadding
|
|
||||||
}
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
|
|
||||||
// no need for coordinate conversion with gtk+
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,25 +9,13 @@ In this case, I chose to waste a window handle rather than keep things super com
|
||||||
If this is seriously an issue in the future, I can roll it back.
|
If this is seriously an issue in the future, I can roll it back.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define containerclass L"gouicontainer"
|
|
||||||
|
|
||||||
static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
void *data;
|
|
||||||
RECT r;
|
|
||||||
LRESULT lResult;
|
LRESULT lResult;
|
||||||
|
|
||||||
data = getWindowData(hwnd, uMsg, wParam, lParam, &lResult, storeContainerHWND);
|
|
||||||
if (data == NULL)
|
|
||||||
return lResult;
|
|
||||||
if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult))
|
if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult))
|
||||||
return lResult;
|
return lResult;
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
case WM_SIZE:
|
|
||||||
if (GetClientRect(hwnd, &r) == 0)
|
|
||||||
xpanic("error getting client rect for Window in WM_SIZE", GetLastError());
|
|
||||||
containerResize(data, &r);
|
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +41,7 @@ DWORD makeContainerWindowClass(char **errmsg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND newContainer(void *data)
|
HWND newContainer(void)
|
||||||
{
|
{
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
|
|
||||||
|
@ -63,12 +51,21 @@ HWND newContainer(void *data)
|
||||||
WS_CHILD | WS_VISIBLE,
|
WS_CHILD | WS_VISIBLE,
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
100, 100,
|
100, 100,
|
||||||
msgwin, NULL, hInstance, data);
|
msgwin, NULL, hInstance, NULL);
|
||||||
if (hwnd == NULL)
|
if (hwnd == NULL)
|
||||||
xpanic("container creation failed", GetLastError());
|
xpanic("container creation failed", GetLastError());
|
||||||
return hwnd;
|
return hwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RECT containerBounds(HWND hwnd)
|
||||||
|
{
|
||||||
|
RECT r;
|
||||||
|
|
||||||
|
if (GetClientRect(hwnd, &r) == 0)
|
||||||
|
xpanic("error getting container client rect for container.bounds()", GetLastError());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void calculateBaseUnits(HWND hwnd, int *baseX, int *baseY, LONG *internalLeading)
|
void calculateBaseUnits(HWND hwnd, int *baseX, int *baseY, LONG *internalLeading)
|
||||||
{
|
{
|
||||||
HDC dc;
|
HDC dc;
|
||||||
|
|
|
@ -5,17 +5,13 @@ package ui
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// #include "winapi_windows.h"
|
// #include "winapi_windows.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type container struct {
|
type container struct {
|
||||||
containerbase
|
*controlSingleHWND
|
||||||
hwnd C.HWND
|
|
||||||
nchildren int
|
|
||||||
isGroup bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type sizing struct {
|
type sizing struct {
|
||||||
|
@ -40,45 +36,30 @@ func makeContainerWindowClass() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContainer(control Control) *container {
|
func newContainer() *container {
|
||||||
c := new(container)
|
// don't set preferredSize(); it should never be called
|
||||||
hwnd := C.newContainer(unsafe.Pointer(c))
|
return &container{
|
||||||
if hwnd != c.hwnd {
|
controlSingleHWND: newControlSingleHWND(C.newContainer()),
|
||||||
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in container (%p) differ", hwnd, c.hwnd))
|
|
||||||
}
|
}
|
||||||
c.child = control
|
|
||||||
c.child.setParent(&controlParent{c})
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *container) setParent(hwnd C.HWND) {
|
|
||||||
C.controlSetParent(c.hwnd, hwnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is needed because Windows won't move/resize a child window for us
|
|
||||||
func (c *container) move(r *C.RECT) {
|
|
||||||
C.moveWindow(c.hwnd, C.int(r.left), C.int(r.top), C.int(r.right-r.left), C.int(r.bottom-r.top))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO merge with controlSingleHWND
|
||||||
func (c *container) show() {
|
func (c *container) show() {
|
||||||
C.ShowWindow(c.hwnd, C.SW_SHOW)
|
C.ShowWindow(c.hwnd, C.SW_SHOW)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO merge with controlSingleHWND
|
||||||
func (c *container) hide() {
|
func (c *container) hide() {
|
||||||
C.ShowWindow(c.hwnd, C.SW_HIDE)
|
C.ShowWindow(c.hwnd, C.SW_HIDE)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export storeContainerHWND
|
func (c *container) parent() *controlParent {
|
||||||
func storeContainerHWND(data unsafe.Pointer, hwnd C.HWND) {
|
return &controlParent{c.hwnd}
|
||||||
c := (*container)(data)
|
|
||||||
c.hwnd = hwnd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//export containerResize
|
func (c *container) bounds(d *sizing) (int, int, int, int) {
|
||||||
func containerResize(data unsafe.Pointer, r *C.RECT) {
|
r := C.containerBounds(c.hwnd)
|
||||||
c := (*container)(data)
|
return int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top)
|
||||||
// the origin of any window's content area is always (0, 0), but let's use the values from the RECT just to be safe
|
|
||||||
c.resize(int(r.left), int(r.top), int(r.right-r.left), int(r.bottom-r.top))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Windows, Microsoft just hands you a list of preferred control sizes as part of the MSDN documentation and tells you to roll with it.
|
// For Windows, Microsoft just hands you a list of preferred control sizes as part of the MSDN documentation and tells you to roll with it.
|
||||||
|
@ -103,45 +84,31 @@ func fromdlgunitsY(du int, d *sizing) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// shared by multiple containers
|
||||||
marginDialogUnits = 7
|
marginDialogUnits = 7
|
||||||
paddingDialogUnits = 4
|
paddingDialogUnits = 4
|
||||||
|
|
||||||
groupXMargin = 6
|
|
||||||
groupYMarginTop = 11 // note this value /includes the groupbox label/
|
|
||||||
groupYMarginBottom = 7
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *container) beginResize() (d *sizing) {
|
func (w *window) beginResize() (d *sizing) {
|
||||||
var baseX, baseY C.int
|
var baseX, baseY C.int
|
||||||
var internalLeading C.LONG
|
var internalLeading C.LONG
|
||||||
|
|
||||||
d = new(sizing)
|
d = new(sizing)
|
||||||
|
|
||||||
C.calculateBaseUnits(c.hwnd, &baseX, &baseY, &internalLeading)
|
C.calculateBaseUnits(w.hwnd, &baseX, &baseY, &internalLeading)
|
||||||
d.baseX = baseX
|
d.baseX = baseX
|
||||||
d.baseY = baseY
|
d.baseY = baseY
|
||||||
d.internalLeading = internalLeading
|
d.internalLeading = internalLeading
|
||||||
|
|
||||||
if spaced {
|
d.xpadding = fromdlgunitsX(paddingDialogUnits, d)
|
||||||
d.xmargin = fromdlgunitsX(marginDialogUnits, d)
|
d.ypadding = fromdlgunitsY(paddingDialogUnits, d)
|
||||||
d.ymargintop = fromdlgunitsY(marginDialogUnits, d)
|
|
||||||
d.ymarginbottom = d.ymargintop
|
|
||||||
d.xpadding = fromdlgunitsX(paddingDialogUnits, d)
|
|
||||||
d.ypadding = fromdlgunitsY(paddingDialogUnits, d)
|
|
||||||
}
|
|
||||||
if c.isGroup {
|
|
||||||
// note that these values apply regardless of whether or not spaced is set
|
|
||||||
// this is because Windows groupboxes have the client rect spanning the entire size of the control, not just the active work area
|
|
||||||
// the measurements Microsoft give us are for spaced margining; let's just use them
|
|
||||||
d.xmargin = fromdlgunitsX(groupXMargin, d)
|
|
||||||
d.ymargintop = fromdlgunitsY(groupYMarginTop, d)
|
|
||||||
d.ymarginbottom = fromdlgunitsY(groupYMarginBottom, d)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
|
func marginRectDLU(r *C.RECT, top int, bottom int, left int, right int, d *sizing) {
|
||||||
// no translation needed on windows
|
r.left += C.LONG(fromdlgunitsX(left, d))
|
||||||
|
r.top += C.LONG(fromdlgunitsY(top, d))
|
||||||
|
r.right -= C.LONG(fromdlgunitsX(right, d))
|
||||||
|
r.bottom -= C.LONG(fromdlgunitsY(bottom, d))
|
||||||
}
|
}
|
||||||
|
|
36
control.go
36
control.go
|
@ -5,16 +5,32 @@ package ui
|
||||||
// Control represents a control.
|
// Control represents a control.
|
||||||
type Control interface {
|
type Control interface {
|
||||||
setParent(p *controlParent) // controlParent defined per-platform
|
setParent(p *controlParent) // controlParent defined per-platform
|
||||||
controlSizing
|
preferredSize(d *sizing) (width, height int)
|
||||||
|
resize(x int, y int, width int, height int, d *sizing)
|
||||||
|
nTabStops() int // used by the Windows backend
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is the same across all platforms
|
type controlbase struct {
|
||||||
func baseallocate(c Control, x int, y int, width int, height int, d *sizing) []*allocation {
|
fsetParent func(p *controlParent)
|
||||||
return []*allocation{&allocation{
|
fpreferredSize func(d *sizing) (width, height int)
|
||||||
x: x,
|
fresize func(x int, y int, width int, height int, d *sizing)
|
||||||
y: y,
|
fnTabStops func() int
|
||||||
width: width,
|
}
|
||||||
height: height,
|
|
||||||
this: c,
|
// children should not use the same name as these, otherwise weird things will happen
|
||||||
}}
|
|
||||||
|
func (c *controlbase) setParent(p *controlParent) {
|
||||||
|
c.fsetParent(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlbase) preferredSize(d *sizing) (width, height int) {
|
||||||
|
return c.fpreferredSize(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlbase) resize(x int, y int, width int, height int, d *sizing) {
|
||||||
|
c.fresize(x, y, width, height, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlbase) nTabStops() int {
|
||||||
|
return c.fnTabStops()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,54 +5,52 @@ package ui
|
||||||
// #include "objc_darwin.h"
|
// #include "objc_darwin.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// all Controls that call base methods must be this
|
|
||||||
type controlPrivate interface {
|
|
||||||
id() C.id
|
|
||||||
Control
|
|
||||||
}
|
|
||||||
|
|
||||||
type controlParent struct {
|
type controlParent struct {
|
||||||
id C.id
|
id C.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func basesetParent(c controlPrivate, p *controlParent) {
|
type controlSingleObject struct {
|
||||||
// redrawing the new window handled by C.parent()
|
*controlbase
|
||||||
C.parent(c.id(), p.id)
|
id C.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func basepreferredSize(c controlPrivate, d *sizing) (int, int) {
|
func newControlSingleObject(id C.id) *controlSingleObject {
|
||||||
s := C.controlPreferredSize(c.id())
|
c := new(controlSingleObject)
|
||||||
|
c.controlbase = &controlbase{
|
||||||
|
fsetParent: c.xsetParent,
|
||||||
|
fpreferredSize: c.xpreferredSize,
|
||||||
|
fresize: c.xresize,
|
||||||
|
}
|
||||||
|
c.id = id
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlSingleObject) xsetParent(p *controlParent) {
|
||||||
|
// redrawing the new window handled by C.parent()
|
||||||
|
C.parent(c.id, p.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlSingleObject) xpreferredSize(d *sizing) (int, int) {
|
||||||
|
s := C.controlPreferredSize(c.id)
|
||||||
return int(s.width), int(s.height)
|
return int(s.width), int(s.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
|
func (c *controlSingleObject) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
dobasecommitResize(c.id(), a, d)
|
C.moveControl(c.id, C.intptr_t(x), C.intptr_t(y), C.intptr_t(width), C.intptr_t(height))
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
d.neighborAlign = C.alignmentInfoFrame(c.id())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type scroller struct {
|
type scroller struct {
|
||||||
id C.id
|
*controlSingleObject
|
||||||
|
scroller *controlSingleObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func newScroller(child C.id, bordered bool) *scroller {
|
func newScroller(child C.id, bordered bool) *scroller {
|
||||||
id := C.newScrollView(child, toBOOL(bordered))
|
sid := C.newScrollView(child, toBOOL(bordered))
|
||||||
s := &scroller{
|
s := &scroller{
|
||||||
id: id,
|
controlSingleObject: newControlSingleObject(child),
|
||||||
|
scroller: newControlSingleObject(sid),
|
||||||
}
|
}
|
||||||
|
s.fsetParent = s.scroller.fsetParent
|
||||||
|
s.fresize = s .scroller.fresize
|
||||||
return s
|
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)
|
|
||||||
}
|
|
||||||
|
|
121
control_unix.go
121
control_unix.go
|
@ -11,24 +11,34 @@ import (
|
||||||
// #include "gtk_unix.h"
|
// #include "gtk_unix.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// all Controls that call base methods must be this
|
|
||||||
type controlPrivate interface {
|
|
||||||
widget() *C.GtkWidget
|
|
||||||
Control
|
|
||||||
}
|
|
||||||
|
|
||||||
type controlParent struct {
|
type controlParent struct {
|
||||||
c *C.GtkContainer
|
c *C.GtkContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
func basesetParent(c controlPrivate, p *controlParent) {
|
type controlSingleWidget struct {
|
||||||
widget := c.widget() // avoid multiple interface lookups
|
*controlbase
|
||||||
C.gtk_container_add(p.c, widget)
|
widget *C.GtkWidget
|
||||||
// make sure the new widget is shown if not explicitly hidden
|
|
||||||
C.gtk_widget_show_all(widget)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func basepreferredSize(c controlPrivate, d *sizing) (int, int) {
|
func newControlSingleWidget(widget *C.GtkWidget) *controlSingleWidget {
|
||||||
|
c := new(controlSingleWidget)
|
||||||
|
c.controlbase = &controlbase{
|
||||||
|
fsetParent: c.xsetParent,
|
||||||
|
fpreferredSize: c.xpreferredSize,
|
||||||
|
fresize: c.xresize,
|
||||||
|
}
|
||||||
|
c.widget = widget
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlSingleWidget) xsetParent(p *controlParent) {
|
||||||
|
C.gtk_container_add(p.c, c.widget)
|
||||||
|
// make sure the new widget is shown if not explicitly hidden
|
||||||
|
// TODO why did I have this again?
|
||||||
|
C.gtk_widget_show_all(c.widget)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlSingleWidget) xpreferredSize(d *sizing) (int, int) {
|
||||||
// GTK+ 3 makes this easy: controls can tell us what their preferred size is!
|
// 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".
|
// ...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 "minimum size" is the smallest size we /can/ display /anything/. The "natural size" is the smallest size we would /prefer/ to display.
|
||||||
|
@ -37,15 +47,11 @@ func basepreferredSize(c controlPrivate, d *sizing) (int, int) {
|
||||||
// There is a warning about height-for-width controls, but in my tests this isn't an issue.
|
// There is a warning about height-for-width controls, but in my tests this isn't an issue.
|
||||||
var r C.GtkRequisition
|
var r C.GtkRequisition
|
||||||
|
|
||||||
C.gtk_widget_get_preferred_size(c.widget(), nil, &r)
|
C.gtk_widget_get_preferred_size(c.widget, nil, &r)
|
||||||
return int(r.width), int(r.height)
|
return int(r.width), int(r.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
|
func (c *controlSingleWidget) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
dobasecommitResize(c.widget(), a, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// 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 fine anyway; in fact, this allows us to move without knowing what the container is!
|
||||||
// this is what GtkBox does anyway
|
// this is what GtkBox does anyway
|
||||||
|
@ -53,68 +59,63 @@ func dobasecommitResize(w *C.GtkWidget, c *allocation, d *sizing) {
|
||||||
|
|
||||||
var r C.GtkAllocation
|
var r C.GtkAllocation
|
||||||
|
|
||||||
r.x = C.int(c.x)
|
r.x = C.int(x)
|
||||||
r.y = C.int(c.y)
|
r.y = C.int(y)
|
||||||
r.width = C.int(c.width)
|
r.width = C.int(width)
|
||||||
r.height = C.int(c.height)
|
r.height = C.int(height)
|
||||||
C.gtk_widget_size_allocate(w, &r)
|
C.gtk_widget_size_allocate(c.widget, &r)
|
||||||
}
|
|
||||||
|
|
||||||
func basegetAuxResizeInfo(c Control, 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 {
|
type scroller struct {
|
||||||
|
*controlSingleWidget
|
||||||
|
|
||||||
|
scroller *controlSingleWidget
|
||||||
scrollwidget *C.GtkWidget
|
scrollwidget *C.GtkWidget
|
||||||
scrollcontainer *C.GtkContainer
|
scrollcontainer *C.GtkContainer
|
||||||
scrollwindow *C.GtkScrolledWindow
|
scrollwindow *C.GtkScrolledWindow
|
||||||
|
|
||||||
|
overlay *controlSingleWidget
|
||||||
overlaywidget *C.GtkWidget
|
overlaywidget *C.GtkWidget
|
||||||
overlaycontainer *C.GtkContainer
|
overlaycontainer *C.GtkContainer
|
||||||
overlay *C.GtkOverlay
|
overlayoverlay *C.GtkOverlay
|
||||||
|
|
||||||
addShowWhich *C.GtkWidget
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newScroller(widget *C.GtkWidget, native bool, bordered bool, overlay bool) *scroller {
|
func newScroller(widget *C.GtkWidget, native bool, bordered bool, overlay bool) *scroller {
|
||||||
var o *C.GtkWidget
|
s := new(scroller)
|
||||||
|
s.controlSingleWidget = newControlSingleWidget(widget)
|
||||||
|
s.scrollwidget = C.gtk_scrolled_window_new(nil, nil)
|
||||||
|
s.scrollcontainer = (*C.GtkContainer)(unsafe.Pointer(s.scrollwidget))
|
||||||
|
s.scrollwindow = (*C.GtkScrolledWindow)(unsafe.Pointer(s.scrollwidget))
|
||||||
|
|
||||||
scrollwidget := C.gtk_scrolled_window_new(nil, nil)
|
// any actual changing operations need to be done to the GtkScrolledWindow
|
||||||
if overlay {
|
// that is, everything /except/ preferredSize() are done to the GtkScrolledWindow
|
||||||
o = C.gtk_overlay_new()
|
s.scroller = newControlSingleWidget(s.scrollwidget)
|
||||||
}
|
s.fsetParent = s.scroller.fsetParent
|
||||||
s := &scroller{
|
s.fresize = s.scroller.fresize
|
||||||
scrollwidget: scrollwidget,
|
|
||||||
scrollcontainer: (*C.GtkContainer)(unsafe.Pointer(scrollwidget)),
|
// in GTK+ 3.4 we still technically need to use the separate gtk_scrolled_window_add_with_viewpoint()/gtk_container_add() spiel for adding the widget to the scrolled window
|
||||||
scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scrollwidget)),
|
if native {
|
||||||
overlaywidget: o,
|
C.gtk_container_add(s.scrollcontainer, s.widget)
|
||||||
overlaycontainer: (*C.GtkContainer)(unsafe.Pointer(o)),
|
} else {
|
||||||
overlay: (*C.GtkOverlay)(unsafe.Pointer(o)),
|
C.gtk_scrolled_window_add_with_viewport(s.scrollwindow, s.widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
// give the scrolled window a border (thanks to jlindgren in irc.gimp.net/#gtk+)
|
// give the scrolled window a border (thanks to jlindgren in irc.gimp.net/#gtk+)
|
||||||
if bordered {
|
if bordered {
|
||||||
C.gtk_scrolled_window_set_shadow_type(s.scrollwindow, C.GTK_SHADOW_IN)
|
C.gtk_scrolled_window_set_shadow_type(s.scrollwindow, C.GTK_SHADOW_IN)
|
||||||
}
|
}
|
||||||
if native {
|
|
||||||
C.gtk_container_add(s.scrollcontainer, widget)
|
|
||||||
} else {
|
|
||||||
C.gtk_scrolled_window_add_with_viewport(s.scrollwindow, widget)
|
|
||||||
}
|
|
||||||
s.addShowWhich = s.scrollwidget
|
|
||||||
if overlay {
|
if overlay {
|
||||||
|
// ok things get REALLY fun now
|
||||||
|
// we now have to do all of the above again
|
||||||
|
s.overlaywidget = C.gtk_overlay_new()
|
||||||
|
s.overlaycontainer = (*C.GtkContainer)(unsafe.Pointer(s.overlaywidget))
|
||||||
|
s.overlayoverlay = (*C.GtkOverlay)(unsafe.Pointer(s.overlaywidget))
|
||||||
|
s.overlay = newControlSingleWidget(s.overlaywidget)
|
||||||
|
s.fsetParent = s.overlay.fsetParent
|
||||||
|
s.fresize = s.overlay.fresize
|
||||||
C.gtk_container_add(s.overlaycontainer, s.scrollwidget)
|
C.gtk_container_add(s.overlaycontainer, s.scrollwidget)
|
||||||
s.addShowWhich = s.overlaywidget
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scroller) setParent(p *controlParent) {
|
|
||||||
C.gtk_container_add(p.c, s.addShowWhich)
|
|
||||||
// see basesetParent() above for why we call gtk_widget_show_all()
|
|
||||||
C.gtk_widget_show_all(s.addShowWhich)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *scroller) commitResize(c *allocation, d *sizing) {
|
|
||||||
dobasecommitResize(s.addShowWhich, c, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,45 +5,59 @@ package ui
|
||||||
// #include "winapi_windows.h"
|
// #include "winapi_windows.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type controlPrivate interface {
|
|
||||||
hwnd() C.HWND
|
|
||||||
Control
|
|
||||||
}
|
|
||||||
|
|
||||||
type controlParent struct {
|
type controlParent struct {
|
||||||
c *container
|
hwnd C.HWND
|
||||||
}
|
}
|
||||||
|
|
||||||
func basesetParent(c controlPrivate, p *controlParent) {
|
// don't specify preferredSize in any of these; they're per-control
|
||||||
C.controlSetParent(c.hwnd(), p.c.hwnd)
|
|
||||||
p.c.nchildren++
|
type controlSingleHWND struct {
|
||||||
|
*controlbase
|
||||||
|
hwnd C.HWND
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't specify basepreferredSize; it is custom on ALL controls
|
func newControlSingleHWND(hwnd C.HWND) *controlSingleHWND {
|
||||||
|
c := new(controlSingleHWND)
|
||||||
func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
|
c.controlbase = &controlbase{
|
||||||
C.moveWindow(c.hwnd(), C.int(a.x), C.int(a.y), C.int(a.width), C.int(a.height))
|
fsetParent: c.xsetParent,
|
||||||
|
fresize: c.xresize,
|
||||||
|
fnTabStops: func() int {
|
||||||
|
// most controls count as one tab stop
|
||||||
|
return 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c.hwnd = hwnd
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func basegetAuxResizeInfo(c controlPrivate, d *sizing) {
|
func (c *controlSingleHWND) xsetParent(p *controlParent) {
|
||||||
// do nothing
|
C.controlSetParent(c.hwnd, p.hwnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlSingleHWND) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
|
C.moveWindow(c.hwnd, C.int(x), C.int(y), C.int(width), C.int(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are provided for convenience
|
// these are provided for convenience
|
||||||
|
|
||||||
type textableControl interface {
|
type controlSingleHWNDWithText struct {
|
||||||
controlPrivate
|
*controlSingleHWND
|
||||||
textlen() C.LONG
|
textlen C.LONG
|
||||||
settextlen(C.LONG)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseText(c textableControl) string {
|
func newControlSingleHWNDWithText(h C.HWND) *controlSingleHWNDWithText {
|
||||||
return getWindowText(c.hwnd())
|
return &controlSingleHWNDWithText{
|
||||||
|
controlSingleHWND: newControlSingleHWND(h),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseSetText(c textableControl, text string) {
|
// TODO export these instead of requiring dummy declarations in each implementation
|
||||||
hwnd := c.hwnd()
|
func (c *controlSingleHWNDWithText) text() string {
|
||||||
|
return getWindowText(c.hwnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controlSingleHWNDWithText) setText(text string) {
|
||||||
t := toUTF16(text)
|
t := toUTF16(text)
|
||||||
C.setWindowText(hwnd, t)
|
C.setWindowText(c.hwnd, t)
|
||||||
c.settextlen(C.controlTextLength(hwnd, t))
|
c.textlen = C.controlTextLength(c.hwnd, t)
|
||||||
}
|
}
|
||||||
|
|
94
grid.go
94
grid.go
|
@ -27,6 +27,11 @@ type Grid interface {
|
||||||
// The effect of overlapping spanning Controls is also undefined.
|
// The effect of overlapping spanning Controls is also undefined.
|
||||||
// Add panics if either xspan or yspan are zero or negative.
|
// Add panics if either xspan or yspan are zero or negative.
|
||||||
Add(control Control, nextTo Control, side Side, xexpand bool, xalign Align, yexpand bool, yalign Align, xspan int, yspan int)
|
Add(control Control, nextTo Control, side Side, xexpand bool, xalign Align, yexpand bool, yalign Align, xspan int, yspan int)
|
||||||
|
|
||||||
|
// Padded and SetPadded get and set whether the controls of the Grid have padding between them.
|
||||||
|
// The size of the padding is platform-dependent.
|
||||||
|
Padded() bool
|
||||||
|
SetPadded(padded bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align represents the alignment of a Control in its cell of a Grid.
|
// Align represents the alignment of a Control in its cell of a Grid.
|
||||||
|
@ -54,7 +59,8 @@ type grid struct {
|
||||||
controls []gridCell
|
controls []gridCell
|
||||||
indexof map[Control]int
|
indexof map[Control]int
|
||||||
prev int
|
prev int
|
||||||
parent *controlParent
|
container *container
|
||||||
|
padded bool
|
||||||
|
|
||||||
xmax int
|
xmax int
|
||||||
ymax int
|
ymax int
|
||||||
|
@ -84,6 +90,7 @@ type gridCell struct {
|
||||||
func NewGrid() Grid {
|
func NewGrid() Grid {
|
||||||
return &grid{
|
return &grid{
|
||||||
indexof: map[Control]int{},
|
indexof: map[Control]int{},
|
||||||
|
container: newContainer(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +136,7 @@ func (g *grid) Add(control Control, nextTo Control, side Side, xexpand bool, xal
|
||||||
xspan: xspan,
|
xspan: xspan,
|
||||||
yspan: yspan,
|
yspan: yspan,
|
||||||
}
|
}
|
||||||
if g.parent != nil {
|
control.setParent(g.container.parent())
|
||||||
control.setParent(g.parent)
|
|
||||||
}
|
|
||||||
// if this is the first control, just add it in directly
|
// if this is the first control, just add it in directly
|
||||||
if len(g.controls) != 0 {
|
if len(g.controls) != 0 {
|
||||||
next := g.prev
|
next := g.prev
|
||||||
|
@ -161,11 +166,16 @@ func (g *grid) Add(control Control, nextTo Control, side Side, xexpand bool, xal
|
||||||
g.reorigin()
|
g.reorigin()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *grid) Padded() bool {
|
||||||
|
return g.padded
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grid) SetPadded(padded bool) {
|
||||||
|
g.padded = padded
|
||||||
|
}
|
||||||
|
|
||||||
func (g *grid) setParent(p *controlParent) {
|
func (g *grid) setParent(p *controlParent) {
|
||||||
g.parent = p
|
g.container.setParent(p)
|
||||||
for i := range g.controls {
|
|
||||||
g.controls[i].control.setParent(g.parent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// builds the topological cell grid; also makes colwidths and rowheights
|
// builds the topological cell grid; also makes colwidths and rowheights
|
||||||
|
@ -187,15 +197,27 @@ func (g *grid) mkgrid() (gg [][]int, colwidths []int, rowheights []int) {
|
||||||
return gg, make([]int, g.xmax), make([]int, g.ymax)
|
return gg, make([]int, g.xmax), make([]int, g.ymax)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) {
|
func (g *grid) resize(x int, y int, width int, height int, d *sizing) {
|
||||||
|
g.container.resize(x, y, width, height, d)
|
||||||
|
|
||||||
if len(g.controls) == 0 {
|
if len(g.controls) == 0 {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return nil
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
x, y, width, height = g.container.bounds(d)
|
||||||
|
|
||||||
|
// -2) get this Grid's padding
|
||||||
|
xpadding := d.xpadding
|
||||||
|
ypadding := d.ypadding
|
||||||
|
if !g.padded {
|
||||||
|
xpadding = 0
|
||||||
|
ypadding = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// -1) discount padding from width/height
|
// -1) discount padding from width/height
|
||||||
width -= (g.xmax - 1) * d.xpadding
|
width -= (g.xmax - 1) * xpadding
|
||||||
height -= (g.ymax - 1) * d.ypadding
|
height -= (g.ymax - 1) * ypadding
|
||||||
|
|
||||||
// 0) build necessary data structures
|
// 0) build necessary data structures
|
||||||
gg, colwidths, rowheights := g.mkgrid()
|
gg, colwidths, rowheights := g.mkgrid()
|
||||||
|
@ -317,11 +339,11 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
|
||||||
if i != prev {
|
if i != prev {
|
||||||
g.controls[i].finalx = curx
|
g.controls[i].finalx = curx
|
||||||
} else {
|
} else {
|
||||||
g.controls[i].finalwidth += d.xpadding
|
g.controls[i].finalwidth += xpadding
|
||||||
}
|
}
|
||||||
g.controls[i].finalwidth += colwidths[x]
|
g.controls[i].finalwidth += colwidths[x]
|
||||||
}
|
}
|
||||||
curx += colwidths[x] + d.xpadding
|
curx += colwidths[x] + xpadding
|
||||||
prev = i
|
prev = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,11 +356,11 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
|
||||||
if i != prev {
|
if i != prev {
|
||||||
g.controls[i].finaly = cury
|
g.controls[i].finaly = cury
|
||||||
} else {
|
} else {
|
||||||
g.controls[i].finalheight += d.ypadding
|
g.controls[i].finalheight += ypadding
|
||||||
}
|
}
|
||||||
g.controls[i].finalheight += rowheights[y]
|
g.controls[i].finalheight += rowheights[y]
|
||||||
}
|
}
|
||||||
cury += rowheights[y] + d.ypadding
|
cury += rowheights[y] + ypadding
|
||||||
prev = i
|
prev = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,29 +389,17 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8) and FINALLY we draw
|
// 8) and FINALLY we draw
|
||||||
var current *allocation
|
|
||||||
|
|
||||||
for _, ycol := range gg {
|
for _, ycol := range gg {
|
||||||
current = nil
|
|
||||||
for _, i := range ycol {
|
for _, i := range ycol {
|
||||||
if i != -1 { // treat empty cells like spaces
|
if i != -1 { // treat empty cells like spaces
|
||||||
as := g.controls[i].control.allocate(
|
g.controls[i].control.resize(
|
||||||
g.controls[i].finalx+x, g.controls[i].finaly+y,
|
g.controls[i].finalx+x, g.controls[i].finaly+y,
|
||||||
g.controls[i].finalwidth, g.controls[i].finalheight, d)
|
g.controls[i].finalwidth, g.controls[i].finalheight, d)
|
||||||
if current != nil { // connect first left to first right
|
|
||||||
current.neighbor = g.controls[i].control
|
|
||||||
}
|
|
||||||
if len(as) != 0 {
|
|
||||||
current = as[0] // next left is first subwidget
|
|
||||||
} else {
|
|
||||||
current = nil // spaces don't have allocation data
|
|
||||||
}
|
|
||||||
allocations = append(allocations, as...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocations
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *grid) preferredSize(d *sizing) (width, height int) {
|
func (g *grid) preferredSize(d *sizing) (width, height int) {
|
||||||
|
@ -398,6 +408,14 @@ func (g *grid) preferredSize(d *sizing) (width, height int) {
|
||||||
return 0, 0
|
return 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -1) get this Grid's padding
|
||||||
|
xpadding := d.xpadding
|
||||||
|
ypadding := d.ypadding
|
||||||
|
if !g.padded {
|
||||||
|
xpadding = 0
|
||||||
|
ypadding = 0
|
||||||
|
}
|
||||||
|
|
||||||
// 0) build necessary data structures
|
// 0) build necessary data structures
|
||||||
gg, colwidths, rowheights := g.mkgrid()
|
gg, colwidths, rowheights := g.mkgrid()
|
||||||
|
|
||||||
|
@ -434,14 +452,14 @@ func (g *grid) preferredSize(d *sizing) (width, height int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// and that's it; just account for padding
|
// and that's it; just account for padding
|
||||||
return colwidth + (g.xmax-1)*d.xpadding,
|
return colwidth + (g.xmax-1) * xpadding,
|
||||||
rowheight + (g.ymax-1)*d.ypadding
|
rowheight + (g.ymax-1) * ypadding
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *grid) commitResize(a *allocation, d *sizing) {
|
func (g *grid) nTabStops() int {
|
||||||
// do nothing; needed to satisfy Control
|
n := 0
|
||||||
}
|
for _, c := range g.controls {
|
||||||
|
n += c.control.nTabStops()
|
||||||
func (g *grid) getAuxResizeInfo(d *sizing) {
|
}
|
||||||
// do nothing; needed to satisfy Control
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,49 +10,51 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type group struct {
|
type group struct {
|
||||||
_id C.id
|
*controlSingleObject
|
||||||
|
|
||||||
*container
|
child Control
|
||||||
|
container *container
|
||||||
|
|
||||||
|
margined bool
|
||||||
|
|
||||||
|
chainresize func(x int, y int, width int, height int, d *sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGroup(text string, control Control) Group {
|
func newGroup(text string, control Control) Group {
|
||||||
g := new(group)
|
g := new(group)
|
||||||
g.container = newContainer(control)
|
g.container = newContainer()
|
||||||
g._id = C.newGroup(g.container.id)
|
g.controlSingleObject = newControlSingleObject(C.newGroup(g.container.id))
|
||||||
|
g.child = control
|
||||||
|
g.child.setParent(g.container.parent())
|
||||||
g.SetText(text)
|
g.SetText(text)
|
||||||
|
g.chainresize = g.fresize
|
||||||
|
g.fresize = g.xresize
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) Text() string {
|
func (g *group) Text() string {
|
||||||
return C.GoString(C.groupText(g._id))
|
return C.GoString(C.groupText(g.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) SetText(text string) {
|
func (g *group) SetText(text string) {
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
C.groupSetText(g._id, ctext)
|
C.groupSetText(g.id, ctext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) id() C.id {
|
func (g *group) Margined() bool {
|
||||||
return g._id
|
return g.margined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) setParent(p *controlParent) {
|
func (g *group) SetMargined(margined bool) {
|
||||||
basesetParent(g, p)
|
g.margined = margined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
func (g *group) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
return baseallocate(g, x, y, width, height, d)
|
// first, chain up to change the GtkFrame and its child container
|
||||||
}
|
g.chainresize(x, y, width, height, d)
|
||||||
|
|
||||||
func (g *group) preferredSize(d *sizing) (width, height int) {
|
// now that the container has the correct size, we can resize the child
|
||||||
return basepreferredSize(g, d)
|
a := g.container.allocation(g.margined)
|
||||||
}
|
g.child.resize(int(a.x), int(a.y), int(a.width), int(a.height), d)
|
||||||
|
|
||||||
func (g *group) commitResize(a *allocation, d *sizing) {
|
|
||||||
basecommitResize(g, a, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *group) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(g, d)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,16 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type group struct {
|
type group struct {
|
||||||
_widget *C.GtkWidget
|
*controlSingleWidget
|
||||||
gcontainer *C.GtkContainer
|
gcontainer *C.GtkContainer
|
||||||
frame *C.GtkFrame
|
frame *C.GtkFrame
|
||||||
|
|
||||||
*container
|
child Control
|
||||||
|
container *container
|
||||||
|
|
||||||
|
margined bool
|
||||||
|
|
||||||
|
chainresize func(x int, y int, width int, height int, d *sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGroup(text string, control Control) Group {
|
func newGroup(text string, control Control) Group {
|
||||||
|
@ -24,9 +29,10 @@ func newGroup(text string, control Control) Group {
|
||||||
defer freegstr(ctext)
|
defer freegstr(ctext)
|
||||||
widget := C.gtk_frame_new(ctext)
|
widget := C.gtk_frame_new(ctext)
|
||||||
g := &group{
|
g := &group{
|
||||||
_widget: widget,
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
gcontainer: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
gcontainer: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
||||||
frame: (*C.GtkFrame)(unsafe.Pointer(widget)),
|
frame: (*C.GtkFrame)(unsafe.Pointer(widget)),
|
||||||
|
child: control,
|
||||||
}
|
}
|
||||||
|
|
||||||
// with GTK+, groupboxes by default have frames and slightly x-offset regular text
|
// with GTK+, groupboxes by default have frames and slightly x-offset regular text
|
||||||
|
@ -46,9 +52,13 @@ func newGroup(text string, control Control) Group {
|
||||||
C.gtk_label_set_attributes(label, boldlist)
|
C.gtk_label_set_attributes(label, boldlist)
|
||||||
C.pango_attr_list_unref(boldlist) // thanks baedert in irc.gimp.net/#gtk+
|
C.pango_attr_list_unref(boldlist) // thanks baedert in irc.gimp.net/#gtk+
|
||||||
|
|
||||||
g.container = newContainer(control)
|
g.container = newContainer()
|
||||||
|
g.child.setParent(g.container.parent())
|
||||||
g.container.setParent(&controlParent{g.gcontainer})
|
g.container.setParent(&controlParent{g.gcontainer})
|
||||||
|
|
||||||
|
g.chainresize = g.fresize
|
||||||
|
g.fresize = g.xresize
|
||||||
|
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,26 +72,19 @@ func (g *group) SetText(text string) {
|
||||||
C.gtk_frame_set_label(g.frame, ctext)
|
C.gtk_frame_set_label(g.frame, ctext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) widget() *C.GtkWidget {
|
func (g *group) Margined() bool {
|
||||||
return g._widget
|
return g.margined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) setParent(p *controlParent) {
|
func (g *group) SetMargined(margined bool) {
|
||||||
basesetParent(g, p)
|
g.margined = margined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
func (g *group) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
return baseallocate(g, x, y, width, height, d)
|
// first, chain up to change the GtkFrame and its child container
|
||||||
}
|
g.chainresize(x, y, width, height, d)
|
||||||
|
|
||||||
func (g *group) preferredSize(d *sizing) (width, height int) {
|
// now that the container has the correct size, we can resize the child
|
||||||
return basepreferredSize(g, d)
|
a := g.container.allocation(g.margined)
|
||||||
}
|
g.child.resize(int(a.x), int(a.y), int(a.width), int(a.height), d)
|
||||||
|
|
||||||
func (g *group) commitResize(a *allocation, d *sizing) {
|
|
||||||
basecommitResize(g, a, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *group) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(g, d)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ package ui
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type group struct {
|
type group struct {
|
||||||
_hwnd C.HWND
|
*controlSingleHWNDWithText
|
||||||
_textlen C.LONG
|
child Control
|
||||||
|
margined bool
|
||||||
*container
|
chainresize func(x int, y int, width int, height int, d *sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGroup(text string, control Control) Group {
|
func newGroup(text string, control Control) Group {
|
||||||
|
@ -17,66 +17,82 @@ func newGroup(text string, control Control) Group {
|
||||||
C.BS_GROUPBOX,
|
C.BS_GROUPBOX,
|
||||||
C.WS_EX_CONTROLPARENT)
|
C.WS_EX_CONTROLPARENT)
|
||||||
g := &group{
|
g := &group{
|
||||||
_hwnd: hwnd,
|
controlSingleHWNDWithText: newControlSingleHWNDWithText(hwnd),
|
||||||
container: newContainer(control),
|
child: control,
|
||||||
}
|
}
|
||||||
|
g.fpreferredSize = g.xpreferredSize
|
||||||
|
g.chainresize = g.fresize
|
||||||
|
g.fresize = g.xresize
|
||||||
|
g.fnTabStops = control.nTabStops // groupbox itself is not tabbable but the contents might be
|
||||||
g.SetText(text)
|
g.SetText(text)
|
||||||
C.controlSetControlFont(g._hwnd)
|
C.controlSetControlFont(g.hwnd)
|
||||||
g.container.setParent(g._hwnd)
|
control.setParent(&controlParent{g.hwnd})
|
||||||
g.container.isGroup = true
|
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) Text() string {
|
func (g *group) Text() string {
|
||||||
return baseText(g)
|
return g.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) SetText(text string) {
|
func (g *group) SetText(text string) {
|
||||||
baseSetText(g, text)
|
g.setText(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) hwnd() C.HWND {
|
func (g *group) Margined() bool {
|
||||||
return g._hwnd
|
return g.margined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) textlen() C.LONG {
|
func (g *group) SetMargined(margined bool) {
|
||||||
return g._textlen
|
g.margined = margined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) settextlen(len C.LONG) {
|
const (
|
||||||
g._textlen = len
|
groupXMargin = 6
|
||||||
}
|
groupYMarginTop = 11 // note this value /includes the groupbox label/
|
||||||
|
groupYMarginBottom = 7
|
||||||
|
)
|
||||||
|
|
||||||
func (g *group) setParent(p *controlParent) {
|
func (g *group) xpreferredSize(d *sizing) (width, height int) {
|
||||||
basesetParent(g, p)
|
var r C.RECT
|
||||||
}
|
|
||||||
|
|
||||||
func (g *group) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(g, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *group) preferredSize(d *sizing) (width, height int) {
|
|
||||||
width, height = g.child.preferredSize(d)
|
width, height = g.child.preferredSize(d)
|
||||||
if width < int(g._textlen) { // if the text is longer, try not to truncate
|
if width < int(g.textlen) { // if the text is longer, try not to truncate
|
||||||
width = int(g._textlen)
|
width = int(g.textlen)
|
||||||
}
|
}
|
||||||
// the two margin constants come from container_windows.go
|
r.left = 0
|
||||||
return width, height + fromdlgunitsY(groupYMarginTop, d) + fromdlgunitsY(groupYMarginBottom, d)
|
r.top = 0
|
||||||
|
r.right = C.LONG(width)
|
||||||
|
r.bottom = C.LONG(height)
|
||||||
|
// use negative numbers to increase the size of the rectangle
|
||||||
|
if g.margined {
|
||||||
|
marginRectDLU(&r, -groupYMarginTop, -groupYMarginBottom, -groupXMargin, -groupXMargin, d)
|
||||||
|
} else {
|
||||||
|
// unforutnately, as mentioned above, the size of a groupbox includes the label and border
|
||||||
|
// 1DLU on each side should be enough to make up for that; TODO is not, we can change it
|
||||||
|
// TODO make these named constants
|
||||||
|
marginRectDLU(&r, -1, -1, -1, -1, d)
|
||||||
|
}
|
||||||
|
return int(r.right - r.left), int(r.bottom - r.top)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *group) commitResize(c *allocation, d *sizing) {
|
func (g *group) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
|
// first, chain up to the container base to keep the Z-order correct
|
||||||
|
g.chainresize(x, y, width, height, d)
|
||||||
|
|
||||||
|
// now resize the child container
|
||||||
var r C.RECT
|
var r C.RECT
|
||||||
|
|
||||||
// pretend that the client area of the group box only includes the actual empty space
|
// pretend that the client area of the group box only includes the actual empty space
|
||||||
// container will handle the necessary adjustments properly
|
// container will handle the necessary adjustments properly
|
||||||
r.left = 0
|
r.left = 0
|
||||||
r.top = 0
|
r.top = 0
|
||||||
r.right = C.LONG(c.width)
|
r.right = C.LONG(width)
|
||||||
r.bottom = C.LONG(c.height)
|
r.bottom = C.LONG(height)
|
||||||
g.container.move(&r)
|
if g.margined {
|
||||||
basecommitResize(g, c, d)
|
// see above
|
||||||
}
|
marginRectDLU(&r, groupYMarginTop, groupYMarginBottom, groupXMargin, groupXMargin, d)
|
||||||
|
} else {
|
||||||
func (g *group) getAuxResizeInfo(d *sizing) {
|
marginRectDLU(&r, 1, 1, 1, 1, d)
|
||||||
basegetAuxResizeInfo(g, d)
|
}
|
||||||
|
g.child.resize(int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top), d)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,57 +10,28 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type label struct {
|
type label struct {
|
||||||
_id C.id
|
*controlSingleObject
|
||||||
standalone bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishNewLabel(text string, standalone bool) *label {
|
func newLabel(text string) Label {
|
||||||
l := &label{
|
l := &label{
|
||||||
_id: C.newLabel(),
|
controlSingleObject: newControlSingleObject(C.newLabel()),
|
||||||
standalone: standalone,
|
|
||||||
}
|
}
|
||||||
l.SetText(text)
|
l.SetText(text)
|
||||||
return l
|
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 {
|
func (l *label) Text() string {
|
||||||
return C.GoString(C.textfieldText(l._id))
|
return C.GoString(C.textfieldText(l.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *label) SetText(text string) {
|
func (l *label) SetText(text string) {
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
C.textfieldSetText(l._id, ctext)
|
C.textfieldSetText(l.id, ctext)
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) isStandalone() bool {
|
|
||||||
return l.standalone
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) id() C.id {
|
|
||||||
return l._id
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) setParent(p *controlParent) {
|
|
||||||
basesetParent(l, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*TODO
|
||||||
func (l *label) commitResize(c *allocation, d *sizing) {
|
func (l *label) commitResize(c *allocation, d *sizing) {
|
||||||
if !l.standalone && c.neighbor != nil {
|
if !l.standalone && c.neighbor != nil {
|
||||||
c.neighbor.getAuxResizeInfo(d)
|
c.neighbor.getAuxResizeInfo(d)
|
||||||
|
@ -89,7 +60,4 @@ func (l *label) commitResize(c *allocation, d *sizing) {
|
||||||
}
|
}
|
||||||
basecommitResize(l, c, d)
|
basecommitResize(l, c, d)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
func (l *label) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(l, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,40 +9,34 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// #include "gtk_unix.h"
|
// #include "gtk_unix.h"
|
||||||
// extern void buttonClicked(GtkButton *, gpointer);
|
|
||||||
// extern void checkboxToggled(GtkToggleButton *, gpointer);
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type label struct {
|
type label struct {
|
||||||
_widget *C.GtkWidget
|
*controlSingleWidget
|
||||||
misc *C.GtkMisc
|
misc *C.GtkMisc
|
||||||
label *C.GtkLabel
|
label *C.GtkLabel
|
||||||
standalone bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishNewLabel(text string, standalone bool) *label {
|
func newLabel(text string) 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)
|
||||||
l := &label{
|
l := &label{
|
||||||
_widget: widget,
|
controlSingleWidget: newControlSingleWidget(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,
|
|
||||||
}
|
}
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLabel(text string) Label {
|
/*TODO
|
||||||
return finishNewLabel(text, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStandaloneLabel(text string) Label {
|
func newStandaloneLabel(text string) Label {
|
||||||
l := finishNewLabel(text, true)
|
l := finishNewLabel(text, true)
|
||||||
// standalone labels are always at the top left
|
// standalone labels are always at the top left
|
||||||
C.gtk_misc_set_alignment(l.misc, 0, 0)
|
C.gtk_misc_set_alignment(l.misc, 0, 0)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (l *label) Text() string {
|
func (l *label) Text() string {
|
||||||
return fromgstr(C.gtk_label_get_text(l.label))
|
return fromgstr(C.gtk_label_get_text(l.label))
|
||||||
|
@ -54,26 +48,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) isStandalone() bool {
|
/*TODO
|
||||||
return l.standalone
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) widget() *C.GtkWidget {
|
|
||||||
return l._widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) setParent(p *controlParent) {
|
|
||||||
basesetParent(l, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
func (l *label) commitResize(c *allocation, d *sizing) {
|
||||||
if !l.standalone && c.neighbor != nil {
|
if !l.standalone && c.neighbor != nil {
|
||||||
c.neighbor.getAuxResizeInfo(d)
|
c.neighbor.getAuxResizeInfo(d)
|
||||||
|
@ -86,7 +61,4 @@ func (l *label) commitResize(c *allocation, d *sizing) {
|
||||||
}
|
}
|
||||||
basecommitResize(l, c, d)
|
basecommitResize(l, c, d)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
func (l *label) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(l, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,67 +6,37 @@ package ui
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type label struct {
|
type label struct {
|
||||||
_hwnd C.HWND
|
*controlSingleHWNDWithText
|
||||||
_textlen C.LONG
|
|
||||||
standalone bool
|
standalone bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var labelclass = toUTF16("STATIC")
|
var labelclass = toUTF16("STATIC")
|
||||||
|
|
||||||
func finishNewLabel(text string, standalone bool) *label {
|
func newLabel(text string) Label {
|
||||||
hwnd := C.newControl(labelclass,
|
hwnd := C.newControl(labelclass,
|
||||||
// SS_NOPREFIX avoids accelerator translation; SS_LEFTNOWORDWRAP clips text past the end
|
// 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)
|
// controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi)
|
||||||
C.SS_NOPREFIX|C.SS_LEFTNOWORDWRAP,
|
C.SS_NOPREFIX|C.SS_LEFTNOWORDWRAP,
|
||||||
C.WS_EX_TRANSPARENT)
|
C.WS_EX_TRANSPARENT)
|
||||||
l := &label{
|
l := &label{
|
||||||
_hwnd: hwnd,
|
controlSingleHWNDWithText: newControlSingleHWNDWithText(hwnd),
|
||||||
standalone: standalone,
|
}
|
||||||
|
l.fpreferredSize = l.xpreferredSize
|
||||||
|
l.fnTabStops = func() int {
|
||||||
|
// labels are not tab stops
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
l.SetText(text)
|
l.SetText(text)
|
||||||
C.controlSetControlFont(l._hwnd)
|
C.controlSetControlFont(l.hwnd)
|
||||||
return l
|
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 {
|
func (l *label) Text() string {
|
||||||
return baseText(l)
|
return l.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *label) SetText(text string) {
|
func (l *label) SetText(text string) {
|
||||||
baseSetText(l, text)
|
l.setText(text)
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) isStandalone() bool {
|
|
||||||
return l.standalone
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) hwnd() C.HWND {
|
|
||||||
return l._hwnd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) textlen() C.LONG {
|
|
||||||
return l._textlen
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) settextlen(len C.LONG) {
|
|
||||||
l._textlen = len
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) setParent(p *controlParent) {
|
|
||||||
C.controlSetParent(l.hwnd(), p.c.hwnd)
|
|
||||||
// don't increment p.c.nchildren here because Labels aren't tab stops
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(l, x, y, width, height, d)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -75,10 +45,11 @@ const (
|
||||||
labelYOffset = 3
|
labelYOffset = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *label) preferredSize(d *sizing) (width, height int) {
|
func (l *label) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return int(l._textlen), fromdlgunitsY(labelHeight, d)
|
return int(l.textlen), fromdlgunitsY(labelHeight, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*TODO
|
||||||
func (l *label) commitResize(c *allocation, d *sizing) {
|
func (l *label) commitResize(c *allocation, d *sizing) {
|
||||||
if !l.standalone {
|
if !l.standalone {
|
||||||
yoff := fromdlgunitsY(labelYOffset, d)
|
yoff := fromdlgunitsY(labelYOffset, d)
|
||||||
|
@ -93,7 +64,4 @@ func (l *label) commitResize(c *allocation, d *sizing) {
|
||||||
}
|
}
|
||||||
basecommitResize(l, c, d)
|
basecommitResize(l, c, d)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
func (l *label) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(l, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ extern void groupSetText(id, char *);
|
||||||
/* container_darwin.m */
|
/* container_darwin.m */
|
||||||
extern id newContainerView(void *);
|
extern id newContainerView(void *);
|
||||||
extern void moveControl(id, intptr_t, intptr_t, intptr_t, intptr_t);
|
extern void moveControl(id, intptr_t, intptr_t, intptr_t, intptr_t);
|
||||||
|
extern struct xrect containerBounds(id);
|
||||||
|
|
||||||
/* tab_darwin.m */
|
/* tab_darwin.m */
|
||||||
extern id newTab(void);
|
extern id newTab(void);
|
||||||
|
|
102
simplegrid.go
102
simplegrid.go
|
@ -14,8 +14,6 @@ import (
|
||||||
// One Control can be marked as "stretchy": when the Window containing the SimpleGrid is resized, the cell containing that Control resizes to take any remaining space; its row and column are adjusted accordingly (so other filling controls in the same row and column will fill to the new height and width, respectively).
|
// One Control can be marked as "stretchy": when the Window containing the SimpleGrid is resized, the cell containing that Control resizes to take any remaining space; its row and column are adjusted accordingly (so other filling controls in the same row and column will fill to the new height and width, respectively).
|
||||||
// A stretchy Control implicitly fills its cell.
|
// A stretchy Control implicitly fills its cell.
|
||||||
// All cooridnates in a SimpleGrid are given in (row,column) form with (0,0) being the top-left cell.
|
// All cooridnates in a SimpleGrid are given in (row,column) form with (0,0) being the top-left cell.
|
||||||
//
|
|
||||||
// As a special rule, to ensure proper appearance, non-standalone Labels are automatically made filling.
|
|
||||||
type SimpleGrid interface {
|
type SimpleGrid interface {
|
||||||
Control
|
Control
|
||||||
|
|
||||||
|
@ -28,6 +26,11 @@ type SimpleGrid interface {
|
||||||
// Only one control can be stretchy per SimpleGrid; calling SetStretchy multiple times merely changes which control is stretchy (preserving the previous filling value).
|
// Only one control can be stretchy per SimpleGrid; calling SetStretchy multiple times merely changes which control is stretchy (preserving the previous filling value).
|
||||||
// It panics if the given coordinate is invalid.
|
// It panics if the given coordinate is invalid.
|
||||||
SetStretchy(row int, column int)
|
SetStretchy(row int, column int)
|
||||||
|
|
||||||
|
// Padded and SetPadded get and set whether the controls of the SimpleGrid have padding between them.
|
||||||
|
// The size of the padding is platform-dependent.
|
||||||
|
Padded() bool
|
||||||
|
SetPadded(padded bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
type simpleGrid struct {
|
type simpleGrid struct {
|
||||||
|
@ -37,6 +40,8 @@ type simpleGrid struct {
|
||||||
stretchyfill bool
|
stretchyfill bool
|
||||||
widths, heights [][]int // caches to avoid reallocating each time
|
widths, heights [][]int // caches to avoid reallocating each time
|
||||||
rowheights, colwidths []int
|
rowheights, colwidths []int
|
||||||
|
container *container
|
||||||
|
padded bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimpleGrid creates a new SimpleGrid with the given Controls.
|
// NewSimpleGrid creates a new SimpleGrid with the given Controls.
|
||||||
|
@ -64,13 +69,10 @@ func NewSimpleGrid(nPerRow int, controls ...Control) SimpleGrid {
|
||||||
ch[row] = make([]int, nPerRow)
|
ch[row] = make([]int, nPerRow)
|
||||||
for x := 0; x < nPerRow; x++ {
|
for x := 0; x < nPerRow; x++ {
|
||||||
cc[row][x] = controls[i]
|
cc[row][x] = controls[i]
|
||||||
if l, ok := controls[i].(Label); ok && !l.isStandalone() {
|
|
||||||
cf[row][x] = true
|
|
||||||
}
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &simpleGrid{
|
g := &simpleGrid{
|
||||||
controls: cc,
|
controls: cc,
|
||||||
filling: cf,
|
filling: cf,
|
||||||
stretchyrow: -1,
|
stretchyrow: -1,
|
||||||
|
@ -79,7 +81,15 @@ func NewSimpleGrid(nPerRow int, controls ...Control) SimpleGrid {
|
||||||
heights: ch,
|
heights: ch,
|
||||||
rowheights: make([]int, nRows),
|
rowheights: make([]int, nRows),
|
||||||
colwidths: make([]int, nPerRow),
|
colwidths: make([]int, nPerRow),
|
||||||
|
container: newContainer(),
|
||||||
}
|
}
|
||||||
|
p := g.container.parent()
|
||||||
|
for _, cc := range g.controls {
|
||||||
|
for _, c := range cc {
|
||||||
|
c.setParent(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *simpleGrid) SetFilling(row int, column int) {
|
func (g *simpleGrid) SetFilling(row int, column int) {
|
||||||
|
@ -102,15 +112,19 @@ func (g *simpleGrid) SetStretchy(row int, column int) {
|
||||||
g.filling[g.stretchyrow][g.stretchycol] = true
|
g.filling[g.stretchyrow][g.stretchycol] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *simpleGrid) setParent(parent *controlParent) {
|
func (g *simpleGrid) Padded() bool {
|
||||||
for _, col := range g.controls {
|
return g.padded
|
||||||
for _, c := range col {
|
|
||||||
c.setParent(parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) {
|
func (g *simpleGrid) SetPadded(padded bool) {
|
||||||
|
g.padded = padded
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *simpleGrid) setParent(parent *controlParent) {
|
||||||
|
g.container.setParent(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *simpleGrid) resize(x int, y int, width int, height int, d *sizing) {
|
||||||
max := func(a int, b int) int {
|
max := func(a int, b int) int {
|
||||||
if a > b {
|
if a > b {
|
||||||
return a
|
return a
|
||||||
|
@ -118,14 +132,21 @@ func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (a
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
var current *allocation // for neighboring
|
g.container.resize(x, y, width, height, d)
|
||||||
|
|
||||||
if len(g.controls) == 0 {
|
if len(g.controls) == 0 {
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
// 0) inset the available rect by the needed padding
|
x, y, width, height = g.container.bounds(d)
|
||||||
width -= (len(g.colwidths) - 1) * d.xpadding
|
// -1) get this SimpleGrid's padding
|
||||||
height -= (len(g.rowheights) - 1) * d.ypadding
|
xpadding := d.xpadding
|
||||||
|
ypadding := d.ypadding
|
||||||
|
if !g.padded {
|
||||||
|
xpadding = 0
|
||||||
|
ypadding = 0
|
||||||
|
}
|
||||||
|
// 0) inset the available rect by the needed padding and reset x/y for children
|
||||||
|
width -= (len(g.colwidths) - 1) * xpadding
|
||||||
|
height -= (len(g.rowheights) - 1) * ypadding
|
||||||
// 1) clear data structures
|
// 1) clear data structures
|
||||||
for i := range g.rowheights {
|
for i := range g.rowheights {
|
||||||
g.rowheights[i] = 0
|
g.rowheights[i] = 0
|
||||||
|
@ -161,7 +182,6 @@ func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (a
|
||||||
// 4) draw
|
// 4) draw
|
||||||
startx := x
|
startx := x
|
||||||
for row, xcol := range g.controls {
|
for row, xcol := range g.controls {
|
||||||
current = nil // reset on new columns
|
|
||||||
for col, c := range xcol {
|
for col, c := range xcol {
|
||||||
w := g.widths[row][col]
|
w := g.widths[row][col]
|
||||||
h := g.heights[row][col]
|
h := g.heights[row][col]
|
||||||
|
@ -169,22 +189,12 @@ func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (a
|
||||||
w = g.colwidths[col]
|
w = g.colwidths[col]
|
||||||
h = g.rowheights[row]
|
h = g.rowheights[row]
|
||||||
}
|
}
|
||||||
as := c.allocate(x, y, w, h, d)
|
c.resize(x, y, w, h, d)
|
||||||
if current != nil { // connect first left to first right
|
x += g.colwidths[col] + xpadding
|
||||||
current.neighbor = c
|
|
||||||
}
|
|
||||||
if len(as) != 0 {
|
|
||||||
current = as[0] // next left is first subwidget
|
|
||||||
} else {
|
|
||||||
current = nil // spaces don't have allocation data
|
|
||||||
}
|
|
||||||
allocations = append(allocations, as...)
|
|
||||||
x += g.colwidths[col] + d.xpadding
|
|
||||||
}
|
}
|
||||||
x = startx
|
x = startx
|
||||||
y += g.rowheights[row] + d.ypadding
|
y += g.rowheights[row] + ypadding
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// filling and stretchy are ignored for preferred size calculation
|
// filling and stretchy are ignored for preferred size calculation
|
||||||
|
@ -196,8 +206,14 @@ func (g *simpleGrid) preferredSize(d *sizing) (width int, height int) {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
width -= (len(g.colwidths) - 1) * d.xpadding
|
xpadding := d.xpadding
|
||||||
height -= (len(g.rowheights) - 1) * d.ypadding
|
ypadding := d.ypadding
|
||||||
|
if !g.padded {
|
||||||
|
xpadding = 0
|
||||||
|
ypadding = 0
|
||||||
|
}
|
||||||
|
width -= (len(g.colwidths) - 1) * xpadding
|
||||||
|
height -= (len(g.rowheights) - 1) * ypadding
|
||||||
// 1) clear data structures
|
// 1) clear data structures
|
||||||
for i := range g.rowheights {
|
for i := range g.rowheights {
|
||||||
g.rowheights[i] = 0
|
g.rowheights[i] = 0
|
||||||
|
@ -225,10 +241,12 @@ func (g *simpleGrid) preferredSize(d *sizing) (width int, height int) {
|
||||||
return width, height
|
return width, height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *simpleGrid) commitResize(c *allocation, d *sizing) {
|
func (g *simpleGrid) nTabStops() int {
|
||||||
// this is to satisfy Control; nothing to do here
|
n := 0
|
||||||
}
|
for _, cc := range g.controls {
|
||||||
|
for _, c := range cc {
|
||||||
func (g *simpleGrid) getAuxResizeInfo(d *sizing) {
|
n += c.nTabStops()
|
||||||
// this is to satisfy Control; nothing to do here
|
}
|
||||||
}
|
}
|
||||||
|
return n
|
||||||
|
}
|
90
stack.go
90
stack.go
|
@ -24,6 +24,11 @@ type Stack interface {
|
||||||
// SetStretchy marks a control in a Stack as stretchy.
|
// SetStretchy marks a control in a Stack as stretchy.
|
||||||
// It panics if index is out of range.
|
// It panics if index is out of range.
|
||||||
SetStretchy(index int)
|
SetStretchy(index int)
|
||||||
|
|
||||||
|
// Padded and SetPadded get and set whether the controls of the Stack have padding between them.
|
||||||
|
// The size of the padding is platform-dependent.
|
||||||
|
Padded() bool
|
||||||
|
SetPadded(padded bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
type stack struct {
|
type stack struct {
|
||||||
|
@ -31,16 +36,24 @@ type stack struct {
|
||||||
controls []Control
|
controls []Control
|
||||||
stretchy []bool
|
stretchy []bool
|
||||||
width, height []int // caches to avoid reallocating these each time
|
width, height []int // caches to avoid reallocating these each time
|
||||||
|
container *container
|
||||||
|
padded bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStack(o orientation, controls ...Control) Stack {
|
func newStack(o orientation, controls ...Control) Stack {
|
||||||
return &stack{
|
s := &stack{
|
||||||
orientation: o,
|
orientation: o,
|
||||||
controls: controls,
|
controls: controls,
|
||||||
stretchy: make([]bool, len(controls)),
|
stretchy: make([]bool, len(controls)),
|
||||||
width: make([]int, len(controls)),
|
width: make([]int, len(controls)),
|
||||||
height: make([]int, len(controls)),
|
height: make([]int, len(controls)),
|
||||||
|
container: newContainer(),
|
||||||
}
|
}
|
||||||
|
p := s.container.parent()
|
||||||
|
for _, c := range s.controls {
|
||||||
|
c.setParent(p)
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHorizontalStack creates a new Stack that arranges the given Controls horizontally.
|
// NewHorizontalStack creates a new Stack that arranges the given Controls horizontally.
|
||||||
|
@ -60,24 +73,38 @@ func (s *stack) SetStretchy(index int) {
|
||||||
s.stretchy[index] = true
|
s.stretchy[index] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stack) setParent(parent *controlParent) {
|
func (s *stack) Padded() bool {
|
||||||
for _, c := range s.controls {
|
return s.padded
|
||||||
c.setParent(parent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stack) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) {
|
func (s *stack) SetPadded(padded bool) {
|
||||||
var stretchywid, stretchyht int
|
s.padded = padded
|
||||||
var current *allocation // for neighboring
|
}
|
||||||
|
|
||||||
|
func (s *stack) setParent(parent *controlParent) {
|
||||||
|
s.container.setParent(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stack) resize(x int, y int, width int, height int, d *sizing) {
|
||||||
|
var stretchywid, stretchyht int
|
||||||
|
|
||||||
|
s.container.resize(x, y, width, height, d)
|
||||||
if len(s.controls) == 0 { // do nothing if there's nothing to do
|
if len(s.controls) == 0 { // do nothing if there's nothing to do
|
||||||
return nil
|
return
|
||||||
|
}
|
||||||
|
x, y, width, height = s.container.bounds(d)
|
||||||
|
// -1) get this Stack's padding
|
||||||
|
xpadding := d.xpadding
|
||||||
|
ypadding := d.ypadding
|
||||||
|
if !s.padded {
|
||||||
|
xpadding = 0
|
||||||
|
ypadding = 0
|
||||||
}
|
}
|
||||||
// 0) inset the available rect by the needed padding
|
// 0) inset the available rect by the needed padding
|
||||||
if s.orientation == horizontal {
|
if s.orientation == horizontal {
|
||||||
width -= (len(s.controls) - 1) * d.xpadding
|
width -= (len(s.controls) - 1) * xpadding
|
||||||
} else {
|
} else {
|
||||||
height -= (len(s.controls) - 1) * d.ypadding
|
height -= (len(s.controls) - 1) * ypadding
|
||||||
}
|
}
|
||||||
// 1) get height and width of non-stretchy controls; figure out how much space is alloted to stretchy controls
|
// 1) get height and width of non-stretchy controls; figure out how much space is alloted to stretchy controls
|
||||||
stretchywid = width
|
stretchywid = width
|
||||||
|
@ -116,25 +143,14 @@ func (s *stack) allocate(x int, y int, width int, height int, d *sizing) (alloca
|
||||||
}
|
}
|
||||||
// 3) now actually place controls
|
// 3) now actually place controls
|
||||||
for i, c := range s.controls {
|
for i, c := range s.controls {
|
||||||
as := c.allocate(x, y, s.width[i], s.height[i], d)
|
c.resize(x, y, s.width[i], s.height[i], d)
|
||||||
if s.orientation == horizontal { // no vertical neighbors
|
|
||||||
if current != nil { // connect first left to first right
|
|
||||||
current.neighbor = c
|
|
||||||
}
|
|
||||||
if len(as) != 0 {
|
|
||||||
current = as[0] // next left is first subwidget
|
|
||||||
} else {
|
|
||||||
current = nil // spaces don't have allocation data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allocations = append(allocations, as...)
|
|
||||||
if s.orientation == horizontal {
|
if s.orientation == horizontal {
|
||||||
x += s.width[i] + d.xpadding
|
x += s.width[i] + xpadding
|
||||||
} else {
|
} else {
|
||||||
y += s.height[i] + d.ypadding
|
y += s.height[i] + ypadding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allocations
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The preferred size of a Stack is the sum of the preferred sizes of non-stretchy controls + (the number of stretchy controls * the largest preferred size among all stretchy controls).
|
// The preferred size of a Stack is the sum of the preferred sizes of non-stretchy controls + (the number of stretchy controls * the largest preferred size among all stretchy controls).
|
||||||
|
@ -152,10 +168,16 @@ func (s *stack) preferredSize(d *sizing) (width int, height int) {
|
||||||
if len(s.controls) == 0 { // no controls, so return emptiness
|
if len(s.controls) == 0 { // no controls, so return emptiness
|
||||||
return 0, 0
|
return 0, 0
|
||||||
}
|
}
|
||||||
|
xpadding := d.xpadding
|
||||||
|
ypadding := d.ypadding
|
||||||
|
if !s.padded {
|
||||||
|
xpadding = 0
|
||||||
|
ypadding = 0
|
||||||
|
}
|
||||||
if s.orientation == horizontal {
|
if s.orientation == horizontal {
|
||||||
width = (len(s.controls) - 1) * d.xpadding
|
width = (len(s.controls) - 1) * xpadding
|
||||||
} else {
|
} else {
|
||||||
height = (len(s.controls) - 1) * d.ypadding
|
height = (len(s.controls) - 1) * ypadding
|
||||||
}
|
}
|
||||||
for i, c := range s.controls {
|
for i, c := range s.controls {
|
||||||
w, h := c.preferredSize(d)
|
w, h := c.preferredSize(d)
|
||||||
|
@ -184,13 +206,15 @@ func (s *stack) preferredSize(d *sizing) (width int, height int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stack) commitResize(c *allocation, d *sizing) {
|
func (s *stack) nTabStops() int {
|
||||||
// this is to satisfy Control; nothing to do here
|
n := 0
|
||||||
|
for _, c := range s.controls {
|
||||||
|
n += c.nTabStops()
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stack) getAuxResizeInfo(d *sizing) {
|
// TODO the below needs to be changed
|
||||||
// this is to satisfy Control; nothing to do here
|
|
||||||
}
|
|
||||||
|
|
||||||
// Space returns a null Control intended for padding layouts with blank space.
|
// Space returns a null Control intended for padding layouts with blank space.
|
||||||
// It appears to its owner as a Control of 0x0 size.
|
// It appears to its owner as a Control of 0x0 size.
|
||||||
|
|
|
@ -10,46 +10,44 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type tab struct {
|
type tab struct {
|
||||||
_id C.id
|
*controlSingleObject
|
||||||
tabs []*container
|
tabs []*container
|
||||||
|
children []Control
|
||||||
|
chainresize func(x int, y int, width int, height int, d *sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTab() Tab {
|
func newTab() Tab {
|
||||||
return &tab{
|
t := &tab{
|
||||||
_id: C.newTab(),
|
controlSingleObject: newControlSingleObject(C.newTab()),
|
||||||
}
|
}
|
||||||
|
t.fpreferredSize = t.xpreferredSize
|
||||||
|
t.chainresize = t.fresize
|
||||||
|
t.fresize = t.xresize
|
||||||
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tab) Append(name string, control Control) {
|
func (t *tab) Append(name string, control Control) {
|
||||||
c := newContainer(control)
|
c := newContainer()
|
||||||
t.tabs = append(t.tabs, c)
|
t.tabs = append(t.tabs, c)
|
||||||
|
control.setParent(c.parent())
|
||||||
|
t.children = append(t.children, control)
|
||||||
cname := C.CString(name)
|
cname := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(cname))
|
defer C.free(unsafe.Pointer(cname))
|
||||||
C.tabAppend(t._id, cname, c.id)
|
C.tabAppend(t.id, cname, c.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tab) id() C.id {
|
func (t *tab) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return t._id
|
s := C.tabPreferredSize(t.id)
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tab) setParent(p *controlParent) {
|
|
||||||
basesetParent(t, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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.tabPreferredSize(t._id)
|
|
||||||
return int(s.width), int(s.height)
|
return int(s.width), int(s.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// no need to override Control.commitResize() as only prepared the tabbed control; its children will be resized when that one is resized (and NSTabView itself will call setFrame: for us)
|
func (t *tab) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
func (t *tab) commitResize(a *allocation, d *sizing) {
|
// first, chain up to change the GtkFrame and its child container
|
||||||
basecommitResize(t, a, d)
|
t.chainresize(x, y, width, height, d)
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tab) getAuxResizeInfo(d *sizing) {
|
// now that the containers have the correct size, we can resize the children
|
||||||
basegetAuxResizeInfo(t, d)
|
for i, _ := range t.tabs {
|
||||||
|
a := t.tabs[i].allocation(false/*TODO*/)
|
||||||
|
t.children[i].resize(int(a.x), int(a.y), int(a.width), int(a.height), d)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
43
tab_unix.go
43
tab_unix.go
|
@ -12,30 +12,37 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type tab struct {
|
type tab struct {
|
||||||
_widget *C.GtkWidget
|
*controlSingleWidget
|
||||||
container *C.GtkContainer
|
container *C.GtkContainer
|
||||||
notebook *C.GtkNotebook
|
notebook *C.GtkNotebook
|
||||||
|
|
||||||
tabs []*container
|
tabs []*container
|
||||||
|
children []Control
|
||||||
|
|
||||||
|
chainresize func(x int, y int, width int, height int, d *sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTab() Tab {
|
func newTab() Tab {
|
||||||
widget := C.gtk_notebook_new()
|
widget := C.gtk_notebook_new()
|
||||||
t := &tab{
|
t := &tab{
|
||||||
_widget: widget,
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
container: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
container: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
||||||
notebook: (*C.GtkNotebook)(unsafe.Pointer(widget)),
|
notebook: (*C.GtkNotebook)(unsafe.Pointer(widget)),
|
||||||
}
|
}
|
||||||
|
t.chainresize = t.fresize
|
||||||
|
t.fresize = t.xresize
|
||||||
// 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
|
||||||
C.gtk_notebook_set_scrollable(t.notebook, C.TRUE)
|
C.gtk_notebook_set_scrollable(t.notebook, C.TRUE)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tab) Append(name string, control Control) {
|
func (t *tab) Append(name string, control Control) {
|
||||||
c := newContainer(control)
|
c := newContainer()
|
||||||
t.tabs = append(t.tabs, c)
|
t.tabs = append(t.tabs, c)
|
||||||
// this calls gtk_container_add(), which, according to gregier in irc.gimp.net/#gtk+, acts just like gtk_notebook_append_page()
|
// this calls gtk_container_add(), which, according to gregier in irc.gimp.net/#gtk+, acts just like gtk_notebook_append_page()
|
||||||
c.setParent(&controlParent{t.container})
|
c.setParent(&controlParent{t.container})
|
||||||
|
control.setParent(c.parent())
|
||||||
|
t.children = append(t.children, control)
|
||||||
cname := togstr(name)
|
cname := togstr(name)
|
||||||
defer freegstr(cname)
|
defer freegstr(cname)
|
||||||
C.gtk_notebook_set_tab_label_text(t.notebook,
|
C.gtk_notebook_set_tab_label_text(t.notebook,
|
||||||
|
@ -44,27 +51,13 @@ func (t *tab) Append(name string, control Control) {
|
||||||
cname)
|
cname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tab) widget() *C.GtkWidget {
|
func (t *tab) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
return t._widget
|
// first, chain up to change the GtkFrame and its child container
|
||||||
}
|
t.chainresize(x, y, width, height, d)
|
||||||
|
|
||||||
func (t *tab) setParent(p *controlParent) {
|
// now that the containers have the correct size, we can resize the children
|
||||||
basesetParent(t, p)
|
for i, _ := range t.tabs {
|
||||||
}
|
a := t.tabs[i].allocation(false/*TODO*/)
|
||||||
|
t.children[i].resize(int(a.x), int(a.y), int(a.width), int(a.height), d)
|
||||||
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(t, d)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,14 @@ import "C"
|
||||||
/*
|
/*
|
||||||
On Windows, container controls are just regular controls that notify their parent when the user wants to do things; changing the contents of a switching container (such as a tab control) must be done manually.
|
On Windows, container controls are just regular controls that notify their parent when the user wants to do things; changing the contents of a switching container (such as a tab control) must be done manually.
|
||||||
|
|
||||||
We'll create a dummy window using the pre-existing Window window class for each tab page. This makes showing and hiding tabs a matter of showing and hiding one control.
|
We'll create a dummy window using the container window class for each tab page. This makes showing and hiding tabs a matter of showing and hiding one control.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type tab struct {
|
type tab struct {
|
||||||
_hwnd C.HWND
|
*controlSingleHWND
|
||||||
tabs []*container
|
tabs []*container
|
||||||
|
children []Control
|
||||||
|
chainresize func(x int, y int, width int, height int, d *sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTab() Tab {
|
func newTab() Tab {
|
||||||
|
@ -25,22 +27,29 @@ func newTab() Tab {
|
||||||
C.TCS_TOOLTIPS|C.WS_TABSTOP,
|
C.TCS_TOOLTIPS|C.WS_TABSTOP,
|
||||||
0) // don't set WS_EX_CONTROLPARENT here; see uitask_windows.c
|
0) // don't set WS_EX_CONTROLPARENT here; see uitask_windows.c
|
||||||
t := &tab{
|
t := &tab{
|
||||||
_hwnd: hwnd,
|
controlSingleHWND: newControlSingleHWND(hwnd),
|
||||||
}
|
}
|
||||||
C.controlSetControlFont(t._hwnd)
|
t.fpreferredSize = t.xpreferredSize
|
||||||
C.setTabSubclass(t._hwnd, unsafe.Pointer(t))
|
t.chainresize = t.fresize
|
||||||
|
t.fresize = t.xresize
|
||||||
|
// count tabs as 1 tab stop; the actual number of tab stops varies
|
||||||
|
C.controlSetControlFont(t.hwnd)
|
||||||
|
C.setTabSubclass(t.hwnd, unsafe.Pointer(t))
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO margined
|
||||||
func (t *tab) Append(name string, control Control) {
|
func (t *tab) Append(name string, control Control) {
|
||||||
c := newContainer(control)
|
c := newContainer()
|
||||||
c.setParent(t._hwnd)
|
control.setParent(&controlParent{c.hwnd})
|
||||||
|
c.setParent(&controlParent{t.hwnd})
|
||||||
t.tabs = append(t.tabs, c)
|
t.tabs = append(t.tabs, c)
|
||||||
|
t.children = append(t.children, control)
|
||||||
// initially hide tab 1..n controls; if we don't, they'll appear over other tabs, resulting in weird behavior
|
// initially hide tab 1..n controls; if we don't, they'll appear over other tabs, resulting in weird behavior
|
||||||
if len(t.tabs) != 1 {
|
if len(t.tabs) != 1 {
|
||||||
t.tabs[len(t.tabs)-1].hide()
|
t.tabs[len(t.tabs)-1].hide()
|
||||||
}
|
}
|
||||||
C.tabAppend(t._hwnd, toUTF16(name))
|
C.tabAppend(t.hwnd, toUTF16(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export tabChanging
|
//export tabChanging
|
||||||
|
@ -61,27 +70,15 @@ func tabTabHasChildren(data unsafe.Pointer, which C.LRESULT) C.BOOL {
|
||||||
if len(t.tabs) == 0 { // currently no tabs
|
if len(t.tabs) == 0 { // currently no tabs
|
||||||
return C.FALSE
|
return C.FALSE
|
||||||
}
|
}
|
||||||
if t.tabs[int(which)].nchildren > 0 {
|
if t.children[int(which)].nTabStops() > 0 {
|
||||||
return C.TRUE
|
return C.TRUE
|
||||||
}
|
}
|
||||||
return C.FALSE
|
return C.FALSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tab) hwnd() C.HWND {
|
func (t *tab) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return t._hwnd
|
for _, c := range t.children {
|
||||||
}
|
w, h := c.preferredSize(d)
|
||||||
|
|
||||||
func (t *tab) setParent(p *controlParent) {
|
|
||||||
basesetParent(t, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
for _, s := range t.tabs {
|
|
||||||
w, h := s.child.preferredSize(d)
|
|
||||||
if width < w {
|
if width < w {
|
||||||
width = w
|
width = w
|
||||||
}
|
}
|
||||||
|
@ -89,30 +86,30 @@ func (t *tab) preferredSize(d *sizing) (width, height int) {
|
||||||
height = h
|
height = h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return width, height + int(C.tabGetTabHeight(t._hwnd))
|
return width, height + int(C.tabGetTabHeight(t.hwnd))
|
||||||
}
|
}
|
||||||
|
|
||||||
// a tab control contains other controls; size appropriately
|
// a tab control contains other controls; size appropriately
|
||||||
func (t *tab) commitResize(c *allocation, d *sizing) {
|
func (t *tab) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
|
// first, chain up to the container base to keep the Z-order correct
|
||||||
|
t.chainresize(x, y, width, height, d)
|
||||||
|
|
||||||
|
// now resize the children
|
||||||
var r C.RECT
|
var r C.RECT
|
||||||
|
|
||||||
// figure out what the rect for each child is...
|
// figure out what the rect for each child is...
|
||||||
// the tab contents are children of the tab itself, so ignore c.x and c.y, which are relative to the window!
|
// the tab contents are children of the tab itself, so ignore x and y, which are relative to the window!
|
||||||
r.left = C.LONG(0)
|
r.left = C.LONG(0)
|
||||||
r.top = C.LONG(0)
|
r.top = C.LONG(0)
|
||||||
r.right = C.LONG(c.width)
|
r.right = C.LONG(width)
|
||||||
r.bottom = C.LONG(c.height)
|
r.bottom = C.LONG(height)
|
||||||
C.tabGetContentRect(t._hwnd, &r)
|
C.tabGetContentRect(t.hwnd, &r)
|
||||||
// and resize tabs
|
// and resize tabs
|
||||||
// don't resize just the current tab; resize all tabs!
|
// don't resize just the current tab; resize all tabs!
|
||||||
for _, c := range t.tabs {
|
for i, _ := range t.tabs {
|
||||||
// because each widget is actually a child of the Window, the origin is the one we calculated above
|
// because each widget is actually a child of the Window, the origin is the one we calculated above
|
||||||
c.move(&r)
|
t.tabs[i].resize(int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top), d)
|
||||||
|
// TODO get the actual client rect
|
||||||
|
t.children[i].resize(int(0), int(0), int(r.right - r.left), int(r.bottom - r.top), d)
|
||||||
}
|
}
|
||||||
// and now resize the tab control itself
|
|
||||||
basecommitResize(t, c, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tab) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(t, d)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,7 @@ import "C"
|
||||||
type table struct {
|
type table struct {
|
||||||
*tablebase
|
*tablebase
|
||||||
|
|
||||||
_id C.id
|
*scroller
|
||||||
scroller *scroller
|
|
||||||
|
|
||||||
images []C.id
|
images []C.id
|
||||||
selected *event
|
selected *event
|
||||||
|
@ -24,13 +23,13 @@ type table struct {
|
||||||
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||||
id := C.newTable()
|
id := C.newTable()
|
||||||
t := &table{
|
t := &table{
|
||||||
_id: id,
|
|
||||||
scroller: newScroller(id, true), // border on Table
|
scroller: newScroller(id, true), // border on Table
|
||||||
tablebase: b,
|
tablebase: b,
|
||||||
selected: newEvent(),
|
selected: newEvent(),
|
||||||
}
|
}
|
||||||
|
t.fpreferredSize = t.xpreferredSize
|
||||||
// also sets the delegate
|
// also sets the delegate
|
||||||
C.tableMakeDataSource(t._id, unsafe.Pointer(t))
|
C.tableMakeDataSource(t.id, unsafe.Pointer(t))
|
||||||
for i := 0; i < ty.NumField(); i++ {
|
for i := 0; i < ty.NumField(); i++ {
|
||||||
cname := C.CString(ty.Field(i).Name)
|
cname := C.CString(ty.Field(i).Name)
|
||||||
coltype := C.colTypeText
|
coltype := C.colTypeText
|
||||||
|
@ -42,7 +41,7 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||||
coltype = C.colTypeCheckbox
|
coltype = C.colTypeCheckbox
|
||||||
editable = true
|
editable = true
|
||||||
}
|
}
|
||||||
C.tableAppendColumn(t._id, C.intptr_t(i), cname, C.int(coltype), toBOOL(editable))
|
C.tableAppendColumn(t.id, C.intptr_t(i), cname, C.int(coltype), toBOOL(editable))
|
||||||
C.free(unsafe.Pointer(cname)) // free now (not deferred) to conserve memory
|
C.free(unsafe.Pointer(cname)) // free now (not deferred) to conserve memory
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
|
@ -56,7 +55,7 @@ func (t *table) Unlock() {
|
||||||
Do(func() {
|
Do(func() {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
C.tableUpdate(t._id)
|
C.tableUpdate(t.id)
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -68,13 +67,13 @@ func (t *table) LoadImageList(i ImageList) {
|
||||||
func (t *table) Selected() int {
|
func (t *table) Selected() int {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
return int(C.tableSelected(t._id))
|
return int(C.tableSelected(t.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) Select(index int) {
|
func (t *table) Select(index int) {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
C.tableSelect(t._id, C.intptr_t(index))
|
C.tableSelect(t.id, C.intptr_t(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) OnSelected(f func()) {
|
func (t *table) OnSelected(f func()) {
|
||||||
|
@ -132,27 +131,7 @@ func tableSelectionChanged(data unsafe.Pointer) {
|
||||||
t.selected.fire()
|
t.selected.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) id() C.id {
|
func (t *table) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return t._id
|
s := C.tablePreferredSize(t.id)
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) setParent(p *controlParent) {
|
|
||||||
t.scroller.setParent(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
s := C.tablePreferredSize(t._id)
|
|
||||||
return int(s.width), int(s.height)
|
return int(s.width), int(s.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) commitResize(c *allocation, d *sizing) {
|
|
||||||
t.scroller.commitResize(c, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(t, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,9 +18,8 @@ import "C"
|
||||||
type table struct {
|
type table struct {
|
||||||
*tablebase
|
*tablebase
|
||||||
|
|
||||||
_widget *C.GtkWidget
|
*scroller
|
||||||
treeview *C.GtkTreeView
|
treeview *C.GtkTreeView
|
||||||
scroller *scroller
|
|
||||||
|
|
||||||
model *C.goTableModel
|
model *C.goTableModel
|
||||||
modelgtk *C.GtkTreeModel
|
modelgtk *C.GtkTreeModel
|
||||||
|
@ -48,7 +47,6 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||||
t := &table{
|
t := &table{
|
||||||
scroller: newScroller(widget, true, true, false), // natively scrollable; has a border; no overlay
|
scroller: newScroller(widget, true, true, false), // natively scrollable; has a border; no overlay
|
||||||
tablebase: b,
|
tablebase: b,
|
||||||
_widget: widget,
|
|
||||||
treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)),
|
treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)),
|
||||||
crtocol: make(map[*C.GtkCellRendererToggle]int),
|
crtocol: make(map[*C.GtkCellRendererToggle]int),
|
||||||
selected: newEvent(),
|
selected: newEvent(),
|
||||||
|
@ -222,28 +220,3 @@ func tableSelectionChanged(sel *C.GtkTreeSelection, data C.gpointer) {
|
||||||
t := (*table)(unsafe.Pointer(data))
|
t := (*table)(unsafe.Pointer(data))
|
||||||
t.selected.fire()
|
t.selected.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) widget() *C.GtkWidget {
|
|
||||||
return t._widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) setParent(p *controlParent) {
|
|
||||||
t.scroller.setParent(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
d.shouldVAlignTop = true
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import "C"
|
||||||
|
|
||||||
type table struct {
|
type table struct {
|
||||||
*tablebase
|
*tablebase
|
||||||
_hwnd C.HWND
|
*controlSingleHWND
|
||||||
noautosize bool
|
noautosize bool
|
||||||
colcount C.int
|
colcount C.int
|
||||||
hotrow C.int
|
hotrow C.int
|
||||||
|
@ -21,13 +21,15 @@ type table struct {
|
||||||
pushedrow C.int
|
pushedrow C.int
|
||||||
pushedcol C.int
|
pushedcol C.int
|
||||||
selected *event
|
selected *event
|
||||||
|
chainresize func(x int, y int, width int, height int, d *sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||||
|
hwnd := C.newControl(C.xWC_LISTVIEW,
|
||||||
|
C.LVS_REPORT|C.LVS_OWNERDATA|C.LVS_NOSORTHEADER|C.LVS_SHOWSELALWAYS|C.LVS_SINGLESEL|C.WS_HSCROLL|C.WS_VSCROLL|C.WS_TABSTOP,
|
||||||
|
C.WS_EX_CLIENTEDGE) // WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
|
||||||
t := &table{
|
t := &table{
|
||||||
_hwnd: C.newControl(C.xWC_LISTVIEW,
|
controlSingleHWND: newControlSingleHWND(hwnd),
|
||||||
C.LVS_REPORT|C.LVS_OWNERDATA|C.LVS_NOSORTHEADER|C.LVS_SHOWSELALWAYS|C.LVS_SINGLESEL|C.WS_HSCROLL|C.WS_VSCROLL|C.WS_TABSTOP,
|
|
||||||
C.WS_EX_CLIENTEDGE), // WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
|
|
||||||
tablebase: b,
|
tablebase: b,
|
||||||
hotrow: -1,
|
hotrow: -1,
|
||||||
hotcol: -1,
|
hotcol: -1,
|
||||||
|
@ -35,14 +37,17 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||||
pushedcol: -1,
|
pushedcol: -1,
|
||||||
selected: newEvent(),
|
selected: newEvent(),
|
||||||
}
|
}
|
||||||
C.setTableSubclass(t._hwnd, unsafe.Pointer(t))
|
t.fpreferredSize = t.xpreferredSize
|
||||||
|
t.chainresize = t.fresize
|
||||||
|
t.fresize = t.xresize
|
||||||
|
C.setTableSubclass(t.hwnd, unsafe.Pointer(t))
|
||||||
// LVS_EX_FULLROWSELECT gives us selection across the whole row, not just the leftmost column; this makes the list view work like on other platforms
|
// LVS_EX_FULLROWSELECT gives us selection across the whole row, not just the leftmost column; this makes the list view work like on other platforms
|
||||||
// LVS_EX_SUBITEMIMAGES gives us images in subitems, which will be important when both images and checkboxes are added
|
// LVS_EX_SUBITEMIMAGES gives us images in subitems, which will be important when both images and checkboxes are added
|
||||||
C.tableAddExtendedStyles(t._hwnd, C.LVS_EX_FULLROWSELECT|C.LVS_EX_SUBITEMIMAGES)
|
C.tableAddExtendedStyles(t.hwnd, C.LVS_EX_FULLROWSELECT|C.LVS_EX_SUBITEMIMAGES)
|
||||||
// this must come after the subclass because it uses one of our private messages
|
// this must come after the subclass because it uses one of our private messages
|
||||||
C.SendMessageW(t._hwnd, C.msgTableMakeInitialCheckboxImageList, 0, 0)
|
C.SendMessageW(t.hwnd, C.msgTableMakeInitialCheckboxImageList, 0, 0)
|
||||||
for i := 0; i < ty.NumField(); i++ {
|
for i := 0; i < ty.NumField(); i++ {
|
||||||
C.tableAppendColumn(t._hwnd, C.int(i), toUTF16(ty.Field(i).Name))
|
C.tableAppendColumn(t.hwnd, C.int(i), toUTF16(ty.Field(i).Name))
|
||||||
}
|
}
|
||||||
t.colcount = C.int(ty.NumField())
|
t.colcount = C.int(ty.NumField())
|
||||||
return t
|
return t
|
||||||
|
@ -56,25 +61,25 @@ func (t *table) Unlock() {
|
||||||
Do(func() {
|
Do(func() {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
|
C.tableUpdate(t.hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) LoadImageList(il ImageList) {
|
func (t *table) LoadImageList(il ImageList) {
|
||||||
il.apply(t._hwnd, C.msgLoadImageList)
|
il.apply(t.hwnd, C.msgLoadImageList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) Selected() int {
|
func (t *table) Selected() int {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
return int(C.tableSelectedItem(t._hwnd))
|
return int(C.tableSelectedItem(t.hwnd))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) Select(index int) {
|
func (t *table) Select(index int) {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
C.tableSelectItem(t._hwnd, C.intptr_t(index))
|
C.tableSelectItem(t.hwnd, C.intptr_t(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) OnSelected(f func()) {
|
func (t *table) OnSelected(f func()) {
|
||||||
|
@ -144,7 +149,7 @@ func (t *table) autoresize() {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
if !t.noautosize {
|
if !t.noautosize {
|
||||||
C.tableAutosizeColumns(t._hwnd, t.colcount)
|
C.tableAutosizeColumns(t.hwnd, t.colcount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +172,7 @@ func tableSetHot(data unsafe.Pointer, row C.int, col C.int) {
|
||||||
t.hotrow = row
|
t.hotrow = row
|
||||||
t.hotcol = col
|
t.hotcol = col
|
||||||
if redraw {
|
if redraw {
|
||||||
C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
|
C.tableUpdate(t.hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +181,7 @@ func tablePushed(data unsafe.Pointer, row C.int, col C.int) {
|
||||||
t := (*table)(data)
|
t := (*table)(data)
|
||||||
t.pushedrow = row
|
t.pushedrow = row
|
||||||
t.pushedcol = col
|
t.pushedcol = col
|
||||||
C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
|
C.tableUpdate(t.hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export tableToggled
|
//export tableToggled
|
||||||
|
@ -211,18 +216,6 @@ func tableSelectionChanged(data unsafe.Pointer) {
|
||||||
t.selected.fire()
|
t.selected.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) hwnd() C.HWND {
|
|
||||||
return t._hwnd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) setParent(p *controlParent) {
|
|
||||||
basesetParent(t, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(t, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// from C++ Template 05 in http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx as this is the best I can do for now
|
// from C++ Template 05 in http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx as this is the best I can do for now
|
||||||
// there IS a message LVM_APPROXIMATEVIEWRECT that can do calculations, but it doesn't seem to work right when asked to base its calculations on the current width/height on Windows and wine...
|
// there IS a message LVM_APPROXIMATEVIEWRECT that can do calculations, but it doesn't seem to work right when asked to base its calculations on the current width/height on Windows and wine...
|
||||||
|
@ -230,17 +223,13 @@ const (
|
||||||
tableHeight = 50
|
tableHeight = 50
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *table) preferredSize(d *sizing) (width, height int) {
|
func (t *table) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return fromdlgunitsX(tableWidth, d), fromdlgunitsY(tableHeight, d)
|
return fromdlgunitsX(tableWidth, d), fromdlgunitsY(tableHeight, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) commitResize(a *allocation, d *sizing) {
|
func (t *table) xresize(x int, y int, width int, height int, d *sizing) {
|
||||||
basecommitResize(t, a, d)
|
t.chainresize(x, y, width, height, d)
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
t.autoresize()
|
t.autoresize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(t, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,17 +10,20 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type textfield struct {
|
type textfield struct {
|
||||||
_id C.id
|
*controlSingleObject
|
||||||
changed *event
|
changed *event
|
||||||
invalid C.id
|
invalid C.id
|
||||||
|
chainpreferredSize func(d *sizing) (int, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishNewTextField(id C.id) *textfield {
|
func finishNewTextField(id C.id) *textfield {
|
||||||
t := &textfield{
|
t := &textfield{
|
||||||
_id: id,
|
controlSingleObject: newControlSingleObject(id),
|
||||||
changed: newEvent(),
|
changed: newEvent(),
|
||||||
}
|
}
|
||||||
C.textfieldSetDelegate(t._id, unsafe.Pointer(t))
|
C.textfieldSetDelegate(t.id, unsafe.Pointer(t))
|
||||||
|
t.chainpreferredSize = t.fpreferredSize
|
||||||
|
t.fpreferredSize = t.xpreferredSize
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,13 +36,13 @@ func newPasswordField() *textfield {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) Text() string {
|
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) {
|
func (t *textfield) SetText(text string) {
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
C.textfieldSetText(t._id, ctext)
|
C.textfieldSetText(t.id, ctext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) OnChanged(f func()) {
|
func (t *textfield) OnChanged(f func()) {
|
||||||
|
@ -56,7 +59,7 @@ func (t *textfield) Invalid(reason string) {
|
||||||
}
|
}
|
||||||
creason := C.CString(reason)
|
creason := C.CString(reason)
|
||||||
defer C.free(unsafe.Pointer(creason))
|
defer C.free(unsafe.Pointer(creason))
|
||||||
t.invalid = C.textfieldOpenInvalidPopover(t._id, creason)
|
t.invalid = C.textfieldOpenInvalidPopover(t.id, creason)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export textfieldChanged
|
//export textfieldChanged
|
||||||
|
@ -65,28 +68,8 @@ func textfieldChanged(data unsafe.Pointer) {
|
||||||
t.changed.fire()
|
t.changed.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) id() C.id {
|
func (t *textfield) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return t._id
|
_, height = t.chainpreferredSize(d)
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) setParent(p *controlParent) {
|
|
||||||
basesetParent(t, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
_, height = basepreferredSize(t, d)
|
|
||||||
// the returned width is based on the contents; use this instead
|
// the returned width is based on the contents; use this instead
|
||||||
return C.textfieldWidth, height
|
return C.textfieldWidth, height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) commitResize(a *allocation, d *sizing) {
|
|
||||||
basecommitResize(t, a, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(t, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type textfield struct {
|
type textfield struct {
|
||||||
_widget *C.GtkWidget
|
*controlSingleWidget
|
||||||
entry *C.GtkEntry
|
entry *C.GtkEntry
|
||||||
changed *event
|
changed *event
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,12 @@ type textfield struct {
|
||||||
func startNewTextField() *textfield {
|
func startNewTextField() *textfield {
|
||||||
widget := C.gtk_entry_new()
|
widget := C.gtk_entry_new()
|
||||||
t := &textfield{
|
t := &textfield{
|
||||||
_widget: widget,
|
controlSingleWidget: newControlSingleWidget(widget),
|
||||||
entry: (*C.GtkEntry)(unsafe.Pointer(widget)),
|
entry: (*C.GtkEntry)(unsafe.Pointer(widget)),
|
||||||
changed: newEvent(),
|
changed: newEvent(),
|
||||||
}
|
}
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
C.gpointer(unsafe.Pointer(t._widget)),
|
C.gpointer(unsafe.Pointer(t.widget)),
|
||||||
"changed",
|
"changed",
|
||||||
C.GCallback(C.textfieldChanged),
|
C.GCallback(C.textfieldChanged),
|
||||||
C.gpointer(unsafe.Pointer(t)))
|
C.gpointer(unsafe.Pointer(t)))
|
||||||
|
@ -71,7 +71,7 @@ func (t *textfield) Invalid(reason string) {
|
||||||
creason := togstr(reason)
|
creason := togstr(reason)
|
||||||
defer freegstr(creason)
|
defer freegstr(creason)
|
||||||
C.gtk_entry_set_icon_tooltip_text(t.entry, C.GTK_ENTRY_ICON_SECONDARY, creason)
|
C.gtk_entry_set_icon_tooltip_text(t.entry, C.GTK_ENTRY_ICON_SECONDARY, creason)
|
||||||
C.gtk_widget_error_bell(t._widget)
|
C.gtk_widget_error_bell(t.widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export textfieldChanged
|
//export textfieldChanged
|
||||||
|
@ -79,27 +79,3 @@ func textfieldChanged(editable *C.GtkEditable, data C.gpointer) {
|
||||||
t := (*textfield)(unsafe.Pointer(data))
|
t := (*textfield)(unsafe.Pointer(data))
|
||||||
t.changed.fire()
|
t.changed.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) widget() *C.GtkWidget {
|
|
||||||
return t._widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) setParent(p *controlParent) {
|
|
||||||
basesetParent(t, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type textfield struct {
|
type textfield struct {
|
||||||
_hwnd C.HWND
|
*controlSingleHWNDWithText
|
||||||
_textlen C.LONG
|
|
||||||
changed *event
|
changed *event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,11 +21,12 @@ func startNewTextField(style C.DWORD) *textfield {
|
||||||
style|C.textfieldStyle,
|
style|C.textfieldStyle,
|
||||||
C.textfieldExtStyle) // WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
|
C.textfieldExtStyle) // WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
|
||||||
t := &textfield{
|
t := &textfield{
|
||||||
_hwnd: hwnd,
|
controlSingleHWNDWithText: newControlSingleHWNDWithText(hwnd),
|
||||||
changed: newEvent(),
|
changed: newEvent(),
|
||||||
}
|
}
|
||||||
C.controlSetControlFont(t._hwnd)
|
t.fpreferredSize = t.xpreferredSize
|
||||||
C.setTextFieldSubclass(t._hwnd, unsafe.Pointer(t))
|
C.controlSetControlFont(t.hwnd)
|
||||||
|
C.setTextFieldSubclass(t.hwnd, unsafe.Pointer(t))
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +39,11 @@ func newPasswordField() *textfield {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) Text() string {
|
func (t *textfield) Text() string {
|
||||||
return baseText(t)
|
return t.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) SetText(text string) {
|
func (t *textfield) SetText(text string) {
|
||||||
baseSetText(t, text)
|
t.setText(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) OnChanged(f func()) {
|
func (t *textfield) OnChanged(f func()) {
|
||||||
|
@ -52,10 +52,10 @@ func (t *textfield) OnChanged(f func()) {
|
||||||
|
|
||||||
func (t *textfield) Invalid(reason string) {
|
func (t *textfield) Invalid(reason string) {
|
||||||
if reason == "" {
|
if reason == "" {
|
||||||
C.textfieldHideInvalidBalloonTip(t._hwnd)
|
C.textfieldHideInvalidBalloonTip(t.hwnd)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
C.textfieldSetAndShowInvalidBalloonTip(t._hwnd, toUTF16(reason))
|
C.textfieldSetAndShowInvalidBalloonTip(t.hwnd, toUTF16(reason))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export textfieldChanged
|
//export textfieldChanged
|
||||||
|
@ -64,40 +64,12 @@ func textfieldChanged(data unsafe.Pointer) {
|
||||||
t.changed.fire()
|
t.changed.fire()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) hwnd() C.HWND {
|
|
||||||
return t._hwnd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) textlen() C.LONG {
|
|
||||||
return t._textlen
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) settextlen(len C.LONG) {
|
|
||||||
t._textlen = len
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) setParent(p *controlParent) {
|
|
||||||
basesetParent(t, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
|
|
||||||
return baseallocate(t, x, y, width, height, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
||||||
textfieldWidth = 107 // this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary
|
textfieldWidth = 107 // this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary
|
||||||
textfieldHeight = 14
|
textfieldHeight = 14
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *textfield) preferredSize(d *sizing) (width, height int) {
|
func (t *textfield) xpreferredSize(d *sizing) (width, height int) {
|
||||||
return fromdlgunitsX(textfieldWidth, d), fromdlgunitsY(textfieldHeight, d)
|
return fromdlgunitsX(textfieldWidth, d), fromdlgunitsY(textfieldHeight, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) commitResize(a *allocation, d *sizing) {
|
|
||||||
basecommitResize(t, a, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *textfield) getAuxResizeInfo(d *sizing) {
|
|
||||||
basegetAuxResizeInfo(t, d)
|
|
||||||
}
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ extern LRESULT getWindowTextLen(HWND);
|
||||||
extern void getWindowText(HWND, WPARAM, LPWSTR);
|
extern void getWindowText(HWND, WPARAM, LPWSTR);
|
||||||
extern void setWindowText(HWND, LPWSTR);
|
extern void setWindowText(HWND, LPWSTR);
|
||||||
extern void updateWindow(HWND);
|
extern void updateWindow(HWND);
|
||||||
extern void *getWindowData(HWND, UINT, WPARAM, LPARAM, LRESULT *, void (*)(void *, HWND));
|
extern void *getWindowData(HWND, UINT, WPARAM, LPARAM, LRESULT *);
|
||||||
extern BOOL sharedWndProc(HWND, UINT, WPARAM, LPARAM, LRESULT *);
|
extern BOOL sharedWndProc(HWND, UINT, WPARAM, LPARAM, LRESULT *);
|
||||||
extern void paintControlBackground(HWND, HDC);
|
extern void paintControlBackground(HWND, HDC);
|
||||||
|
|
||||||
|
@ -122,8 +122,10 @@ extern intptr_t tableSelectedItem(HWND);
|
||||||
extern void tableSelectItem(HWND, intptr_t);
|
extern void tableSelectItem(HWND, intptr_t);
|
||||||
|
|
||||||
// container_windows.c
|
// container_windows.c
|
||||||
|
#define containerclass L"gouicontainer"
|
||||||
extern DWORD makeContainerWindowClass(char **);
|
extern DWORD makeContainerWindowClass(char **);
|
||||||
extern HWND newContainer(void *);
|
extern HWND newContainer();
|
||||||
|
extern RECT containerBounds(HWND);
|
||||||
extern void calculateBaseUnits(HWND, int *, int *, LONG *);
|
extern void calculateBaseUnits(HWND, int *, int *, LONG *);
|
||||||
|
|
||||||
// area_windows.c
|
// area_windows.c
|
||||||
|
|
|
@ -26,6 +26,11 @@ type Window interface {
|
||||||
// If this handler returns false, the Window is not closed.
|
// If this handler returns false, the Window is not closed.
|
||||||
OnClosing(func() bool)
|
OnClosing(func() bool)
|
||||||
|
|
||||||
|
// Margined and SetMargined get and set whether the contents of the Window have a margin around them.
|
||||||
|
// The size of the margin is platform-dependent.
|
||||||
|
Margined() bool
|
||||||
|
SetMargined(margined bool)
|
||||||
|
|
||||||
windowDialog
|
windowDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ type window struct {
|
||||||
|
|
||||||
closing *event
|
closing *event
|
||||||
|
|
||||||
*container
|
child Control
|
||||||
|
container *container
|
||||||
|
|
||||||
|
margined bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWindow(title string, width int, height int, control Control) *window {
|
func newWindow(title string, width int, height int, control Control) *window {
|
||||||
|
@ -25,10 +28,13 @@ func newWindow(title string, width int, height int, control Control) *window {
|
||||||
w := &window{
|
w := &window{
|
||||||
id: id,
|
id: id,
|
||||||
closing: newEvent(),
|
closing: newEvent(),
|
||||||
container: newContainer(control),
|
child: control,
|
||||||
|
container: newContainer(),
|
||||||
}
|
}
|
||||||
C.windowSetDelegate(w.id, unsafe.Pointer(w))
|
C.windowSetDelegate(w.id, unsafe.Pointer(w))
|
||||||
C.windowSetContentView(w.id, w.container.id)
|
C.windowSetContentView(w.id, w.container.id)
|
||||||
|
w.child.setParent(w.container.parent())
|
||||||
|
// trigger an initial resize
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +50,9 @@ func (w *window) SetTitle(title string) {
|
||||||
|
|
||||||
func (w *window) Show() {
|
func (w *window) Show() {
|
||||||
C.windowShow(w.id)
|
C.windowShow(w.id)
|
||||||
|
// trigger an initial resize
|
||||||
|
// TODO fine-tune this
|
||||||
|
windowResized(unsafe.Pointer(w))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) Hide() {
|
func (w *window) Hide() {
|
||||||
|
@ -58,6 +67,14 @@ func (w *window) OnClosing(e func() bool) {
|
||||||
w.closing.setbool(e)
|
w.closing.setbool(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *window) Margined() bool {
|
||||||
|
return w.margined
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *window) SetMargined(margined bool) {
|
||||||
|
w.margined = margined
|
||||||
|
}
|
||||||
|
|
||||||
//export windowClosing
|
//export windowClosing
|
||||||
func windowClosing(xw unsafe.Pointer) C.BOOL {
|
func windowClosing(xw unsafe.Pointer) C.BOOL {
|
||||||
w := (*window)(unsafe.Pointer(xw))
|
w := (*window)(unsafe.Pointer(xw))
|
||||||
|
@ -67,3 +84,11 @@ func windowClosing(xw unsafe.Pointer) C.BOOL {
|
||||||
}
|
}
|
||||||
return C.NO
|
return C.NO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export windowResized
|
||||||
|
func windowResized(data unsafe.Pointer) {
|
||||||
|
w := (*window)(data)
|
||||||
|
a := w.container.allocation(w.margined)
|
||||||
|
d := w.beginResize()
|
||||||
|
w.child.resize(int(a.x), int(a.y), int(a.width), int(a.height), d)
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
return windowClosing(self->gowin);
|
return windowClosing(self->gowin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResize:(NSNotification *)note
|
||||||
|
{
|
||||||
|
windowResized(self->gowin);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
id newWindow(intptr_t width, intptr_t height)
|
id newWindow(intptr_t width, intptr_t height)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
// #include "gtk_unix.h"
|
// #include "gtk_unix.h"
|
||||||
// extern gboolean windowClosing(GtkWidget *, GdkEvent *, gpointer);
|
// extern gboolean windowClosing(GtkWidget *, GdkEvent *, gpointer);
|
||||||
|
// extern void windowResized(GtkWidget *, GdkRectangle *, gpointer);
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type window struct {
|
type window struct {
|
||||||
|
@ -22,7 +23,10 @@ type window struct {
|
||||||
|
|
||||||
closing *event
|
closing *event
|
||||||
|
|
||||||
*container
|
child Control
|
||||||
|
container *container
|
||||||
|
|
||||||
|
margined bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWindow(title string, width int, height int, control Control) *window {
|
func newWindow(title string, width int, height int, control Control) *window {
|
||||||
|
@ -35,6 +39,7 @@ func newWindow(title string, width int, height int, control Control) *window {
|
||||||
bin: (*C.GtkBin)(unsafe.Pointer(widget)),
|
bin: (*C.GtkBin)(unsafe.Pointer(widget)),
|
||||||
window: (*C.GtkWindow)(unsafe.Pointer(widget)),
|
window: (*C.GtkWindow)(unsafe.Pointer(widget)),
|
||||||
closing: newEvent(),
|
closing: newEvent(),
|
||||||
|
child: control,
|
||||||
}
|
}
|
||||||
C.gtk_window_set_title(w.window, ctitle)
|
C.gtk_window_set_title(w.window, ctitle)
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
|
@ -43,8 +48,15 @@ func newWindow(title string, width int, height int, control Control) *window {
|
||||||
C.GCallback(C.windowClosing),
|
C.GCallback(C.windowClosing),
|
||||||
C.gpointer(unsafe.Pointer(w)))
|
C.gpointer(unsafe.Pointer(w)))
|
||||||
C.gtk_window_resize(w.window, C.gint(width), C.gint(height))
|
C.gtk_window_resize(w.window, C.gint(width), C.gint(height))
|
||||||
w.container = newContainer(control)
|
w.container = newContainer()
|
||||||
|
w.child.setParent(w.container.parent())
|
||||||
w.container.setParent(&controlParent{w.wc})
|
w.container.setParent(&controlParent{w.wc})
|
||||||
|
// notice that we connect this to the container
|
||||||
|
g_signal_connect_after( // so we get it after the child container has been allocated
|
||||||
|
C.gpointer(unsafe.Pointer(w.container.widget)),
|
||||||
|
"size-allocate",
|
||||||
|
C.GCallback(C.windowResized),
|
||||||
|
C.gpointer(unsafe.Pointer(w)))
|
||||||
// for dialogs; otherwise, they will be modal to all windows, not just this one
|
// for dialogs; otherwise, they will be modal to all windows, not just this one
|
||||||
w.group = C.gtk_window_group_new()
|
w.group = C.gtk_window_group_new()
|
||||||
C.gtk_window_group_add_window(w.group, w.window)
|
C.gtk_window_group_add_window(w.group, w.window)
|
||||||
|
@ -77,6 +89,14 @@ func (w *window) OnClosing(e func() bool) {
|
||||||
w.closing.setbool(e)
|
w.closing.setbool(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *window) Margined() bool {
|
||||||
|
return w.margined
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *window) SetMargined(margined bool) {
|
||||||
|
w.margined = margined
|
||||||
|
}
|
||||||
|
|
||||||
//export windowClosing
|
//export windowClosing
|
||||||
func windowClosing(wid *C.GtkWidget, e *C.GdkEvent, data C.gpointer) C.gboolean {
|
func windowClosing(wid *C.GtkWidget, e *C.GdkEvent, data C.gpointer) C.gboolean {
|
||||||
w := (*window)(unsafe.Pointer(data))
|
w := (*window)(unsafe.Pointer(data))
|
||||||
|
@ -86,3 +106,11 @@ func windowClosing(wid *C.GtkWidget, e *C.GdkEvent, data C.gpointer) C.gboolean
|
||||||
}
|
}
|
||||||
return C.GDK_EVENT_STOP // keeps window alive
|
return C.GDK_EVENT_STOP // keeps window alive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export windowResized
|
||||||
|
func windowResized(wid *C.GtkWidget, r *C.GdkRectangle, data C.gpointer) {
|
||||||
|
w := (*window)(unsafe.Pointer(data))
|
||||||
|
a := w.container.allocation(w.margined)
|
||||||
|
d := w.beginResize()
|
||||||
|
w.child.resize(int(a.x), int(a.y), int(a.width), int(a.height), d)
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ static LRESULT CALLBACK windowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARA
|
||||||
RECT r;
|
RECT r;
|
||||||
LRESULT lResult;
|
LRESULT lResult;
|
||||||
|
|
||||||
data = (void *) getWindowData(hwnd, uMsg, wParam, lParam, &lResult, storeWindowHWND);
|
data = (void *) getWindowData(hwnd, uMsg, wParam, lParam, &lResult);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return lResult;
|
return lResult;
|
||||||
if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult))
|
if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult))
|
||||||
|
|
|
@ -17,7 +17,8 @@ type window struct {
|
||||||
|
|
||||||
closing *event
|
closing *event
|
||||||
|
|
||||||
*container
|
child Control
|
||||||
|
margined bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeWindowWindowClass() error {
|
func makeWindowWindowClass() error {
|
||||||
|
@ -32,19 +33,15 @@ func makeWindowWindowClass() error {
|
||||||
|
|
||||||
func newWindow(title string, width int, height int, control Control) *window {
|
func newWindow(title string, width int, height int, control Control) *window {
|
||||||
w := &window{
|
w := &window{
|
||||||
// hwnd set in WM_CREATE handler
|
|
||||||
closing: newEvent(),
|
closing: newEvent(),
|
||||||
container: newContainer(control),
|
child: control,
|
||||||
}
|
|
||||||
hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w))
|
|
||||||
if hwnd != w.hwnd {
|
|
||||||
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in Window (%p) differ", hwnd, w.hwnd))
|
|
||||||
}
|
}
|
||||||
|
w.hwnd = C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w))
|
||||||
hresult := C.EnableThemeDialogTexture(w.hwnd, C.ETDT_ENABLE|C.ETDT_USETABTEXTURE)
|
hresult := C.EnableThemeDialogTexture(w.hwnd, C.ETDT_ENABLE|C.ETDT_USETABTEXTURE)
|
||||||
if hresult != C.S_OK {
|
if hresult != C.S_OK {
|
||||||
panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
|
panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
|
||||||
}
|
}
|
||||||
w.container.setParent(w.hwnd)
|
w.child.setParent(&controlParent{w.hwnd})
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,17 +75,22 @@ func (w *window) OnClosing(e func() bool) {
|
||||||
w.closing.setbool(e)
|
w.closing.setbool(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export storeWindowHWND
|
func (w *window) Margined() bool {
|
||||||
func storeWindowHWND(data unsafe.Pointer, hwnd C.HWND) {
|
return w.margined
|
||||||
w := (*window)(data)
|
}
|
||||||
w.hwnd = hwnd
|
|
||||||
|
func (w *window) SetMargined(margined bool) {
|
||||||
|
w.margined = margined
|
||||||
}
|
}
|
||||||
|
|
||||||
//export windowResize
|
//export windowResize
|
||||||
func windowResize(data unsafe.Pointer, r *C.RECT) {
|
func windowResize(data unsafe.Pointer, r *C.RECT) {
|
||||||
w := (*window)(data)
|
w := (*window)(data)
|
||||||
// the origin of the window's content area is always (0, 0), but let's use the values from the RECT just to be safe
|
d := w.beginResize()
|
||||||
w.container.move(r)
|
if w.margined {
|
||||||
|
marginRectDLU(r, marginDialogUnits, marginDialogUnits, marginDialogUnits, marginDialogUnits, d)
|
||||||
|
}
|
||||||
|
w.child.resize(int(r.left), int (r.top), int(r.right - r.left), int(r.bottom - r.top), d)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export windowClosing
|
//export windowClosing
|
||||||
|
|
|
@ -52,6 +52,7 @@ func newRepainter(times int) *repainter {
|
||||||
grid.Add(r.repaint, nil, South, true, Fill, true, Fill, 1, 1)
|
grid.Add(r.repaint, nil, South, true, Fill, true, Fill, 1, 1)
|
||||||
grid.Add(r.all, nil, South, true, Center, false, LeftTop, 1, 1)
|
grid.Add(r.all, nil, South, true, Center, false, LeftTop, 1, 1)
|
||||||
r.grid = grid
|
r.grid = grid
|
||||||
|
r.grid.SetPadded(*spaced)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
57
zz_test.go
57
zz_test.go
|
@ -18,6 +18,25 @@ import (
|
||||||
|
|
||||||
var closeOnClick = flag.Bool("close", false, "close on click")
|
var closeOnClick = flag.Bool("close", false, "close on click")
|
||||||
var smallWindow = flag.Bool("small", false, "open a small window (test Mac OS X initial control sizing)")
|
var smallWindow = flag.Bool("small", false, "open a small window (test Mac OS X initial control sizing)")
|
||||||
|
var spaced = flag.Bool("spaced", false, "enable spacing")
|
||||||
|
|
||||||
|
func newHorizontalStack(c ...Control) Stack {
|
||||||
|
s := NewHorizontalStack(c...)
|
||||||
|
s.SetPadded(*spaced)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func newVerticalStack(c ...Control) Stack {
|
||||||
|
s := NewVerticalStack(c...)
|
||||||
|
s.SetPadded(*spaced)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSimpleGrid(n int, c ...Control) SimpleGrid {
|
||||||
|
g := NewSimpleGrid(n, c...)
|
||||||
|
g.SetPadded(*spaced)
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
type dtype struct {
|
type dtype struct {
|
||||||
Name string
|
Name string
|
||||||
|
@ -96,7 +115,7 @@ func (tw *testwin) addfe() {
|
||||||
tw.felabel.SetText(t.String())
|
tw.felabel.SetText(t.String())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
tw.felabel = NewStandaloneLabel("<stopped>")
|
tw.felabel = NewLabel("<stopped>")
|
||||||
tw.festop = NewButton("Stop")
|
tw.festop = NewButton("Stop")
|
||||||
tw.festop.OnClicked(func() {
|
tw.festop.OnClicked(func() {
|
||||||
if tw.fe != nil {
|
if tw.fe != nil {
|
||||||
|
@ -117,8 +136,8 @@ func (tw *testwin) addfe() {
|
||||||
tw.openbtn.OnClicked(func() {
|
tw.openbtn.OnClicked(func() {
|
||||||
OpenFile(tw.w, tw.openFile)
|
OpenFile(tw.w, tw.openFile)
|
||||||
})
|
})
|
||||||
tw.fnlabel = NewStandaloneLabel("<no file selected>")
|
tw.fnlabel = NewLabel("<no file selected>")
|
||||||
tw.festack = NewVerticalStack(tw.festart,
|
tw.festack = newVerticalStack(tw.festart,
|
||||||
tw.felabel,
|
tw.felabel,
|
||||||
tw.festop,
|
tw.festop,
|
||||||
NewCheckbox("This is a checkbox test"),
|
NewCheckbox("This is a checkbox test"),
|
||||||
|
@ -129,7 +148,7 @@ func (tw *testwin) addfe() {
|
||||||
tw.openbtn, tw.fnlabel)
|
tw.openbtn, tw.fnlabel)
|
||||||
tw.festack.SetStretchy(4)
|
tw.festack.SetStretchy(4)
|
||||||
tw.festack.SetStretchy(6)
|
tw.festack.SetStretchy(6)
|
||||||
tw.festack = NewHorizontalStack(tw.festack, Space())
|
tw.festack = newHorizontalStack(tw.festack, Space())
|
||||||
tw.festack.SetStretchy(0)
|
tw.festack.SetStretchy(0)
|
||||||
tw.festack.SetStretchy(1)
|
tw.festack.SetStretchy(1)
|
||||||
tw.t.Append("Foreign Events", tw.festack)
|
tw.t.Append("Foreign Events", tw.festack)
|
||||||
|
@ -138,6 +157,7 @@ func (tw *testwin) addfe() {
|
||||||
func (tw *testwin) make(done chan struct{}) {
|
func (tw *testwin) make(done chan struct{}) {
|
||||||
tw.t = NewTab()
|
tw.t = NewTab()
|
||||||
tw.w = NewWindow("Hello", 320, 240, tw.t)
|
tw.w = NewWindow("Hello", 320, 240, tw.t)
|
||||||
|
tw.w.SetMargined(*spaced)
|
||||||
tw.w.OnClosing(func() bool {
|
tw.w.OnClosing(func() bool {
|
||||||
if *closeOnClick {
|
if *closeOnClick {
|
||||||
panic("window closed normally in close on click mode (should not happen)")
|
panic("window closed normally in close on click mode (should not happen)")
|
||||||
|
@ -171,12 +191,14 @@ func (tw *testwin) make(done chan struct{}) {
|
||||||
tw.group2 = NewGroup("Group", NewButton("Button in Group"))
|
tw.group2 = NewGroup("Group", NewButton("Button in Group"))
|
||||||
tw.t.Append("Empty Group", NewGroup("Group", Space()))
|
tw.t.Append("Empty Group", NewGroup("Group", Space()))
|
||||||
tw.t.Append("Filled Group", tw.group2)
|
tw.t.Append("Filled Group", tw.group2)
|
||||||
tw.group = NewGroup("Group", NewVerticalStack(NewCheckbox("Checkbox in Group")))
|
tw.group2.SetMargined(*spaced)
|
||||||
|
tw.group = NewGroup("Group", newVerticalStack(NewCheckbox("Checkbox in Group")))
|
||||||
|
tw.group.SetMargined(*spaced)
|
||||||
tw.t.Append("Group", tw.group)
|
tw.t.Append("Group", tw.group)
|
||||||
tw.simpleGrid = NewSimpleGrid(3,
|
tw.simpleGrid = newSimpleGrid(3,
|
||||||
NewLabel("0,0"), NewTextField(), NewLabel("0,2"),
|
NewLabel("0,0"), NewTextField(), NewLabel("0,2"),
|
||||||
NewButton("1,0"), NewButton("1,1"), NewButton("1,2"),
|
NewButton("1,0"), NewButton("1,1"), NewButton("1,2"),
|
||||||
NewLabel("2,0"), NewTextField(), NewStandaloneLabel("2,2"))
|
NewLabel("2,0"), NewTextField(), NewLabel("2,2"))
|
||||||
tw.simpleGrid.SetFilling(2, 1)
|
tw.simpleGrid.SetFilling(2, 1)
|
||||||
tw.simpleGrid.SetFilling(1, 2)
|
tw.simpleGrid.SetFilling(1, 2)
|
||||||
tw.simpleGrid.SetStretchy(1, 1)
|
tw.simpleGrid.SetStretchy(1, 1)
|
||||||
|
@ -189,33 +211,33 @@ func (tw *testwin) make(done chan struct{}) {
|
||||||
tw.t.Append("Space", Space())
|
tw.t.Append("Space", Space())
|
||||||
tw.a = NewArea(200, 200, &areaHandler{false})
|
tw.a = NewArea(200, 200, &areaHandler{false})
|
||||||
tw.t.Append("Area", tw.a)
|
tw.t.Append("Area", tw.a)
|
||||||
tw.spw = NewHorizontalStack(
|
tw.spw = newHorizontalStack(
|
||||||
NewButton("hello"),
|
NewButton("hello"),
|
||||||
NewCheckbox("hello"),
|
NewCheckbox("hello"),
|
||||||
NewTextField(),
|
NewTextField(),
|
||||||
NewPasswordField(),
|
NewPasswordField(),
|
||||||
NewTable(reflect.TypeOf(struct{ A, B, C int }{})),
|
NewTable(reflect.TypeOf(struct{ A, B, C int }{})),
|
||||||
NewStandaloneLabel("hello"))
|
NewLabel("hello"))
|
||||||
tw.t.Append("Pref Width", tw.spw)
|
tw.t.Append("Pref Width", tw.spw)
|
||||||
tw.sph = NewVerticalStack(
|
tw.sph = newVerticalStack(
|
||||||
NewButton("hello"),
|
NewButton("hello"),
|
||||||
NewCheckbox("hello"),
|
NewCheckbox("hello"),
|
||||||
NewTextField(),
|
NewTextField(),
|
||||||
NewPasswordField(),
|
NewPasswordField(),
|
||||||
NewTable(reflect.TypeOf(struct{ A, B, C int }{})),
|
NewTable(reflect.TypeOf(struct{ A, B, C int }{})),
|
||||||
NewStandaloneLabel("hello ÉÀÔ"))
|
NewLabel("hello ÉÀÔ"))
|
||||||
tw.t.Append("Pref Height", tw.sph)
|
tw.t.Append("Pref Height", tw.sph)
|
||||||
stack1 := NewHorizontalStack(NewLabel("Test"), NewTextField())
|
stack1 := newHorizontalStack(NewLabel("Test"), NewTextField())
|
||||||
stack1.SetStretchy(1)
|
stack1.SetStretchy(1)
|
||||||
stack2 := NewHorizontalStack(NewLabel("ÉÀÔ"), NewTextField())
|
stack2 := newHorizontalStack(NewLabel("ÉÀÔ"), NewTextField())
|
||||||
stack2.SetStretchy(1)
|
stack2.SetStretchy(1)
|
||||||
stack3 := NewHorizontalStack(NewLabel("Test 2"),
|
stack3 := newHorizontalStack(NewLabel("Test 2"),
|
||||||
NewTable(reflect.TypeOf(struct{ A, B, C int }{})))
|
NewTable(reflect.TypeOf(struct{ A, B, C int }{})))
|
||||||
stack3.SetStretchy(1)
|
stack3.SetStretchy(1)
|
||||||
tw.s = NewVerticalStack(stack1, stack2, stack3)
|
tw.s = newVerticalStack(stack1, stack2, stack3)
|
||||||
tw.s.SetStretchy(2)
|
tw.s.SetStretchy(2)
|
||||||
tw.t.Append("Stack", tw.s)
|
tw.t.Append("Stack", tw.s)
|
||||||
tw.l = NewStandaloneLabel("hello")
|
tw.l = NewLabel("hello")
|
||||||
tw.t.Append("Label", tw.l)
|
tw.t.Append("Label", tw.l)
|
||||||
tw.table = NewTable(reflect.TypeOf(ddata[0]))
|
tw.table = NewTable(reflect.TypeOf(ddata[0]))
|
||||||
tw.table.Lock()
|
tw.table.Lock()
|
||||||
|
@ -248,7 +270,7 @@ func (tw *testwin) make(done chan struct{}) {
|
||||||
tw.w.Show()
|
tw.w.Show()
|
||||||
if *smallWindow {
|
if *smallWindow {
|
||||||
tw.wsmall = NewWindow("Small", 80, 80,
|
tw.wsmall = NewWindow("Small", 80, 80,
|
||||||
NewVerticalStack(
|
newVerticalStack(
|
||||||
NewButton("Small"),
|
NewButton("Small"),
|
||||||
NewButton("Small 2"),
|
NewButton("Small 2"),
|
||||||
NewArea(200, 200, &areaHandler{true})))
|
NewArea(200, 200, &areaHandler{true})))
|
||||||
|
@ -262,7 +284,6 @@ var tw *testwin
|
||||||
|
|
||||||
// because Cocoa hates being run off the main thread, even if it's run exclusively off the main thread
|
// because Cocoa hates being run off the main thread, even if it's run exclusively off the main thread
|
||||||
func init() {
|
func init() {
|
||||||
flag.BoolVar(&spaced, "spaced", false, "enable spacing")
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
go func() {
|
go func() {
|
||||||
tw = new(testwin)
|
tw = new(testwin)
|
||||||
|
|
Loading…
Reference in New Issue