go fmt. Precursor to bug report filing.
This commit is contained in:
parent
09db0bffff
commit
982004d050
14
area.go
14
area.go
|
@ -62,9 +62,9 @@ type Area interface {
|
|||
}
|
||||
|
||||
type areabase struct {
|
||||
width int
|
||||
height int
|
||||
handler AreaHandler
|
||||
width int
|
||||
height int
|
||||
handler AreaHandler
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
return newArea(&areabase{
|
||||
width: width,
|
||||
height: height,
|
||||
handler: handler,
|
||||
width: width,
|
||||
height: height,
|
||||
handler: handler,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ func toARGB(i *image.RGBA, memory uintptr, memstride int, toNRGBA bool) {
|
|||
p := pixelDataPos(i)
|
||||
q := 0
|
||||
iPix := i.Pix
|
||||
if toNRGBA { // for Windows image lists
|
||||
if toNRGBA { // for Windows image lists
|
||||
j := image.NewNRGBA(i.Rect)
|
||||
draw.Draw(j, j.Rect, i, i.Rect.Min, draw.Src)
|
||||
iPix = j.Pix
|
||||
|
|
|
@ -15,19 +15,19 @@ import "C"
|
|||
type area struct {
|
||||
*areabase
|
||||
|
||||
_id C.id
|
||||
scroller *scroller
|
||||
textfield C.id
|
||||
textfielddone *event
|
||||
_id C.id
|
||||
scroller *scroller
|
||||
textfield C.id
|
||||
textfielddone *event
|
||||
}
|
||||
|
||||
func newArea(ab *areabase) Area {
|
||||
a := &area{
|
||||
areabase: ab,
|
||||
textfielddone: newEvent(),
|
||||
areabase: ab,
|
||||
textfielddone: newEvent(),
|
||||
}
|
||||
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.textfield = C.newTextField()
|
||||
C.areaSetTextField(a._id, a.textfield)
|
||||
|
|
66
area_unix.go
66
area_unix.go
|
@ -34,18 +34,18 @@ import "C"
|
|||
type area struct {
|
||||
*areabase
|
||||
|
||||
_widget *C.GtkWidget
|
||||
drawingarea *C.GtkDrawingArea
|
||||
scroller *scroller
|
||||
_widget *C.GtkWidget
|
||||
drawingarea *C.GtkDrawingArea
|
||||
scroller *scroller
|
||||
|
||||
clickCounter *clickCounter
|
||||
clickCounter *clickCounter
|
||||
|
||||
textfieldw *C.GtkWidget
|
||||
textfield *C.GtkEntry
|
||||
textfieldx int
|
||||
textfieldy int
|
||||
textfielddone *event
|
||||
inmenu bool
|
||||
textfieldw *C.GtkWidget
|
||||
textfield *C.GtkEntry
|
||||
textfieldx int
|
||||
textfieldy int
|
||||
textfielddone *event
|
||||
inmenu bool
|
||||
}
|
||||
|
||||
func newArea(ab *areabase) Area {
|
||||
|
@ -58,14 +58,14 @@ func newArea(ab *areabase) Area {
|
|||
C.gtk_widget_set_can_focus(widget, C.TRUE)
|
||||
textfieldw := C.gtk_entry_new()
|
||||
a := &area{
|
||||
areabase: ab,
|
||||
_widget: widget,
|
||||
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
||||
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
||||
clickCounter: new(clickCounter),
|
||||
textfieldw: textfieldw,
|
||||
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
|
||||
textfielddone: newEvent(),
|
||||
areabase: ab,
|
||||
_widget: widget,
|
||||
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
||||
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
||||
clickCounter: new(clickCounter),
|
||||
textfieldw: textfieldw,
|
||||
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
|
||||
textfielddone: newEvent(),
|
||||
}
|
||||
for _, c := range areaCallbacks {
|
||||
g_signal_connect(
|
||||
|
@ -124,7 +124,7 @@ func (a *area) OpenTextFieldAt(x, y int) {
|
|||
}
|
||||
a.textfieldx = x
|
||||
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
|
||||
C.gtk_widget_set_no_show_all(a.textfieldw, C.FALSE)
|
||||
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)
|
||||
a.textfielddone.fire()
|
||||
}
|
||||
a.inmenu = false // for next time
|
||||
a.inmenu = false // for next time
|
||||
return continueEventChain
|
||||
}
|
||||
|
||||
var area_textfield_focus_out_event_callback = C.GCallback(C.our_area_textfield_focus_out_event_callback)
|
||||
|
||||
var areaCallbacks = []struct {
|
||||
name string
|
||||
callback C.GCallback
|
||||
name string
|
||||
callback C.GCallback
|
||||
}{
|
||||
{ "draw", area_draw_callback },
|
||||
{ "button-press-event", area_button_press_event_callback },
|
||||
{ "button-release-event", area_button_release_event_callback },
|
||||
{ "motion-notify-event", area_motion_notify_event_callback },
|
||||
{ "enter-notify-event", area_enterleave_notify_event_callback },
|
||||
{ "leave-notify-event", area_enterleave_notify_event_callback },
|
||||
{ "key-press-event", area_key_press_event_callback },
|
||||
{ "key-release-event", area_key_release_event_callback },
|
||||
{"draw", area_draw_callback},
|
||||
{"button-press-event", area_button_press_event_callback},
|
||||
{"button-release-event", area_button_release_event_callback},
|
||||
{"motion-notify-event", area_motion_notify_event_callback},
|
||||
{"enter-notify-event", area_enterleave_notify_event_callback},
|
||||
{"leave-notify-event", area_enterleave_notify_event_callback},
|
||||
{"key-press-event", area_key_press_event_callback},
|
||||
{"key-release-event", area_key_release_event_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+)
|
||||
C.cairo_surface_flush(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_set_source_surface(cr,
|
||||
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
|
||||
// (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
|
||||
|
@ -252,7 +252,7 @@ func makeModifiers(state C.guint) (m Modifiers) {
|
|||
if (state & C.GDK_META_MASK) != 0 {
|
||||
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
|
||||
}
|
||||
if (state & C.GDK_SHIFT_MASK) != 0 {
|
||||
|
|
|
@ -15,12 +15,12 @@ import "C"
|
|||
type area struct {
|
||||
*areabase
|
||||
|
||||
_hwnd C.HWND
|
||||
_hwnd C.HWND
|
||||
|
||||
clickCounter *clickCounter
|
||||
clickCounter *clickCounter
|
||||
|
||||
textfield C.HWND
|
||||
textfielddone *event
|
||||
textfield C.HWND
|
||||
textfielddone *event
|
||||
}
|
||||
|
||||
func makeAreaWindowClass() error {
|
||||
|
@ -35,9 +35,9 @@ func makeAreaWindowClass() error {
|
|||
|
||||
func newArea(ab *areabase) Area {
|
||||
a := &area{
|
||||
areabase: ab,
|
||||
clickCounter: new(clickCounter),
|
||||
textfielddone: newEvent(),
|
||||
areabase: ab,
|
||||
clickCounter: new(clickCounter),
|
||||
textfielddone: newEvent(),
|
||||
}
|
||||
a._hwnd = C.newArea(unsafe.Pointer(a))
|
||||
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))
|
||||
t := toNRGBA != C.FALSE
|
||||
// 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
|
||||
|
@ -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)
|
||||
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)
|
||||
}
|
||||
if button != 2 && (heldButtons & C.MK_MBUTTON) != 0 {
|
||||
if button != 2 && (heldButtons&C.MK_MBUTTON) != 0 {
|
||||
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)
|
||||
}
|
||||
if button != 4 && (heldButtons & C.MK_XBUTTON1) != 0 {
|
||||
if button != 4 && (heldButtons&C.MK_XBUTTON1) != 0 {
|
||||
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)
|
||||
}
|
||||
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
|
||||
|
||||
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 enter, however, is a right-hand key because it has the same virtual-key code as the typewriter enter
|
||||
righthand := (lp & 0x01000000) != 0
|
||||
|
|
|
@ -10,16 +10,16 @@ import (
|
|||
import "C"
|
||||
|
||||
type button struct {
|
||||
_id C.id
|
||||
clicked *event
|
||||
_id C.id
|
||||
clicked *event
|
||||
}
|
||||
|
||||
func newButton(text string) *button {
|
||||
ctext := C.CString(text)
|
||||
defer C.free(unsafe.Pointer(ctext))
|
||||
b := &button{
|
||||
_id: C.newButton(),
|
||||
clicked: newEvent(),
|
||||
_id: C.newButton(),
|
||||
clicked: newEvent(),
|
||||
}
|
||||
C.buttonSetText(b._id, ctext)
|
||||
C.buttonSetDelegate(b._id, unsafe.Pointer(b))
|
||||
|
|
|
@ -13,9 +13,9 @@ import (
|
|||
import "C"
|
||||
|
||||
type button struct {
|
||||
_widget *C.GtkWidget
|
||||
button *C.GtkButton
|
||||
clicked *event
|
||||
_widget *C.GtkWidget
|
||||
button *C.GtkButton
|
||||
clicked *event
|
||||
}
|
||||
|
||||
// shared code for setting up buttons, check boxes, etc.
|
||||
|
@ -24,9 +24,9 @@ func newButton(text string) *button {
|
|||
defer freegstr(ctext)
|
||||
widget := C.gtk_button_new_with_label(ctext)
|
||||
b := &button{
|
||||
_widget: widget,
|
||||
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||
clicked: newEvent(),
|
||||
_widget: widget,
|
||||
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||
clicked: newEvent(),
|
||||
}
|
||||
g_signal_connect(
|
||||
C.gpointer(unsafe.Pointer(b.button)),
|
||||
|
|
|
@ -10,20 +10,20 @@ import (
|
|||
import "C"
|
||||
|
||||
type button struct {
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
clicked *event
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
clicked *event
|
||||
}
|
||||
|
||||
var buttonclass = toUTF16("BUTTON")
|
||||
|
||||
func newButton(text string) *button {
|
||||
hwnd := C.newControl(buttonclass,
|
||||
C.BS_PUSHBUTTON | C.WS_TABSTOP,
|
||||
C.BS_PUSHBUTTON|C.WS_TABSTOP,
|
||||
0)
|
||||
b := &button{
|
||||
_hwnd: hwnd,
|
||||
clicked: newEvent(),
|
||||
_hwnd: hwnd,
|
||||
clicked: newEvent(),
|
||||
}
|
||||
b.SetText(text)
|
||||
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...
|
||||
var size C.SIZE
|
||||
|
||||
size.cx = 0 // explicitly ask for ideal size
|
||||
size.cx = 0 // explicitly ask for ideal size
|
||||
size.cy = 0
|
||||
if C.SendMessageW(b._hwnd, C.BCM_GETIDEALSIZE, 0, C.LPARAM(uintptr(unsafe.Pointer(&size)))) != C.FALSE {
|
||||
return int(size.cx), int(size.cy)
|
||||
}
|
||||
// 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)
|
||||
xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE))
|
||||
return xmargins + int(b._textlen), fromdlgunitsY(buttonHeight, d)
|
||||
|
|
|
@ -10,16 +10,16 @@ import (
|
|||
import "C"
|
||||
|
||||
type checkbox struct {
|
||||
_id C.id
|
||||
toggled *event
|
||||
_id C.id
|
||||
toggled *event
|
||||
}
|
||||
|
||||
func newCheckbox(text string) *checkbox {
|
||||
ctext := C.CString(text)
|
||||
defer C.free(unsafe.Pointer(ctext))
|
||||
c := &checkbox{
|
||||
_id: C.newCheckbox(),
|
||||
toggled: newEvent(),
|
||||
_id: C.newCheckbox(),
|
||||
toggled: newEvent(),
|
||||
}
|
||||
C.buttonSetText(c._id, ctext)
|
||||
C.checkboxSetDelegate(c._id, unsafe.Pointer(c))
|
||||
|
|
|
@ -13,11 +13,11 @@ import (
|
|||
import "C"
|
||||
|
||||
type checkbox struct {
|
||||
_widget *C.GtkWidget
|
||||
button *C.GtkButton
|
||||
toggle *C.GtkToggleButton
|
||||
checkbox *C.GtkCheckButton
|
||||
toggled *event
|
||||
_widget *C.GtkWidget
|
||||
button *C.GtkButton
|
||||
toggle *C.GtkToggleButton
|
||||
checkbox *C.GtkCheckButton
|
||||
toggled *event
|
||||
}
|
||||
|
||||
func newCheckbox(text string) *checkbox {
|
||||
|
@ -25,11 +25,11 @@ func newCheckbox(text string) *checkbox {
|
|||
defer freegstr(ctext)
|
||||
widget := C.gtk_check_button_new_with_label(ctext)
|
||||
c := &checkbox{
|
||||
_widget: widget,
|
||||
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||
toggle: (*C.GtkToggleButton)(unsafe.Pointer(widget)),
|
||||
checkbox: (*C.GtkCheckButton)(unsafe.Pointer(widget)),
|
||||
toggled: newEvent(),
|
||||
_widget: widget,
|
||||
button: (*C.GtkButton)(unsafe.Pointer(widget)),
|
||||
toggle: (*C.GtkToggleButton)(unsafe.Pointer(widget)),
|
||||
checkbox: (*C.GtkCheckButton)(unsafe.Pointer(widget)),
|
||||
toggled: newEvent(),
|
||||
}
|
||||
g_signal_connect(
|
||||
C.gpointer(unsafe.Pointer(c.checkbox)),
|
||||
|
|
|
@ -10,20 +10,20 @@ import (
|
|||
import "C"
|
||||
|
||||
type checkbox struct {
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
toggled *event
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
toggled *event
|
||||
}
|
||||
|
||||
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)
|
||||
// we'll handle actually toggling the check state ourselves (see controls_windows.c)
|
||||
hwnd := C.newControl(buttonclass,
|
||||
C.BS_CHECKBOX | C.WS_TABSTOP,
|
||||
C.BS_CHECKBOX|C.WS_TABSTOP,
|
||||
0)
|
||||
c := &checkbox{
|
||||
_hwnd: hwnd,
|
||||
toggled: newEvent(),
|
||||
_hwnd: hwnd,
|
||||
toggled: newEvent(),
|
||||
}
|
||||
c.SetText(text)
|
||||
C.controlSetControlFont(c._hwnd)
|
||||
|
|
|
@ -4,9 +4,9 @@ package ui
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// #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
|
||||
// but WM_GETTEXT expects the buffer size handed to it to /include/ the terminating null character
|
||||
n := C.getWindowTextLen(hwnd)
|
||||
buf := make([]uint16, int(n + 1))
|
||||
buf := make([]uint16, int(n+1))
|
||||
C.getWindowText(hwnd, C.WPARAM(n),
|
||||
C.LPWSTR(unsafe.Pointer(&buf[0])))
|
||||
return syscall.UTF16ToString(buf)
|
||||
|
@ -49,9 +49,9 @@ func getWindowText(hwnd C.HWND) string {
|
|||
func wstrToString(wstr *C.WCHAR) string {
|
||||
n := C.wcslen((*C.wchar_t)(unsafe.Pointer(wstr)))
|
||||
xbuf := &reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(wstr)),
|
||||
Len: int(n + 1),
|
||||
Cap: int(n + 1),
|
||||
Data: uintptr(unsafe.Pointer(wstr)),
|
||||
Len: int(n + 1),
|
||||
Cap: int(n + 1),
|
||||
}
|
||||
buf := (*[]uint16)(unsafe.Pointer(xbuf))
|
||||
return syscall.UTF16ToString(*buf)
|
||||
|
|
30
container.go
30
container.go
|
@ -3,20 +3,20 @@
|
|||
package ui
|
||||
|
||||
type allocation struct {
|
||||
x int
|
||||
y int
|
||||
width int
|
||||
height int
|
||||
this Control
|
||||
neighbor Control
|
||||
x int
|
||||
y int
|
||||
width int
|
||||
height int
|
||||
this Control
|
||||
neighbor Control
|
||||
}
|
||||
|
||||
type sizingbase struct {
|
||||
xmargin int
|
||||
ymargintop int
|
||||
ymarginbottom int
|
||||
xpadding int
|
||||
ypadding int
|
||||
xmargin int
|
||||
ymargintop int
|
||||
ymarginbottom int
|
||||
xpadding int
|
||||
ypadding int
|
||||
}
|
||||
|
||||
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.
|
||||
// All containers must embed containerbase.
|
||||
type containerbase struct {
|
||||
child Control
|
||||
child Control
|
||||
}
|
||||
|
||||
// set to true to apply spacing to all windows
|
||||
var spaced bool = false
|
||||
|
||||
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
|
||||
}
|
||||
d := c.beginResize()
|
||||
allocations := c.child.allocate(x + d.xmargin, y + d.ymargintop,
|
||||
width - (2 * d.xmargin), height - d.ymargintop - d.ymarginbottom, d)
|
||||
allocations := c.child.allocate(x+d.xmargin, y+d.ymargintop,
|
||||
width-(2*d.xmargin), height-d.ymargintop-d.ymarginbottom, d)
|
||||
c.translateAllocationCoords(allocations, width, height)
|
||||
// move in reverse so as to approximate right->left order so neighbors make sense
|
||||
for i := len(allocations) - 1; i >= 0; i-- {
|
||||
|
|
|
@ -11,7 +11,7 @@ import "C"
|
|||
|
||||
type container struct {
|
||||
containerbase
|
||||
id C.id
|
||||
id C.id
|
||||
}
|
||||
|
||||
type sizing struct {
|
||||
|
@ -21,7 +21,7 @@ type sizing struct {
|
|||
// nothing for mac
|
||||
|
||||
// for the actual resizing
|
||||
neighborAlign C.struct_xalignment
|
||||
neighborAlign C.struct_xalignment
|
||||
}
|
||||
|
||||
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.
|
||||
const (
|
||||
macXMargin = 20
|
||||
macYMargin = 20
|
||||
macXMargin = 20
|
||||
macYMargin = 20
|
||||
macXPadding = 8
|
||||
macYPadding = 8
|
||||
)
|
||||
|
|
|
@ -13,8 +13,8 @@ import "C"
|
|||
|
||||
type container struct {
|
||||
containerbase
|
||||
layoutwidget *C.GtkWidget
|
||||
layoutcontainer *C.GtkContainer
|
||||
layoutwidget *C.GtkWidget
|
||||
layoutcontainer *C.GtkContainer
|
||||
}
|
||||
|
||||
type sizing struct {
|
||||
|
@ -24,7 +24,7 @@ type sizing struct {
|
|||
// gtk+ needs nothing
|
||||
|
||||
// for the actual resizing
|
||||
shouldVAlignTop bool
|
||||
shouldVAlignTop bool
|
||||
}
|
||||
|
||||
func newContainer(child Control) *container {
|
||||
|
@ -48,8 +48,8 @@ func containerResizing(data unsafe.Pointer, r *C.GtkAllocation) {
|
|||
}
|
||||
|
||||
const (
|
||||
gtkXMargin = 12
|
||||
gtkYMargin = 12
|
||||
gtkXMargin = 12
|
||||
gtkYMargin = 12
|
||||
gtkXPadding = 12
|
||||
gtkYPadding = 6
|
||||
)
|
||||
|
|
|
@ -13,18 +13,18 @@ import "C"
|
|||
|
||||
type container struct {
|
||||
containerbase
|
||||
hwnd C.HWND
|
||||
nchildren int
|
||||
isGroup bool
|
||||
hwnd C.HWND
|
||||
nchildren int
|
||||
isGroup bool
|
||||
}
|
||||
|
||||
type sizing struct {
|
||||
sizingbase
|
||||
|
||||
// for size calculations
|
||||
baseX C.int
|
||||
baseY C.int
|
||||
internalLeading C.LONG // for Label; see Label.commitResize() for details
|
||||
baseX C.int
|
||||
baseY C.int
|
||||
internalLeading C.LONG // for Label; see Label.commitResize() for details
|
||||
|
||||
// for the actual resizing
|
||||
// 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
|
||||
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() {
|
||||
|
@ -78,7 +78,7 @@ func storeContainerHWND(data unsafe.Pointer, hwnd C.HWND) {
|
|||
func containerResize(data unsafe.Pointer, r *C.RECT) {
|
||||
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
|
||||
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.
|
||||
|
@ -103,11 +103,11 @@ func fromdlgunitsY(du int, d *sizing) int {
|
|||
}
|
||||
|
||||
const (
|
||||
marginDialogUnits = 7
|
||||
marginDialogUnits = 7
|
||||
paddingDialogUnits = 4
|
||||
|
||||
groupXMargin = 6
|
||||
groupYMarginTop = 11 // note this value /includes the groupbox label/
|
||||
groupXMargin = 6
|
||||
groupYMarginTop = 11 // note this value /includes the groupbox label/
|
||||
groupYMarginBottom = 7
|
||||
)
|
||||
|
||||
|
|
12
control.go
12
control.go
|
@ -4,17 +4,17 @@ package ui
|
|||
|
||||
// Control represents a control.
|
||||
type Control interface {
|
||||
setParent(p *controlParent) // controlParent defined per-platform
|
||||
setParent(p *controlParent) // controlParent defined per-platform
|
||||
controlSizing
|
||||
}
|
||||
|
||||
// this is the same across all platforms
|
||||
func baseallocate(c Control, x int, y int, width int, height int, d *sizing) []*allocation {
|
||||
return []*allocation{&allocation{
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
this: c,
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
this: c,
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ type controlPrivate interface {
|
|||
}
|
||||
|
||||
type controlParent struct {
|
||||
id C.id
|
||||
id C.id
|
||||
}
|
||||
|
||||
func basesetParent(c controlPrivate, p *controlParent) {
|
||||
|
@ -38,13 +38,13 @@ func basegetAuxResizeInfo(c controlPrivate, d *sizing) {
|
|||
}
|
||||
|
||||
type scroller struct {
|
||||
id C.id
|
||||
id C.id
|
||||
}
|
||||
|
||||
func newScroller(child C.id, bordered bool) *scroller {
|
||||
id := C.newScrollView(child, toBOOL(bordered))
|
||||
s := &scroller{
|
||||
id: id,
|
||||
id: id,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ type controlPrivate interface {
|
|||
}
|
||||
|
||||
type controlParent struct {
|
||||
c *C.GtkContainer
|
||||
c *C.GtkContainer
|
||||
}
|
||||
|
||||
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)
|
||||
// make sure the new widget is shown if not explicitly hidden
|
||||
C.gtk_widget_show_all(widget)
|
||||
|
@ -66,15 +66,15 @@ func basegetAuxResizeInfo(c Control, d *sizing) {
|
|||
}
|
||||
|
||||
type scroller struct {
|
||||
scrollwidget *C.GtkWidget
|
||||
scrollcontainer *C.GtkContainer
|
||||
scrollwindow *C.GtkScrolledWindow
|
||||
scrollwidget *C.GtkWidget
|
||||
scrollcontainer *C.GtkContainer
|
||||
scrollwindow *C.GtkScrolledWindow
|
||||
|
||||
overlaywidget *C.GtkWidget
|
||||
overlaycontainer *C.GtkContainer
|
||||
overlay *C.GtkOverlay
|
||||
overlaywidget *C.GtkWidget
|
||||
overlaycontainer *C.GtkContainer
|
||||
overlay *C.GtkOverlay
|
||||
|
||||
addShowWhich *C.GtkWidget
|
||||
addShowWhich *C.GtkWidget
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
s := &scroller{
|
||||
scrollwidget: scrollwidget,
|
||||
scrollcontainer: (*C.GtkContainer)(unsafe.Pointer(scrollwidget)),
|
||||
scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scrollwidget)),
|
||||
overlaywidget: o,
|
||||
overlaycontainer: (*C.GtkContainer)(unsafe.Pointer(o)),
|
||||
overlay: (*C.GtkOverlay)(unsafe.Pointer(o)),
|
||||
scrollwidget: scrollwidget,
|
||||
scrollcontainer: (*C.GtkContainer)(unsafe.Pointer(scrollwidget)),
|
||||
scrollwindow: (*C.GtkScrolledWindow)(unsafe.Pointer(scrollwidget)),
|
||||
overlaywidget: o,
|
||||
overlaycontainer: (*C.GtkContainer)(unsafe.Pointer(o)),
|
||||
overlay: (*C.GtkOverlay)(unsafe.Pointer(o)),
|
||||
}
|
||||
// give the scrolled window a border (thanks to jlindgren in irc.gimp.net/#gtk+)
|
||||
if bordered {
|
||||
|
|
|
@ -11,7 +11,7 @@ type controlPrivate interface {
|
|||
}
|
||||
|
||||
type controlParent struct {
|
||||
c *container
|
||||
c *container
|
||||
}
|
||||
|
||||
func basesetParent(c controlPrivate, p *controlParent) {
|
||||
|
|
|
@ -25,7 +25,7 @@ import "C"
|
|||
func (w *window) openFile(f func(filename string)) {
|
||||
widget := C.newOpenFileDialog(w.window)
|
||||
window := (*C.GtkWindow)(unsafe.Pointer(widget))
|
||||
dialog := (*C.GtkDialog)(unsafe.Pointer(widget))
|
||||
dialog := (*C.GtkDialog)(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
|
||||
C.gtk_file_chooser_set_local_only(fc, C.TRUE)
|
||||
|
|
104
grid.go
104
grid.go
|
@ -9,7 +9,7 @@ import (
|
|||
// Grid is a Control that arranges other Controls in a grid.
|
||||
// Grid is a very powerful container: it can position and size each Control in several ways and can (and must) have Controls added to it at any time, in any direction.
|
||||
// it can also have Controls spanning multiple rows and columns.
|
||||
//
|
||||
//
|
||||
// Each Control in a Grid has associated "expansion" and "alignment" values in both the X and Y direction.
|
||||
// Expansion determines whether all cells in the same row/column are given whatever space is left over after figuring out how big the rest of the Grid should be.
|
||||
// Alignment determines the position of a Control relative to its cell after computing the above.
|
||||
|
@ -31,6 +31,7 @@ type Grid interface {
|
|||
|
||||
// Align represents the alignment of a Control in its cell of a Grid.
|
||||
type Align uint
|
||||
|
||||
const (
|
||||
LeftTop Align = iota
|
||||
Center
|
||||
|
@ -40,6 +41,7 @@ const (
|
|||
|
||||
// Side represents a side of a Control to add other Controls to a Grid to.
|
||||
type Side uint
|
||||
|
||||
const (
|
||||
West Side = iota
|
||||
East
|
||||
|
@ -49,39 +51,39 @@ const (
|
|||
)
|
||||
|
||||
type grid struct {
|
||||
controls []gridCell
|
||||
indexof map[Control]int
|
||||
prev int
|
||||
parent *controlParent
|
||||
controls []gridCell
|
||||
indexof map[Control]int
|
||||
prev int
|
||||
parent *controlParent
|
||||
|
||||
xmax int
|
||||
ymax int
|
||||
xmax int
|
||||
ymax int
|
||||
}
|
||||
|
||||
type gridCell struct {
|
||||
control Control
|
||||
xexpand bool
|
||||
xalign Align
|
||||
yexpand bool
|
||||
yalign Align
|
||||
xspan int
|
||||
yspan int
|
||||
control Control
|
||||
xexpand bool
|
||||
xalign Align
|
||||
yexpand bool
|
||||
yalign Align
|
||||
xspan int
|
||||
yspan int
|
||||
|
||||
x int
|
||||
y int
|
||||
x int
|
||||
y int
|
||||
|
||||
finalx int
|
||||
finaly int
|
||||
finalwidth int
|
||||
finalheight int
|
||||
prefwidth int
|
||||
prefheight int
|
||||
finalx int
|
||||
finaly int
|
||||
finalwidth int
|
||||
finalheight int
|
||||
prefwidth int
|
||||
prefheight int
|
||||
}
|
||||
|
||||
// NewGrid creates a new Grid with no Controls.
|
||||
func NewGrid() Grid {
|
||||
return &grid{
|
||||
indexof: map[Control]int{},
|
||||
indexof: map[Control]int{},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,10 +107,10 @@ func (g *grid) reorigin() {
|
|||
for i := range g.controls {
|
||||
g.controls[i].x += xmin
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
cell := gridCell{
|
||||
control: control,
|
||||
xexpand: xexpand,
|
||||
xalign: xalign,
|
||||
yexpand: yexpand,
|
||||
yalign: yalign,
|
||||
xspan: xspan,
|
||||
yspan: yspan,
|
||||
control: control,
|
||||
xexpand: xexpand,
|
||||
xalign: xalign,
|
||||
yexpand: yexpand,
|
||||
yalign: yalign,
|
||||
xspan: xspan,
|
||||
yspan: yspan,
|
||||
}
|
||||
if g.parent != nil {
|
||||
control.setParent(g.parent)
|
||||
|
@ -176,8 +178,8 @@ func (g *grid) mkgrid() (gg [][]int, colwidths []int, rowheights []int) {
|
|||
}
|
||||
}
|
||||
for i := range g.controls {
|
||||
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 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++ {
|
||||
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 {
|
||||
if g.controls[i].xexpand && g.controls[i].xspan != 1 {
|
||||
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] {
|
||||
do = false
|
||||
break
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
if g.controls[i].yexpand && g.controls[i].yspan != 1 {
|
||||
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] {
|
||||
do = false
|
||||
break
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +313,7 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
|
|||
prev := -1
|
||||
for x := 0; x < g.xmax; 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 {
|
||||
g.controls[i].finalx = curx
|
||||
} else {
|
||||
|
@ -328,7 +330,7 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
|
|||
prev := -1
|
||||
for y := 0; y < g.ymax; y++ {
|
||||
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 {
|
||||
g.controls[i].finaly = cury
|
||||
} else {
|
||||
|
@ -351,7 +353,7 @@ func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocat
|
|||
case Center:
|
||||
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 {
|
||||
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:
|
||||
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 {
|
||||
current = nil
|
||||
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].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)
|
||||
if current != nil { // connect first left to first right
|
||||
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
|
||||
current = as[0] // next left is first subwidget
|
||||
} else {
|
||||
current = nil // spaces don't have allocation data
|
||||
current = nil // spaces don't have allocation data
|
||||
}
|
||||
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)
|
||||
// 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
|
||||
}
|
||||
if rowheights[y] < h / g.controls[i].yspan {
|
||||
if rowheights[y] < h/g.controls[i].yspan {
|
||||
rowheights[y] = h / g.controls[i].yspan
|
||||
}
|
||||
// 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
|
||||
return colwidth + (g.xmax - 1) * d.xpadding,
|
||||
rowheight + (g.ymax - 1) * d.ypadding
|
||||
return colwidth + (g.xmax-1)*d.xpadding,
|
||||
rowheight + (g.ymax-1)*d.ypadding
|
||||
}
|
||||
|
||||
func (g *grid) commitResize(a *allocation, d *sizing) {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
import "C"
|
||||
|
||||
type group struct {
|
||||
_id C.id
|
||||
_id C.id
|
||||
|
||||
*container
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
import "C"
|
||||
|
||||
type group struct {
|
||||
_widget *C.GtkWidget
|
||||
gcontainer *C.GtkContainer
|
||||
frame *C.GtkFrame
|
||||
_widget *C.GtkWidget
|
||||
gcontainer *C.GtkContainer
|
||||
frame *C.GtkFrame
|
||||
|
||||
*container
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ func newGroup(text string, control Control) Group {
|
|||
defer freegstr(ctext)
|
||||
widget := C.gtk_frame_new(ctext)
|
||||
g := &group{
|
||||
_widget: widget,
|
||||
gcontainer: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
||||
frame: (*C.GtkFrame)(unsafe.Pointer(widget)),
|
||||
_widget: widget,
|
||||
gcontainer: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
||||
frame: (*C.GtkFrame)(unsafe.Pointer(widget)),
|
||||
}
|
||||
|
||||
// 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()
|
||||
C.pango_attr_list_insert(boldlist, bold)
|
||||
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.setParent(&controlParent{g.gcontainer})
|
||||
|
|
|
@ -6,8 +6,8 @@ package ui
|
|||
import "C"
|
||||
|
||||
type group struct {
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
|
||||
*container
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ func newGroup(text string, control Control) Group {
|
|||
C.BS_GROUPBOX,
|
||||
C.WS_EX_CONTROLPARENT)
|
||||
g := &group{
|
||||
_hwnd: hwnd,
|
||||
container: newContainer(control),
|
||||
_hwnd: hwnd,
|
||||
container: newContainer(control),
|
||||
}
|
||||
g.SetText(text)
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
// the two margin constants come from container_windows.go
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
import "C"
|
||||
|
||||
type imagelist struct {
|
||||
list []C.id
|
||||
list []C.id
|
||||
}
|
||||
|
||||
func newImageList() ImageList {
|
||||
|
|
|
@ -6,15 +6,15 @@ package ui
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// #include "gtk_unix.h"
|
||||
import "C"
|
||||
|
||||
type imagelist struct {
|
||||
list []*C.GdkPixbuf
|
||||
list []*C.GdkPixbuf
|
||||
}
|
||||
|
||||
func newImageList() ImageList {
|
||||
|
@ -37,7 +37,7 @@ func (i *imagelist) Append(img *image.RGBA) {
|
|||
}
|
||||
C.cairo_surface_flush(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)
|
||||
basepixbuf := C.gdk_pixbuf_get_from_surface(surface, 0, 0, C.gint(img.Rect.Dx()), C.gint(img.Rect.Dy()))
|
||||
if basepixbuf == nil {
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
import "C"
|
||||
|
||||
type imagelist struct {
|
||||
list []C.HBITMAP
|
||||
width []int
|
||||
height []int
|
||||
list []C.HBITMAP
|
||||
width []int
|
||||
height []int
|
||||
}
|
||||
|
||||
func newImageList() ImageList {
|
||||
|
|
|
@ -10,14 +10,14 @@ import (
|
|||
import "C"
|
||||
|
||||
type label struct {
|
||||
_id C.id
|
||||
standalone bool
|
||||
_id C.id
|
||||
standalone bool
|
||||
}
|
||||
|
||||
func finishNewLabel(text string, standalone bool) *label {
|
||||
l := &label{
|
||||
_id: C.newLabel(),
|
||||
standalone: standalone,
|
||||
_id: C.newLabel(),
|
||||
standalone: standalone,
|
||||
}
|
||||
l.SetText(text)
|
||||
return l
|
||||
|
@ -64,16 +64,16 @@ func (l *label) preferredSize(d *sizing) (width, height int) {
|
|||
func (l *label) commitResize(c *allocation, d *sizing) {
|
||||
if !l.standalone && c.neighbor != nil {
|
||||
c.neighbor.getAuxResizeInfo(d)
|
||||
if d.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline
|
||||
if d.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline
|
||||
// in order for the baseline value to be correct, the label MUST BE AT THE HEIGHT THAT OS X WANTS IT TO BE!
|
||||
// otherwise, the baseline calculation will be relative to the bottom of the control, and everything will be wrong
|
||||
origsize := C.controlPreferredSize(l._id)
|
||||
c.height = int(origsize.height)
|
||||
newrect := C.struct_xrect{
|
||||
x: C.intptr_t(c.x),
|
||||
y: C.intptr_t(c.y),
|
||||
width: C.intptr_t(c.width),
|
||||
height: C.intptr_t(c.height),
|
||||
x: C.intptr_t(c.x),
|
||||
y: C.intptr_t(c.y),
|
||||
width: C.intptr_t(c.width),
|
||||
height: C.intptr_t(c.height),
|
||||
}
|
||||
ourAlign := C.alignmentInfo(l._id, newrect)
|
||||
// we need to find the exact Y positions of the baselines
|
||||
|
|
|
@ -14,10 +14,10 @@ import (
|
|||
import "C"
|
||||
|
||||
type label struct {
|
||||
_widget *C.GtkWidget
|
||||
misc *C.GtkMisc
|
||||
label *C.GtkLabel
|
||||
standalone bool
|
||||
_widget *C.GtkWidget
|
||||
misc *C.GtkMisc
|
||||
label *C.GtkLabel
|
||||
standalone bool
|
||||
}
|
||||
|
||||
func finishNewLabel(text string, standalone bool) *label {
|
||||
|
@ -25,10 +25,10 @@ func finishNewLabel(text string, standalone bool) *label {
|
|||
defer freegstr(ctext)
|
||||
widget := C.gtk_label_new(ctext)
|
||||
l := &label{
|
||||
_widget: widget,
|
||||
misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
|
||||
label: (*C.GtkLabel)(unsafe.Pointer(widget)),
|
||||
standalone: standalone,
|
||||
_widget: widget,
|
||||
misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
|
||||
label: (*C.GtkLabel)(unsafe.Pointer(widget)),
|
||||
standalone: standalone,
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ package ui
|
|||
import "C"
|
||||
|
||||
type label struct {
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
standalone bool
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
standalone bool
|
||||
}
|
||||
|
||||
var labelclass = toUTF16("STATIC")
|
||||
|
@ -17,11 +17,11 @@ func finishNewLabel(text string, standalone bool) *label {
|
|||
hwnd := C.newControl(labelclass,
|
||||
// SS_NOPREFIX avoids accelerator translation; SS_LEFTNOWORDWRAP clips text past the end
|
||||
// controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi)
|
||||
C.SS_NOPREFIX | C.SS_LEFTNOWORDWRAP,
|
||||
C.SS_NOPREFIX|C.SS_LEFTNOWORDWRAP,
|
||||
C.WS_EX_TRANSPARENT)
|
||||
l := &label{
|
||||
_hwnd: hwnd,
|
||||
standalone: standalone,
|
||||
_hwnd: hwnd,
|
||||
standalone: standalone,
|
||||
}
|
||||
l.SetText(text)
|
||||
C.controlSetControlFont(l._hwnd)
|
||||
|
@ -71,7 +71,7 @@ func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allo
|
|||
|
||||
const (
|
||||
// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
||||
labelHeight = 8
|
||||
labelHeight = 8
|
||||
labelYOffset = 3
|
||||
)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ 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).
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// As a special rule, to ensure proper appearance, non-standalone Labels are automatically made filling.
|
||||
type SimpleGrid interface {
|
||||
Control
|
||||
|
@ -34,7 +34,7 @@ type simpleGrid struct {
|
|||
controls [][]Control
|
||||
filling [][]bool
|
||||
stretchyrow, stretchycol int
|
||||
stretchyfill bool
|
||||
stretchyfill bool
|
||||
widths, heights [][]int // caches to avoid reallocating each time
|
||||
rowheights, colwidths []int
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ func (g *simpleGrid) SetStretchy(row int, column int) {
|
|||
}
|
||||
g.stretchyrow = row
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (a
|
|||
return b
|
||||
}
|
||||
|
||||
var current *allocation // for neighboring
|
||||
var current *allocation // for neighboring
|
||||
|
||||
if len(g.controls) == 0 {
|
||||
return nil
|
||||
|
@ -161,7 +161,7 @@ func (g *simpleGrid) allocate(x int, y int, width int, height int, d *sizing) (a
|
|||
// 4) draw
|
||||
startx := x
|
||||
for row, xcol := range g.controls {
|
||||
current = nil // reset on new columns
|
||||
current = nil // reset on new columns
|
||||
for col, c := range xcol {
|
||||
w := g.widths[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]
|
||||
}
|
||||
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
|
||||
}
|
||||
if len(as) != 0 {
|
||||
current = as[0] // next left is first subwidget
|
||||
current = as[0] // next left is first subwidget
|
||||
} else {
|
||||
current = nil // spaces don't have allocation data
|
||||
current = nil // spaces don't have allocation data
|
||||
}
|
||||
allocations = append(allocations, as...)
|
||||
x += g.colwidths[col] + d.xpadding
|
||||
|
|
11
stack.go
11
stack.go
|
@ -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) {
|
||||
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
|
||||
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
|
||||
for i, c := range s.controls {
|
||||
as := c.allocate(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
|
||||
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
|
||||
current = as[0] // next left is first subwidget
|
||||
} else {
|
||||
current = nil // spaces don't have allocation data
|
||||
current = nil // spaces don't have allocation data
|
||||
}
|
||||
}
|
||||
allocations = append(allocations, as...)
|
||||
|
@ -192,7 +192,6 @@ func (s *stack) getAuxResizeInfo(d *sizing) {
|
|||
// this is to satisfy Control; nothing to do here
|
||||
}
|
||||
|
||||
|
||||
// Space returns a null Control intended for padding layouts with blank space.
|
||||
// It appears to its owner as a Control of 0x0 size.
|
||||
//
|
||||
|
|
|
@ -10,13 +10,13 @@ import (
|
|||
import "C"
|
||||
|
||||
type tab struct {
|
||||
_id C.id
|
||||
tabs []*container
|
||||
_id C.id
|
||||
tabs []*container
|
||||
}
|
||||
|
||||
func newTab() Tab {
|
||||
return &tab{
|
||||
_id: C.newTab(),
|
||||
_id: C.newTab(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
16
tab_unix.go
16
tab_unix.go
|
@ -12,19 +12,19 @@ import (
|
|||
import "C"
|
||||
|
||||
type tab struct {
|
||||
_widget *C.GtkWidget
|
||||
container *C.GtkContainer
|
||||
notebook *C.GtkNotebook
|
||||
_widget *C.GtkWidget
|
||||
container *C.GtkContainer
|
||||
notebook *C.GtkNotebook
|
||||
|
||||
tabs []*container
|
||||
tabs []*container
|
||||
}
|
||||
|
||||
func newTab() Tab {
|
||||
widget := C.gtk_notebook_new()
|
||||
t := &tab{
|
||||
_widget: widget,
|
||||
container: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
||||
notebook: (*C.GtkNotebook)(unsafe.Pointer(widget)),
|
||||
_widget: widget,
|
||||
container: (*C.GtkContainer)(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
|
||||
C.gtk_notebook_set_scrollable(t.notebook, C.TRUE)
|
||||
|
@ -40,7 +40,7 @@ func (t *tab) Append(name string, control Control) {
|
|||
defer freegstr(cname)
|
||||
C.gtk_notebook_set_tab_label_text(t.notebook,
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,16 +16,16 @@ We'll create a dummy window using the pre-existing Window window class for each
|
|||
*/
|
||||
|
||||
type tab struct {
|
||||
_hwnd C.HWND
|
||||
tabs []*container
|
||||
_hwnd C.HWND
|
||||
tabs []*container
|
||||
}
|
||||
|
||||
func newTab() Tab {
|
||||
hwnd := C.newControl(C.xWC_TABCONTROL,
|
||||
C.TCS_TOOLTIPS | C.WS_TABSTOP,
|
||||
0) // don't set WS_EX_CONTROLPARENT here; see uitask_windows.c
|
||||
C.TCS_TOOLTIPS|C.WS_TABSTOP,
|
||||
0) // don't set WS_EX_CONTROLPARENT here; see uitask_windows.c
|
||||
t := &tab{
|
||||
_hwnd: hwnd,
|
||||
_hwnd: hwnd,
|
||||
}
|
||||
C.controlSetControlFont(t._hwnd)
|
||||
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)
|
||||
// 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 {
|
||||
t.tabs[len(t.tabs) - 1].hide()
|
||||
t.tabs[len(t.tabs)-1].hide()
|
||||
}
|
||||
C.tabAppend(t._hwnd, toUTF16(name))
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func tabChanged(data unsafe.Pointer, new C.LRESULT) {
|
|||
//export tabTabHasChildren
|
||||
func tabTabHasChildren(data unsafe.Pointer, which C.LRESULT) C.BOOL {
|
||||
t := (*tab)(data)
|
||||
if len(t.tabs) == 0 { // currently no tabs
|
||||
if len(t.tabs) == 0 { // currently no tabs
|
||||
return C.FALSE
|
||||
}
|
||||
if t.tabs[int(which)].nchildren > 0 {
|
||||
|
|
4
table.go
4
table.go
|
@ -52,8 +52,8 @@ type Table interface {
|
|||
}
|
||||
|
||||
type tablebase struct {
|
||||
lock sync.RWMutex
|
||||
data interface{}
|
||||
lock sync.RWMutex
|
||||
data interface{}
|
||||
}
|
||||
|
||||
// NewTable creates a new Table.
|
||||
|
|
|
@ -14,20 +14,20 @@ import "C"
|
|||
type table struct {
|
||||
*tablebase
|
||||
|
||||
_id C.id
|
||||
scroller *scroller
|
||||
_id C.id
|
||||
scroller *scroller
|
||||
|
||||
images []C.id
|
||||
selected *event
|
||||
images []C.id
|
||||
selected *event
|
||||
}
|
||||
|
||||
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||
id := C.newTable()
|
||||
t := &table{
|
||||
_id: id,
|
||||
scroller: newScroller(id, true), // border on Table
|
||||
tablebase: b,
|
||||
selected: newEvent(),
|
||||
_id: id,
|
||||
scroller: newScroller(id, true), // border on Table
|
||||
tablebase: b,
|
||||
selected: newEvent(),
|
||||
}
|
||||
// also sets the delegate
|
||||
C.tableMakeDataSource(t._id, unsafe.Pointer(t))
|
||||
|
@ -43,7 +43,7 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
|||
editable = true
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -18,27 +18,27 @@ import "C"
|
|||
type table struct {
|
||||
*tablebase
|
||||
|
||||
_widget *C.GtkWidget
|
||||
treeview *C.GtkTreeView
|
||||
scroller *scroller
|
||||
_widget *C.GtkWidget
|
||||
treeview *C.GtkTreeView
|
||||
scroller *scroller
|
||||
|
||||
model *C.goTableModel
|
||||
modelgtk *C.GtkTreeModel
|
||||
selection *C.GtkTreeSelection
|
||||
model *C.goTableModel
|
||||
modelgtk *C.GtkTreeModel
|
||||
selection *C.GtkTreeSelection
|
||||
|
||||
pixbufs []*C.GdkPixbuf
|
||||
pixbufs []*C.GdkPixbuf
|
||||
|
||||
selected *event
|
||||
selected *event
|
||||
|
||||
// stuff required by GtkTreeModel
|
||||
nColumns C.gint
|
||||
old C.gint
|
||||
types []C.GType
|
||||
crtocol map[*C.GtkCellRendererToggle]int
|
||||
nColumns C.gint
|
||||
old C.gint
|
||||
types []C.GType
|
||||
crtocol map[*C.GtkCellRendererToggle]int
|
||||
}
|
||||
|
||||
var (
|
||||
attribText = togstr("text")
|
||||
attribText = togstr("text")
|
||||
attribPixbuf = togstr("pixbuf")
|
||||
attribActive = togstr("active")
|
||||
)
|
||||
|
@ -46,12 +46,12 @@ var (
|
|||
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||
widget := C.gtk_tree_view_new()
|
||||
t := &table{
|
||||
scroller: newScroller(widget, true, true, false), // natively scrollable; has a border; no overlay
|
||||
tablebase: b,
|
||||
_widget: widget,
|
||||
treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)),
|
||||
crtocol: make(map[*C.GtkCellRendererToggle]int),
|
||||
selected: newEvent(),
|
||||
scroller: newScroller(widget, true, true, false), // natively scrollable; has a border; no overlay
|
||||
tablebase: b,
|
||||
_widget: widget,
|
||||
treeview: (*C.GtkTreeView)(unsafe.Pointer(widget)),
|
||||
crtocol: make(map[*C.GtkCellRendererToggle]int),
|
||||
selected: newEvent(),
|
||||
}
|
||||
model := C.newTableModel(unsafe.Pointer(t))
|
||||
t.model = model
|
||||
|
@ -87,7 +87,7 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
|||
C.tableAppendColumn(t.treeview, C.gint(i), cname,
|
||||
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
|
||||
t.nColumns = C.gint(ty.NumField())
|
||||
|
|
|
@ -4,8 +4,8 @@ package ui
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// #include "winapi_windows.h"
|
||||
|
@ -13,32 +13,32 @@ import "C"
|
|||
|
||||
type table struct {
|
||||
*tablebase
|
||||
_hwnd C.HWND
|
||||
noautosize bool
|
||||
colcount C.int
|
||||
hotrow C.int
|
||||
hotcol C.int
|
||||
pushedrow C.int
|
||||
pushedcol C.int
|
||||
selected *event
|
||||
_hwnd C.HWND
|
||||
noautosize bool
|
||||
colcount C.int
|
||||
hotrow C.int
|
||||
hotcol C.int
|
||||
pushedrow C.int
|
||||
pushedcol C.int
|
||||
selected *event
|
||||
}
|
||||
|
||||
func finishNewTable(b *tablebase, ty reflect.Type) Table {
|
||||
t := &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)
|
||||
tablebase: b,
|
||||
hotrow: -1,
|
||||
hotcol: -1,
|
||||
pushedrow: -1,
|
||||
pushedcol: -1,
|
||||
selected: newEvent(),
|
||||
_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)
|
||||
tablebase: b,
|
||||
hotrow: -1,
|
||||
hotcol: -1,
|
||||
pushedrow: -1,
|
||||
pushedcol: -1,
|
||||
selected: newEvent(),
|
||||
}
|
||||
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_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
|
||||
C.SendMessageW(t._hwnd, C.msgTableMakeInitialCheckboxImageList, 0, 0)
|
||||
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))
|
||||
datum := d.Index(int(item.iItem)).Field(int(item.iSubItem))
|
||||
isText := true
|
||||
if item.mask & C.LVIF_IMAGE != 0 {
|
||||
if item.mask&C.LVIF_IMAGE != 0 {
|
||||
if datum.Type() == reflect.TypeOf(ImageIndex(0)) {
|
||||
item.iImage = C.int(datum.Interface().(ImageIndex))
|
||||
isText = false
|
||||
}
|
||||
// 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
|
||||
item.iIndent = 0
|
||||
}
|
||||
if item.mask & C.LVIF_STATE != 0 {
|
||||
if item.mask&C.LVIF_STATE != 0 {
|
||||
// start by not changing any state
|
||||
item.stateMask = 0
|
||||
if datum.Kind() == reflect.Bool {
|
||||
|
@ -129,7 +129,7 @@ func tableGetCell(data unsafe.Pointer, item *C.LVITEMW) {
|
|||
isText = false
|
||||
}
|
||||
}
|
||||
if item.mask & C.LVIF_TEXT != 0 {
|
||||
if item.mask&C.LVIF_TEXT != 0 {
|
||||
if isText {
|
||||
s := fmt.Sprintf("%v", datum)
|
||||
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
|
||||
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
|
||||
}
|
||||
if row != t.pushedrow || col != t.pushedcol { // mouse moved out
|
||||
if row != t.pushedrow || col != t.pushedcol { // mouse moved out
|
||||
return
|
||||
}
|
||||
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 (
|
||||
// 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...
|
||||
tableWidth = 183
|
||||
tableWidth = 183
|
||||
tableHeight = 50
|
||||
)
|
||||
|
||||
|
|
|
@ -10,15 +10,15 @@ import (
|
|||
import "C"
|
||||
|
||||
type textfield struct {
|
||||
_id C.id
|
||||
changed *event
|
||||
invalid C.id
|
||||
_id C.id
|
||||
changed *event
|
||||
invalid C.id
|
||||
}
|
||||
|
||||
func finishNewTextField(id C.id) *textfield {
|
||||
t := &textfield{
|
||||
_id: id,
|
||||
changed: newEvent(),
|
||||
_id: id,
|
||||
changed: newEvent(),
|
||||
}
|
||||
C.textfieldSetDelegate(t._id, unsafe.Pointer(t))
|
||||
return t
|
||||
|
|
|
@ -18,17 +18,17 @@ import (
|
|||
import "C"
|
||||
|
||||
type textfield struct {
|
||||
_widget *C.GtkWidget
|
||||
entry *C.GtkEntry
|
||||
changed *event
|
||||
_widget *C.GtkWidget
|
||||
entry *C.GtkEntry
|
||||
changed *event
|
||||
}
|
||||
|
||||
func startNewTextField() *textfield {
|
||||
widget := C.gtk_entry_new()
|
||||
t := &textfield{
|
||||
_widget: widget,
|
||||
entry: (*C.GtkEntry)(unsafe.Pointer(widget)),
|
||||
changed: newEvent(),
|
||||
_widget: widget,
|
||||
entry: (*C.GtkEntry)(unsafe.Pointer(widget)),
|
||||
changed: newEvent(),
|
||||
}
|
||||
g_signal_connect(
|
||||
C.gpointer(unsafe.Pointer(t._widget)),
|
||||
|
|
|
@ -10,20 +10,20 @@ import (
|
|||
import "C"
|
||||
|
||||
type textfield struct {
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
changed *event
|
||||
_hwnd C.HWND
|
||||
_textlen C.LONG
|
||||
changed *event
|
||||
}
|
||||
|
||||
var editclass = toUTF16("EDIT")
|
||||
|
||||
func startNewTextField(style C.DWORD) *textfield {
|
||||
hwnd := C.newControl(editclass,
|
||||
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)
|
||||
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)
|
||||
t := &textfield{
|
||||
_hwnd: hwnd,
|
||||
changed: newEvent(),
|
||||
_hwnd: hwnd,
|
||||
changed: newEvent(),
|
||||
}
|
||||
C.controlSetControlFont(t._hwnd)
|
||||
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 (
|
||||
// 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
|
||||
)
|
||||
|
||||
|
|
20
uitask.go
20
uitask.go
|
@ -3,10 +3,10 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Go initializes and runs package ui.
|
||||
|
@ -63,13 +63,13 @@ func uiissueloop() {
|
|||
|
||||
type event struct {
|
||||
// All events internally return bool; those that don't will be wrapped around to return a dummy value.
|
||||
do func() bool
|
||||
lock sync.Mutex
|
||||
do func() bool
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func newEvent() *event {
|
||||
return &event{
|
||||
do: func() bool {
|
||||
do: func() bool {
|
||||
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.
|
||||
type ForeignEvent struct {
|
||||
c reflect.Value
|
||||
e *event
|
||||
d interface{}
|
||||
c reflect.Value
|
||||
e *event
|
||||
d interface{}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
c := reflect.ValueOf(channel)
|
||||
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()")
|
||||
}
|
||||
fe := &ForeignEvent{
|
||||
c: c,
|
||||
e: newEvent(),
|
||||
c: c,
|
||||
e: newEvent(),
|
||||
}
|
||||
fe.e.set(func() {
|
||||
handler(fe.d)
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
import "C"
|
||||
|
||||
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+)
|
||||
// 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
|
||||
func xdoissue(data C.gpointer) C.gboolean {
|
||||
perform(unsafe.Pointer(data))
|
||||
return C.FALSE // don't repeat
|
||||
return C.FALSE // don't repeat
|
||||
}
|
||||
|
||||
//export doissue
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
import "C"
|
||||
|
||||
type window struct {
|
||||
id C.id
|
||||
id C.id
|
||||
|
||||
closing *event
|
||||
closing *event
|
||||
|
||||
*container
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ func newWindow(title string, width int, height int, control Control) *window {
|
|||
defer C.free(unsafe.Pointer(ctitle))
|
||||
C.windowSetTitle(id, ctitle)
|
||||
w := &window{
|
||||
id: id,
|
||||
closing: newEvent(),
|
||||
container: newContainer(control),
|
||||
id: id,
|
||||
closing: newEvent(),
|
||||
container: newContainer(control),
|
||||
}
|
||||
C.windowSetDelegate(w.id, unsafe.Pointer(w))
|
||||
C.windowSetContentView(w.id, w.container.id)
|
||||
|
|
|
@ -13,14 +13,14 @@ import (
|
|||
import "C"
|
||||
|
||||
type window struct {
|
||||
widget *C.GtkWidget
|
||||
wc *C.GtkContainer
|
||||
bin *C.GtkBin
|
||||
window *C.GtkWindow
|
||||
widget *C.GtkWidget
|
||||
wc *C.GtkContainer
|
||||
bin *C.GtkBin
|
||||
window *C.GtkWindow
|
||||
|
||||
group *C.GtkWindowGroup
|
||||
group *C.GtkWindowGroup
|
||||
|
||||
closing *event
|
||||
closing *event
|
||||
|
||||
*container
|
||||
}
|
||||
|
@ -30,11 +30,11 @@ func newWindow(title string, width int, height int, control Control) *window {
|
|||
ctitle := togstr(title)
|
||||
defer freegstr(ctitle)
|
||||
w := &window{
|
||||
widget: widget,
|
||||
wc: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
||||
bin: (*C.GtkBin)(unsafe.Pointer(widget)),
|
||||
window: (*C.GtkWindow)(unsafe.Pointer(widget)),
|
||||
closing: newEvent(),
|
||||
widget: widget,
|
||||
wc: (*C.GtkContainer)(unsafe.Pointer(widget)),
|
||||
bin: (*C.GtkBin)(unsafe.Pointer(widget)),
|
||||
window: (*C.GtkWindow)(unsafe.Pointer(widget)),
|
||||
closing: newEvent(),
|
||||
}
|
||||
C.gtk_window_set_title(w.window, ctitle)
|
||||
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))
|
||||
close := w.closing.fire()
|
||||
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
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ import (
|
|||
import "C"
|
||||
|
||||
type window struct {
|
||||
hwnd C.HWND
|
||||
shownbefore bool
|
||||
hwnd C.HWND
|
||||
shownbefore bool
|
||||
|
||||
closing *event
|
||||
closing *event
|
||||
|
||||
*container
|
||||
}
|
||||
|
@ -33,14 +33,14 @@ func makeWindowWindowClass() error {
|
|||
func newWindow(title string, width int, height int, control Control) *window {
|
||||
w := &window{
|
||||
// hwnd set in WM_CREATE handler
|
||||
closing: newEvent(),
|
||||
container: newContainer(control),
|
||||
closing: newEvent(),
|
||||
container: newContainer(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))
|
||||
}
|
||||
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 {
|
||||
panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
|
||||
}
|
||||
|
|
1224
yz_icons_test.go
1224
yz_icons_test.go
File diff suppressed because it is too large
Load Diff
|
@ -10,20 +10,20 @@ import (
|
|||
)
|
||||
|
||||
type repainter struct {
|
||||
img *image.RGBA
|
||||
area Area
|
||||
x TextField
|
||||
y TextField
|
||||
width TextField
|
||||
height TextField
|
||||
repaint Button
|
||||
all Button
|
||||
grid Grid
|
||||
img *image.RGBA
|
||||
area Area
|
||||
x TextField
|
||||
y TextField
|
||||
width TextField
|
||||
height TextField
|
||||
repaint Button
|
||||
all Button
|
||||
grid Grid
|
||||
|
||||
xv int
|
||||
yv int
|
||||
wv int
|
||||
hv int
|
||||
xv int
|
||||
yv int
|
||||
wv int
|
||||
hv int
|
||||
}
|
||||
|
||||
func newRepainter(times int) *repainter {
|
||||
|
@ -55,7 +55,7 @@ func newRepainter(times int) *repainter {
|
|||
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)
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ func (r *repainter) alter(rect image.Rectangle, c color.Color) {
|
|||
}
|
||||
|
||||
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.area.Repaint(rect)
|
||||
}
|
||||
|
|
96
zz_test.go
96
zz_test.go
|
@ -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)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"flag"
|
||||
"reflect"
|
||||
"testing"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"time"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
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)")
|
||||
|
||||
type dtype struct {
|
||||
Name string
|
||||
Address string
|
||||
Name string
|
||||
Address string
|
||||
}
|
||||
|
||||
var ddata = []dtype{
|
||||
{ "alpha", "beta" },
|
||||
{ "gamma", "delta" },
|
||||
{ "epsilon", "zeta" },
|
||||
{ "eta", "theta" },
|
||||
{ "iota", "kappa" },
|
||||
{"alpha", "beta"},
|
||||
{"gamma", "delta"},
|
||||
{"epsilon", "zeta"},
|
||||
{"eta", "theta"},
|
||||
{"iota", "kappa"},
|
||||
}
|
||||
|
||||
type testwin struct {
|
||||
t Tab
|
||||
w Window
|
||||
repainter *repainter
|
||||
fe *ForeignEvent
|
||||
festack Stack
|
||||
festart Button
|
||||
felabel Label
|
||||
festop Button
|
||||
vedit TextField
|
||||
openbtn Button
|
||||
fnlabel Label
|
||||
icons []icon
|
||||
il ImageList
|
||||
icontbl Table
|
||||
group2 Group
|
||||
group Group
|
||||
simpleGrid SimpleGrid
|
||||
nt Tab
|
||||
a Area
|
||||
spw Stack
|
||||
sph Stack
|
||||
s Stack
|
||||
l Label
|
||||
table Table
|
||||
b Button
|
||||
c Checkbox
|
||||
e TextField
|
||||
e2 TextField
|
||||
t Tab
|
||||
w Window
|
||||
repainter *repainter
|
||||
fe *ForeignEvent
|
||||
festack Stack
|
||||
festart Button
|
||||
felabel Label
|
||||
festop Button
|
||||
vedit TextField
|
||||
openbtn Button
|
||||
fnlabel Label
|
||||
icons []icon
|
||||
il ImageList
|
||||
icontbl Table
|
||||
group2 Group
|
||||
group Group
|
||||
simpleGrid SimpleGrid
|
||||
nt Tab
|
||||
a Area
|
||||
spw Stack
|
||||
sph Stack
|
||||
s Stack
|
||||
l Label
|
||||
table Table
|
||||
b Button
|
||||
c Checkbox
|
||||
e TextField
|
||||
e2 TextField
|
||||
|
||||
wsmall Window
|
||||
wsmall Window
|
||||
}
|
||||
|
||||
type areaHandler struct {
|
||||
handled bool
|
||||
handled bool
|
||||
}
|
||||
|
||||
func (a *areaHandler) Paint(r image.Rectangle) *image.RGBA {
|
||||
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
|
||||
}
|
||||
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 (tw *testwin) openFile(fn string) {
|
||||
|
@ -145,7 +147,7 @@ func (tw *testwin) make(done chan struct{}) {
|
|||
done <- struct{}{}
|
||||
return true
|
||||
})
|
||||
tw.icons, tw.il = readIcons() // repainter uses these
|
||||
tw.icons, tw.il = readIcons() // repainter uses these
|
||||
tw.repainter = newRepainter(15)
|
||||
tw.t.Append("Repaint", tw.repainter.grid)
|
||||
tw.addfe()
|
||||
|
@ -192,7 +194,7 @@ func (tw *testwin) make(done chan struct{}) {
|
|||
NewCheckbox("hello"),
|
||||
NewTextField(),
|
||||
NewPasswordField(),
|
||||
NewTable(reflect.TypeOf(struct{A,B,C int}{})),
|
||||
NewTable(reflect.TypeOf(struct{ A, B, C int }{})),
|
||||
NewStandaloneLabel("hello"))
|
||||
tw.t.Append("Pref Width", tw.spw)
|
||||
tw.sph = NewVerticalStack(
|
||||
|
@ -200,7 +202,7 @@ func (tw *testwin) make(done chan struct{}) {
|
|||
NewCheckbox("hello"),
|
||||
NewTextField(),
|
||||
NewPasswordField(),
|
||||
NewTable(reflect.TypeOf(struct{A,B,C int}{})),
|
||||
NewTable(reflect.TypeOf(struct{ A, B, C int }{})),
|
||||
NewStandaloneLabel("hello ÉÀÔ"))
|
||||
tw.t.Append("Pref Height", tw.sph)
|
||||
stack1 := NewHorizontalStack(NewLabel("Test"), NewTextField())
|
||||
|
@ -208,7 +210,7 @@ func (tw *testwin) make(done chan struct{}) {
|
|||
stack2 := NewHorizontalStack(NewLabel("ÉÀÔ"), NewTextField())
|
||||
stack2.SetStretchy(1)
|
||||
stack3 := NewHorizontalStack(NewLabel("Test 2"),
|
||||
NewTable(reflect.TypeOf(struct{A,B,C int}{})))
|
||||
NewTable(reflect.TypeOf(struct{ A, B, C int }{})))
|
||||
stack3.SetStretchy(1)
|
||||
tw.s = NewVerticalStack(stack1, stack2, stack3)
|
||||
tw.s.SetStretchy(2)
|
||||
|
|
Loading…
Reference in New Issue