go fmt. Precursor to bug report filing.

This commit is contained in:
Pietro Gagliardi 2014-10-02 10:05:53 -04:00
parent 09db0bffff
commit 982004d050
50 changed files with 1081 additions and 1078 deletions

14
area.go
View File

@ -62,9 +62,9 @@ type Area interface {
} }
type areabase struct { type areabase struct {
width int width int
height int height int
handler AreaHandler handler AreaHandler
} }
// AreaHandler represents the events that an Area should respond to. // AreaHandler represents the events that an Area should respond to.
@ -314,9 +314,9 @@ func NewArea(width int, height int, handler AreaHandler) Area {
panic("handler passed to NewArea() must not be nil") panic("handler passed to NewArea() must not be nil")
} }
return newArea(&areabase{ return newArea(&areabase{
width: width, width: width,
height: height, height: height,
handler: handler, handler: handler,
}) })
} }
@ -342,7 +342,7 @@ func toARGB(i *image.RGBA, memory uintptr, memstride int, toNRGBA bool) {
p := pixelDataPos(i) p := pixelDataPos(i)
q := 0 q := 0
iPix := i.Pix iPix := i.Pix
if toNRGBA { // for Windows image lists if toNRGBA { // for Windows image lists
j := image.NewNRGBA(i.Rect) j := image.NewNRGBA(i.Rect)
draw.Draw(j, j.Rect, i, i.Rect.Min, draw.Src) draw.Draw(j, j.Rect, i, i.Rect.Min, draw.Src)
iPix = j.Pix iPix = j.Pix

View File

@ -15,19 +15,19 @@ import "C"
type area struct { type area struct {
*areabase *areabase
_id C.id _id C.id
scroller *scroller scroller *scroller
textfield C.id textfield C.id
textfielddone *event textfielddone *event
} }
func newArea(ab *areabase) Area { func newArea(ab *areabase) Area {
a := &area{ a := &area{
areabase: ab, areabase: ab,
textfielddone: newEvent(), textfielddone: newEvent(),
} }
a._id = C.newArea(unsafe.Pointer(a)) a._id = C.newArea(unsafe.Pointer(a))
a.scroller = newScroller(a._id, false) // no border on Area a.scroller = newScroller(a._id, false) // no border on Area
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)

View File

@ -34,18 +34,18 @@ import "C"
type area struct { type area struct {
*areabase *areabase
_widget *C.GtkWidget _widget *C.GtkWidget
drawingarea *C.GtkDrawingArea drawingarea *C.GtkDrawingArea
scroller *scroller scroller *scroller
clickCounter *clickCounter clickCounter *clickCounter
textfieldw *C.GtkWidget textfieldw *C.GtkWidget
textfield *C.GtkEntry textfield *C.GtkEntry
textfieldx int textfieldx int
textfieldy int textfieldy int
textfielddone *event textfielddone *event
inmenu bool inmenu bool
} }
func newArea(ab *areabase) Area { func newArea(ab *areabase) Area {
@ -58,14 +58,14 @@ func newArea(ab *areabase) Area {
C.gtk_widget_set_can_focus(widget, C.TRUE) C.gtk_widget_set_can_focus(widget, C.TRUE)
textfieldw := C.gtk_entry_new() textfieldw := C.gtk_entry_new()
a := &area{ a := &area{
areabase: ab, areabase: ab,
_widget: widget, _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),
textfieldw: textfieldw, textfieldw: textfieldw,
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)), textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
textfielddone: newEvent(), textfielddone: newEvent(),
} }
for _, c := range areaCallbacks { for _, c := range areaCallbacks {
g_signal_connect( g_signal_connect(
@ -124,7 +124,7 @@ func (a *area) OpenTextFieldAt(x, y int) {
} }
a.textfieldx = x a.textfieldx = x
a.textfieldy = y a.textfieldy = y
a.inmenu = false // to start a.inmenu = false // to start
// we disabled this for the initial Area show; we don't need to anymore // we disabled this for the initial Area show; we don't need to anymore
C.gtk_widget_set_no_show_all(a.textfieldw, C.FALSE) C.gtk_widget_set_no_show_all(a.textfieldw, C.FALSE)
C.gtk_widget_show_all(a.textfieldw) C.gtk_widget_show_all(a.textfieldw)
@ -175,24 +175,24 @@ func our_area_textfield_focus_out_event_callback(widget *C.GtkWidget, event *C.G
C.gtk_widget_hide(a.textfieldw) C.gtk_widget_hide(a.textfieldw)
a.textfielddone.fire() a.textfielddone.fire()
} }
a.inmenu = false // for next time a.inmenu = false // for next time
return continueEventChain return continueEventChain
} }
var area_textfield_focus_out_event_callback = C.GCallback(C.our_area_textfield_focus_out_event_callback) var area_textfield_focus_out_event_callback = C.GCallback(C.our_area_textfield_focus_out_event_callback)
var areaCallbacks = []struct { var areaCallbacks = []struct {
name string name string
callback C.GCallback callback C.GCallback
}{ }{
{ "draw", area_draw_callback }, {"draw", area_draw_callback},
{ "button-press-event", area_button_press_event_callback }, {"button-press-event", area_button_press_event_callback},
{ "button-release-event", area_button_release_event_callback }, {"button-release-event", area_button_release_event_callback},
{ "motion-notify-event", area_motion_notify_event_callback }, {"motion-notify-event", area_motion_notify_event_callback},
{ "enter-notify-event", area_enterleave_notify_event_callback }, {"enter-notify-event", area_enterleave_notify_event_callback},
{ "leave-notify-event", area_enterleave_notify_event_callback }, {"leave-notify-event", area_enterleave_notify_event_callback},
{ "key-press-event", area_key_press_event_callback }, {"key-press-event", area_key_press_event_callback},
{ "key-release-event", area_key_release_event_callback }, {"key-release-event", area_key_release_event_callback},
} }
//export our_area_draw_callback //export our_area_draw_callback
@ -222,11 +222,11 @@ func our_area_draw_callback(widget *C.GtkWidget, cr *C.cairo_t, data C.gpointer)
// the flush and mark_dirty calls are required; see the cairo docs and https://git.gnome.org/browse/gtk+/tree/gdk/gdkcairo.c#n232 (thanks desrt in irc.gimp.net/#gtk+) // the flush and mark_dirty calls are required; see the cairo docs and https://git.gnome.org/browse/gtk+/tree/gdk/gdkcairo.c#n232 (thanks desrt in irc.gimp.net/#gtk+)
C.cairo_surface_flush(surface) C.cairo_surface_flush(surface)
toARGB(i, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))), toARGB(i, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))),
int(C.cairo_image_surface_get_stride(surface)), false) // not NRGBA int(C.cairo_image_surface_get_stride(surface)), false) // not NRGBA
C.cairo_surface_mark_dirty(surface) C.cairo_surface_mark_dirty(surface)
C.cairo_set_source_surface(cr, C.cairo_set_source_surface(cr,
surface, surface,
x0, y0) // point on cairo_t where we want to draw (thanks Company in irc.gimp.net/#gtk+) x0, y0) // point on cairo_t where we want to draw (thanks Company in irc.gimp.net/#gtk+)
// that just set the brush that cairo uses: we have to actually draw now // that just set the brush that cairo uses: we have to actually draw now
// (via https://developer.gnome.org/gtkmm-tutorial/stable/sec-draw-images.html.en) // (via https://developer.gnome.org/gtkmm-tutorial/stable/sec-draw-images.html.en)
C.cairo_rectangle(cr, x0, y0, x1, y1) // breaking the norm here since we have the coordinates as a C double already C.cairo_rectangle(cr, x0, y0, x1, y1) // breaking the norm here since we have the coordinates as a C double already
@ -252,7 +252,7 @@ func makeModifiers(state C.guint) (m Modifiers) {
if (state & C.GDK_META_MASK) != 0 { if (state & C.GDK_META_MASK) != 0 {
m |= Alt m |= Alt
} }
if (state & C.GDK_MOD1_MASK) != 0 { // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c) if (state & C.GDK_MOD1_MASK) != 0 { // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c)
m |= Alt m |= Alt
} }
if (state & C.GDK_SHIFT_MASK) != 0 { if (state & C.GDK_SHIFT_MASK) != 0 {

View File

@ -15,12 +15,12 @@ import "C"
type area struct { type area struct {
*areabase *areabase
_hwnd C.HWND _hwnd C.HWND
clickCounter *clickCounter clickCounter *clickCounter
textfield C.HWND textfield C.HWND
textfielddone *event textfielddone *event
} }
func makeAreaWindowClass() error { func makeAreaWindowClass() error {
@ -35,9 +35,9 @@ func makeAreaWindowClass() error {
func newArea(ab *areabase) Area { func newArea(ab *areabase) Area {
a := &area{ a := &area{
areabase: ab, areabase: ab,
clickCounter: new(clickCounter), clickCounter: new(clickCounter),
textfielddone: newEvent(), textfielddone: newEvent(),
} }
a._hwnd = C.newArea(unsafe.Pointer(a)) a._hwnd = C.newArea(unsafe.Pointer(a))
a.SetSize(a.width, a.height) a.SetSize(a.width, a.height)
@ -122,7 +122,7 @@ func dotoARGB(img unsafe.Pointer, ppvBits unsafe.Pointer, toNRGBA C.BOOL) {
i := (*image.RGBA)(unsafe.Pointer(img)) i := (*image.RGBA)(unsafe.Pointer(img))
t := toNRGBA != C.FALSE t := toNRGBA != C.FALSE
// the bitmap Windows gives us has a stride == width // the bitmap Windows gives us has a stride == width
toARGB(i, uintptr(ppvBits), i.Rect.Dx() * 4, t) toARGB(i, uintptr(ppvBits), i.Rect.Dx()*4, t)
} }
//export areaWidthLONG //export areaWidthLONG
@ -184,19 +184,19 @@ func finishAreaMouseEvent(data unsafe.Pointer, cbutton C.DWORD, up C.BOOL, heldB
} }
// though wparam will contain control and shift state, let's use just one function to get modifiers for both keyboard and mouse events; it'll work the same anyway since we have to do this for alt and windows key (super) // though wparam will contain control and shift state, let's use just one function to get modifiers for both keyboard and mouse events; it'll work the same anyway since we have to do this for alt and windows key (super)
me.Modifiers = getModifiers() me.Modifiers = getModifiers()
if button != 1 && (heldButtons & C.MK_LBUTTON) != 0 { if button != 1 && (heldButtons&C.MK_LBUTTON) != 0 {
me.Held = append(me.Held, 1) me.Held = append(me.Held, 1)
} }
if button != 2 && (heldButtons & C.MK_MBUTTON) != 0 { if button != 2 && (heldButtons&C.MK_MBUTTON) != 0 {
me.Held = append(me.Held, 2) me.Held = append(me.Held, 2)
} }
if button != 3 && (heldButtons & C.MK_RBUTTON) != 0 { if button != 3 && (heldButtons&C.MK_RBUTTON) != 0 {
me.Held = append(me.Held, 3) me.Held = append(me.Held, 3)
} }
if button != 4 && (heldButtons & C.MK_XBUTTON1) != 0 { if button != 4 && (heldButtons&C.MK_XBUTTON1) != 0 {
me.Held = append(me.Held, 4) me.Held = append(me.Held, 4)
} }
if button != 5 && (heldButtons & C.MK_XBUTTON2) != 0 { if button != 5 && (heldButtons&C.MK_XBUTTON2) != 0 {
me.Held = append(me.Held, 5) me.Held = append(me.Held, 5)
} }
a.handler.Mouse(me) a.handler.Mouse(me)
@ -207,7 +207,7 @@ func areaKeyEvent(data unsafe.Pointer, up C.BOOL, wParam C.WPARAM, lParam C.LPAR
var ke KeyEvent var ke KeyEvent
a := (*area)(data) a := (*area)(data)
lp := uint32(lParam) // to be safe lp := uint32(lParam) // to be safe
// the numeric keypad keys when Num Lock is off are considered left-hand keys as the separate navigation buttons were added later // the numeric keypad keys when Num Lock is off are considered left-hand keys as the separate navigation buttons were added later
// the numeric keypad enter, however, is a right-hand key because it has the same virtual-key code as the typewriter enter // the numeric keypad enter, however, is a right-hand key because it has the same virtual-key code as the typewriter enter
righthand := (lp & 0x01000000) != 0 righthand := (lp & 0x01000000) != 0

View File

@ -10,16 +10,16 @@ import (
import "C" import "C"
type button struct { type button struct {
_id C.id _id C.id
clicked *event clicked *event
} }
func newButton(text string) *button { 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(), _id: 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))

View File

@ -13,9 +13,9 @@ import (
import "C" import "C"
type button struct { type button struct {
_widget *C.GtkWidget _widget *C.GtkWidget
button *C.GtkButton button *C.GtkButton
clicked *event clicked *event
} }
// shared code for setting up buttons, check boxes, etc. // shared code for setting up buttons, check boxes, etc.
@ -24,9 +24,9 @@ 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, _widget: widget,
button: (*C.GtkButton)(unsafe.Pointer(widget)), button: (*C.GtkButton)(unsafe.Pointer(widget)),
clicked: newEvent(), clicked: newEvent(),
} }
g_signal_connect( g_signal_connect(
C.gpointer(unsafe.Pointer(b.button)), C.gpointer(unsafe.Pointer(b.button)),

View File

@ -10,20 +10,20 @@ import (
import "C" import "C"
type button struct { type button struct {
_hwnd C.HWND _hwnd C.HWND
_textlen C.LONG _textlen C.LONG
clicked *event clicked *event
} }
var buttonclass = toUTF16("BUTTON") var buttonclass = toUTF16("BUTTON")
func newButton(text string) *button { func newButton(text string) *button {
hwnd := C.newControl(buttonclass, hwnd := C.newControl(buttonclass,
C.BS_PUSHBUTTON | C.WS_TABSTOP, C.BS_PUSHBUTTON|C.WS_TABSTOP,
0) 0)
b := &button{ b := &button{
_hwnd: hwnd, _hwnd: hwnd,
clicked: newEvent(), clicked: newEvent(),
} }
b.SetText(text) b.SetText(text)
C.controlSetControlFont(b._hwnd) C.controlSetControlFont(b._hwnd)
@ -78,13 +78,13 @@ func (b *button) preferredSize(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)

View File

@ -10,16 +10,16 @@ import (
import "C" import "C"
type checkbox struct { type checkbox struct {
_id C.id _id C.id
toggled *event toggled *event
} }
func newCheckbox(text string) *checkbox { 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(), _id: 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))

View File

@ -13,11 +13,11 @@ import (
import "C" import "C"
type checkbox struct { type checkbox struct {
_widget *C.GtkWidget _widget *C.GtkWidget
button *C.GtkButton button *C.GtkButton
toggle *C.GtkToggleButton toggle *C.GtkToggleButton
checkbox *C.GtkCheckButton checkbox *C.GtkCheckButton
toggled *event toggled *event
} }
func newCheckbox(text string) *checkbox { func newCheckbox(text string) *checkbox {
@ -25,11 +25,11 @@ 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, _widget: 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)),
toggled: newEvent(), toggled: newEvent(),
} }
g_signal_connect( g_signal_connect(
C.gpointer(unsafe.Pointer(c.checkbox)), C.gpointer(unsafe.Pointer(c.checkbox)),

View File

@ -10,20 +10,20 @@ import (
import "C" import "C"
type checkbox struct { type checkbox struct {
_hwnd C.HWND _hwnd C.HWND
_textlen C.LONG _textlen C.LONG
toggled *event toggled *event
} }
func newCheckbox(text string) *checkbox { func newCheckbox(text string) *checkbox {
// don't use BS_AUTOCHECKBOX here because it creates problems when refocusing (see http://blogs.msdn.com/b/oldnewthing/archive/2014/05/22/10527522.aspx) // don't use BS_AUTOCHECKBOX here because it creates problems when refocusing (see http://blogs.msdn.com/b/oldnewthing/archive/2014/05/22/10527522.aspx)
// we'll handle actually toggling the check state ourselves (see controls_windows.c) // we'll handle actually toggling the check state ourselves (see controls_windows.c)
hwnd := C.newControl(buttonclass, hwnd := C.newControl(buttonclass,
C.BS_CHECKBOX | C.WS_TABSTOP, C.BS_CHECKBOX|C.WS_TABSTOP,
0) 0)
c := &checkbox{ c := &checkbox{
_hwnd: hwnd, _hwnd: hwnd,
toggled: newEvent(), toggled: newEvent(),
} }
c.SetText(text) c.SetText(text)
C.controlSetControlFont(c._hwnd) C.controlSetControlFont(c._hwnd)

View File

@ -4,9 +4,9 @@ package ui
import ( import (
"fmt" "fmt"
"reflect"
"syscall" "syscall"
"unsafe" "unsafe"
"reflect"
) )
// #include "winapi_windows.h" // #include "winapi_windows.h"
@ -40,7 +40,7 @@ func getWindowText(hwnd C.HWND) string {
// WM_GETTEXTLENGTH and WM_GETTEXT return the count /without/ the terminating null character // WM_GETTEXTLENGTH and WM_GETTEXT return the count /without/ the terminating null character
// but WM_GETTEXT expects the buffer size handed to it to /include/ the terminating null character // but WM_GETTEXT expects the buffer size handed to it to /include/ the terminating null character
n := C.getWindowTextLen(hwnd) n := C.getWindowTextLen(hwnd)
buf := make([]uint16, int(n + 1)) buf := make([]uint16, int(n+1))
C.getWindowText(hwnd, C.WPARAM(n), C.getWindowText(hwnd, C.WPARAM(n),
C.LPWSTR(unsafe.Pointer(&buf[0]))) C.LPWSTR(unsafe.Pointer(&buf[0])))
return syscall.UTF16ToString(buf) return syscall.UTF16ToString(buf)
@ -49,9 +49,9 @@ func getWindowText(hwnd C.HWND) string {
func wstrToString(wstr *C.WCHAR) string { func wstrToString(wstr *C.WCHAR) string {
n := C.wcslen((*C.wchar_t)(unsafe.Pointer(wstr))) n := C.wcslen((*C.wchar_t)(unsafe.Pointer(wstr)))
xbuf := &reflect.SliceHeader{ xbuf := &reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(wstr)), Data: uintptr(unsafe.Pointer(wstr)),
Len: int(n + 1), Len: int(n + 1),
Cap: int(n + 1), Cap: int(n + 1),
} }
buf := (*[]uint16)(unsafe.Pointer(xbuf)) buf := (*[]uint16)(unsafe.Pointer(xbuf))
return syscall.UTF16ToString(*buf) return syscall.UTF16ToString(*buf)

View File

@ -3,20 +3,20 @@
package ui package ui
type allocation struct { type allocation struct {
x int x int
y int y int
width int width int
height int height int
this Control this Control
neighbor Control neighbor Control
} }
type sizingbase struct { type sizingbase struct {
xmargin int xmargin int
ymargintop int ymargintop int
ymarginbottom int ymarginbottom int
xpadding int xpadding int
ypadding int ypadding int
} }
type controlSizing interface { type controlSizing interface {
@ -31,19 +31,19 @@ type controlSizing interface {
// 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. // 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. // All containers must embed containerbase.
type containerbase struct { type containerbase struct {
child Control child Control
} }
// set to true to apply spacing to all windows // set to true to apply spacing to all windows
var spaced bool = false var spaced bool = false
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
} }
d := c.beginResize() d := c.beginResize()
allocations := c.child.allocate(x + d.xmargin, y + d.ymargintop, allocations := c.child.allocate(x+d.xmargin, y+d.ymargintop,
width - (2 * d.xmargin), height - d.ymargintop - d.ymarginbottom, d) width-(2*d.xmargin), height-d.ymargintop-d.ymarginbottom, d)
c.translateAllocationCoords(allocations, width, height) c.translateAllocationCoords(allocations, width, height)
// move in reverse so as to approximate right->left order so neighbors make sense // move in reverse so as to approximate right->left order so neighbors make sense
for i := len(allocations) - 1; i >= 0; i-- { for i := len(allocations) - 1; i >= 0; i-- {

View File

@ -11,7 +11,7 @@ import "C"
type container struct { type container struct {
containerbase containerbase
id C.id id C.id
} }
type sizing struct { type sizing struct {
@ -21,7 +21,7 @@ type sizing struct {
// nothing for mac // nothing for mac
// for the actual resizing // for the actual resizing
neighborAlign C.struct_xalignment neighborAlign C.struct_xalignment
} }
func newContainer(child Control) *container { func newContainer(child Control) *container {
@ -41,8 +41,8 @@ func containerResized(data unsafe.Pointer, width C.intptr_t, height C.intptr_t)
// These are based on measurements from Interface Builder. // These are based on measurements from Interface Builder.
const ( const (
macXMargin = 20 macXMargin = 20
macYMargin = 20 macYMargin = 20
macXPadding = 8 macXPadding = 8
macYPadding = 8 macYPadding = 8
) )

View File

@ -13,8 +13,8 @@ import "C"
type container struct { type container struct {
containerbase containerbase
layoutwidget *C.GtkWidget layoutwidget *C.GtkWidget
layoutcontainer *C.GtkContainer layoutcontainer *C.GtkContainer
} }
type sizing struct { type sizing struct {
@ -24,7 +24,7 @@ type sizing struct {
// gtk+ needs nothing // gtk+ needs nothing
// for the actual resizing // for the actual resizing
shouldVAlignTop bool shouldVAlignTop bool
} }
func newContainer(child Control) *container { func newContainer(child Control) *container {
@ -48,8 +48,8 @@ func containerResizing(data unsafe.Pointer, r *C.GtkAllocation) {
} }
const ( const (
gtkXMargin = 12 gtkXMargin = 12
gtkYMargin = 12 gtkYMargin = 12
gtkXPadding = 12 gtkXPadding = 12
gtkYPadding = 6 gtkYPadding = 6
) )

View File

@ -13,18 +13,18 @@ import "C"
type container struct { type container struct {
containerbase containerbase
hwnd C.HWND hwnd C.HWND
nchildren int nchildren int
isGroup bool isGroup bool
} }
type sizing struct { type sizing struct {
sizingbase sizingbase
// for size calculations // for size calculations
baseX C.int baseX C.int
baseY C.int baseY C.int
internalLeading C.LONG // for Label; see Label.commitResize() for details internalLeading C.LONG // for Label; see Label.commitResize() for details
// for the actual resizing // for the actual resizing
// possibly the HDWP // possibly the HDWP
@ -57,7 +57,7 @@ func (c *container) setParent(hwnd C.HWND) {
// this is needed because Windows won't move/resize a child window for us // this is needed because Windows won't move/resize a child window for us
func (c *container) move(r *C.RECT) { 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)) C.moveWindow(c.hwnd, C.int(r.left), C.int(r.top), C.int(r.right-r.left), C.int(r.bottom-r.top))
} }
func (c *container) show() { func (c *container) show() {
@ -78,7 +78,7 @@ func storeContainerHWND(data unsafe.Pointer, hwnd C.HWND) {
func containerResize(data unsafe.Pointer, r *C.RECT) { func containerResize(data unsafe.Pointer, r *C.RECT) {
c := (*container)(data) c := (*container)(data)
// 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 // 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)) 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,11 +103,11 @@ func fromdlgunitsY(du int, d *sizing) int {
} }
const ( const (
marginDialogUnits = 7 marginDialogUnits = 7
paddingDialogUnits = 4 paddingDialogUnits = 4
groupXMargin = 6 groupXMargin = 6
groupYMarginTop = 11 // note this value /includes the groupbox label/ groupYMarginTop = 11 // note this value /includes the groupbox label/
groupYMarginBottom = 7 groupYMarginBottom = 7
) )

View File

@ -4,17 +4,17 @@ 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 controlSizing
} }
// this is the same across all platforms // this is the same across all platforms
func baseallocate(c Control, x int, y int, width int, height int, d *sizing) []*allocation { func baseallocate(c Control, x int, y int, width int, height int, d *sizing) []*allocation {
return []*allocation{&allocation{ return []*allocation{&allocation{
x: x, x: x,
y: y, y: y,
width: width, width: width,
height: height, height: height,
this: c, this: c,
}} }}
} }

View File

@ -12,7 +12,7 @@ type controlPrivate interface {
} }
type controlParent struct { type controlParent struct {
id C.id id C.id
} }
func basesetParent(c controlPrivate, p *controlParent) { func basesetParent(c controlPrivate, p *controlParent) {
@ -38,13 +38,13 @@ func basegetAuxResizeInfo(c controlPrivate, d *sizing) {
} }
type scroller struct { type scroller struct {
id C.id id C.id
} }
func newScroller(child C.id, bordered bool) *scroller { func newScroller(child C.id, bordered bool) *scroller {
id := C.newScrollView(child, toBOOL(bordered)) id := C.newScrollView(child, toBOOL(bordered))
s := &scroller{ s := &scroller{
id: id, id: id,
} }
return s return s
} }

View File

@ -18,11 +18,11 @@ type controlPrivate interface {
} }
type controlParent struct { type controlParent struct {
c *C.GtkContainer c *C.GtkContainer
} }
func basesetParent(c controlPrivate, p *controlParent) { func basesetParent(c controlPrivate, p *controlParent) {
widget := c.widget() // avoid multiple interface lookups widget := c.widget() // avoid multiple interface lookups
C.gtk_container_add(p.c, widget) C.gtk_container_add(p.c, widget)
// make sure the new widget is shown if not explicitly hidden // make sure the new widget is shown if not explicitly hidden
C.gtk_widget_show_all(widget) C.gtk_widget_show_all(widget)
@ -66,15 +66,15 @@ func basegetAuxResizeInfo(c Control, d *sizing) {
} }
type scroller struct { type scroller struct {
scrollwidget *C.GtkWidget scrollwidget *C.GtkWidget
scrollcontainer *C.GtkContainer scrollcontainer *C.GtkContainer
scrollwindow *C.GtkScrolledWindow scrollwindow *C.GtkScrolledWindow
overlaywidget *C.GtkWidget overlaywidget *C.GtkWidget
overlaycontainer *C.GtkContainer overlaycontainer *C.GtkContainer
overlay *C.GtkOverlay overlay *C.GtkOverlay
addShowWhich *C.GtkWidget 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 {
@ -85,12 +85,12 @@ func newScroller(widget *C.GtkWidget, native bool, bordered bool, overlay bool)
o = C.gtk_overlay_new() o = C.gtk_overlay_new()
} }
s := &scroller{ s := &scroller{
scrollwidget: scrollwidget, scrollwidget: scrollwidget,
scrollcontainer: (*C.GtkContainer)(unsafe.Pointer(scrollwidget)), scrollcontainer: (*C.GtkContainer)(unsafe.Pointer(scrollwidget)),
scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scrollwidget)), scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scrollwidget)),
overlaywidget: o, overlaywidget: o,
overlaycontainer: (*C.GtkContainer)(unsafe.Pointer(o)), overlaycontainer: (*C.GtkContainer)(unsafe.Pointer(o)),
overlay: (*C.GtkOverlay)(unsafe.Pointer(o)), overlay: (*C.GtkOverlay)(unsafe.Pointer(o)),
} }
// 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 {

View File

@ -11,7 +11,7 @@ type controlPrivate interface {
} }
type controlParent struct { type controlParent struct {
c *container c *container
} }
func basesetParent(c controlPrivate, p *controlParent) { func basesetParent(c controlPrivate, p *controlParent) {

View File

@ -25,7 +25,7 @@ import "C"
func (w *window) openFile(f func(filename string)) { func (w *window) openFile(f func(filename string)) {
widget := C.newOpenFileDialog(w.window) widget := C.newOpenFileDialog(w.window)
window := (*C.GtkWindow)(unsafe.Pointer(widget)) window := (*C.GtkWindow)(unsafe.Pointer(widget))
dialog := (*C.GtkDialog)(unsafe.Pointer(widget)) dialog := (*C.GtkDialog)(unsafe.Pointer(widget))
fc := (*C.GtkFileChooser)(unsafe.Pointer(widget)) fc := (*C.GtkFileChooser)(unsafe.Pointer(widget))
// non-local filenames are relevant mainly to GIO where we can open *anything*, not to Go os.File; see https://twitter.com/braket/status/506142849654870016 // non-local filenames are relevant mainly to GIO where we can open *anything*, not to Go os.File; see https://twitter.com/braket/status/506142849654870016
C.gtk_file_chooser_set_local_only(fc, C.TRUE) C.gtk_file_chooser_set_local_only(fc, C.TRUE)

102
grid.go
View File

@ -31,6 +31,7 @@ type Grid interface {
// 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.
type Align uint type Align uint
const ( const (
LeftTop Align = iota LeftTop Align = iota
Center Center
@ -40,6 +41,7 @@ const (
// Side represents a side of a Control to add other Controls to a Grid to. // Side represents a side of a Control to add other Controls to a Grid to.
type Side uint type Side uint
const ( const (
West Side = iota West Side = iota
East East
@ -49,39 +51,39 @@ const (
) )
type grid struct { type grid struct {
controls []gridCell controls []gridCell
indexof map[Control]int indexof map[Control]int
prev int prev int
parent *controlParent parent *controlParent
xmax int xmax int
ymax int ymax int
} }
type gridCell struct { type gridCell struct {
control Control control Control
xexpand bool xexpand bool
xalign Align xalign Align
yexpand bool yexpand bool
yalign Align yalign Align
xspan int xspan int
yspan int yspan int
x int x int
y int y int
finalx int finalx int
finaly int finaly int
finalwidth int finalwidth int
finalheight int finalheight int
prefwidth int prefwidth int
prefheight int prefheight int
} }
// NewGrid creates a new Grid with no Controls. // NewGrid creates a new Grid with no Controls.
func NewGrid() Grid { func NewGrid() Grid {
return &grid{ return &grid{
indexof: map[Control]int{}, indexof: map[Control]int{},
} }
} }
@ -105,10 +107,10 @@ func (g *grid) reorigin() {
for i := range g.controls { for i := range g.controls {
g.controls[i].x += xmin g.controls[i].x += xmin
g.controls[i].y += ymin g.controls[i].y += ymin
if g.xmax < g.controls[i].x + g.controls[i].xspan { if g.xmax < g.controls[i].x+g.controls[i].xspan {
g.xmax = g.controls[i].x + g.controls[i].xspan g.xmax = g.controls[i].x + g.controls[i].xspan
} }
if g.ymax < g.controls[i].y + g.controls[i].yspan { if g.ymax < g.controls[i].y+g.controls[i].yspan {
g.ymax = g.controls[i].y + g.controls[i].yspan g.ymax = g.controls[i].y + g.controls[i].yspan
} }
} }
@ -119,13 +121,13 @@ func (g *grid) Add(control Control, nextTo Control, side Side, xexpand bool, xal
panic(fmt.Errorf("invalid span %dx%d given to Grid.Add()", xspan, yspan)) panic(fmt.Errorf("invalid span %dx%d given to Grid.Add()", xspan, yspan))
} }
cell := gridCell{ cell := gridCell{
control: control, control: control,
xexpand: xexpand, xexpand: xexpand,
xalign: xalign, xalign: xalign,
yexpand: yexpand, yexpand: yexpand,
yalign: yalign, yalign: yalign,
xspan: xspan, xspan: xspan,
yspan: yspan, yspan: yspan,
} }
if g.parent != nil { if g.parent != nil {
control.setParent(g.parent) control.setParent(g.parent)
@ -176,8 +178,8 @@ func (g *grid) mkgrid() (gg [][]int, colwidths []int, rowheights []int) {
} }
} }
for i := range g.controls { for i := range g.controls {
for y := g.controls[i].y; y < g.controls[i].y + g.controls[i].yspan; y++ { for y := g.controls[i].y; y < g.controls[i].y+g.controls[i].yspan; y++ {
for x := g.controls[i].x; x < g.controls[i].x + g.controls[i].xspan; x++ { for x := g.controls[i].x; x < g.controls[i].x+g.controls[i].xspan; x++ {
gg[y][x] = i gg[y][x] = i
} }
} }
@ -241,28 +243,28 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
for i := range g.controls { for i := range g.controls {
if g.controls[i].xexpand && g.controls[i].xspan != 1 { if g.controls[i].xexpand && g.controls[i].xspan != 1 {
do := true do := true
for x := g.controls[i].x; x < g.controls[i].x + g.controls[i].xspan; x++ { for x := g.controls[i].x; x < g.controls[i].x+g.controls[i].xspan; x++ {
if xexpand[x] { if xexpand[x] {
do = false do = false
break break
} }
} }
if do { if do {
for x := g.controls[i].x; x < g.controls[i].x + g.controls[i].xspan; x++ { for x := g.controls[i].x; x < g.controls[i].x+g.controls[i].xspan; x++ {
xexpand[x] = true xexpand[x] = true
} }
} }
} }
if g.controls[i].yexpand && g.controls[i].yspan != 1 { if g.controls[i].yexpand && g.controls[i].yspan != 1 {
do := true do := true
for y := g.controls[i].y; y < g.controls[i].y + g.controls[i].yspan; y++ { for y := g.controls[i].y; y < g.controls[i].y+g.controls[i].yspan; y++ {
if yexpand[y] { if yexpand[y] {
do = false do = false
break break
} }
} }
if do { if do {
for y := g.controls[i].y; y < g.controls[i].y + g.controls[i].yspan; y++ { for y := g.controls[i].y; y < g.controls[i].y+g.controls[i].yspan; y++ {
yexpand[y] = true yexpand[y] = true
} }
} }
@ -311,7 +313,7 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
prev := -1 prev := -1
for x := 0; x < g.xmax; x++ { for x := 0; x < g.xmax; x++ {
i := gg[y][x] i := gg[y][x]
if i != -1 && y == g.controls[i].y { // don't repeat this step if the control spans vertically if i != -1 && y == g.controls[i].y { // don't repeat this step if the control spans vertically
if i != prev { if i != prev {
g.controls[i].finalx = curx g.controls[i].finalx = curx
} else { } else {
@ -328,7 +330,7 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
prev := -1 prev := -1
for y := 0; y < g.ymax; y++ { for y := 0; y < g.ymax; y++ {
i := gg[y][x] i := gg[y][x]
if i != -1 && x == g.controls[i].x { // don't repeat this step if the control spans horizontally if i != -1 && x == g.controls[i].x { // don't repeat this step if the control spans horizontally
if i != prev { if i != prev {
g.controls[i].finaly = cury g.controls[i].finaly = cury
} else { } else {
@ -351,7 +353,7 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
case Center: case Center:
g.controls[i].finalx += (g.controls[i].finalwidth - g.controls[i].prefwidth) / 2 g.controls[i].finalx += (g.controls[i].finalwidth - g.controls[i].prefwidth) / 2
} }
g.controls[i].finalwidth = g.controls[i].prefwidth // for all three g.controls[i].finalwidth = g.controls[i].prefwidth // for all three
} }
if g.controls[i].yalign != Fill { if g.controls[i].yalign != Fill {
switch g.controls[i].yalign { switch g.controls[i].yalign {
@ -360,7 +362,7 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
case Center: case Center:
g.controls[i].finaly += (g.controls[i].finalheight - g.controls[i].prefheight) / 2 g.controls[i].finaly += (g.controls[i].finalheight - g.controls[i].prefheight) / 2
} }
g.controls[i].finalheight = g.controls[i].prefheight // for all three g.controls[i].finalheight = g.controls[i].prefheight // for all three
} }
} }
@ -370,17 +372,17 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
for _, ycol := range gg { for _, ycol := range gg {
current = nil 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( as := g.controls[i].control.allocate(
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 if current != nil { // connect first left to first right
current.neighbor = g.controls[i].control current.neighbor = g.controls[i].control
} }
if len(as) != 0 { if len(as) != 0 {
current = as[0] // next left is first subwidget current = as[0] // next left is first subwidget
} else { } else {
current = nil // spaces don't have allocation data current = nil // spaces don't have allocation data
} }
allocations = append(allocations, as...) allocations = append(allocations, as...)
} }
@ -409,10 +411,10 @@ func (g *grid) preferredSize(d *sizing) (width, height int) {
} }
w, h := g.controls[i].control.preferredSize(d) w, h := g.controls[i].control.preferredSize(d)
// allot equal space in the presence of spanning to keep things sane // allot equal space in the presence of spanning to keep things sane
if colwidths[x] < w / g.controls[i].xspan { if colwidths[x] < w/g.controls[i].xspan {
colwidths[x] = w / g.controls[i].xspan colwidths[x] = w / g.controls[i].xspan
} }
if rowheights[y] < h / g.controls[i].yspan { if rowheights[y] < h/g.controls[i].yspan {
rowheights[y] = h / g.controls[i].yspan rowheights[y] = h / g.controls[i].yspan
} }
// save these for step 6 // save these for step 6
@ -432,8 +434,8 @@ 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)*d.xpadding,
rowheight + (g.ymax - 1) * d.ypadding rowheight + (g.ymax-1)*d.ypadding
} }
func (g *grid) commitResize(a *allocation, d *sizing) { func (g *grid) commitResize(a *allocation, d *sizing) {

View File

@ -10,7 +10,7 @@ import (
import "C" import "C"
type group struct { type group struct {
_id C.id _id C.id
*container *container
} }

View File

@ -12,9 +12,9 @@ import (
import "C" import "C"
type group struct { type group struct {
_widget *C.GtkWidget _widget *C.GtkWidget
gcontainer *C.GtkContainer gcontainer *C.GtkContainer
frame *C.GtkFrame frame *C.GtkFrame
*container *container
} }
@ -24,9 +24,9 @@ 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, _widget: 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)),
} }
// 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
@ -44,7 +44,7 @@ func newGroup(text string, control Control) Group {
boldlist := C.pango_attr_list_new() boldlist := C.pango_attr_list_new()
C.pango_attr_list_insert(boldlist, bold) C.pango_attr_list_insert(boldlist, bold)
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(control)
g.container.setParent(&controlParent{g.gcontainer}) g.container.setParent(&controlParent{g.gcontainer})

View File

@ -6,8 +6,8 @@ package ui
import "C" import "C"
type group struct { type group struct {
_hwnd C.HWND _hwnd C.HWND
_textlen C.LONG _textlen C.LONG
*container *container
} }
@ -17,8 +17,8 @@ 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, _hwnd: hwnd,
container: newContainer(control), container: newContainer(control),
} }
g.SetText(text) g.SetText(text)
C.controlSetControlFont(g._hwnd) C.controlSetControlFont(g._hwnd)
@ -57,7 +57,7 @@ func (g *group) allocate(x int, y int, width int, height int, d *sizing) []*allo
func (g *group) preferredSize(d *sizing) (width, height int) { 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 // the two margin constants come from container_windows.go

View File

@ -11,7 +11,7 @@ import (
import "C" import "C"
type imagelist struct { type imagelist struct {
list []C.id list []C.id
} }
func newImageList() ImageList { func newImageList() ImageList {

View File

@ -6,15 +6,15 @@ package ui
import ( import (
"fmt" "fmt"
"unsafe"
"image" "image"
"unsafe"
) )
// #include "gtk_unix.h" // #include "gtk_unix.h"
import "C" import "C"
type imagelist struct { type imagelist struct {
list []*C.GdkPixbuf list []*C.GdkPixbuf
} }
func newImageList() ImageList { func newImageList() ImageList {
@ -37,7 +37,7 @@ func (i *imagelist) Append(img *image.RGBA) {
} }
C.cairo_surface_flush(surface) C.cairo_surface_flush(surface)
toARGB(img, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))), toARGB(img, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))),
int(C.cairo_image_surface_get_stride(surface)), false) // not NRGBA int(C.cairo_image_surface_get_stride(surface)), false) // not NRGBA
C.cairo_surface_mark_dirty(surface) C.cairo_surface_mark_dirty(surface)
basepixbuf := C.gdk_pixbuf_get_from_surface(surface, 0, 0, C.gint(img.Rect.Dx()), C.gint(img.Rect.Dy())) basepixbuf := C.gdk_pixbuf_get_from_surface(surface, 0, 0, C.gint(img.Rect.Dx()), C.gint(img.Rect.Dy()))
if basepixbuf == nil { if basepixbuf == nil {

View File

@ -11,9 +11,9 @@ import (
import "C" import "C"
type imagelist struct { type imagelist struct {
list []C.HBITMAP list []C.HBITMAP
width []int width []int
height []int height []int
} }
func newImageList() ImageList { func newImageList() ImageList {

View File

@ -10,14 +10,14 @@ import (
import "C" import "C"
type label struct { type label struct {
_id C.id _id C.id
standalone bool standalone bool
} }
func finishNewLabel(text string, standalone bool) *label { func finishNewLabel(text string, standalone bool) *label {
l := &label{ l := &label{
_id: C.newLabel(), _id: C.newLabel(),
standalone: standalone, standalone: standalone,
} }
l.SetText(text) l.SetText(text)
return l return l
@ -64,16 +64,16 @@ func (l *label) preferredSize(d *sizing) (width, height int) {
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)
if d.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline if d.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline
// in order for the baseline value to be correct, the label MUST BE AT THE HEIGHT THAT OS X WANTS IT TO BE! // in order for the baseline value to be correct, the label MUST BE AT THE HEIGHT THAT OS X WANTS IT TO BE!
// otherwise, the baseline calculation will be relative to the bottom of the control, and everything will be wrong // otherwise, the baseline calculation will be relative to the bottom of the control, and everything will be wrong
origsize := C.controlPreferredSize(l._id) origsize := C.controlPreferredSize(l._id)
c.height = int(origsize.height) c.height = int(origsize.height)
newrect := C.struct_xrect{ newrect := C.struct_xrect{
x: C.intptr_t(c.x), x: C.intptr_t(c.x),
y: C.intptr_t(c.y), y: C.intptr_t(c.y),
width: C.intptr_t(c.width), width: C.intptr_t(c.width),
height: C.intptr_t(c.height), height: C.intptr_t(c.height),
} }
ourAlign := C.alignmentInfo(l._id, newrect) ourAlign := C.alignmentInfo(l._id, newrect)
// we need to find the exact Y positions of the baselines // we need to find the exact Y positions of the baselines

View File

@ -14,10 +14,10 @@ import (
import "C" import "C"
type label struct { type label struct {
_widget *C.GtkWidget _widget *C.GtkWidget
misc *C.GtkMisc misc *C.GtkMisc
label *C.GtkLabel label *C.GtkLabel
standalone bool standalone bool
} }
func finishNewLabel(text string, standalone bool) *label { func finishNewLabel(text string, standalone bool) *label {
@ -25,10 +25,10 @@ func finishNewLabel(text string, standalone bool) *label {
defer freegstr(ctext) defer freegstr(ctext)
widget := C.gtk_label_new(ctext) widget := C.gtk_label_new(ctext)
l := &label{ l := &label{
_widget: widget, _widget: 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, standalone: standalone,
} }
return l return l
} }

View File

@ -6,9 +6,9 @@ package ui
import "C" import "C"
type label struct { type label struct {
_hwnd C.HWND _hwnd C.HWND
_textlen C.LONG _textlen C.LONG
standalone bool standalone bool
} }
var labelclass = toUTF16("STATIC") var labelclass = toUTF16("STATIC")
@ -17,11 +17,11 @@ func finishNewLabel(text string, standalone bool) *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, _hwnd: hwnd,
standalone: standalone, standalone: standalone,
} }
l.SetText(text) l.SetText(text)
C.controlSetControlFont(l._hwnd) C.controlSetControlFont(l._hwnd)
@ -71,7 +71,7 @@ func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allo
const ( const (
// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing // via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
labelHeight = 8 labelHeight = 8
labelYOffset = 3 labelYOffset = 3
) )

View File

@ -34,7 +34,7 @@ type simpleGrid struct {
controls [][]Control controls [][]Control
filling [][]bool filling [][]bool
stretchyrow, stretchycol int stretchyrow, stretchycol int
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
} }
@ -98,7 +98,7 @@ func (g *simpleGrid) SetStretchy(row int, column int) {
} }
g.stretchyrow = row g.stretchyrow = row
g.stretchycol = column g.stretchycol = column
g.stretchyfill = g.filling[g.stretchyrow][g.stretchycol] // save previous value in case it changes later g.stretchyfill = g.filling[g.stretchyrow][g.stretchycol] // save previous value in case it changes later
g.filling[g.stretchyrow][g.stretchycol] = true g.filling[g.stretchyrow][g.stretchycol] = true
} }
@ -118,7 +118,7 @@ func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (a
return b return b
} }
var current *allocation // for neighboring var current *allocation // for neighboring
if len(g.controls) == 0 { if len(g.controls) == 0 {
return nil return nil
@ -161,7 +161,7 @@ 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 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]
@ -170,13 +170,13 @@ func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (a
h = g.rowheights[row] h = g.rowheights[row]
} }
as := c.allocate(x, y, w, h, d) as := c.allocate(x, y, w, h, d)
if current != nil { // connect first left to first right if current != nil { // connect first left to first right
current.neighbor = c current.neighbor = c
} }
if len(as) != 0 { if len(as) != 0 {
current = as[0] // next left is first subwidget current = as[0] // next left is first subwidget
} else { } else {
current = nil // spaces don't have allocation data current = nil // spaces don't have allocation data
} }
allocations = append(allocations, as...) allocations = append(allocations, as...)
x += g.colwidths[col] + d.xpadding x += g.colwidths[col] + d.xpadding

View File

@ -68,7 +68,7 @@ func (s *stack) setParent(parent *controlParent) {
func (s *stack) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) { func (s *stack) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) {
var stretchywid, stretchyht int var stretchywid, stretchyht int
var current *allocation // for neighboring var current *allocation // for neighboring
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 nil
@ -117,14 +117,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) as := c.allocate(x, y, s.width[i], s.height[i], d)
if s.orientation == horizontal { // no vertical neighbors if s.orientation == horizontal { // no vertical neighbors
if current != nil { // connect first left to first right if current != nil { // connect first left to first right
current.neighbor = c current.neighbor = c
} }
if len(as) != 0 { if len(as) != 0 {
current = as[0] // next left is first subwidget current = as[0] // next left is first subwidget
} else { } else {
current = nil // spaces don't have allocation data current = nil // spaces don't have allocation data
} }
} }
allocations = append(allocations, as...) allocations = append(allocations, as...)
@ -192,7 +192,6 @@ func (s *stack) getAuxResizeInfo(d *sizing) {
// this is to satisfy Control; nothing to do here // 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.
// //

View File

@ -10,13 +10,13 @@ import (
import "C" import "C"
type tab struct { type tab struct {
_id C.id _id C.id
tabs []*container tabs []*container
} }
func newTab() Tab { func newTab() Tab {
return &tab{ return &tab{
_id: C.newTab(), _id: C.newTab(),
} }
} }

View File

@ -12,19 +12,19 @@ import (
import "C" import "C"
type tab struct { type tab struct {
_widget *C.GtkWidget _widget *C.GtkWidget
container *C.GtkContainer container *C.GtkContainer
notebook *C.GtkNotebook notebook *C.GtkNotebook
tabs []*container tabs []*container
} }
func newTab() Tab { func newTab() Tab {
widget := C.gtk_notebook_new() widget := C.gtk_notebook_new()
t := &tab{ t := &tab{
_widget: widget, _widget: 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)),
} }
// 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)
@ -40,7 +40,7 @@ func (t *tab) Append(name string, control Control) {
defer freegstr(cname) defer freegstr(cname)
C.gtk_notebook_set_tab_label_text(t.notebook, C.gtk_notebook_set_tab_label_text(t.notebook,
// unfortunately there does not seem to be a gtk_notebook_set_nth_tab_label_text() // unfortunately there does not seem to be a gtk_notebook_set_nth_tab_label_text()
C.gtk_notebook_get_nth_page(t.notebook, C.gint(len(t.tabs) - 1)), C.gtk_notebook_get_nth_page(t.notebook, C.gint(len(t.tabs)-1)),
cname) cname)
} }

View File

@ -16,16 +16,16 @@ We'll create a dummy window using the pre-existing Window window class for each
*/ */
type tab struct { type tab struct {
_hwnd C.HWND _hwnd C.HWND
tabs []*container tabs []*container
} }
func newTab() Tab { func newTab() Tab {
hwnd := C.newControl(C.xWC_TABCONTROL, hwnd := C.newControl(C.xWC_TABCONTROL,
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, _hwnd: hwnd,
} }
C.controlSetControlFont(t._hwnd) C.controlSetControlFont(t._hwnd)
C.setTabSubclass(t._hwnd, unsafe.Pointer(t)) C.setTabSubclass(t._hwnd, unsafe.Pointer(t))
@ -38,7 +38,7 @@ func (t *tab) Append(name string, control Control) {
t.tabs = append(t.tabs, c) t.tabs = append(t.tabs, c)
// 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))
} }
@ -58,7 +58,7 @@ func tabChanged(data unsafe.Pointer, new C.LRESULT) {
//export tabTabHasChildren //export tabTabHasChildren
func tabTabHasChildren(data unsafe.Pointer, which C.LRESULT) C.BOOL { func tabTabHasChildren(data unsafe.Pointer, which C.LRESULT) C.BOOL {
t := (*tab)(data) t := (*tab)(data)
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.tabs[int(which)].nchildren > 0 {

View File

@ -52,8 +52,8 @@ type Table interface {
} }
type tablebase struct { type tablebase struct {
lock sync.RWMutex lock sync.RWMutex
data interface{} data interface{}
} }
// NewTable creates a new Table. // NewTable creates a new Table.

View File

@ -14,20 +14,20 @@ import "C"
type table struct { type table struct {
*tablebase *tablebase
_id C.id _id C.id
scroller *scroller scroller *scroller
images []C.id images []C.id
selected *event selected *event
} }
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, _id: id,
scroller: newScroller(id, true), // border on Table scroller: newScroller(id, true), // border on Table
tablebase: b, tablebase: b,
selected: newEvent(), selected: newEvent(),
} }
// also sets the delegate // also sets the delegate
C.tableMakeDataSource(t._id, unsafe.Pointer(t)) C.tableMakeDataSource(t._id, unsafe.Pointer(t))
@ -43,7 +43,7 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
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
} }

View File

@ -18,27 +18,27 @@ import "C"
type table struct { type table struct {
*tablebase *tablebase
_widget *C.GtkWidget _widget *C.GtkWidget
treeview *C.GtkTreeView treeview *C.GtkTreeView
scroller *scroller scroller *scroller
model *C.goTableModel model *C.goTableModel
modelgtk *C.GtkTreeModel modelgtk *C.GtkTreeModel
selection *C.GtkTreeSelection selection *C.GtkTreeSelection
pixbufs []*C.GdkPixbuf pixbufs []*C.GdkPixbuf
selected *event selected *event
// stuff required by GtkTreeModel // stuff required by GtkTreeModel
nColumns C.gint nColumns C.gint
old C.gint old C.gint
types []C.GType types []C.GType
crtocol map[*C.GtkCellRendererToggle]int crtocol map[*C.GtkCellRendererToggle]int
} }
var ( var (
attribText = togstr("text") attribText = togstr("text")
attribPixbuf = togstr("pixbuf") attribPixbuf = togstr("pixbuf")
attribActive = togstr("active") attribActive = togstr("active")
) )
@ -46,12 +46,12 @@ var (
func finishNewTable(b *tablebase, ty reflect.Type) Table { func finishNewTable(b *tablebase, ty reflect.Type) Table {
widget := C.gtk_tree_view_new() widget := C.gtk_tree_view_new()
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, _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(),
} }
model := C.newTableModel(unsafe.Pointer(t)) model := C.newTableModel(unsafe.Pointer(t))
t.model = model t.model = model
@ -87,7 +87,7 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
C.tableAppendColumn(t.treeview, C.gint(i), cname, C.tableAppendColumn(t.treeview, C.gint(i), cname,
C.gtk_cell_renderer_text_new(), attribText) C.gtk_cell_renderer_text_new(), attribText)
} }
freegstr(cname) // free now (not deferred) to conserve memory freegstr(cname) // free now (not deferred) to conserve memory
} }
// and for some GtkTreeModel boilerplate // and for some GtkTreeModel boilerplate
t.nColumns = C.gint(ty.NumField()) t.nColumns = C.gint(ty.NumField())

View File

@ -4,8 +4,8 @@ package ui
import ( import (
"fmt" "fmt"
"unsafe"
"reflect" "reflect"
"unsafe"
) )
// #include "winapi_windows.h" // #include "winapi_windows.h"
@ -13,32 +13,32 @@ import "C"
type table struct { type table struct {
*tablebase *tablebase
_hwnd C.HWND _hwnd C.HWND
noautosize bool noautosize bool
colcount C.int colcount C.int
hotrow C.int hotrow C.int
hotcol C.int hotcol C.int
pushedrow C.int pushedrow C.int
pushedcol C.int pushedcol C.int
selected *event selected *event
} }
func finishNewTable(b *tablebase, ty reflect.Type) Table { func finishNewTable(b *tablebase, ty reflect.Type) Table {
t := &table{ t := &table{
_hwnd: C.newControl(C.xWC_LISTVIEW, _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.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) 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,
pushedrow: -1, pushedrow: -1,
pushedcol: -1, pushedcol: -1,
selected: newEvent(), selected: newEvent(),
} }
C.setTableSubclass(t._hwnd, unsafe.Pointer(t)) 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++ {
@ -89,18 +89,18 @@ func tableGetCell(data unsafe.Pointer, item *C.LVITEMW) {
d := reflect.Indirect(reflect.ValueOf(t.data)) d := reflect.Indirect(reflect.ValueOf(t.data))
datum := d.Index(int(item.iItem)).Field(int(item.iSubItem)) datum := d.Index(int(item.iItem)).Field(int(item.iSubItem))
isText := true isText := true
if item.mask & C.LVIF_IMAGE != 0 { if item.mask&C.LVIF_IMAGE != 0 {
if datum.Type() == reflect.TypeOf(ImageIndex(0)) { if datum.Type() == reflect.TypeOf(ImageIndex(0)) {
item.iImage = C.int(datum.Interface().(ImageIndex)) item.iImage = C.int(datum.Interface().(ImageIndex))
isText = false isText = false
} }
// else let the default behavior work // else let the default behavior work
} }
if item.mask & C.LVIF_INDENT != 0 { if item.mask&C.LVIF_INDENT != 0 {
// always have an indent of zero // always have an indent of zero
item.iIndent = 0 item.iIndent = 0
} }
if item.mask & C.LVIF_STATE != 0 { if item.mask&C.LVIF_STATE != 0 {
// start by not changing any state // start by not changing any state
item.stateMask = 0 item.stateMask = 0
if datum.Kind() == reflect.Bool { if datum.Kind() == reflect.Bool {
@ -129,7 +129,7 @@ func tableGetCell(data unsafe.Pointer, item *C.LVITEMW) {
isText = false isText = false
} }
} }
if item.mask & C.LVIF_TEXT != 0 { if item.mask&C.LVIF_TEXT != 0 {
if isText { if isText {
s := fmt.Sprintf("%v", datum) s := fmt.Sprintf("%v", datum)
item.pszText = toUTF16(s) item.pszText = toUTF16(s)
@ -190,10 +190,10 @@ func tableToggled(data unsafe.Pointer, row C.int, col C.int) {
// and THEN unlock so the reset takes effect // and THEN unlock so the reset takes effect
t.Unlock() t.Unlock()
}() }()
if row == -1 || col == -1 { // discard extras sent by handle() in table_windows.c if row == -1 || col == -1 { // discard extras sent by handle() in table_windows.c
return return
} }
if row != t.pushedrow || col != t.pushedcol { // mouse moved out if row != t.pushedrow || col != t.pushedcol { // mouse moved out
return return
} }
d := reflect.Indirect(reflect.ValueOf(t.data)) d := reflect.Indirect(reflect.ValueOf(t.data))
@ -226,7 +226,7 @@ func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allo
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...
tableWidth = 183 tableWidth = 183
tableHeight = 50 tableHeight = 50
) )

View File

@ -10,15 +10,15 @@ import (
import "C" import "C"
type textfield struct { type textfield struct {
_id C.id _id C.id
changed *event changed *event
invalid C.id invalid C.id
} }
func finishNewTextField(id C.id) *textfield { func finishNewTextField(id C.id) *textfield {
t := &textfield{ t := &textfield{
_id: id, _id: id,
changed: newEvent(), changed: newEvent(),
} }
C.textfieldSetDelegate(t._id, unsafe.Pointer(t)) C.textfieldSetDelegate(t._id, unsafe.Pointer(t))
return t return t

View File

@ -18,17 +18,17 @@ import (
import "C" import "C"
type textfield struct { type textfield struct {
_widget *C.GtkWidget _widget *C.GtkWidget
entry *C.GtkEntry entry *C.GtkEntry
changed *event changed *event
} }
func startNewTextField() *textfield { func startNewTextField() *textfield {
widget := C.gtk_entry_new() widget := C.gtk_entry_new()
t := &textfield{ t := &textfield{
_widget: widget, _widget: 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)),

View File

@ -10,20 +10,20 @@ import (
import "C" import "C"
type textfield struct { type textfield struct {
_hwnd C.HWND _hwnd C.HWND
_textlen C.LONG _textlen C.LONG
changed *event changed *event
} }
var editclass = toUTF16("EDIT") var editclass = toUTF16("EDIT")
func startNewTextField(style C.DWORD) *textfield { func startNewTextField(style C.DWORD) *textfield {
hwnd := C.newControl(editclass, hwnd := C.newControl(editclass,
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, _hwnd: hwnd,
changed: newEvent(), changed: newEvent(),
} }
C.controlSetControlFont(t._hwnd) C.controlSetControlFont(t._hwnd)
C.setTextFieldSubclass(t._hwnd, unsafe.Pointer(t)) C.setTextFieldSubclass(t._hwnd, unsafe.Pointer(t))
@ -86,7 +86,7 @@ func (t *textfield) allocate(x int, y int, width int, height int, d *sizing) []*
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
) )

View File

@ -3,10 +3,10 @@
package ui package ui
import ( import (
"reflect"
"runtime" "runtime"
"sync" "sync"
"unsafe" "unsafe"
"reflect"
) )
// Go initializes and runs package ui. // Go initializes and runs package ui.
@ -63,13 +63,13 @@ func uiissueloop() {
type event struct { type event struct {
// All events internally return bool; those that don't will be wrapped around to return a dummy value. // All events internally return bool; those that don't will be wrapped around to return a dummy value.
do func() bool do func() bool
lock sync.Mutex lock sync.Mutex
} }
func newEvent() *event { func newEvent() *event {
return &event{ return &event{
do: func() bool { do: func() bool {
return false return false
}, },
} }
@ -119,9 +119,9 @@ func perform(fp unsafe.Pointer) {
// ForeignEvent wraps a channel in such a way that it can be used safely with package ui. // ForeignEvent wraps a channel in such a way that it can be used safely with package ui.
type ForeignEvent struct { type ForeignEvent struct {
c reflect.Value c reflect.Value
e *event e *event
d interface{} d interface{}
} }
// NewForeignEvent creates a new ForeignEvent with the specified channel. // NewForeignEvent creates a new ForeignEvent with the specified channel.
@ -131,12 +131,12 @@ type ForeignEvent struct {
func NewForeignEvent(channel interface{}, handler func(data interface{})) *ForeignEvent { func NewForeignEvent(channel interface{}, handler func(data interface{})) *ForeignEvent {
c := reflect.ValueOf(channel) c := reflect.ValueOf(channel)
t := c.Type() t := c.Type()
if t.Kind() != reflect.Chan || (t.ChanDir() & reflect.RecvDir) == 0 { if t.Kind() != reflect.Chan || (t.ChanDir()&reflect.RecvDir) == 0 {
panic("non-channel or non-receivable channel passed to NewForeignEvent()") panic("non-channel or non-receivable channel passed to NewForeignEvent()")
} }
fe := &ForeignEvent{ fe := &ForeignEvent{
c: c, c: c,
e: newEvent(), e: newEvent(),
} }
fe.e.set(func() { fe.e.set(func() {
handler(fe.d) handler(fe.d)

View File

@ -16,7 +16,7 @@ import (
import "C" import "C"
func uiinit() error { func uiinit() error {
var err *C.GError = nil // redundant in Go, but let's explicitly assign it anyway var err *C.GError = nil // redundant in Go, but let's explicitly assign it anyway
// gtk_init_with_args() gives us error info (thanks chpe in irc.gimp.net/#gtk+) // gtk_init_with_args() gives us error info (thanks chpe in irc.gimp.net/#gtk+)
// don't worry about GTK+'s command-line arguments; they're also available as environment variables (thanks mclasen in irc.gimp.net/#gtk+) // don't worry about GTK+'s command-line arguments; they're also available as environment variables (thanks mclasen in irc.gimp.net/#gtk+)
@ -42,7 +42,7 @@ func issue(f *func()) {
//export xdoissue //export xdoissue
func xdoissue(data C.gpointer) C.gboolean { func xdoissue(data C.gpointer) C.gboolean {
perform(unsafe.Pointer(data)) perform(unsafe.Pointer(data))
return C.FALSE // don't repeat return C.FALSE // don't repeat
} }
//export doissue //export doissue

View File

@ -10,9 +10,9 @@ import (
import "C" import "C"
type window struct { type window struct {
id C.id id C.id
closing *event closing *event
*container *container
} }
@ -23,9 +23,9 @@ func newWindow(title string, width int, height int, control Control) *window {
defer C.free(unsafe.Pointer(ctitle)) defer C.free(unsafe.Pointer(ctitle))
C.windowSetTitle(id, ctitle) C.windowSetTitle(id, ctitle)
w := &window{ w := &window{
id: id, id: id,
closing: newEvent(), closing: newEvent(),
container: newContainer(control), container: newContainer(control),
} }
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)

View File

@ -13,14 +13,14 @@ import (
import "C" import "C"
type window struct { type window struct {
widget *C.GtkWidget widget *C.GtkWidget
wc *C.GtkContainer wc *C.GtkContainer
bin *C.GtkBin bin *C.GtkBin
window *C.GtkWindow window *C.GtkWindow
group *C.GtkWindowGroup group *C.GtkWindowGroup
closing *event closing *event
*container *container
} }
@ -30,11 +30,11 @@ func newWindow(title string, width int, height int, control Control) *window {
ctitle := togstr(title) ctitle := togstr(title)
defer freegstr(ctitle) defer freegstr(ctitle)
w := &window{ w := &window{
widget: widget, widget: widget,
wc: (*C.GtkContainer)(unsafe.Pointer(widget)), wc: (*C.GtkContainer)(unsafe.Pointer(widget)),
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(),
} }
C.gtk_window_set_title(w.window, ctitle) C.gtk_window_set_title(w.window, ctitle)
g_signal_connect( g_signal_connect(
@ -82,7 +82,7 @@ func windowClosing(wid *C.GtkWidget, e *C.GdkEvent, data C.gpointer) C.gboolean
w := (*window)(unsafe.Pointer(data)) w := (*window)(unsafe.Pointer(data))
close := w.closing.fire() close := w.closing.fire()
if close { if close {
return C.GDK_EVENT_PROPAGATE // will do gtk_widget_destroy(), which is what we want (thanks ebassi in irc.gimp.net/#gtk+) return C.GDK_EVENT_PROPAGATE // will do gtk_widget_destroy(), which is what we want (thanks ebassi in irc.gimp.net/#gtk+)
} }
return C.GDK_EVENT_STOP // keeps window alive return C.GDK_EVENT_STOP // keeps window alive
} }

View File

@ -12,10 +12,10 @@ import (
import "C" import "C"
type window struct { type window struct {
hwnd C.HWND hwnd C.HWND
shownbefore bool shownbefore bool
closing *event closing *event
*container *container
} }
@ -33,14 +33,14 @@ 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 // hwnd set in WM_CREATE handler
closing: newEvent(), closing: newEvent(),
container: newContainer(control), container: newContainer(control),
} }
hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w)) hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w))
if hwnd != w.hwnd { if hwnd != w.hwnd {
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in Window (%p) differ", hwnd, w.hwnd)) panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in Window (%p) differ", hwnd, w.hwnd))
} }
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))
} }

File diff suppressed because it is too large Load Diff

View File

@ -10,20 +10,20 @@ import (
) )
type repainter struct { type repainter struct {
img *image.RGBA img *image.RGBA
area Area area Area
x TextField x TextField
y TextField y TextField
width TextField width TextField
height TextField height TextField
repaint Button repaint Button
all Button all Button
grid Grid grid Grid
xv int xv int
yv int yv int
wv int wv int
hv int hv int
} }
func newRepainter(times int) *repainter { func newRepainter(times int) *repainter {
@ -55,7 +55,7 @@ func newRepainter(times int) *repainter {
return r return r
} }
func (r *repainter) Paint(rect image.Rectangle) *image.RGBA { func (r *repainter) Paint(rect image.Rectangle) *image.RGBA {
return r.img.SubImage(rect).(*image.RGBA) return r.img.SubImage(rect).(*image.RGBA)
} }
@ -116,7 +116,7 @@ func (r *repainter) alter(rect image.Rectangle, c color.Color) {
} }
func (r *repainter) dorect() { func (r *repainter) dorect() {
rect := image.Rect(r.xv, r.yv, r.xv + r.wv, r.yv + r.hv) rect := image.Rect(r.xv, r.yv, r.xv+r.wv, r.yv+r.hv)
r.alter(rect, color.RGBA{255, 0, 255, 128}) r.alter(rect, color.RGBA{255, 0, 255, 128})
r.area.Repaint(rect) r.area.Repaint(rect)
} }

View File

@ -5,74 +5,76 @@ package ui
// This file is called zz_test.go to keep it separate from the other files in this package (and because go test won't accept just test.go) // This file is called zz_test.go to keep it separate from the other files in this package (and because go test won't accept just test.go)
import ( import (
"fmt"
"flag" "flag"
"reflect" "fmt"
"testing"
"image" "image"
"image/color" "image/color"
"image/draw" "image/draw"
"time" "reflect"
"strings" "strings"
"testing"
"time"
) )
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)")
type dtype struct { type dtype struct {
Name string Name string
Address string Address string
} }
var ddata = []dtype{ var ddata = []dtype{
{ "alpha", "beta" }, {"alpha", "beta"},
{ "gamma", "delta" }, {"gamma", "delta"},
{ "epsilon", "zeta" }, {"epsilon", "zeta"},
{ "eta", "theta" }, {"eta", "theta"},
{ "iota", "kappa" }, {"iota", "kappa"},
} }
type testwin struct { type testwin struct {
t Tab t Tab
w Window w Window
repainter *repainter repainter *repainter
fe *ForeignEvent fe *ForeignEvent
festack Stack festack Stack
festart Button festart Button
felabel Label felabel Label
festop Button festop Button
vedit TextField vedit TextField
openbtn Button openbtn Button
fnlabel Label fnlabel Label
icons []icon icons []icon
il ImageList il ImageList
icontbl Table icontbl Table
group2 Group group2 Group
group Group group Group
simpleGrid SimpleGrid simpleGrid SimpleGrid
nt Tab nt Tab
a Area a Area
spw Stack spw Stack
sph Stack sph Stack
s Stack s Stack
l Label l Label
table Table table Table
b Button b Button
c Checkbox c Checkbox
e TextField e TextField
e2 TextField e2 TextField
wsmall Window wsmall Window
} }
type areaHandler struct { type areaHandler struct {
handled bool handled bool
} }
func (a *areaHandler) Paint(r image.Rectangle) *image.RGBA { func (a *areaHandler) Paint(r image.Rectangle) *image.RGBA {
i := image.NewRGBA(r) i := image.NewRGBA(r)
draw.Draw(i, r, &image.Uniform{color.RGBA{128,0,128,255}}, image.ZP, draw.Src) draw.Draw(i, r, &image.Uniform{color.RGBA{128, 0, 128, 255}}, image.ZP, draw.Src)
return i return i
} }
func (a *areaHandler) Mouse(me MouseEvent) { fmt.Printf("%#v\n", me) } func (a *areaHandler) Mouse(me MouseEvent) { fmt.Printf("%#v\n", me) }
func (a *areaHandler) Key(ke KeyEvent) bool { fmt.Printf("%#v %q\n", ke, ke.Key); return a.handled } func (a *areaHandler) Key(ke KeyEvent) bool { fmt.Printf("%#v %q\n", ke, ke.Key); return a.handled }
func (tw *testwin) openFile(fn string) { func (tw *testwin) openFile(fn string) {
@ -145,7 +147,7 @@ func (tw *testwin) make(done chan struct{}) {
done <- struct{}{} done <- struct{}{}
return true return true
}) })
tw.icons, tw.il = readIcons() // repainter uses these tw.icons, tw.il = readIcons() // repainter uses these
tw.repainter = newRepainter(15) tw.repainter = newRepainter(15)
tw.t.Append("Repaint", tw.repainter.grid) tw.t.Append("Repaint", tw.repainter.grid)
tw.addfe() tw.addfe()
@ -192,7 +194,7 @@ func (tw *testwin) make(done chan struct{}) {
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")) NewStandaloneLabel("hello"))
tw.t.Append("Pref Width", tw.spw) tw.t.Append("Pref Width", tw.spw)
tw.sph = NewVerticalStack( tw.sph = NewVerticalStack(
@ -200,7 +202,7 @@ func (tw *testwin) make(done chan struct{}) {
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 ÉÀÔ")) NewStandaloneLabel("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())
@ -208,7 +210,7 @@ func (tw *testwin) make(done chan struct{}) {
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)