summaryrefslogtreecommitdiff
path: root/redo
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-08-30 23:02:02 -0400
committerPietro Gagliardi <[email protected]>2014-08-30 23:02:02 -0400
commit77bf566ebbcb62acd4d08d905d9542d6ff9b6b80 (patch)
treeeeb8e72bc3bf57f5be7f0c0af4319189ac6de838 /redo
parent155899c65ed32245e2ccad4197a10c77017d835b (diff)
...in with the new.
Diffstat (limited to 'redo')
-rw-r--r--redo/area.go370
-rw-r--r--redo/area_darwin.go264
-rw-r--r--redo/area_darwin.m236
-rw-r--r--redo/area_unix.go520
-rw-r--r--redo/area_windows.c500
-rw-r--r--redo/area_windows.go361
-rw-r--r--redo/basicctrls.go129
-rw-r--r--redo/basicctrls_darwin.m219
-rw-r--r--redo/basicctrls_windows.c129
-rw-r--r--redo/button_darwin.go72
-rw-r--r--redo/button_unix.go82
-rw-r--r--redo/button_windows.go100
-rw-r--r--redo/checkbox_darwin.go79
-rw-r--r--redo/checkbox_unix.go92
-rw-r--r--redo/checkbox_windows.go103
-rw-r--r--redo/comctl32_windows.c134
-rw-r--r--redo/common_darwin.go20
-rw-r--r--redo/common_darwin.m16
-rw-r--r--redo/common_unix.go56
-rw-r--r--redo/common_windows.c139
-rw-r--r--redo/common_windows.go58
-rw-r--r--redo/container.go52
-rw-r--r--redo/container_darwin.go68
-rw-r--r--redo/container_darwin.m44
-rw-r--r--redo/container_unix.c103
-rw-r--r--redo/container_unix.go71
-rw-r--r--redo/container_windows.c96
-rw-r--r--redo/container_windows.go147
-rw-r--r--redo/control.go20
-rw-r--r--redo/control_darwin.go58
-rw-r--r--redo/control_darwin.m98
-rw-r--r--redo/control_unix.go120
-rw-r--r--redo/control_windows.c62
-rw-r--r--redo/control_windows.go49
-rwxr-xr-xredo/controlbase.sh28
-rw-r--r--redo/dialog.go21
-rw-r--r--redo/dialog_darwin.go25
-rw-r--r--redo/dialog_darwin.m30
-rw-r--r--redo/dialog_unix.go58
-rw-r--r--redo/dialog_windows.c62
-rw-r--r--redo/dialog_windows.go25
-rw-r--r--redo/doc.go12
-rw-r--r--redo/events_darwin.go132
-rw-r--r--redo/events_notdarwin.go152
-rw-r--r--redo/future97
-rw-r--r--redo/grid.go234
-rw-r--r--redo/group_darwin.go58
-rw-r--r--redo/group_unix.go87
-rw-r--r--redo/group_windows.go82
-rw-r--r--redo/gtk_unix.h42
-rw-r--r--redo/imagelist.go29
-rw-r--r--redo/imagelist_darwin.go38
-rw-r--r--redo/imagelist_darwin.m30
-rw-r--r--redo/imagelist_unix.go78
-rw-r--r--redo/imagelist_windows.c268
-rw-r--r--redo/imagelist_windows.go45
-rw-r--r--redo/init_windows.c73
-rw-r--r--redo/label_darwin.go95
-rw-r--r--redo/label_unix.go92
-rw-r--r--redo/label_windows.go99
-rw-r--r--redo/mergeback/layout.go36
-rw-r--r--redo/mergeback/table_mouseleave_windows.c4
-rw-r--r--redo/mergeback/windows-one-tab.go115
-rw-r--r--redo/objc_darwin.h150
-rw-r--r--redo/proposals/sidebar.md32
-rw-r--r--redo/proposals/tree.md35
-rw-r--r--redo/scrapped4
-rw-r--r--redo/stack.go209
-rw-r--r--redo/tab_darwin.go55
-rw-r--r--redo/tab_darwin.m40
-rw-r--r--redo/tab_unix.go70
-rw-r--r--redo/tab_windows.c108
-rw-r--r--redo/tab_windows.go118
-rw-r--r--redo/table.go92
-rw-r--r--redo/table_darwin.go158
-rw-r--r--redo/table_darwin.m194
-rw-r--r--redo/table_unix.c270
-rw-r--r--redo/table_unix.go249
-rw-r--r--redo/table_windows.c195
-rw-r--r--redo/table_windows.go262
-rw-r--r--redo/textfield_darwin.go93
-rw-r--r--redo/textfield_unix.go106
-rw-r--r--redo/textfield_windows.go104
-rw-r--r--redo/uitask.go164
-rw-r--r--redo/uitask_darwin.go41
-rw-r--r--redo/uitask_darwin.m138
-rw-r--r--redo/uitask_unix.go52
-rw-r--r--redo/uitask_windows.c167
-rw-r--r--redo/uitask_windows.go70
-rw-r--r--redo/warningpopover_darwin.m157
-rw-r--r--redo/winapi_windows.h154
-rw-r--r--redo/window.go35
-rw-r--r--redo/window_darwin.go69
-rw-r--r--redo/window_darwin.m86
-rw-r--r--redo/window_unix.go88
-rw-r--r--redo/window_windows.c84
-rw-r--r--redo/window_windows.go101
-rw-r--r--redo/yz_icons_test.go685
-rw-r--r--redo/yz_repaint_test.go125
-rw-r--r--redo/zz_test.go279
100 files changed, 0 insertions, 11853 deletions
diff --git a/redo/area.go b/redo/area.go
deleted file mode 100644
index 3719b30..0000000
--- a/redo/area.go
+++ /dev/null
@@ -1,370 +0,0 @@
-// 14 march 2014
-
-package ui
-
-import (
- "fmt"
- "image"
- "image/draw"
- "reflect"
- "unsafe"
-)
-
-// Area represents a blank canvas upon which programs may draw anything and receive arbitrary events from the user.
-// An Area has an explicit size, represented in pixels, that may be different from the size shown in its Window.
-// For information on scrollbars, see "Scrollbars" in the Overview.
-// The coordinate system of an Area always has an origin of (0,0) which maps to the top-left corner; all image.Points and image.Rectangles sent across Area's channels conform to this.
-// The size of an Area must be at least 1x1 (that is, neither its width nor its height may be zero or negative).
-// For control layout purposes, an Area prefers to be at the size you set it to (so if an Area is not stretchy in its layout, it will ask to have that size).
-//
-// To handle events to the Area, an Area must be paired with an AreaHandler.
-// See AreaHandler for details.
-//
-// Area will accept keyboard focus if tabbed into, but will refuse to relinquish keyboard focus if tabbed out.
-//
-// Do not use an Area if you intend to read text.
-// Area reads keys based on their position on a standard
-// 101-key keyboard, and does no character processing.
-// Character processing methods differ across operating
-// systems; trying ot recreate these yourself is only going
-// to lead to trouble.
-// If you absolutely need to enter text somehow, use OpenTextFieldAt() and its related methods.
-type Area interface {
- Control
-
- // SetSize sets the Area's internal drawing size.
- // It has no effect on the actual control size.
- // SetSize will also signal the entirety of the Area to be redrawn as in RepaintAll.
- // It panics if width or height is zero or negative.
- SetSize(width int, height int)
-
- // Repaint marks the given rectangle of the Area as needing to be redrawn.
- // The given rectangle is clipped to the Area's size.
- // If, after clipping, the rectangle is empty, Repaint does nothing.
- Repaint(r image.Rectangle)
-
- // RepaintAll marks the entirety of the Area as needing to be redrawn.
- RepaintAll()
-
- // OpenTextFieldAt opens a TextField with the top-left corner at the given coordinates of the Area.
- // It panics if the coordinates fall outside the Area.
- // Any text previously in the TextField (be it by the user or by a call to SetTextFieldText()) is retained.
- // The TextField receives the input focus so the user can type things; when the TextField loses the input focus, it hides itself and signals the event set by OnTextFieldDismissed.
- // The TextField will also dismiss itself on some platforms when the user "completes editing"; the exact meaning of this is platform-specific.
- OpenTextFieldAt(x int, y int)
-
- // TextFieldText and TextFieldSetText get and set the OpenTextFieldAt TextField's text, respectively.
- TextFieldText() string
- SetTextFieldText(text string)
-
- // OnTextFieldDismissed is an event that is fired when the OpenTextFieldAt TextField is dismissed.
- OnTextFieldDismissed(f func())
-}
-
-type areabase struct {
- width int
- height int
- handler AreaHandler
-}
-
-// AreaHandler represents the events that an Area should respond to.
-// These methods are all executed on the main goroutine, not necessarily the same one that you created the AreaHandler in; you are responsible for the thread safety of any members of the actual type that implements ths interface.
-// (Having to use this interface does not strike me as being particularly Go-like, but the nature of Paint makes channel-based event handling a non-option; in practice, deadlocks occur.)
-type AreaHandler interface {
- // Paint is called when the Area needs to be redrawn.
- // The part of the Area that needs to be redrawn is stored in cliprect.
- // Before Paint() is called, this region is cleared with a system-defined background color.
- // You MUST handle this event, and you MUST return a valid image, otherwise deadlocks and panicking will occur.
- // The image returned must have the same size as rect (but does not have to have the same origin points).
- // Example:
- // imgFromFile, _, err := image.Decode(file)
- // if err != nil { panic(err) }
- // img := image.NewRGBA(imgFromFile.Rect)
- // draw.Draw(img, img.Rect, imgFromFile, image.ZP, draw.Over)
- // // ...
- // func (h *myAreaHandler) Paint(rect image.Rectangle) *image.RGBA {
- // return img.SubImage(rect).(*image.RGBA)
- // }
- Paint(cliprect image.Rectangle) *image.RGBA
-
- // Mouse is called when the Area receives a mouse event.
- // You are allowed to do nothing in this handler (to ignore mouse events).
- // See MouseEvent for details.
- // After handling the mouse event, package ui will decide whether to perform platform-dependent event chain continuation based on that platform's designated action (so it is not possible to override global mouse events this way).
- Mouse(e MouseEvent)
-
- // Key is called when the Area receives a keyboard event.
- // Return true to indicate that you handled the event; return false to indicate that you did not and let the system handle the event.
- // You are allowed to do nothing in this handler (to ignore keyboard events); in this case, return false.
- // See KeyEvent for details.
- Key(e KeyEvent) (handled bool)
-}
-
-// MouseEvent contains all the information for a mous event sent by Area.Mouse.
-// Mouse button IDs start at 1, with 1 being the left mouse button, 2 being the middle mouse button, and 3 being the right mouse button.
-// If additional buttons are supported, they will be returned with 4 being the first additional button.
-// For example, on Unix systems where mouse buttons 4 through 7 are pseudobuttons for the scroll wheel directions, the next button, button 8, will be returned as 4, 9 as 5, etc.
-// The association between button numbers and physical buttons are system-defined.
-// For example, on Windows, buttons 4 and 5 are mapped to what are internally referred to as "XBUTTON1" and "XBUTTON2", which often correspond to the dedicated back/forward navigation buttons on the sides of many mice.
-// The examples here are NOT a guarantee as to how many buttons maximum will be available on a given system.
-//
-// If the user clicked on the Area to switch to the Window it is contained in from another window in the OS, the Area will receive a MouseEvent for that click.
-type MouseEvent struct {
- // Pos is the position of the mouse in the Area at the time of the event.
- Pos image.Point
-
- // If the event was generated by a mouse button being pressed, Down contains the ID of that button.
- // Otherwise, Down contains 0.
- // If Down contains nonzero, the Area will also receive keyboard focus.
- Down uint
-
- // If the event was generated by a mouse button being released, Up contains the ID of that button.
- // Otherwise, Up contains 0.
- // If both Down and Up are 0, the event represents mouse movement (with optional held buttons for dragging; see below).
- // Down and Up shall not both be nonzero.
- Up uint
-
- // If Down is nonzero, Count indicates the number of clicks: 1 for single-click, 2 for double-click, 3 for triple-click, and so on.
- // The order of events will be Down:Count=1 -> Up -> Down:Count=2 -> Up -> Down:Count=3 -> Up -> ...
- Count uint
-
- // Modifiers is a bit mask indicating the modifier keys being held during the event.
- Modifiers Modifiers
-
- // Held is a slice of button IDs that indicate which mouse buttons are being held during the event.
- // Held will not include Down and Up.
- // Held will be sorted.
- // Only buttons 1, 2, and 3 are guaranteed to be detected by Held properly; whether or not any others are is implementation-defined.
- //
- // If Held is non-empty but Up and Down are both zero, the mouse is being dragged, with all the buttons in Held being held.
- // Whether or not a drag into an Area generates MouseEvents is implementation-defined.
- // Whether or not a drag over an Area when the program is inactive generates MouseEvents is also implementation-defined.
- // Moving the mouse over an Area when the program is inactive and no buttons are held will, however, generate MouseEvents.
- Held []uint
-}
-
-// HeldBits returns Held as a bit mask.
-// Bit 0 maps to button 1, bit 1 maps to button 2, etc.
-func (e MouseEvent) HeldBits() (h uintptr) {
- for _, x := range e.Held {
- h |= uintptr(1) << (x - 1)
- }
- return h
-}
-
-// A KeyEvent represents a keypress in an Area.
-//
-// Key presses are based on their positions on a standard
-// 101-key keyboard found on most computers. The
-// names chosen for keys here are based on their names
-// on US English QWERTY keyboards; see Key for details.
-//
-// If a key is pressed that is not supported by Key, ExtKey,
-// or Modifiers, no KeyEvent will be produced and package ui will behave as if false was returned from the event handler.
-type KeyEvent struct {
- // Key is a byte representing a character pressed
- // in the typewriter section of the keyboard.
- // The value, which is independent of whether the
- // Shift key is held, is a constant with one of the
- // following (case-sensitive) values, drawn according
- // to the key's position on the keyboard.
- // ` 1 2 3 4 5 6 7 8 9 0 - =
- // q w e r t y u i o p [ ] \
- // a s d f g h j k l ; '
- // z x c v b n m , . /
- // The actual key entered will be the key at the respective
- // position on the user's keyboard, regardless of the actual
- // layout. (Some keyboards move \ to either the row above
- // or the row below but in roughly the same spot; this is
- // accounted for. Some keyboards have an additonal key
- // to the left of 'z' or additional keys to the right of '='; these
- // cannot be read.)
- // In addition, Key will contain
- // - ' ' (space) if the spacebar was pressed
- // - '\t' if Tab was pressed, regardless of Modifiers
- // - '\n' if the typewriter Enter key was pressed
- // - '\b' if the typewriter Backspace key was pressed
- // If this value is zero, see ExtKey.
- Key byte
-
- // If Key is zero, ExtKey contains a predeclared identifier
- // naming an extended key. See ExtKey for details.
- // If both Key and ExtKey are zero, a Modifier by itself
- // was pressed. Key and ExtKey will not both be nonzero.
- ExtKey ExtKey
-
- // If both Key and ExtKey are zero, Modifier will contain exactly one of its bits set, indicating which Modifier was pressed or released.
- // As with Modifiers itself, there is no way to differentiate between left and right modifier keys.
- // As such, the result of pressing and/or releasing both left and right of the same Modifier is system-defined.
- // Furthermore, the result of holding down a Key or ExtKey, then pressing a Modifier, and then releasing the original key is system-defined.
- // Under no condition shall Key, ExtKey, AND Modifier all be zero.
- Modifier Modifiers
-
- // Modifiers contains all the modifier keys currently being held at the time of the KeyEvent.
- // If Modifier is nonzero, Modifiers will not contain Modifier itself.
- Modifiers Modifiers
-
- // If Up is true, the key was released; if not, the key was pressed.
- // There is no guarantee that all pressed keys shall have
- // corresponding release events (for instance, if the user switches
- // programs while holding the key down, then releases the key).
- // Keys that have been held down are reported as multiple
- // key press events.
- Up bool
-}
-
-// ExtKey represents keys that are not in the typewriter section of the keyboard.
-type ExtKey uintptr
-
-const (
- Escape ExtKey = iota + 1
- Insert // equivalent to "Help" on Apple keyboards
- Delete
- Home
- End
- PageUp
- PageDown
- Up
- Down
- Left
- Right
- F1 // F1..F12 are guaranteed to be consecutive
- F2
- F3
- F4
- F5
- F6
- F7
- F8
- F9
- F10
- F11
- F12
- N0 // numpad keys; independent of Num Lock state
- N1 // N0..N9 are guaranteed to be consecutive
- N2
- N3
- N4
- N5
- N6
- N7
- N8
- N9
- NDot
- NEnter
- NAdd
- NSubtract
- NMultiply
- NDivide
- _nextkeys // for sanity check
-)
-
-// EffectiveKey returns e.Key if it is set.
-// Otherwise, if e.ExtKey denotes a numpad key,
-// EffectiveKey returns the equivalent e.Key value
-// ('0'..'9', '.', '\n', '+', '-', '*', or '/').
-// Otherwise, EffectiveKey returns zero.
-func (e KeyEvent) EffectiveKey() byte {
- if e.Key != 0 {
- return e.Key
- }
- k := e.ExtKey
- switch {
- case k >= N0 && k <= N9:
- return byte(k-N0) + '0'
- case k == NDot:
- return '.'
- case k == NEnter:
- return '\n'
- case k == NAdd:
- return '+'
- case k == NSubtract:
- return '-'
- case k == NMultiply:
- return '*'
- case k == NDivide:
- return '/'
- }
- return 0
-}
-
-// Modifiers indicates modifier keys being held during an event.
-// There is no way to differentiate between left and right modifier keys.
-// As such, what KeyEvents get sent if the user does something unusual with both of a certain modifier key at once is undefined.
-type Modifiers uintptr
-
-const (
- Ctrl Modifiers = 1 << iota // the keys labelled Ctrl or Control on all platforms
- Alt // the keys labelled Alt or Option or Meta on all platforms
- Shift // the Shift keys
- Super // the Super keys on platforms that have one, or the Windows keys on Windows, or the Command keys on Mac OS X
-)
-
-func checkAreaSize(width int, height int, which string) {
- if width <= 0 || height <= 0 {
- panic(fmt.Errorf("invalid size %dx%d in %s", width, height, which))
- }
-}
-
-// NewArea creates a new Area with the given size and handler.
-// It panics if handler is nil or if width or height is zero or negative.
-func NewArea(width int, height int, handler AreaHandler) Area {
- checkAreaSize(width, height, "NewArea()")
- if handler == nil {
- panic("handler passed to NewArea() must not be nil")
- }
- return newArea(&areabase{
- width: width,
- height: height,
- handler: handler,
- })
-}
-
-// internal function, but shared by all system implementations: &img.Pix[0] is not necessarily the first pixel in the image
-func pixelDataPos(img *image.RGBA) int {
- return img.PixOffset(img.Rect.Min.X, img.Rect.Min.Y)
-}
-
-func pixelData(img *image.RGBA) *uint8 {
- return &img.Pix[pixelDataPos(img)]
-}
-
-// some platforms require pixels in ARGB order in their native endianness (because they treat the pixel array as an array of uint32s)
-// this does the conversion
-// you need to convert somewhere (Windows and cairo give us memory to use; Windows has stride==width but cairo might not)
-func toARGB(i *image.RGBA, memory uintptr, memstride int, toNRGBA bool) {
- var realbits []byte
-
- rbs := (*reflect.SliceHeader)(unsafe.Pointer(&realbits))
- rbs.Data = memory
- rbs.Len = 4 * i.Rect.Dx() * i.Rect.Dy()
- rbs.Cap = rbs.Len
- p := pixelDataPos(i)
- q := 0
- iPix := i.Pix
- 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
- }
- for y := i.Rect.Min.Y; y < i.Rect.Max.Y; y++ {
- nextp := p + i.Stride
- nextq := q + memstride
- for x := i.Rect.Min.X; x < i.Rect.Max.X; x++ {
- argb := uint32(iPix[p+3]) << 24 // A
- argb |= uint32(iPix[p+0]) << 16 // R
- argb |= uint32(iPix[p+1]) << 8 // G
- argb |= uint32(iPix[p+2]) // B
- // the magic of conversion
- native := (*[4]byte)(unsafe.Pointer(&argb))
- realbits[q+0] = native[0]
- realbits[q+1] = native[1]
- realbits[q+2] = native[2]
- realbits[q+3] = native[3]
- p += 4
- q += 4
- }
- p = nextp
- q = nextq
- }
-}
diff --git a/redo/area_darwin.go b/redo/area_darwin.go
deleted file mode 100644
index 259e95d..0000000
--- a/redo/area_darwin.go
+++ /dev/null
@@ -1,264 +0,0 @@
-// 29 march 2014
-
-package ui
-
-import (
- "fmt"
- "image"
- "unsafe"
-)
-
-//// #include <HIToolbox/Events.h>
-// #include "objc_darwin.h"
-import "C"
-
-type area struct {
- *areabase
-
- _id C.id
- scroller *scroller
- textfield C.id
- textfielddone *event
-}
-
-func newArea(ab *areabase) Area {
- a := &area{
- areabase: ab,
- textfielddone: newEvent(),
- }
- a._id = C.newArea(unsafe.Pointer(a))
- 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)
- return a
-}
-
-func (a *area) SetSize(width, height int) {
- a.width = width
- a.height = height
- // set the frame size to set the area's effective size on the Cocoa side
- C.moveControl(a._id, 0, 0, C.intptr_t(a.width), C.intptr_t(a.height))
-}
-
-func (a *area) Repaint(r image.Rectangle) {
- var s C.struct_xrect
-
- r = image.Rect(0, 0, a.width, a.height).Intersect(r)
- if r.Empty() {
- return
- }
- s.x = C.intptr_t(r.Min.X)
- s.y = C.intptr_t(r.Min.Y)
- s.width = C.intptr_t(r.Dx())
- s.height = C.intptr_t(r.Dy())
- C.areaRepaint(a._id, s)
-}
-
-func (a *area) RepaintAll() {
- C.areaRepaintAll(a._id)
-}
-
-func (a *area) OpenTextFieldAt(x, y int) {
- if x < 0 || x >= a.width || y < 0 || y >= a.height {
- panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
- }
- C.areaTextFieldOpen(a._id, a.textfield, C.intptr_t(x), C.intptr_t(y))
-}
-
-func (a *area) TextFieldText() string {
- return C.GoString(C.textfieldText(a.textfield))
-}
-
-func (a *area) SetTextFieldText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.textfieldSetText(a.textfield, ctext)
-}
-
-func (a *area) OnTextFieldDismissed(f func()) {
- a.textfielddone.set(f)
-}
-
-//export areaTextFieldDismissed
-func areaTextFieldDismissed(data unsafe.Pointer) {
- a := (*area)(unsafe.Pointer(data))
- C.controlSetHidden(a.textfield, C.YES)
- a.textfielddone.fire()
-}
-
-//export areaView_drawRect
-func areaView_drawRect(self C.id, rect C.struct_xrect, data unsafe.Pointer) {
- a := (*area)(data)
- // no need to clear the clip rect; the NSScrollView does that for us (see the setDrawsBackground: call in objc_darwin.m)
- // rectangles in Cocoa are origin/size, not point0/point1; if we don't watch for this, weird things will happen when scrolling
- cliprect := image.Rect(int(rect.x), int(rect.y), int(rect.x+rect.width), int(rect.y+rect.height))
- cliprect = image.Rect(0, 0, int(a.width), int(a.height)).Intersect(cliprect)
- if cliprect.Empty() { // no intersection; nothing to paint
- return
- }
- i := a.handler.Paint(cliprect)
- success := C.drawImage(
- unsafe.Pointer(pixelData(i)), C.intptr_t(i.Rect.Dx()), C.intptr_t(i.Rect.Dy()), C.intptr_t(i.Stride),
- C.intptr_t(cliprect.Min.X), C.intptr_t(cliprect.Min.Y))
- if success == C.NO {
- panic("error drawing into Area (exactly what is unknown)")
- }
-}
-
-func parseModifiers(e C.id) (m Modifiers) {
- mods := C.modifierFlags(e)
- if (mods & C.cNSControlKeyMask) != 0 {
- m |= Ctrl
- }
- if (mods & C.cNSAlternateKeyMask) != 0 {
- m |= Alt
- }
- if (mods & C.cNSShiftKeyMask) != 0 {
- m |= Shift
- }
- if (mods & C.cNSCommandKeyMask) != 0 {
- m |= Super
- }
- return m
-}
-
-func areaMouseEvent(self C.id, e C.id, click bool, up bool, data unsafe.Pointer) {
- var me MouseEvent
-
- a := (*area)(data)
- xp := C.getTranslatedEventPoint(self, e)
- me.Pos = image.Pt(int(xp.x), int(xp.y))
- // for the most part, Cocoa won't geenerate an event outside the Area... except when dragging outside the Area, so check for this
- if !me.Pos.In(image.Rect(0, 0, int(a.width), int(a.height))) {
- return
- }
- me.Modifiers = parseModifiers(e)
- which := uint(C.buttonNumber(e)) + 1
- if which == 3 { // swap middle and right button numbers
- which = 2
- } else if which == 2 {
- which = 3
- }
- if click && up {
- me.Up = which
- } else if click {
- me.Down = which
- // this already works the way we want it to so nothing special needed like with Windows and GTK+
- me.Count = uint(C.clickCount(e))
- } else {
- which = 0 // reset for Held processing below
- }
- // the docs do say don't use this for tracking (mouseMoved:) since it returns the state now, and mouse move events work by tracking, but as far as I can tell dragging the mouse over the inactive window does not generate an event on Mac OS X, so :/ (tracking doesn't touch dragging anyway except during mouseEntered: and mouseExited:, which we don't handle, and the only other tracking message, cursorChanged:, we also don't handle (yet...? need to figure out if this is how to set custom cursors or not), so)
- held := C.pressedMouseButtons()
- if which != 1 && (held&1) != 0 { // button 1
- me.Held = append(me.Held, 1)
- }
- if which != 2 && (held&4) != 0 { // button 2; mind the swap
- me.Held = append(me.Held, 2)
- }
- if which != 3 && (held&2) != 0 { // button 3
- me.Held = append(me.Held, 3)
- }
- held >>= 3
- for i := uint(4); held != 0; i++ {
- if which != i && (held&1) != 0 {
- me.Held = append(me.Held, i)
- }
- held >>= 1
- }
- a.handler.Mouse(me)
-}
-
-//export areaView_mouseMoved_mouseDragged
-func areaView_mouseMoved_mouseDragged(self C.id, e C.id, data unsafe.Pointer) {
- // for moving, this is handled by the tracking rect stuff above
- // for dragging, if multiple buttons are held, only one of their xxxMouseDragged: messages will be sent, so this is OK to do
- areaMouseEvent(self, e, false, false, data)
-}
-
-//export areaView_mouseDown
-func areaView_mouseDown(self C.id, e C.id, data unsafe.Pointer) {
- // no need to manually set focus; Mac OS X has already done that for us by this point since we set our view to be a first responder
- areaMouseEvent(self, e, true, false, data)
-}
-
-//export areaView_mouseUp
-func areaView_mouseUp(self C.id, e C.id, data unsafe.Pointer) {
- areaMouseEvent(self, e, true, true, data)
-}
-
-func sendKeyEvent(self C.id, ke KeyEvent, data unsafe.Pointer) C.BOOL {
- a := (*area)(data)
- handled := a.handler.Key(ke)
- return toBOOL(handled)
-}
-
-func areaKeyEvent(self C.id, e C.id, up bool, data unsafe.Pointer) C.BOOL {
- var ke KeyEvent
-
- keyCode := uintptr(C.keyCode(e))
- ke, ok := fromKeycode(keyCode)
- if !ok {
- // no such key; modifiers by themselves are handled by -[self flagsChanged:]
- return C.NO
- }
- // either ke.Key or ke.ExtKey will be set at this point
- ke.Modifiers = parseModifiers(e)
- ke.Up = up
- return sendKeyEvent(self, ke, data)
-}
-
-//export areaView_keyDown
-func areaView_keyDown(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
- return areaKeyEvent(self, e, false, data)
-}
-
-//export areaView_keyUp
-func areaView_keyUp(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
- return areaKeyEvent(self, e, true, data)
-}
-
-//export areaView_flagsChanged
-func areaView_flagsChanged(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
- var ke KeyEvent
-
- // Mac OS X sends this event on both key up and key down.
- // Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], and check if the respective bit is set or not — that will give us the up/down state
- keyCode := uintptr(C.keyCode(e))
- mod, ok := keycodeModifiers[keyCode] // comma-ok form to avoid adding entries
- if !ok { // unknown modifier; ignore
- return C.NO
- }
- ke.Modifiers = parseModifiers(e)
- ke.Up = (ke.Modifiers & mod) == 0
- ke.Modifier = mod
- // don't include the modifier in ke.Modifiers
- ke.Modifiers &^= mod
- return sendKeyEvent(self, ke, data)
-}
-
-func (a *area) id() C.id {
- return a._id
-}
-
-func (a *area) setParent(p *controlParent) {
- a.scroller.setParent(p)
-}
-
-func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(a, x, y, width, height, d)
-}
-
-func (a *area) preferredSize(d *sizing) (width, height int) {
- // the preferred size of an Area is its size
- return a.width, a.height
-}
-
-func (a *area) commitResize(c *allocation, d *sizing) {
- a.scroller.commitResize(c, d)
-}
-
-func (a *area) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(a, d)
-}
diff --git a/redo/area_darwin.m b/redo/area_darwin.m
deleted file mode 100644
index 9049c3a..0000000
--- a/redo/area_darwin.m
+++ /dev/null
@@ -1,236 +0,0 @@
-// 13 may 2014
-
-#include "objc_darwin.h"
-#include "_cgo_export.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSEvent(x) ((NSEvent *) (x))
-#define toNSView(x) ((NSView *) (x))
-#define toNSObject(x) ((NSObject *) (x))
-#define toNSTextField(x) ((NSTextField *) (x))
-
-#define toNSInteger(x) ((NSInteger) (x))
-#define fromNSInteger(x) ((intptr_t) (x))
-#define toNSUInteger(x) ((NSUInteger) (x))
-#define fromNSUInteger(x) ((uintptr_t) (x))
-
-@interface goAreaView : NSView <NSTextFieldDelegate> {
-@public
- void *goarea;
- NSTrackingArea *trackingArea;
-}
-@end
-
-@implementation goAreaView
-
-- (id)initWithFrame:(NSRect)r
-{
- self = [super initWithFrame:r];
- if (self)
- [self retrack];
- return self;
-}
-
-- (void)drawRect:(NSRect)cliprect
-{
- struct xrect rect;
-
- rect.x = (intptr_t) cliprect.origin.x;
- rect.y = (intptr_t) cliprect.origin.y;
- rect.width = (intptr_t) cliprect.size.width;
- rect.height = (intptr_t) cliprect.size.height;
- areaView_drawRect(self, rect, self->goarea);
-}
-
-- (BOOL)isFlipped
-{
- return YES;
-}
-
-- (BOOL)acceptsFirstResponder
-{
- return YES;
-}
-
-// this will have the Area receive a click that switches to the Window it is in from another one
-- (BOOL)acceptsFirstMouse:(NSEvent *)e
-{
- return YES;
-}
-
-- (void)retrack
-{
- self->trackingArea = [[NSTrackingArea alloc]
- initWithRect:[self bounds]
- // this bit mask (except for NSTrackingInVisibleRect, which was added later to prevent events from being triggered outside the visible area of the Area) comes from https://github.com/andlabs/misctestprogs/blob/master/cocoaviewmousetest.m (and I wrote this bit mask on 25 april 2014) and yes I know it includes enter/exit even though we don't watch those events; it probably won't really matter anyway but if it does I can change it easily
- options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag | NSTrackingInVisibleRect)
- owner:self
- userInfo:nil];
- [self addTrackingArea:self->trackingArea];
-}
-
-- (void)updateTrackingAreas
-{
- [self removeTrackingArea:self->trackingArea];
- [self->trackingArea release];
- [self retrack];
-}
-
-#define event(m, f) \
- - (void)m:(NSEvent *)e \
- { \
- f(self, e, self->goarea); \
- }
-event(mouseMoved, areaView_mouseMoved_mouseDragged)
-event(mouseDragged, areaView_mouseMoved_mouseDragged)
-event(rightMouseDragged, areaView_mouseMoved_mouseDragged)
-event(otherMouseDragged, areaView_mouseMoved_mouseDragged)
-event(mouseDown, areaView_mouseDown)
-event(rightMouseDown, areaView_mouseDown)
-event(otherMouseDown, areaView_mouseDown)
-event(mouseUp, areaView_mouseUp)
-event(rightMouseUp, areaView_mouseUp)
-event(otherMouseUp, areaView_mouseUp)
-
-#define retevent(m, f) \
- - (BOOL)m:(NSEvent *)e \
- { \
- return f(self, e, self->goarea); \
- }
-retevent(doKeyDown, areaView_keyDown)
-retevent(doKeyUp, areaView_keyUp)
-retevent(doFlagsChanged, areaView_flagsChanged)
-
-// seems to be triggered when the user would have finished editing the NSTextField anyway according to the system's rules on that (at least on Mountain Lion)
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
- areaTextFieldDismissed(self->goarea);
- [toNSObject(object) removeObserver:self forKeyPath:@"firstResponder"];
-}
-
-@end
-
-Class getAreaClass(void)
-{
- return [goAreaView class];
-}
-
-id newArea(void *goarea)
-{
- goAreaView *a;
-
- a = [[goAreaView alloc] initWithFrame:NSZeroRect];
- a->goarea = goarea;
- return (id) a;
-}
-
-BOOL drawImage(void *pixels, intptr_t width, intptr_t height, intptr_t stride, intptr_t xdest, intptr_t ydest)
-{
- unsigned char *planes[1]; // NSBitmapImageRep wants an array of planes; we have one plane
- NSBitmapImageRep *bitmap;
- BOOL success;
-
- planes[0] = (unsigned char *) pixels;
- bitmap = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:planes
- pixelsWide:toNSInteger(width)
- pixelsHigh:toNSInteger(height)
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- // NSCalibratedRGBColorSpace changes the colors; let's not
- // thanks to JtRip in irc.freenode.net/#macdev
- colorSpaceName:NSDeviceRGBColorSpace
- bitmapFormat:0 // this is where the flag for placing alpha first would go if alpha came first; the default is alpha last, which is how we're doing things (otherwise the docs say "Color planes are arranged in the standard order—for example, red before green before blue for RGB color."); this is also where the flag for non-premultiplied colors would go if we used it (the default is alpha-premultiplied)
- bytesPerRow:toNSInteger(stride)
- bitsPerPixel:32];
- success = [bitmap drawInRect:NSMakeRect((CGFloat) xdest, (CGFloat) ydest, (CGFloat) width, (CGFloat) height)
- fromRect:NSZeroRect // draw whole image
- operation:NSCompositeSourceOver
- fraction:1.0
- respectFlipped:YES
- hints:nil];
- [bitmap release];
- return success;
-}
-
-// can't include the header file with these from the Go side since it's an Objective-C header file; keep them here to be safe
-const uintptr_t cNSShiftKeyMask = (uintptr_t) NSShiftKeyMask;
-const uintptr_t cNSControlKeyMask = (uintptr_t) NSControlKeyMask;
-const uintptr_t cNSAlternateKeyMask = (uintptr_t) NSAlternateKeyMask;
-const uintptr_t cNSCommandKeyMask = (uintptr_t) NSCommandKeyMask;
-
-uintptr_t modifierFlags(id e)
-{
- return fromNSUInteger([toNSEvent(e) modifierFlags]);
-}
-
-struct xpoint getTranslatedEventPoint(id area, id e)
-{
- NSPoint p;
- struct xpoint q;
-
- p = [toNSView(area) convertPoint:[toNSEvent(e) locationInWindow] fromView:nil];
- q.x = (intptr_t) p.x;
- q.y = (intptr_t) p.y;
- return q;
-}
-
-intptr_t buttonNumber(id e)
-{
- return fromNSInteger([toNSEvent(e) buttonNumber]);
-}
-
-intptr_t clickCount(id e)
-{
- return fromNSInteger([toNSEvent(e) clickCount]);
-}
-
-uintptr_t pressedMouseButtons(void)
-{
- return fromNSUInteger([NSEvent pressedMouseButtons]);
-}
-
-uintptr_t keyCode(id e)
-{
- return (uintptr_t) ([toNSEvent(e) keyCode]);
-}
-
-void areaRepaint(id view, struct xrect r)
-{
- NSRect s;
-
- s.origin.x = (CGFloat) r.x;
- s.origin.y = (CGFloat) r.y;
- s.size.width = (CGFloat) r.width;
- s.size.height = (CGFloat) r.height;
- [toNSView(view) displayRect:s];
-}
-
-void areaRepaintAll(id view)
-{
- [toNSView(view) display];
-}
-
-void areaSetTextField(id area, id textfield)
-{
- goAreaView *a = (goAreaView *) area;
- NSTextField *tf = toNSTextField(textfield);
-
- [a addSubview:tf];
-}
-
-void areaTextFieldOpen(id area, id textfield, intptr_t x, intptr_t y)
-{
- goAreaView *a = (goAreaView *) area;
- NSTextField *tf = toNSTextField(textfield);
-
- // see TextField.preferredSize() in textfield_darwin.go
- [tf sizeToFit];
- [tf setFrameSize:NSMakeSize(textfieldWidth, [tf frame].size.height)];
- [tf setFrameOrigin:NSMakePoint((CGFloat) x, (CGFloat) y)];
- [tf setHidden:NO];
- [[tf window] makeFirstResponder:tf];
- [[tf window] addObserver:a forKeyPath:@"firstResponder" options:NSKeyValueObservingOptionNew context:NULL];
-}
diff --git a/redo/area_unix.go b/redo/area_unix.go
deleted file mode 100644
index 3c88f52..0000000
--- a/redo/area_unix.go
+++ /dev/null
@@ -1,520 +0,0 @@
-// +build !windows,!darwin,!plan9
-
-// 14 march 2014
-
-package ui
-
-import (
- "fmt"
- "image"
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern gboolean our_area_get_child_position_callback(GtkOverlay *, GtkWidget *, GdkRectangle *, gpointer);
-// extern void our_area_textfield_populate_popup_callback(GtkEntry *, GtkMenu *, gpointer);
-// extern gboolean our_area_textfield_focus_out_event_callback(GtkWidget *, GdkEvent *, gpointer);
-// extern gboolean our_area_draw_callback(GtkWidget *, cairo_t *, gpointer);
-// extern gboolean our_area_button_press_event_callback(GtkWidget *, GdkEvent *, gpointer);
-// extern gboolean our_area_button_release_event_callback(GtkWidget *, GdkEvent *, gpointer);
-// extern gboolean our_area_motion_notify_event_callback(GtkWidget *, GdkEvent *, gpointer);
-// extern gboolean our_area_enterleave_notify_event_callback(GtkWidget *, GdkEvent *, gpointer);
-// extern gboolean our_area_key_press_event_callback(GtkWidget *, GdkEvent *, gpointer);
-// extern gboolean our_area_key_release_event_callback(GtkWidget *, GdkEvent *, gpointer);
-// /* because cgo doesn't like ... */
-// static inline void gtkGetDoubleClickSettings(GtkSettings *settings, gint *maxTime, gint *maxDistance)
-// {
-// g_object_get(settings,
-// "gtk-double-click-time", maxTime,
-// "gtk-double-click-distance", maxDistance,
-// NULL);
-// }
-import "C"
-
-type area struct {
- *areabase
-
- _widget *C.GtkWidget
- drawingarea *C.GtkDrawingArea
- scroller *scroller
-
- clickCounter *clickCounter
-
- textfieldw *C.GtkWidget
- textfield *C.GtkEntry
- textfieldx int
- textfieldy int
- textfielddone *event
- inmenu bool
-}
-
-func newArea(ab *areabase) Area {
- widget := C.gtk_drawing_area_new()
- // the Area's size will be set later
- // we need to explicitly subscribe to mouse events with GtkDrawingArea
- C.gtk_widget_add_events(widget,
- C.GDK_BUTTON_PRESS_MASK|C.GDK_BUTTON_RELEASE_MASK|C.GDK_POINTER_MOTION_MASK|C.GDK_BUTTON_MOTION_MASK|C.GDK_ENTER_NOTIFY_MASK|C.GDK_LEAVE_NOTIFY_MASK)
- // and we need to allow focusing on a GtkDrawingArea to enable keyboard events
- 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(),
- }
- for _, c := range areaCallbacks {
- g_signal_connect(
- C.gpointer(unsafe.Pointer(a.drawingarea)),
- c.name,
- c.callback,
- C.gpointer(unsafe.Pointer(a)))
- }
- a.SetSize(a.width, a.height)
- C.gtk_overlay_add_overlay(a.scroller.overlay, a.textfieldw)
- g_signal_connect(
- C.gpointer(unsafe.Pointer(a.scroller.overlay)),
- "get-child-position",
- area_get_child_position_callback,
- C.gpointer(unsafe.Pointer(a)))
- // this part is important
- // entering the context menu is considered focusing out
- // so we connect to populate-popup to mark that we're entering the context menu (thanks slaf in irc.gimp.net/#gtk+)
- // and we have to connect_after to focus-out-event so that it runs after the populate-popup
- g_signal_connect(
- C.gpointer(unsafe.Pointer(a.textfield)),
- "populate-popup",
- area_textfield_populate_popup_callback,
- C.gpointer(unsafe.Pointer(a)))
- g_signal_connect_after(
- C.gpointer(unsafe.Pointer(a.textfield)),
- "focus-out-event",
- area_textfield_focus_out_event_callback,
- C.gpointer(unsafe.Pointer(a)))
- // the widget shows up initially
- C.gtk_widget_set_no_show_all(a.textfieldw, C.TRUE)
- return a
-}
-
-func (a *area) SetSize(width, height int) {
- a.width = width
- a.height = height
- C.gtk_widget_set_size_request(a._widget, C.gint(a.width), C.gint(a.height))
-}
-
-func (a *area) Repaint(r image.Rectangle) {
- r = image.Rect(0, 0, a.width, a.height).Intersect(r)
- if r.Empty() {
- return
- }
-println(a._widget, C.gint(r.Min.X), C.gint(r.Min.Y), C.gint(r.Dx()), C.gint(r.Dy()))
- C.gtk_widget_queue_draw_area(a._widget, C.gint(r.Min.X), C.gint(r.Min.Y), C.gint(r.Dx()), C.gint(r.Dy()))
-}
-
-func (a *area) RepaintAll() {
- C.gtk_widget_queue_draw(a._widget)
-}
-
-func (a *area) OpenTextFieldAt(x, y int) {
- if x < 0 || x >= a.width || y < 0 || y >= a.height {
- panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
- }
- a.textfieldx = x
- a.textfieldy = y
- 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)
- C.gtk_widget_grab_focus(a.textfieldw)
-}
-
-func (a *area) TextFieldText() string {
- return fromgstr(C.gtk_entry_get_text(a.textfield))
-}
-
-func (a *area) SetTextFieldText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_entry_set_text(a.textfield, ctext)
-}
-
-func (a *area) OnTextFieldDismissed(f func()) {
- a.textfielddone.set(f)
-}
-
-//export our_area_get_child_position_callback
-func our_area_get_child_position_callback(overlay *C.GtkOverlay, widget *C.GtkWidget, rect *C.GdkRectangle, data C.gpointer) C.gboolean {
- var nat C.GtkRequisition
-
- a := (*area)(unsafe.Pointer(data))
- rect.x = C.int(a.textfieldx)
- rect.y = C.int(a.textfieldy)
- C.gtk_widget_get_preferred_size(a.textfieldw, nil, &nat)
- rect.width = C.int(nat.width)
- rect.height = C.int(nat.height)
- return C.TRUE
-}
-
-var area_get_child_position_callback = C.GCallback(C.our_area_get_child_position_callback)
-
-//export our_area_textfield_populate_popup_callback
-func our_area_textfield_populate_popup_callback(entry *C.GtkEntry, menu *C.GtkMenu, data C.gpointer) {
- a := (*area)(unsafe.Pointer(data))
- a.inmenu = true
-}
-
-var area_textfield_populate_popup_callback = C.GCallback(C.our_area_textfield_populate_popup_callback)
-
-//export our_area_textfield_focus_out_event_callback
-func our_area_textfield_focus_out_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- a := (*area)(unsafe.Pointer(data))
- if !a.inmenu {
- C.gtk_widget_hide(a.textfieldw)
- a.textfielddone.fire()
- }
- 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
-}{
- { "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
-func our_area_draw_callback(widget *C.GtkWidget, cr *C.cairo_t, data C.gpointer) C.gboolean {
- var x0, y0, x1, y1 C.double
-
- a := (*area)(unsafe.Pointer(data))
- // thanks to desrt in irc.gimp.net/#gtk+
- // these are in user coordinates, which match what coordinates we want by default, even out of a draw event handler (thanks johncc3, mclasen, and Company in irc.gimp.net/#gtk+)
- C.cairo_clip_extents(cr, &x0, &y0, &x1, &y1)
- // we do not need to clear the cliprect; GtkDrawingArea did it for us beforehand
- cliprect := image.Rect(int(x0), int(y0), int(x1), int(y1))
- // the cliprect can actually fall outside the size of the Area; clip it by intersecting the two rectangles
- cliprect = image.Rect(0, 0, a.width, a.height).Intersect(cliprect)
- if cliprect.Empty() { // no intersection; nothing to paint
- return C.FALSE // signals handled without stopping the event chain (thanks to desrt again)
- }
- i := a.handler.Paint(cliprect)
- surface := C.cairo_image_surface_create(
- C.CAIRO_FORMAT_ARGB32, // alpha-premultiplied; native byte order
- C.int(i.Rect.Dx()),
- C.int(i.Rect.Dy()))
- if status := C.cairo_surface_status(surface); status != C.CAIRO_STATUS_SUCCESS {
- panic(fmt.Errorf("cairo_create_image_surface() failed: %s\n",
- C.GoString(C.cairo_status_to_string(status))))
- }
- // 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
- 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+)
- // 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
- C.cairo_fill(cr)
- C.cairo_surface_destroy(surface) // free surface
- return C.FALSE // signals handled without stopping the event chain (thanks to desrt again)
-}
-
-var area_draw_callback = C.GCallback(C.our_area_draw_callback)
-
-func translateModifiers(state C.guint, window *C.GdkWindow) C.guint {
- // GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+)
- C.gdk_keymap_add_virtual_modifiers(
- C.gdk_keymap_get_for_display(C.gdk_window_get_display(window)),
- (*C.GdkModifierType)(unsafe.Pointer(&state)))
- return state
-}
-
-func makeModifiers(state C.guint) (m Modifiers) {
- if (state & C.GDK_CONTROL_MASK) != 0 {
- m |= Ctrl
- }
- 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)
- m |= Alt
- }
- if (state & C.GDK_SHIFT_MASK) != 0 {
- m |= Shift
- }
- if (state & C.GDK_SUPER_MASK) != 0 {
- m |= Super
- }
- return m
-}
-
-// shared code for finishing up and sending a mouse event
-func finishMouseEvent(widget *C.GtkWidget, data C.gpointer, me MouseEvent, mb uint, x C.gdouble, y C.gdouble, state C.guint, gdkwindow *C.GdkWindow) {
- var areawidth, areaheight C.gint
-
- // on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake
- if mb >= 4 && mb <= 7 {
- return
- }
- a := (*area)(unsafe.Pointer(data))
- state = translateModifiers(state, gdkwindow)
- me.Modifiers = makeModifiers(state)
- // the mb != # checks exclude the Up/Down button from Held
- if mb != 1 && (state&C.GDK_BUTTON1_MASK) != 0 {
- me.Held = append(me.Held, 1)
- }
- if mb != 2 && (state&C.GDK_BUTTON2_MASK) != 0 {
- me.Held = append(me.Held, 2)
- }
- if mb != 3 && (state&C.GDK_BUTTON3_MASK) != 0 {
- me.Held = append(me.Held, 3)
- }
- // don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those are for the scrolling buttons mentioned above
- // GDK expressly does not support any more buttons in the GdkModifierType; see https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkdevice-xi2.c#n763 (thanks mclasen in irc.gimp.net/#gtk+)
- me.Pos = image.Pt(int(x), int(y))
- C.gtk_widget_get_size_request(widget, &areawidth, &areaheight)
- if !me.Pos.In(image.Rect(0, 0, int(areawidth), int(areaheight))) { // outside the actual Area; no event
- return
- }
- // and finally, if the button ID >= 8, continue counting from 4, as above and as in the MouseEvent spec
- if me.Down >= 8 {
- me.Down -= 4
- }
- if me.Up >= 8 {
- me.Up -= 4
- }
- a.handler.Mouse(me)
-}
-
-// convenience name to make our intent clear
-const continueEventChain C.gboolean = C.FALSE
-const stopEventChain C.gboolean = C.TRUE
-
-// checking for a mouse click that makes the program/window active is meaningless on GTK+: it's a property of the window manager/X11, and it's the WM that decides if the program should become active or not
-// however, one thing is certain: the click event will ALWAYS be sent (to the window that the X11 decides to send it to)
-// I assume the same is true for Wayland
-// thanks Chipzz in irc.gimp.net/#gtk+
-
-//export our_area_button_press_event_callback
-func our_area_button_press_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- // clicking doesn't automatically transfer keyboard focus; we must do so manually (thanks tristan in irc.gimp.net/#gtk+)
- C.gtk_widget_grab_focus(widget)
- e := (*C.GdkEventButton)(unsafe.Pointer(event))
- me := MouseEvent{
- // GDK button ID == our button ID with some exceptions taken care of by finishMouseEvent()
- Down: uint(e.button),
- }
-
- var maxTime C.gint
- var maxDistance C.gint
-
- if e._type != C.GDK_BUTTON_PRESS {
- // ignore GDK's generated double-clicks and beyond; we handled those ourselves below
- return continueEventChain
- }
- a := (*area)(unsafe.Pointer(data))
- // e.time is unsigned and in milliseconds
- // maxTime is also milliseconds; despite being gint, it is only allowed to be positive
- // maxDistance is also only allowed to be positive
- settings := C.gtk_widget_get_settings(widget)
- C.gtkGetDoubleClickSettings(settings, &maxTime, &maxDistance)
- me.Count = a.clickCounter.click(me.Down, int(e.x), int(e.y),
- uintptr(e.time), uintptr(maxTime),
- int(maxDistance), int(maxDistance))
-
- finishMouseEvent(widget, data, me, me.Down, e.x, e.y, e.state, e.window)
- return continueEventChain
-}
-
-var area_button_press_event_callback = C.GCallback(C.our_area_button_press_event_callback)
-
-//export our_area_button_release_event_callback
-func our_area_button_release_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- e := (*C.GdkEventButton)(unsafe.Pointer(event))
- me := MouseEvent{
- // GDK button ID == our button ID with some exceptions taken care of by finishMouseEvent()
- Up: uint(e.button),
- }
- finishMouseEvent(widget, data, me, me.Up, e.x, e.y, e.state, e.window)
- return continueEventChain
-}
-
-var area_button_release_event_callback = C.GCallback(C.our_area_button_release_event_callback)
-
-//export our_area_motion_notify_event_callback
-func our_area_motion_notify_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- e := (*C.GdkEventMotion)(unsafe.Pointer(event))
- me := MouseEvent{}
- finishMouseEvent(widget, data, me, 0, e.x, e.y, e.state, e.window)
- return continueEventChain
-}
-
-var area_motion_notify_event_callback = C.GCallback(C.our_area_motion_notify_event_callback)
-
-// we want switching away from the control to reset the double-click counter, like with WM_ACTIVATE on Windows
-// according to tristan in irc.gimp.net/#gtk+, doing this on enter-notify-event and leave-notify-event is correct (and it seems to be true in my own tests; plus the events DO get sent when switching programs with the keyboard (just pointing that out))
-// differentiating between enter-notify-event and leave-notify-event is unimportant
-
-//export our_area_enterleave_notify_event_callback
-func our_area_enterleave_notify_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- a := (*area)(unsafe.Pointer(data))
- a.clickCounter.reset()
- return continueEventChain
-}
-
-var area_enterleave_notify_event_callback = C.GCallback(C.our_area_enterleave_notify_event_callback)
-
-// shared code for doing a key event
-func doKeyEvent(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer, up bool) bool {
- var ke KeyEvent
-
- e := (*C.GdkEventKey)(unsafe.Pointer(event))
- a := (*area)(unsafe.Pointer(data))
- keyval := e.keyval
- // get modifiers now in case a modifier was pressed
- state := translateModifiers(e.state, e.window)
- ke.Modifiers = makeModifiers(state)
- if extkey, ok := extkeys[keyval]; ok {
- ke.ExtKey = extkey
- } else if mod, ok := modonlykeys[keyval]; ok {
- ke.Modifier = mod
- // don't include the modifier in ke.Modifiers
- ke.Modifiers &^= mod
- } else if xke, ok := fromScancode(uintptr(e.hardware_keycode) - 8); ok {
- // see events_notdarwin.go for details of the above map lookup
- // one of these will be nonzero
- ke.Key = xke.Key
- ke.ExtKey = xke.ExtKey
- } else { // no match
- return false
- }
- ke.Up = up
- return a.handler.Key(ke)
-}
-
-//export our_area_key_press_event_callback
-func our_area_key_press_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- if doKeyEvent(widget, event, data, false) == true {
- return stopEventChain
- }
- return continueEventChain
-}
-
-var area_key_press_event_callback = C.GCallback(C.our_area_key_press_event_callback)
-
-//export our_area_key_release_event_callback
-func our_area_key_release_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- if doKeyEvent(widget, event, data, true) == true {
- return stopEventChain
- }
- return continueEventChain
-}
-
-var area_key_release_event_callback = C.GCallback(C.our_area_key_release_event_callback)
-
-var extkeys = map[C.guint]ExtKey{
- C.GDK_KEY_Escape: Escape,
- C.GDK_KEY_Insert: Insert,
- C.GDK_KEY_Delete: Delete,
- C.GDK_KEY_Home: Home,
- C.GDK_KEY_End: End,
- C.GDK_KEY_Page_Up: PageUp,
- C.GDK_KEY_Page_Down: PageDown,
- C.GDK_KEY_Up: Up,
- C.GDK_KEY_Down: Down,
- C.GDK_KEY_Left: Left,
- C.GDK_KEY_Right: Right,
- C.GDK_KEY_F1: F1,
- C.GDK_KEY_F2: F2,
- C.GDK_KEY_F3: F3,
- C.GDK_KEY_F4: F4,
- C.GDK_KEY_F5: F5,
- C.GDK_KEY_F6: F6,
- C.GDK_KEY_F7: F7,
- C.GDK_KEY_F8: F8,
- C.GDK_KEY_F9: F9,
- C.GDK_KEY_F10: F10,
- C.GDK_KEY_F11: F11,
- C.GDK_KEY_F12: F12,
- // numpad numeric keys and . are handled in events_notdarwin.go
- C.GDK_KEY_KP_Enter: NEnter,
- C.GDK_KEY_KP_Add: NAdd,
- C.GDK_KEY_KP_Subtract: NSubtract,
- C.GDK_KEY_KP_Multiply: NMultiply,
- C.GDK_KEY_KP_Divide: NDivide,
-}
-
-// sanity check
-func init() {
- included := make([]bool, _nextkeys)
- for _, v := range extkeys {
- included[v] = true
- }
- for i := 1; i < int(_nextkeys); i++ {
- if i >= int(N0) && i <= int(N9) { // skip numpad numbers and .
- continue
- }
- if i == int(NDot) {
- continue
- }
- if !included[i] {
- panic(fmt.Errorf("error: not all ExtKeys defined on Unix (missing %d)", i))
- }
- }
-}
-
-var modonlykeys = map[C.guint]Modifiers{
- C.GDK_KEY_Control_L: Ctrl,
- C.GDK_KEY_Control_R: Ctrl,
- C.GDK_KEY_Alt_L: Alt,
- C.GDK_KEY_Alt_R: Alt,
- C.GDK_KEY_Meta_L: Alt,
- C.GDK_KEY_Meta_R: Alt,
- C.GDK_KEY_Shift_L: Shift,
- C.GDK_KEY_Shift_R: Shift,
- C.GDK_KEY_Super_L: Super,
- C.GDK_KEY_Super_R: Super,
-}
-
-func (a *area) widget() *C.GtkWidget {
- return a._widget
-}
-
-func (a *area) setParent(p *controlParent) {
- a.scroller.setParent(p)
-}
-
-func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(a, x, y, width, height, d)
-}
-
-func (a *area) preferredSize(d *sizing) (width, height int) {
- // the preferred size of an Area is its size
- return a.width, a.height
-}
-
-func (a *area) commitResize(c *allocation, d *sizing) {
- a.scroller.commitResize(c, d)
-}
-
-func (a *area) getAuxResizeInfo(d *sizing) {
- // a Label to the left of an Area should be vertically aligned to the top
- d.shouldVAlignTop = true
-}
diff --git a/redo/area_windows.c b/redo/area_windows.c
deleted file mode 100644
index b8f1235..0000000
--- a/redo/area_windows.c
+++ /dev/null
@@ -1,500 +0,0 @@
-// 24 march 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-static void getScrollPos(HWND hwnd, int *xpos, int *ypos)
-{
- SCROLLINFO si;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS | SIF_TRACKPOS;
- if (GetScrollInfo(hwnd, SB_HORZ, &si) == 0)
- xpanic("error getting horizontal scroll position for Area", GetLastError());
- *xpos = si.nPos;
- // MSDN example code reinitializes this each time, so we'll do it too just to be safe
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS | SIF_TRACKPOS;
- if (GetScrollInfo(hwnd, SB_VERT, &si) == 0)
- xpanic("error getting vertical scroll position for Area", GetLastError());
- *ypos = si.nPos;
-}
-
-#define areaBackgroundBrush ((HBRUSH) (COLOR_BTNFACE + 1))
-
-static void paintArea(HWND hwnd, void *data)
-{
- RECT xrect;
- PAINTSTRUCT ps;
- HDC hdc;
- HDC rdc;
- HBITMAP rbitmap, prevrbitmap;
- RECT rrect;
- BITMAPINFO bi;
- VOID *ppvBits;
- HBITMAP ibitmap;
- HDC idc;
- HBITMAP previbitmap;
- BLENDFUNCTION blendfunc;
- void *i;
- intptr_t dx, dy;
- int hscroll, vscroll;
-
- // FALSE here indicates don't send WM_ERASEBKGND
- if (GetUpdateRect(hwnd, &xrect, FALSE) == 0)
- return; // no update rect; do nothing
-
- getScrollPos(hwnd, &hscroll, &vscroll);
-
- hdc = BeginPaint(hwnd, &ps);
- if (hdc == NULL)
- xpanic("error beginning Area repaint", GetLastError());
-
- // very big thanks to Ninjifox for suggesting this technique and helping me go through it
-
- // first let's create the destination image, which we fill with the windows background color
- // this is how we fake drawing the background; see also http://msdn.microsoft.com/en-us/library/ms969905.aspx
- rdc = CreateCompatibleDC(hdc);
- if (rdc == NULL)
- xpanic("error creating off-screen rendering DC", GetLastError());
- // the bitmap has to be compatible with the window
- // if we create a bitmap compatible with the DC we just created, it'll be monochrome
- // thanks to David Heffernan in http://stackoverflow.com/questions/23033636/winapi-gdi-fillrectcolor-btnface-fills-with-strange-grid-like-brush-on-window
- rbitmap = CreateCompatibleBitmap(hdc, xrect.right - xrect.left, xrect.bottom - xrect.top);
- if (rbitmap == NULL)
- xpanic("error creating off-screen rendering bitmap", GetLastError());
- prevrbitmap = (HBITMAP) SelectObject(rdc, rbitmap);
- if (prevrbitmap == NULL)
- xpanic("error connecting off-screen rendering bitmap to off-screen rendering DC", GetLastError());
- rrect.left = 0;
- rrect.right = xrect.right - xrect.left;
- rrect.top = 0;
- rrect.bottom = xrect.bottom - xrect.top;
- if (FillRect(rdc, &rrect, areaBackgroundBrush) == 0)
- xpanic("error filling off-screen rendering bitmap with the system background color", GetLastError());
-
- i = doPaint(&xrect, hscroll, vscroll, data, &dx, &dy);
- if (i == NULL) // cliprect empty
- goto nobitmap; // we need to blit the background no matter what
-
- // now we need to shove realbits into a bitmap
- // technically bitmaps don't know about alpha; they just ignore the alpha byte
- // AlphaBlend(), however, sees it - see http://msdn.microsoft.com/en-us/library/windows/desktop/dd183352%28v=vs.85%29.aspx
- ZeroMemory(&bi, sizeof (BITMAPINFO));
- bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
- bi.bmiHeader.biWidth = (LONG) dx;
- bi.bmiHeader.biHeight = -((LONG) dy); // negative height to force top-down drawing;
- bi.bmiHeader.biPlanes = 1;
- bi.bmiHeader.biBitCount = 32;
- bi.bmiHeader.biCompression = BI_RGB;
- bi.bmiHeader.biSizeImage = (DWORD) (dx * dy * 4);
- // this is all we need, but because this confused me at first, I will say the two pixels-per-meter fields are unused (see http://blogs.msdn.com/b/oldnewthing/archive/2013/05/15/10418646.aspx and page 581 of Charles Petzold's Programming Windows, Fifth Edition)
- // now for the trouble: CreateDIBSection() allocates the memory for us...
- ibitmap = CreateDIBSection(NULL, // Ninjifox does this, so do some wine tests (http://source.winehq.org/source/dlls/gdi32/tests/bitmap.c#L725, thanks vpovirk in irc.freenode.net/#winehackers) and even Raymond Chen (http://blogs.msdn.com/b/oldnewthing/archive/2006/11/16/1086835.aspx), so.
- &bi, DIB_RGB_COLORS, &ppvBits, 0, 0);
- if (ibitmap == NULL)
- xpanic("error creating HBITMAP for image returned by AreaHandler.Paint()", GetLastError());
-
- // now we have to do TWO MORE things before we can finally do alpha blending
- // first, we need to load the bitmap memory, because Windows makes it for us
- // the pixels are arranged in RGBA order, but GDI requires BGRA
- // this turns out to be just ARGB in little endian; let's convert into this memory
- dotoARGB(i, (void *) ppvBits, FALSE); // FALSE = not NRGBA
-
- // the second thing is... make a device context for the bitmap :|
- // Ninjifox just makes another compatible DC; we'll do the same
- idc = CreateCompatibleDC(hdc);
- if (idc == NULL)
- xpanic("error creating HDC for image returned by AreaHandler.Paint()", GetLastError());
- previbitmap = (HBITMAP) SelectObject(idc, ibitmap);
- if (previbitmap == NULL)
- xpanic("error connecting HBITMAP for image returned by AreaHandler.Paint() to its HDC", GetLastError());
-
- // AND FINALLY WE CAN DO THE ALPHA BLENDING!!!!!!111
- blendfunc.BlendOp = AC_SRC_OVER;
- blendfunc.BlendFlags = 0;
- blendfunc.SourceConstantAlpha = 255; // only use per-pixel alphas
- blendfunc.AlphaFormat = AC_SRC_ALPHA; // premultiplied
- if (AlphaBlend(rdc, 0, 0, (int) dx, (int) dy, // destination
- idc, 0, 0, (int) dx, (int)dy, // source
- blendfunc) == FALSE)
- xpanic("error alpha-blending image returned by AreaHandler.Paint() onto background", GetLastError());
-
- // clean up after idc/ibitmap here because of the goto nobitmap
- if (SelectObject(idc, previbitmap) != ibitmap)
- xpanic("error reverting HDC for image returned by AreaHandler.Paint() to original HBITMAP", GetLastError());
- if (DeleteObject(ibitmap) == 0)
- xpanic("error deleting HBITMAP for image returned by AreaHandler.Paint()", GetLastError());
- if (DeleteDC(idc) == 0)
- xpanic("error deleting HDC for image returned by AreaHandler.Paint()", GetLastError());
-
-nobitmap:
- // and finally we can just blit that into the window
- if (BitBlt(hdc, xrect.left, xrect.top, xrect.right - xrect.left, xrect.bottom - xrect.top,
- rdc, 0, 0, // from the rdc's origin
- SRCCOPY) == 0)
- xpanic("error blitting Area image to Area", GetLastError());
-
- // now to clean up
- if (SelectObject(rdc, prevrbitmap) != rbitmap)
- xpanic("error reverting HDC for off-screen rendering to original HBITMAP", GetLastError());
- if (DeleteObject(rbitmap) == 0)
- xpanic("error deleting HBITMAP for off-screen rendering", GetLastError());
- if (DeleteDC(rdc) == 0)
- xpanic("error deleting HDC for off-screen rendering", GetLastError());
-
- EndPaint(hwnd, &ps);
-}
-
-static SIZE getAreaControlSize(HWND hwnd)
-{
- RECT rect;
- SIZE size;
-
- if (GetClientRect(hwnd, &rect) == 0)
- xpanic("error getting size of actual Area control", GetLastError());
- size.cx = (LONG) (rect.right - rect.left);
- size.cy = (LONG) (rect.bottom - rect.top);
- return size;
-}
-
-static void scrollArea(HWND hwnd, void *data, WPARAM wParam, int which)
-{
- SCROLLINFO si;
- SIZE size;
- LONG cwid, cht;
- LONG pagesize, maxsize;
- LONG newpos;
- LONG delta;
- LONG dx, dy;
-
- size = getAreaControlSize(hwnd);
- cwid = size.cx;
- cht = size.cy;
- if (which == SB_HORZ) {
- pagesize = cwid;
- maxsize = areaWidthLONG(data);
- } else if (which == SB_VERT) {
- pagesize = cht;
- maxsize = areaHeightLONG(data);
- } else
- xpanic("invalid which sent to scrollArea()", 0);
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS | SIF_TRACKPOS;
- if (GetScrollInfo(hwnd, which, &si) == 0)
- xpanic("error getting current scroll position for scrolling", GetLastError());
-
- newpos = (LONG) si.nPos;
- switch (LOWORD(wParam)) {
- case SB_LEFT: // also SB_TOP; C won't let me have both (C89 §6.6.4.2; C99 §6.8.4.2)
- newpos = 0;
- break;
- case SB_RIGHT: // also SB_BOTTOM
- // see comment in adjustAreaScrollbars() below
- newpos = maxsize - pagesize;
- break;
- case SB_LINELEFT: // also SB_LINEUP
- newpos--;
- break;
- case SB_LINERIGHT: // also SB_LINEDOWN
- newpos++;
- break;
- case SB_PAGELEFT: // also SB_PAGEUP
- newpos -= pagesize;
- break;
- case SB_PAGERIGHT: // also SB_PAGEDOWN
- newpos += pagesize;
- break;
- case SB_THUMBPOSITION:
- // raymond chen says to just set the newpos to the SCROLLINFO nPos for this message; see http://blogs.msdn.com/b/oldnewthing/archive/2003/07/31/54601.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/08/05/54602.aspx
- // do nothing here; newpos already has nPos
- break;
- case SB_THUMBTRACK:
- newpos = (LONG) si.nTrackPos;
- }
- // otherwise just keep the current position (that's what MSDN example code says, anyway)
-
- // make sure we're not out of range
- if (newpos < 0)
- newpos = 0;
- if (newpos > (maxsize - pagesize))
- newpos = maxsize - pagesize;
-
- // this would be where we would put a check to not scroll if the scroll position changed, but see the note about SB_THUMBPOSITION above: Raymond Chen's code always does the scrolling anyway in this case
-
- delta = -(newpos - si.nPos); // negative because ScrollWindowEx() scrolls in the opposite direction
- dx = delta;
- dy = 0;
- if (which == SB_VERT) {
- dx = 0;
- dy = delta;
- }
-
- // this automatically scrolls the edit control, if any
- if (ScrollWindowEx(hwnd,
- (int) dx, (int) dy,
- // these four change what is scrolled and record info about the scroll; we're scrolling the whole client area and don't care about the returned information here
- NULL, NULL, NULL, NULL,
- // mark the remaining rect as needing redraw and erase...
- SW_INVALIDATE | SW_ERASE) == ERROR)
- xpanic("error scrolling Area", GetLastError());
- // ...but don't redraw the window yet; we need to apply our scroll changes
-
- // we actually have to commit the change back to the scrollbar; otherwise the scroll position will merely reset itself
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS;
- si.nPos = (int) newpos;
- // this is not expressly documented as returning an error so IDK what the error code is so assume there is none
- SetScrollInfo(hwnd, which, &si, TRUE); // redraw scrollbar
-
- // NOW redraw it
- if (UpdateWindow(hwnd) == 0)
- xpanic("error updating Area after scrolling", GetLastError());
- if ((HWND) GetWindowLongPtrW(hwnd, 0) != NULL)
- if (UpdateWindow((HWND) GetWindowLongPtrW(hwnd, 0)) == 0)
- xpanic("error updating Area TextField after scrolling", GetLastError());
-}
-
-static void adjustAreaScrollbars(HWND hwnd, void *data)
-{
- SCROLLINFO si;
- SIZE size;
- LONG cwid, cht;
-
- size = getAreaControlSize(hwnd);
- cwid = size.cx;
- cht = size.cy;
-
- // the trick is we want a page to be the width/height of the visible area
- // so the scroll range would go from [0..image_dimension - control_dimension]
- // but judging from the sample code on MSDN, we don't need to do this; the scrollbar will do it for us
- // we DO need to handle it when scrolling, though, since the thumb can only go up to this upper limit
-
- // have to do horizontal and vertical separately
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_RANGE | SIF_PAGE;
- si.nMin = 0;
- si.nMax = (int) (areaWidthLONG(data) - 1); // the max point is inclusive, so we have to pass in the last valid value, not the first invalid one (see http://blogs.msdn.com/b/oldnewthing/archive/2003/07/31/54601.aspx); if we don't, we get weird things like the scrollbar sometimes showing one extra scroll position at the end that you can never scroll to
- si.nPage = (UINT) cwid;
- SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); // redraw the scroll bar
-
- // MSDN sample code does this a second time; let's do it too to be safe
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_RANGE | SIF_PAGE;
- si.nMin = 0;
- si.nMax = (int) (areaHeightLONG(data) - 1);
- si.nPage = (UINT) cht;
- SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
-}
-
-void repaintArea(HWND hwnd, RECT *r)
-{
- // NULL - the whole area; TRUE - have windows erase if possible
- if (InvalidateRect(hwnd, r, TRUE) == 0)
- xpanic("error flagging Area as needing repainting after event", GetLastError());
- if (UpdateWindow(hwnd) == 0)
- xpanic("error repainting Area after event", GetLastError());
-}
-
-void areaMouseEvent(HWND hwnd, void *data, DWORD button, BOOL up, uintptr_t heldButtons, LPARAM lParam)
-{
- int xpos, ypos;
-
- // mouse coordinates are relative to control; make them relative to Area
- getScrollPos(hwnd, &xpos, &ypos);
- xpos += GET_X_LPARAM(lParam);
- ypos += GET_Y_LPARAM(lParam);
- finishAreaMouseEvent(data, button, up, heldButtons, xpos, ypos);
-}
-
-static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- void *data;
- DWORD which;
- uintptr_t heldButtons = (uintptr_t) wParam;
- LRESULT lResult;
-
- data = getWindowData(hwnd, uMsg, wParam, lParam, &lResult, storeAreaHWND);
- if (data == NULL)
- return lResult;
- switch (uMsg) {
- case WM_PAINT:
- paintArea(hwnd, data);
- return 0;
- case WM_ERASEBKGND:
- // don't draw a background; we'll do so when painting
- // this is to make things flicker-free; see http://msdn.microsoft.com/en-us/library/ms969905.aspx
- return 1;
- case WM_HSCROLL:
- scrollArea(hwnd, data, wParam, SB_HORZ);
- return 0;
- case WM_VSCROLL:
- scrollArea(hwnd, data, wParam, SB_VERT);
- return 0;
- case WM_SIZE:
- adjustAreaScrollbars(hwnd, data);
- return 0;
- case WM_ACTIVATE:
- // don't keep the double-click timer running if the user switched programs in between clicks
- areaResetClickCounter(data);
- return 0;
- case WM_MOUSEMOVE:
- areaMouseEvent(hwnd, data, 0, FALSE, heldButtons, lParam);
- return 0;
- case WM_LBUTTONDOWN:
- SetFocus(hwnd);
- areaMouseEvent(hwnd, data, 1, FALSE, heldButtons, lParam);
- return 0;
- case WM_LBUTTONUP:
- areaMouseEvent(hwnd, data, 1, TRUE, heldButtons, lParam);
- return 0;
- case WM_MBUTTONDOWN:
- SetFocus(hwnd);
- areaMouseEvent(hwnd, data, 2, FALSE, heldButtons, lParam);
- return 0;
- case WM_MBUTTONUP:
- areaMouseEvent(hwnd, data, 2, TRUE, heldButtons, lParam);
- return 0;
- case WM_RBUTTONDOWN:
- SetFocus(hwnd);
- areaMouseEvent(hwnd, data, 3, FALSE, heldButtons, lParam);
- return 0;
- case WM_RBUTTONUP:
- areaMouseEvent(hwnd, data, 3, TRUE, heldButtons, lParam);
- return 0;
- case WM_XBUTTONDOWN:
- SetFocus(hwnd);
- // values start at 1; we want them to start at 4
- which = (DWORD) GET_XBUTTON_WPARAM(wParam) + 3;
- heldButtons = (uintptr_t) GET_KEYSTATE_WPARAM(wParam);
- areaMouseEvent(hwnd, data, which, FALSE, heldButtons, lParam);
- return TRUE; // XBUTTON messages are different!
- case WM_XBUTTONUP:
- which = (DWORD) GET_XBUTTON_WPARAM(wParam) + 3;
- heldButtons = (uintptr_t) GET_KEYSTATE_WPARAM(wParam);
- areaMouseEvent(hwnd, data, which, TRUE, heldButtons, lParam);
- return TRUE;
- case msgAreaKeyDown:
- return (LRESULT) areaKeyEvent(data, FALSE, wParam, lParam);
- case msgAreaKeyUp:
- return (LRESULT) areaKeyEvent(data, TRUE, wParam, lParam);
- case msgAreaSizeChanged:
- adjustAreaScrollbars(hwnd, data);
- repaintArea(hwnd, NULL); // this calls for an update
- return 0;
- case msgAreaGetScroll:
- getScrollPos(hwnd, (int *) wParam, (int *) lParam);
- return 0;
- case msgAreaRepaint:
- repaintArea(hwnd, (RECT *) lParam);
- return 0;
- case msgAreaRepaintAll:
- repaintArea(hwnd, NULL);
- return 0;
- default:
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("Area", "areaWndProc()", uMsg);
- return 0; // unreached
-}
-
-DWORD makeAreaWindowClass(char **errmsg)
-{
- WNDCLASSW wc;
-
- ZeroMemory(&wc, sizeof (WNDCLASSW));
- wc.style = CS_HREDRAW | CS_VREDRAW; // no CS_DBLCLKS because do that manually
- wc.lpszClassName = areaWindowClass;
- wc.lpfnWndProc = areaWndProc;
- wc.hInstance = hInstance;
- wc.hIcon = hDefaultIcon;
- wc.hCursor = hArrowCursor,
- wc.hbrBackground = NULL; // no brush; we handle WM_ERASEBKGND
- wc.cbWndExtra = 3 * sizeof (LONG_PTR); // text field handle, text field current x, text field current y
- if (RegisterClassW(&wc) == 0) {
- *errmsg = "error registering Area window class";
- return GetLastError();
- }
- return 0;
-}
-
-HWND newArea(void *data)
-{
- HWND hwnd;
-
- hwnd = CreateWindowExW(
- 0,
- areaWindowClass, L"",
- WS_HSCROLL | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 100, 100,
- msgwin, NULL, hInstance, data);
- if (hwnd == NULL)
- xpanic("container creation failed", GetLastError());
- return hwnd;
-}
-
-static LRESULT CALLBACK areaTextFieldSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
-{
- switch (uMsg) {
- case WM_KILLFOCUS:
- ShowWindow(hwnd, SW_HIDE);
- areaTextFieldDone((void *) data);
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_NCDESTROY:
- if ((*fv_RemoveWindowSubclass)(hwnd, areaTextFieldSubProc, id) == FALSE)
- xpanic("error removing Area TextField subclass (which was for handling WM_KILLFOCUS)", GetLastError());
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- default:
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("Area TextField", "areaTextFieldSubProc()", uMsg);
- return 0; // unreached
-}
-
-HWND newAreaTextField(HWND area, void *goarea)
-{
- HWND tf;
-
- tf = CreateWindowExW(textfieldExtStyle,
- L"edit", L"",
- textfieldStyle | WS_CHILD,
- 0, 0, 0, 0,
- area, NULL, hInstance, NULL);
- if (tf == NULL)
- xpanic("error making Area TextField", GetLastError());
- if ((*fv_SetWindowSubclass)(tf, areaTextFieldSubProc, 0, (DWORD_PTR) goarea) == FALSE)
- xpanic("error subclassing Area TextField to give it its own WM_KILLFOCUS handler", GetLastError());
- return tf;
-}
-
-void areaOpenTextField(HWND area, HWND textfield, int x, int y, int width, int height)
-{
- int sx, sy;
- int baseX, baseY;
- LONG unused;
-
- getScrollPos(area, &sx, &sy);
- x += sx;
- y += sy;
- calculateBaseUnits(textfield, &baseX, &baseY, &unused);
- width = MulDiv(width, baseX, 4);
- height = MulDiv(height, baseY, 8);
- if (MoveWindow(textfield, x, y, width, height, TRUE) == 0)
- xpanic("error moving Area TextField in Area.OpenTextFieldAt()", GetLastError());
- ShowWindow(textfield, SW_SHOW);
- if (SetFocus(textfield) == NULL)
- xpanic("error giving Area TextField focus", GetLastError());
-}
-
-void areaMarkTextFieldDone(HWND area)
-{
- SetWindowLongPtrW(area, 0, (LONG_PTR) NULL);
-}
diff --git a/redo/area_windows.go b/redo/area_windows.go
deleted file mode 100644
index e5e8ac0..0000000
--- a/redo/area_windows.go
+++ /dev/null
@@ -1,361 +0,0 @@
-// 24 march 2014
-
-package ui
-
-import (
- "fmt"
- "image"
- "syscall"
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type area struct {
- *areabase
-
- _hwnd C.HWND
-
- clickCounter *clickCounter
-
- textfield C.HWND
- textfielddone *event
-}
-
-func makeAreaWindowClass() error {
- var errmsg *C.char
-
- err := C.makeAreaWindowClass(&errmsg)
- if err != 0 || errmsg != nil {
- return fmt.Errorf("%s: %v", C.GoString(errmsg), syscall.Errno(err))
- }
- return nil
-}
-
-func newArea(ab *areabase) Area {
- a := &area{
- areabase: ab,
- clickCounter: new(clickCounter),
- textfielddone: newEvent(),
- }
- a._hwnd = C.newArea(unsafe.Pointer(a))
- a.SetSize(a.width, a.height)
- a.textfield = C.newAreaTextField(a._hwnd, unsafe.Pointer(a))
- C.controlSetControlFont(a.textfield)
- return a
-}
-
-func (a *area) SetSize(width, height int) {
- a.width = width
- a.height = height
- C.SendMessageW(a._hwnd, C.msgAreaSizeChanged, 0, 0)
-}
-
-func (a *area) Repaint(r image.Rectangle) {
- var hscroll, vscroll C.int
- var rect C.RECT
-
- C.SendMessageW(a._hwnd, C.msgAreaGetScroll, C.WPARAM(uintptr(unsafe.Pointer(&hscroll))), C.LPARAM(uintptr(unsafe.Pointer(&vscroll))))
- r = r.Add(image.Pt(int(hscroll), int(vscroll))) // adjust by scroll position
- r = image.Rect(0, 0, a.width, a.height).Intersect(r)
- if r.Empty() {
- return
- }
- rect.left = C.LONG(r.Min.X)
- rect.top = C.LONG(r.Min.Y)
- rect.right = C.LONG(r.Max.X)
- rect.bottom = C.LONG(r.Max.Y)
- C.SendMessageW(a._hwnd, C.msgAreaRepaint, 0, C.LPARAM(uintptr(unsafe.Pointer(&rect))))
-}
-
-func (a *area) RepaintAll() {
- C.SendMessageW(a._hwnd, C.msgAreaRepaintAll, 0, 0)
-}
-
-func (a *area) OpenTextFieldAt(x, y int) {
- if x < 0 || x >= a.width || y < 0 || y >= a.height {
- panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
- }
- C.areaOpenTextField(a._hwnd, a.textfield, C.int(x), C.int(y), textfieldWidth, textfieldHeight)
-}
-
-func (a *area) TextFieldText() string {
- return getWindowText(a.textfield)
-}
-
-func (a *area) SetTextFieldText(text string) {
- t := toUTF16(text)
- C.setWindowText(a.textfield, t)
-}
-
-func (a *area) OnTextFieldDismissed(f func()) {
- a.textfielddone.set(f)
-}
-
-//export areaTextFieldDone
-func areaTextFieldDone(data unsafe.Pointer) {
- a := (*area)(data)
- C.areaMarkTextFieldDone(a._hwnd)
- a.textfielddone.fire()
-}
-
-//export doPaint
-func doPaint(xrect *C.RECT, hscroll C.int, vscroll C.int, data unsafe.Pointer, dx *C.intptr_t, dy *C.intptr_t) unsafe.Pointer {
- a := (*area)(data)
- // both Windows RECT and Go image.Rect are point..point, so the following is correct
- cliprect := image.Rect(int(xrect.left), int(xrect.top), int(xrect.right), int(xrect.bottom))
- cliprect = cliprect.Add(image.Pt(int(hscroll), int(vscroll))) // adjust by scroll position
- // make sure the cliprect doesn't fall outside the size of the Area
- cliprect = cliprect.Intersect(image.Rect(0, 0, a.width, a.height))
- if !cliprect.Empty() { // we have an update rect
- i := a.handler.Paint(cliprect)
- *dx = C.intptr_t(i.Rect.Dx())
- *dy = C.intptr_t(i.Rect.Dy())
- return unsafe.Pointer(i)
- }
- return nil
-}
-
-//export dotoARGB
-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)
-}
-
-//export areaWidthLONG
-func areaWidthLONG(data unsafe.Pointer) C.LONG {
- a := (*area)(data)
- return C.LONG(a.width)
-}
-
-//export areaHeightLONG
-func areaHeightLONG(data unsafe.Pointer) C.LONG {
- a := (*area)(data)
- return C.LONG(a.height)
-}
-
-func getModifiers() (m Modifiers) {
- down := func(x C.int) bool {
- // GetKeyState() gets the key state at the time of the message, so this is what we want
- return (C.GetKeyState(x) & 0x80) != 0
- }
-
- if down(C.VK_CONTROL) {
- m |= Ctrl
- }
- if down(C.VK_MENU) {
- m |= Alt
- }
- if down(C.VK_SHIFT) {
- m |= Shift
- }
- if down(C.VK_LWIN) || down(C.VK_RWIN) {
- m |= Super
- }
- return m
-}
-
-//export finishAreaMouseEvent
-func finishAreaMouseEvent(data unsafe.Pointer, cbutton C.DWORD, up C.BOOL, heldButtons C.uintptr_t, xpos C.int, ypos C.int) {
- var me MouseEvent
-
- a := (*area)(data)
- button := uint(cbutton)
- me.Pos = image.Pt(int(xpos), int(ypos))
- if !me.Pos.In(image.Rect(0, 0, a.width, a.height)) { // outside the actual Area; no event
- return
- }
- if up != C.FALSE {
- me.Up = button
- } else if button != 0 { // don't run the click counter if the mouse was only moved
- me.Down = button
- // this returns a LONG, which is int32, but we don't need to worry about the signedness because for the same bit widths and two's complement arithmetic, s1-s2 == u1-u2 if bits(s1)==bits(s2) and bits(u1)==bits(u2) (and Windows requires two's complement: http://blogs.msdn.com/b/oldnewthing/archive/2005/05/27/422551.aspx)
- // signedness isn't much of an issue for these calls anyway because http://stackoverflow.com/questions/24022225/what-are-the-sign-extension-rules-for-calling-windows-api-functions-stdcall-t and that we're only using unsigned values (think back to how you (didn't) handle signedness in assembly language) AND because of the above AND because the statistics below (time interval and width/height) really don't make sense if negative
- time := C.GetMessageTime()
- maxTime := C.GetDoubleClickTime()
- // ignore zero returns and errors; MSDN says zero will be returned on error but that GetLastError() is meaningless
- xdist := C.GetSystemMetrics(C.SM_CXDOUBLECLK)
- ydist := C.GetSystemMetrics(C.SM_CYDOUBLECLK)
- me.Count = a.clickCounter.click(button, me.Pos.X, me.Pos.Y,
- uintptr(time), uintptr(maxTime), int(xdist/2), int(ydist/2))
- }
- // 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 {
- me.Held = append(me.Held, 1)
- }
- if button != 2 && (heldButtons & C.MK_MBUTTON) != 0 {
- me.Held = append(me.Held, 2)
- }
- if button != 3 && (heldButtons & C.MK_RBUTTON) != 0 {
- me.Held = append(me.Held, 3)
- }
- if button != 4 && (heldButtons & C.MK_XBUTTON1) != 0 {
- me.Held = append(me.Held, 4)
- }
- if button != 5 && (heldButtons & C.MK_XBUTTON2) != 0 {
- me.Held = append(me.Held, 5)
- }
- a.handler.Mouse(me)
-}
-
-//export areaKeyEvent
-func areaKeyEvent(data unsafe.Pointer, up C.BOOL, wParam C.WPARAM, lParam C.LPARAM) C.BOOL {
- var ke KeyEvent
-
- a := (*area)(data)
- 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
-
- scancode := byte((lp >> 16) & 0xFF)
- ke.Modifiers = getModifiers()
- if extkey, ok := numpadextkeys[wParam]; ok && !righthand {
- // the above is special handling for numpad keys to ignore the state of Num Lock and Shift; see http://blogs.msdn.com/b/oldnewthing/archive/2004/09/06/226045.aspx and https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152
- ke.ExtKey = extkey
- } else if wParam == C.VK_RETURN && righthand {
- ke.ExtKey = NEnter
- } else if extkey, ok := extkeys[wParam]; ok {
- ke.ExtKey = extkey
- } else if mod, ok := modonlykeys[wParam]; ok {
- ke.Modifier = mod
- // don't include the modifier in ke.Modifiers
- ke.Modifiers &^= mod
- } else if xke, ok := fromScancode(uintptr(scancode)); ok {
- // one of these will be nonzero
- ke.Key = xke.Key
- ke.ExtKey = xke.ExtKey
- } else if ke.Modifiers == 0 {
- // no key, extkey, or modifiers; do nothing
- return C.FALSE
- }
- ke.Up = up != C.FALSE
- handled := a.handler.Key(ke)
- if handled {
- return C.TRUE
- }
- return C.FALSE
-}
-
-// all mappings come from GLFW - https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152
-var numpadextkeys = map[C.WPARAM]ExtKey{
- C.VK_HOME: N7,
- C.VK_UP: N8,
- C.VK_PRIOR: N9,
- C.VK_LEFT: N4,
- C.VK_CLEAR: N5,
- C.VK_RIGHT: N6,
- C.VK_END: N1,
- C.VK_DOWN: N2,
- C.VK_NEXT: N3,
- C.VK_INSERT: N0,
- C.VK_DELETE: NDot,
-}
-
-var extkeys = map[C.WPARAM]ExtKey{
- C.VK_ESCAPE: Escape,
- C.VK_INSERT: Insert,
- C.VK_DELETE: Delete,
- C.VK_HOME: Home,
- C.VK_END: End,
- C.VK_PRIOR: PageUp,
- C.VK_NEXT: PageDown,
- C.VK_UP: Up,
- C.VK_DOWN: Down,
- C.VK_LEFT: Left,
- C.VK_RIGHT: Right,
- C.VK_F1: F1,
- C.VK_F2: F2,
- C.VK_F3: F3,
- C.VK_F4: F4,
- C.VK_F5: F5,
- C.VK_F6: F6,
- C.VK_F7: F7,
- C.VK_F8: F8,
- C.VK_F9: F9,
- C.VK_F10: F10,
- C.VK_F11: F11,
- C.VK_F12: F12,
- // numpad numeric keys and . are handled in events_notdarwin.go
- // numpad enter is handled in code above
- C.VK_ADD: NAdd,
- C.VK_SUBTRACT: NSubtract,
- C.VK_MULTIPLY: NMultiply,
- C.VK_DIVIDE: NDivide,
-}
-
-// sanity check
-func init() {
- included := make([]bool, _nextkeys)
- for _, v := range extkeys {
- included[v] = true
- }
- for i := 1; i < int(_nextkeys); i++ {
- if i >= int(N0) && i <= int(N9) { // skip numpad numbers, ., and enter
- continue
- }
- if i == int(NDot) || i == int(NEnter) {
- continue
- }
- if !included[i] {
- panic(fmt.Errorf("error: not all ExtKeys defined on Windows (missing %d)", i))
- }
- }
-}
-
-var modonlykeys = map[C.WPARAM]Modifiers{
- // even if the separate left/right aren't necessary, have them here anyway, just to be safe
- C.VK_CONTROL: Ctrl,
- C.VK_LCONTROL: Ctrl,
- C.VK_RCONTROL: Ctrl,
- C.VK_MENU: Alt,
- C.VK_LMENU: Alt,
- C.VK_RMENU: Alt,
- C.VK_SHIFT: Shift,
- C.VK_LSHIFT: Shift,
- C.VK_RSHIFT: Shift,
- // there's no combined Windows key virtual-key code as there is with the others
- C.VK_LWIN: Super,
- C.VK_RWIN: Super,
-}
-
-//export storeAreaHWND
-func storeAreaHWND(data unsafe.Pointer, hwnd C.HWND) {
- a := (*area)(data)
- a._hwnd = hwnd
-}
-
-//export areaResetClickCounter
-func areaResetClickCounter(data unsafe.Pointer) {
- a := (*area)(data)
- a.clickCounter.reset()
-}
-
-func (a *area) hwnd() C.HWND {
- return a._hwnd
-}
-
-func (a *area) setParent(p *controlParent) {
- basesetParent(a, p)
-}
-
-func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(a, x, y, width, height, d)
-}
-
-func (a *area) preferredSize(d *sizing) (width, height int) {
- // the preferred size of an Area is its size
- return a.width, a.height
-}
-
-func (a *area) commitResize(c *allocation, d *sizing) {
- basecommitResize(a, c, d)
-}
-
-func (a *area) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(a, d)
-}
diff --git a/redo/basicctrls.go b/redo/basicctrls.go
deleted file mode 100644
index cee60f2..0000000
--- a/redo/basicctrls.go
+++ /dev/null
@@ -1,129 +0,0 @@
-// 7 july 2014
-
-package ui
-
-// Button is a clickable button that performs some task.
-type Button interface {
- Control
-
- // OnClicked sets the event handler for when the Button is clicked.
- OnClicked(func())
-
- // Text and SetText get and set the Button's label text.
- Text() string
- SetText(text string)
-}
-
-// NewButton creates a new Button with the given label text.
-func NewButton(text string) Button {
- return newButton(text)
-}
-
-// Checkbox is a clickable box that indicates some Boolean value.
-type Checkbox interface {
- Control
-
- // OnToggled sets the event handler for when the Checkbox is toggled.
- OnToggled(func())
-
- // Text and SetText get and set the Checkbox's label text.
- Text() string
- SetText(text string)
-
- // Checked and SetChecked get and set the Checkbox's check state.
- Checked() bool
- SetChecked(checked bool)
-}
-
-// NewCheckbox creates a new Checkbox with the given label text.
-// The Checkbox will be initially unchecked.
-func NewCheckbox(text string) Checkbox {
- return newCheckbox(text)
-}
-
-// TextField is a Control in which the user can enter a single line of text.
-type TextField interface {
- Control
-
- // Text and SetText are Requests that get and set the TextField's text.
- Text() string
- SetText(text string)
-
- // OnChanged is triggered when the text in a TextField is changed somehow.
- // Do not bother trying to figure out how the text was changed; instead, perform your validation and use Invalid to inform the user that the entered text is invalid instead.
- OnChanged(func())
-
- // Invalid throws a non-modal alert (whose nature is system-defined) on or near the TextField that alerts the user that input is invalid.
- // The string passed to Invalid will be displayed to the user to inform them of what specifically is wrong with the input.
- // Pass an empty string to remove the warning.
- Invalid(reason string)
-}
-
-// NewTextField creates a new TextField.
-func NewTextField() TextField {
- return newTextField()
-}
-
-// NewPasswordField creates a new TextField for entering passwords; that is, it hides the text being entered.
-func NewPasswordField() TextField {
- return newPasswordField()
-}
-
-// Tab is a Control that contains multiple pages of tabs, each containing a single Control.
-// You can add and remove tabs from the Tab at any time.
-// The appearance of a Tab with no tabs is implementation-defined.
-type Tab interface {
- Control
-
- // Append adds a new tab to Tab.
- // The tab is added to the end of the current list of tabs.
- Append(name string, control Control)
-}
-
-// NewTab creates a new Tab with no tabs.
-func NewTab() Tab {
- return newTab()
-}
-
-// Label is a Control that shows a static line of text.
-// Label shows one line of text; any text that does not fit is truncated.
-// A Label can either have smart vertical alignment relative to the control to its right or just be vertically aligned to the top (standalone).
-// The effect of placing a non-standalone Label in any context other than to the immediate left of a Control is undefined.
-// Both types of labels are left-aligned. [FUTURE PLANS: For platform-specific horizontal alignment rules, use a Form.]
-type Label interface {
- Control
-
- // Text and SetText get and set the Label's text.
- Text() string
- SetText(text string)
-
- isStandalone() bool
-}
-
-// NewLabel creates a new Label with the given text.
-// The Label will smartly vertically position itself relative to the control to its immediate right.
-func NewLabel(text string) Label {
- return newLabel(text)
-}
-
-// NewStandaloneLabel creates a new Label with the given text.
-// The Label will be vertically positioned at the top of its allocated space.
-func NewStandaloneLabel(text string) Label {
- return newStandaloneLabel(text)
-}
-
-// Group is a Control that holds a single Control; if that Control also contains other Controls, then the Controls will appear visually grouped together.
-// The appearance of a Group varies from system to system; for the most part a Group consists of a thin frame.
-// All Groups have a text label indicating what the Group is for.
-type Group interface {
- Control
-
- // Text and SetText get and set the Group's label text.
- Text() string
- SetText(text string)
-}
-
-// NewGroup creates a new Group with the given text label and child Control.
-func NewGroup(text string, control Control) Group {
- return newGroup(text, control)
-}
diff --git a/redo/basicctrls_darwin.m b/redo/basicctrls_darwin.m
deleted file mode 100644
index e0e5f75..0000000
--- a/redo/basicctrls_darwin.m
+++ /dev/null
@@ -1,219 +0,0 @@
-// 16 july 2014
-
-#import "objc_darwin.h"
-#import "_cgo_export.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSButton(x) ((NSButton *) (x))
-#define toNSTextField(x) ((NSTextField *) (x))
-#define toNSView(x) ((NSView *) (x))
-#define toNSWindow(x) ((NSWindow *) (x))
-#define toNSBox(x) ((NSBox *) (x))
-
-@interface goControlDelegate : NSObject <NSTextFieldDelegate> {
-@public
- void *gocontrol;
-}
-@end
-
-@implementation goControlDelegate
-
-- (IBAction)buttonClicked:(id)sender
-{
- buttonClicked(self->gocontrol);
-}
-
-- (IBAction)checkboxToggled:(id)sender
-{
- checkboxToggled(self->gocontrol);
-}
-
-- (void)controlTextDidChange:(NSNotification *)note
-{
- textfieldChanged(self->gocontrol);
-}
-
-@end
-
-id newButton(void)
-{
- NSButton *b;
-
- b = [[NSButton alloc] initWithFrame:NSZeroRect];
- [b setButtonType:NSMomentaryPushInButton];
- [b setBordered:YES];
- [b setBezelStyle:NSRoundedBezelStyle];
- setStandardControlFont((id) b);
- return (id) b;
-}
-
-void buttonSetDelegate(id button, void *b)
-{
- goControlDelegate *d;
-
- d = [goControlDelegate new];
- d->gocontrol = b;
- [toNSButton(button) setTarget:d];
- [toNSButton(button) setAction:@selector(buttonClicked:)];
-}
-
-const char *buttonText(id button)
-{
- return [[toNSButton(button) title] UTF8String];
-}
-
-void buttonSetText(id button, char *text)
-{
- [toNSButton(button) setTitle:[NSString stringWithUTF8String:text]];
-}
-
-id newCheckbox(void)
-{
- NSButton *c;
-
- c = [[NSButton alloc] initWithFrame:NSZeroRect];
- [c setButtonType:NSSwitchButton];
- [c setBordered:NO];
- setStandardControlFont((id) c);
- return (id) c;
-}
-
-void checkboxSetDelegate(id checkbox, void *b)
-{
- goControlDelegate *d;
-
- d = [goControlDelegate new];
- d->gocontrol = b;
- [toNSButton(checkbox) setTarget:d];
- [toNSButton(checkbox) setAction:@selector(checkboxToggled:)];
-}
-
-BOOL checkboxChecked(id c)
-{
- if ([toNSButton(c) state] == NSOnState)
- return YES;
- return NO;
-}
-
-void checkboxSetChecked(id c, BOOL checked)
-{
- NSInteger state;
-
- state = NSOnState;
- if (checked == NO)
- state = NSOffState;
- [toNSButton(c) setState:state];
-}
-
-// also good for labels
-// not static because area_darwin.m uses it
-id finishNewTextField(id _t, BOOL bordered)
-{
- NSTextField *t = toNSTextField(_t);
-
- // same for text fields, password fields, and labels
- setStandardControlFont((id) t);
- // these three are the same across text fields, password fields, and labels; the only difference is the setBezeled: value, and it's only different on labels
- // THE ORDER OF THESE CALLS IS IMPORTANT; CHANGE IT AND THE BORDERS WILL DISAPPEAR
- [t setBordered:NO];
- [t setBezelStyle:NSTextFieldSquareBezel];
- [t setBezeled:bordered];
- // smart quotes and other autocorrect features are handled by the window; see newWindow() in window_darwin.m for details
- // Interface Builder does this to make the text box behave properly
- // this disables both word wrap AND ellipsizing in one fell swoop
- // however, we need to send it to the control's cell, not to the control directly
- [[t cell] setLineBreakMode:NSLineBreakByClipping];
- // Interface Builder also sets this to allow horizontal scrolling
- // it also sets this for labels, despite those not being scrollable
- [[t cell] setScrollable:YES];
- return (id) t;
-}
-
-id newTextField(void)
-{
- NSTextField *t;
-
- t = [[NSTextField alloc] initWithFrame:NSZeroRect];
- return finishNewTextField((id) t, YES);
-}
-
-id newPasswordField(void)
-{
- NSSecureTextField *t;
-
- t = [[NSSecureTextField alloc] initWithFrame:NSZeroRect];
- return finishNewTextField((id) t, YES);
-}
-
-void textfieldSetDelegate(id textfield, void *t)
-{
- goControlDelegate *d;
-
- d = [goControlDelegate new];
- d->gocontrol = t;
- [toNSTextField(textfield) setDelegate:d];
-}
-
-// also good for labels
-const char *textfieldText(id t)
-{
- return [[toNSTextField(t) stringValue] UTF8String];
-}
-
-// also good for labels
-void textfieldSetText(id t, char *text)
-{
- [toNSTextField(t) setStringValue:[NSString stringWithUTF8String:text]];
-}
-
-id textfieldOpenInvalidPopover(id textfield, char *reason)
-{
- id popover;
-
- popover = newWarningPopover(reason);
- warningPopoverShow(popover, textfield);
- NSBeep();
- return (id) popover;
-}
-
-void textfieldCloseInvalidPopover(id popover)
-{
- [toNSWindow(popover) close];
- // don't release; close does that already
-}
-
-id newLabel(void)
-{
- NSTextField *l;
-
- l = [[NSTextField alloc] initWithFrame:NSZeroRect];
- [l setEditable:NO];
- [l setSelectable:NO];
- [l setDrawsBackground:NO];
- return finishNewTextField((id) l, NO);
-}
-
-id newGroup(id container)
-{
- NSBox *group;
-
- group = [[NSBox alloc] initWithFrame:NSZeroRect];
- [group setBorderType:NSLineBorder];
- [group setBoxType:NSBoxPrimary];
- [group setTransparent:NO];
- // can't use setSmallControlFont() here because the selector is different
- [group setTitleFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
- [group setTitlePosition:NSAtTop];
- [group setContentView:toNSView(container)];
- return (id) group;
-}
-
-const char *groupText(id group)
-{
- return [[toNSBox(group) title] UTF8String];
-}
-
-void groupSetText(id group, char *text)
-{
- [toNSBox(group) setTitle:[NSString stringWithUTF8String:text]];
-}
diff --git a/redo/basicctrls_windows.c b/redo/basicctrls_windows.c
deleted file mode 100644
index 8947187..0000000
--- a/redo/basicctrls_windows.c
+++ /dev/null
@@ -1,129 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-static LRESULT CALLBACK buttonSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
-{
- switch (uMsg) {
- case msgCOMMAND:
- if (HIWORD(wParam) == BN_CLICKED) {
- buttonClicked((void *) data);
- return 0;
- }
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_NCDESTROY:
- if ((*fv_RemoveWindowSubclass)(hwnd, buttonSubProc, id) == FALSE)
- xpanic("error removing Button subclass (which was for its own event handler)", GetLastError());
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- default:
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("Button", "buttonSubProc()", uMsg);
- return 0; // unreached
-}
-
-void setButtonSubclass(HWND hwnd, void *data)
-{
- if ((*fv_SetWindowSubclass)(hwnd, buttonSubProc, 0, (DWORD_PTR) data) == FALSE)
- xpanic("error subclassing Button to give it its own event handler", GetLastError());
-}
-
-static LRESULT CALLBACK checkboxSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
-{
- switch (uMsg) {
- case msgCOMMAND:
- if (HIWORD(wParam) == BN_CLICKED) {
- WPARAM check;
-
- // we didn't use BS_AUTOCHECKBOX (see controls_windows.go) so we have to manage the check state ourselves
- check = BST_CHECKED;
- if (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
- check = BST_UNCHECKED;
- SendMessage(hwnd, BM_SETCHECK, check, 0);
- checkboxToggled((void *) data);
- return 0;
- }
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_NCDESTROY:
- if ((*fv_RemoveWindowSubclass)(hwnd, checkboxSubProc, id) == FALSE)
- xpanic("error removing Checkbox subclass (which was for its own event handler)", GetLastError());
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- default:
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("Checkbox", "checkboxSubProc()", uMsg);
- return 0; // unreached
-}
-
-void setCheckboxSubclass(HWND hwnd, void *data)
-{
- if ((*fv_SetWindowSubclass)(hwnd, checkboxSubProc, 0, (DWORD_PTR) data) == FALSE)
- xpanic("error subclassing Checkbox to give it its own event handler", GetLastError());
-}
-
-BOOL checkboxChecked(HWND hwnd)
-{
- if (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_UNCHECKED)
- return FALSE;
- return TRUE;
-}
-
-void checkboxSetChecked(HWND hwnd, BOOL c)
-{
- WPARAM check;
-
- check = BST_CHECKED;
- if (c == FALSE)
- check = BST_UNCHECKED;
- SendMessage(hwnd, BM_SETCHECK, check, 0);
-}
-
-static LRESULT CALLBACK textfieldSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
-{
- switch (uMsg) {
- case msgCOMMAND:
- if (HIWORD(wParam) == EN_CHANGE) {
- textfieldChanged((void *) data);
- return 0;
- }
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_NCDESTROY:
- if ((*fv_RemoveWindowSubclass)(hwnd, textfieldSubProc, id) == FALSE)
- xpanic("error removing TextField subclass (which was for its own event handler)", GetLastError());
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- default:
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("TextField", "textfieldSubProc()", uMsg);
- return 0; // unreached
-}
-
-void setTextFieldSubclass(HWND hwnd, void *data)
-{
- if ((*fv_SetWindowSubclass)(hwnd, textfieldSubProc, 0, (DWORD_PTR) data) == FALSE)
- xpanic("error subclassing TextField to give it its own event handler", GetLastError());
-}
-
-void textfieldSetAndShowInvalidBalloonTip(HWND hwnd, WCHAR *text)
-{
- EDITBALLOONTIP ti;
-
- ZeroMemory(&ti, sizeof (EDITBALLOONTIP));
- ti.cbStruct = sizeof (EDITBALLOONTIP);
- // this is required to show the error icon
- // this probably should be localized...
- ti.pszTitle = L"Invalid Input";
- ti.pszText = text;
- ti.ttiIcon = TTI_ERROR;
- if (SendMessageW(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM) (&ti)) == FALSE)
- xpanic("error showing TextField.Invalid() balloon tip", GetLastError());
- if (MessageBeep(0xFFFFFFFF) == 0)
- xpanic("error beeping in response to TextField.Invalid()", GetLastError());
-}
-
-void textfieldHideInvalidBalloonTip(HWND hwnd)
-{
- if (SendMessageW(hwnd, EM_HIDEBALLOONTIP, 0, 0) == FALSE)
- xpanic("error hiding TextField.Invalid() balloon tip", GetLastError());
-}
diff --git a/redo/button_darwin.go b/redo/button_darwin.go
deleted file mode 100644
index 9444da4..0000000
--- a/redo/button_darwin.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// 16 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type button struct {
- _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(),
- }
- C.buttonSetText(b._id, ctext)
- C.buttonSetDelegate(b._id, unsafe.Pointer(b))
- return b
-}
-
-func (b *button) OnClicked(e func()) {
- b.clicked.set(e)
-}
-
-func (b *button) Text() string {
- return C.GoString(C.buttonText(b._id))
-}
-
-func (b *button) SetText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.buttonSetText(b._id, ctext)
-}
-
-//export buttonClicked
-func buttonClicked(xb unsafe.Pointer) {
- b := (*button)(unsafe.Pointer(xb))
- b.clicked.fire()
- println("button clicked")
-}
-
-func (b *button) id() C.id {
- return b._id
-}
-
-func (b *button) setParent(p *controlParent) {
- basesetParent(b, p)
-}
-
-func (b *button) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(b, x, y, width, height, d)
-}
-
-func (b *button) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(b, d)
-}
-
-func (b *button) commitResize(a *allocation, d *sizing) {
- basecommitResize(b, a, d)
-}
-
-func (b *button) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(b, d)
-}
diff --git a/redo/button_unix.go b/redo/button_unix.go
deleted file mode 100644
index 7d41b55..0000000
--- a/redo/button_unix.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern void buttonClicked(GtkButton *, gpointer);
-import "C"
-
-type button struct {
- _widget *C.GtkWidget
- button *C.GtkButton
- clicked *event
-}
-
-// shared code for setting up buttons, check boxes, etc.
-func newButton(text string) *button {
- ctext := togstr(text)
- defer freegstr(ctext)
- widget := C.gtk_button_new_with_label(ctext)
- b := &button{
- _widget: widget,
- button: (*C.GtkButton)(unsafe.Pointer(widget)),
- clicked: newEvent(),
- }
- g_signal_connect(
- C.gpointer(unsafe.Pointer(b.button)),
- "clicked",
- C.GCallback(C.buttonClicked),
- C.gpointer(unsafe.Pointer(b)))
- return b
-}
-
-func (b *button) OnClicked(e func()) {
- b.clicked.set(e)
-}
-
-func (b *button) Text() string {
- return fromgstr(C.gtk_button_get_label(b.button))
-}
-
-func (b *button) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_button_set_label(b.button, ctext)
-}
-
-//export buttonClicked
-func buttonClicked(bwid *C.GtkButton, data C.gpointer) {
- b := (*button)(unsafe.Pointer(data))
- b.clicked.fire()
- println("button clicked")
-}
-
-func (b *button) widget() *C.GtkWidget {
- return b._widget
-}
-
-func (b *button) setParent(p *controlParent) {
- basesetParent(b, p)
-}
-
-func (b *button) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(b, x, y, width, height, d)
-}
-
-func (b *button) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(b, d)
-}
-
-func (b *button) commitResize(a *allocation, d *sizing) {
- basecommitResize(b, a, d)
-}
-
-func (b *button) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(b, d)
-}
diff --git a/redo/button_windows.go b/redo/button_windows.go
deleted file mode 100644
index ac2b9b7..0000000
--- a/redo/button_windows.go
+++ /dev/null
@@ -1,100 +0,0 @@
-// 15 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type button struct {
- _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,
- 0)
- b := &button{
- _hwnd: hwnd,
- clicked: newEvent(),
- }
- b.SetText(text)
- C.controlSetControlFont(b._hwnd)
- C.setButtonSubclass(b._hwnd, unsafe.Pointer(b))
- return b
-}
-
-func (b *button) OnClicked(e func()) {
- b.clicked.set(e)
-}
-
-func (b *button) Text() string {
- return baseText(b)
-}
-
-func (b *button) SetText(text string) {
- baseSetText(b, text)
-}
-
-//export buttonClicked
-func buttonClicked(data unsafe.Pointer) {
- b := (*button)(data)
- b.clicked.fire()
- println("button clicked")
-}
-
-func (b *button) hwnd() C.HWND {
- return b._hwnd
-}
-
-func (b *button) textlen() C.LONG {
- return b._textlen
-}
-
-func (b *button) settextlen(len C.LONG) {
- b._textlen = len
-}
-
-func (b *button) setParent(p *controlParent) {
- basesetParent(b, p)
-}
-
-func (b *button) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(b, x, y, width, height, d)
-}
-
-const (
- // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
- buttonHeight = 14
-)
-
-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.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")
- // 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)
-}
-
-func (b *button) commitResize(a *allocation, d *sizing) {
- basecommitResize(b, a, d)
-}
-
-func (b *button) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(b, d)
-}
diff --git a/redo/checkbox_darwin.go b/redo/checkbox_darwin.go
deleted file mode 100644
index ac3375a..0000000
--- a/redo/checkbox_darwin.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// 16 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type checkbox struct {
- _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(),
- }
- C.buttonSetText(c._id, ctext)
- C.checkboxSetDelegate(c._id, unsafe.Pointer(c))
- return c
-}
-
-func (c *checkbox) OnToggled(e func()) {
- c.toggled.set(e)
-}
-
-func (c *checkbox) Text() string {
- return C.GoString(C.buttonText(c._id))
-}
-
-func (c *checkbox) SetText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.buttonSetText(c._id, ctext)
-}
-
-func (c *checkbox) Checked() bool {
- return fromBOOL(C.checkboxChecked(c._id))
-}
-
-func (c *checkbox) SetChecked(checked bool) {
- C.checkboxSetChecked(c._id, toBOOL(checked))
-}
-
-//export checkboxToggled
-func checkboxToggled(xc unsafe.Pointer) {
- c := (*checkbox)(unsafe.Pointer(xc))
- c.toggled.fire()
-}
-
-func (c *checkbox) id() C.id {
- return c._id
-}
-
-func (c *checkbox) setParent(p *controlParent) {
- basesetParent(c, p)
-}
-
-func (c *checkbox) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(c, x, y, width, height, d)
-}
-
-func (c *checkbox) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(c, d)
-}
-
-func (c *checkbox) commitResize(a *allocation, d *sizing) {
- basecommitResize(c, a, d)
-}
-
-func (c *checkbox) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(c, d)
-}
diff --git a/redo/checkbox_unix.go b/redo/checkbox_unix.go
deleted file mode 100644
index 3cae5fa..0000000
--- a/redo/checkbox_unix.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern void checkboxToggled(GtkToggleButton *, gpointer);
-import "C"
-
-type checkbox struct {
- _widget *C.GtkWidget
- button *C.GtkButton
- toggle *C.GtkToggleButton
- checkbox *C.GtkCheckButton
- toggled *event
-}
-
-func newCheckbox(text string) *checkbox {
- ctext := togstr(text)
- 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(),
- }
- g_signal_connect(
- C.gpointer(unsafe.Pointer(c.checkbox)),
- "toggled",
- C.GCallback(C.checkboxToggled),
- C.gpointer(unsafe.Pointer(c)))
- return c
-}
-
-func (c *checkbox) OnToggled(e func()) {
- c.toggled.set(e)
-}
-
-func (c *checkbox) Text() string {
- return fromgstr(C.gtk_button_get_label(c.button))
-}
-
-func (c *checkbox) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_button_set_label(c.button, ctext)
-}
-
-func (c *checkbox) Checked() bool {
- return fromgbool(C.gtk_toggle_button_get_active(c.toggle))
-}
-
-func (c *checkbox) SetChecked(checked bool) {
- C.gtk_toggle_button_set_active(c.toggle, togbool(checked))
-}
-
-//export checkboxToggled
-func checkboxToggled(bwid *C.GtkToggleButton, data C.gpointer) {
- c := (*checkbox)(unsafe.Pointer(data))
- c.toggled.fire()
-}
-
-func (c *checkbox) widget() *C.GtkWidget {
- return c._widget
-}
-
-func (c *checkbox) setParent(p *controlParent) {
- basesetParent(c, p)
-}
-
-func (c *checkbox) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(c, x, y, width, height, d)
-}
-
-func (c *checkbox) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(c, d)
-}
-
-func (c *checkbox) commitResize(a *allocation, d *sizing) {
- basecommitResize(c, a, d)
-}
-
-func (c *checkbox) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(c, d)
-}
diff --git a/redo/checkbox_windows.go b/redo/checkbox_windows.go
deleted file mode 100644
index eab0764..0000000
--- a/redo/checkbox_windows.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// 15 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type checkbox struct {
- _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,
- 0)
- c := &checkbox{
- _hwnd: hwnd,
- toggled: newEvent(),
- }
- c.SetText(text)
- C.controlSetControlFont(c._hwnd)
- C.setCheckboxSubclass(c._hwnd, unsafe.Pointer(c))
- return c
-}
-
-func (c *checkbox) OnToggled(e func()) {
- c.toggled.set(e)
-}
-
-func (c *checkbox) Text() string {
- return baseText(c)
-}
-
-func (c *checkbox) SetText(text string) {
- baseSetText(c, text)
-}
-
-func (c *checkbox) Checked() bool {
- return C.checkboxChecked(c._hwnd) != C.FALSE
-}
-
-func (c *checkbox) SetChecked(checked bool) {
- if checked {
- C.checkboxSetChecked(c._hwnd, C.TRUE)
- return
- }
- C.checkboxSetChecked(c._hwnd, C.FALSE)
-}
-
-//export checkboxToggled
-func checkboxToggled(data unsafe.Pointer) {
- c := (*checkbox)(data)
- c.toggled.fire()
- println("checkbox toggled")
-}
-
-func (c *checkbox) hwnd() C.HWND {
- return c._hwnd
-}
-
-func (c *checkbox) textlen() C.LONG {
- return c._textlen
-}
-
-func (c *checkbox) settextlen(len C.LONG) {
- c._textlen = len
-}
-
-func (c *checkbox) setParent(p *controlParent) {
- basesetParent(c, p)
-}
-
-func (c *checkbox) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(c, x, y, width, height, d)
-}
-
-const (
- // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
- checkboxHeight = 10
- // from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx
- checkboxXFromLeftOfBoxToLeftOfLabel = 12
-)
-
-func (c *checkbox) preferredSize(d *sizing) (width, height int) {
- return fromdlgunitsX(checkboxXFromLeftOfBoxToLeftOfLabel, d) + int(c._textlen),
- fromdlgunitsY(checkboxHeight, d)
-}
-
-func (c *checkbox) commitResize(a *allocation, d *sizing) {
- basecommitResize(c, a, d)
-}
-
-func (c *checkbox) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(c, d)
-}
diff --git a/redo/comctl32_windows.c b/redo/comctl32_windows.c
deleted file mode 100644
index 841aa80..0000000
--- a/redo/comctl32_windows.c
+++ /dev/null
@@ -1,134 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-
-static ULONG_PTR comctlManifestCookie;
-static HMODULE comctl32;
-
-// these are listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
-BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
-BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
-LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
-HIMAGELIST (*WINAPI fv_ImageList_Create)(int, int, UINT, int, int);
-int (*WINAPI fv_ImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
-BOOL (*WINAPI fv_ImageList_Destroy)(HIMAGELIST);
-
-#define wantedICCClasses ( \
- ICC_PROGRESS_CLASS | /* progress bars */ \
- ICC_TAB_CLASSES | /* tabs */ \
- ICC_LISTVIEW_CLASSES | /* list views */ \
- 0)
-
-// note that this is an 8-bit character string we're writing; see the encoding clause
-static const char manifest[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n version=\"1.0.0.0\"\n processorArchitecture=\"*\"\n name=\"CompanyName.ProductName.YourApplication\"\n type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n <dependentAssembly>\n <assemblyIdentity\n type=\"win32\"\n name=\"Microsoft.Windows.Common-Controls\"\n version=\"6.0.0.0\"\n processorArchitecture=\"*\"\n publicKeyToken=\"6595b64144ccf1df\"\n language=\"*\"\n />\n </dependentAssembly>\n</dependency>\n</assembly>\n";
-
-/*
-Windows requires a manifest file to enable Common Controls version 6.
-The only way to not require an external manifest is to synthesize the manifest ourselves.
-We can use the activation context API to load it at runtime.
-References:
-- http://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest
-- http://support.microsoft.com/kb/830033
-Because neither Go nor MinGW have ways to compile in resources like this (as far as I know), we have to do the work ourselves.
-*/
-DWORD initCommonControls(char **errmsg)
-{
- WCHAR temppath[MAX_PATH + 1];
- WCHAR filename[MAX_PATH + 1];
- HANDLE file;
- DWORD nExpected, nGot;
- ACTCTX actctx;
- HANDLE ac;
- INITCOMMONCONTROLSEX icc;
- FARPROC f;
- // this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
- BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX);
-
- if (GetTempPathW(MAX_PATH + 1, temppath) == 0) {
- *errmsg = "error getting temporary path for writing manifest file";
- return GetLastError();
- }
- if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0) {
- *errmsg = "error getting temporary filename for writing manifest file";
- return GetLastError();
- }
- file = CreateFileW(filename, GENERIC_WRITE,
- 0, // don't share while writing
- NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (file == NULL) {
- *errmsg = "error creating manifest file";
- return GetLastError();
- }
- nExpected = (sizeof manifest / sizeof manifest[0]) - 1; // - 1 to omit the terminating null character)
- SetLastError(0); // catch errorless short writes
- if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0) {
- *errmsg = "error writing manifest file";
- return GetLastError();
- }
- if (nGot != nExpected) {
- DWORD lasterr;
-
- lasterr = GetLastError();
- *errmsg = "short write to manifest file";
- if (lasterr == 0)
- *errmsg = "short write to manifest file without error code";
- return lasterr;
- }
- if (CloseHandle(file) == 0) {
- *errmsg = "error closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context)";
- return GetLastError();
- }
-
- ZeroMemory(&actctx, sizeof (ACTCTX));
- actctx.cbSize = sizeof (ACTCTX);
- actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
- actctx.lpSource = filename;
- ac = CreateActCtx(&actctx);
- if (ac == INVALID_HANDLE_VALUE) {
- *errmsg = "error creating activation context for synthesized manifest file";
- return GetLastError();
- }
- if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE) {
- *errmsg = "error activating activation context for synthesized manifest file";
- return GetLastError();
- }
-
- ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
- icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
- icc.dwICC = wantedICCClasses;
-
- comctl32 = LoadLibraryW(L"comctl32.dll");
- if (comctl32 == NULL) {
- *errmsg = "error loading comctl32.dll";
- return GetLastError();
- }
-
- // GetProcAddress() only takes a multibyte string
-#define LOAD(fn) f = GetProcAddress(comctl32, fn); \
- if (f == NULL) { \
- *errmsg = "error loading " fn "()"; \
- return GetLastError(); \
- }
-
- LOAD("InitCommonControlsEx");
- ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f;
- LOAD("SetWindowSubclass");
- fv_SetWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR)) f;
- LOAD("RemoveWindowSubclass");
- fv_RemoveWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR)) f;
- LOAD("DefSubclassProc");
- fv_DefSubclassProc = (LRESULT (*WINAPI)(HWND, UINT, WPARAM, LPARAM)) f;
- LOAD("ImageList_Create");
- fv_ImageList_Create = (HIMAGELIST (*WINAPI)(int, int, UINT, int, int)) f;
- LOAD("ImageList_Add");
- fv_ImageList_Add = (int (*WINAPI)(HIMAGELIST, HBITMAP, HBITMAP)) f;
- LOAD("ImageList_Destroy");
- fv_ImageList_Destroy = (BOOL (*WINAPI)(HIMAGELIST)) f;
-
- if ((*ficc)(&icc) == FALSE) {
- *errmsg = "error initializing Common Controls (comctl32.dll)";
- return GetLastError();
- }
-
- return 0;
-}
diff --git a/redo/common_darwin.go b/redo/common_darwin.go
deleted file mode 100644
index bf8c0c0..0000000
--- a/redo/common_darwin.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// 20 july 2014
-
-package ui
-
-// #include "objc_darwin.h"
-import "C"
-
-func fromBOOL(b C.BOOL) bool {
- if b != C.NO {
- return true
- }
- return false
-}
-
-func toBOOL(b bool) C.BOOL {
- if b == true {
- return C.YES
- }
- return C.NO
-}
diff --git a/redo/common_darwin.m b/redo/common_darwin.m
deleted file mode 100644
index 3043f21..0000000
--- a/redo/common_darwin.m
+++ /dev/null
@@ -1,16 +0,0 @@
-// 11 august 2014
-
-#include "objc_darwin.h"
-#include <Cocoa/Cocoa.h>
-
-void disableAutocorrect(id onwhat)
-{
- NSTextView *tv;
-
- tv = (NSTextView *) onwhat;
- [tv setEnabledTextCheckingTypes:0];
- [tv setAutomaticDashSubstitutionEnabled:NO];
- // don't worry about automatic data detection; it won't change stringValue (thanks pretty_function in irc.freenode.net/#macdev)
- [tv setAutomaticSpellingCorrectionEnabled:NO];
- [tv setAutomaticTextReplacementEnabled:NO];
-}
diff --git a/redo/common_unix.go b/redo/common_unix.go
deleted file mode 100644
index d88afbb..0000000
--- a/redo/common_unix.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// /* because cgo doesn't like g_signal_connect() */
-// void gSignalConnect(gpointer obj, gchar *sig, GCallback callback, gpointer data)
-// {
-// g_signal_connect(obj, sig, callback, data);
-// }
-// void gSignalConnectAfter(gpointer obj, gchar *sig, GCallback callback, gpointer data)
-// {
-// g_signal_connect_after(obj, sig, callback, data);
-// }
-import "C"
-
-func fromgstr(s *C.gchar) string {
- return C.GoString((*C.char)(unsafe.Pointer(s)))
-}
-
-func togstr(s string) *C.gchar {
- return (*C.gchar)(unsafe.Pointer(C.CString(s)))
-}
-
-func freegstr(s *C.gchar) {
- C.free(unsafe.Pointer(s))
-}
-
-func fromgbool(b C.gboolean) bool {
- return b != C.FALSE
-}
-
-func togbool(b bool) C.gboolean {
- if b == true {
- return C.TRUE
- }
- return C.FALSE
-}
-
-func g_signal_connect(object C.gpointer, name string, to C.GCallback, data C.gpointer) {
- cname := togstr(name)
- defer freegstr(cname)
- C.gSignalConnect(object, cname, to, data)
-}
-
-func g_signal_connect_after(object C.gpointer, name string, to C.GCallback, data C.gpointer) {
- cname := togstr(name)
- defer freegstr(cname)
- C.gSignalConnectAfter(object, cname, to, data)
-}
diff --git a/redo/common_windows.c b/redo/common_windows.c
deleted file mode 100644
index 327e707..0000000
--- a/redo/common_windows.c
+++ /dev/null
@@ -1,139 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-LRESULT getWindowTextLen(HWND hwnd)
-{
- return SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
-}
-
-void getWindowText(HWND hwnd, WPARAM n, LPWSTR buf)
-{
- SetLastError(0);
- if (SendMessageW(hwnd, WM_GETTEXT, n + 1, (LPARAM) buf) != (LRESULT) n)
- xpanic("WM_GETTEXT did not copy the correct number of characters out", GetLastError());
-}
-
-void setWindowText(HWND hwnd, LPWSTR text)
-{
- switch (SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM) text)) {
- case FALSE:
- xpanic("WM_SETTEXT failed", GetLastError());
- }
-}
-
-void updateWindow(HWND hwnd)
-{
- if (UpdateWindow(hwnd) == 0)
- xpanic("error calling UpdateWindow()", GetLastError());
-}
-
-void *getWindowData(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult, void (*storeHWND)(void *, HWND))
-{
- CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
- void *data;
-
- data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
- if (data == NULL) {
- // the lpParam is available during WM_NCCREATE and WM_CREATE
- if (uMsg == WM_NCCREATE) {
- SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams));
- data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
- (*storeHWND)(data, hwnd);
- }
- // act as if we're not ready yet, even during WM_NCCREATE (nothing important to the switch statement below happens here anyway)
- *lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- return data;
-}
-
-/*
-all container windows (including the message-only window, hence this is not in container_windows.c) have to call the sharedWndProc() to ensure messages go in the right place and control colors are handled properly
-*/
-
-/*
-all controls that have events receive the events themselves through subclasses
-to do this, all container windows (including the message-only window; see http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q104069) forward WM_COMMAND to each control with this function, WM_NOTIFY with forwardNotify, etc.
-*/
-static LRESULT forwardCommand(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- HWND control = (HWND) lParam;
-
- // don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
- if (control != NULL && IsChild(msgwin, control) == 0)
- return SendMessageW(control, msgCOMMAND, wParam, lParam);
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-}
-
-static LRESULT forwardNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- NMHDR *nmhdr = (NMHDR *) lParam;
- HWND control = nmhdr->hwndFrom;
-
- // don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
- if (control != NULL && IsChild(msgwin, control) == 0)
- return SendMessageW(control, msgNOTIFY, wParam, lParam);
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-}
-
-BOOL sharedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
-{
- switch (uMsg) {
- case WM_COMMAND:
- *lResult = forwardCommand(hwnd, uMsg, wParam, lParam);
- return TRUE;
- case WM_NOTIFY:
- *lResult = forwardNotify(hwnd, uMsg, wParam, lParam);
- return TRUE;
- case WM_CTLCOLORSTATIC:
- case WM_CTLCOLORBTN:
- if (SetBkMode((HDC) wParam, TRANSPARENT) == 0)
- xpanic("error setting transparent background mode to Labels", GetLastError());
- paintControlBackground((HWND) lParam, (HDC) wParam);
- *lResult = (LRESULT) hollowBrush;
- return TRUE;
- }
- return FALSE;
-}
-
-void paintControlBackground(HWND hwnd, HDC dc)
-{
- HWND parent;
- RECT r;
- POINT p;
- int saved;
- WCHAR classname[128] = L""; // more than enough to avoid collisions
-
- parent = hwnd;
- do {
- parent = GetParent(parent);
- if (parent == NULL)
- xpanic("error getting parent container of control in paintControlBackground()", GetLastError());
- // wine sends these messages early, yay...
- if (parent == msgwin)
- return;
- parent = GetParent(parent);
- if (parent == NULL)
- xpanic("error getting parent control of control in paintControlBackground()", GetLastError());
- if (parent == msgwin)
- return;
- if (GetClassNameW(parent, classname, 128) == 0)
- xpanic("error getting name of focused window class in paintControlBackground()", GetLastError());
- } while (_wcsicmp(classname, L"button") == 0); // skip groupboxes
- if (GetWindowRect(hwnd, &r) == 0)
- xpanic("error getting control's window rect in paintControlBackground()", GetLastError());
- // the above is a window rect; convert to client rect
- p.x = r.left;
- p.y = r.top;
- if (ScreenToClient(parent, &p) == 0)
- xpanic("error getting client origin of control in paintControlBackground()", GetLastError());
- saved = SaveDC(dc);
- if (saved == 0)
- xpanic("error saving DC info in paintControlBackground()", GetLastError());
- if (SetWindowOrgEx(dc, p.x, p.y, NULL) == 0)
- xpanic("error moving window origin in paintControlBackground()", GetLastError());
- SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) dc, PRF_CLIENT);
- if (RestoreDC(dc, saved) == 0)
- xpanic("error restoring DC info in paintControlBackground()", GetLastError());
-}
diff --git a/redo/common_windows.go b/redo/common_windows.go
deleted file mode 100644
index d7f8eaf..0000000
--- a/redo/common_windows.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// 12 july 2014
-
-package ui
-
-import (
- "fmt"
- "syscall"
- "unsafe"
- "reflect"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-//export xpanic
-func xpanic(msg *C.char, lasterr C.DWORD) {
- panic(fmt.Errorf("%s: %s", C.GoString(msg), syscall.Errno(lasterr)))
-}
-
-//export xpanichresult
-func xpanichresult(msg *C.char, hresult C.HRESULT) {
- panic(fmt.Errorf("%s; HRESULT: 0x%X", C.GoString(msg), hresult))
-}
-
-//export xpaniccomdlg
-func xpaniccomdlg(msg *C.char, err C.DWORD) {
- panic(fmt.Errorf("%s; comdlg32.dll extended error: 0x%X", C.GoString(msg), err))
-}
-
-//export xmissedmsg
-func xmissedmsg(purpose *C.char, f *C.char, uMsg C.UINT) {
- panic(fmt.Errorf("%s window procedure message %d does not return a value (bug in %s)", C.GoString(purpose), uMsg, C.GoString(f)))
-}
-
-func toUTF16(s string) C.LPWSTR {
- return C.LPWSTR(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))
-}
-
-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))
- C.getWindowText(hwnd, C.WPARAM(n),
- C.LPWSTR(unsafe.Pointer(&buf[0])))
- return syscall.UTF16ToString(buf)
-}
-
-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),
- }
- buf := (*[]uint16)(unsafe.Pointer(xbuf))
- return syscall.UTF16ToString(*buf)
-}
diff --git a/redo/container.go b/redo/container.go
deleted file mode 100644
index c855072..0000000
--- a/redo/container.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// 25 june 2014
-
-package ui
-
-type allocation struct {
- 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
-}
-
-type controlSizing interface {
- allocate(x int, y int, width int, height int, d *sizing) []*allocation
- preferredSize(*sizing) (int, int)
- commitResize(*allocation, *sizing)
- getAuxResizeInfo(*sizing)
-}
-
-// A container hosts a Control and resizes that Control based on changes in size to the parent Window.
-// container is used by Window, Tab, and Group to contain and control their respective Controls.
-// Tab and Group use containers for their content; as such, their commitResize() functions should only change the size of the Tab and Group themselves, and have their containers do the real work.
-// All containers must embed containerbase.
-type containerbase struct {
- child Control
-}
-
-// set to true to apply spacing to all windows
-var spaced bool = false
-
-func (c *container) resize(x, y, width, height int) {
- 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)
- 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-- {
- allocations[i].this.commitResize(allocations[i], d)
- }
-}
diff --git a/redo/container_darwin.go b/redo/container_darwin.go
deleted file mode 100644
index 8b98b64..0000000
--- a/redo/container_darwin.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// 4 august 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type container struct {
- containerbase
- id C.id
-}
-
-type sizing struct {
- sizingbase
-
- // for size calculations
- // nothing for mac
-
- // for the actual resizing
- neighborAlign C.struct_xalignment
-}
-
-func newContainer(child Control) *container {
- c := new(container)
- c.id = C.newContainerView(unsafe.Pointer(c))
- c.child = child
- c.child.setParent(&controlParent{c.id})
- return c
-}
-
-//export containerResized
-func containerResized(data unsafe.Pointer, width C.intptr_t, height C.intptr_t) {
- c := (*container)(unsafe.Pointer(data))
- // the origin of a view's content area is always (0, 0)
- c.resize(0, 0, int(width), int(height))
-}
-
-// These are based on measurements from Interface Builder.
-const (
- macXMargin = 20
- macYMargin = 20
- macXPadding = 8
- macYPadding = 8
-)
-
-func (c *container) beginResize() (d *sizing) {
- d = new(sizing)
- if spaced {
- d.xmargin = macXMargin
- d.ymargintop = macYMargin
- d.ymarginbottom = d.ymargintop
- d.xpadding = macXPadding
- d.ypadding = macYPadding
- }
- return d
-}
-
-func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
- for _, a := range allocations {
- // winheight - y because (0,0) is the bottom-left corner of the window and not the top-left corner
- // (winheight - y) - height because (x, y) is the bottom-left corner of the control and not the top-left
- a.y = (winheight - a.y) - a.height
- }
-}
diff --git a/redo/container_darwin.m b/redo/container_darwin.m
deleted file mode 100644
index 0a598c6..0000000
--- a/redo/container_darwin.m
+++ /dev/null
@@ -1,44 +0,0 @@
-// 4 august 2014
-
-#include "objc_darwin.h"
-#include "_cgo_export.h"
-#include <Cocoa/Cocoa.h>
-
-#define toNSView(x) ((NSView *) (x))
-
-// calling -[className] on the content views of NSWindow, NSTabItem, and NSBox all return NSView, so I'm assuming I just need to override these
-// fornunately:
-// - NSWindow resizing calls -[setFrameSize:] (but not -[setFrame:])
-// - NSTab resizing calls both -[setFrame:] and -[setFrameSIze:] on the current tab
-// - NSTab switching tabs calls both -[setFrame:] and -[setFrameSize:] on the new tab
-// so we just override setFrameSize:
-// thanks to mikeash and JtRip in irc.freenode.net/#macdev
-@interface goContainerView : NSView {
-@public
- void *gocontainer;
-}
-@end
-
-@implementation goContainerView
-
-- (void)setFrameSize:(NSSize)s
-{
- [super setFrameSize:s];
- containerResized(self->gocontainer, (intptr_t) s.width, (intptr_t) s.height);
-}
-
-@end
-
-id newContainerView(void *gocontainer)
-{
- goContainerView *c;
-
- c = [[goContainerView alloc] initWithFrame:NSZeroRect];
- c->gocontainer = gocontainer;
- return (id) c;
-}
-
-void moveControl(id c, intptr_t x, intptr_t y, intptr_t width, intptr_t height)
-{
- [toNSView(c) setFrame:NSMakeRect((CGFloat) x, (CGFloat) y, (CGFloat) width, (CGFloat) height)];
-}
diff --git a/redo/container_unix.c b/redo/container_unix.c
deleted file mode 100644
index 9802383..0000000
--- a/redo/container_unix.c
+++ /dev/null
@@ -1,103 +0,0 @@
-// +build !windows,!darwin
-
-// 13 august 2014
-
-#include "gtk_unix.h"
-#include "_cgo_export.h"
-
-#define GOCONTAINER_TYPE (goContainer_get_type())
-#define GOCONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GOCONTAINER_TYPE, goContainer))
-#define IS_GOCONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GOCONTAINER_TYPE))
-#define GOCONTAINER_CLASS(class) (G_TYPE_CHECK_CLASS_CAST((class), GOCONTAINER_TYPE, goContainerClass))
-#define IS_GOCONTAINER_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE((class), GOCONTAINER_TYPE))
-#define GOCONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GOCONTAINER_TYPE, goContainerClass))
-
-typedef struct goContainer goContainer;
-typedef struct goContainerClass goContainerClass;
-
-struct goContainer {
- GtkContainer parent_instance;
- void *gocontainer;
- GPtrArray *children; // for forall()
-};
-
-struct goContainerClass {
- GtkContainerClass parent_class;
-};
-
-G_DEFINE_TYPE(goContainer, goContainer, GTK_TYPE_CONTAINER)
-
-static void goContainer_init(goContainer *c)
-{
- c->children = g_ptr_array_new();
- gtk_widget_set_has_window(GTK_WIDGET(c), FALSE);
-}
-
-static void goContainer_dispose(GObject *obj)
-{
- g_ptr_array_unref(GOCONTAINER(obj)->children);
- G_OBJECT_CLASS(goContainer_parent_class)->dispose(obj);
-}
-
-static void goContainer_finalize(GObject *obj)
-{
- G_OBJECT_CLASS(goContainer_parent_class)->finalize(obj);
-}
-
-static void goContainer_add(GtkContainer *container, GtkWidget *widget)
-{
- gtk_widget_set_parent(widget, GTK_WIDGET(container));
- g_ptr_array_add(GOCONTAINER(container)->children, widget);
-}
-
-static void goContainer_remove(GtkContainer *container, GtkWidget *widget)
-{
- gtk_widget_unparent(widget);
- g_ptr_array_remove(GOCONTAINER(container)->children, widget);
-}
-
-static void goContainer_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
-{
- gtk_widget_set_allocation(widget, allocation);
- containerResizing(GOCONTAINER(widget)->gocontainer, allocation);
-}
-
-struct forall {
- GtkCallback callback;
- gpointer data;
-};
-
-static void doforall(gpointer obj, gpointer data)
-{
- struct forall *s = (struct forall *) data;
-
- (*(s->callback))(GTK_WIDGET(obj), s->data);
-}
-
-static void goContainer_forall(GtkContainer *container, gboolean includeInternals, GtkCallback callback, gpointer data)
-{
- struct forall s;
-
- s.callback = callback;
- s.data = data;
- g_ptr_array_foreach(GOCONTAINER(container)->children, doforall, &s);
-}
-
-static void goContainer_class_init(goContainerClass *class)
-{
- G_OBJECT_CLASS(class)->dispose = goContainer_dispose;
- G_OBJECT_CLASS(class)->finalize = goContainer_finalize;
- GTK_WIDGET_CLASS(class)->size_allocate = goContainer_size_allocate;
- GTK_CONTAINER_CLASS(class)->add = goContainer_add;
- GTK_CONTAINER_CLASS(class)->remove = goContainer_remove;
- GTK_CONTAINER_CLASS(class)->forall = goContainer_forall;
-}
-
-GtkWidget *newContainer(void *gocontainer)
-{
- goContainer *c;
-
- c = (goContainer *) g_object_new(GOCONTAINER_TYPE, NULL);
- c->gocontainer = gocontainer;
- return GTK_WIDGET(c);
-}
diff --git a/redo/container_unix.go b/redo/container_unix.go
deleted file mode 100644
index fbfd993..0000000
--- a/redo/container_unix.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// +build !windows,!darwin
-
-// 23 february 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-import "C"
-
-type container struct {
- containerbase
- layoutwidget *C.GtkWidget
- layoutcontainer *C.GtkContainer
-}
-
-type sizing struct {
- sizingbase
-
- // for size calculations
- // gtk+ needs nothing
-
- // for the actual resizing
- shouldVAlignTop bool
-}
-
-func newContainer(child Control) *container {
- c := new(container)
- widget := C.newContainer(unsafe.Pointer(c))
- c.layoutwidget = widget
- c.layoutcontainer = (*C.GtkContainer)(unsafe.Pointer(widget))
- c.child = child
- c.child.setParent(&controlParent{c.layoutcontainer})
- return c
-}
-
-func (c *container) setParent(p *controlParent) {
- C.gtk_container_add(p.c, c.layoutwidget)
-}
-
-//export containerResizing
-func containerResizing(data unsafe.Pointer, r *C.GtkAllocation) {
- c := (*container)(data)
- c.resize(int(r.x), int(r.y), int(r.width), int(r.height))
-}
-
-const (
- gtkXMargin = 12
- gtkYMargin = 12
- gtkXPadding = 12
- gtkYPadding = 6
-)
-
-func (c *container) beginResize() (d *sizing) {
- d = new(sizing)
- if spaced {
- d.xmargin = gtkXMargin
- d.ymargintop = gtkYMargin
- d.ymarginbottom = d.ymargintop
- d.xpadding = gtkXPadding
- d.ypadding = gtkYPadding
- }
- return d
-}
-
-func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
- // no need for coordinate conversion with gtk+
-}
diff --git a/redo/container_windows.c b/redo/container_windows.c
deleted file mode 100644
index a95818d..0000000
--- a/redo/container_windows.c
+++ /dev/null
@@ -1,96 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-/*
-This could all just be part of Window, but doing so just makes things complex.
-In this case, I chose to waste a window handle rather than keep things super complex.
-If this is seriously an issue in the future, I can roll it back.
-*/
-
-#define containerclass L"gouicontainer"
-
-static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- void *data;
- RECT r;
- LRESULT lResult;
-
- data = getWindowData(hwnd, uMsg, wParam, lParam, &lResult, storeContainerHWND);
- if (data == NULL)
- return lResult;
- if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult))
- return lResult;
- switch (uMsg) {
- case WM_SIZE:
- if (GetClientRect(hwnd, &r) == 0)
- xpanic("error getting client rect for Window in WM_SIZE", GetLastError());
- containerResize(data, &r);
- return 0;
- default:
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("container", "containerWndProc()", uMsg);
- return 0; // unreached
-}
-
-DWORD makeContainerWindowClass(char **errmsg)
-{
- WNDCLASSW wc;
-
- ZeroMemory(&wc, sizeof (WNDCLASSW));
- wc.lpfnWndProc = containerWndProc;
- wc.hInstance = hInstance;
- wc.hIcon = hDefaultIcon;
- wc.hCursor = hArrowCursor;
- wc.hbrBackground = NULL;//(HBRUSH) (COLOR_BTNFACE + 1);
- wc.lpszClassName = containerclass;
- if (RegisterClassW(&wc) == 0) {
- *errmsg = "error registering container window class";
- return GetLastError();
- }
- return 0;
-}
-
-HWND newContainer(void *data)
-{
- HWND hwnd;
-
- hwnd = CreateWindowExW(
- WS_EX_CONTROLPARENT | WS_EX_TRANSPARENT,
- containerclass, L"",
- WS_CHILD | WS_VISIBLE,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 100, 100,
- msgwin, NULL, hInstance, data);
- if (hwnd == NULL)
- xpanic("container creation failed", GetLastError());
- return hwnd;
-}
-
-void calculateBaseUnits(HWND hwnd, int *baseX, int *baseY, LONG *internalLeading)
-{
- HDC dc;
- HFONT prevFont;
- TEXTMETRICW tm;
- SIZE size;
-
- dc = GetDC(hwnd);
- if (dc == NULL)
- xpanic("error getting DC for preferred size calculations", GetLastError());
- prevFont = (HFONT) SelectObject(dc, controlFont);
- if (prevFont == NULL)
- xpanic("error loading control font into device context for preferred size calculation", GetLastError());
- if (GetTextMetricsW(dc, &tm) == 0)
- xpanic("error getting text metrics for preferred size calculations", GetLastError());
- if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0)
- xpanic("error getting text extent point for preferred size calculations", GetLastError());
- *baseX = (int) ((size.cx / 26 + 1) / 2);
- *baseY = (int) tm.tmHeight;
- *internalLeading = tm.tmInternalLeading;
- if (SelectObject(dc, prevFont) != controlFont)
- xpanic("error restoring previous font into device context after preferred size calculations", GetLastError());
- if (ReleaseDC(hwnd, dc) == 0)
- xpanic("error releasing DC for preferred size calculations", GetLastError());
-}
diff --git a/redo/container_windows.go b/redo/container_windows.go
deleted file mode 100644
index d3fd327..0000000
--- a/redo/container_windows.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// 4 august 2014
-
-package ui
-
-import (
- "fmt"
- "syscall"
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type container struct {
- containerbase
- 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
-
- // for the actual resizing
- // possibly the HDWP
-}
-
-func makeContainerWindowClass() error {
- var errmsg *C.char
-
- err := C.makeContainerWindowClass(&errmsg)
- if err != 0 || errmsg != nil {
- return fmt.Errorf("%s: %v", C.GoString(errmsg), syscall.Errno(err))
- }
- return nil
-}
-
-func newContainer(control Control) *container {
- c := new(container)
- hwnd := C.newContainer(unsafe.Pointer(c))
- if hwnd != c.hwnd {
- panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in container (%p) differ", hwnd, c.hwnd))
- }
- c.child = control
- c.child.setParent(&controlParent{c})
- return c
-}
-
-func (c *container) setParent(hwnd C.HWND) {
- C.controlSetParent(c.hwnd, hwnd)
-}
-
-// this is needed because Windows won't move/resize a child window for us
-func (c *container) move(r *C.RECT) {
- C.moveWindow(c.hwnd, C.int(r.left), C.int(r.top), C.int(r.right - r.left), C.int(r.bottom - r.top))
-}
-
-func (c *container) show() {
- C.ShowWindow(c.hwnd, C.SW_SHOW)
-}
-
-func (c *container) hide() {
- C.ShowWindow(c.hwnd, C.SW_HIDE)
-}
-
-//export storeContainerHWND
-func storeContainerHWND(data unsafe.Pointer, hwnd C.HWND) {
- c := (*container)(data)
- c.hwnd = hwnd
-}
-
-//export containerResize
-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))
-}
-
-// 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.
-// These sizes are given in "dialog units", which are independent of the font in use.
-// We need to convert these into standard pixels, which requires we get the device context of the OS window.
-// References:
-// - http://msdn.microsoft.com/en-us/library/ms645502%28VS.85%29.aspx - the calculation needed
-// - http://support.microsoft.com/kb/125681 - to get the base X and Y
-// (thanks to http://stackoverflow.com/questions/58620/default-button-size)
-// In my tests (see https://github.com/andlabs/windlgunits), the GetTextExtentPoint32() option for getting the base X produces much more accurate results than the tmAveCharWidth option when tested against the sample values given in http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing, but can be off by a pixel in either direction (probably due to rounding errors).
-
-// note on MulDiv():
-// div will not be 0 in the usages below
-// we also ignore overflow; that isn't likely to happen for our use case anytime soon
-
-func fromdlgunitsX(du int, d *sizing) int {
- return int(C.MulDiv(C.int(du), d.baseX, 4))
-}
-
-func fromdlgunitsY(du int, d *sizing) int {
- return int(C.MulDiv(C.int(du), d.baseY, 8))
-}
-
-const (
- marginDialogUnits = 7
- paddingDialogUnits = 4
-
- groupXMargin = 6
- groupYMarginTop = 11 // note this value /includes the groupbox label/
- groupYMarginBottom = 7
-)
-
-func (c *container) beginResize() (d *sizing) {
- var baseX, baseY C.int
- var internalLeading C.LONG
-
- d = new(sizing)
-
- C.calculateBaseUnits(c.hwnd, &baseX, &baseY, &internalLeading)
- d.baseX = baseX
- d.baseY = baseY
- d.internalLeading = internalLeading
-
- if spaced {
- d.xmargin = fromdlgunitsX(marginDialogUnits, d)
- d.ymargintop = fromdlgunitsY(marginDialogUnits, d)
- d.ymarginbottom = d.ymargintop
- d.xpadding = fromdlgunitsX(paddingDialogUnits, d)
- d.ypadding = fromdlgunitsY(paddingDialogUnits, d)
- }
- if c.isGroup {
- // note that these values apply regardless of whether or not spaced is set
- // this is because Windows groupboxes have the client rect spanning the entire size of the control, not just the active work area
- // the measurements Microsoft give us are for spaced margining; let's just use them
- d.xmargin = fromdlgunitsX(groupXMargin, d)
- d.ymargintop = fromdlgunitsY(groupYMarginTop, d)
- d.ymarginbottom = fromdlgunitsY(groupYMarginBottom, d)
-
- }
-
- return d
-}
-
-func (c *container) translateAllocationCoords(allocations []*allocation, winwidth, winheight int) {
- // no translation needed on windows
-}
diff --git a/redo/control.go b/redo/control.go
deleted file mode 100644
index 0358965..0000000
--- a/redo/control.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// 30 july 2014
-
-package ui
-
-// Control represents a control.
-type Control interface {
- 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,
- }}
-}
diff --git a/redo/control_darwin.go b/redo/control_darwin.go
deleted file mode 100644
index b3b3dcf..0000000
--- a/redo/control_darwin.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// 30 july 2014
-
-package ui
-
-// #include "objc_darwin.h"
-import "C"
-
-// all Controls that call base methods must be this
-type controlPrivate interface {
- id() C.id
- Control
-}
-
-type controlParent struct {
- id C.id
-}
-
-func basesetParent(c controlPrivate, p *controlParent) {
- // redrawing the new window handled by C.parent()
- C.parent(c.id(), p.id)
-}
-
-func basepreferredSize(c controlPrivate, d *sizing) (int, int) {
- s := C.controlPreferredSize(c.id())
- return int(s.width), int(s.height)
-}
-
-func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
- dobasecommitResize(c.id(), a, d)
-}
-
-func dobasecommitResize(id C.id, c *allocation, d *sizing) {
- C.moveControl(id, C.intptr_t(c.x), C.intptr_t(c.y), C.intptr_t(c.width), C.intptr_t(c.height))
-}
-
-func basegetAuxResizeInfo(c controlPrivate, d *sizing) {
- d.neighborAlign = C.alignmentInfoFrame(c.id())
-}
-
-type scroller struct {
- id C.id
-}
-
-func newScroller(child C.id, bordered bool) *scroller {
- id := C.newScrollView(child, toBOOL(bordered))
- s := &scroller{
- id: id,
- }
- return s
-}
-
-func (s *scroller) setParent(p *controlParent) {
- C.parent(s.id, p.id)
-}
-
-func (s *scroller) commitResize(c *allocation, d *sizing) {
- dobasecommitResize(s.id, c, d)
-}
diff --git a/redo/control_darwin.m b/redo/control_darwin.m
deleted file mode 100644
index 816085b..0000000
--- a/redo/control_darwin.m
+++ /dev/null
@@ -1,98 +0,0 @@
-// 30 july 2014
-
-#import "objc_darwin.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSView(x) ((NSView *) (x))
-#define toNSControl(x) ((NSControl *) (x))
-
-void parent(id control, id parentid)
-{
- [toNSView(parentid) addSubview:toNSView(control)];
-}
-
-void controlSetHidden(id control, BOOL hidden)
-{
- [toNSView(control) setHidden:hidden];
-}
-
-// also fine for NSCells
-void setStandardControlFont(id control)
-{
- [toNSControl(control) setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
-}
-
-// also fine for NSCells
-void setSmallControlFont(id control)
-{
- [toNSControl(control) setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
-}
-
-// also good for NSBox and NSProgressIndicator
-struct xsize controlPreferredSize(id control)
-{
- NSControl *c;
- NSRect r;
- struct xsize s;
-
- c = toNSControl(control);
- [c sizeToFit];
- r = [c frame];
- s.width = (intptr_t) r.size.width;
- s.height = (intptr_t) r.size.height;
- return s;
-}
-
-id newScrollView(id content, BOOL bordered)
-{
- NSScrollView *sv;
-
- sv = [[NSScrollView alloc] initWithFrame:NSZeroRect];
- [sv setDocumentView:toNSView(content)];
- [sv setHasHorizontalScroller:YES];
- [sv setHasVerticalScroller:YES];
- [sv setAutohidesScrollers:YES];
- if (bordered)
- [sv setBorderType:NSBezelBorder];
- else
- [sv setBorderType:NSNoBorder];
- return (id) sv;
-}
-
-// these function are safe to call on Areas; they'll just return the frame and a baseline of 0 since they use the default NSView implementations
-
-static struct xalignment doAlignmentInfo(NSView *v, NSRect r)
-{
- struct xalignment a;
-
- r = [v alignmentRectForFrame:r];
- a.rect.x = (intptr_t) r.origin.x;
- a.rect.y = (intptr_t) r.origin.y;
- a.rect.width = (intptr_t) r.size.width;
- a.rect.height = (intptr_t) r.size.height;
- // I'm not sure if we need to set the frame for -[NSView baselineOffsetFromBottom], but let's do it just to be safe
- [v setFrame:r];
- a.baseline = (intptr_t) [v baselineOffsetFromBottom];
- return a;
-}
-
-struct xalignment alignmentInfo(id c, struct xrect newrect)
-{
- NSView *v;
- NSRect r;
-
- v = toNSView(c);
- r = NSMakeRect((CGFloat) newrect.x,
- (CGFloat) newrect.y,
- (CGFloat) newrect.width,
- (CGFloat) newrect.height);
- return doAlignmentInfo(v, r);
-}
-
-struct xalignment alignmentInfoFrame(id c)
-{
- NSView *v;
-
- v = toNSView(c);
- return doAlignmentInfo(v, [v frame]);
-}
diff --git a/redo/control_unix.go b/redo/control_unix.go
deleted file mode 100644
index 10193e8..0000000
--- a/redo/control_unix.go
+++ /dev/null
@@ -1,120 +0,0 @@
-// +build !windows,!darwin
-
-// 30 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-import "C"
-
-// all Controls that call base methods must be this
-type controlPrivate interface {
- widget() *C.GtkWidget
- Control
-}
-
-type controlParent struct {
- c *C.GtkContainer
-}
-
-func basesetParent(c controlPrivate, p *controlParent) {
- 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)
-}
-
-func basepreferredSize(c controlPrivate, d *sizing) (int, int) {
- // GTK+ 3 makes this easy: controls can tell us what their preferred size is!
- // ...actually, it tells us two things: the "minimum size" and the "natural size".
- // The "minimum size" is the smallest size we /can/ display /anything/. The "natural size" is the smallest size we would /prefer/ to display.
- // The difference? Minimum size takes into account things like truncation with ellipses: the minimum size of a label can allot just the ellipses!
- // So we use the natural size instead.
- // There is a warning about height-for-width controls, but in my tests this isn't an issue.
- var r C.GtkRequisition
-
- C.gtk_widget_get_preferred_size(c.widget(), nil, &r)
- return int(r.width), int(r.height)
-}
-
-func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
- dobasecommitResize(c.widget(), a, d)
-}
-
-func dobasecommitResize(w *C.GtkWidget, c *allocation, d *sizing) {
- // as we resize on size-allocate, we have to also use size-allocate on our children
- // this is fine anyway; in fact, this allows us to move without knowing what the container is!
- // this is what GtkBox does anyway
- // thanks to tristan in irc.gimp.net/#gtk+
-
- var r C.GtkAllocation
-
- r.x = C.int(c.x)
- r.y = C.int(c.y)
- r.width = C.int(c.width)
- r.height = C.int(c.height)
- C.gtk_widget_size_allocate(w, &r)
-}
-
-func basegetAuxResizeInfo(c Control, d *sizing) {
- // controls set this to true if a Label to its left should be vertically aligned to the control's top
- d.shouldVAlignTop = false
-}
-
-type scroller struct {
- scrollwidget *C.GtkWidget
- scrollcontainer *C.GtkContainer
- scrollwindow *C.GtkScrolledWindow
-
- overlaywidget *C.GtkWidget
- overlaycontainer *C.GtkContainer
- overlay *C.GtkOverlay
-
- addShowWhich *C.GtkWidget
-}
-
-func newScroller(widget *C.GtkWidget, native bool, bordered bool, overlay bool) *scroller {
- var o *C.GtkWidget
-
- scrollwidget := C.gtk_scrolled_window_new(nil, nil)
- if overlay {
- 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)),
- }
- // give the scrolled window a border (thanks to jlindgren in irc.gimp.net/#gtk+)
- if bordered {
- C.gtk_scrolled_window_set_shadow_type(s.scrollwindow, C.GTK_SHADOW_IN)
- }
- if native {
- C.gtk_container_add(s.scrollcontainer, widget)
- } else {
- C.gtk_scrolled_window_add_with_viewport(s.scrollwindow, widget)
- }
- s.addShowWhich = s.scrollwidget
- if overlay {
- C.gtk_container_add(s.overlaycontainer, s.scrollwidget)
- s.addShowWhich = s.overlaywidget
- }
- return s
-}
-
-func (s *scroller) setParent(p *controlParent) {
- C.gtk_container_add(p.c, s.addShowWhich)
- // see basesetParent() above for why we call gtk_widget_show_all()
- C.gtk_widget_show_all(s.addShowWhich)
-}
-
-func (s *scroller) commitResize(c *allocation, d *sizing) {
- dobasecommitResize(s.addShowWhich, c, d)
-}
diff --git a/redo/control_windows.c b/redo/control_windows.c
deleted file mode 100644
index 03af5c6..0000000
--- a/redo/control_windows.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-HWND newControl(LPWSTR class, DWORD style, DWORD extstyle)
-{
- HWND hwnd;
-
- hwnd = CreateWindowExW(
- extstyle,
- class, L"",
- style | WS_CHILD | WS_VISIBLE,
- CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT,
- // the following has the consequence of making the control message-only at first
- // this shouldn't cause any problems... hopefully not
- // but see the msgwndproc() for caveat info
- // also don't use low control IDs as they will conflict with dialog boxes (IDCANCEL, etc.)
- msgwin, (HMENU) 100, hInstance, NULL);
- if (hwnd == NULL)
- xpanic("error creating control", GetLastError());
- return hwnd;
-}
-
-void controlSetParent(HWND control, HWND parent)
-{
- if (SetParent(control, parent) == NULL)
- xpanic("error changing control parent", GetLastError());
-}
-
-void controlSetControlFont(HWND which)
-{
- SendMessageW(which, WM_SETFONT, (WPARAM) controlFont, TRUE);
-}
-
-void moveWindow(HWND hwnd, int x, int y, int width, int height)
-{
- if (MoveWindow(hwnd, x, y, width, height, TRUE) == 0)
- xpanic("error setting window/control rect", GetLastError());
-}
-
-LONG controlTextLength(HWND hwnd, LPWSTR text)
-{
- HDC dc;
- HFONT prev;
- SIZE size;
-
- dc = GetDC(hwnd);
- if (dc == NULL)
- xpanic("error getting DC of control for text length", GetLastError());
- prev = SelectObject(dc, controlFont);
- if (prev == NULL)
- xpanic("error setting control font to DC for text length", GetLastError());
- if (GetTextExtentPoint32W(dc, text, wcslen(text), &size) == 0)
- xpanic("error actually getting text length", GetLastError());
- if (SelectObject(dc, prev) != controlFont)
- xpanic("error restoring previous control font to DC for text length", GetLastError());
- if (ReleaseDC(hwnd, dc) == 0)
- xpanic("error releasing DC of control for text length", GetLastError());
- return size.cx;
-}
diff --git a/redo/control_windows.go b/redo/control_windows.go
deleted file mode 100644
index 564d8d4..0000000
--- a/redo/control_windows.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// 30 july 2014
-
-package ui
-
-// #include "winapi_windows.h"
-import "C"
-
-type controlPrivate interface {
- hwnd() C.HWND
- Control
-}
-
-type controlParent struct {
- c *container
-}
-
-func basesetParent(c controlPrivate, p *controlParent) {
- C.controlSetParent(c.hwnd(), p.c.hwnd)
- p.c.nchildren++
-}
-
-// don't specify basepreferredSize; it is custom on ALL controls
-
-func basecommitResize(c controlPrivate, a *allocation, d *sizing) {
- C.moveWindow(c.hwnd(), C.int(a.x), C.int(a.y), C.int(a.width), C.int(a.height))
-}
-
-func basegetAuxResizeInfo(c controlPrivate, d *sizing) {
- // do nothing
-}
-
-// these are provided for convenience
-
-type textableControl interface {
- controlPrivate
- textlen() C.LONG
- settextlen(C.LONG)
-}
-
-func baseText(c textableControl) string {
- return getWindowText(c.hwnd())
-}
-
-func baseSetText(c textableControl, text string) {
- hwnd := c.hwnd()
- t := toUTF16(text)
- C.setWindowText(hwnd, t)
- c.settextlen(C.controlTextLength(hwnd, t))
-}
diff --git a/redo/controlbase.sh b/redo/controlbase.sh
deleted file mode 100755
index 6d10bb1..0000000
--- a/redo/controlbase.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-sed "s/AAA/$1/g
-s/BBB/$2/g
-s/CCC/$3/g
-s/DDD/$4/g" <<\END
-func (AAA *BBB) CCC() DDD {
- return AAA._CCC
-}
-
-func (AAA *BBB) setParent(p *controlParent) {
- basesetParent(AAA, p)
-}
-
-func (AAA *BBB) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(AAA, x, y, width, height, d)
-}
-
-func (AAA *BBB) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(AAA, d)
-}
-
-func (AAA *BBB) commitResize(a *allocation, d *sizing) {
- basecommitResize(AAA, a, d)
-}
-
-func (AAA *BBB) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(AAA, d)
-}
-END
diff --git a/redo/dialog.go b/redo/dialog.go
deleted file mode 100644
index 730e1be..0000000
--- a/redo/dialog.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// 18 august 2014
-
-package ui
-
-type windowDialog interface {
- openFile(f func(filename string))
-}
-
-// OpenFile opens a dialog box that asks the user to choose a file.
-// The dialog box is modal to win, which mut not be nil.
-// Some time after the dialog box is closed, OpenFile runs f on the main thread, passing filename.
-// filename is the selected filename, or an empty string if no file was chosen.
-// OpenFile does not ensure that f remains alive; the programmer is responsible for this.
-// If possible on a given system, OpenFile() will not dereference links; it will return the link file itself.
-// Hidden files will not be hidden by OpenFile().
-func OpenFile(win Window, f func(filename string)) {
- if win == nil {
- panic("Window passed to OpenFile() cannot be nil")
- }
- win.openFile(f)
-}
diff --git a/redo/dialog_darwin.go b/redo/dialog_darwin.go
deleted file mode 100644
index f1882a8..0000000
--- a/redo/dialog_darwin.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// 19 august 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-func (w *window) openFile(f func(filename string)) {
- C.openFile(w.id, unsafe.Pointer(&f))
-}
-
-//export finishOpenFile
-func finishOpenFile(fname *C.char, data unsafe.Pointer) {
- f := (*func(string))(data)
- if fname == nil {
- (*f)("")
- return
- }
- defer C.free(unsafe.Pointer(fname))
- (*f)(C.GoString(fname))
-}
diff --git a/redo/dialog_darwin.m b/redo/dialog_darwin.m
deleted file mode 100644
index 4fb9e3e..0000000
--- a/redo/dialog_darwin.m
+++ /dev/null
@@ -1,30 +0,0 @@
-// 19 august 2014
-
-#import "objc_darwin.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSWindow(x) ((NSWindow *) (x))
-
-void openFile(id parent, void *data)
-{
- NSOpenPanel *op;
-
- op = [NSOpenPanel openPanel];
- [op setCanChooseFiles:YES];
- [op setCanChooseDirectories:NO];
- [op setResolvesAliases:NO];
- [op setAllowsMultipleSelection:NO];
- [op setShowsHiddenFiles:YES];
- [op setCanSelectHiddenExtension:NO];
- [op setExtensionHidden:NO];
- [op setAllowsOtherFileTypes:YES];
- [op setTreatsFilePackagesAsDirectories:YES];
- [op beginSheetModalForWindow:toNSWindow(parent) completionHandler:^(NSInteger ret){
- if (ret != NSFileHandlingPanelOKButton) {
- finishOpenFile(NULL, data);
- return;
- }
- // string freed on the Go side
- finishOpenFile(strdup([[[op URL] path] UTF8String]), data);
- }];
-}
diff --git a/redo/dialog_unix.go b/redo/dialog_unix.go
deleted file mode 100644
index 158d11b..0000000
--- a/redo/dialog_unix.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// +build !windows,!darwin
-
-// 19 august 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern void our_openfile_response_callback(GtkDialog *, gint, gpointer);
-// /* because cgo doesn't like ... */
-// static inline GtkWidget *newOpenFileDialog(GtkWindow *parent)
-// {
-// return gtk_file_chooser_dialog_new(NULL, /* default title */
-// parent,
-// GTK_FILE_CHOOSER_ACTION_OPEN,
-// GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-// GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-// NULL);
-// }
-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))
- fc := (*C.GtkFileChooser)(unsafe.Pointer(widget))
- C.gtk_file_chooser_set_local_only(fc, C.FALSE)
- C.gtk_file_chooser_set_select_multiple(fc, C.FALSE)
- C.gtk_file_chooser_set_show_hidden(fc, C.TRUE)
- C.gtk_window_set_modal(window, C.TRUE)
- g_signal_connect(
- C.gpointer(unsafe.Pointer(dialog)),
- "response",
- C.GCallback(C.our_openfile_response_callback),
- C.gpointer(unsafe.Pointer(&f)))
- C.gtk_widget_show_all(widget)
-}
-
-//export our_openfile_response_callback
-func our_openfile_response_callback(dialog *C.GtkDialog, response C.gint, data C.gpointer) {
- f := (*func(string))(unsafe.Pointer(data))
- if response != C.GTK_RESPONSE_ACCEPT {
- (*f)("")
- C.gtk_widget_destroy((*C.GtkWidget)(unsafe.Pointer(dialog)))
- return
- }
- filename := C.gtk_file_chooser_get_filename((*C.GtkFileChooser)(unsafe.Pointer(dialog)))
- if filename == nil {
- panic("[DEBUG TODO] chosen filename NULL")
- }
- realfilename := fromgstr(filename)
- C.g_free(C.gpointer(unsafe.Pointer(filename)))
- C.gtk_widget_destroy((*C.GtkWidget)(unsafe.Pointer(dialog)))
- (*f)(realfilename)
-}
diff --git a/redo/dialog_windows.c b/redo/dialog_windows.c
deleted file mode 100644
index f8ef687..0000000
--- a/redo/dialog_windows.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// 18 august 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-// this should be reasonable
-#define NFILENAME 4096
-
-struct openFileData {
- HWND parent;
- void *f;
- WCHAR *filenameBuffer;
-};
-
-static DWORD WINAPI doOpenFile(LPVOID data)
-{
- struct openFileData *o = (struct openFileData *) data;
- OPENFILENAMEW ofn;
- DWORD err;
-
- o->filenameBuffer[0] = L'\0'; // required by GetOpenFileName() to indicate no previous filename
- ZeroMemory(&ofn, sizeof (OPENFILENAMEW));
- ofn.lStructSize = sizeof (OPENFILENAMEW);
- ofn.hwndOwner = o->parent;
- ofn.hInstance = hInstance;
- ofn.lpstrFilter = NULL; // no filters
- ofn.lpstrFile = o->filenameBuffer;
- ofn.nMaxFile = NFILENAME + 1; // seems to include null terminator according to docs
- ofn.lpstrInitialDir = NULL; // let system decide
- ofn.lpstrTitle = NULL; // let system decide
- // TODO OFN_SHAREAWARE?
- ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_FORCESHOWHIDDEN | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_NOCHANGEDIR | OFN_NODEREFERENCELINKS | OFN_NOTESTFILECREATE | OFN_PATHMUSTEXIST;
- if (GetOpenFileNameW(&ofn) == FALSE) {
- err = CommDlgExtendedError();
- if (err != 0) // user cancelled
- xpaniccomdlg("error running open file dialog", err);
- free(o->filenameBuffer); // free now so we can set it to NULL without leaking
- o->filenameBuffer = NULL;
- }
- if (PostMessageW(msgwin, msgOpenFileDone, (WPARAM) (o->filenameBuffer), (LPARAM) (o->f)) == 0)
- xpanic("error posting OpenFile() finished message to message-only window", GetLastError());
- free(o); // won't free o->f or o->filenameBuffer in above invocation
- return 0;
-}
-
-void openFile(HWND hwnd, void *f)
-{
- struct openFileData *o;
-
- // freed by the thread
- o = (struct openFileData *) malloc(sizeof (struct openFileData));
- if (o == NULL)
- xpanic("memory exhausted allocating data structure in OpenFile()", GetLastError());
- o->parent = hwnd;
- o->f = f;
- // freed on the Go side
- o->filenameBuffer = (WCHAR *) malloc((NFILENAME + 1) * sizeof (WCHAR));
- if (o->filenameBuffer == NULL)
- xpanic("memory exhausted allocating filename buffer in OpenFile()", GetLastError());
- if (CreateThread(NULL, 0, doOpenFile, (LPVOID) o, 0, NULL) == NULL)
- xpanic("error creating thread for running OpenFIle()", GetLastError());
-}
diff --git a/redo/dialog_windows.go b/redo/dialog_windows.go
deleted file mode 100644
index 80f7ac6..0000000
--- a/redo/dialog_windows.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// 18 august 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-func (w *window) openFile(f func(filename string)) {
- C.openFile(w.hwnd, unsafe.Pointer(&f))
-}
-
-//export finishOpenFile
-func finishOpenFile(name *C.WCHAR, fp unsafe.Pointer) {
- f := (*func(string))(fp)
- if name == nil {
- (*f)("")
- return
- }
- defer C.free(unsafe.Pointer(name))
- (*f)(wstrToString(name))
-}
diff --git a/redo/doc.go b/redo/doc.go
deleted file mode 100644
index be96265..0000000
--- a/redo/doc.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// 14 august 2014
-
-/*
-[this is being written]
-
-notes:
-- default behavior of event handlers is to do nothing
-- default behavior of event handlers that return bool is to do nothing but return false
-- passing nil to an event handler set function restores default behavior
-- only functions safe for calling outside Do() are Go(), Do(), and Stop()
-*/
-package ui
diff --git a/redo/events_darwin.go b/redo/events_darwin.go
deleted file mode 100644
index d9cbe0c..0000000
--- a/redo/events_darwin.go
+++ /dev/null
@@ -1,132 +0,0 @@
-// 30 march 2014
-
-package ui
-
-/*
-Mac OS X uses its own set of hardware key codes that are different from PC keyboard scancodes, but are positional (like PC keyboard scancodes). These are defined in <HIToolbox/Events.h>, a Carbon header. As far as I can tell, there's no way to include this header without either using an absolute path or linking Carbon into the program, so the constant values are used here instead.
-
-The Cocoa docs do guarantee that -[NSEvent keyCode] results in key codes that are the same as those returned by Carbon; that is, these codes.
-*/
-
-// use uintptr to be safe
-var keycodeKeys = map[uintptr]byte{
- 0x00: 'a',
- 0x01: 's',
- 0x02: 'd',
- 0x03: 'f',
- 0x04: 'h',
- 0x05: 'g',
- 0x06: 'z',
- 0x07: 'x',
- 0x08: 'c',
- 0x09: 'v',
- 0x0B: 'b',
- 0x0C: 'q',
- 0x0D: 'w',
- 0x0E: 'e',
- 0x0F: 'r',
- 0x10: 'y',
- 0x11: 't',
- 0x12: '1',
- 0x13: '2',
- 0x14: '3',
- 0x15: '4',
- 0x16: '6',
- 0x17: '5',
- 0x18: '=',
- 0x19: '9',
- 0x1A: '7',
- 0x1B: '-',
- 0x1C: '8',
- 0x1D: '0',
- 0x1E: ']',
- 0x1F: 'o',
- 0x20: 'u',
- 0x21: '[',
- 0x22: 'i',
- 0x23: 'p',
- 0x25: 'l',
- 0x26: 'j',
- 0x27: '\'',
- 0x28: 'k',
- 0x29: ';',
- 0x2A: '\\',
- 0x2B: ',',
- 0x2C: '/',
- 0x2D: 'n',
- 0x2E: 'm',
- 0x2F: '.',
- 0x32: '`',
- 0x24: '\n',
- 0x30: '\t',
- 0x31: ' ',
- 0x33: '\b',
-}
-
-var keycodeExtKeys = map[uintptr]ExtKey{
- 0x41: NDot,
- 0x43: NMultiply,
- 0x45: NAdd,
- 0x4B: NDivide,
- 0x4C: NEnter,
- 0x4E: NSubtract,
- 0x52: N0,
- 0x53: N1,
- 0x54: N2,
- 0x55: N3,
- 0x56: N4,
- 0x57: N5,
- 0x58: N6,
- 0x59: N7,
- 0x5B: N8,
- 0x5C: N9,
- 0x35: Escape,
- 0x60: F5,
- 0x61: F6,
- 0x62: F7,
- 0x63: F3,
- 0x64: F8,
- 0x65: F9,
- 0x67: F11,
- 0x6D: F10,
- 0x6F: F12,
- 0x72: Insert, // listed as the Help key but it's in the same position on an Apple keyboard as the Insert key on a Windows keyboard; thanks to SeanieB from irc.badnik.net and Psy in irc.freenode.net/#macdev for confirming they have the same code
- 0x73: Home,
- 0x74: PageUp,
- 0x75: Delete,
- 0x76: F4,
- 0x77: End,
- 0x78: F2,
- 0x79: PageDown,
- 0x7A: F1,
- 0x7B: Left,
- 0x7C: Right,
- 0x7D: Down,
- 0x7E: Up,
-}
-
-var keycodeModifiers = map[uintptr]Modifiers{
- 0x37: Super, // left command
- 0x38: Shift, // left shift
- 0x3A: Alt, // left option
- 0x3B: Ctrl, // left control
- 0x3C: Shift, // right shift
- 0x3D: Alt, // right alt
- 0x3E: Ctrl, // right control
-
- // the following is not in Events.h for some reason
- // thanks to Nicole and jedivulcan from irc.badnik.net
- 0x36: Super, // right command
-}
-
-func fromKeycode(keycode uintptr) (ke KeyEvent, ok bool) {
- if key, ok := keycodeKeys[keycode]; ok {
- ke.Key = key
- return ke, true
- }
- if extkey, ok := keycodeExtKeys[keycode]; ok {
- ke.ExtKey = extkey
- return ke, true
- }
- return ke, false
-}
diff --git a/redo/events_notdarwin.go b/redo/events_notdarwin.go
deleted file mode 100644
index 352151a..0000000
--- a/redo/events_notdarwin.go
+++ /dev/null
@@ -1,152 +0,0 @@
-// +build !darwin
-// Mac OS X uses its own set of position-independent key codes
-
-// 29 march 2014
-
-package ui
-
-import (
- "image"
-)
-
-/*
-Windows and GTK+ have a limit of 2 and 3 clicks, respectively, natively supported. Fortunately, we can simulate the double/triple-click behavior to build higher-order clicks. We can use the same algorithm Windows uses on both:
- http://blogs.msdn.com/b/oldnewthing/archive/2004/10/18/243925.aspx
-For GTK+, we pull the double-click time and double-click distance, which work the same as the equivalents on Windows (so the distance is in all directions), from the GtkSettings system.
-
-On GTK+ this will also allow us to discard the GDK_BUTTON_2PRESS and GDK_BUTTON_3PRESS events, so the button press stream will be just like on other platforms.
-
-Thanks to mclasen, garnacho_, halfline, and tristan in irc.gimp.net/#gtk+.
-*/
-
-// the zero value is a reset clickCounter ready for use
-// it doesn't matter that all the non-count fields are zero: the first click will fail the curButton test straightaway, so it'll return 1 and set the rest of the structure accordingly
-type clickCounter struct {
- curButton uint
- rect image.Rectangle
- prevTime uintptr
- count uint
-}
-
-// x, y, xdist, ydist, and c.rect must have the same units
-// so must time, maxTime, and c.prevTime
-func (c *clickCounter) click(button uint, x int, y int, time uintptr, maxTime uintptr, xdist int, ydist int) uint {
- if button != c.curButton { // different button; start over
- c.count = 0
- }
- if !image.Pt(x, y).In(c.rect) { // not in the allowed region for a double-click; don't count
- c.count = 0
- }
- if (time - c.prevTime) > maxTime { // too slow; don't count
- // note the above expression; time > (c.prevTime + maxTime) can overflow!
- c.count = 0
- }
- c.count++ // if either of the above ifs happened, this will make the click count 1; otherwise it will make the click count 2, 3, 4, 5, ...
-
- // now we need to update the internal structures for the next test
- c.curButton = button
- c.prevTime = time
- c.rect = image.Rect(x-xdist, y-ydist,
- x+xdist, y+ydist)
-
- return c.count
-}
-
-// call this when losing focus, etc.
-func (c *clickCounter) reset() {
- c.count = 0
-}
-
-/*
-For position independence across international keyboard layouts, typewriter keys are read using scancodes (which are always set 1).
-Windows provides the scancodes directly in the LPARAM.
-GTK+ provides the scancodes directly from the underlying window system via GdkEventKey.hardware_keycode.
-On X11, this is scancode + 8 (because X11 keyboard codes have a range of [8,255]).
-Wayland is guaranteed to give the same result (thanks ebassi in irc.gimp.net/#gtk+).
-On Linux, where evdev is used instead of polling scancodes directly from the keyboard, evdev's typewriter section key code constants are the same as scancodes anyway, so the rules above apply.
-Typewriter section scancodes are the same across international keyboards with some exceptions that have been accounted for (see KeyEvent's documentation); see http://www.quadibloc.com/comp/scan.htm for details.
-Non-typewriter keys can be handled safely using constants provided by the respective backend API.
-
-Because GTK+ keysyms may or may not obey Num Lock, we also handle the 0-9 and . keys on the numeric keypad with scancodes (they match too).
-*/
-
-// use uintptr to be safe; the size of the scancode/hardware key code field on each platform is different
-var scancodeKeys = map[uintptr]byte{
- 0x02: '1',
- 0x03: '2',
- 0x04: '3',
- 0x05: '4',
- 0x06: '5',
- 0x07: '6',
- 0x08: '7',
- 0x09: '8',
- 0x0A: '9',
- 0x0B: '0',
- 0x0C: '-',
- 0x0D: '=',
- 0x0E: '\b',
- 0x0F: '\t',
- 0x10: 'q',
- 0x11: 'w',
- 0x12: 'e',
- 0x13: 'r',
- 0x14: 't',
- 0x15: 'y',
- 0x16: 'u',
- 0x17: 'i',
- 0x18: 'o',
- 0x19: 'p',
- 0x1A: '[',
- 0x1B: ']',
- 0x1C: '\n',
- 0x1E: 'a',
- 0x1F: 's',
- 0x20: 'd',
- 0x21: 'f',
- 0x22: 'g',
- 0x23: 'h',
- 0x24: 'j',
- 0x25: 'k',
- 0x26: 'l',
- 0x27: ';',
- 0x28: '\'',
- 0x29: '`',
- 0x2B: '\\',
- 0x2C: 'z',
- 0x2D: 'x',
- 0x2E: 'c',
- 0x2F: 'v',
- 0x30: 'b',
- 0x31: 'n',
- 0x32: 'm',
- 0x33: ',',
- 0x34: '.',
- 0x35: '/',
- 0x39: ' ',
-}
-
-var scancodeExtKeys = map[uintptr]ExtKey{
- 0x47: N7,
- 0x48: N8,
- 0x49: N9,
- 0x4B: N4,
- 0x4C: N5,
- 0x4D: N6,
- 0x4F: N1,
- 0x50: N2,
- 0x51: N3,
- 0x52: N0,
- 0x53: NDot,
-}
-
-func fromScancode(scancode uintptr) (ke KeyEvent, ok bool) {
- if key, ok := scancodeKeys[scancode]; ok {
- ke.Key = key
- return ke, true
- }
- if extkey, ok := scancodeExtKeys[scancode]; ok {
- ke.ExtKey = extkey
- return ke, true
- }
- return ke, false
-}
diff --git a/redo/future b/redo/future
deleted file mode 100644
index fd40ac3..0000000
--- a/redo/future
+++ /dev/null
@@ -1,97 +0,0 @@
-Group
- Mac OS X: NSBox
- container_darwin.m: figure out if our setFrameSize: thing applies to resizing the groupbox as well
-
-Control
- Enable()
- Disable()
-
-Table
- refresh only selected rows of view to avoid flicker (especially on Windows)
- add functions for header manipulation
-
-Tab
- // [TODO if each tab of your Tab is going to have the same content Controls, then use LikeTab instead, to conserve resources]
- Delete()
- // Delete removes the given tab.
- // It panics if index is out of range.
- // After Delete(), the effect of accessing the Control of the deleted tab or any of its children is undefned. [TODO reword?]
- investigate close buttons (especially for LikeTab)
- LikeArea is probably going to have to be a custom control
-
-Area
- keyboard scrolling
- OpenTextAreaAt() to allow editing of text blocks from within Areas (only after I add TextArea; it will use TextAreas themselves, rather than providing its own)
- OpenTextFieldAt(): more platform-specific finished editing options; escape key for cancelling too?
- bounds checking in Select()
-
-Tree
- Mac OS X: make sure newScrollView() has the correct parameters for Table and Tree (and that Area has the appropriate ones from both)
-
-TextArea
- Mac OS X: be sure to call disableAutocorrect()
-
-Mac OS X
- label alignment
- // in the other case, the most correct thing would be for Label to be aligned to the alignment rect, but I can't get this working, and it looks fine as it is anyway
- other controls
- same rules? checkboxes seem damning...
- ok in general
- spacing applies to alignment rects
- will conflict with Stack/Grid precalculation
- unless we resize the control and move it around to suit
- Tabs seem to have differnt margin rules
- need to check padding rules within Tabs
- text alignment (think labels and checkboxes) may be a perpetual problem though
- activateIgnoringOtherApps: and command line programs: evaluate just how much it will matter
- http://stackoverflow.com/a/25318870/3408572
- use the undocumented _CFRunLoopSetCurrent() API to drop the stupid "must run on the man thread" restriction
-
-TextField
- figure out numerics because you CAN paste into numeric boxes on Windows and GTK+ has no built-in number validator as far as I know
- will likely just use Invalid()
-
-Stack, Grid
- method calls should trigger re-layout of windows
-default buttons
- figure out how they interact with Areas (especially on GTK+, where GtkEntry somehow has special handling for this)
-
-in general
- new moving stack and future moving heap make package ui a pain in general
- issue 8310: watch for changes
-
-dialog boxes
- find out if Stop has an effect before a dialog box function returns
- our solution for common dialogs is rather heavyweight and doesn't work for user-created dialogs
- foreign events are a problem
-
-so I don't forget, some TODOs:
-windows
- - Area isn't transparent
- - hard: has to be excluded from scrolling
- - tab order is backwards
- - extra space on first column of all Tables on real Windows
- - fine-tune Table checkbox behavior (especially with regards to selection)
- - open dialog, resize small window, hscroll size area, double click file -> stack points in no man's land (yay attached threads?)
- - uitask pointer bug again?
- - tabbing on an empty group infinite loops (same bug as with tabs)
- - groupbox line behind groupbox text
- - scrolling edit controls in Areas back into view don't cause redraw
- - need to figure out the WM_MOUSELEAVE tango (see mergeback/table_mouseleave_windows.c)
- - tell wine that WM_CTLCOLOR*** doesn't get sent early ?????
-gtk+
- - Area: figure out how Enter is processed in Entry
- https://git.gnome.org/browse/gtk+/tree/gtk/gtkwindow.c#n1229
- - Table: figure out how to allow empty selection by clicking in an empty area
- - After applying the AreaHandler.Key() change, -small crashes in 3.10/distribution but not 3.14/jhbuild
- - will need to install 14.04 somewhere for this
-mac os x
- - http://stackoverflow.com/questions/25558728/how-can-i-be-notified-when-a-control-becomes-key-i-want-t-o-have-my-custom-warn/25562783?noredirect=1#comment39949908_25562783
-gtk+, windows
- - Area: keyboard scrolling
-gtk+, mac os x
- - figure out how dialogs and Areas work together
- - once that is done, document the behavior of Areas
-all
- - make spaced settable somehow
- - rename Selected to Selection?
diff --git a/redo/grid.go b/redo/grid.go
deleted file mode 100644
index 6a91318..0000000
--- a/redo/grid.go
+++ /dev/null
@@ -1,234 +0,0 @@
-// 25 february 2014
-
-package ui
-
-import (
- "fmt"
-)
-
-// A Grid arranges Controls in a two-dimensional grid.
-// The height of each row and the width of each column is the maximum preferred height and width (respectively) of all the controls in that row or column (respectively).
-// Controls are aligned to the top left corner of each cell.
-// All Controls in a Grid maintain their preferred sizes by default; if a Control is marked as being "filling", it will be sized to fill its cell.
-// Even if a Control is marked as filling, its preferred size is used to calculate cell sizes.
-// One Control can be marked as "stretchy": when the Window containing the Grid 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 Grid 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 Grid interface {
- Control
-
- // SetFilling marks the given Control of the Grid as filling its cell instead of staying at its preferred size.
- // It panics if the given coordinate is invalid.
- SetFilling(row int, column int)
-
- // SetStretchy marks the given Control of the Grid as stretchy.
- // Stretchy implies filling.
- // Only one control can be stretchy per Grid; calling SetStretchy multiple times merely changes which control is stretchy (preserving the previous filling value).
- // It panics if the given coordinate is invalid.
- SetStretchy(row int, column int)
-}
-
-type grid struct {
- controls [][]Control
- filling [][]bool
- stretchyrow, stretchycol int
- stretchyfill bool
- widths, heights [][]int // caches to avoid reallocating each time
- rowheights, colwidths []int
-}
-
-// NewGrid creates a new Grid with the given Controls.
-// NewGrid needs to know the number of Controls in a row (alternatively, the number of columns); it will determine the number in a column from the number of Controls given.
-// NewGrid panics if not given a full grid of Controls.
-// Example:
-// grid := NewGrid(3,
-// control00, control01, control02,
-// control10, control11, control12,
-// control20, control21, control22)
-func NewGrid(nPerRow int, controls ...Control) Grid {
- if len(controls)%nPerRow != 0 {
- panic(fmt.Errorf("incomplete grid given to NewGrid() (not enough controls to evenly divide %d controls into rows of %d controls each)", len(controls), nPerRow))
- }
- nRows := len(controls) / nPerRow
- cc := make([][]Control, nRows)
- cf := make([][]bool, nRows)
- cw := make([][]int, nRows)
- ch := make([][]int, nRows)
- i := 0
- for row := 0; row < nRows; row++ {
- cc[row] = make([]Control, nPerRow)
- cf[row] = make([]bool, nPerRow)
- cw[row] = make([]int, nPerRow)
- ch[row] = make([]int, nPerRow)
- for x := 0; x < nPerRow; x++ {
- cc[row][x] = controls[i]
- if l, ok := controls[i].(Label); ok && !l.isStandalone() {
- cf[row][x] = true
- }
- i++
- }
- }
- return &grid{
- controls: cc,
- filling: cf,
- stretchyrow: -1,
- stretchycol: -1,
- widths: cw,
- heights: ch,
- rowheights: make([]int, nRows),
- colwidths: make([]int, nPerRow),
- }
-}
-
-func (g *grid) SetFilling(row int, column int) {
- if row < 0 || column < 0 || row > len(g.filling) || column > len(g.filling[row]) {
- panic(fmt.Errorf("coordinate (%d,%d) out of range passed to Grid.SetFilling()", row, column))
- }
- g.filling[row][column] = true
-}
-
-func (g *grid) SetStretchy(row int, column int) {
- if row < 0 || column < 0 || row > len(g.filling) || column > len(g.filling[row]) {
- panic(fmt.Errorf("coordinate (%d,%d) out of range passed to Grid.SetStretchy()", row, column))
- }
- if g.stretchyrow != -1 || g.stretchycol != -1 {
- g.filling[g.stretchyrow][g.stretchycol] = g.stretchyfill
- }
- g.stretchyrow = row
- g.stretchycol = column
- g.stretchyfill = g.filling[g.stretchyrow][g.stretchycol] // save previous value in case it changes later
- g.filling[g.stretchyrow][g.stretchycol] = true
-}
-
-func (g *grid) setParent(parent *controlParent) {
- for _, col := range g.controls {
- for _, c := range col {
- c.setParent(parent)
- }
- }
-}
-
-func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) {
- max := func(a int, b int) int {
- if a > b {
- return a
- }
- return b
- }
-
- var current *allocation // for neighboring
-
- if len(g.controls) == 0 {
- return nil
- }
- // 0) inset the available rect by the needed padding
- width -= (len(g.colwidths) - 1) * d.xpadding
- height -= (len(g.rowheights) - 1) * d.ypadding
- // 1) clear data structures
- for i := range g.rowheights {
- g.rowheights[i] = 0
- }
- for i := range g.colwidths {
- g.colwidths[i] = 0
- }
- // 2) get preferred sizes; compute row/column sizes
- for row, xcol := range g.controls {
- for col, c := range xcol {
- w, h := c.preferredSize(d)
- g.widths[row][col] = w
- g.heights[row][col] = h
- g.rowheights[row] = max(g.rowheights[row], h)
- g.colwidths[col] = max(g.colwidths[col], w)
- }
- }
- // 3) handle the stretchy control
- if g.stretchyrow != -1 && g.stretchycol != -1 {
- for i, w := range g.colwidths {
- if i != g.stretchycol {
- width -= w
- }
- }
- for i, h := range g.rowheights {
- if i != g.stretchyrow {
- height -= h
- }
- }
- g.colwidths[g.stretchycol] = width
- g.rowheights[g.stretchyrow] = height
- }
- // 4) draw
- startx := x
- for row, xcol := range g.controls {
- current = nil // reset on new columns
- for col, c := range xcol {
- w := g.widths[row][col]
- h := g.heights[row][col]
- if g.filling[row][col] {
- w = g.colwidths[col]
- h = g.rowheights[row]
- }
- as := c.allocate(x, y, w, h, d)
- if current != nil { // connect first left to first right
- current.neighbor = c
- }
- if len(as) != 0 {
- current = as[0] // next left is first subwidget
- } else {
- current = nil // spaces don't have allocation data
- }
- allocations = append(allocations, as...)
- x += g.colwidths[col] + d.xpadding
- }
- x = startx
- y += g.rowheights[row] + d.ypadding
- }
- return
-}
-
-// filling and stretchy are ignored for preferred size calculation
-func (g *grid) preferredSize(d *sizing) (width int, height int) {
- max := func(a int, b int) int {
- if a > b {
- return a
- }
- return b
- }
-
- width -= (len(g.colwidths) - 1) * d.xpadding
- height -= (len(g.rowheights) - 1) * d.ypadding
- // 1) clear data structures
- for i := range g.rowheights {
- g.rowheights[i] = 0
- }
- for i := range g.colwidths {
- g.colwidths[i] = 0
- }
- // 2) get preferred sizes; compute row/column sizes
- for row, xcol := range g.controls {
- for col, c := range xcol {
- w, h := c.preferredSize(d)
- g.widths[row][col] = w
- g.heights[row][col] = h
- g.rowheights[row] = max(g.rowheights[row], h)
- g.colwidths[col] = max(g.colwidths[col], w)
- }
- }
- // 3) now compute
- for _, w := range g.colwidths {
- width += w
- }
- for _, h := range g.rowheights {
- height += h
- }
- return width, height
-}
-
-func (g *grid) commitResize(c *allocation, d *sizing) {
- // this is to satisfy Control; nothing to do here
-}
-
-func (g *grid) getAuxResizeInfo(d *sizing) {
- // this is to satisfy Control; nothing to do here
-}
diff --git a/redo/group_darwin.go b/redo/group_darwin.go
deleted file mode 100644
index 788ba83..0000000
--- a/redo/group_darwin.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// 16 august 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type group struct {
- _id C.id
-
- *container
-}
-
-func newGroup(text string, control Control) Group {
- g := new(group)
- g.container = newContainer(control)
- g._id = C.newGroup(g.container.id)
- g.SetText(text)
- return g
-}
-
-func (g *group) Text() string {
- return C.GoString(C.groupText(g._id))
-}
-
-func (g *group) SetText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.groupSetText(g._id, ctext)
-}
-
-func (g *group) id() C.id {
- return g._id
-}
-
-func (g *group) setParent(p *controlParent) {
- basesetParent(g, p)
-}
-
-func (g *group) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(g, x, y, width, height, d)
-}
-
-func (g *group) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(g, d)
-}
-
-func (g *group) commitResize(a *allocation, d *sizing) {
- basecommitResize(g, a, d)
-}
-
-func (g *group) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(g, d)
-}
diff --git a/redo/group_unix.go b/redo/group_unix.go
deleted file mode 100644
index ceaa59c..0000000
--- a/redo/group_unix.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// +build !windows,!darwin
-
-// 15 august 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-import "C"
-
-type group struct {
- _widget *C.GtkWidget
- gcontainer *C.GtkContainer
- frame *C.GtkFrame
-
- *container
-}
-
-func newGroup(text string, control Control) Group {
- ctext := togstr(text)
- 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)),
- }
-
- // with GTK+, groupboxes by default have frames and slightly x-offset regular text
- // they should have no frame and fully left-justified, bold text
- var yalign C.gfloat
-
- // preserve default y-alignment
- C.gtk_frame_get_label_align(g.frame, nil, &yalign)
- C.gtk_frame_set_label_align(g.frame, 0, yalign)
- C.gtk_frame_set_shadow_type(g.frame, C.GTK_SHADOW_NONE)
- label := (*C.GtkLabel)(unsafe.Pointer(C.gtk_frame_get_label_widget(g.frame)))
- // this is the boldness level used by GtkPrintUnixDialog
- // (it technically uses "bold" but see pango's pango-enum-types.c for the name conversion; GType is weird)
- bold := C.pango_attr_weight_new(C.PANGO_WEIGHT_BOLD)
- 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+
-
- g.container = newContainer(control)
- g.container.setParent(&controlParent{g.gcontainer})
-
- return g
-}
-
-func (g *group) Text() string {
- return fromgstr(C.gtk_frame_get_label(g.frame))
-}
-
-func (g *group) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_frame_set_label(g.frame, ctext)
-}
-
-func (g *group) widget() *C.GtkWidget {
- return g._widget
-}
-
-func (g *group) setParent(p *controlParent) {
- basesetParent(g, p)
-}
-
-func (g *group) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(g, x, y, width, height, d)
-}
-
-func (g *group) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(g, d)
-}
-
-func (g *group) commitResize(a *allocation, d *sizing) {
- basecommitResize(g, a, d)
-}
-
-func (g *group) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(g, d)
-}
diff --git a/redo/group_windows.go b/redo/group_windows.go
deleted file mode 100644
index fda95e3..0000000
--- a/redo/group_windows.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// 15 august 2014
-
-package ui
-
-// #include "winapi_windows.h"
-import "C"
-
-type group struct {
- _hwnd C.HWND
- _textlen C.LONG
-
- *container
-}
-
-func newGroup(text string, control Control) Group {
- hwnd := C.newControl(buttonclass,
- C.BS_GROUPBOX,
- C.WS_EX_CONTROLPARENT)
- g := &group{
- _hwnd: hwnd,
- container: newContainer(control),
- }
- g.SetText(text)
- C.controlSetControlFont(g._hwnd)
- g.container.setParent(g._hwnd)
- g.container.isGroup = true
- return g
-}
-
-func (g *group) Text() string {
- return baseText(g)
-}
-
-func (g *group) SetText(text string) {
- baseSetText(g, text)
-}
-
-func (g *group) hwnd() C.HWND {
- return g._hwnd
-}
-
-func (g *group) textlen() C.LONG {
- return g._textlen
-}
-
-func (g *group) settextlen(len C.LONG) {
- g._textlen = len
-}
-
-func (g *group) setParent(p *controlParent) {
- basesetParent(g, p)
-}
-
-func (g *group) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(g, x, y, width, height, d)
-}
-
-func (g *group) preferredSize(d *sizing) (width, height int) {
- width, height = g.child.preferredSize(d)
- 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
- return width, height + fromdlgunitsY(groupYMarginTop, d) + fromdlgunitsY(groupYMarginBottom, d)
-}
-
-func (g *group) commitResize(c *allocation, d *sizing) {
- var r C.RECT
-
- // pretend that the client area of the group box only includes the actual empty space
- // container will handle the necessary adjustments properly
- r.left = 0
- r.top = 0
- r.right = C.LONG(c.width)
- r.bottom = C.LONG(c.height)
- g.container.move(&r)
- basecommitResize(g, c, d)
-}
-
-func (g *group) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(g, d)
-}
diff --git a/redo/gtk_unix.h b/redo/gtk_unix.h
deleted file mode 100644
index 98b9637..0000000
--- a/redo/gtk_unix.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// 16 march 2014
-
-#ifndef __GO_UI_GTK_UNIX_H__
-#define __GO_UI_GTK_UNIX_H__
-
-/*
-MIN_REQUIRED signals that programs are expected to run on at least GLib 2.32/GTK+ 3.4 and thus deprectation warnings for newer versions (such as gtk_scrolled_window_add_with_viewport() being deprecated in GTK+ 3.8) should be suppressed.
-MAX_ALLOWED signals that programs will not use features introduced in newer versions of GLib/GTK+ and that the compiler should warn us if we slip.
-Thanks to desrt in irc.gimp.net/#gtk+
-*/
-
-// GLib/GObject
-#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_32
-#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_32
-
-// GDK/GTK+
-#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_4
-#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_4
-
-// cairo has no such macros (thanks Company in irc.gimp.net/#gtk+)
-
-#include <stdlib.h>
-#include <gtk/gtk.h>
-
-// table_unix.c
-extern void tableAppendColumn(GtkTreeView *, gint, gchar *, GtkCellRenderer *, gchar *);
-typedef struct goTableModel goTableModel;
-typedef struct goTableModelClass goTableModelClass;
-struct goTableModel {
- GObject parent_instance;
- void *gotable;
-};
-struct goTableModelClass {
- GObjectClass parent_class;
-};
-extern goTableModel *newTableModel(void *);
-extern void tableUpdate(goTableModel *, gint, gint);
-
-// container_unix.c
-extern GtkWidget *newContainer(void *);
-
-#endif
diff --git a/redo/imagelist.go b/redo/imagelist.go
deleted file mode 100644
index 6b34b28..0000000
--- a/redo/imagelist.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// 16 august 2014
-
-package ui
-
-import (
- "image"
-)
-
-// ImageList is a list of images that can be used in the rows of a Table or Tree.
-// ImageList maintains a copy of each image added.
-// Images in an ImageList will be automatically scaled to the needed size.
-type ImageList interface {
- // Append inserts an image into the ImageList.
- Append(i *image.RGBA)
-
- // Len returns the number of images in the ImageList.
- Len() ImageIndex
-
- imageListApply
-}
-
-// NewImageList creates a new ImageList.
-// The ImageList is initially empty.
-func NewImageList() ImageList {
- return newImageList()
-}
-
-// ImageIndex is a special type used to denote an entry in a Table or Tree's ImageList.
-type ImageIndex int
diff --git a/redo/imagelist_darwin.go b/redo/imagelist_darwin.go
deleted file mode 100644
index 53fafa5..0000000
--- a/redo/imagelist_darwin.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// 16 august 2014
-
-package ui
-
-import (
- "image"
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type imagelist struct {
- list []C.id
-}
-
-func newImageList() ImageList {
- return new(imagelist)
-}
-
-func (i *imagelist) Append(img *image.RGBA) {
- id := C.toImageListImage(
- unsafe.Pointer(pixelData(img)), C.intptr_t(img.Rect.Dx()), C.intptr_t(img.Rect.Dy()), C.intptr_t(img.Stride))
- i.list = append(i.list, id)
-}
-
-func (i *imagelist) Len() ImageIndex {
- return ImageIndex(len(i.list))
-}
-
-type imageListApply interface {
- apply(*[]C.id)
-}
-
-func (i *imagelist) apply(out *[]C.id) {
- *out = make([]C.id, len(i.list))
- copy(*out, i.list)
-}
diff --git a/redo/imagelist_darwin.m b/redo/imagelist_darwin.m
deleted file mode 100644
index 7433b12..0000000
--- a/redo/imagelist_darwin.m
+++ /dev/null
@@ -1,30 +0,0 @@
-// 16 august 2014
-
-#import "objc_darwin.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSInteger(x) ((NSInteger) (x))
-
-id toImageListImage(void *pixels, intptr_t width, intptr_t height, intptr_t stride)
-{
- NSBitmapImageRep *bitmap;
- NSImage *image;
-
- // we can't just hand it pixels; we need to make a copy
- bitmap = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:NULL
- pixelsWide:toNSInteger(width)
- pixelsHigh:toNSInteger(height)
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bitmapFormat:0
- bytesPerRow:toNSInteger(stride)
- bitsPerPixel:32];
- memcpy((void *) [bitmap bitmapData], pixels, [bitmap bytesPerPlane]);
- image = [[NSImage alloc] initWithSize:NSMakeSize((CGFloat) width, (CGFloat) height)];
- [image addRepresentation:bitmap];
- return (id) image;
-}
diff --git a/redo/imagelist_unix.go b/redo/imagelist_unix.go
deleted file mode 100644
index 246f281..0000000
--- a/redo/imagelist_unix.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// +build !windows,!darwin
-
-// 16 august 2014
-
-package ui
-
-import (
- "fmt"
- "unsafe"
- "image"
-)
-
-// #include "gtk_unix.h"
-import "C"
-
-type imagelist struct {
- list []*C.GdkPixbuf
-}
-
-func newImageList() ImageList {
- return new(imagelist)
-}
-
-// this is what GtkFileChooserWidget uses
-// technically it uses max(width from that, height from that) if the call below fails and 16x16 otherwise, but we won't worry about that here (yet?)
-const scaleTo = C.GTK_ICON_SIZE_MENU
-
-func (i *imagelist) Append(img *image.RGBA) {
- var width, height C.gint
-
- surface := C.cairo_image_surface_create(C.CAIRO_FORMAT_ARGB32,
- C.int(img.Rect.Dx()),
- C.int(img.Rect.Dy()))
- if status := C.cairo_surface_status(surface); status != C.CAIRO_STATUS_SUCCESS {
- panic(fmt.Errorf("cairo_create_image_surface() failed in ImageList.Append(): %s\n",
- C.GoString(C.cairo_status_to_string(status))))
- }
- 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
- 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 {
- panic(fmt.Errorf("gdk_pixbuf_get_from_surface() failed in ImageList.Append() (no reason available)"))
- }
-
- if C.gtk_icon_size_lookup(scaleTo, &width, &height) == C.FALSE {
- panic(fmt.Errorf("gtk_icon_size_lookup() failed in ImageList.Append() (no reason available)"))
- }
- if int(width) == img.Rect.Dx() && int(height) == img.Rect.Dy() {
- // just add the base pixbuf; we're good
- i.list = append(i.list, basepixbuf)
- C.cairo_surface_destroy(surface)
- return
- }
- // else scale
- pixbuf := C.gdk_pixbuf_scale_simple(basepixbuf, C.int(width), C.int(height), C.GDK_INTERP_NEAREST)
- if pixbuf == nil {
- panic(fmt.Errorf("gdk_pixbuf_scale_simple() failed in ImageList.Append() (no reason available)"))
- }
-
- i.list = append(i.list, pixbuf)
- C.gdk_pixbuf_unref(basepixbuf)
- C.cairo_surface_destroy(surface)
-}
-
-func (i *imagelist) Len() ImageIndex {
- return ImageIndex(len(i.list))
-}
-
-type imageListApply interface {
- apply(*[]*C.GdkPixbuf)
-}
-
-func (i *imagelist) apply(out *[]*C.GdkPixbuf) {
- *out = make([]*C.GdkPixbuf, len(i.list))
- copy(*out, i.list)
-}
diff --git a/redo/imagelist_windows.c b/redo/imagelist_windows.c
deleted file mode 100644
index 14d33a9..0000000
--- a/redo/imagelist_windows.c
+++ /dev/null
@@ -1,268 +0,0 @@
-// 16 august 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-// TODO top left pixel of checkbox state 0 not drawn?
-
-HBITMAP unscaledBitmap(void *i, intptr_t dx, intptr_t dy)
-{
- BITMAPINFO bi;
- VOID *ppvBits;
- HBITMAP bitmap;
-
- ZeroMemory(&bi, sizeof (BITMAPINFO));
- bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
- bi.bmiHeader.biWidth = (LONG) dx;
- bi.bmiHeader.biHeight = -((LONG) dy); // negative height to force top-down drawing;
- bi.bmiHeader.biPlanes = 1;
- bi.bmiHeader.biBitCount = 32;
- bi.bmiHeader.biCompression = BI_RGB;
- bi.bmiHeader.biSizeImage = (DWORD) (dx * dy * 4);
- bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0);
- if (bitmap == NULL)
- xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError());
- // image lists use non-premultiplied RGBA - see http://stackoverflow.com/a/25578789/3408572
- // the TRUE here does the conversion
- dotoARGB(i, (void *) ppvBits, TRUE);
- return bitmap;
-}
-
-HIMAGELIST newImageList(int width, int height)
-{
- HIMAGELIST il;
-
- // this handles alpha properly; see https://web.archive.org/web/20100512144953/http://msdn.microsoft.com/en-us/library/ms997646.aspx#xptheming_topic13 and http://stackoverflow.com/a/2640897/3408572
- il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable
- if (il == NULL)
- xpanic("error creating image list", GetLastError());
- return il;
-}
-
-void addImage(HIMAGELIST il, HWND hwnd, HBITMAP bitmap, int origwid, int oright, int width, int height)
-{
- BOOL wasScaled = FALSE;
- HDC winDC, scaledDC, origDC;
- HBITMAP scaled;
- HBITMAP prevscaled, prevorig;
-
- // first we need to scale the bitmap
- if (origwid == width && oright == height) {
- scaled = bitmap;
- goto noscale;
- }
- wasScaled = TRUE;
- winDC = GetDC(hwnd);
- if (winDC == NULL)
- xpanic("error getting DC for window", GetLastError());
- origDC = CreateCompatibleDC(winDC);
- if (origDC == NULL)
- xpanic("error getting DC for original ImageList bitmap", GetLastError());
- prevorig = SelectObject(origDC, bitmap);
- if (prevorig == NULL)
- xpanic("error selecting original ImageList bitmap into DC", GetLastError());
- scaledDC = CreateCompatibleDC(origDC);
- if (scaledDC == NULL)
- xpanic("error getting DC for scaled ImageList bitmap", GetLastError());
- scaled = CreateCompatibleBitmap(origDC, width, height);
- if (scaled == NULL)
- xpanic("error creating scaled ImageList bitmap", GetLastError());
- prevscaled = SelectObject(scaledDC, scaled);
- if (prevscaled == NULL)
- xpanic("error selecting scaled ImageList bitmap into DC", GetLastError());
- if (SetStretchBltMode(scaledDC, COLORONCOLOR) == 0)
- xpanic("error setting scaling mode", GetLastError());
- if (StretchBlt(scaledDC, 0, 0, width, height,
- origDC, 0, 0, origwid, oright,
- SRCCOPY) == 0)
- xpanic("error scaling ImageList bitmap down", GetLastError());
- if (SelectObject(origDC, prevorig) != bitmap)
- xpanic("error selecting previous bitmap into original image's DC", GetLastError());
- if (DeleteDC(origDC) == 0)
- xpanic("error deleting original image's DC", GetLastError());
- if (SelectObject(scaledDC, prevscaled) != scaled)
- xpanic("error selecting previous bitmap into scaled image's DC", GetLastError());
- if (DeleteDC(scaledDC) == 0)
- xpanic("error deleting scaled image's DC", GetLastError());
- if (ReleaseDC(hwnd, winDC) == 0)
- xpanic("error deleting window DC", GetLastError());
-
-noscale:
- if ((*fv_ImageList_Add)(il, scaled, NULL) == -1)
- xpanic("error adding ImageList image to image list", GetLastError());
- if (wasScaled) // clean up
- if (DeleteObject(scaled) == 0)
- xpanic("error deleting scaled bitmap", GetLastError());
-}
-
-void applyImageList(HWND hwnd, UINT uMsg, WPARAM wParam, HIMAGELIST il, HIMAGELIST old)
-{
- if (SendMessageW(hwnd, uMsg, wParam, (LPARAM) il) != (LRESULT) old)
- xpanic("error setting image list", GetLastError());
- if (old != NULL && (*fv_ImageList_Destroy)(old) == 0)
- xpanic("error freeing old checkbox image list", GetLastError());
-
-}
-
-static UINT dfcState(int cbstate)
-{
- UINT ret;
-
- ret = DFCS_BUTTONCHECK;
- if ((cbstate & checkboxStateChecked) != 0)
- ret |= DFCS_CHECKED;
- if ((cbstate & checkboxStateHot) != 0)
- ret |= DFCS_HOT;
- if ((cbstate & checkboxStatePushed) != 0)
- ret |= DFCS_PUSHED;
- return ret;
-}
-
-static void dfcImage(HDC dc, RECT *r, int cbState, HTHEME theme)
-{
- if (DrawFrameControl(dc, r, DFC_BUTTON, dfcState(cbState)) == 0)
- xpanic("error drawing checkbox image", GetLastError());
-}
-
-static void dfcSize(HDC dc, int *width, int *height, HTHEME theme)
-{
- // there's no real metric around
- // let's use SM_CX/YSMICON and hope for the best
- *width = GetSystemMetrics(SM_CXSMICON);
- *height = GetSystemMetrics(SM_CYSMICON);
-}
-
-static int themestates[checkboxnStates] = {
- CBS_UNCHECKEDNORMAL, // 0
- CBS_CHECKEDNORMAL, // checked
- CBS_UNCHECKEDHOT, // hot
- CBS_CHECKEDHOT, // checked | hot
- CBS_UNCHECKEDPRESSED, // pushed
- CBS_CHECKEDPRESSED, // checked | pushed
- CBS_UNCHECKEDPRESSED, // hot | pushed
- CBS_CHECKEDPRESSED, // checked | hot | pushed
-};
-
-static SIZE getStateSize(HDC dc, int cbState, HTHEME theme)
-{
- SIZE s;
- HRESULT res;
-
- res = GetThemePartSize(theme, dc, BP_CHECKBOX, themestates[cbState], NULL, TS_DRAW, &s);
- if (res != S_OK)
- xpanichresult("error getting theme part size", res);
- return s;
-}
-
-static void themeImage(HDC dc, RECT *r, int cbState, HTHEME theme)
-{
- HRESULT res;
-
- res = DrawThemeBackground(theme, dc, BP_CHECKBOX, themestates[cbState], r, NULL);
- if (res != S_OK)
- xpanichresult("error drawing checkbox image", res);
-}
-
-static void themeSize(HDC dc, int *width, int *height, HTHEME theme)
-{
- SIZE size;
- int cbState;
-
- size = getStateSize(dc, 0, theme);
- for (cbState = 1; cbState < checkboxnStates; cbState++) {
- SIZE against;
-
- against = getStateSize(dc, cbState, theme);
- if (size.cx != against.cx || size.cy != against.cy)
- xpanic("size mismatch in checkbox states", GetLastError());
- }
- *width = (int) size.cx;
- *height = (int) size.cy;
-}
-
-static HBITMAP makeCheckboxImageListEntry(HDC dc, int width, int height, int cbState, void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme)
-{
- BITMAPINFO bi;
- VOID *ppvBits;
- HBITMAP bitmap;
- RECT r;
- HDC drawDC;
- HBITMAP prevbitmap;
-
- r.left = 0;
- r.top = 0;
- r.right = width;
- r.bottom = height;
- ZeroMemory(&bi, sizeof (BITMAPINFO));
- bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
- bi.bmiHeader.biWidth = (LONG) width;
- bi.bmiHeader.biHeight = -((LONG) height); // negative height to force top-down drawing;
- bi.bmiHeader.biPlanes = 1;
- bi.bmiHeader.biBitCount = 32;
- bi.bmiHeader.biCompression = BI_RGB;
- bi.bmiHeader.biSizeImage = (DWORD) (width * height * 4);
- bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0);
- if (bitmap == NULL)
- xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError());
-
- drawDC = CreateCompatibleDC(dc);
- if (drawDC == NULL)
- xpanic("error getting DC for checkbox image list bitmap", GetLastError());
- prevbitmap = SelectObject(drawDC, bitmap);
- if (prevbitmap == NULL)
- xpanic("error selecting checkbox image list bitmap into DC", GetLastError());
- (*drawfunc)(drawDC, &r, cbState, theme);
- if (SelectObject(drawDC, prevbitmap) != bitmap)
- xpanic("error selecting previous bitmap into checkbox image's DC", GetLastError());
- if (DeleteDC(drawDC) == 0)
- xpanic("error deleting checkbox image's DC", GetLastError());
-
- return bitmap;
-}
-
-static HIMAGELIST newCheckboxImageList(HWND hwnddc, void (*sizefunc)(HDC, int *, int *, HTHEME), void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme)
-{
- int width, height;
- int cbState;
- HDC dc;
- HIMAGELIST il;
-
- dc = GetDC(hwnddc);
- if (dc == NULL)
- xpanic("error getting DC for making the checkbox image list", GetLastError());
- (*sizefunc)(dc, &width, &height, theme);
- il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable
- if (il == NULL)
- xpanic("error creating checkbox image list", GetLastError());
- for (cbState = 0; cbState < checkboxnStates; cbState++) {
- HBITMAP bitmap;
-
- bitmap = makeCheckboxImageListEntry(dc, width, height, cbState, drawfunc, theme);
- if ((*fv_ImageList_Add)(il, bitmap, NULL) == -1)
- xpanic("error adding checkbox image to image list", GetLastError());
- if (DeleteObject(bitmap) == 0)
- xpanic("error deleting checkbox bitmap", GetLastError());
- }
- if (ReleaseDC(hwnddc, dc) == 0)
- xpanic("error deleting checkbox image list DC", GetLastError());
- return il;
-}
-
-HIMAGELIST makeCheckboxImageList(HWND hwnddc, HTHEME *theme)
-{
- if (*theme != NULL) {
- HRESULT res;
-
- res = CloseThemeData(*theme);
- if (res != S_OK)
- xpanichresult("error closing theme", res);
- *theme = NULL;
- }
- // ignore error; if it can't be done, we can fall back to DrawFrameControl()
- if (*theme == NULL) // try to open the theme
- *theme = OpenThemeData(hwnddc, L"button");
- if (*theme != NULL) // use the theme
- return newCheckboxImageList(hwnddc, themeSize, themeImage, *theme);
- // couldn't open; fall back
- return newCheckboxImageList(hwnddc, dfcSize, dfcImage, *theme);
-}
diff --git a/redo/imagelist_windows.go b/redo/imagelist_windows.go
deleted file mode 100644
index 7ab014b..0000000
--- a/redo/imagelist_windows.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// 16 august 2014
-
-package ui
-
-import (
- "image"
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type imagelist struct {
- list []C.HBITMAP
- width []int
- height []int
-}
-
-func newImageList() ImageList {
- return new(imagelist)
-}
-
-func (i *imagelist) Append(img *image.RGBA) {
- i.list = append(i.list, C.unscaledBitmap(unsafe.Pointer(img), C.intptr_t(img.Rect.Dx()), C.intptr_t(img.Rect.Dy())))
- i.width = append(i.width, img.Rect.Dx())
- i.height = append(i.height, img.Rect.Dy())
-}
-
-func (i *imagelist) Len() ImageIndex {
- return ImageIndex(len(i.list))
-}
-
-type imageListApply interface {
- apply(C.HWND, C.UINT)
-}
-
-func (i *imagelist) apply(hwnd C.HWND, uMsg C.UINT) {
- width := C.GetSystemMetrics(C.SM_CXSMICON)
- height := C.GetSystemMetrics(C.SM_CYSMICON)
- il := C.newImageList(width, height)
- for index := range i.list {
- C.addImage(il, hwnd, i.list[index], C.int(i.width[index]), C.int(i.height[index]), width, height)
- }
- C.SendMessageW(hwnd, uMsg, 0, C.LPARAM(uintptr(unsafe.Pointer(il))))
-}
diff --git a/redo/init_windows.c b/redo/init_windows.c
deleted file mode 100644
index 4b35fc3..0000000
--- a/redo/init_windows.c
+++ /dev/null
@@ -1,73 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-
-HINSTANCE hInstance;
-int nCmdShow;
-
-HICON hDefaultIcon;
-HCURSOR hArrowCursor;
-
-HFONT controlFont;
-HFONT titleFont;
-HFONT smallTitleFont;
-HFONT menubarFont;
-HFONT statusbarFont;
-
-HBRUSH hollowBrush;
-
-DWORD initWindows(char **errmsg)
-{
- STARTUPINFOW si;
- NONCLIENTMETRICSW ncm;
-
- // WinMain() parameters
- hInstance = GetModuleHandleW(NULL);
- if (hInstance == NULL) {
- *errmsg = "error getting hInstance";
- return GetLastError();
- }
- nCmdShow = SW_SHOWDEFAULT;
- GetStartupInfoW(&si);
- if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0)
- nCmdShow = si.wShowWindow;
-
- // icons and cursors
- hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION);
- if (hDefaultIcon == NULL) {
- *errmsg = "error loading default icon";
- return GetLastError();
- }
- hArrowCursor = LoadCursorW(NULL, IDC_ARROW);
- if (hArrowCursor == NULL) {
- *errmsg = "error loading arrow (default) cursor";
- return GetLastError();
- }
-
- // standard fonts
-#define GETFONT(l, f, n) l = CreateFontIndirectW(&ncm.f); \
- if (l == NULL) { \
- *errmsg = "error loading " n " font"; \
- return GetLastError(); \
- }
-
- ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW));
- ncm.cbSize = sizeof (NONCLIENTMETRICSW);
- if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) {
- *errmsg = "error getting non-client metrics parameters";
- return GetLastError();
- }
- GETFONT(controlFont, lfMessageFont, "control");
- GETFONT(titleFont, lfCaptionFont, "titlebar");
- GETFONT(smallTitleFont, lfSmCaptionFont, "small title bar");
- GETFONT(menubarFont, lfMenuFont, "menu bar");
- GETFONT(statusbarFont, lfStatusFont, "status bar");
-
- hollowBrush = GetStockObject(HOLLOW_BRUSH);
- if (hollowBrush == NULL) {
- *errmsg = "error getting hollow brush";
- return GetLastError();
- }
-
- return 0;
-}
diff --git a/redo/label_darwin.go b/redo/label_darwin.go
deleted file mode 100644
index 0508931..0000000
--- a/redo/label_darwin.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// 16 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type label struct {
- _id C.id
- standalone bool
-}
-
-func finishNewLabel(text string, standalone bool) *label {
- l := &label{
- _id: C.newLabel(),
- standalone: standalone,
- }
- l.SetText(text)
- return l
-}
-
-func newLabel(text string) Label {
- return finishNewLabel(text, false)
-}
-
-func newStandaloneLabel(text string) Label {
- return finishNewLabel(text, true)
-}
-
-func (l *label) Text() string {
- return C.GoString(C.textfieldText(l._id))
-}
-
-func (l *label) SetText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.textfieldSetText(l._id, ctext)
-}
-
-func (l *label) isStandalone() bool {
- return l.standalone
-}
-
-func (l *label) id() C.id {
- return l._id
-}
-
-func (l *label) setParent(p *controlParent) {
- basesetParent(l, p)
-}
-
-func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(l, x, y, width, height, d)
-}
-
-func (l *label) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(l, d)
-}
-
-func (l *label) commitResize(c *allocation, d *sizing) {
- if !l.standalone && c.neighbor != nil {
- c.neighbor.getAuxResizeInfo(d)
- if d.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline
- // in order for the baseline value to be correct, the label MUST BE AT THE HEIGHT THAT OS X WANTS IT TO BE!
- // otherwise, the baseline calculation will be relative to the bottom of the control, and everything will be wrong
- origsize := C.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),
- }
- ourAlign := C.alignmentInfo(l._id, newrect)
- // we need to find the exact Y positions of the baselines
- // fortunately, this is easy now that (x,y) is the bottom-left corner
- thisbasey := ourAlign.rect.y + ourAlign.baseline
- neighborbasey := d.neighborAlign.rect.y + d.neighborAlign.baseline
- // now the amount we have to move the label down by is easy to find
- yoff := neighborbasey - thisbasey
- // and we just add that
- c.y += int(yoff)
- }
- // in the other case, the most correct thing would be for Label to be aligned to the alignment rect, but I can't get this working, and it looks fine as it is anyway
- }
- basecommitResize(l, c, d)
-}
-
-func (l *label) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(l, d)
-}
diff --git a/redo/label_unix.go b/redo/label_unix.go
deleted file mode 100644
index 45a3dad..0000000
--- a/redo/label_unix.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern void buttonClicked(GtkButton *, gpointer);
-// extern void checkboxToggled(GtkToggleButton *, gpointer);
-import "C"
-
-type label struct {
- _widget *C.GtkWidget
- misc *C.GtkMisc
- label *C.GtkLabel
- standalone bool
-}
-
-func finishNewLabel(text string, standalone bool) *label {
- ctext := togstr(text)
- defer freegstr(ctext)
- widget := C.gtk_label_new(ctext)
- l := &label{
- _widget: widget,
- misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
- label: (*C.GtkLabel)(unsafe.Pointer(widget)),
- standalone: standalone,
- }
- return l
-}
-
-func newLabel(text string) Label {
- return finishNewLabel(text, false)
-}
-
-func newStandaloneLabel(text string) Label {
- l := finishNewLabel(text, true)
- // standalone labels are always at the top left
- C.gtk_misc_set_alignment(l.misc, 0, 0)
- return l
-}
-
-func (l *label) Text() string {
- return fromgstr(C.gtk_label_get_text(l.label))
-}
-
-func (l *label) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_label_set_text(l.label, ctext)
-}
-
-func (l *label) isStandalone() bool {
- return l.standalone
-}
-
-func (l *label) widget() *C.GtkWidget {
- return l._widget
-}
-
-func (l *label) setParent(p *controlParent) {
- basesetParent(l, p)
-}
-
-func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(l, x, y, width, height, d)
-}
-
-func (l *label) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(l, d)
-}
-
-func (l *label) commitResize(c *allocation, d *sizing) {
- if !l.standalone && c.neighbor != nil {
- c.neighbor.getAuxResizeInfo(d)
- if d.shouldVAlignTop {
- // don't bother aligning it to the first line of text in the control; this is harder than it's worth (thanks gregier in irc.gimp.net/#gtk+)
- C.gtk_misc_set_alignment(l.misc, 0, 0)
- } else {
- C.gtk_misc_set_alignment(l.misc, 0, 0.5)
- }
- }
- basecommitResize(l, c, d)
-}
-
-func (l *label) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(l, d)
-}
diff --git a/redo/label_windows.go b/redo/label_windows.go
deleted file mode 100644
index 96daa67..0000000
--- a/redo/label_windows.go
+++ /dev/null
@@ -1,99 +0,0 @@
-// 15 july 2014
-
-package ui
-
-// #include "winapi_windows.h"
-import "C"
-
-type label struct {
- _hwnd C.HWND
- _textlen C.LONG
- standalone bool
-}
-
-var labelclass = toUTF16("STATIC")
-
-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.WS_EX_TRANSPARENT)
- l := &label{
- _hwnd: hwnd,
- standalone: standalone,
- }
- l.SetText(text)
- C.controlSetControlFont(l._hwnd)
- return l
-}
-
-func newLabel(text string) Label {
- return finishNewLabel(text, false)
-}
-
-func newStandaloneLabel(text string) Label {
- return finishNewLabel(text, true)
-}
-
-func (l *label) Text() string {
- return baseText(l)
-}
-
-func (l *label) SetText(text string) {
- baseSetText(l, text)
-}
-
-func (l *label) isStandalone() bool {
- return l.standalone
-}
-
-func (l *label) hwnd() C.HWND {
- return l._hwnd
-}
-
-func (l *label) textlen() C.LONG {
- return l._textlen
-}
-
-func (l *label) settextlen(len C.LONG) {
- l._textlen = len
-}
-
-func (l *label) setParent(p *controlParent) {
- C.controlSetParent(l.hwnd(), p.c.hwnd)
- // don't increment p.c.nchildren here because Labels aren't tab stops
-}
-
-func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(l, x, y, width, height, d)
-}
-
-const (
- // via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
- labelHeight = 8
- labelYOffset = 3
-)
-
-func (l *label) preferredSize(d *sizing) (width, height int) {
- return int(l._textlen), fromdlgunitsY(labelHeight, d)
-}
-
-func (l *label) commitResize(c *allocation, d *sizing) {
- if !l.standalone {
- yoff := fromdlgunitsY(labelYOffset, d)
- c.y += yoff
- c.height -= yoff
- // by default, labels are drawn offset by the internal leading (the space reserved for accents on uppercase letters)
- // the above calculation assumes otherwise, so account for the difference
- // there will be enough space left over for the internal leading anyway (at least on the standard fonts)
- // don't do this to standalone labels, otherwise those accents get cut off!
- c.y -= int(d.internalLeading)
- c.height += int(d.internalLeading)
- }
- basecommitResize(l, c, d)
-}
-
-func (l *label) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(l, d)
-}
diff --git a/redo/mergeback/layout.go b/redo/mergeback/layout.go
deleted file mode 100644
index e88cae4..0000000
--- a/redo/mergeback/layout.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package ui
-
-// Recursively replaces nils with stretchy empty spaces and changes the orientation
-// of inner stack so they are perpenticular to each other.
-func resetControls(parent *Stack) {
- for i, control := range parent.controls {
- switch control.(type) {
- case *Stack:
- stack := control.(*Stack)
- stack.orientation = !parent.orientation
- resetControls(stack)
- case nil:
- emptySpace := newStack(horizontal)
- parent.controls[i] = emptySpace
- parent.stretchy[i] = true
- }
- }
-}
-
-// Creates a new Stack from the given controls. The topmost Stack will have
-// vertical orientation and margin borders, with each nested stack being
-// oriented oppositely. Controls are displayed with a default padding
-// between them.
-func Layout(controls ...Control) *Stack {
- stack := &Stack{
- orientation: vertical,
- controls: controls,
- stretchy: make([]bool, len(controls)),
- width: make([]int, len(controls)),
- height: make([]int, len(controls)),
- }
-
- resetControls(stack)
-
- return stack
-}
diff --git a/redo/mergeback/table_mouseleave_windows.c b/redo/mergeback/table_mouseleave_windows.c
deleted file mode 100644
index 9412c40..0000000
--- a/redo/mergeback/table_mouseleave_windows.c
+++ /dev/null
@@ -1,4 +0,0 @@
- case WM_MOUSELEAVE:
- tablePushed(t->gotable, -1, -1); // in case button held as drag out
- // and let the list view do its thing
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
diff --git a/redo/mergeback/windows-one-tab.go b/redo/mergeback/windows-one-tab.go
deleted file mode 100644
index 04babc8..0000000
--- a/redo/mergeback/windows-one-tab.go
+++ /dev/null
@@ -1,115 +0,0 @@
-// 25 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-/*
-On Windows, container controls are just regular controls that notify their parent when the user wants to do things; changing the contents of a switching container (such as a tab control) must be done manually.
-
-We'll create a dummy window using the pre-existing Window window class for each tab page. This makes showing and hiding tabs a matter of showing and hiding one control.
-
-TODO
-- make sure all tabs cannot be deselected (that is, make sure the current tab can never have index -1)
-*/
-
-type tab struct {
- _hwnd C.HWND
- tabs []*container
- switchrect C.RECT // size that new tab should take when switching to it
-}
-
-func newTab() Tab {
- hwnd := C.newControl(C.xWC_TABCONTROL,
- C.TCS_TOOLTIPS | C.WS_TABSTOP,
- 0)
- t := &tab{
- _hwnd: hwnd,
- }
- C.controlSetControlFont(t._hwnd)
- C.setTabSubclass(t._hwnd, unsafe.Pointer(t))
- return t
-}
-
-func (t *tab) Append(name string, control Control) {
- c := newContainer(control)
- c.setParent(&controlParent{t._hwnd})
- 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()
- }
- C.tabAppend(t._hwnd, toUTF16(name))
-}
-
-//export tabChanging
-func tabChanging(data unsafe.Pointer, current C.LRESULT) {
- t := (*tab)(data)
- t.tabs[int(current)].hide()
-}
-
-//export tabChanged
-func tabChanged(data unsafe.Pointer, new C.LRESULT) {
- t := (*tab)(data)
- // resize the new tab...
- t.tabs[int(new)].move(&t.switchrect)
- // ...then show
- t.tabs[int(new)].show()
-}
-
-func (t *tab) hwnd() C.HWND {
- return t._hwnd
-}
-
-func (t *tab) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *tab) preferredSize(d *sizing) (width, height int) {
- // TODO only consider the size of the current tab?
- for _, s := range t.tabs {
- w, h := s.child.preferredSize(d)
- if width < w {
- width = w
- }
- if height < h {
- height = h
- }
- }
- return width, height + int(C.tabGetTabHeight(t._hwnd))
-}
-
-// a tab control contains other controls; size appropriately
-func (t *tab) commitResize(c *allocation, d *sizing) {
- var r C.RECT
-
- // figure out what the rect for each child is...
- // the tab contents are children of the tab itself, so ignore c.x and c.y, which are relative to the window!
- r.left = C.LONG(0)
- r.top = C.LONG(0)
- r.right = C.LONG(c.width)
- r.bottom = C.LONG(c.height)
- C.tabGetContentRect(t._hwnd, &r)
- // and resize tabs
- // resize only the current tab; we trigger a resize on a tab change to make sure things look correct
- if len(t.tabs) > 0 {
- t.tabs[C.SendMessageW(t._hwnd, C.TCM_GETCURSEL, 0, 0)].move(&r)
- }
- // save the tab size so we can
- t.switchrect = r
- // and now resize the tab control itself
- basecommitResize(t, c, d)
-}
-
-func (t *tab) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/objc_darwin.h b/redo/objc_darwin.h
deleted file mode 100644
index 5fa1557..0000000
--- a/redo/objc_darwin.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* 8 july 2014 */
-
-/* cgo will include this file multiple times */
-#ifndef __GO_UI_OBJC_DARWIN_H__
-#define __GO_UI_OBJC_DARWIN_H__
-
-#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_7
-#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_7
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <objc/message.h>
-#include <objc/objc.h>
-#include <objc/runtime.h>
-
-/* Objective-C -> Go types for max safety */
-struct xsize {
- intptr_t width;
- intptr_t height;
-};
-
-struct xrect {
- intptr_t x;
- intptr_t y;
- intptr_t width;
- intptr_t height;
-};
-
-struct xalignment {
- struct xrect rect;
- intptr_t baseline;
-};
-
-struct xpoint {
- intptr_t x;
- intptr_t y;
-};
-
-/* uitask_darwin.m */
-extern id getAppDelegate(void); /* used by the other .m files */
-extern void uiinit(char **);
-extern void uimsgloop(void);
-extern void uistop(void);
-extern void beginModal(void);
-extern void endModal(void);
-extern void issue(void *);
-
-/* window_darwin.m */
-extern id newWindow(intptr_t, intptr_t);
-extern void windowSetDelegate(id, void *);
-extern void windowSetContentView(id, id);
-extern const char *windowTitle(id);
-extern void windowSetTitle(id, const char *);
-extern void windowShow(id);
-extern void windowHide(id);
-extern void windowClose(id);
-extern id windowContentView(id);
-extern void windowRedraw(id);
-
-/* basicctrls_darwin.m */
-#define textfieldWidth (96) /* according to Interface Builder */
-extern id newButton(void);
-extern void buttonSetDelegate(id, void *);
-extern const char *buttonText(id);
-extern void buttonSetText(id, char *);
-extern id newCheckbox(void);
-extern void checkboxSetDelegate(id, void *);
-extern BOOL checkboxChecked(id);
-extern void checkboxSetChecked(id, BOOL);
-extern id finishNewTextField(id, BOOL);
-extern id newTextField(void);
-extern id newPasswordField(void);
-extern void textfieldSetDelegate(id, void *);
-extern const char *textfieldText(id);
-extern void textfieldSetText(id, char *);
-extern id textfieldOpenInvalidPopover(id, char *);
-extern void textfieldCloseInvalidPopover(id);
-extern id newLabel(void);
-extern id newGroup(id);
-extern const char *groupText(id);
-extern void groupSetText(id, char *);
-
-/* container_darwin.m */
-extern id newContainerView(void *);
-extern void moveControl(id, intptr_t, intptr_t, intptr_t, intptr_t);
-
-/* tab_darwin.m */
-extern id newTab(void);
-extern void tabAppend(id, char *, id);
-extern struct xsize tabPreferredSize(id);
-
-/* table_darwin.m */
-enum {
- colTypeText,
- colTypeImage,
- colTypeCheckbox,
-};
-extern id newTable(void);
-extern void tableAppendColumn(id, intptr_t, char *, int, BOOL);
-extern void tableUpdate(id);
-extern void tableMakeDataSource(id, void *);
-extern struct xsize tablePreferredSize(id);
-extern intptr_t tableSelected(id);
-extern void tableSelect(id, intptr_t);
-
-/* control_darwin.m */
-extern void parent(id, id);
-extern void controlSetHidden(id, BOOL);
-extern void setStandardControlFont(id);
-extern void setSmallControlFont(id);
-extern struct xsize controlPreferredSize(id);
-extern id newScrollView(id, BOOL);
-extern struct xalignment alignmentInfo(id, struct xrect);
-extern struct xalignment alignmentInfoFrame(id);
-
-/* area_darwin.h */
-extern Class getAreaClass(void);
-extern id newArea(void *);
-extern BOOL drawImage(void *, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
-extern const uintptr_t cNSShiftKeyMask;
-extern const uintptr_t cNSControlKeyMask;
-extern const uintptr_t cNSAlternateKeyMask;
-extern const uintptr_t cNSCommandKeyMask;
-extern uintptr_t modifierFlags(id);
-extern struct xpoint getTranslatedEventPoint(id, id);
-extern intptr_t buttonNumber(id);
-extern intptr_t clickCount(id);
-extern uintptr_t pressedMouseButtons(void);
-extern uintptr_t keyCode(id);
-extern void areaRepaint(id, struct xrect);
-extern void areaRepaintAll(id);
-extern void areaTextFieldOpen(id, id, intptr_t, intptr_t);
-extern void areaSetTextField(id, id);
-extern void areaEndTextFieldEditing(id, id);
-
-
-/* common_darwin.m */
-extern void disableAutocorrect(id);
-
-/* imagerep_darwin.m */
-extern id toImageListImage(void *, intptr_t, intptr_t, intptr_t);
-
-/* dialog_darwin.m */
-extern void openFile(id, void *);
-
-/* warningpopover_darwin.m */
-extern id newWarningPopover(char *);
-extern void warningPopoverShow(id, id);
-
-#endif
diff --git a/redo/proposals/sidebar.md b/redo/proposals/sidebar.md
deleted file mode 100644
index fa23392..0000000
--- a/redo/proposals/sidebar.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Sidebar Control
-
-```go
-type Sidebar interface {
- Control
-
- AppendCategory(text string)
- DeleteCategory(index int)
-
- AppendItem(category int, name string)
- DeleteItem(category int, index int)
-
- Selection() (category int, index int) // or Selected()?
- Select(category int, index int)
-
- OnSelected(func())
-}
-```
-
-Simple two-level sidebars.
-
-Could have images on each item in the future.
-
-## Mac OS X
-Source List NSTableView (need to see how this will work)
-
-## GTK+
-GTK_STYLE_CLASS_SIDEBAR (available in 3.4); see how GtkPlacesSidebar implements this
- - other programs that do: Rhythmbox
-
-## Windows
-????
diff --git a/redo/proposals/tree.md b/redo/proposals/tree.md
deleted file mode 100644
index a4752f6..0000000
--- a/redo/proposals/tree.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Tree
-
-Unlike Table, Tree can only store a set of a single data type. (Blame Windows.)
-
-```go
-type TreeData struct {
- Checked bool
- Image ImageIndex
- Text string
- Children []TreeData // TODO does this need to be *[]TreeData?
-}
-```
-
-(the facilities for Images has yet to be designed)
-
-Tree itself will operate similarly to Table:
-
-```go
-type Tree struct {
- Control
- sync.Locker // with Unlock() refreshing the view
- Data() *[]TreeData
- SetHasCheckboxes(bool)
- SetHasImages(bool)
-}
-```
-
-By default, a Tree only shows the Text field.
-
-A Tree path is just an `[]int` with each element set to the consecutive index in Children. For example:
-
-```go
-i := []int{3, 4, 5}
-value := tree.Data()[i[0]].Children[i[1]].Children[i[2]].Text
-```
diff --git a/redo/scrapped b/redo/scrapped
deleted file mode 100644
index c42bba3..0000000
--- a/redo/scrapped
+++ /dev/null
@@ -1,4 +0,0 @@
-Window.SetSize()
-Window.Center() (only really effective on Mac OS X)
-Control.Show()/Control.Hide() (too much effort to get right)
-Multiple selection Tables (Windows and GTK+ event handling is some wacky dumb thing; could reconsider for Windows if I can write a good replacement but GTK+ still kills it)
diff --git a/redo/stack.go b/redo/stack.go
deleted file mode 100644
index 0bd587a..0000000
--- a/redo/stack.go
+++ /dev/null
@@ -1,209 +0,0 @@
-// 13 february 2014
-
-package ui
-
-import (
- "fmt"
-)
-
-type orientation bool
-
-const (
- horizontal orientation = false
- vertical orientation = true
-)
-
-// A Stack stacks controls horizontally or vertically within the Stack's parent.
-// A horizontal Stack gives all controls the same height and their preferred widths.
-// A vertical Stack gives all controls the same width and their preferred heights.
-// Any extra space at the end of a Stack is left blank.
-// Some controls may be marked as "stretchy": when the Window they are in changes size, stretchy controls resize to take up the remaining space after non-stretchy controls are laid out. If multiple controls are marked stretchy, they are alloted equal distribution of the remaining space.
-type Stack interface {
- Control
-
- // SetStretchy marks a control in a Stack as stretchy.
- // It panics if index is out of range.
- SetStretchy(index int)
-}
-
-type stack struct {
- orientation orientation
- controls []Control
- stretchy []bool
- width, height []int // caches to avoid reallocating these each time
-}
-
-func newStack(o orientation, controls ...Control) Stack {
- return &stack{
- orientation: o,
- controls: controls,
- stretchy: make([]bool, len(controls)),
- width: make([]int, len(controls)),
- height: make([]int, len(controls)),
- }
-}
-
-// NewHorizontalStack creates a new Stack that arranges the given Controls horizontally.
-func NewHorizontalStack(controls ...Control) Stack {
- return newStack(horizontal, controls...)
-}
-
-// NewVerticalStack creates a new Stack that arranges the given Controls vertically.
-func NewVerticalStack(controls ...Control) Stack {
- return newStack(vertical, controls...)
-}
-
-func (s *stack) SetStretchy(index int) {
- if index < 0 || index > len(s.stretchy) {
- panic(fmt.Errorf("index %d out of range in Stack.SetStretchy()", index))
- }
- s.stretchy[index] = true
-}
-
-func (s *stack) setParent(parent *controlParent) {
- for _, c := range s.controls {
- c.setParent(parent)
- }
-}
-
-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
-
- if len(s.controls) == 0 { // do nothing if there's nothing to do
- return nil
- }
- // 0) inset the available rect by the needed padding
- if s.orientation == horizontal {
- width -= (len(s.controls) - 1) * d.xpadding
- } else {
- height -= (len(s.controls) - 1) * d.ypadding
- }
- // 1) get height and width of non-stretchy controls; figure out how much space is alloted to stretchy controls
- stretchywid = width
- stretchyht = height
- nStretchy := 0
- for i, c := range s.controls {
- if s.stretchy[i] {
- nStretchy++
- continue
- }
- w, h := c.preferredSize(d)
- if s.orientation == horizontal { // all controls have same height
- s.width[i] = w
- s.height[i] = height
- stretchywid -= w
- } else { // all controls have same width
- s.width[i] = width
- s.height[i] = h
- stretchyht -= h
- }
- }
- // 2) figure out size of stretchy controls
- if nStretchy != 0 {
- if s.orientation == horizontal { // split rest of width
- stretchywid /= nStretchy
- } else { // split rest of height
- stretchyht /= nStretchy
- }
- }
- for i := range s.controls {
- if !s.stretchy[i] {
- continue
- }
- s.width[i] = stretchywid
- s.height[i] = stretchyht
- }
- // 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
- current.neighbor = c
- }
- if len(as) != 0 {
- current = as[0] // next left is first subwidget
- } else {
- current = nil // spaces don't have allocation data
- }
- }
- allocations = append(allocations, as...)
- if s.orientation == horizontal {
- x += s.width[i] + d.xpadding
- } else {
- y += s.height[i] + d.ypadding
- }
- }
- return allocations
-}
-
-// The preferred size of a Stack is the sum of the preferred sizes of non-stretchy controls + (the number of stretchy controls * the largest preferred size among all stretchy controls).
-func (s *stack) preferredSize(d *sizing) (width int, height int) {
- max := func(a int, b int) int {
- if a > b {
- return a
- }
- return b
- }
-
- var nStretchy int
- var maxswid, maxsht int
-
- if len(s.controls) == 0 { // no controls, so return emptiness
- return 0, 0
- }
- if s.orientation == horizontal {
- width = (len(s.controls) - 1) * d.xpadding
- } else {
- height = (len(s.controls) - 1) * d.ypadding
- }
- for i, c := range s.controls {
- w, h := c.preferredSize(d)
- if s.stretchy[i] {
- nStretchy++
- maxswid = max(maxswid, w)
- maxsht = max(maxsht, h)
- }
- if s.orientation == horizontal { // max vertical size
- if !s.stretchy[i] {
- width += w
- }
- height = max(height, h)
- } else {
- width = max(width, w)
- if !s.stretchy[i] {
- height += h
- }
- }
- }
- if s.orientation == horizontal {
- width += nStretchy * maxswid
- } else {
- height += nStretchy * maxsht
- }
- return
-}
-
-func (s *stack) commitResize(c *allocation, d *sizing) {
- // this is to satisfy Control; nothing to do here
-}
-
-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.
-//
-// For a Stack, Space can be used to insert spaces in the beginning or middle of Stacks (Stacks by nature handle spaces at the end themselves). In order for this to work properly, make the Space stretchy.
-//
-// For a Grid, Space can be used to have an empty cell. A stretchy Grid cell with a Space can be used to anchor the perimeter of a Grid to the respective Window edges without making one of the other controls stretchy instead (leaving empty space in the Window otherwise). Otherwise, you do not need to do anything special for the Space to work (though remember that an entire row or column of Spaces will appear as having height or width zero, respectively, unless one is marked as stretchy).
-//
-// The value returned from Space() may or may not be unique.
-func Space() Control {
- return space
-}
-
-// As above, a Stack with no controls draws nothing and reports no errors; its parent will still size it properly if made stretchy.
-var space Control = newStack(horizontal)
diff --git a/redo/tab_darwin.go b/redo/tab_darwin.go
deleted file mode 100644
index e6e0c8a..0000000
--- a/redo/tab_darwin.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// 25 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type tab struct {
- _id C.id
- tabs []*container
-}
-
-func newTab() Tab {
- return &tab{
- _id: C.newTab(),
- }
-}
-
-func (t *tab) Append(name string, control Control) {
- c := newContainer(control)
- t.tabs = append(t.tabs, c)
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- C.tabAppend(t._id, cname, c.id)
-}
-
-func (t *tab) id() C.id {
- return t._id
-}
-
-func (t *tab) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *tab) preferredSize(d *sizing) (width, height int) {
- s := C.tabPreferredSize(t._id)
- return int(s.width), int(s.height)
-}
-
-// no need to override Control.commitResize() as only prepared the tabbed control; its children will be resized when that one is resized (and NSTabView itself will call setFrame: for us)
-func (t *tab) commitResize(a *allocation, d *sizing) {
- basecommitResize(t, a, d)
-}
-
-func (t *tab) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/tab_darwin.m b/redo/tab_darwin.m
deleted file mode 100644
index 1c2920a..0000000
--- a/redo/tab_darwin.m
+++ /dev/null
@@ -1,40 +0,0 @@
-// 25 july 2014
-
-#import "objc_darwin.h"
-#import "_cgo_export.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSTabView(x) ((NSTabView *) (x))
-#define toNSView(x) ((NSView *) (x))
-
-id newTab(void)
-{
- NSTabView *t;
-
- t = [[NSTabView alloc] initWithFrame:NSZeroRect];
- setStandardControlFont((id) t); // safe; same selector provided by NSTabView
- return (id) t;
-}
-
-void tabAppend(id t, char *name, id view)
-{
- NSTabViewItem *i;
-
- i = [[NSTabViewItem alloc] initWithIdentifier:nil];
- [i setLabel:[NSString stringWithUTF8String:name]];
- [i setView:toNSView(view)];
- [toNSTabView(t) addTabViewItem:i];
-}
-
-struct xsize tabPreferredSize(id control)
-{
- NSTabView *tv;
- NSSize s;
- struct xsize t;
-
- tv = toNSTabView(control);
- s = [tv minimumSize];
- t.width = (intptr_t) s.width;
- t.height = (intptr_t) s.height;
- return t;
-}
diff --git a/redo/tab_unix.go b/redo/tab_unix.go
deleted file mode 100644
index c73796f..0000000
--- a/redo/tab_unix.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// +build !windows,!darwin
-
-// 25 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-import "C"
-
-type tab struct {
- _widget *C.GtkWidget
- container *C.GtkContainer
- notebook *C.GtkNotebook
-
- 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)),
- }
- // 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)
- return t
-}
-
-func (t *tab) Append(name string, control Control) {
- c := newContainer(control)
- t.tabs = append(t.tabs, c)
- // this calls gtk_container_add(), which, according to gregier in irc.gimp.net/#gtk+, acts just like gtk_notebook_append_page()
- c.setParent(&controlParent{t.container})
- cname := togstr(name)
- 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)),
- cname)
-}
-
-func (t *tab) widget() *C.GtkWidget {
- return t._widget
-}
-
-func (t *tab) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *tab) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(t, d)
-}
-
-// no need to override Control.commitResize() as only prepared the tabbed control; its children will be reallocated when that one is resized
-func (t *tab) commitResize(a *allocation, d *sizing) {
- basecommitResize(t, a, d)
-}
-
-func (t *tab) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/tab_windows.c b/redo/tab_windows.c
deleted file mode 100644
index 9a9908a..0000000
--- a/redo/tab_windows.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// 25 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-// provided for cgo's benefit
-LPWSTR xWC_TABCONTROL = WC_TABCONTROL;
-
-static LRESULT CALLBACK tabSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
-{
- NMHDR *nmhdr = (NMHDR *) lParam;
- LRESULT r;
-
- switch (uMsg) {
- case msgNOTIFY:
- switch (nmhdr->code) {
- case TCN_SELCHANGING:
- r = SendMessageW(hwnd, TCM_GETCURSEL, 0, 0);
- if (r == (LRESULT) -1) // no tab currently selected
- return FALSE;
- tabChanging((void *) data, r);
- return FALSE; // allow change
- case TCN_SELCHANGE:
- tabChanged((void *) data, SendMessageW(hwnd, TCM_GETCURSEL, 0, 0));
- return 0;
- }
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case msgTabCurrentTabHasChildren:
- return (LRESULT) tabTabHasChildren((void *) data, SendMessageW(hwnd, TCM_GETCURSEL, 0, 0));
- case WM_NCDESTROY:
- if ((*fv_RemoveWindowSubclass)(hwnd, tabSubProc, id) == FALSE)
- xpanic("error removing Tab subclass (which was for its own event handler)", GetLastError());
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- default:
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("Tab", "tabSubProc()", uMsg);
- return 0; // unreached
-}
-
-void setTabSubclass(HWND hwnd, void *data)
-{
- if ((*fv_SetWindowSubclass)(hwnd, tabSubProc, 0, (DWORD_PTR) data) == FALSE)
- xpanic("error subclassing Tab to give it its own event handler", GetLastError());
-}
-
-void tabAppend(HWND hwnd, LPWSTR name)
-{
- TCITEM item;
- LRESULT n;
-
- ZeroMemory(&item, sizeof (TCITEM));
- item.mask = TCIF_TEXT;
- item.pszText = name;
- // MSDN's example code uses the first invalid index directly for this
- n = SendMessageW(hwnd, TCM_GETITEMCOUNT, 0, 0);
- if (SendMessageW(hwnd, TCM_INSERTITEM, (WPARAM) n, (LPARAM) (&item)) == (LRESULT) -1)
- xpanic("error adding tab to Tab", GetLastError());
-}
-
-void tabGetContentRect(HWND hwnd, RECT *r)
-{
- // not &r; already a pointer (thanks MindChild in irc.efnet.net/#winprog for spotting my failure)
- SendMessageW(hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM) r);
-}
-
-// theoretically we don't need to iterate over every tab for this, but let's do it just to be safe
-LONG tabGetTabHeight(HWND hwnd)
-{
- RECT r;
- LRESULT i, n;
- LONG tallest;
-
- n = SendMessageW(hwnd, TCM_GETITEMCOUNT, 0, 0);
- // if there are no tabs, then the control just draws a box over the full window rect, reserving no space for tabs; this is handled with the next line
- tallest = 0;
- for (i = 0; i < n; i++) {
- if (SendMessageW(hwnd, TCM_GETITEMRECT, (WPARAM) i, (LPARAM) (&r)) == FALSE)
- xpanic("error getting tab height for Tab.preferredSize()", GetLastError());
- if (tallest < (r.bottom - r.top))
- tallest = r.bottom - r.top;
- }
- return tallest;
-}
-
-void tabEnterChildren(HWND hwnd)
-{
- DWORD style, xstyle;
-
- style = (DWORD) GetWindowLongPtrW(hwnd, GWL_STYLE);
- xstyle = (DWORD) GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
- style &= ~((DWORD) WS_TABSTOP);
- xstyle |= WS_EX_CONTROLPARENT;
- SetWindowLongPtrW(hwnd, GWL_STYLE, (LONG_PTR) style);
- SetWindowLongPtrW(hwnd, GWL_EXSTYLE, (LONG_PTR) xstyle);
-}
-
-void tabLeaveChildren(HWND hwnd)
-{
- DWORD style, xstyle;
-
- style = (DWORD) GetWindowLongPtrW(hwnd, GWL_STYLE);
- xstyle = (DWORD) GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
- style |= WS_TABSTOP;
- xstyle &= ~((DWORD) WS_EX_CONTROLPARENT);
- SetWindowLongPtrW(hwnd, GWL_STYLE, (LONG_PTR) style);
- SetWindowLongPtrW(hwnd, GWL_EXSTYLE, (LONG_PTR) xstyle);
-}
diff --git a/redo/tab_windows.go b/redo/tab_windows.go
deleted file mode 100644
index 5aabd8d..0000000
--- a/redo/tab_windows.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// 25 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-/*
-On Windows, container controls are just regular controls that notify their parent when the user wants to do things; changing the contents of a switching container (such as a tab control) must be done manually.
-
-We'll create a dummy window using the pre-existing Window window class for each tab page. This makes showing and hiding tabs a matter of showing and hiding one control.
-*/
-
-type tab struct {
- _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
- t := &tab{
- _hwnd: hwnd,
- }
- C.controlSetControlFont(t._hwnd)
- C.setTabSubclass(t._hwnd, unsafe.Pointer(t))
- return t
-}
-
-func (t *tab) Append(name string, control Control) {
- c := newContainer(control)
- c.setParent(t._hwnd)
- 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()
- }
- C.tabAppend(t._hwnd, toUTF16(name))
-}
-
-//export tabChanging
-func tabChanging(data unsafe.Pointer, current C.LRESULT) {
- t := (*tab)(data)
- t.tabs[int(current)].hide()
-}
-
-//export tabChanged
-func tabChanged(data unsafe.Pointer, new C.LRESULT) {
- t := (*tab)(data)
- t.tabs[int(new)].show()
-}
-
-//export tabTabHasChildren
-func tabTabHasChildren(data unsafe.Pointer, which C.LRESULT) C.BOOL {
- t := (*tab)(data)
- if len(t.tabs) == 0 { // currently no tabs
- return C.FALSE
- }
- if t.tabs[int(which)].nchildren > 0 {
- return C.TRUE
- }
- return C.FALSE
-}
-
-func (t *tab) hwnd() C.HWND {
- return t._hwnd
-}
-
-func (t *tab) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *tab) preferredSize(d *sizing) (width, height int) {
- for _, s := range t.tabs {
- w, h := s.child.preferredSize(d)
- if width < w {
- width = w
- }
- if height < h {
- height = h
- }
- }
- return width, height + int(C.tabGetTabHeight(t._hwnd))
-}
-
-// a tab control contains other controls; size appropriately
-func (t *tab) commitResize(c *allocation, d *sizing) {
- var r C.RECT
-
- // figure out what the rect for each child is...
- // the tab contents are children of the tab itself, so ignore c.x and c.y, which are relative to the window!
- r.left = C.LONG(0)
- r.top = C.LONG(0)
- r.right = C.LONG(c.width)
- r.bottom = C.LONG(c.height)
- C.tabGetContentRect(t._hwnd, &r)
- // and resize tabs
- // don't resize just the current tab; resize all tabs!
- for _, c := range t.tabs {
- // because each widget is actually a child of the Window, the origin is the one we calculated above
- c.move(&r)
- }
- // and now resize the tab control itself
- basecommitResize(t, c, d)
-}
-
-func (t *tab) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/table.go b/redo/table.go
deleted file mode 100644
index 846378d..0000000
--- a/redo/table.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// 28 july 2014
-
-package ui
-
-import (
- "fmt"
- "reflect"
- "sync"
-)
-
-// Table is a Control that displays a list of like-structured data in a grid where each row represents an item and each column represents a bit of data.
-// Tables store and render a slice of struct values.
-// Each field of the struct of type ImageIndex is rendered as an icon from the Table's ImageList.
-// Each field whose type is bool or equivalent to bool is rendered as a checkbox.
-// All other fields are rendered as strings formatted with package fmt's %v format specifier.
-//
-// Tables are read-only by default, except for checkboxes, which are user-settable.
-//
-// Tables have headers on top of all columns.
-// Currently the name of the header is the same as the name of the field.
-//
-// Tables maintain their own storage behind a sync.RWMutex-compatible sync.Locker; use Table.Lock()/Table.Unlock() to make changes and Table.RLock()/Table.RUnlock() to merely read values.
-type Table interface {
- Control
-
- // Lock and Unlock lock and unlock Data for reading or writing.
- // RLock and RUnlock lock and unlock Data for reading only.
- // These methods have identical semantics to the analogous methods of sync.RWMutex.
- // In addition, Unlock() will request an update of the Table to account for whatever was changed.
- Lock()
- Unlock()
- RLock()
- RUnlock()
-
- // Data returns the internal data.
- // The returned value will contain an object of type pointer to slice of some structure; use a type assertion to get the properly typed object out.
- // Do not call this outside a Lock()..Unlock() or RLock()..RUnlock() pair.
- Data() interface{}
-
- // LoadImageList loads the given ImageList into the Table.
- // This function copies; changes to the ImageList made later will not be reflected by the Table.
- LoadImageList(imagelist ImageList)
-
- // Selected and Select get and set the currently selected item in the Table.
- // Selected returns -1 if no item is selected.
- // Pass -1 to Select to deselect all items.
- Selected() int
- Select(index int)
-
- // OnSelected is an event that gets triggered after the selection in the Table changes in whatever way (item selected or item deselected).
- OnSelected(func())
-}
-
-type tablebase struct {
- lock sync.RWMutex
- data interface{}
-}
-
-// NewTable creates a new Table.
-// Currently, the argument must be a reflect.Type representing the structure that each item in the Table will hold, and the Table will be initially empty.
-// This will change in the future.
-func NewTable(ty reflect.Type) Table {
- if ty.Kind() != reflect.Struct {
- panic(fmt.Errorf("unknown or unsupported type %v given to NewTable()", ty))
- }
- b := new(tablebase)
- // we want a pointer to a slice
- b.data = reflect.New(reflect.SliceOf(ty)).Interface()
- return finishNewTable(b, ty)
-}
-
-func (b *tablebase) Lock() {
- b.lock.Lock()
-}
-
-// Unlock() is defined on each backend implementation of Table
-// they should all call this, however
-func (b *tablebase) unlock() {
- b.lock.Unlock()
-}
-
-func (b *tablebase) RLock() {
- b.lock.RLock()
-}
-
-func (b *tablebase) RUnlock() {
- b.lock.RUnlock()
-}
-
-func (b *tablebase) Data() interface{} {
- return b.data
-}
diff --git a/redo/table_darwin.go b/redo/table_darwin.go
deleted file mode 100644
index 904600d..0000000
--- a/redo/table_darwin.go
+++ /dev/null
@@ -1,158 +0,0 @@
-// 29 july 2014
-
-package ui
-
-import (
- "fmt"
- "reflect"
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type table struct {
- *tablebase
-
- _id C.id
- scroller *scroller
-
- 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(),
- }
- // also sets the delegate
- C.tableMakeDataSource(t._id, unsafe.Pointer(t))
- for i := 0; i < ty.NumField(); i++ {
- cname := C.CString(ty.Field(i).Name)
- coltype := C.colTypeText
- editable := false
- switch {
- case ty.Field(i).Type == reflect.TypeOf(ImageIndex(0)):
- coltype = C.colTypeImage
- case ty.Field(i).Type.Kind() == reflect.Bool:
- coltype = C.colTypeCheckbox
- 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
- }
- return t
-}
-
-func (t *table) Unlock() {
- t.unlock()
- // there's a possibility that user actions can happen at this point, before the view is updated
- // alas, this is something we have to deal with, because Unlock() can be called from any thread
- go func() {
- Do(func() {
- t.RLock()
- defer t.RUnlock()
- C.tableUpdate(t._id)
- })
- }()
-}
-
-func (t *table) LoadImageList(i ImageList) {
- i.apply(&t.images)
-}
-
-func (t *table) Selected() int {
- t.RLock()
- defer t.RUnlock()
- return int(C.tableSelected(t._id))
-}
-
-func (t *table) Select(index int) {
- t.RLock()
- defer t.RUnlock()
- C.tableSelect(t._id, C.intptr_t(index))
-}
-
-func (t *table) OnSelected(f func()) {
- t.selected.set(f)
-}
-
-//export goTableDataSource_getValue
-func goTableDataSource_getValue(data unsafe.Pointer, row C.intptr_t, col C.intptr_t, outtype *C.int) unsafe.Pointer {
- t := (*table)(data)
- t.RLock()
- defer t.RUnlock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- datum := d.Index(int(row)).Field(int(col))
- switch {
- case datum.Type() == reflect.TypeOf(ImageIndex(0)):
- *outtype = C.colTypeImage
- d := datum.Interface().(ImageIndex)
- return unsafe.Pointer(t.images[d])
- case datum.Kind() == reflect.Bool:
- *outtype = C.colTypeCheckbox
- if datum.Bool() == true {
- // return a non-nil pointer
- // outtype isn't Go-side so it'll work
- return unsafe.Pointer(outtype)
- }
- return nil
- default:
- s := fmt.Sprintf("%v", datum)
- return unsafe.Pointer(C.CString(s))
- }
-}
-
-//export goTableDataSource_getRowCount
-func goTableDataSource_getRowCount(data unsafe.Pointer) C.intptr_t {
- t := (*table)(data)
- t.RLock()
- defer t.RUnlock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- return C.intptr_t(d.Len())
-}
-
-//export goTableDataSource_toggled
-func goTableDataSource_toggled(data unsafe.Pointer, row C.intptr_t, col C.intptr_t, checked C.BOOL) {
- t := (*table)(data)
- t.Lock()
- defer t.Unlock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- datum := d.Index(int(row)).Field(int(col))
- datum.SetBool(fromBOOL(checked))
-}
-
-//export tableSelectionChanged
-func tableSelectionChanged(data unsafe.Pointer) {
- t := (*table)(data)
- t.selected.fire()
-}
-
-func (t *table) id() C.id {
- return t._id
-}
-
-func (t *table) setParent(p *controlParent) {
- t.scroller.setParent(p)
-}
-
-func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *table) preferredSize(d *sizing) (width, height int) {
- s := C.tablePreferredSize(t._id)
- return int(s.width), int(s.height)
-}
-
-func (t *table) commitResize(c *allocation, d *sizing) {
- t.scroller.commitResize(c, d)
-}
-
-func (t *table) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/table_darwin.m b/redo/table_darwin.m
deleted file mode 100644
index 5e7a9e6..0000000
--- a/redo/table_darwin.m
+++ /dev/null
@@ -1,194 +0,0 @@
-// 29 july 2014
-
-#import "objc_darwin.h"
-#import "_cgo_export.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSTableView(x) ((NSTableView *) (x))
-
-// NSTableColumn provides no provision to store an integer data
-// it does provide an identifier tag, but that's a NSString, and I'd rather not risk the conversion overhead
-@interface goTableColumn : NSTableColumn {
-@public
- intptr_t gocolnum;
-}
-@end
-
-@implementation goTableColumn
-@end
-
-@interface goTableDataSource : NSObject <NSTableViewDataSource, NSTableViewDelegate> {
-@public
- void *gotable;
-}
-@end
-
-@implementation goTableDataSource
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)view
-{
- return (NSInteger) goTableDataSource_getRowCount(self->gotable);
-}
-
-- (id)tableView:(NSTableView *)view objectValueForTableColumn:(NSTableColumn *)col row:(NSInteger)row
-{
- void *ret;
- NSString *s;
- intptr_t colnum;
- char *str;
- int type = colTypeText;
-
- colnum = ((goTableColumn *) col)->gocolnum;
- ret = goTableDataSource_getValue(self->gotable, (intptr_t) row, colnum, &type);
- switch (type) {
- case colTypeImage:
- return (id) ret;
- case colTypeCheckbox:
- if (ret == NULL)
- return nil;
- return (id) [NSNumber numberWithInt:1];
- }
- str = (char *) ret;
- s = [NSString stringWithUTF8String:str];
- free(str); // allocated with C.CString() on the Go side
- return (id) s;
-}
-
-- (void)tableView:(NSTableView *)view setObjectValue:(id)value forTableColumn:(NSTableColumn *)col row:(NSInteger)row
-{
- intptr_t colnum;
- NSNumber *number = (NSNumber *) value; // thanks to mikeash in irc.freenode.net/#macdev
-
- colnum = ((goTableColumn *) col)->gocolnum;
- goTableDataSource_toggled(self->gotable, (intptr_t) row, colnum, [number boolValue]);
-}
-
-- (void)tableViewSelectionDidChange:(NSNotification *)note
-{
- tableSelectionChanged(self->gotable);
-}
-
-@end
-
-id newTable(void)
-{
- NSTableView *t;
-
- t = [[NSTableView alloc] initWithFrame:NSZeroRect];
- [t setAllowsColumnReordering:NO];
- [t setAllowsColumnResizing:YES];
- [t setAllowsMultipleSelection:NO];
- [t setAllowsEmptySelection:YES];
- [t setAllowsColumnSelection:NO];
- return (id) t;
-}
-
-void tableAppendColumn(id t, intptr_t colnum, char *name, int type, BOOL editable)
-{
- goTableColumn *c;
- NSImageCell *ic;
- NSButtonCell *bc;
- NSLineBreakMode lbm = NSLineBreakByTruncatingTail; // default for most types
-
- c = [[goTableColumn alloc] initWithIdentifier:nil];
- c->gocolnum = colnum;
- switch (type) {
- case colTypeImage:
- ic = [[NSImageCell alloc] initImageCell:nil];
- // this is the behavior we want, which differs from the Interface Builder default of proportionally down
- [ic setImageScaling:NSImageScaleProportionallyUpOrDown];
- // these two, however, ARE Interface Builder defaults
- [ic setImageFrameStyle:NSImageFrameNone];
- [ic setImageAlignment:NSImageAlignCenter];
- [c setDataCell:ic];
- break;
- case colTypeCheckbox:
- bc = [[NSButtonCell alloc] init];
- [bc setBezelStyle:NSRegularSquareBezelStyle]; // not explicitly stated as such in Interface Builder; extracted with a test program
- [bc setButtonType:NSSwitchButton];
- [bc setBordered:NO];
- [bc setTransparent:NO];
- [bc setAllowsMixedState:NO];
- [bc setTitle:@""]; // no label
- lbm = NSLineBreakByWordWrapping; // Interface Builder sets this mode for this type
- [c setDataCell:bc];
- break;
- }
- // otherwise just use the current cell
- [c setEditable:editable];
- [[c headerCell] setStringValue:[NSString stringWithUTF8String:name]];
- setSmallControlFont((id) [c headerCell]);
- setStandardControlFont((id) [c dataCell]);
- // the following are according to Interface Builder
- // for the header cell, a stub program had to be written because Interface Builder doesn't support editing header cells directly
- [[c headerCell] setScrollable:NO];
- [[c headerCell] setWraps:NO];
- [[c headerCell] setLineBreakMode:NSLineBreakByTruncatingTail];
- [[c headerCell] setUsesSingleLineMode:NO];
- [[c headerCell] setTruncatesLastVisibleLine:NO];
- [[c dataCell] setScrollable:NO];
- [[c dataCell] setWraps:NO];
- [[c dataCell] setLineBreakMode:lbm];
- [[c dataCell] setUsesSingleLineMode:NO];
- [[c dataCell] setTruncatesLastVisibleLine:NO];
- [toNSTableView(t) addTableColumn:c];
-}
-
-void tableUpdate(id t)
-{
- [toNSTableView(t) reloadData];
-}
-
-// also sets the delegate
-void tableMakeDataSource(id table, void *gotable)
-{
- goTableDataSource *model;
-
- model = [goTableDataSource new];
- model->gotable = gotable;
- [toNSTableView(table) setDataSource:model];
- [toNSTableView(table) setDelegate:model];
-}
-
-// -[NSTableView sizeToFit] does not actually size to fit
-// -[NSTableColumn sizeToFit] is just for the header
-// -[NSTableColumn sizeToFit] can work for guessing but overrides user settings
-// -[[NSTableColumn headerCell] cellSize] does NOT (despite being documented as returning the minimum needed size)
-// Let's write our own to prefer:
-// - width of the sum of all columns's current widths
-// - height of 5 rows (arbitrary count; seems reasonable) + header view height
-// Hopefully this is reasonable.
-struct xsize tablePreferredSize(id control)
-{
- NSTableView *t;
- NSArray *columns;
- struct xsize s;
- NSUInteger i, n;
- NSTableColumn *c;
-
- t = toNSTableView(control);
- columns = [t tableColumns];
- n = [columns count];
- s.width = 0;
- for (i = 0; i < n; i++) {
- CGFloat width;
-
- c = (NSTableColumn *) [columns objectAtIndex:i];
- s.width += (intptr_t) [c width];
- }
- s.height = 5 * (intptr_t) [t rowHeight];
- s.height += (intptr_t) [[t headerView] frame].size.height;
- return s;
-}
-
-intptr_t tableSelected(id table)
-{
- return (intptr_t) [toNSTableView(table) selectedRow];
-}
-
-void tableSelect(id table, intptr_t row)
-{
- [toNSTableView(table) deselectAll:table];
- if (row != -1)
- [toNSTableView(table) selectRowIndexes:[NSIndexSet indexSetWithIndex:((NSUInteger) row)] byExtendingSelection:NO];
-}
diff --git a/redo/table_unix.c b/redo/table_unix.c
deleted file mode 100644
index ed06bb6..0000000
--- a/redo/table_unix.c
+++ /dev/null
@@ -1,270 +0,0 @@
-// +build !windows,!darwin
-
-// 29 july 2014
-
-#include "gtk_unix.h"
-#include "_cgo_export.h"
-
-void tableAppendColumn(GtkTreeView *table, gint index, gchar *name, GtkCellRenderer *renderer, gchar *attribute)
-{
- GtkTreeViewColumn *col;
-
- col = gtk_tree_view_column_new_with_attributes(name, renderer,
- attribute, index,
- NULL);
- // allow columns to be resized
- gtk_tree_view_column_set_resizable(col, TRUE);
- gtk_tree_view_append_column(table, col);
-}
-
-/*
-how our GtkTreeIters are stored:
- stamp: either GOOD_STAMP or BAD_STAMP
- user_data: row index
-Thanks to Company in irc.gimp.net/#gtk+ for suggesting the GSIZE_TO_POINTER() trick.
-*/
-#define GOOD_STAMP 0x1234
-#define BAD_STAMP 0x5678
-#define FROM(x) ((gint) GPOINTER_TO_SIZE((x)))
-#define TO(x) GSIZE_TO_POINTER((gsize) (x))
-
-static void goTableModel_initGtkTreeModel(GtkTreeModelIface *);
-
-G_DEFINE_TYPE_WITH_CODE(goTableModel, goTableModel, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL, goTableModel_initGtkTreeModel))
-
-static void goTableModel_init(goTableModel *t)
-{
- // do nothing
-}
-
-static void goTableModel_dispose(GObject *obj)
-{
- G_OBJECT_CLASS(goTableModel_parent_class)->dispose(obj);
-}
-
-static void goTableModel_finalize(GObject *obj)
-{
- G_OBJECT_CLASS(goTableModel_parent_class)->finalize(obj);
-}
-
-// and now for the interface function definitions
-
-static GtkTreeModelFlags goTableModel_get_flags(GtkTreeModel *model)
-{
- return GTK_TREE_MODEL_LIST_ONLY;
-}
-
-// get_n_columns and get_column_type in Go
-
-static gboolean goTableModel_get_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
-{
- goTableModel *t = (goTableModel *) model;
- gint index;
-
- if (gtk_tree_path_get_depth(path) != 1)
- goto bad;
- index = gtk_tree_path_get_indices(path)[0];
- if (index < 0)
- goto bad;
- if (index >= goTableModel_getRowCount(t->gotable))
- goto bad;
- iter->stamp = GOOD_STAMP;
- iter->user_data = TO(index);
- return TRUE;
-bad:
- iter->stamp = BAD_STAMP;
- return FALSE;
-}
-
-static GtkTreePath *goTableModel_get_path(GtkTreeModel *model, GtkTreeIter *iter)
-{
- // note: from this point forward, the GOOD_STAMP checks ensure that the index stored in iter is nonnegative
- if (iter->stamp != GOOD_STAMP)
- return NULL; // this is what both GtkListStore and GtkTreeStore do
- return gtk_tree_path_new_from_indices(FROM(iter->user_data), -1);
-}
-
-static void goTableModel_get_value(GtkTreeModel *model, GtkTreeIter *iter, gint column, GValue *value)
-{
- goTableModel *t = (goTableModel *) model;
-
- if (iter->stamp != GOOD_STAMP)
- return; // this is what both GtkListStore and GtkTreeStore do
- goTableModel_do_get_value(t->gotable, FROM(iter->user_data), column, value);
-}
-
-static gboolean goTableModel_iter_next(GtkTreeModel *model, GtkTreeIter *iter)
-{
- goTableModel *t = (goTableModel *) model;
- gint index;
-
- if (iter->stamp != GOOD_STAMP)
- return FALSE; // this is what both GtkListStore and GtkTreeStore do
- index = FROM(iter->user_data);
- index++;
- if (index >= goTableModel_getRowCount(t->gotable)) {
- iter->stamp = BAD_STAMP;
- return FALSE;
- }
- iter->user_data = TO(index);
- return TRUE;
-}
-
-static gboolean goTableModel_iter_previous(GtkTreeModel *model, GtkTreeIter *iter)
-{
- goTableModel *t = (goTableModel *) model;
- gint index;
-
- if (iter->stamp != GOOD_STAMP)
- return FALSE; // this is what both GtkListStore and GtkTreeStore do
- index = FROM(iter->user_data);
- if (index <= 0) {
- iter->stamp = BAD_STAMP;
- return FALSE;
- }
- index--;
- iter->user_data = TO(index);
- return TRUE;
-}
-
-static gboolean goTableModel_iter_children(GtkTreeModel *model, GtkTreeIter *child, GtkTreeIter *parent)
-{
- goTableModel *t = (goTableModel *) model;
-
- if (parent == NULL && goTableModel_getRowCount(t->gotable) > 0) {
- child->stamp = GOOD_STAMP;
- child->user_data = 0;
- return TRUE;
- }
- child->stamp = BAD_STAMP;
- return FALSE;
-}
-
-static gboolean goTableModel_iter_has_child(GtkTreeModel *model, GtkTreeIter *iter)
-{
- return FALSE;
-}
-
-static gint goTableModel_iter_n_children(GtkTreeModel *model, GtkTreeIter *iter)
-{
- goTableModel *t = (goTableModel *) model;
-
- if (iter == NULL)
- return goTableModel_getRowCount(t->gotable);
- return 0;
-}
-
-static gboolean goTableModel_iter_nth_child(GtkTreeModel *model, GtkTreeIter *child, GtkTreeIter *parent, gint n)
-{
- goTableModel *t = (goTableModel *) model;
-
- if (parent == NULL && n >= 0 && n < goTableModel_getRowCount(t->gotable)) {
- child->stamp = GOOD_STAMP;
- child->user_data = TO(n);
- return TRUE;
- }
- child->stamp = BAD_STAMP;
- return FALSE;
-}
-
-static gboolean goTableModel_iter_parent(GtkTreeModel *model, GtkTreeIter *parent, GtkTreeIter *child)
-{
- parent->stamp = BAD_STAMP;
- return FALSE;
-}
-
-// end of interface definitions
-
-static void goTableModel_initGtkTreeModel(GtkTreeModelIface *interface)
-{
- // don't chain; we have nothing to chain to
-#define DEF(x) interface->x = goTableModel_ ## x;
- DEF(get_flags)
- DEF(get_n_columns)
- DEF(get_column_type)
- DEF(get_iter)
- DEF(get_path)
- DEF(get_value)
- DEF(iter_next)
- DEF(iter_previous)
- DEF(iter_children)
- DEF(iter_has_child)
- DEF(iter_n_children)
- DEF(iter_nth_child)
- DEF(iter_parent)
- // no need for ref_node and unref_node
-}
-
-static GParamSpec *goTableModelProperties[2];
-
-static void goTableModel_set_property(GObject *obj, guint id, const GValue *value, GParamSpec *pspec)
-{
- goTableModel *t = (goTableModel *) obj;
-
- if (id == 1) {
- t->gotable = (void *) g_value_get_pointer(value);
- return;
- }
- G_OBJECT_WARN_INVALID_PROPERTY_ID(t, id, pspec);
-}
-
-static void goTableModel_get_property(GObject *obj, guint id, GValue *value, GParamSpec *pspec)
-{
- G_OBJECT_WARN_INVALID_PROPERTY_ID((goTableModel *) obj, id, pspec);
-}
-
-static void goTableModel_class_init(goTableModelClass *class)
-{
- G_OBJECT_CLASS(class)->dispose = goTableModel_dispose;
- G_OBJECT_CLASS(class)->finalize = goTableModel_finalize;
- G_OBJECT_CLASS(class)->set_property = goTableModel_set_property;
- G_OBJECT_CLASS(class)->get_property = goTableModel_get_property;
-
- goTableModelProperties[1] = g_param_spec_pointer(
- "gotable",
- "go-table",
- "Go-side *table value",
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- g_object_class_install_properties(G_OBJECT_CLASS(class), 2, goTableModelProperties);
-}
-
-goTableModel *newTableModel(void *gotable)
-{
- return (goTableModel *) g_object_new(goTableModel_get_type(), "gotable", (gpointer) gotable, NULL);
-}
-
-// somewhat naive, but the only alternatives seem to be unloading/reloading the model (or the view!), which is bleh
-void tableUpdate(goTableModel *t, gint old, gint new)
-{
- gint i;
- gint nUpdate;
- GtkTreePath *path;
- GtkTreeIter iter;
-
- iter.stamp = GOOD_STAMP;
- // first, append extra items
- if (old < new) {
- for (i = old; i < new; i++) {
- path = gtk_tree_path_new_from_indices(i, -1);
- iter.user_data = TO(i);
- g_signal_emit_by_name(t, "row-inserted", path, &iter);
- }
- nUpdate = old;
- } else
- nUpdate = new;
- // next, update existing items
- for (i = 0; i < nUpdate; i++) {
- path = gtk_tree_path_new_from_indices(i, -1);
- iter.user_data = TO(i);
- g_signal_emit_by_name(t, "row-updated", path, &iter);
- }
- // finally, remove deleted items
- if (old > new)
- for (i = new; i < old; i++) {
- // note that we repeatedly remove the row at index new, as that changes with each removal; NOT i
- path = gtk_tree_path_new_from_indices(new, -1);
- // row-deleted has no iter
- g_signal_emit_by_name(t, "row-deleted", path);
- }
-}
diff --git a/redo/table_unix.go b/redo/table_unix.go
deleted file mode 100644
index 3566c87..0000000
--- a/redo/table_unix.go
+++ /dev/null
@@ -1,249 +0,0 @@
-// +build !windows,!darwin
-
-// 29 july 2014
-
-package ui
-
-import (
- "fmt"
- "reflect"
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern void goTableModel_toggled(GtkCellRendererToggle *, gchar *, gpointer);
-// extern void tableSelectionChanged(GtkTreeSelection *, gpointer);
-import "C"
-
-type table struct {
- *tablebase
-
- _widget *C.GtkWidget
- treeview *C.GtkTreeView
- scroller *scroller
-
- model *C.goTableModel
- modelgtk *C.GtkTreeModel
- selection *C.GtkTreeSelection
-
- pixbufs []*C.GdkPixbuf
-
- selected *event
-
- // stuff required by GtkTreeModel
- nColumns C.gint
- old C.gint
- types []C.GType
- crtocol map[*C.GtkCellRendererToggle]int
-}
-
-var (
- attribText = togstr("text")
- attribPixbuf = togstr("pixbuf")
- attribActive = togstr("active")
-)
-
-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(),
- }
- model := C.newTableModel(unsafe.Pointer(t))
- t.model = model
- t.modelgtk = (*C.GtkTreeModel)(unsafe.Pointer(model))
- t.selection = C.gtk_tree_view_get_selection(t.treeview)
- g_signal_connect(
- C.gpointer(unsafe.Pointer(t.selection)),
- "changed",
- C.GCallback(C.tableSelectionChanged),
- C.gpointer(unsafe.Pointer(t)))
- C.gtk_tree_view_set_model(t.treeview, t.modelgtk)
- for i := 0; i < ty.NumField(); i++ {
- cname := togstr(ty.Field(i).Name)
- switch {
- case ty.Field(i).Type == reflect.TypeOf(ImageIndex(0)):
- // can't use GDK_TYPE_PIXBUF here because it's a macro that expands to a function and cgo hates that
- t.types = append(t.types, C.gdk_pixbuf_get_type())
- C.tableAppendColumn(t.treeview, C.gint(i), cname,
- C.gtk_cell_renderer_pixbuf_new(), attribPixbuf)
- case ty.Field(i).Type.Kind() == reflect.Bool:
- t.types = append(t.types, C.G_TYPE_BOOLEAN)
- cr := C.gtk_cell_renderer_toggle_new()
- crt := (*C.GtkCellRendererToggle)(unsafe.Pointer(cr))
- t.crtocol[crt] = i
- g_signal_connect(C.gpointer(unsafe.Pointer(cr)),
- "toggled",
- C.GCallback(C.goTableModel_toggled),
- C.gpointer(unsafe.Pointer(t)))
- C.tableAppendColumn(t.treeview, C.gint(i), cname,
- cr, attribActive)
- default:
- t.types = append(t.types, C.G_TYPE_STRING)
- C.tableAppendColumn(t.treeview, C.gint(i), cname,
- C.gtk_cell_renderer_text_new(), attribText)
- }
- freegstr(cname) // free now (not deferred) to conserve memory
- }
- // and for some GtkTreeModel boilerplate
- t.nColumns = C.gint(ty.NumField())
- return t
-}
-
-func (t *table) Lock() {
- t.tablebase.Lock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- t.old = C.gint(d.Len())
-}
-
-func (t *table) Unlock() {
- t.unlock()
- // there's a possibility that user actions can happen at this point, before the view is updated
- // alas, this is something we have to deal with, because Unlock() can be called from any thread
- go func() {
- Do(func() {
- t.RLock()
- defer t.RUnlock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- new := C.gint(d.Len())
- C.tableUpdate(t.model, t.old, new)
- })
- }()
-}
-
-func (t *table) LoadImageList(i ImageList) {
- i.apply(&t.pixbufs)
-}
-
-func (t *table) Selected() int {
- var iter C.GtkTreeIter
-
- t.RLock()
- defer t.RUnlock()
- if C.gtk_tree_selection_get_selected(t.selection, nil, &iter) == C.FALSE {
- return -1
- }
- path := C.gtk_tree_model_get_path(t.modelgtk, &iter)
- if path == nil {
- panic(fmt.Errorf("invalid iter in Table.Selected()"))
- }
- defer C.gtk_tree_path_free(path)
- return int(*C.gtk_tree_path_get_indices(path))
-}
-
-func (t *table) Select(index int) {
- t.RLock()
- defer t.RUnlock()
- C.gtk_tree_selection_unselect_all(t.selection)
- if index == -1 {
- return
- }
- path := C.gtk_tree_path_new()
- defer C.gtk_tree_path_free(path)
- C.gtk_tree_path_append_index(path, C.gint(index))
- C.gtk_tree_selection_select_path(t.selection, path)
-}
-
-func (t *table) OnSelected(f func()) {
- t.selected.set(f)
-}
-
-//export goTableModel_get_n_columns
-func goTableModel_get_n_columns(model *C.GtkTreeModel) C.gint {
- tm := (*C.goTableModel)(unsafe.Pointer(model))
- t := (*table)(tm.gotable)
- return t.nColumns
-}
-
-//export goTableModel_get_column_type
-func goTableModel_get_column_type(model *C.GtkTreeModel, column C.gint) C.GType {
- tm := (*C.goTableModel)(unsafe.Pointer(model))
- t := (*table)(tm.gotable)
- return t.types[column]
-}
-
-//export goTableModel_do_get_value
-func goTableModel_do_get_value(data unsafe.Pointer, row C.gint, col C.gint, value *C.GValue) {
- t := (*table)(data)
- t.RLock()
- defer t.RUnlock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- datum := d.Index(int(row)).Field(int(col))
- switch {
- case datum.Type() == reflect.TypeOf(ImageIndex(0)):
- d := datum.Interface().(ImageIndex)
- C.g_value_init(value, C.gdk_pixbuf_get_type())
- C.g_value_set_object(value, C.gpointer(unsafe.Pointer(t.pixbufs[d])))
- case datum.Kind() == reflect.Bool:
- d := datum.Interface().(bool)
- C.g_value_init(value, C.G_TYPE_BOOLEAN)
- C.g_value_set_boolean(value, togbool(d))
- default:
- s := fmt.Sprintf("%v", datum)
- str := togstr(s)
- defer freegstr(str)
- C.g_value_init(value, C.G_TYPE_STRING)
- C.g_value_set_string(value, str)
- }
-}
-
-//export goTableModel_getRowCount
-func goTableModel_getRowCount(data unsafe.Pointer) C.gint {
- t := (*table)(data)
- t.RLock()
- defer t.RUnlock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- return C.gint(d.Len())
-}
-
-//export goTableModel_toggled
-func goTableModel_toggled(cr *C.GtkCellRendererToggle, pathstr *C.gchar, data C.gpointer) {
- t := (*table)(unsafe.Pointer(data))
- t.Lock()
- defer t.Unlock()
- path := C.gtk_tree_path_new_from_string(pathstr)
- if len := C.gtk_tree_path_get_depth(path); len != 1 {
- panic(fmt.Errorf("invalid path of depth %d given to goTableModel_toggled()", len))
- }
- // dereference return value to get our sole member
- row := *C.gtk_tree_path_get_indices(path)
- col := t.crtocol[cr]
- d := reflect.Indirect(reflect.ValueOf(t.data))
- datum := d.Index(int(row)).Field(int(col))
- datum.SetBool(!datum.Bool())
-}
-
-//export tableSelectionChanged
-func tableSelectionChanged(sel *C.GtkTreeSelection, data C.gpointer) {
- t := (*table)(unsafe.Pointer(data))
- t.selected.fire()
-}
-
-func (t *table) widget() *C.GtkWidget {
- return t._widget
-}
-
-func (t *table) setParent(p *controlParent) {
- t.scroller.setParent(p)
-}
-
-func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *table) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(t, d)
-}
-
-func (t *table) commitResize(c *allocation, d *sizing) {
- t.scroller.commitResize(c, d)
-}
-
-func (t *table) getAuxResizeInfo(d *sizing) {
- // a Label to the left of a Table should be vertically aligned to the top
- d.shouldVAlignTop = true
-}
diff --git a/redo/table_windows.c b/redo/table_windows.c
deleted file mode 100644
index 2c956f5..0000000
--- a/redo/table_windows.c
+++ /dev/null
@@ -1,195 +0,0 @@
-// 28 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-// provided for cgo's benefit
-LPWSTR xWC_LISTVIEW = WC_LISTVIEW;
-
-static void handle(HWND hwnd, LPARAM lParam, void (*handler)(void *, int, int), void *data)
-{
- LVHITTESTINFO ht;
-
- ZeroMemory(&ht, sizeof (LVHITTESTINFO));
- ht.pt.x = GET_X_LPARAM(lParam);
- ht.pt.y = GET_Y_LPARAM(lParam);
- if (SendMessageW(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM) (&ht)) == (LRESULT) -1) {
- (*handler)(data, -1, -1);
- return; // no item
- }
- if (ht.flags != LVHT_ONITEMSTATEICON) {
- (*handler)(data, -1, -1);
- return; // not on a checkbox
- }
- (*handler)(data, ht.iItem, ht.iSubItem);
-}
-
-struct tableData {
- void *gotable;
- HIMAGELIST imagelist;
- HTHEME theme;
- HIMAGELIST checkboxImageList;
-};
-
-static void tableLoadImageList(HWND hwnd, struct tableData *t, HIMAGELIST new)
-{
- HIMAGELIST old;
-
- old = t->imagelist;
- t->imagelist = new;
- applyImageList(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, t->imagelist, old);
-}
-
-static void tableSetCheckboxImageList(HWND hwnd, struct tableData *t)
-{
- HIMAGELIST old;
-
- old = t->checkboxImageList;
- t->checkboxImageList = makeCheckboxImageList(hwnd, &t->theme);
- applyImageList(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, t->checkboxImageList, old);
- // thanks to Jonathan Potter (http://stackoverflow.com/questions/25354448/why-do-my-owner-data-list-view-state-images-come-up-as-blank-on-windows-xp)
- if (SendMessageW(hwnd, LVM_SETCALLBACKMASK, LVIS_STATEIMAGEMASK, 0) == FALSE)
- xpanic("error marking state image list as application-managed", GetLastError());
-}
-
-static LRESULT CALLBACK tableSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
-{
- NMHDR *nmhdr = (NMHDR *) lParam;
- NMLVDISPINFOW *fill = (NMLVDISPINFO *) lParam;
- NMLISTVIEW *nlv = (NMLISTVIEW *) lParam;
- struct tableData *t = (struct tableData *) data;
-
- switch (uMsg) {
- case msgNOTIFY:
- switch (nmhdr->code) {
- case LVN_GETDISPINFO:
- tableGetCell(t->gotable, &(fill->item));
- return 0;
- case LVN_ITEMCHANGED:
- if ((nlv->uChanged & LVIF_STATE) == 0)
- break;
- // if both old and new states have the same value for the selected bit, then the selection state did not change, regardless of selected or deselected
- if ((nlv->uOldState & LVIS_SELECTED) == (nlv->uNewState & LVIS_SELECTED))
- break;
- tableSelectionChanged(t->gotable);
- return 0;
- }
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_MOUSEMOVE:
- handle(hwnd, lParam, tableSetHot, t->gotable);
- // and let the list view do its thing
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_LBUTTONDOWN:
- case WM_LBUTTONDBLCLK: // listviews have CS_DBLCICKS; check this to better mimic the behavior of a real checkbox
- handle(hwnd, lParam, tablePushed, t->gotable);
- // and let the list view do its thing
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_LBUTTONUP:
- handle(hwnd, lParam, tableToggled, t->gotable);
- // and let the list view do its thing
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case msgLoadImageList:
- tableLoadImageList(hwnd, t, (HIMAGELIST) lParam);
- return 0;
- case msgTableMakeInitialCheckboxImageList:
- tableSetCheckboxImageList(hwnd, t);
- return 0;
- case WM_THEMECHANGED:
- tableSetCheckboxImageList(hwnd, t);
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- // see table.autoresize() in table_windows.go for the column autosize policy
- case WM_NOTIFY: // from the contained header control
- if (nmhdr->code == HDN_BEGINTRACK)
- tableStopColumnAutosize(t->gotable);
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- case WM_NCDESTROY:
- free(t);
- if ((*fv_RemoveWindowSubclass)(hwnd, tableSubProc, id) == FALSE)
- xpanic("error removing Table subclass (which was for its own event handler)", GetLastError());
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- default:
- return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("Button", "tableSubProc()", uMsg);
- return 0; // unreached
-}
-
-void setTableSubclass(HWND hwnd, void *data)
-{
- struct tableData *t;
-
- t = (struct tableData *) malloc(sizeof (struct tableData));
- if (t == NULL)
- xpanic("error allocating structure for Table extra data", GetLastError());
- ZeroMemory(t, sizeof (struct tableData));
- t->gotable = data;
- if ((*fv_SetWindowSubclass)(hwnd, tableSubProc, 0, (DWORD_PTR) t) == FALSE)
- xpanic("error subclassing Table to give it its own event handler", GetLastError());
-}
-
-void tableAppendColumn(HWND hwnd, int index, LPWSTR name)
-{
- LVCOLUMNW col;
-
- ZeroMemory(&col, sizeof (LVCOLUMNW));
- col.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
- col.fmt = LVCFMT_LEFT;
- col.pszText = name;
- col.iSubItem = index;
- col.iOrder = index;
- if (SendMessageW(hwnd, LVM_INSERTCOLUMN, (WPARAM) index, (LPARAM) (&col)) == (LRESULT) -1)
- xpanic("error adding column to Table", GetLastError());
-}
-
-void tableUpdate(HWND hwnd, int nItems)
-{
- if (SendMessageW(hwnd, LVM_SETITEMCOUNT, (WPARAM) nItems, 0) == 0)
- xpanic("error setting number of items in Table", GetLastError());
-}
-
-void tableAddExtendedStyles(HWND hwnd, LPARAM styles)
-{
- // the bits of WPARAM specify which bits of LPARAM to look for; having WPARAM == LPARAM ensures that only the bits we want to add are affected
- SendMessageW(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, (WPARAM) styles, styles);
-}
-
-void tableAutosizeColumns(HWND hwnd, int nColumns)
-{
- int i;
-
- for (i = 0; i < nColumns; i++)
- if (SendMessageW(hwnd, LVM_SETCOLUMNWIDTH, (WPARAM) i, (LPARAM) LVSCW_AUTOSIZE_USEHEADER) == FALSE)
- xpanic("error resizing columns of results list view", GetLastError());
-}
-
-// because Go won't let me do C.WPARAM(-1)
-intptr_t tableSelectedItem(HWND hwnd)
-{
- return (intptr_t) SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM) -1, LVNI_SELECTED);
-}
-
-void tableSelectItem(HWND hwnd, intptr_t index)
-{
- LVITEMW item;
- LRESULT current;
-
- // via http://support.microsoft.com/kb/131284
- // we don't need to clear the other bits; Tables don't support cutting or drag/drop
- current = SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM) -1, LVNI_SELECTED);
- if (current != (LRESULT) -1) {
- ZeroMemory(&item, sizeof (LVITEMW));
- item.mask = LVIF_STATE;
- item.state = 0;
- item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
- if (SendMessageW(hwnd, LVM_SETITEMSTATE, (WPARAM) current, (LPARAM) (&item)) == FALSE)
- xpanic("error deselecting current Table item", GetLastError());
- }
- if (index == -1) // select nothing
- return;
- ZeroMemory(&item, sizeof (LVITEMW));
- item.mask = LVIF_STATE;
- item.state = LVIS_FOCUSED | LVIS_SELECTED;
- item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
- if (SendMessageW(hwnd, LVM_SETITEMSTATE, (WPARAM) index, (LPARAM) (&item)) == FALSE)
- xpanic("error selecting new Table item", GetLastError());
-}
diff --git a/redo/table_windows.go b/redo/table_windows.go
deleted file mode 100644
index 21d681d..0000000
--- a/redo/table_windows.go
+++ /dev/null
@@ -1,262 +0,0 @@
-// 28 july 2014
-
-package ui
-
-import (
- "fmt"
- "unsafe"
- "reflect"
-)
-
-// #include "winapi_windows.h"
-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
-}
-
-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(),
- }
- 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)
- // 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++ {
- C.tableAppendColumn(t._hwnd, C.int(i), toUTF16(ty.Field(i).Name))
- }
- t.colcount = C.int(ty.NumField())
- return t
-}
-
-func (t *table) Unlock() {
- t.unlock()
- // there's a possibility that user actions can happen at this point, before the view is updated
- // alas, this is something we have to deal with, because Unlock() can be called from any thread
- go func() {
- Do(func() {
- t.RLock()
- defer t.RUnlock()
- C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
- })
- }()
-}
-
-func (t *table) LoadImageList(il ImageList) {
- il.apply(t._hwnd, C.msgLoadImageList)
-}
-
-func (t *table) Selected() int {
- t.RLock()
- defer t.RUnlock()
- return int(C.tableSelectedItem(t._hwnd))
-}
-
-func (t *table) Select(index int) {
- t.RLock()
- defer t.RUnlock()
- C.tableSelectItem(t._hwnd, C.intptr_t(index))
-}
-
-func (t *table) OnSelected(f func()) {
- t.selected.set(f)
-}
-
-func printMask(item *C.LVITEMW) {
-fmt.Printf("%d %d ", item.iItem, item.iSubItem)
-x := item.mask
-if x&C.LVIF_COLUMNS != 0{ fmt.Print("LVIF_COLUMNS ") }
-if x&C.LVIF_DI_SETITEM != 0{ fmt.Print("LVIF_DI_SETITEM ") }
-if x&C.LVIF_GROUPID != 0{ fmt.Print("LVIF_GROUPID ") }
-if x&C.LVIF_IMAGE != 0{ fmt.Print("LVIF_IMAGE ") }
-if x&C.LVIF_INDENT != 0{ fmt.Print("LVIF_INDENT ") }
-if x&C.LVIF_NORECOMPUTE != 0{ fmt.Print("LVIF_NORECOMPUTE ") }
-if x&C.LVIF_PARAM != 0{ fmt.Print("LVIF_PARAM ") }
-if x&C.LVIF_STATE != 0{ fmt.Print("LVIF_STATE ") }
-if x&C.LVIF_TEXT != 0{ fmt.Print("LVIF_TEXT ") }
-fmt.Print("\n")
-}
-
-//export tableGetCell
-func tableGetCell(data unsafe.Pointer, item *C.LVITEMW) {
- t := (*table)(data)
- t.RLock()
- defer t.RUnlock()
- d := reflect.Indirect(reflect.ValueOf(t.data))
- datum := d.Index(int(item.iItem)).Field(int(item.iSubItem))
-printMask(item)
- isText := true
- 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 {
- // always have an indent of zero
- item.iIndent = 0
- }
- if item.mask & C.LVIF_STATE != 0 {
- // start by not changing any state
- item.stateMask = 0
- if datum.Kind() == reflect.Bool {
- item.stateMask = C.LVIS_STATEIMAGEMASK
- // state image index is 1-based
- curstate := ((item.state & C.LVIS_STATEIMAGEMASK) >> 12)
- if curstate > 0 {
- curstate--
- }
- if datum.Bool() == true {
- curstate |= C.checkboxStateChecked
- } else {
- curstate &^= C.checkboxStateChecked
- }
- if item.iItem == t.hotrow && item.iSubItem == t.hotcol {
- curstate |= C.checkboxStateHot
- } else {
- curstate &^= C.checkboxStateHot
- }
- if item.iItem == t.pushedrow && item.iSubItem == t.pushedcol {
- curstate |= C.checkboxStatePushed
- } else {
- curstate &^= C.checkboxStatePushed
- }
- item.state = (curstate + 1) << 12
- isText = false
- }
- }
- if item.mask & C.LVIF_TEXT != 0 {
- if isText {
- s := fmt.Sprintf("%v", datum)
- item.pszText = toUTF16(s)
- }
- // else let the default handler work
- }
-}
-
-// the column autoresize policy is simple:
-// on every table.commitResize() call, if the columns have not been resized by the user, autoresize
-func (t *table) autoresize() {
- t.RLock()
- defer t.RUnlock()
- if !t.noautosize {
- C.tableAutosizeColumns(t._hwnd, t.colcount)
- }
-}
-
-//export tableStopColumnAutosize
-func tableStopColumnAutosize(data unsafe.Pointer) {
- t := (*table)(data)
- t.noautosize = true
-}
-
-//export tableColumnCount
-func tableColumnCount(data unsafe.Pointer) C.int {
- t := (*table)(data)
- return t.colcount
-}
-
-//export tableSetHot
-func tableSetHot(data unsafe.Pointer, row C.int, col C.int) {
- t := (*table)(data)
- redraw := (row != t.hotrow || col != t.hotcol)
- t.hotrow = row
- t.hotcol = col
- if redraw {
- C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
- }
-}
-
-//export tablePushed
-func tablePushed(data unsafe.Pointer, row C.int, col C.int) {
- t := (*table)(data)
- t.pushedrow = row
- t.pushedcol = col
- C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
-}
-
-//export tableToggled
-func tableToggled(data unsafe.Pointer, row C.int, col C.int) {
- t := (*table)(data)
- t.Lock()
- defer func() {
- // reset for next time
- t.pushedrow = -1
- t.pushedcol = -1
- // and THEN unlock so the reset takes effect
- t.Unlock()
- }()
- 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
- return
- }
- d := reflect.Indirect(reflect.ValueOf(t.data))
- datum := d.Index(int(row)).Field(int(col))
- if datum.Kind() == reflect.Bool {
- datum.SetBool(!datum.Bool())
- return
- }
- panic(fmt.Errorf("tableSetHot() on non-checkbox at (%d, %d)", row, col))
-}
-
-//export tableSelectionChanged
-func tableSelectionChanged(data unsafe.Pointer) {
- t := (*table)(data)
- t.selected.fire()
-}
-
-func (t *table) hwnd() C.HWND {
- return t._hwnd
-}
-
-func (t *table) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-const (
- // 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
- tableHeight = 50
-)
-
-func (t *table) preferredSize(d *sizing) (width, height int) {
- return fromdlgunitsX(tableWidth, d), fromdlgunitsY(tableHeight, d)
-}
-
-func (t *table) commitResize(a *allocation, d *sizing) {
- basecommitResize(t, a, d)
- t.RLock()
- defer t.RUnlock()
- t.autoresize()
-}
-
-func (t *table) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/textfield_darwin.go b/redo/textfield_darwin.go
deleted file mode 100644
index 5c52a38..0000000
--- a/redo/textfield_darwin.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// 16 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type textfield struct {
- _id C.id
- changed *event
- invalid C.id
-}
-
-func finishNewTextField(id C.id) *textfield {
- t := &textfield{
- _id: id,
- changed: newEvent(),
- }
- C.textfieldSetDelegate(t._id, unsafe.Pointer(t))
- return t
-}
-
-func newTextField() *textfield {
- return finishNewTextField(C.newTextField())
-}
-
-func newPasswordField() *textfield {
- return finishNewTextField(C.newPasswordField())
-}
-
-func (t *textfield) Text() string {
- return C.GoString(C.textfieldText(t._id))
-}
-
-func (t *textfield) SetText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.textfieldSetText(t._id, ctext)
-}
-
-func (t *textfield) OnChanged(f func()) {
- t.changed.set(f)
-}
-
-func (t *textfield) Invalid(reason string) {
- if t.invalid != nil {
- C.textfieldCloseInvalidPopover(t.invalid)
- t.invalid = nil
- }
- if reason == "" {
- return
- }
- creason := C.CString(reason)
- defer C.free(unsafe.Pointer(creason))
- t.invalid = C.textfieldOpenInvalidPopover(t._id, creason)
-}
-
-//export textfieldChanged
-func textfieldChanged(data unsafe.Pointer) {
- t := (*textfield)(data)
-println("changed")
- t.changed.fire()
-}
-
-func (t *textfield) id() C.id {
- return t._id
-}
-
-func (t *textfield) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *textfield) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *textfield) preferredSize(d *sizing) (width, height int) {
- _, height = basepreferredSize(t, d)
- // the returned width is based on the contents; use this instead
- return C.textfieldWidth, height
-}
-
-func (t *textfield) commitResize(a *allocation, d *sizing) {
- basecommitResize(t, a, d)
-}
-
-func (t *textfield) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/textfield_unix.go b/redo/textfield_unix.go
deleted file mode 100644
index b06da02..0000000
--- a/redo/textfield_unix.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern void textfieldChanged(GtkEditable *, gpointer);
-// /* because cgo doesn't like GTK_STOCK_DIALOG_ERROR */
-// static inline void setErrorIcon(GtkEntry *entry)
-// {
-// gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR);
-// }
-import "C"
-
-type textfield struct {
- _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(),
- }
- g_signal_connect(
- C.gpointer(unsafe.Pointer(t._widget)),
- "changed",
- C.GCallback(C.textfieldChanged),
- C.gpointer(unsafe.Pointer(t)))
- return t
-}
-
-func newTextField() *textfield {
- return startNewTextField()
-}
-
-func newPasswordField() *textfield {
- t := startNewTextField()
- C.gtk_entry_set_visibility(t.entry, C.FALSE)
- return t
-}
-
-func (t *textfield) Text() string {
- return fromgstr(C.gtk_entry_get_text(t.entry))
-}
-
-func (t *textfield) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_entry_set_text(t.entry, ctext)
-}
-
-func (t *textfield) OnChanged(f func()) {
- t.changed.set(f)
-}
-
-func (t *textfield) Invalid(reason string) {
- if reason == "" {
- C.gtk_entry_set_icon_from_stock(t.entry, C.GTK_ENTRY_ICON_SECONDARY, nil)
- return
- }
- C.setErrorIcon(t.entry)
- creason := togstr(reason)
- defer freegstr(creason)
- C.gtk_entry_set_icon_tooltip_text(t.entry, C.GTK_ENTRY_ICON_SECONDARY, creason)
- C.gtk_widget_error_bell(t._widget)
-}
-
-//export textfieldChanged
-func textfieldChanged(editable *C.GtkEditable, data C.gpointer) {
- t := (*textfield)(unsafe.Pointer(data))
-println("changed")
- t.changed.fire()
-}
-
-func (t *textfield) widget() *C.GtkWidget {
- return t._widget
-}
-
-func (t *textfield) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *textfield) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-func (t *textfield) preferredSize(d *sizing) (width, height int) {
- return basepreferredSize(t, d)
-}
-
-func (t *textfield) commitResize(a *allocation, d *sizing) {
- basecommitResize(t, a, d)
-}
-
-func (t *textfield) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/textfield_windows.go b/redo/textfield_windows.go
deleted file mode 100644
index 236be97..0000000
--- a/redo/textfield_windows.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// 15 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type textfield struct {
- _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)
- t := &textfield{
- _hwnd: hwnd,
- changed: newEvent(),
- }
- C.controlSetControlFont(t._hwnd)
- C.setTextFieldSubclass(t._hwnd, unsafe.Pointer(t))
- return t
-}
-
-func newTextField() *textfield {
- return startNewTextField(0)
-}
-
-func newPasswordField() *textfield {
- return startNewTextField(C.ES_PASSWORD)
-}
-
-func (t *textfield) Text() string {
- return baseText(t)
-}
-
-func (t *textfield) SetText(text string) {
- baseSetText(t, text)
-}
-
-func (t *textfield) OnChanged(f func()) {
- t.changed.set(f)
-}
-
-func (t *textfield) Invalid(reason string) {
- if reason == "" {
- C.textfieldHideInvalidBalloonTip(t._hwnd)
- return
- }
- C.textfieldSetAndShowInvalidBalloonTip(t._hwnd, toUTF16(reason))
-}
-
-//export textfieldChanged
-func textfieldChanged(data unsafe.Pointer) {
- t := (*textfield)(data)
-println("changed")
- t.changed.fire()
-}
-
-func (t *textfield) hwnd() C.HWND {
- return t._hwnd
-}
-
-func (t *textfield) textlen() C.LONG {
- return t._textlen
-}
-
-func (t *textfield) settextlen(len C.LONG) {
- t._textlen = len
-}
-
-func (t *textfield) setParent(p *controlParent) {
- basesetParent(t, p)
-}
-
-func (t *textfield) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return baseallocate(t, x, y, width, height, d)
-}
-
-const (
- // 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
- textfieldHeight = 14
-)
-
-func (t *textfield) preferredSize(d *sizing) (width, height int) {
- return fromdlgunitsX(textfieldWidth, d), fromdlgunitsY(textfieldHeight, d)
-}
-
-func (t *textfield) commitResize(a *allocation, d *sizing) {
- basecommitResize(t, a, d)
-}
-
-func (t *textfield) getAuxResizeInfo(d *sizing) {
- basegetAuxResizeInfo(t, d)
-}
diff --git a/redo/uitask.go b/redo/uitask.go
deleted file mode 100644
index 3193f4e..0000000
--- a/redo/uitask.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// 6 july 2014
-
-package ui
-
-import (
- "runtime"
- "sync"
- "unsafe"
- "reflect"
-)
-
-// Go initializes and runs package ui.
-// It returns a non-nil error if initialization fails.
-// Otherwise, it will run the event loop and not return until Stop is called.
-// Due to platform-specific issues, it must be called from the main OS thread; in general, do not call Go() from anywhere except main() (including any goroutines).
-func Go() error {
- runtime.LockOSThread()
- if err := uiinit(); err != nil {
- return err
- }
- go uiissueloop()
- uimsgloop()
- return nil
-}
-
-// To ensure that Do() and Stop() only do things after Go() has been called, this channel accepts the requests to issue. The issuing is done by uiissueloop() below.
-// Notice that this is a pointer ot a function. See Do() below for details.
-var issuer = make(chan *func())
-
-// Do performs f on the main loop, as if it were an event handler.
-// It waits for f to execute before returning.
-// Do cannot be called within event handlers or within Do itself.
-func Do(f func()) {
- done := make(chan struct{})
- defer close(done)
- // THIS MUST BE A POINTER.
- // Previously, the pointer was constructed within issue().
- // This meant that if the Do() was stalled, the garbage collector came in and reused the pointer value too soon!
- call := func() {
- f()
- done <- struct{}{}
- }
- issuer <- &call
- <-done
-}
-
-// Stop informs package ui that it should stop.
-// Stop then returns immediately.
-// Some time after this request is received, Go() will return without performing any final cleanup.
-// Stop will not have an effect until any event handlers return.
-func Stop() {
- // can't send this directly across issuer
- go func() {
- Do(uistop)
- }()
-}
-
-func uiissueloop() {
- for f := range issuer {
- issue(f)
- }
-}
-
-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
-}
-
-func newEvent() *event {
- return &event{
- do: func() bool {
- return false
- },
- }
-}
-
-func (e *event) set(f func()) {
- e.lock.Lock()
- defer e.lock.Unlock()
-
- if f == nil {
- f = func() {}
- }
- e.do = func() bool {
- f()
- return false
- }
-}
-
-func (e *event) setbool(f func() bool) {
- e.lock.Lock()
- defer e.lock.Unlock()
-
- if f == nil {
- f = func() bool {
- return false
- }
- }
- e.do = f
-}
-
-// This is the common code for running an event.
-// It runs on the main thread without a message pump; it provides its own.
-func (e *event) fire() bool {
- e.lock.Lock()
- defer e.lock.Unlock()
-
- return e.do()
-}
-
-// Common code for performing a requested action (ui.Do() or ui.Stop()).
-// This should run on the main thread.
-// Implementations of issue() should call this.
-func perform(fp unsafe.Pointer) {
- f := (*func())(fp)
- (*f)()
-}
-
-// 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{}
-}
-
-// NewForeignEvent creates a new ForeignEvent with the specified channel.
-// It panics if the argument is not a receivable channel.
-// The returned ForeignEvent assumes ownership of the channel.
-// Each time a value is received on the channel, the returned function is invoked on the main thread.
-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 {
- panic("non-channel or non-receivable channel passed to NewForeignEvent()")
- }
- fe := &ForeignEvent{
- c: c,
- e: newEvent(),
- }
- fe.e.set(func() {
- handler(fe.d)
- })
- go fe.do()
- return fe
-}
-
-func (fe *ForeignEvent) do() {
- for {
- v, ok := fe.c.Recv()
- if !ok {
- break
- }
- fe.d = v.Interface()
- Do(func() {
- fe.e.fire()
- })
- }
-}
-
-// Stop ceases all future invocations of the handler passed to NewForeignEvent() on fe; the values read from the channel are merely discarded.
-func (fe *ForeignEvent) Stop() {
- fe.e.set(nil)
-}
diff --git a/redo/uitask_darwin.go b/redo/uitask_darwin.go
deleted file mode 100644
index 13de8e0..0000000
--- a/redo/uitask_darwin.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// 8 july 2014
-
-package ui
-
-import (
- "fmt"
- "unsafe"
-)
-
-// #cgo CFLAGS: -mmacosx-version-min=10.7 -DMACOSX_DEPLOYMENT_TARGET=10.7
-// #cgo LDFLAGS: -mmacosx-version-min=10.7 -lobjc -framework Foundation -framework AppKit
-// #include "objc_darwin.h"
-import "C"
-
-func uiinit() error {
- var errmsg *C.char
-
- errmsg = nil
- C.uiinit(&errmsg)
- if errmsg != nil {
- return fmt.Errorf("package ui initialization failed: %s", C.GoString(errmsg))
- }
- return nil
-}
-
-func uimsgloop() {
- C.uimsgloop()
-}
-
-func uistop() {
- C.uistop()
-}
-
-func issue(f *func()) {
- C.issue(unsafe.Pointer(f))
-}
-
-//export doissue
-func doissue(fp unsafe.Pointer) {
- perform(fp)
-}
diff --git a/redo/uitask_darwin.m b/redo/uitask_darwin.m
deleted file mode 100644
index e69882a..0000000
--- a/redo/uitask_darwin.m
+++ /dev/null
@@ -1,138 +0,0 @@
-// 8 july 2014
-
-#import "objc_darwin.h"
-#import "_cgo_export.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSWindow(x) ((NSWindow *) (x))
-
-static Class areaClass;
-
-@interface goApplication : NSApplication
-@end
-
-@implementation goApplication
-
-// by default, NSApplication eats some key events
-// this prevents that from happening with Area
-// see http://stackoverflow.com/questions/24099063/how-do-i-detect-keyup-in-my-nsview-with-the-command-key-held and http://lists.apple.com/archives/cocoa-dev/2003/Oct/msg00442.html
-- (void)sendEvent:(NSEvent *)e
-{
- NSEventType type;
- BOOL handled = NO;
-
- type = [e type];
- if (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged) {
- id focused;
-
- focused = [[e window] firstResponder];
- if (focused != nil && [focused isKindOfClass:areaClass])
- switch (type) {
- case NSKeyDown:
- handled = [focused doKeyDown:e];
- break;
- case NSKeyUp:
- handled = [focused doKeyUp:e];
- break;
- case NSFlagsChanged:
- handled = [focused doFlagsChanged:e];
- break;
- }
- }
- if (!handled)
- [super sendEvent:e];
-}
-
-// ok AppKit, wanna play hardball? let's play hardball.
-// because I can neither break out of the special version of the NSModalPanelRunLoopMode that the regular terminate: puts us in nor avoid the exit(0); call included, I'm taking control
-// note that this is called AFTER applicationShouldTerminate:
-- (void)terminate:(id)sender
-{
- // DO ABSOLUTELY NOTHING
- // the magic is [NSApp run] will just... stop.
-}
-
-@end
-
-@interface appDelegateClass : NSObject <NSApplicationDelegate>
-@end
-
-@implementation appDelegateClass
-
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app
-{
- NSArray *windows;
- NSUInteger i, n;
-
- windows = [NSApp windows];
- n = [windows count];
- for (i = 0; i < n; i++) {
- NSWindow *w;
-
- w = toNSWindow([windows objectAtIndex:i]);
- if (![[w delegate] windowShouldClose:w])
- // stop at the first rejection; thanks Lyle42 in irc.freenode.net/#macdev
- return NSTerminateCancel;
- }
- // all windows closed; stop gracefully for Go
- // note that this is designed for our special terminate: above
- return NSTerminateNow;
-}
-
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
-{
- return NO;
-}
-
-@end
-
-appDelegateClass *appDelegate;
-
-id getAppDelegate(void)
-{
- return appDelegate;
-}
-
-void uiinit(char **errmsg)
-{
- areaClass = getAreaClass();
- appDelegate = [appDelegateClass new];
- [goApplication sharedApplication];
- // don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy!
- // see https://github.com/andlabs/ui/issues/6
- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
- [NSApp setDelegate:appDelegate];
-}
-
-void uimsgloop(void)
-{
- [NSApp run];
-// NSLog(@"you shouldn't see this under normal circumstances, but screw the rules, I have SUBCLASSING");
-}
-
-// don't use [NSApp terminate:]; that quits the program
-void uistop(void)
-{
- NSEvent *e;
-
- [NSApp stop:NSApp];
- // stop: won't register until another event has passed; let's synthesize one
- e = [NSEvent otherEventWithType:NSApplicationDefined
- location:NSZeroPoint
- modifierFlags:0
- timestamp:[[NSProcessInfo processInfo] systemUptime]
- windowNumber:0
- context:[NSGraphicsContext currentContext]
- subtype:0
- data1:0
- data2:0];
- [NSApp postEvent:e atStart:NO]; // let pending events take priority
-}
-
-// thanks to mikeash in irc.freenode.net/#macdev for suggesting the use of Grand Central Dispatch and blocks for this
-void issue(void *what)
-{
- dispatch_async(dispatch_get_main_queue(), ^{
- doissue(what);
- });
-}
diff --git a/redo/uitask_unix.go b/redo/uitask_unix.go
deleted file mode 100644
index 4a3e4b8..0000000
--- a/redo/uitask_unix.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "fmt"
- "unsafe"
-)
-
-// #cgo pkg-config: gtk+-3.0
-// #cgo CFLAGS: --std=c99
-// #include "gtk_unix.h"
-// extern gboolean xdoissue(gpointer data);
-import "C"
-
-func uiinit() error {
- 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+)
- result := C.gtk_init_with_args(nil, nil, nil, nil, nil, &err)
- if result == C.FALSE {
- return fmt.Errorf("error actually initilaizing GTK+: %s", fromgstr(err.message))
- }
- return nil
-}
-
-func uimsgloop() {
- C.gtk_main()
-}
-
-func uistop() {
- C.gtk_main_quit()
-}
-
-func issue(f *func()) {
- C.gdk_threads_add_idle(C.GSourceFunc(C.xdoissue), C.gpointer(unsafe.Pointer(f)))
-}
-
-//export xdoissue
-func xdoissue(data C.gpointer) C.gboolean {
- perform(unsafe.Pointer(data))
- return C.FALSE // don't repeat
-}
-
-//export doissue
-func doissue(data unsafe.Pointer) {
- // for the modal queue functions
- perform(data)
-}
diff --git a/redo/uitask_windows.c b/redo/uitask_windows.c
deleted file mode 100644
index dec6ed2..0000000
--- a/redo/uitask_windows.c
+++ /dev/null
@@ -1,167 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-// note that this includes the terminating '\0'
-// this also assumes WC_TABCONTROL is longer than areaWindowClass
-#define NCLASSNAME (sizeof WC_TABCONTROL / sizeof WC_TABCONTROL[0])
-
-void uimsgloop_area(HWND active, HWND focus, MSG *msg)
-{
- MSG copy;
-
- copy = *msg;
- switch (copy.message) {
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN: // Alt+[anything] and F10 send these instead
- copy.message = msgAreaKeyDown;
- break;
- case WM_KEYUP:
- case WM_SYSKEYUP:
- copy.message = msgAreaKeyUp;
- break;
- default:
- goto notkey;
- }
- // if we handled the key, don't do the default behavior
- // don't call TranslateMessage(); we do our own keyboard handling
- if (DispatchMessage(&copy) != FALSE)
- return;
-notkey:
- if (IsDialogMessage(active, msg) != 0)
- return;
- DispatchMessage(msg);
-}
-
-void uimsgloop_tab(HWND active, HWND focus, MSG *msg)
-{
- BOOL hasChildren;
- BOOL idm;
-
- // THIS BIT IS IMPORTANT: if the current tab has no children, then there will be no children left in the dialog to tab to, and IsDialogMessageW() will loop forever
- hasChildren = SendMessageW(focus, msgTabCurrentTabHasChildren, 0, 0);
- if (hasChildren)
- tabEnterChildren(focus);
- idm = IsDialogMessageW(active, msg);
- if (hasChildren)
- tabLeaveChildren(focus);
- if (idm != 0)
- return;
- TranslateMessage(msg);
- DispatchMessage(msg);
-}
-
-void uimsgloop_else(MSG *msg)
-{
- TranslateMessage(msg);
- DispatchMessage(msg);
-}
-
-void uimsgloop(void)
-{
- MSG msg;
- int res;
- HWND active, focus;
- WCHAR classchk[NCLASSNAME];
- BOOL dodlgmessage;
-
- for (;;) {
- SetLastError(0);
- res = GetMessageW(&msg, NULL, 0, 0);
- if (res < 0)
- xpanic("error calling GetMessage()", GetLastError());
- if (res == 0) // WM_QUIT
- break;
- active = GetActiveWindow();
- if (active == NULL) {
- uimsgloop_else(&msg);
- continue;
- }
-
- // bit of logic involved here:
- // we don't want dialog messages passed into Areas, so we don't call IsDialogMessageW() there
- // as for Tabs, we can't have both WS_TABSTOP and WS_EX_CONTROLPARENT set at the same time, so we hotswap the two styles to get the behavior we want
- // theoretically we could use the class atom to avoid a wcscmp()
- // however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything)
- // we could also theoretically just send msgAreaDefocuses directly, but what DefWindowProc() does to a WM_APP message is undocumented
- focus = GetFocus();
- if (focus != NULL) {
- if (GetClassNameW(focus, classchk, NCLASSNAME) == 0)
- xpanic("error getting name of focused window class for Area check", GetLastError());
- if (_wcsicmp(classchk, areaWindowClass) == 0) {
- uimsgloop_area(active, focus, &msg);
- continue;
- } else if (_wcsicmp(classchk, WC_TABCONTROL) == 0) {
- uimsgloop_tab(active, focus, &msg);
- continue;
- }
- // else fall through
- }
-
- if (IsDialogMessage(active, &msg) != 0)
- continue;
- uimsgloop_else(&msg);
- }
-}
-
-void issue(void *request)
-{
- SetLastError(0);
- if (PostMessageW(msgwin, msgRequest, 0, (LPARAM) request) == 0)
- xpanic("error issuing request", GetLastError());
-}
-
-HWND msgwin;
-
-#define msgwinclass L"gouimsgwin"
-
-static LRESULT CALLBACK msgwinproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- LRESULT shared;
- size_t i;
-
- if (sharedWndProc(hwnd, uMsg, wParam, lParam, &shared))
- return shared;
- switch (uMsg) {
- case msgRequest:
- doissue((void *) lParam);
- return 0;
- case msgOpenFileDone:
- finishOpenFile((WCHAR *) wParam, (void *) lParam);
- return 0;
- default:
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("message-only", "msgwinproc()", uMsg);
- return 0; // unreachable
-}
-
-DWORD makemsgwin(char **errmsg)
-{
- WNDCLASSW wc;
-
- ZeroMemory(&wc, sizeof (WNDCLASSW));
- wc.lpfnWndProc = msgwinproc;
- wc.hInstance = hInstance;
- wc.hIcon = hDefaultIcon;
- wc.hCursor = hArrowCursor;
- wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
- wc.lpszClassName = msgwinclass;
- if (RegisterClassW(&wc) == 0) {
- *errmsg = "error registering message-only window classs";
- return GetLastError();
- }
- msgwin = CreateWindowExW(
- 0,
- msgwinclass, L"package ui message-only window",
- 0,
- CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT,
- HWND_MESSAGE, NULL, hInstance, NULL);
- if (msgwin == NULL) {
- *errmsg = "error creating message-only window";
- return GetLastError();
- }
- return 0;
-}
diff --git a/redo/uitask_windows.go b/redo/uitask_windows.go
deleted file mode 100644
index c3c1884..0000000
--- a/redo/uitask_windows.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// 12 july 2014
-
-package ui
-
-import (
- "fmt"
- "syscall"
- "unsafe"
-)
-
-// #cgo CFLAGS: --std=c99
-// #cgo LDFLAGS: -luser32 -lkernel32 -lgdi32 -luxtheme -lmsimg32 -lcomdlg32
-// #include "winapi_windows.h"
-import "C"
-
-var msgwin C.HWND
-
-func uiinit() error {
- var errmsg *C.char
-
- errcode := C.initWindows(&errmsg)
- if errcode != 0 || errmsg != nil {
- return fmt.Errorf("error initializing package ui on Windows: %s: %v", C.GoString(errmsg), syscall.Errno(errcode))
- }
- errmsg = nil
- errcode = C.initCommonControls(&errmsg)
- if errcode != 0 || errmsg != nil {
- return fmt.Errorf("error initializing comctl32.dll: %s: %v", C.GoString(errmsg), syscall.Errno(errcode))
- }
- if err := makemsgwin(); err != nil {
- return fmt.Errorf("error creating message-only window: %v", err)
- }
- if err := makeWindowWindowClass(); err != nil {
- return fmt.Errorf("error creating Window window class: %v", err)
- }
- if err := makeContainerWindowClass(); err != nil {
- return fmt.Errorf("error creating container window class: %v", err)
- }
- if err := makeAreaWindowClass(); err != nil {
- return fmt.Errorf("error creating Area window class: %v", err)
- }
- return nil
-}
-
-func uimsgloop() {
- C.uimsgloop()
-}
-
-func uistop() {
- C.PostQuitMessage(0)
-}
-
-func issue(f *func()) {
- C.issue(unsafe.Pointer(f))
-}
-
-func makemsgwin() error {
- var errmsg *C.char
-
- err := C.makemsgwin(&errmsg)
- if err != 0 || errmsg != nil {
- return fmt.Errorf("%s: %v", C.GoString(errmsg), syscall.Errno(err))
- }
- return nil
-}
-
-//export doissue
-func doissue(fp unsafe.Pointer) {
- perform(fp)
-}
diff --git a/redo/warningpopover_darwin.m b/redo/warningpopover_darwin.m
deleted file mode 100644
index 50c9118..0000000
--- a/redo/warningpopover_darwin.m
+++ /dev/null
@@ -1,157 +0,0 @@
-// 26 august 2014
-
-#include "objc_darwin.h"
-#include <Cocoa/Cocoa.h>
-
-// We would be able to just use plain old NSPopover here, but alas that steals focus.
-// NSPopovers are intended for interactive content, and Apple seems to be diligent in enforcing this rule, as the known techniques for preventing a NSPopover from stealing focus no longer work in 10.9.
-// Let's just fake it with a window.
-
-@interface goWarningPopover : NSWindow {
-@public
- id onBegin;
- id onEnd;
- id textfield;
- NSTextView *tv;
-}
-@end
-
-@implementation goWarningPopover
-
-- (id)init
-{
- self = [super initWithContentRect:NSZeroRect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:YES];
- [self setOpaque:NO];
- [self setHasShadow:YES];
- [self setExcludedFromWindowsMenu:YES];
- [self setMovableByWindowBackground:NO];
- [self setLevel:NSPopUpMenuWindowLevel];
- [self setHidesOnDeactivate:YES];
- self->onBegin = nil;
- self->onEnd = nil;
- return self;
-}
-
-- (void)close
-{
- if (self->onBegin != nil) {
- [[NSNotificationCenter defaultCenter] removeObserver:self->onBegin];
- self->onBegin = nil;
- }
- if (self->onEnd != nil) {
- [[NSNotificationCenter defaultCenter] removeObserver:self->onEnd];
- self->onEnd = nil;
- }
- if (self->tv != nil)
- [self->tv removeObserver:self forKeyPath:@"delegate"];
- [super close];
-}
-
-- (BOOL)canBecomeKeyWindow
-{
- return NO;
-}
-
-- (BOOL)canBecomeMainWindow
-{
- return NO;
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
- if ([self->tv delegate] == self->textfield)
- [self orderFront:self];
- else
- [self orderOut:self];
-}
-
-@end
-
-@interface goWarningView : NSView {
-@public
- NSImageView *icon;
- NSTextField *label;
-}
-@end
-
-@implementation goWarningView
-
-- (void)sizeToFitAndArrange
-{
- [self->label sizeToFit];
-
- CGFloat labelheight, imageheight;
- CGFloat targetwidth, imagewidth;
-
- labelheight = [self->label frame].size.height;
- imageheight = [[self->icon image] size].height;
- imagewidth = [[self->icon image] size].width;
- targetwidth = (imagewidth * labelheight) / imageheight;
-
- [self->icon setFrameSize:NSMakeSize(targetwidth, labelheight)];
-
- [self setFrameSize:NSMakeSize(targetwidth + [self->label frame].size.width, labelheight)];
- [self->icon setFrameOrigin:NSMakePoint(0, 0)];
- [self->label setFrameOrigin:NSMakePoint(targetwidth, 0)];
-}
-
-- (BOOL)acceptsFirstResponder
-{
- return NO;
-}
-
-@end
-
-id newWarningPopover(char *text)
-{
- goWarningView *wv;
-
- wv = [[goWarningView alloc] initWithFrame:NSZeroRect];
-
- wv->icon = [[NSImageView alloc] initWithFrame:NSZeroRect];
- [wv->icon setImage:[NSImage imageNamed:NSImageNameCaution]];
- [wv->icon setImageFrameStyle:NSImageFrameNone];
- [wv->icon setImageAlignment:NSImageAlignCenter];
- [wv->icon setImageScaling:NSImageScaleProportionallyUpOrDown];
- [wv->icon setEditable:NO];
- [wv->icon setAnimates:NO];
- [wv->icon setAllowsCutCopyPaste:NO];
- [wv->icon setRefusesFirstResponder:YES];
-
- wv->label = (NSTextField *) newLabel();
- textfieldSetText((id) wv->label, text);
- [wv->label setRefusesFirstResponder:YES];
-
- [wv addSubview:wv->icon];
- [wv addSubview:wv->label];
- [wv sizeToFitAndArrange];
-
- goWarningPopover *popover;
-
- popover = [[goWarningPopover alloc] init]; // explicitly use our initializer
- [[popover contentView] addSubview:wv];
- [popover setContentSize:[wv frame].size];
-
- return (id) popover;
-}
-
-void warningPopoverShow(id popover, id control)
-{
- goWarningPopover *p = (goWarningPopover *) popover;
- NSView *v = (NSView *) control;
- NSRect vr;
- NSPoint vo;
-
- // note that the frame is a rect of the superview
- vr = [[v superview] convertRect:[v frame] toView:nil];
- vo = [[v window] convertRectToScreen:vr].origin;
- [p setFrameOrigin:NSMakePoint(vo.x, vo.y - [p frame].size.height)];
- p->textfield = control;
- p->tv = (NSTextView *) [[v window] fieldEditor:NO forObject:nil];
- // thanks to http://stackoverflow.com/a/25562783/3408572 for suggesting KVO here
- [p->tv addObserver:p forKeyPath:@"delegate" options:NSKeyValueObservingOptionNew context:NULL];
- [p orderFront:p];
-}
diff --git a/redo/winapi_windows.h b/redo/winapi_windows.h
deleted file mode 100644
index 83f7822..0000000
--- a/redo/winapi_windows.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// 17 july 2014
-
-// cgo will include this file multiple times
-#ifndef __GO_UI_WINAPI_WINDOWS_H__
-#define __GO_UI_WINAPI_WINDOWS_H__
-
-#define UNICODE
-#define _UNICODE
-#define STRICT
-#define STRICT_TYPED_ITEMIDS
-// get Windows version right; right now Windows XP
-#define WINVER 0x0501
-#define _WIN32_WINNT 0x0501
-#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
-#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
-#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
-#include <windows.h>
-#include <commctrl.h>
-#include <stdint.h>
-#include <uxtheme.h>
-#include <string.h>
-#include <wchar.h>
-#include <windowsx.h>
-#include <vsstyle.h>
-#include <vssym32.h>
-
-// global messages unique to everything
-enum {
- msgRequest = WM_APP + 1, // + 1 just to be safe
- msgCOMMAND, // WM_COMMAND proxy; see forwardCommand() in controls_windows.go
- msgNOTIFY, // WM_NOTIFY proxy
- msgAreaSizeChanged,
- msgAreaGetScroll,
- msgAreaRepaint,
- msgAreaRepaintAll,
- msgTabCurrentTabHasChildren,
- msgAreaKeyDown,
- msgAreaKeyUp,
- msgLoadImageList,
- msgTableMakeInitialCheckboxImageList,
- msgOpenFileDone,
-};
-
-// uitask_windows.c
-extern void uimsgloop(void);
-extern void issue(void *);
-extern HWND msgwin;
-extern DWORD makemsgwin(char **);
-
-// comctl32_windows.c
-extern DWORD initCommonControls(char **);
-// these are listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
-extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
-extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
-extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
-extern HIMAGELIST (*WINAPI fv_ImageList_Create)(int, int, UINT, int, int);
-extern int (*WINAPI fv_ImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
-extern BOOL (*WINAPI fv_ImageList_Destroy)(HIMAGELIST);
-
-// control_windows.c
-extern HWND newControl(LPWSTR, DWORD, DWORD);
-extern void controlSetParent(HWND, HWND);
-extern void controlSetControlFont(HWND);
-extern void moveWindow(HWND, int, int, int, int);
-extern LONG controlTextLength(HWND, LPWSTR);
-
-// basicctrls_windows.c
-extern void setButtonSubclass(HWND, void *);
-extern void setCheckboxSubclass(HWND, void *);
-extern BOOL checkboxChecked(HWND);
-extern void checkboxSetChecked(HWND, BOOL);
-#define textfieldStyle (ES_AUTOHSCROLL | ES_LEFT | ES_NOHIDESEL | WS_TABSTOP)
-#define textfieldExtStyle (WS_EX_CLIENTEDGE)
-extern void setTextFieldSubclass(HWND, void *);
-extern void textfieldSetAndShowInvalidBalloonTip(HWND, WCHAR *);
-extern void textfieldHideInvalidBalloonTip(HWND);
-
-// init_windows.c
-extern HINSTANCE hInstance;
-extern int nCmdShow;
-extern HICON hDefaultIcon;
-extern HCURSOR hArrowCursor;
-extern HFONT controlFont;
-extern HFONT titleFont;
-extern HFONT smallTitleFont;
-extern HFONT menubarFont;
-extern HFONT statusbarFont;
-extern HBRUSH hollowBrush;
-extern DWORD initWindows(char **);
-
-// window_windows.c
-extern DWORD makeWindowWindowClass(char **);
-extern HWND newWindow(LPWSTR, int, int, void *);
-extern void windowClose(HWND);
-
-// common_windows.c
-extern LRESULT getWindowTextLen(HWND);
-extern void getWindowText(HWND, WPARAM, LPWSTR);
-extern void setWindowText(HWND, LPWSTR);
-extern void updateWindow(HWND);
-extern void *getWindowData(HWND, UINT, WPARAM, LPARAM, LRESULT *, void (*)(void *, HWND));
-extern BOOL sharedWndProc(HWND, UINT, WPARAM, LPARAM, LRESULT *);
-extern void paintControlBackground(HWND, HDC);
-
-// tab_windows.go
-extern LPWSTR xWC_TABCONTROL;
-extern void setTabSubclass(HWND, void *);
-extern void tabAppend(HWND, LPWSTR);
-extern void tabGetContentRect(HWND, RECT *);
-extern LONG tabGetTabHeight(HWND);
-extern void tabEnterChildren(HWND);
-extern void tabLeaveChildren(HWND);
-
-// table_windows.go
-extern LPWSTR xWC_LISTVIEW;
-extern void setTableSubclass(HWND, void *);
-extern void tableAppendColumn(HWND, int, LPWSTR);
-extern void tableUpdate(HWND, int);
-extern void tableAddExtendedStyles(HWND, LPARAM);
-extern void tableAutosizeColumns(HWND, int);
-extern intptr_t tableSelectedItem(HWND);
-extern void tableSelectItem(HWND, intptr_t);
-
-// container_windows.c
-extern DWORD makeContainerWindowClass(char **);
-extern HWND newContainer(void *);
-extern void calculateBaseUnits(HWND, int *, int *, LONG *);
-
-// area_windows.c
-#define areaWindowClass L"gouiarea"
-extern void repaintArea(HWND, RECT *);
-extern DWORD makeAreaWindowClass(char **);
-extern HWND newArea(void *);
-extern HWND newAreaTextField(HWND, void *);
-extern void areaOpenTextField(HWND, HWND, int, int, int, int);
-extern void areaMarkTextFieldDone(HWND);
-
-// imagelist_windows.c
-extern HBITMAP unscaledBitmap(void *, intptr_t, intptr_t);
-extern HIMAGELIST newImageList(int, int);
-extern void addImage(HIMAGELIST, HWND, HBITMAP, int, int, int, int);
-extern void applyImageList(HWND, UINT, WPARAM, HIMAGELIST, HIMAGELIST);
-enum {
- checkboxStateChecked = 1 << 0,
- checkboxStateHot = 1 << 1,
- checkboxStatePushed = 1 << 2,
- checkboxnStates = 1 << 3,
-};
-extern HIMAGELIST makeCheckboxImageList(HWND, HTHEME *);
-
-// dialog_windows.c
-extern void openFile(HWND, void *);
-
-#endif
diff --git a/redo/window.go b/redo/window.go
deleted file mode 100644
index d700d14..0000000
--- a/redo/window.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// 7 july 2014
-
-package ui
-
-// Window represents a top-level window on screen that contains other Controls.
-// Windows in package ui can only contain one control; the Stack and Grid layout Controls allow you to pack multiple Controls in a Window.
-// Note that a Window is not itself a Control.
-type Window interface {
- // Title and SetTitle get and set the Window's title, respectively.
- Title() string
- SetTitle(title string)
-
- // Show and Hide bring the Window on-screen and off-screen, respectively.
- Show()
- Hide()
-
- // Close closes the Window.
- // Any Controls within the Window are destroyed, and the Window itself is also destroyed.
- // Attempting to use a Window after it has been closed results in undefined behavior.
- // Close unconditionally closes the Window; it neither raises OnClosing nor checks for a return from OnClosing.
- Close()
-
- // OnClosing registers an event handler that is triggered when the user clicks the Window's close button.
- // On systems where whole applications own windows, OnClosing is also triggered when the user asks to close the application.
- // If this handler returns true, the Window is closed as defined by Close above.
- // If this handler returns false, the Window is not closed.
- OnClosing(func() bool)
-
- windowDialog
-}
-
-// NewWindow creates a new Window with the given title text, size, and control.
-func NewWindow(title string, width int, height int, control Control) Window {
- return newWindow(title, width, height, control)
-}
diff --git a/redo/window_darwin.go b/redo/window_darwin.go
deleted file mode 100644
index ddd598e..0000000
--- a/redo/window_darwin.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// 8 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "objc_darwin.h"
-import "C"
-
-type window struct {
- id C.id
-
- closing *event
-
- *container
-}
-
-func newWindow(title string, width int, height int, control Control) *window {
- id := C.newWindow(C.intptr_t(width), C.intptr_t(height))
- ctitle := C.CString(title)
- defer C.free(unsafe.Pointer(ctitle))
- C.windowSetTitle(id, ctitle)
- w := &window{
- id: id,
- closing: newEvent(),
- container: newContainer(control),
- }
- C.windowSetDelegate(w.id, unsafe.Pointer(w))
- C.windowSetContentView(w.id, w.container.id)
- return w
-}
-
-func (w *window) Title() string {
- return C.GoString(C.windowTitle(w.id))
-}
-
-func (w *window) SetTitle(title string) {
- ctitle := C.CString(title)
- defer C.free(unsafe.Pointer(ctitle))
- C.windowSetTitle(w.id, ctitle)
-}
-
-func (w *window) Show() {
- C.windowShow(w.id)
-}
-
-func (w *window) Hide() {
- C.windowHide(w.id)
-}
-
-func (w *window) Close() {
- C.windowClose(w.id)
-}
-
-func (w *window) OnClosing(e func() bool) {
- w.closing.setbool(e)
-}
-
-//export windowClosing
-func windowClosing(xw unsafe.Pointer) C.BOOL {
- w := (*window)(unsafe.Pointer(xw))
- close := w.closing.fire()
- if close {
- return C.YES
- }
- return C.NO
-}
diff --git a/redo/window_darwin.m b/redo/window_darwin.m
deleted file mode 100644
index 21287cf..0000000
--- a/redo/window_darwin.m
+++ /dev/null
@@ -1,86 +0,0 @@
-// 8 july 2014
-
-#import "objc_darwin.h"
-#import "_cgo_export.h"
-#import <Cocoa/Cocoa.h>
-
-#define toNSWindow(x) ((NSWindow *) (x))
-#define toNSView(x) ((NSView *) (x))
-
-@interface goWindowDelegate : NSObject <NSWindowDelegate> {
-@public
- void *gowin;
-}
-@end
-
-@implementation goWindowDelegate
-
-- (BOOL)windowShouldClose:(id)win
-{
- return windowClosing(self->gowin);
-}
-
-@end
-
-id newWindow(intptr_t width, intptr_t height)
-{
- NSWindow *w;
- NSTextView *tv;
-
- w = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, (CGFloat) width, (CGFloat) height)
- styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
- backing:NSBackingStoreBuffered
- defer:YES];
- // we do not want substitutions
- // text fields, labels, etc. take their smart quotes and other autocorrect settings from their parent window, which provides a shared "field editor"
- // so we have to turn them off here
- // thanks akempgen in irc.freenode.net/#macdev
- // for some reason, this selector returns NSText but is documented to return NSTextView...
- disableAutocorrect((id) [w fieldEditor:YES forObject:nil]);
- return w;
-}
-
-void windowSetDelegate(id win, void *w)
-{
- goWindowDelegate *d;
-
- d = [goWindowDelegate new];
- d->gowin = w;
- [toNSWindow(win) setDelegate:d];
-}
-
-void windowSetContentView(id win, id view)
-{
- [toNSWindow(win) setContentView:toNSView(view)];
-}
-
-const char *windowTitle(id win)
-{
- return [[toNSWindow(win) title] UTF8String];
-}
-
-void windowSetTitle(id win, const char * title)
-{
- [toNSWindow(win) setTitle:[NSString stringWithUTF8String:title]];
-}
-
-void windowShow(id win)
-{
- [toNSWindow(win) makeKeyAndOrderFront:toNSWindow(win)];
- // no need to worry about reshowing the window initially; that's handled by our container view (container_darwin.m)
-}
-
-void windowHide(id win)
-{
- [toNSWindow(win) orderOut:toNSWindow(win)];
-}
-
-void windowClose(id win)
-{
- [toNSWindow(win) close];
-}
-
-id windowContentView(id win)
-{
- return (id) [toNSWindow(win) contentView];
-}
diff --git a/redo/window_unix.go b/redo/window_unix.go
deleted file mode 100644
index 3f31089..0000000
--- a/redo/window_unix.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern gboolean windowClosing(GtkWidget *, GdkEvent *, gpointer);
-import "C"
-
-type window struct {
- widget *C.GtkWidget
- wc *C.GtkContainer
- bin *C.GtkBin
- window *C.GtkWindow
-
- group *C.GtkWindowGroup
-
- closing *event
-
- *container
-}
-
-func newWindow(title string, width int, height int, control Control) *window {
- widget := C.gtk_window_new(C.GTK_WINDOW_TOPLEVEL)
- 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(),
- }
- C.gtk_window_set_title(w.window, ctitle)
- g_signal_connect(
- C.gpointer(unsafe.Pointer(w.window)),
- "delete-event",
- C.GCallback(C.windowClosing),
- C.gpointer(unsafe.Pointer(w)))
- C.gtk_window_resize(w.window, C.gint(width), C.gint(height))
- w.container = newContainer(control)
- w.container.setParent(&controlParent{w.wc})
- // for dialogs; otherwise, they will be modal to all windows, not just this one
- w.group = C.gtk_window_group_new()
- C.gtk_window_group_add_window(w.group, w.window)
- return w
-}
-
-func (w *window) Title() string {
- return fromgstr(C.gtk_window_get_title(w.window))
-}
-
-func (w *window) SetTitle(title string) {
- ctitle := togstr(title)
- defer freegstr(ctitle)
- C.gtk_window_set_title(w.window, ctitle)
-}
-
-func (w *window) Show() {
- C.gtk_widget_show_all(w.widget)
-}
-
-func (w *window) Hide() {
- C.gtk_widget_hide(w.widget)
-}
-
-func (w *window) Close() {
- C.gtk_widget_destroy(w.widget)
-}
-
-func (w *window) OnClosing(e func() bool) {
- w.closing.setbool(e)
-}
-
-//export windowClosing
-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_STOP // keeps window alive
-}
diff --git a/redo/window_windows.c b/redo/window_windows.c
deleted file mode 100644
index 2d047b0..0000000
--- a/redo/window_windows.c
+++ /dev/null
@@ -1,84 +0,0 @@
-// 17 july 2014
-
-#include "winapi_windows.h"
-#include "_cgo_export.h"
-
-#define windowclass L"gouiwindow"
-
-#define windowBackground ((HBRUSH) (COLOR_BTNFACE + 1))
-
-static LRESULT CALLBACK windowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- void *data;
- RECT r;
- LRESULT lResult;
-
- data = (void *) getWindowData(hwnd, uMsg, wParam, lParam, &lResult, storeWindowHWND);
- if (data == NULL)
- return lResult;
- if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult))
- return lResult;
- switch (uMsg) {
- case WM_PRINTCLIENT:
- // the return value of this message is not documented
- // just to be safe, do this first, returning its value later
- lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam);
- if (GetClientRect(hwnd, &r) == 0)
- xpanic("error getting client rect for Window in WM_PRINTCLIENT", GetLastError());
- if (FillRect((HDC) wParam, &r, windowBackground) == 0)
- xpanic("error filling WM_PRINTCLIENT DC with window background color", GetLastError());
- return lResult;
- case WM_SIZE:
- if (GetClientRect(hwnd, &r) == 0)
- xpanic("error getting client rect for Window in WM_SIZE", GetLastError());
- windowResize(data, &r);
- return 0;
- case WM_CLOSE:
- windowClosing(data);
- return 0;
- default:
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- xmissedmsg("Window", "windowWndProc()", uMsg);
- return 0; // unreached
-}
-
-DWORD makeWindowWindowClass(char **errmsg)
-{
- WNDCLASSW wc;
-
- ZeroMemory(&wc, sizeof (WNDCLASSW));
- wc.lpfnWndProc = windowWndProc;
- wc.hInstance = hInstance;
- wc.hIcon = hDefaultIcon;
- wc.hCursor = hArrowCursor;
- wc.hbrBackground = windowBackground;
- wc.lpszClassName = windowclass;
- if (RegisterClassW(&wc) == 0) {
- *errmsg = "error registering Window window class";
- return GetLastError();
- }
- return 0;
-}
-
-HWND newWindow(LPWSTR title, int width, int height, void *data)
-{
- HWND hwnd;
-
- hwnd = CreateWindowExW(
- 0,
- windowclass, title,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT,
- width, height,
- NULL, NULL, hInstance, data);
- if (hwnd == NULL)
- xpanic("Window creation failed", GetLastError());
- return hwnd;
-}
-
-void windowClose(HWND hwnd)
-{
- if (DestroyWindow(hwnd) == 0)
- xpanic("error destroying window", GetLastError());
-}
diff --git a/redo/window_windows.go b/redo/window_windows.go
deleted file mode 100644
index 60f89d1..0000000
--- a/redo/window_windows.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// 12 july 2014
-
-package ui
-
-import (
- "fmt"
- "syscall"
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type window struct {
- hwnd C.HWND
- shownbefore bool
-
- closing *event
-
- *container
-}
-
-func makeWindowWindowClass() error {
- var errmsg *C.char
-
- err := C.makeWindowWindowClass(&errmsg)
- if err != 0 || errmsg != nil {
- return fmt.Errorf("%s: %v", C.GoString(errmsg), syscall.Errno(err))
- }
- return nil
-}
-
-func newWindow(title string, width int, height int, control Control) *window {
- w := &window{
- // hwnd set in WM_CREATE handler
- 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)
- if hresult != C.S_OK {
- panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
- }
- w.container.setParent(w.hwnd)
- return w
-}
-
-func (w *window) Title() string {
- return getWindowText(w.hwnd)
-}
-
-func (w *window) SetTitle(title string) {
- C.setWindowText(w.hwnd, toUTF16(title))
-}
-
-func (w *window) Show() {
- if !w.shownbefore {
- C.ShowWindow(w.hwnd, C.nCmdShow)
- C.updateWindow(w.hwnd)
- w.shownbefore = true
- } else {
- C.ShowWindow(w.hwnd, C.SW_SHOW)
- }
-}
-
-func (w *window) Hide() {
- C.ShowWindow(w.hwnd, C.SW_HIDE)
-}
-
-func (w *window) Close() {
- C.windowClose(w.hwnd)
-}
-
-func (w *window) OnClosing(e func() bool) {
- w.closing.setbool(e)
-}
-
-//export storeWindowHWND
-func storeWindowHWND(data unsafe.Pointer, hwnd C.HWND) {
- w := (*window)(data)
- w.hwnd = hwnd
-}
-
-//export windowResize
-func windowResize(data unsafe.Pointer, r *C.RECT) {
- w := (*window)(data)
- // the origin of the window's content area is always (0, 0), but let's use the values from the RECT just to be safe
- w.container.move(r)
-}
-
-//export windowClosing
-func windowClosing(data unsafe.Pointer) {
- w := (*window)(data)
- close := w.closing.fire()
- if close {
- C.windowClose(w.hwnd)
- }
-}
diff --git a/redo/yz_icons_test.go b/redo/yz_icons_test.go
deleted file mode 100644
index a85f58e..0000000
--- a/redo/yz_icons_test.go
+++ /dev/null
@@ -1,685 +0,0 @@
-// 16 august 2014
-
-package ui
-
-import (
- "fmt"
- "bytes"
- "image"
- "image/draw"
- _ "image/png"
-)
-
-type icon struct {
- Bool bool
- Icon ImageIndex
- Name string
-}
-
-var firstimg *image.RGBA
-
-func readIcons() ([]icon, ImageList) {
- out := make([]icon, len(icons))
- outil := NewImageList()
- for i := range icons {
- r := bytes.NewReader(icons[i].data)
- png, _, err := image.Decode(r)
- if err != nil {
- panic(fmt.Errorf("error loading image %d (%q): %v", i, icons[i].name, err))
- }
- img := image.NewRGBA(png.Bounds())
- draw.Draw(img, img.Rect, png, image.ZP, draw.Src)
- if firstimg == nil {
- firstimg = img
- }
- out[i].Icon = ImageIndex(i)
- out[i].Name = icons[i].name
- outil.Append(img)
- }
- return out, outil
-}
-
-func tileImage(times int) *image.RGBA {
- dx := firstimg.Rect.Dx()
- dy := firstimg.Rect.Dy()
- res := image.NewRGBA(image.Rect(0, 0, times * dx, times * dy))
- r := image.Rect(0, 0, dx, dy)
- for y := 0; y < times; y++ {
- rr := r.Add(image.Pt(0, y * dy))
- for x := 0; x < times; x++ {
- draw.Draw(res, rr, firstimg, image.ZP, draw.Src)
- rr = rr.Add(image.Pt(dx, 0))
- }
- }
- return res
-}
-
-var icons = []struct {
- data []byte
- name string
-}{
- { __16x16_categories_applications_accessories_png, "16x16/categories/applications-accessories.png", },
- { __16x16_places_folder_png, "16x16/places/folder.png", },
- { __16x16_mimetypes_x_office_spreadsheet_png, "16x16/mimetypes/x-office-spreadsheet.png", },
- { __32x32_categories_applications_accessories_png, "32x32/categories/applications-accessories.png", },
- { __32x32_places_folder_png, "32x32/places/folder.png", },
- { __32x32_mimetypes_x_office_spreadsheet_png, "32x32/mimetypes/x-office-spreadsheet.png", },
-}
-
-// from http://tango.freedesktop.org/releases/tango-icon-theme-0.8.90.tar.gz, which is public domain
-
-var __16x16_categories_applications_accessories_png = []byte{
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
- 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
- 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00, 0x00, 0x00,
- 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0,
- 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00,
- 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18,
- 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x0b, 0x1c,
- 0x17, 0x38, 0x22, 0x38, 0xae, 0xb6, 0xe0, 0x00, 0x00, 0x03, 0x36, 0x49,
- 0x44, 0x41, 0x54, 0x38, 0xcb, 0x5d, 0x93, 0x4b, 0x4c, 0x5c, 0x75, 0x14,
- 0xc6, 0xbf, 0xff, 0x63, 0xe6, 0xde, 0x79, 0x80, 0x73, 0x41, 0x60, 0x66,
- 0x80, 0xa2, 0x13, 0x04, 0x9a, 0x49, 0x53, 0x13, 0x17, 0xc5, 0x57, 0xdd,
- 0x18, 0x4a, 0xd2, 0x8d, 0xa9, 0x55, 0x1b, 0x1f, 0xab, 0x36, 0xc1, 0x54,
- 0x6b, 0xd5, 0xd2, 0x66, 0x48, 0x43, 0x1a, 0x62, 0xa2, 0x0d, 0x94, 0x58,
- 0x9b, 0x34, 0xac, 0x4c, 0x88, 0x8f, 0x85, 0x1b, 0x5c, 0x11, 0x12, 0xbb,
- 0xa8, 0xa6, 0x34, 0x5d, 0x18, 0xb5, 0x75, 0x0c, 0x1d, 0xa8, 0x34, 0xf2,
- 0x98, 0x29, 0x65, 0x18, 0xc6, 0x0e, 0x33, 0x70, 0xe7, 0xce, 0xfd, 0xff,
- 0x8f, 0x1b, 0xc0, 0x49, 0xbf, 0xd5, 0x39, 0xdf, 0xc9, 0xf7, 0xcb, 0x49,
- 0x4e, 0x0e, 0xc3, 0xb6, 0x46, 0x46, 0x2f, 0xf6, 0x02, 0xf8, 0xce, 0x34,
- 0xcd, 0x87, 0xa7, 0x3e, 0xf8, 0x38, 0x8e, 0x2a, 0x8d, 0x8c, 0x5e, 0x1c,
- 0x93, 0x52, 0xbe, 0xf5, 0xc9, 0xe9, 0xfe, 0xba, 0x6a, 0x7f, 0x7a, 0x1c,
- 0xef, 0xf1, 0x9d, 0x46, 0x08, 0x31, 0xf1, 0xe1, 0xc9, 0xd3, 0x96, 0x6d,
- 0xdb, 0x8b, 0x57, 0xc7, 0xae, 0x0c, 0xee, 0xf8, 0x97, 0xbf, 0x1a, 0xcd,
- 0x1c, 0xea, 0xe9, 0xed, 0x03, 0x70, 0xe7, 0xb1, 0xf0, 0xcb, 0x00, 0xbe,
- 0xde, 0x05, 0x28, 0xa5, 0xcc, 0x7b, 0xf3, 0xb3, 0xfc, 0xc4, 0xf1, 0xbe,
- 0x1e, 0xa5, 0xd4, 0x7e, 0x00, 0x18, 0xbe, 0xf4, 0xc5, 0x2b, 0xd1, 0xe6,
- 0x68, 0xa4, 0x58, 0xda, 0x60, 0x5a, 0xeb, 0xee, 0xaa, 0x70, 0x3b, 0xe3,
- 0x62, 0x92, 0x31, 0xe1, 0xd9, 0x05, 0x70, 0xce, 0x4b, 0x0b, 0x0b, 0xff,
- 0xc0, 0x34, 0x0c, 0x56, 0x2e, 0x97, 0xe3, 0x57, 0xc7, 0xae, 0x0c, 0x4a,
- 0x29, 0xaf, 0xc5, 0x62, 0x31, 0xac, 0x3c, 0x58, 0xd1, 0x5a, 0xeb, 0xf9,
- 0xed, 0xb0, 0xc5, 0x85, 0xb8, 0xde, 0xd1, 0xfd, 0x69, 0x50, 0x78, 0x6a,
- 0x54, 0xf5, 0x06, 0x3d, 0xa9, 0x54, 0x0a, 0xcb, 0xe9, 0x25, 0x76, 0xe2,
- 0x78, 0x5f, 0xa7, 0x6d, 0xdb, 0xef, 0x77, 0x75, 0x75, 0x79, 0x18, 0x38,
- 0xe6, 0xef, 0xcf, 0x03, 0xc0, 0x0f, 0xd3, 0xe3, 0xf0, 0x70, 0x21, 0xa6,
- 0x5a, 0xe3, 0x47, 0x9b, 0xea, 0x5a, 0x0e, 0x31, 0x00, 0xd8, 0x05, 0x9c,
- 0xeb, 0x1f, 0xb8, 0xc5, 0x39, 0x5f, 0x9c, 0x9b, 0x9b, 0x85, 0x69, 0x98,
- 0xcc, 0x0a, 0x59, 0x51, 0xd2, 0x40, 0x76, 0x6d, 0x55, 0x03, 0x98, 0x3c,
- 0x7b, 0x26, 0xf1, 0x19, 0x17, 0x62, 0xbc, 0xbe, 0xf9, 0xc0, 0xfe, 0x68,
- 0xc7, 0x9b, 0x1e, 0x50, 0x09, 0x44, 0xf4, 0x3f, 0x00, 0x00, 0xb4, 0xd6,
- 0x47, 0x66, 0xee, 0xce, 0xd0, 0xea, 0xea, 0x0a, 0x5c, 0xe5, 0x62, 0x63,
- 0xa3, 0x80, 0x64, 0x32, 0xe9, 0x00, 0x18, 0xba, 0xf9, 0x0d, 0x3f, 0xef,
- 0x0f, 0xb5, 0xbd, 0x16, 0x7b, 0xee, 0x94, 0xe9, 0x16, 0x27, 0xa1, 0xdd,
- 0x0d, 0x00, 0x8f, 0x01, 0xce, 0x9e, 0x49, 0xfc, 0xc6, 0x39, 0xff, 0x76,
- 0x76, 0x2e, 0xa5, 0x43, 0xa1, 0x10, 0x32, 0x0f, 0x32, 0x44, 0x44, 0xe3,
- 0xcf, 0xd7, 0x27, 0x9e, 0xf2, 0x78, 0x6b, 0xcf, 0x77, 0x76, 0x0f, 0xf8,
- 0xdd, 0xd2, 0x34, 0x2a, 0x5b, 0x8b, 0xd0, 0xca, 0x06, 0x88, 0xc0, 0xaa,
- 0x01, 0x13, 0xe1, 0xf0, 0xa8, 0x4b, 0x74, 0xd2, 0xcd, 0xe7, 0x4d, 0xb8,
- 0x2e, 0x9e, 0x0e, 0x37, 0x21, 0x4d, 0x7a, 0x33, 0x78, 0xd0, 0xf6, 0xbe,
- 0x70, 0x69, 0x40, 0x4a, 0xbe, 0x86, 0x62, 0xee, 0x06, 0x0c, 0xd3, 0x84,
- 0x37, 0xf4, 0x06, 0x6e, 0xff, 0x94, 0x50, 0x02, 0x00, 0x26, 0x22, 0x91,
- 0xc1, 0x23, 0x95, 0xca, 0xf5, 0x4e, 0xcb, 0xea, 0x0e, 0x09, 0x21, 0x95,
- 0x72, 0xa9, 0xec, 0x3a, 0xa8, 0x0b, 0xd4, 0xb0, 0x46, 0xd3, 0xf0, 0x18,
- 0xcb, 0x26, 0xff, 0x75, 0x78, 0x0a, 0x9e, 0xc6, 0x1c, 0xb2, 0x5b, 0x77,
- 0x11, 0x6a, 0x6c, 0x02, 0xf7, 0xb6, 0x63, 0xf5, 0xfe, 0xcf, 0xc4, 0x7f,
- 0x8c, 0x46, 0xdf, 0x75, 0x72, 0xb9, 0xa1, 0xce, 0x70, 0x58, 0xcf, 0x2c,
- 0x2d, 0x5d, 0x2b, 0x6c, 0x6d, 0x3a, 0xf9, 0xc2, 0x06, 0xf7, 0x1d, 0xd6,
- 0x2d, 0x42, 0x32, 0xfc, 0x6b, 0x97, 0x50, 0x88, 0x99, 0x68, 0x6f, 0xa8,
- 0x47, 0x32, 0x31, 0x87, 0xfc, 0x94, 0x44, 0xc5, 0x71, 0xa0, 0xdd, 0x32,
- 0x08, 0x04, 0xee, 0x3a, 0xce, 0xf0, 0xbe, 0xd6, 0x56, 0x4a, 0x2d, 0x2f,
- 0x5f, 0x38, 0xa6, 0x54, 0x6f, 0xad, 0xe9, 0x53, 0xc2, 0xe7, 0x53, 0x8d,
- 0xaf, 0xf3, 0xef, 0xff, 0xce, 0xac, 0x20, 0x18, 0x0c, 0x20, 0xfe, 0x65,
- 0x03, 0xf2, 0x2f, 0xad, 0xb9, 0x7b, 0xa3, 0x11, 0x2a, 0xde, 0xf0, 0x42,
- 0x55, 0x2a, 0x70, 0xdd, 0x4d, 0x80, 0x08, 0x1c, 0xe5, 0x72, 0xbd, 0xe3,
- 0x38, 0xea, 0x98, 0x52, 0x9f, 0x4f, 0x06, 0x02, 0x97, 0x3d, 0x52, 0x9a,
- 0xc2, 0x42, 0xc1, 0x6f, 0xb5, 0x1f, 0x08, 0x3d, 0xbb, 0x07, 0x7e, 0x92,
- 0xb8, 0x37, 0xf4, 0x17, 0xcc, 0x57, 0xb7, 0x24, 0x18, 0x31, 0x5d, 0xd0,
- 0x70, 0x1d, 0x07, 0xaa, 0xb2, 0x09, 0x80, 0x20, 0xe1, 0xf5, 0x66, 0x82,
- 0x7e, 0xff, 0x9e, 0xdb, 0x6d, 0x6d, 0x65, 0xad, 0xb5, 0x9c, 0x59, 0x4b,
- 0x17, 0x9b, 0x2f, 0x3c, 0xe1, 0x6f, 0xd9, 0x7b, 0xd4, 0x08, 0x9c, 0xfb,
- 0x05, 0xc9, 0x8f, 0xfe, 0x40, 0xc7, 0x9d, 0x30, 0x2a, 0xbf, 0xd7, 0x40,
- 0x6b, 0x82, 0xac, 0x95, 0x50, 0xda, 0xdd, 0x06, 0x00, 0xe2, 0x6d, 0xcb,
- 0xca, 0xa5, 0xd7, 0xd7, 0x5f, 0x5c, 0x77, 0x1c, 0x99, 0x67, 0xc4, 0xc2,
- 0xfd, 0x5a, 0x3c, 0x73, 0xf8, 0x1d, 0x83, 0x73, 0x0f, 0x8c, 0x86, 0x27,
- 0x61, 0x44, 0xeb, 0x90, 0x5e, 0xc8, 0x22, 0x9b, 0x2d, 0xe0, 0x91, 0x57,
- 0x21, 0x3e, 0x72, 0x10, 0xbe, 0x48, 0x0c, 0x44, 0x0c, 0x8f, 0x1e, 0xfe,
- 0x49, 0xac, 0xea, 0x41, 0xf6, 0x01, 0xb8, 0xc5, 0x98, 0x34, 0x85, 0xf4,
- 0x3b, 0x00, 0x01, 0x44, 0xdb, 0x53, 0xda, 0x3d, 0x35, 0xed, 0xd4, 0x44,
- 0x50, 0xca, 0xf6, 0xfd, 0x07, 0x11, 0xa6, 0x73, 0x42, 0xc7, 0xee, 0xef,
- 0xaa, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
- 0x82,
-}
-
-var __16x16_places_folder_png = []byte{
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
- 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
- 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00, 0x00, 0x00,
- 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
- 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0d,
- 0xd7, 0x00, 0x00, 0x0d, 0xd7, 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00,
- 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61,
- 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63,
- 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00,
- 0x00, 0x01, 0xc2, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xa5, 0x90, 0x31,
- 0x6b, 0x93, 0x51, 0x14, 0x86, 0x9f, 0x73, 0xef, 0x57, 0x2c, 0x29, 0xe2,
- 0xe0, 0x10, 0xba, 0x14, 0x1c, 0x9c, 0x32, 0x76, 0xeb, 0x2e, 0x99, 0x1c,
- 0x82, 0xd0, 0xd5, 0x5f, 0xa0, 0xbb, 0xd0, 0x3f, 0xe0, 0xe2, 0x56, 0x57,
- 0xff, 0x87, 0x28, 0xc4, 0xb9, 0x60, 0xc4, 0x59, 0x29, 0x8a, 0x24, 0x92,
- 0x50, 0x69, 0xbf, 0x26, 0x25, 0xdf, 0xbd, 0xe7, 0x9e, 0xe3, 0x90, 0x26,
- 0x36, 0x58, 0x5a, 0xc1, 0x77, 0x39, 0xdc, 0x7b, 0xcf, 0x79, 0xee, 0x79,
- 0x5f, 0xe9, 0x76, 0xbb, 0xfc, 0x8f, 0xaa, 0xdd, 0xdd, 0xdd, 0x37, 0xee,
- 0xfe, 0xf8, 0x9a, 0xb7, 0x0b, 0x77, 0x7f, 0x32, 0x18, 0x0c, 0x8e, 0x6e,
- 0x04, 0x98, 0x59, 0xaf, 0xd7, 0xeb, 0xdd, 0x33, 0x33, 0xcc, 0x0c, 0x77,
- 0x07, 0xe0, 0xf4, 0xf4, 0xf4, 0x7e, 0xbf, 0xdf, 0x3f, 0xec, 0x74, 0x3a,
- 0xcf, 0x97, 0xcd, 0x39, 0x67, 0x42, 0x08, 0x65, 0x38, 0x1c, 0x7e, 0xac,
- 0xeb, 0xba, 0x00, 0x54, 0x39, 0x67, 0x57, 0x55, 0x26, 0x93, 0x09, 0xa5,
- 0x94, 0x15, 0x24, 0x84, 0xc0, 0xf6, 0xf6, 0x76, 0x07, 0x78, 0xbb, 0x84,
- 0x02, 0x4c, 0xa7, 0xd3, 0xaa, 0x94, 0xf2, 0xaa, 0xae, 0xeb, 0x83, 0x2b,
- 0x80, 0x8c, 0xaa, 0x62, 0x66, 0x6b, 0x90, 0x76, 0xbb, 0xdd, 0xda, 0xdc,
- 0xdc, 0xa4, 0xd5, 0x6a, 0x11, 0x63, 0x24, 0x84, 0xc0, 0x68, 0x34, 0x62,
- 0x3c, 0x1e, 0x3f, 0x5c, 0x59, 0x50, 0x55, 0x53, 0x2d, 0x1c, 0x7e, 0x48,
- 0xcc, 0x9a, 0x3f, 0x3f, 0x81, 0x00, 0xe0, 0xcc, 0x81, 0xf9, 0xea, 0xd6,
- 0x3d, 0x00, 0x7b, 0xfb, 0xec, 0xec, 0xed, 0xc7, 0x18, 0xbe, 0x55, 0x39,
- 0x67, 0x4f, 0x29, 0x31, 0x6d, 0x9c, 0x97, 0xcf, 0x1e, 0x21, 0x72, 0xd9,
- 0x78, 0x35, 0x29, 0x5f, 0x3b, 0x01, 0x90, 0xd4, 0x39, 0x78, 0xfd, 0x7e,
- 0xa7, 0x4a, 0x29, 0x99, 0xaa, 0x02, 0x4e, 0x0c, 0xf0, 0xe9, 0xf8, 0xec,
- 0xea, 0x02, 0xcb, 0xb2, 0x9e, 0x7c, 0x14, 0x1e, 0xb4, 0xb7, 0x40, 0xdc,
- 0x2b, 0x55, 0x25, 0xe7, 0x8c, 0x88, 0x10, 0x83, 0x10, 0xe3, 0x75, 0x23,
- 0xeb, 0xca, 0x6a, 0xb8, 0x39, 0x82, 0x78, 0x95, 0x73, 0xb6, 0x9c, 0x33,
- 0xb8, 0x13, 0x44, 0xd8, 0xb8, 0x01, 0xa0, 0xc5, 0x69, 0xb2, 0x51, 0xcc,
- 0x09, 0x41, 0x00, 0x16, 0x00, 0xd5, 0xc5, 0x06, 0xf3, 0x54, 0x08, 0x80,
- 0xf9, 0xa2, 0xb9, 0xb8, 0x63, 0xe6, 0x98, 0x3b, 0x59, 0x17, 0x75, 0x69,
- 0xa1, 0x49, 0xb6, 0x02, 0xb8, 0x6a, 0x41, 0xa4, 0x62, 0x52, 0x37, 0x0c,
- 0x7f, 0xcd, 0x69, 0xd4, 0x6e, 0xb4, 0x50, 0x45, 0x61, 0x72, 0x36, 0x5f,
- 0x00, 0x54, 0xd5, 0x52, 0x4a, 0xe0, 0x91, 0x2f, 0xa3, 0x73, 0x4e, 0xa6,
- 0x0d, 0x7f, 0x67, 0xbe, 0xae, 0x18, 0x84, 0x9f, 0x67, 0x97, 0x16, 0x44,
- 0xc4, 0xcc, 0x0c, 0x11, 0xa1, 0xc9, 0x46, 0xeb, 0x4e, 0x75, 0x6b, 0x88,
- 0x22, 0xc2, 0x45, 0x52, 0x80, 0x52, 0xb9, 0x3b, 0xc7, 0x27, 0x86, 0x08,
- 0x7c, 0xfe, 0x3a, 0xba, 0x75, 0x78, 0xa9, 0xd9, 0x6c, 0x8e, 0xc0, 0x51,
- 0x65, 0x1b, 0x5b, 0xfd, 0x77, 0xc7, 0x77, 0x9f, 0x82, 0xf3, 0xe3, 0xfb,
- 0xf8, 0x9f, 0x01, 0x22, 0x8c, 0x45, 0xc2, 0x8b, 0xdf, 0x47, 0x16, 0x21,
- 0x9e, 0x1c, 0x63, 0xa7, 0x31, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
- 0x44, 0xae, 0x42, 0x60, 0x82,
-}
-
-var __16x16_mimetypes_x_office_spreadsheet_png = []byte{
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
- 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
- 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00, 0x00, 0x00,
- 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0,
- 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00,
- 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18,
- 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x16,
- 0x14, 0x0d, 0x09, 0xd9, 0x88, 0x44, 0xfa, 0x00, 0x00, 0x02, 0x4d, 0x49,
- 0x44, 0x41, 0x54, 0x38, 0xcb, 0x95, 0x92, 0xdf, 0x4b, 0x53, 0x61, 0x18,
- 0xc7, 0x3f, 0x67, 0x9b, 0x6e, 0x7a, 0xd6, 0xfc, 0x55, 0xe0, 0x59, 0x8a,
- 0x95, 0x71, 0x08, 0x52, 0x21, 0x91, 0x2c, 0x8a, 0x0a, 0x94, 0x11, 0x14,
- 0x78, 0x21, 0x99, 0x14, 0x81, 0xdd, 0x48, 0x7f, 0x45, 0x63, 0x5d, 0x75,
- 0x1b, 0x34, 0xd0, 0x9b, 0x52, 0x83, 0x0a, 0xad, 0x0b, 0x43, 0x72, 0xd0,
- 0x85, 0x14, 0x14, 0x68, 0x77, 0x39, 0xcd, 0x6c, 0x94, 0x0c, 0xf4, 0x48,
- 0x4d, 0x5b, 0x5b, 0x4b, 0xcf, 0x39, 0x3b, 0xef, 0xe9, 0x62, 0x3f, 0xec,
- 0xd7, 0x2e, 0x7c, 0xae, 0xbe, 0x2f, 0xef, 0xf3, 0xfd, 0xbc, 0xdf, 0xf7,
- 0x7d, 0x5e, 0x69, 0x78, 0x78, 0xf8, 0xc9, 0xfa, 0xfa, 0x7a, 0x2f, 0xbb,
- 0xab, 0xcb, 0xc1, 0x60, 0x70, 0x1c, 0x80, 0x50, 0x28, 0x64, 0xef, 0xb6,
- 0x42, 0xa1, 0x90, 0x5d, 0x20, 0xb9, 0x0a, 0x22, 0x12, 0x89, 0xe4, 0x95,
- 0x84, 0xa6, 0x69, 0xf8, 0xfd, 0x0a, 0x00, 0x9a, 0xa6, 0xa1, 0x28, 0xfe,
- 0xbc, 0x5e, 0x63, 0x60, 0x60, 0xe0, 0x8f, 0x28, 0x45, 0x80, 0xa6, 0x69,
- 0x48, 0x52, 0x0e, 0x20, 0x49, 0xb9, 0xf5, 0xce, 0xde, 0x5a, 0xc9, 0xbb,
- 0x14, 0x01, 0x8a, 0x5f, 0xc1, 0x2b, 0x7b, 0x01, 0x88, 0xc5, 0x62, 0xf4,
- 0xf4, 0xf4, 0x00, 0x10, 0x8d, 0x46, 0x69, 0x69, 0x6d, 0x41, 0xb2, 0x25,
- 0xe6, 0xa3, 0xf3, 0xa5, 0x01, 0x86, 0x6e, 0x90, 0x21, 0x83, 0x84, 0x04,
- 0x40, 0x2a, 0x95, 0x22, 0x2f, 0x49, 0x7f, 0x4f, 0x91, 0x8f, 0x57, 0x1a,
- 0xe0, 0x71, 0xbb, 0x91, 0xbd, 0x5e, 0x0a, 0xaf, 0xe3, 0xf3, 0x55, 0x15,
- 0xfc, 0xf8, 0xaa, 0x76, 0x74, 0x49, 0xc0, 0xb6, 0xae, 0xe7, 0x4f, 0xcc,
- 0xb5, 0x7e, 0x8c, 0x3c, 0x67, 0xf5, 0xee, 0x1d, 0xb6, 0x16, 0x16, 0x89,
- 0xa7, 0x33, 0xb9, 0x26, 0xb9, 0x82, 0xc9, 0xb6, 0x56, 0xbc, 0x6d, 0xed,
- 0xff, 0x49, 0xe0, 0xf1, 0x20, 0xcb, 0x32, 0x00, 0xf6, 0xe8, 0x3d, 0x3e,
- 0xcd, 0xcd, 0xd1, 0x74, 0xe5, 0x22, 0x65, 0x9d, 0x2a, 0xc2, 0x21, 0x91,
- 0x15, 0x02, 0xc3, 0x14, 0x48, 0x0e, 0x0f, 0x4d, 0xcf, 0xa6, 0x78, 0x74,
- 0xbc, 0xe3, 0x65, 0xff, 0xec, 0xdb, 0xfe, 0x22, 0x40, 0xd7, 0x75, 0x00,
- 0x36, 0x1e, 0x8c, 0x51, 0xb3, 0xb2, 0x4c, 0xc3, 0x8d, 0x3e, 0xb2, 0xe9,
- 0x24, 0xc9, 0xf8, 0x2a, 0xa6, 0x10, 0x18, 0x96, 0x8d, 0xb3, 0xaa, 0x16,
- 0x53, 0x08, 0xac, 0x4e, 0x15, 0xe7, 0xd2, 0xea, 0x99, 0x11, 0xf5, 0xf0,
- 0xed, 0x22, 0xc0, 0xed, 0x76, 0x23, 0xcb, 0x32, 0x89, 0xc8, 0x34, 0xfb,
- 0xaf, 0x9e, 0xe7, 0x47, 0x3c, 0x56, 0x34, 0x9a, 0x42, 0xf0, 0xa1, 0xfe,
- 0x10, 0x9b, 0x86, 0x0b, 0x53, 0x64, 0x31, 0x24, 0x0b, 0xef, 0xb1, 0x7a,
- 0xd4, 0xa7, 0x93, 0x7d, 0xff, 0x24, 0xb0, 0x37, 0xbf, 0x61, 0x19, 0x5b,
- 0xe8, 0xd6, 0x8e, 0x59, 0x52, 0xca, 0xd9, 0xd3, 0xe1, 0x26, 0xfc, 0xb5,
- 0x0b, 0xc3, 0xd4, 0x51, 0x6b, 0xbd, 0x08, 0xcb, 0xe4, 0xe8, 0xe8, 0x43,
- 0x8f, 0xe3, 0xef, 0x04, 0x66, 0x75, 0x0d, 0xce, 0x7d, 0x0d, 0xe0, 0xab,
- 0x41, 0x17, 0x16, 0xba, 0x25, 0x70, 0xaa, 0x95, 0x34, 0x37, 0xa7, 0xa9,
- 0xcf, 0xae, 0x71, 0xb2, 0x71, 0x2f, 0x5f, 0x52, 0x29, 0x7c, 0x2b, 0xef,
- 0xc9, 0x78, 0x3c, 0xdb, 0xc5, 0x04, 0x81, 0x40, 0x20, 0x37, 0x8d, 0xc1,
- 0x41, 0xde, 0xdd, 0x1f, 0xe3, 0xe0, 0xf5, 0x5e, 0xea, 0x0e, 0x1c, 0xc1,
- 0x76, 0xb9, 0xa8, 0x3e, 0x5d, 0x87, 0xa8, 0x70, 0x10, 0xec, 0x90, 0x78,
- 0xfc, 0x39, 0x4d, 0x63, 0x7c, 0x91, 0xf6, 0xc9, 0x09, 0x2a, 0x55, 0x75,
- 0x5c, 0x0a, 0x87, 0xc3, 0x53, 0x89, 0x44, 0xe2, 0xc2, 0xef, 0xb3, 0xad,
- 0x9d, 0x99, 0x41, 0x7e, 0xf3, 0x1a, 0xf3, 0xdc, 0x09, 0xca, 0x1a, 0xaa,
- 0xf1, 0x9c, 0xb5, 0xd1, 0x0d, 0x41, 0x66, 0xc3, 0x64, 0x7a, 0x4a, 0xd0,
- 0x33, 0xfb, 0x8a, 0x0a, 0x55, 0x7d, 0x71, 0x6d, 0x61, 0x21, 0x50, 0xea,
- 0x7f, 0x30, 0xd2, 0xdd, 0x7d, 0x49, 0x5f, 0x5a, 0xba, 0xe9, 0x4e, 0x26,
- 0x55, 0xe7, 0xcf, 0x4c, 0xb9, 0x6d, 0x83, 0x90, 0x65, 0xc3, 0xa5, 0x28,
- 0xcb, 0x07, 0xbb, 0xba, 0x6e, 0x9d, 0x1a, 0x1a, 0x9a, 0x00, 0xf8, 0x05,
- 0xf4, 0xf5, 0x23, 0xe9, 0x30, 0xeb, 0x2d, 0xf9, 0x00, 0x00, 0x00, 0x00,
- 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
-}
-
-var __32x32_categories_applications_accessories_png = []byte{
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
- 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
- 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x00,
- 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
- 0x88, 0x00, 0x00, 0x08, 0x66, 0x49, 0x44, 0x41, 0x54, 0x58, 0x85, 0xcd,
- 0x97, 0x7b, 0x70, 0x54, 0xd5, 0x1d, 0xc7, 0xbf, 0xe7, 0x9c, 0xfb, 0xd8,
- 0x57, 0x36, 0x4b, 0xb2, 0xcb, 0x12, 0x24, 0x04, 0x08, 0x41, 0x9e, 0x85,
- 0x00, 0x2d, 0x10, 0x71, 0x24, 0xf2, 0x68, 0x67, 0x64, 0xa0, 0x58, 0xed,
- 0xbb, 0xb4, 0x5a, 0x19, 0x2d, 0x4a, 0x18, 0x1e, 0x82, 0x05, 0x9c, 0x59,
- 0x0d, 0x2a, 0x82, 0xe3, 0x28, 0x1d, 0x5b, 0x69, 0x61, 0x04, 0x44, 0x0a,
- 0x8c, 0x8f, 0x62, 0x47, 0x0a, 0x33, 0x3c, 0x85, 0x20, 0x52, 0x85, 0x28,
- 0x98, 0x28, 0x12, 0x1e, 0x9b, 0x40, 0x08, 0xc9, 0xe6, 0xb1, 0x8f, 0xec,
- 0xde, 0xc7, 0x39, 0xa7, 0x7f, 0x24, 0x4b, 0x13, 0x12, 0x20, 0xfe, 0xd5,
- 0xfe, 0x66, 0x7e, 0x73, 0xce, 0xde, 0xfd, 0x9e, 0xdf, 0xef, 0x73, 0x7f,
- 0xe7, 0x9e, 0x73, 0xcf, 0x05, 0xfe, 0x07, 0x76, 0x74, 0x33, 0x9e, 0x4c,
- 0xf7, 0x49, 0x77, 0x82, 0x35, 0x6b, 0xd6, 0x64, 0x82, 0xf2, 0x66, 0x42,
- 0xc9, 0x4f, 0x96, 0x2f, 0x5d, 0xf1, 0xfe, 0x9d, 0x02, 0xae, 0x5d, 0xbb,
- 0xb6, 0x8f, 0x80, 0x55, 0x2b, 0x89, 0x98, 0xfe, 0xc7, 0xa7, 0x9f, 0xdd,
- 0x7f, 0x3b, 0xed, 0x91, 0xb7, 0x50, 0xc0, 0x08, 0xce, 0x4d, 0xfe, 0x5d,
- 0x5b, 0x6e, 0xda, 0x9d, 0x48, 0x51, 0xb1, 0xc2, 0xed, 0xf6, 0x70, 0x46,
- 0x95, 0x0d, 0xa1, 0x50, 0xc8, 0x75, 0x27, 0x00, 0x45, 0x27, 0xaf, 0x7b,
- 0xbd, 0x99, 0x42, 0x53, 0x1d, 0x7f, 0xdd, 0xb0, 0x61, 0x83, 0x7a, 0x2b,
- 0xdd, 0xae, 0x5d, 0x60, 0x9a, 0xaa, 0xbc, 0xd7, 0xf1, 0x5a, 0x17, 0x80,
- 0xb5, 0x6b, 0x4b, 0xf3, 0x29, 0x65, 0x4f, 0xce, 0x99, 0x3d, 0x87, 0xe5,
- 0x0f, 0x1c, 0xe4, 0x76, 0x79, 0x1c, 0xcf, 0xde, 0x2e, 0xf9, 0x9a, 0x35,
- 0xab, 0x8b, 0x28, 0xa1, 0x33, 0x67, 0xcd, 0x9c, 0x4d, 0xf3, 0x72, 0xfb,
- 0x07, 0x5b, 0x62, 0x4d, 0x8b, 0x6e, 0xa5, 0xed, 0x97, 0xa2, 0x2b, 0x33,
- 0x83, 0xdf, 0xcb, 0xbf, 0x2d, 0x00, 0x61, 0xca, 0xaf, 0x47, 0x8d, 0x1a,
- 0xe5, 0xe0, 0x5c, 0x62, 0xec, 0xb8, 0xef, 0x3b, 0x09, 0x25, 0x25, 0xeb,
- 0xd6, 0x95, 0x0e, 0xec, 0xfe, 0x8e, 0x76, 0x31, 0xcd, 0xa1, 0x6f, 0x2e,
- 0x9e, 0x32, 0xd5, 0x69, 0x59, 0x36, 0xc6, 0x8c, 0x1e, 0xeb, 0x52, 0x14,
- 0xb6, 0xa0, 0x3b, 0xed, 0xf1, 0x2d, 0x28, 0xa4, 0x4c, 0x7f, 0x66, 0xf0,
- 0x84, 0xce, 0x15, 0xed, 0x02, 0xc0, 0x05, 0x8f, 0x85, 0xc3, 0xe1, 0x24,
- 0xa5, 0x14, 0x90, 0x40, 0xd1, 0xc4, 0x22, 0x9d, 0x69, 0x8e, 0x37, 0xbb,
- 0x0b, 0x7a, 0xa9, 0xfa, 0xc2, 0x13, 0x7e, 0x7f, 0x76, 0x4e, 0xa6, 0xd7,
- 0x47, 0xa4, 0x94, 0x68, 0x88, 0xd4, 0x0b, 0xce, 0x45, 0xf3, 0xcd, 0xba,
- 0x3d, 0xeb, 0xa1, 0x13, 0xca, 0xde, 0xbb, 0x7b, 0xd2, 0x42, 0x87, 0xa2,
- 0xb8, 0x3b, 0xfd, 0xd7, 0x05, 0x20, 0x95, 0xb0, 0x5f, 0x6b, 0x8e, 0xb6,
- 0xd4, 0x44, 0x1a, 0xeb, 0xa5, 0x94, 0x12, 0xb9, 0xfd, 0xf2, 0x98, 0xc2,
- 0xd4, 0xc9, 0x2f, 0xad, 0x2b, 0x9d, 0xd6, 0x51, 0xf7, 0xe2, 0x8b, 0x2f,
- 0x06, 0x28, 0x21, 0x2f, 0x4d, 0xbe, 0x67, 0x8a, 0x87, 0x73, 0x0e, 0x4a,
- 0x09, 0xca, 0x8e, 0x1f, 0x33, 0x2c, 0xc9, 0x1f, 0xbe, 0x39, 0x66, 0x2f,
- 0x9f, 0xb2, 0x36, 0xab, 0xdf, 0x84, 0x9c, 0xcc, 0xe0, 0x44, 0x02, 0x88,
- 0xdb, 0x03, 0x84, 0x42, 0x21, 0x61, 0x1b, 0xc6, 0x23, 0x87, 0x8f, 0x1c,
- 0x4a, 0x32, 0x46, 0x61, 0xdb, 0x36, 0xa6, 0x16, 0x4f, 0x73, 0xe9, 0x8a,
- 0xfe, 0xb7, 0x50, 0x28, 0xa4, 0xa4, 0x75, 0x0e, 0x97, 0xfa, 0xea, 0x98,
- 0xd1, 0x85, 0x3a, 0x64, 0xdb, 0xef, 0x2f, 0xbe, 0x3c, 0x95, 0x02, 0xb0,
- 0x71, 0xc5, 0xd2, 0x15, 0x5f, 0x77, 0x8c, 0x77, 0xec, 0x2d, 0xdc, 0x4b,
- 0x35, 0xc7, 0xbc, 0x41, 0x63, 0x17, 0x3a, 0x64, 0xf2, 0x20, 0x8e, 0xef,
- 0x9a, 0x7e, 0x7b, 0x00, 0x00, 0x58, 0xbe, 0x7c, 0xd5, 0x09, 0x2e, 0xc4,
- 0xbe, 0xf3, 0x55, 0xe7, 0x2d, 0x00, 0x70, 0xb9, 0xdc, 0x08, 0xf6, 0xe9,
- 0xd3, 0xdb, 0xe3, 0xd5, 0x17, 0x00, 0xc0, 0xcb, 0x2f, 0xaf, 0x1e, 0x4f,
- 0x08, 0x1e, 0x1c, 0x9c, 0x3f, 0x44, 0x13, 0x42, 0x80, 0x73, 0x1b, 0xe7,
- 0xab, 0xaa, 0x5a, 0x63, 0xac, 0x75, 0x55, 0xa7, 0xe4, 0x9b, 0x90, 0xc1,
- 0x14, 0xb6, 0x6b, 0xd8, 0xa4, 0xc5, 0x4e, 0x2a, 0xaf, 0x40, 0xda, 0x97,
- 0x51, 0xf4, 0xf0, 0x47, 0x77, 0x06, 0x00, 0x80, 0xa4, 0x30, 0x16, 0x7c,
- 0x76, 0xea, 0xdf, 0x16, 0xa5, 0x04, 0x9c, 0x73, 0x14, 0x4d, 0xbc, 0xd7,
- 0x45, 0x08, 0x7d, 0xfe, 0x85, 0x17, 0x5e, 0x08, 0xaa, 0x9a, 0xb6, 0x75,
- 0x6a, 0xf1, 0x0c, 0xa7, 0x65, 0x59, 0x50, 0x14, 0x86, 0x23, 0x47, 0x0f,
- 0x25, 0x6c, 0xce, 0x4b, 0x42, 0x25, 0xa1, 0x68, 0xa7, 0xe0, 0x3a, 0x7b,
- 0x23, 0x38, 0xe8, 0x3e, 0x9f, 0x27, 0x7b, 0x04, 0x44, 0xaa, 0x0c, 0x52,
- 0x08, 0x48, 0xc9, 0x7b, 0x06, 0xb0, 0x6a, 0xf1, 0xaa, 0x2b, 0x04, 0xe4,
- 0xa5, 0x93, 0x9f, 0x9d, 0x68, 0xa5, 0x94, 0xc0, 0xb6, 0x6d, 0x14, 0x16,
- 0x8e, 0xd3, 0x74, 0xa7, 0xba, 0x3b, 0x2b, 0xdb, 0xdf, 0xdf, 0xed, 0xf6,
- 0x10, 0x29, 0x25, 0x22, 0x8d, 0x11, 0x11, 0x8b, 0xc5, 0xbe, 0x59, 0xb6,
- 0xe4, 0x99, 0xed, 0x1d, 0xc7, 0x97, 0x6d, 0xc6, 0x03, 0x8a, 0xea, 0x7d,
- 0x28, 0x77, 0xe4, 0x63, 0x0e, 0x9e, 0xd8, 0x0f, 0xc1, 0x53, 0x10, 0x42,
- 0xe0, 0x93, 0x77, 0x67, 0xf5, 0x0c, 0x00, 0x00, 0x34, 0xc5, 0xb1, 0xae,
- 0xba, 0xba, 0x3a, 0x66, 0x5a, 0x26, 0xa4, 0x94, 0x18, 0x98, 0x97, 0xaf,
- 0x51, 0x4a, 0x26, 0x8c, 0x1c, 0x3e, 0xd2, 0x6d, 0xdb, 0x36, 0x74, 0x5d,
- 0xc3, 0xc7, 0x47, 0x0f, 0xa6, 0x6c, 0xd3, 0xfc, 0x3d, 0x21, 0x44, 0xa6,
- 0xc7, 0x7d, 0xba, 0x05, 0xd9, 0x84, 0xb2, 0x6d, 0x43, 0x27, 0x2d, 0x74,
- 0x4a, 0xab, 0x0a, 0xdc, 0xac, 0x81, 0xe0, 0x02, 0x82, 0x73, 0x4c, 0x98,
- 0xb3, 0xb3, 0xe7, 0x00, 0x25, 0x25, 0x25, 0x86, 0x6d, 0xda, 0x4f, 0x1c,
- 0x3a, 0x74, 0x20, 0xae, 0xaa, 0x2a, 0x4c, 0xd3, 0xc4, 0xfd, 0xc5, 0xd3,
- 0xf0, 0xc5, 0x99, 0x72, 0x00, 0x40, 0x45, 0xe5, 0x59, 0x83, 0x73, 0xb9,
- 0x73, 0xd9, 0xb2, 0x95, 0xe5, 0x1d, 0xc7, 0x09, 0xa6, 0x6c, 0xee, 0x3b,
- 0x64, 0xba, 0xcb, 0x99, 0x91, 0x0b, 0xbb, 0xf5, 0x04, 0x2c, 0xd3, 0x02,
- 0xe7, 0x16, 0x84, 0xe0, 0x90, 0xa2, 0x87, 0x53, 0x90, 0xb6, 0xe5, 0xcb,
- 0x57, 0xfc, 0xc3, 0x30, 0x52, 0x5f, 0x36, 0x44, 0xae, 0x0b, 0x21, 0x04,
- 0x74, 0x5d, 0x03, 0x63, 0x0a, 0x6a, 0xaf, 0x5d, 0x41, 0x45, 0x65, 0x85,
- 0xc1, 0x48, 0x72, 0x71, 0x47, 0x7d, 0xd9, 0x56, 0xfc, 0x46, 0xd5, 0xb3,
- 0xa6, 0xe6, 0x14, 0xfc, 0x5c, 0xb3, 0xe2, 0x07, 0x20, 0x6c, 0x03, 0x57,
- 0x2f, 0x9e, 0x03, 0x37, 0x2d, 0x08, 0x2e, 0x70, 0x72, 0xf7, 0x2f, 0xbf,
- 0x1b, 0x00, 0x00, 0x98, 0x75, 0x75, 0x0b, 0x8e, 0x1e, 0x3e, 0x48, 0x9d,
- 0x4e, 0x07, 0x52, 0x86, 0x81, 0xc9, 0x45, 0xf7, 0xa2, 0xfc, 0xd8, 0x61,
- 0x69, 0x35, 0x46, 0x4a, 0x17, 0x2d, 0x0a, 0xdd, 0xd8, 0x78, 0x4e, 0x6c,
- 0x43, 0x3f, 0x02, 0xfa, 0xe7, 0x82, 0x09, 0x7f, 0x70, 0x72, 0xa3, 0x02,
- 0xdc, 0xb8, 0x86, 0x78, 0xb4, 0x19, 0xf5, 0x35, 0x61, 0x48, 0xc1, 0x21,
- 0x04, 0xc7, 0xf8, 0x99, 0x9b, 0x3a, 0xc5, 0x56, 0xba, 0x64, 0xeb, 0xc6,
- 0x3c, 0xef, 0xee, 0x58, 0xa6, 0x4c, 0x9c, 0x8c, 0x43, 0xbd, 0xb2, 0xe0,
- 0xfd, 0xf0, 0x7d, 0xb4, 0x9e, 0x3d, 0x03, 0xe7, 0xb5, 0xab, 0xc4, 0xe5,
- 0xeb, 0xf5, 0x14, 0x80, 0x57, 0x00, 0x40, 0x4a, 0x90, 0x13, 0xef, 0x28,
- 0x3b, 0xfa, 0x0d, 0xfd, 0x91, 0x43, 0x77, 0x64, 0xc1, 0x68, 0xde, 0x0d,
- 0x29, 0x6d, 0x84, 0x2b, 0xcf, 0x26, 0x00, 0xb8, 0x05, 0x17, 0x20, 0xe0,
- 0x90, 0xc2, 0xee, 0x39, 0xc0, 0x1e, 0x40, 0xbf, 0xe6, 0x41, 0xbe, 0xbc,
- 0x5a, 0x33, 0x6b, 0x4a, 0xe5, 0x39, 0x7c, 0x23, 0x80, 0xea, 0xfd, 0xfb,
- 0x30, 0xcc, 0x17, 0x44, 0x9f, 0xdc, 0xa1, 0x38, 0x5d, 0x1f, 0xee, 0xbd,
- 0xc1, 0x85, 0x07, 0x9c, 0xad, 0x38, 0x7c, 0x7c, 0x2b, 0x7d, 0xd4, 0xe5,
- 0x0d, 0x14, 0x06, 0x06, 0xcc, 0x54, 0x8c, 0xe8, 0xbf, 0x20, 0x85, 0x8d,
- 0xba, 0xea, 0x4b, 0x36, 0xb7, 0xad, 0xd3, 0x84, 0x92, 0x71, 0x42, 0x08,
- 0x27, 0x21, 0xc0, 0xe7, 0x7b, 0x1e, 0xef, 0x94, 0xa3, 0xcb, 0x14, 0xec,
- 0x02, 0x3c, 0xdb, 0x29, 0x5d, 0xbd, 0x93, 0xd2, 0x6a, 0xcb, 0xed, 0xbe,
- 0xe2, 0xe3, 0x8e, 0x2f, 0x32, 0x6d, 0xcd, 0x99, 0x6c, 0x8e, 0x22, 0xb1,
- 0x77, 0x77, 0x92, 0x12, 0xba, 0xf1, 0x52, 0xa2, 0x31, 0x19, 0x6f, 0x6d,
- 0xc5, 0x88, 0xec, 0xbb, 0x9c, 0x4e, 0xa6, 0x7e, 0xd8, 0xd7, 0x9f, 0x5d,
- 0x13, 0x59, 0xa2, 0xbd, 0x1e, 0xdb, 0x98, 0xed, 0x8a, 0x9e, 0x2f, 0x03,
- 0x37, 0x23, 0x48, 0xc6, 0x63, 0x68, 0xb8, 0x5a, 0x63, 0x9a, 0x92, 0xcf,
- 0x05, 0x00, 0x21, 0x38, 0x04, 0x17, 0x18, 0x33, 0xe3, 0xb5, 0x5b, 0x57,
- 0x60, 0x3b, 0x70, 0x3f, 0x18, 0xdb, 0x91, 0x17, 0x0c, 0xfa, 0xdc, 0x9a,
- 0xa6, 0x9a, 0xb6, 0x0d, 0x4d, 0xd3, 0x00, 0x21, 0x50, 0x71, 0xf9, 0x92,
- 0x6c, 0xd5, 0xf9, 0x3b, 0xf3, 0xe2, 0x62, 0xde, 0x26, 0x2f, 0xf1, 0x36,
- 0xd8, 0xad, 0x0f, 0x06, 0x4d, 0xaa, 0x0c, 0xf3, 0xe7, 0xd0, 0x2c, 0xb7,
- 0xd7, 0xa7, 0x32, 0x86, 0xd4, 0x25, 0x0b, 0x27, 0x7f, 0xfc, 0x01, 0xfa,
- 0x3f, 0x1e, 0x84, 0x35, 0xb2, 0x36, 0x21, 0x09, 0x9e, 0xbd, 0x6f, 0x2e,
- 0x2e, 0x96, 0x6d, 0x05, 0x84, 0x10, 0x20, 0x00, 0x84, 0xb0, 0xba, 0xaf,
- 0xc0, 0x16, 0x60, 0x9a, 0xee, 0x74, 0xbe, 0x5f, 0x90, 0x9b, 0x1b, 0x48,
- 0x24, 0x93, 0x66, 0x65, 0x38, 0x5c, 0x73, 0xb1, 0xb6, 0xf6, 0x4f, 0x95,
- 0xe1, 0xcb, 0x11, 0x49, 0x08, 0x72, 0x7c, 0xbd, 0xa4, 0x92, 0xc0, 0x69,
- 0x00, 0xa8, 0x8e, 0xf2, 0x5f, 0xd5, 0xb6, 0x34, 0x71, 0xa2, 0x50, 0x44,
- 0x92, 0x31, 0xb3, 0x6a, 0x40, 0xd8, 0xfe, 0x46, 0x8f, 0xa3, 0x26, 0x5a,
- 0x8f, 0xd1, 0x39, 0xf9, 0xa8, 0xdb, 0x14, 0x41, 0xe4, 0x03, 0xa3, 0xe5,
- 0xaa, 0x43, 0xac, 0x4f, 0xc7, 0x17, 0x9c, 0x43, 0x70, 0x8e, 0x2f, 0xf7,
- 0x3f, 0xdd, 0x15, 0x60, 0x3b, 0xe0, 0xd7, 0x15, 0xe5, 0xef, 0x03, 0x02,
- 0x81, 0xcc, 0x9a, 0xfa, 0xfa, 0x96, 0x48, 0x4b, 0xcb, 0xd6, 0x3e, 0x42,
- 0x0c, 0xfc, 0x19, 0xe7, 0x25, 0xb6, 0x90, 0xeb, 0x0c, 0xd3, 0x94, 0xba,
- 0xc3, 0x41, 0x15, 0x4a, 0x87, 0x00, 0x40, 0x08, 0xb0, 0xbd, 0x52, 0x4f,
- 0xd8, 0x90, 0x48, 0x58, 0x31, 0x75, 0xfc, 0xfa, 0xa7, 0x94, 0x71, 0x6f,
- 0x17, 0x21, 0xb0, 0xd0, 0x8b, 0x33, 0xd7, 0x2e, 0x60, 0x44, 0x70, 0x20,
- 0x5a, 0xff, 0xa9, 0xb9, 0x93, 0x3f, 0xc5, 0x8d, 0xc3, 0x47, 0xdb, 0x1e,
- 0x20, 0x30, 0xe2, 0xbe, 0xe7, 0xba, 0x02, 0x50, 0x4a, 0x57, 0xe6, 0xfa,
- 0xfd, 0x59, 0x49, 0xc3, 0xe0, 0xf1, 0x54, 0xea, 0xe8, 0x2f, 0x84, 0x98,
- 0x5f, 0x0c, 0xd8, 0x00, 0xa0, 0x53, 0xfa, 0x03, 0x4d, 0x51, 0x48, 0xd2,
- 0x30, 0x52, 0xdc, 0xb6, 0x3f, 0xef, 0x70, 0x47, 0xf1, 0x60, 0x86, 0x0f,
- 0x8c, 0x39, 0x08, 0x6f, 0x49, 0xc0, 0x4c, 0x54, 0xc0, 0x5f, 0x9c, 0x09,
- 0x6d, 0xba, 0x69, 0xd6, 0x36, 0x47, 0xec, 0x31, 0x83, 0x87, 0x78, 0x3d,
- 0xba, 0xbe, 0x26, 0xad, 0x97, 0xed, 0x3b, 0xe1, 0xcd, 0xab, 0x80, 0x02,
- 0x80, 0x24, 0xe4, 0x21, 0x87, 0xa6, 0xd1, 0xeb, 0xcd, 0xcd, 0x11, 0x8b,
- 0xf3, 0x1b, 0x27, 0xd6, 0xb7, 0x81, 0xd1, 0x9a, 0xaa, 0x4e, 0xd1, 0x54,
- 0x15, 0xd7, 0x1b, 0x1b, 0xe3, 0x75, 0xc0, 0x47, 0x00, 0x18, 0x00, 0xa6,
- 0x16, 0xf2, 0x48, 0x4b, 0x6b, 0x1c, 0xb9, 0x19, 0x01, 0x7c, 0xf5, 0xdc,
- 0x4e, 0x08, 0xce, 0x11, 0x6d, 0x6a, 0x90, 0xae, 0x62, 0xab, 0xf6, 0xe2,
- 0xd5, 0xda, 0x26, 0x8f, 0xae, 0x13, 0x00, 0xf7, 0x00, 0x80, 0x4c, 0x3f,
- 0x84, 0x82, 0xa3, 0xe2, 0x68, 0x69, 0x57, 0x00, 0x02, 0xb8, 0x08, 0x00,
- 0xcb, 0xb6, 0xd9, 0x5c, 0xa0, 0x16, 0x80, 0x73, 0x1d, 0x30, 0x4d, 0x57,
- 0xd5, 0xfd, 0x63, 0x0b, 0x0a, 0xb2, 0xae, 0x47, 0xa3, 0x89, 0x46, 0x29,
- 0xb7, 0x2d, 0x06, 0x9c, 0x00, 0x72, 0x4a, 0xe7, 0x63, 0x8e, 0x98, 0x8d,
- 0xe1, 0x5f, 0x37, 0xd5, 0x21, 0xe0, 0xce, 0x80, 0x71, 0xc2, 0xc0, 0x57,
- 0xaf, 0xd5, 0xe0, 0xc2, 0xd7, 0x61, 0x12, 0x37, 0x45, 0x1e, 0xc9, 0x92,
- 0x01, 0x0a, 0x40, 0xef, 0xa5, 0xf4, 0xfe, 0xf8, 0x2f, 0x90, 0x10, 0xd2,
- 0x99, 0x7e, 0x17, 0x0c, 0x99, 0xb8, 0xa4, 0x13, 0x40, 0x7a, 0x15, 0xc4,
- 0x02, 0x3e, 0x5f, 0x56, 0x34, 0x99, 0x54, 0xb7, 0x37, 0x35, 0x1d, 0x00,
- 0x21, 0x19, 0x01, 0x8f, 0x27, 0x7f, 0x58, 0xff, 0xfe, 0x19, 0x97, 0x1a,
- 0x1a, 0x52, 0x35, 0x8d, 0x8d, 0x15, 0x8b, 0x6d, 0x7b, 0x33, 0x80, 0xde,
- 0x03, 0x73, 0x90, 0xd1, 0x3b, 0x9b, 0x6e, 0x60, 0x39, 0xf7, 0xe8, 0xfa,
- 0x7c, 0xa0, 0xfc, 0x8d, 0x53, 0x18, 0xdb, 0x77, 0x10, 0xaa, 0xcb, 0x1a,
- 0x70, 0xe5, 0x80, 0x03, 0x8e, 0x7c, 0x07, 0x02, 0x9a, 0x0e, 0x55, 0x55,
- 0xc1, 0x21, 0x11, 0xbc, 0x7b, 0x08, 0x54, 0x06, 0x48, 0x22, 0x21, 0x85,
- 0x84, 0xe0, 0x9d, 0x57, 0x01, 0x01, 0x80, 0x1d, 0x8c, 0x3d, 0xe6, 0xcf,
- 0xcc, 0x7c, 0x75, 0x78, 0x6e, 0x6e, 0x86, 0x68, 0xbf, 0x98, 0xb2, 0x2c,
- 0x59, 0x5e, 0x55, 0x15, 0x6d, 0x16, 0x62, 0xdf, 0x52, 0xcb, 0x2a, 0x6d,
- 0x6a, 0xab, 0x96, 0xf2, 0xca, 0x12, 0xb2, 0xba, 0xef, 0x5d, 0xfd, 0xa6,
- 0xf6, 0xce, 0x9b, 0xa6, 0x99, 0xb1, 0x4f, 0xc0, 0x2b, 0x5b, 0x60, 0x6c,
- 0x6a, 0xc2, 0x50, 0x7f, 0x2e, 0x02, 0x9e, 0x4c, 0x48, 0x29, 0xa1, 0xab,
- 0x2a, 0x2e, 0x34, 0xd5, 0x21, 0x36, 0x21, 0x8e, 0xbe, 0xbf, 0xf5, 0x82,
- 0x31, 0x40, 0x4a, 0x00, 0x52, 0xe2, 0x5a, 0xf8, 0x02, 0x00, 0x20, 0xfd,
- 0x5d, 0x70, 0xe3, 0xc3, 0x64, 0x07, 0xa5, 0x0b, 0x18, 0x63, 0x4b, 0x28,
- 0x63, 0x4c, 0x08, 0x41, 0x84, 0x10, 0xe5, 0x95, 0xb6, 0xfd, 0x7c, 0x08,
- 0xa8, 0x6a, 0xaf, 0x14, 0x7d, 0x65, 0x09, 0x66, 0x14, 0xe4, 0xa9, 0x6f,
- 0xe6, 0x8d, 0x7a, 0xd4, 0x61, 0x25, 0xbf, 0x85, 0x9d, 0x0a, 0x83, 0x10,
- 0x09, 0x18, 0x1c, 0xb1, 0xf7, 0x62, 0x48, 0x7e, 0x9a, 0x02, 0x03, 0x83,
- 0x6d, 0xdb, 0xe8, 0x75, 0xbf, 0x0b, 0x39, 0x8f, 0x78, 0x01, 0x22, 0xdb,
- 0x1e, 0x02, 0x48, 0x48, 0x29, 0xe1, 0xf6, 0x4f, 0xc7, 0xc5, 0xf2, 0x8d,
- 0x5d, 0x01, 0xee, 0x64, 0x87, 0xb6, 0xc3, 0xaf, 0x59, 0xe4, 0xdb, 0xbe,
- 0x05, 0x3f, 0xf4, 0xb9, 0xb3, 0x0a, 0x01, 0x69, 0x00, 0x84, 0x41, 0x4a,
- 0x09, 0x48, 0x01, 0x09, 0x09, 0x08, 0xde, 0xd6, 0x4a, 0x01, 0x29, 0x05,
- 0x00, 0x01, 0x48, 0x09, 0x29, 0xdb, 0x4f, 0x42, 0xed, 0xfd, 0xcb, 0x67,
- 0xb6, 0xde, 0x00, 0xe8, 0xd1, 0xcb, 0x08, 0x00, 0x54, 0x03, 0x9b, 0x25,
- 0x91, 0xbe, 0x2b, 0xe7, 0xf6, 0x02, 0xd8, 0xdb, 0xd3, 0x61, 0xb7, 0x0d,
- 0x09, 0xc0, 0xea, 0x71, 0x05, 0xd0, 0x06, 0xab, 0x01, 0xd0, 0xdb, 0x5b,
- 0xb5, 0x43, 0x9b, 0x76, 0x86, 0xff, 0xee, 0xae, 0x1c, 0x6d, 0x7b, 0x89,
- 0xd5, 0xc1, 0xcd, 0x76, 0x4f, 0xb6, 0xb7, 0xf6, 0x77, 0x01, 0xb8, 0xd9,
- 0x48, 0x7b, 0x32, 0xda, 0xde, 0x4f, 0x7b, 0xda, 0x64, 0x07, 0x6f, 0x9f,
- 0x0f, 0x48, 0xfc, 0xbf, 0xd9, 0x7f, 0x00, 0x76, 0x69, 0xe5, 0x89, 0x4b,
- 0x1e, 0x7c, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
- 0x42, 0x60, 0x82,
-}
-
-var __32x32_places_folder_png = []byte{
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
- 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
- 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x00,
- 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
- 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0d,
- 0xd7, 0x00, 0x00, 0x0d, 0xd7, 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00,
- 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61,
- 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63,
- 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00,
- 0x00, 0x04, 0x15, 0x49, 0x44, 0x41, 0x54, 0x58, 0x85, 0xed, 0x97, 0x3d,
- 0x6f, 0x1c, 0x45, 0x18, 0xc7, 0x7f, 0x33, 0xbb, 0x77, 0x7b, 0xaf, 0xf6,
- 0x39, 0x91, 0x30, 0x09, 0x05, 0x56, 0x94, 0xc2, 0x1f, 0x00, 0x09, 0x05,
- 0x21, 0x53, 0x6e, 0x95, 0x82, 0x1a, 0x89, 0x02, 0x5a, 0x3a, 0x3e, 0x40,
- 0x24, 0x3e, 0x40, 0x4a, 0x84, 0x44, 0x85, 0x68, 0xa1, 0x43, 0x48, 0xa7,
- 0x40, 0x17, 0xc9, 0x8a, 0x02, 0x8a, 0xd2, 0x45, 0xc2, 0xc6, 0xc4, 0x28,
- 0x16, 0xc6, 0xf7, 0xba, 0x77, 0xde, 0x97, 0x99, 0x9d, 0x19, 0x8a, 0x7b,
- 0xc9, 0x3a, 0x77, 0x8e, 0x13, 0x72, 0x52, 0x28, 0xf8, 0x4b, 0x8f, 0x76,
- 0x76, 0x76, 0xf7, 0x79, 0x7e, 0xf3, 0x3c, 0x33, 0xb3, 0xbb, 0x22, 0x0c,
- 0x43, 0x5e, 0xa7, 0xe4, 0x6b, 0x8d, 0xfe, 0x5f, 0x00, 0xf0, 0x01, 0x6e,
- 0xdc, 0xb8, 0xe1, 0x2b, 0xa5, 0x7e, 0x36, 0xc6, 0xbc, 0x77, 0xd1, 0x03,
- 0x42, 0x88, 0xdc, 0x5a, 0xfb, 0xf9, 0xc3, 0x87, 0x0f, 0xbf, 0x5c, 0x19,
- 0x40, 0x9a, 0xa6, 0x5b, 0x95, 0x4a, 0xe5, 0x9d, 0x9b, 0x37, 0x6f, 0xfa,
- 0x49, 0x92, 0xe0, 0x9c, 0x03, 0xc0, 0x5a, 0x0b, 0x30, 0x3f, 0x9f, 0xb6,
- 0xfd, 0x3b, 0x77, 0xee, 0xdc, 0xde, 0xde, 0xde, 0xfe, 0xfe, 0xd1, 0xa3,
- 0x47, 0xc7, 0x2b, 0x01, 0x50, 0x4a, 0x65, 0xd5, 0x6a, 0xd5, 0x1d, 0x1d,
- 0x1d, 0xd1, 0xe9, 0x74, 0x70, 0xce, 0x2d, 0x35, 0x00, 0x21, 0x04, 0x9b,
- 0x9b, 0x9b, 0xf9, 0xc1, 0xc1, 0xc1, 0x47, 0xc0, 0xed, 0x95, 0x00, 0x68,
- 0xad, 0xd3, 0x2c, 0xcb, 0xc4, 0xa5, 0x4b, 0x1b, 0x18, 0x63, 0xb0, 0xd6,
- 0x9e, 0x09, 0x5c, 0xcc, 0x84, 0x10, 0x82, 0x6a, 0xb5, 0x5a, 0x3f, 0x3c,
- 0x3c, 0xfc, 0x62, 0x7b, 0x7b, 0xfb, 0xd6, 0xac, 0x7f, 0x99, 0x9c, 0x73,
- 0xda, 0x5a, 0xfb, 0xf1, 0xde, 0xde, 0xde, 0x8f, 0xcf, 0x05, 0x00, 0xb2,
- 0x2c, 0xcb, 0xbc, 0x4e, 0xa7, 0x4b, 0xa7, 0xd3, 0x99, 0x03, 0xcc, 0x8e,
- 0xb3, 0x20, 0xc5, 0x40, 0x5b, 0x5b, 0x5b, 0xf5, 0x46, 0xa3, 0x41, 0xb3,
- 0xd9, 0x44, 0x08, 0x81, 0x10, 0x02, 0x00, 0x29, 0xe5, 0xbc, 0x1d, 0x45,
- 0x11, 0xf7, 0xee, 0xdd, 0xbb, 0x05, 0x3c, 0x1f, 0xe0, 0xf2, 0xe5, 0xcb,
- 0x69, 0xbf, 0xdf, 0xf7, 0x36, 0x36, 0x5a, 0x68, 0xad, 0x17, 0x00, 0x96,
- 0x95, 0x62, 0xa6, 0x38, 0x8e, 0x01, 0xe6, 0x10, 0x45, 0x8b, 0xe3, 0x18,
- 0x63, 0x4c, 0xed, 0xbc, 0xe0, 0x73, 0x80, 0xdd, 0xdd, 0x5d, 0x75, 0xed,
- 0xda, 0x35, 0xd9, 0xeb, 0xf5, 0xe6, 0x19, 0x00, 0x96, 0x82, 0xcc, 0xb2,
- 0x51, 0xd4, 0x6c, 0xc4, 0xc5, 0xe0, 0x52, 0xca, 0x19, 0x40, 0xe5, 0x42,
- 0x00, 0x00, 0x63, 0x8c, 0x6d, 0x36, 0xd7, 0x64, 0x9a, 0x66, 0xdc, 0x3f,
- 0xb4, 0xdc, 0xdd, 0x3f, 0x1b, 0xe4, 0xbc, 0x3a, 0x3f, 0xab, 0x19, 0xcc,
- 0xe4, 0x99, 0x16, 0xce, 0x5d, 0xb9, 0xce, 0xdb, 0x1f, 0xe8, 0xe2, 0x3d,
- 0x9e, 0x27, 0xbe, 0x5d, 0xff, 0xfd, 0x9b, 0x4f, 0xce, 0x00, 0x38, 0xe7,
- 0x74, 0xb7, 0xdb, 0xf5, 0xbb, 0xdd, 0x2e, 0x8f, 0x3b, 0x0d, 0x3e, 0xfd,
- 0xf0, 0x5d, 0xae, 0xbf, 0xb5, 0x51, 0x70, 0x36, 0x3d, 0x3e, 0x2f, 0xfa,
- 0x12, 0xc8, 0x69, 0xcf, 0x3c, 0xce, 0x93, 0xce, 0x98, 0xaf, 0xbe, 0xbb,
- 0xff, 0xfe, 0xec, 0xbc, 0x98, 0x01, 0xdd, 0x68, 0xd4, 0xab, 0x5a, 0x6b,
- 0xd4, 0x1f, 0x92, 0x66, 0xb5, 0xcc, 0xfe, 0xdf, 0x63, 0xa2, 0x38, 0x9f,
- 0x8c, 0x6c, 0xe9, 0x68, 0xcf, 0x23, 0x11, 0x0b, 0x4d, 0x01, 0x34, 0x2a,
- 0x3e, 0x2a, 0xd3, 0x08, 0x41, 0x67, 0x76, 0x79, 0xbe, 0x15, 0x1b, 0x63,
- 0x74, 0xbf, 0x3f, 0xa0, 0xdb, 0xed, 0x12, 0x67, 0x96, 0x7a, 0xb5, 0x84,
- 0x35, 0x93, 0x1b, 0xe4, 0xd4, 0xc1, 0xb3, 0x86, 0x3b, 0xcf, 0xdc, 0x53,
- 0xb3, 0x13, 0xb3, 0xd6, 0x91, 0x64, 0x86, 0x34, 0xcb, 0xc1, 0x89, 0xf9,
- 0x06, 0x56, 0x2c, 0x41, 0x56, 0xa9, 0x04, 0xb4, 0x5a, 0x2d, 0x32, 0x23,
- 0xa8, 0x05, 0x25, 0xac, 0x53, 0x78, 0x72, 0x35, 0xaf, 0x8b, 0x71, 0x9a,
- 0x53, 0x6f, 0xfa, 0x8c, 0x86, 0x39, 0xd6, 0xba, 0x27, 0x0b, 0x00, 0x79,
- 0x9e, 0xab, 0x28, 0x1a, 0xd1, 0xef, 0x0f, 0xd0, 0xe6, 0x0d, 0xaa, 0x81,
- 0x8f, 0x73, 0x0e, 0x4f, 0x9e, 0x9b, 0xe7, 0x17, 0x93, 0x83, 0x51, 0xaa,
- 0xd1, 0xb9, 0x25, 0xf0, 0x25, 0x71, 0xaa, 0xad, 0x31, 0xf9, 0xd1, 0x02,
- 0x80, 0x31, 0x26, 0x2b, 0x97, 0x4b, 0x54, 0x9b, 0x1b, 0xac, 0xd5, 0xca,
- 0x38, 0x40, 0x0a, 0xb1, 0xbc, 0xf8, 0x2f, 0x28, 0xe3, 0x1c, 0xa3, 0x54,
- 0x93, 0x5b, 0x87, 0xe7, 0x09, 0x82, 0xb2, 0xc7, 0x69, 0x92, 0x29, 0x21,
- 0xc4, 0xc9, 0x02, 0x80, 0xb5, 0x36, 0x1b, 0x8d, 0xc6, 0x1c, 0x0f, 0x14,
- 0xeb, 0xf5, 0x4b, 0xe8, 0xdc, 0xbe, 0xd2, 0xe8, 0x33, 0x6d, 0x89, 0x33,
- 0x03, 0x4e, 0xe0, 0x4f, 0xfd, 0x94, 0x3d, 0xc9, 0xe8, 0x54, 0xe5, 0x82,
- 0xa7, 0x93, 0xb0, 0x98, 0x81, 0xd4, 0xf7, 0x7d, 0xbc, 0x20, 0xa0, 0x49,
- 0x99, 0x4c, 0xd9, 0x0b, 0x83, 0x4c, 0xe6, 0x98, 0xc3, 0xba, 0xc9, 0x3e,
- 0x61, 0xec, 0xc4, 0x54, 0x6e, 0x97, 0xad, 0x48, 0x9c, 0x83, 0xc1, 0x28,
- 0xb5, 0xb9, 0x73, 0x8b, 0x00, 0xd6, 0xda, 0x64, 0x3c, 0x1e, 0xd3, 0x19,
- 0xf8, 0x54, 0x5a, 0x65, 0xa2, 0x44, 0x93, 0xe9, 0xe9, 0x4b, 0x08, 0xc8,
- 0x8d, 0x45, 0x1b, 0x87, 0xce, 0x2d, 0xb9, 0x99, 0x6e, 0xcb, 0x2f, 0x99,
- 0x95, 0x44, 0x19, 0x86, 0xe3, 0xc4, 0x13, 0xd2, 0x5b, 0x5a, 0x82, 0x54,
- 0x08, 0x81, 0x0c, 0x1a, 0x94, 0x4a, 0x3e, 0xa3, 0x44, 0x13, 0x25, 0x9a,
- 0x54, 0x19, 0x94, 0xb6, 0x2f, 0x1d, 0x6c, 0x99, 0xe2, 0x2c, 0xe7, 0x34,
- 0xd1, 0x3e, 0xe7, 0x94, 0x20, 0x8e, 0xe3, 0x53, 0x7a, 0x51, 0x85, 0x4a,
- 0x0d, 0x1e, 0x9f, 0xc4, 0x0c, 0x63, 0xbd, 0xd4, 0xd1, 0xbf, 0x91, 0x00,
- 0x86, 0xb1, 0x42, 0x19, 0x53, 0xfa, 0xf5, 0xea, 0x5e, 0x2f, 0x7c, 0xfc,
- 0x0c, 0x80, 0xb5, 0x36, 0x06, 0x81, 0xf5, 0x6b, 0x64, 0xb9, 0x25, 0x8a,
- 0x35, 0x4a, 0x5f, 0x3c, 0x0f, 0x5e, 0x54, 0x52, 0x0a, 0x4e, 0x86, 0x09,
- 0x52, 0xc8, 0x38, 0xdc, 0xdd, 0x9d, 0x3b, 0x3e, 0x33, 0x07, 0x92, 0x24,
- 0x21, 0x4a, 0x0c, 0x57, 0xaf, 0x04, 0x54, 0x03, 0x8f, 0xa0, 0xbc, 0xba,
- 0x6f, 0x56, 0x29, 0x04, 0x69, 0xaa, 0x90, 0x52, 0x0c, 0x8b, 0xfd, 0xc5,
- 0x12, 0x24, 0x00, 0x9a, 0x12, 0xeb, 0x55, 0x8f, 0x7a, 0x69, 0x15, 0x55,
- 0x7f, 0x2a, 0xe7, 0x1c, 0xfd, 0x24, 0x41, 0x58, 0x3b, 0x58, 0x00, 0x68,
- 0xb7, 0xdb, 0x62, 0x67, 0x67, 0xc7, 0x44, 0xb1, 0x62, 0x70, 0xea, 0xf8,
- 0xf3, 0x64, 0x88, 0xec, 0xbe, 0xe2, 0x0e, 0xb8, 0x44, 0xc7, 0xc7, 0x43,
- 0x9b, 0x24, 0xc3, 0x07, 0xbb, 0xed, 0x76, 0x2d, 0x0c, 0xc3, 0x78, 0x0e,
- 0x00, 0x78, 0x51, 0x14, 0xfd, 0xf4, 0xcb, 0xa1, 0xf8, 0x4c, 0xad, 0xe3,
- 0xff, 0xb6, 0xff, 0xca, 0x1f, 0xbb, 0x67, 0xe4, 0xc0, 0x02, 0x58, 0x9d,
- 0x1e, 0x1c, 0x3f, 0xf8, 0xe1, 0xeb, 0xe2, 0x35, 0x31, 0xfb, 0x35, 0x6b,
- 0xb7, 0xdb, 0xcd, 0x60, 0x6d, 0xed, 0xcd, 0x5a, 0xd0, 0xda, 0x74, 0x38,
- 0x29, 0x85, 0x5c, 0xc9, 0x12, 0xc8, 0x8d, 0x31, 0x2a, 0x4b, 0x6b, 0xb9,
- 0x10, 0x79, 0x3e, 0x3a, 0xe9, 0x01, 0x7f, 0x85, 0x61, 0xd8, 0x5b, 0x00,
- 0x98, 0x42, 0x48, 0x20, 0x60, 0x92, 0x99, 0x7c, 0x15, 0x00, 0x53, 0x05,
- 0x40, 0x0a, 0xa8, 0x30, 0x0c, 0xcf, 0x2c, 0x2d, 0xf1, 0xff, 0xcf, 0xe9,
- 0xeb, 0x06, 0xf8, 0x07, 0xbc, 0x32, 0xa5, 0x97, 0xcb, 0x08, 0x37, 0x2b,
- 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
-}
-
-var __32x32_mimetypes_x_office_spreadsheet_png = []byte{
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
- 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
- 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x00,
- 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
- 0x88, 0x00, 0x00, 0x05, 0xa5, 0x49, 0x44, 0x41, 0x54, 0x58, 0x85, 0xe5,
- 0x97, 0xcd, 0x6b, 0x54, 0x57, 0x18, 0xc6, 0x7f, 0xe7, 0xde, 0x3b, 0x93,
- 0x51, 0x67, 0x92, 0x8c, 0x66, 0x32, 0x6a, 0x26, 0x4d, 0x94, 0x18, 0x27,
- 0xa9, 0x50, 0xbf, 0x5a, 0x2d, 0x94, 0x76, 0xd1, 0x85, 0x05, 0x41, 0x8b,
- 0x60, 0x75, 0x53, 0x70, 0x21, 0x0a, 0x55, 0xba, 0x71, 0x51, 0xa8, 0xb4,
- 0x7f, 0x40, 0xd7, 0xd5, 0x45, 0xa5, 0x90, 0x6e, 0x5a, 0xa8, 0x20, 0x34,
- 0x15, 0x0a, 0x6d, 0xa1, 0x25, 0x58, 0x2c, 0xa4, 0xd6, 0x42, 0x4d, 0xa2,
- 0xf9, 0x20, 0xc9, 0xc4, 0x64, 0x3e, 0x4c, 0xa2, 0x13, 0x93, 0xcc, 0xdc,
- 0xef, 0x2e, 0x32, 0xf7, 0xf4, 0xde, 0xc9, 0x97, 0x59, 0x74, 0xd5, 0x03,
- 0x87, 0x7b, 0xde, 0xf3, 0x9e, 0x73, 0xde, 0xe7, 0x3c, 0xef, 0xf3, 0xde,
- 0xb9, 0x03, 0xff, 0xf7, 0x26, 0xaa, 0x27, 0xae, 0x5d, 0xbb, 0x76, 0x4a,
- 0xd3, 0xb4, 0x2e, 0x20, 0xa6, 0xaa, 0x2a, 0x8a, 0xa2, 0xe0, 0x38, 0x0e,
- 0xb6, 0x6d, 0xcb, 0x6e, 0x59, 0x96, 0x7c, 0xfa, 0xc7, 0x6b, 0xcd, 0x01,
- 0xcf, 0x2d, 0xcb, 0x3a, 0xd7, 0xd5, 0xd5, 0x75, 0xcb, 0x1f, 0x4f, 0x5b,
- 0x86, 0x48, 0x88, 0x2f, 0xcf, 0x9f, 0x3f, 0x1f, 0xab, 0x8c, 0xe5, 0xbc,
- 0xeb, 0xba, 0x81, 0x75, 0x7e, 0xfb, 0x05, 0xc7, 0xb1, 0x4b, 0x97, 0x2e,
- 0x7d, 0x09, 0xac, 0x0d, 0xc0, 0xb6, 0xed, 0x7a, 0x80, 0xd1, 0xd1, 0x51,
- 0x84, 0x10, 0x12, 0x84, 0xff, 0xe9, 0x07, 0xe6, 0x1f, 0xaf, 0x64, 0x7b,
- 0x40, 0x1a, 0x1b, 0x1b, 0x31, 0x0c, 0xa3, 0xbe, 0xda, 0xb7, 0x0c, 0x80,
- 0xeb, 0xba, 0x32, 0xc8, 0x8d, 0x1b, 0x37, 0x48, 0x24, 0x12, 0x81, 0xa0,
- 0xf9, 0x7c, 0x9e, 0x64, 0x32, 0x29, 0xed, 0x42, 0xa1, 0x40, 0x32, 0x99,
- 0x94, 0xfb, 0x0b, 0x85, 0x02, 0x8d, 0x8d, 0x8d, 0xd2, 0x9e, 0x9e, 0x9e,
- 0xe6, 0xc2, 0x85, 0x0b, 0xcb, 0x40, 0xad, 0x0a, 0xc0, 0x71, 0x1c, 0x79,
- 0x93, 0x54, 0x2a, 0x45, 0x2a, 0x95, 0x0a, 0xdc, 0xaa, 0xa6, 0xa6, 0x26,
- 0x30, 0x17, 0x89, 0x44, 0x48, 0xa5, 0x52, 0x72, 0x8f, 0xdf, 0xf6, 0xfc,
- 0xde, 0xda, 0xea, 0x34, 0xae, 0x0a, 0xc0, 0x63, 0xc1, 0x3b, 0xb4, 0xfa,
- 0x59, 0x9d, 0x9a, 0x95, 0x68, 0xf7, 0xb7, 0xb5, 0xfc, 0x2b, 0x69, 0x40,
- 0x8e, 0xa7, 0xa6, 0xa6, 0xb0, 0x6d, 0x3b, 0x10, 0xac, 0x50, 0x28, 0x04,
- 0xd6, 0xe4, 0xf3, 0x79, 0x4c, 0xd3, 0x94, 0xfe, 0x7c, 0x3e, 0xef, 0xa9,
- 0x5e, 0xfa, 0x37, 0xcc, 0x80, 0x77, 0xd8, 0xce, 0x9d, 0x3b, 0x03, 0xf4,
- 0x0a, 0x21, 0xd0, 0x34, 0x8d, 0xe3, 0xc7, 0x8f, 0xcb, 0x43, 0x47, 0x46,
- 0x46, 0x68, 0x6b, 0x6b, 0x93, 0x6b, 0x86, 0x87, 0x87, 0xa5, 0x0d, 0x30,
- 0x3c, 0x3c, 0x8c, 0xa2, 0x28, 0x2f, 0x0e, 0xc0, 0xbb, 0x9d, 0x10, 0x82,
- 0x6c, 0x36, 0x8b, 0xe3, 0x38, 0xcb, 0x44, 0x38, 0x34, 0x34, 0x24, 0xd7,
- 0x4f, 0x4c, 0x4c, 0x04, 0x40, 0x67, 0x32, 0x19, 0x69, 0x03, 0x64, 0x32,
- 0x19, 0xd2, 0xe9, 0xf4, 0xc6, 0x01, 0x00, 0xec, 0xd8, 0xb1, 0x83, 0xe6,
- 0xe6, 0xe6, 0x00, 0x00, 0x55, 0x55, 0xd9, 0xbb, 0x77, 0xaf, 0xb4, 0x43,
- 0xa1, 0x50, 0x80, 0x01, 0x4d, 0xd3, 0x02, 0x0c, 0x68, 0x9a, 0xb6, 0xb1,
- 0x14, 0xd8, 0xb6, 0x2d, 0x45, 0x98, 0xcb, 0xe5, 0x96, 0x6d, 0x28, 0x14,
- 0x0a, 0x0c, 0x0e, 0x0e, 0xca, 0x80, 0xff, 0x19, 0x03, 0x9e, 0x06, 0x9a,
- 0x9b, 0x9b, 0xa5, 0x4f, 0x08, 0x41, 0x28, 0x14, 0x92, 0x07, 0x7a, 0xb6,
- 0x9f, 0x01, 0x55, 0x55, 0xd9, 0xb3, 0x67, 0x8f, 0xdc, 0xa3, 0xaa, 0xaa,
- 0x64, 0xc0, 0x0f, 0x6c, 0x5d, 0x00, 0x80, 0xd4, 0x80, 0x77, 0xb8, 0xa7,
- 0xf2, 0x47, 0x8f, 0x1e, 0x49, 0x3b, 0x93, 0xc9, 0x04, 0x40, 0xaf, 0xc4,
- 0x40, 0x47, 0x47, 0xc7, 0xc6, 0x18, 0xf0, 0x52, 0xe0, 0x55, 0x81, 0xbf,
- 0xf6, 0x55, 0x55, 0x25, 0x9d, 0x4e, 0x07, 0xec, 0xf6, 0xf6, 0x76, 0x09,
- 0x40, 0xd3, 0xb4, 0x00, 0x03, 0x7e, 0x0d, 0xbc, 0x10, 0x03, 0xfe, 0x1a,
- 0xf6, 0xbf, 0x07, 0xbc, 0x9e, 0xcb, 0xe5, 0x02, 0x1a, 0x18, 0x1f, 0x1b,
- 0x23, 0x7b, 0xef, 0x1e, 0xf9, 0xfb, 0xf7, 0x79, 0x36, 0x32, 0xc2, 0x7c,
- 0x2e, 0x47, 0x44, 0x51, 0x70, 0x34, 0x8d, 0xf0, 0xd6, 0xad, 0x28, 0x89,
- 0x04, 0xe1, 0x73, 0xe7, 0xe8, 0x7c, 0xfb, 0xed, 0x8d, 0xa5, 0xc0, 0xaf,
- 0x81, 0xea, 0x2a, 0x48, 0xa7, 0xd3, 0xd8, 0xa6, 0x49, 0xef, 0x57, 0x5f,
- 0x31, 0x70, 0xfd, 0x3a, 0xfb, 0x1a, 0x1a, 0x78, 0x6b, 0xd7, 0x2e, 0x5a,
- 0x3a, 0x3b, 0x89, 0x1d, 0x3a, 0x84, 0xeb, 0x38, 0x38, 0xa6, 0x49, 0x71,
- 0x6e, 0x8e, 0xb1, 0x5c, 0x8e, 0xbe, 0x2b, 0x57, 0xe8, 0x2e, 0x97, 0x89,
- 0xd4, 0xd5, 0x71, 0x1a, 0xc2, 0x37, 0xc1, 0x58, 0x17, 0x80, 0xc7, 0xc0,
- 0x4a, 0xef, 0x81, 0x3f, 0x7b, 0x7a, 0xb8, 0xf3, 0xc9, 0x27, 0x1c, 0x88,
- 0x46, 0xb9, 0x7a, 0xf2, 0x24, 0x9b, 0xc3, 0x61, 0x60, 0x29, 0xc7, 0xb6,
- 0x61, 0xe0, 0x98, 0x26, 0x8e, 0x69, 0x12, 0x11, 0x82, 0xf6, 0x86, 0x06,
- 0xda, 0xea, 0xea, 0x58, 0x58, 0x5c, 0xe4, 0xa7, 0x81, 0x01, 0xee, 0xc2,
- 0x6f, 0x1f, 0xc0, 0xa9, 0xeb, 0x30, 0xb1, 0x2a, 0x00, 0x4f, 0x03, 0x4d,
- 0x4d, 0x4d, 0x92, 0x01, 0x8f, 0x15, 0x61, 0x9a, 0xdc, 0xbd, 0x7a, 0x95,
- 0x77, 0x3b, 0x3b, 0x39, 0xdc, 0xd6, 0x06, 0x95, 0x94, 0x39, 0xa6, 0x89,
- 0x6d, 0x59, 0x32, 0xb8, 0x63, 0x9a, 0xd8, 0xbe, 0x71, 0xc8, 0xb2, 0x78,
- 0xa7, 0xb5, 0x95, 0x44, 0x28, 0x74, 0xf8, 0xbb, 0xe1, 0xe1, 0x1f, 0x2f,
- 0xc0, 0xd1, 0x2f, 0xa0, 0xb8, 0xae, 0x06, 0x3c, 0x06, 0x3c, 0x00, 0x43,
- 0x37, 0x6f, 0x72, 0x28, 0x1e, 0xe7, 0x70, 0x47, 0x07, 0xe8, 0x3a, 0x8e,
- 0x6d, 0xaf, 0x18, 0x30, 0x30, 0xe7, 0x03, 0xb6, 0x2f, 0x1e, 0x67, 0x68,
- 0xdb, 0xb6, 0x74, 0xff, 0xcc, 0xcc, 0x47, 0xc0, 0xc7, 0x6b, 0xa6, 0xa0,
- 0x5a, 0x03, 0x42, 0x08, 0xfa, 0x1f, 0x3e, 0xe4, 0xf5, 0xb3, 0x67, 0x71,
- 0x2d, 0x0b, 0xbb, 0x54, 0x5a, 0x37, 0xe0, 0x32, 0x50, 0xae, 0xcb, 0x81,
- 0x44, 0x82, 0xbe, 0x99, 0x99, 0xb3, 0xab, 0x02, 0xf0, 0xea, 0x75, 0x6a,
- 0x6a, 0x4a, 0x8e, 0x3d, 0x16, 0xf4, 0xe9, 0x69, 0x6a, 0x6b, 0x6b, 0xb1,
- 0x9e, 0x3e, 0xc5, 0x29, 0x95, 0xfe, 0x0d, 0x50, 0x09, 0x6a, 0x9b, 0x26,
- 0xe3, 0x6f, 0xec, 0xe7, 0xdb, 0xf2, 0x6b, 0xe0, 0xba, 0x98, 0x86, 0x81,
- 0x6e, 0x18, 0x58, 0x86, 0x81, 0x6e, 0x98, 0x38, 0xb6, 0x49, 0xab, 0x53,
- 0x44, 0x3c, 0xfc, 0xf4, 0x25, 0x40, 0x59, 0x93, 0x01, 0x4f, 0x03, 0x32,
- 0xff, 0x42, 0x70, 0xdf, 0x75, 0x79, 0x92, 0xcd, 0xb2, 0x79, 0xcb, 0x16,
- 0xec, 0x72, 0x79, 0xd9, 0x0d, 0x6d, 0xd7, 0xa6, 0xfc, 0x7e, 0x03, 0xdb,
- 0xba, 0x8b, 0xfc, 0xb9, 0x98, 0x46, 0xd7, 0x0d, 0x0c, 0x43, 0x47, 0xd7,
- 0x0d, 0x74, 0xdd, 0x20, 0xa2, 0xb9, 0x44, 0x67, 0x17, 0x01, 0x54, 0x20,
- 0xba, 0xaa, 0x06, 0x84, 0x10, 0x4c, 0x4e, 0x4e, 0x06, 0xde, 0x84, 0x00,
- 0x4a, 0x2c, 0x46, 0x6f, 0x4f, 0x0f, 0xc9, 0x33, 0x67, 0x50, 0x66, 0x66,
- 0xb0, 0xab, 0x58, 0x28, 0xbe, 0x12, 0x27, 0x17, 0xce, 0xb2, 0x6b, 0xff,
- 0xdf, 0xf4, 0xf6, 0xec, 0xc2, 0xb2, 0xec, 0x4a, 0xb7, 0x08, 0x6b, 0xd0,
- 0x1e, 0xd1, 0xc9, 0x67, 0xc6, 0x88, 0x43, 0x1e, 0x88, 0x28, 0x6b, 0xa5,
- 0xa0, 0xa9, 0xa9, 0x89, 0x96, 0x96, 0x16, 0xd9, 0x5b, 0x5b, 0x5b, 0xa9,
- 0xdd, 0xb7, 0x8f, 0x81, 0xc9, 0x49, 0xfe, 0xf8, 0xe1, 0x07, 0x4a, 0xc9,
- 0x24, 0x6e, 0x32, 0xb9, 0xf4, 0xe9, 0x5d, 0x2e, 0x63, 0x95, 0x4a, 0x64,
- 0x0e, 0x0b, 0xa6, 0xf5, 0x31, 0x1e, 0xef, 0x78, 0xcc, 0x2b, 0xa1, 0xaf,
- 0x97, 0x2e, 0xe4, 0xda, 0x6c, 0x8f, 0x6f, 0xe2, 0xb5, 0x58, 0x99, 0xc1,
- 0xc7, 0x05, 0xe2, 0x7d, 0x3f, 0x53, 0x82, 0x3b, 0x80, 0xbd, 0x6a, 0x0a,
- 0x5c, 0xd7, 0x5d, 0x91, 0x01, 0xf7, 0xe0, 0x41, 0x9e, 0xf7, 0xf5, 0x71,
- 0x6f, 0x74, 0x94, 0x85, 0x62, 0x91, 0x9d, 0xbb, 0x77, 0xb3, 0xbd, 0xad,
- 0x8d, 0x70, 0xa9, 0x84, 0x3d, 0x37, 0x4b, 0xf6, 0x48, 0x84, 0xb2, 0x55,
- 0xc4, 0xb2, 0x75, 0xa2, 0x6f, 0x3d, 0xe0, 0xe5, 0xde, 0xd3, 0xd4, 0x1b,
- 0x30, 0x3d, 0xd8, 0x47, 0xcf, 0xa2, 0xc6, 0x9e, 0xde, 0x6e, 0xc8, 0x8f,
- 0x3c, 0xfb, 0x0b, 0x3e, 0x07, 0x16, 0xd6, 0x2c, 0xc3, 0x8b, 0x17, 0x2f,
- 0x06, 0x2a, 0x40, 0x08, 0x81, 0x7d, 0xe2, 0x04, 0x03, 0x6f, 0xbe, 0xc9,
- 0xed, 0xcb, 0x97, 0x79, 0x9e, 0xcf, 0xb3, 0xd7, 0x30, 0x98, 0xe8, 0xef,
- 0x67, 0x53, 0x34, 0x8a, 0x95, 0x8e, 0x32, 0xf7, 0x57, 0x8c, 0x90, 0x02,
- 0xb8, 0xb0, 0x50, 0xd6, 0x31, 0xfe, 0xee, 0xe2, 0xfb, 0x85, 0xa3, 0x34,
- 0x17, 0xb3, 0xec, 0xef, 0xbd, 0x85, 0x9e, 0x1b, 0x99, 0x7e, 0x00, 0x1f,
- 0x3e, 0x80, 0x7e, 0xa0, 0x5c, 0x0d, 0x20, 0xa6, 0x28, 0xca, 0x9c, 0xeb,
- 0xba, 0xb5, 0xf5, 0xf5, 0xff, 0x7e, 0xc2, 0x57, 0x7f, 0x54, 0x1e, 0x3a,
- 0x76, 0x8c, 0x86, 0xdb, 0xb7, 0xf9, 0xe5, 0xb3, 0xcf, 0xf8, 0xbd, 0xbb,
- 0x9b, 0x58, 0x28, 0x44, 0x52, 0xd7, 0x51, 0x1f, 0x2f, 0x30, 0x3e, 0xfe,
- 0x0c, 0x67, 0x93, 0xc0, 0x71, 0x5d, 0x42, 0x33, 0x16, 0x4a, 0x5f, 0x3f,
- 0xaf, 0x3e, 0xfc, 0x15, 0xa7, 0x58, 0xa0, 0xb0, 0x75, 0xab, 0x75, 0x07,
- 0x2e, 0x66, 0xa1, 0x17, 0x78, 0x02, 0xc1, 0xbf, 0x66, 0x31, 0x20, 0x71,
- 0xe4, 0xc8, 0x91, 0xf7, 0x5a, 0x5a, 0x5a, 0x3e, 0x05, 0x36, 0x55, 0xb3,
- 0xe3, 0x6f, 0xae, 0xeb, 0x62, 0x18, 0x06, 0xd6, 0xfc, 0x3c, 0x35, 0x93,
- 0x93, 0x44, 0x66, 0x67, 0xa9, 0x99, 0x9f, 0x47, 0x33, 0x0c, 0x14, 0xcb,
- 0xc2, 0xd1, 0x34, 0xcc, 0x50, 0x08, 0x3d, 0x1a, 0xa5, 0x14, 0x8f, 0x53,
- 0xda, 0xbe, 0xdd, 0x18, 0xcd, 0xe5, 0xbe, 0x18, 0x1c, 0x1c, 0xfc, 0x06,
- 0x18, 0x07, 0xb2, 0x80, 0xe3, 0x07, 0x10, 0x06, 0x92, 0xc0, 0x36, 0xa0,
- 0x1e, 0xa8, 0x61, 0xa9, 0x54, 0xd6, 0x6b, 0x0a, 0x10, 0x01, 0x36, 0x57,
- 0xf6, 0x68, 0x95, 0x39, 0x00, 0x87, 0xa5, 0x1f, 0x9e, 0xa7, 0x80, 0x0e,
- 0x3c, 0x03, 0x66, 0x59, 0xfa, 0x1d, 0x98, 0xaf, 0x66, 0xc0, 0x6b, 0x35,
- 0x95, 0x03, 0xc3, 0xab, 0xf8, 0xd7, 0x6b, 0xa2, 0xd2, 0xbd, 0xaf, 0x0f,
- 0xb7, 0x02, 0xc4, 0xac, 0x80, 0xd0, 0x7d, 0x3e, 0xfe, 0x01, 0x9f, 0x1e,
- 0x98, 0x64, 0x1e, 0x77, 0xb2, 0x47, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
- 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
-}
diff --git a/redo/yz_repaint_test.go b/redo/yz_repaint_test.go
deleted file mode 100644
index 1c8eb55..0000000
--- a/redo/yz_repaint_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// 21 august 2014
-
-package ui
-
-import (
- "image"
- "image/color"
- "image/draw"
- "strconv"
-)
-
-type repainter struct {
- img *image.RGBA
- area Area
- x TextField
- y TextField
- width TextField
- height TextField
- repaint Button
- all Button
- stack Stack
-
- xv int
- yv int
- wv int
- hv int
-}
-
-func newRepainter(times int) *repainter {
- r := new(repainter)
- r.img = tileImage(times)
- r.area = NewArea(r.img.Rect.Dx(), r.img.Rect.Dy(), r)
- r.area.OnTextFieldDismissed(r.tfdone)
- r.x = NewTextField()
- r.x.OnChanged(r.setx)
- r.y = NewTextField()
- r.y.OnChanged(r.sety)
- r.width = NewTextField()
- r.width.OnChanged(r.setwidth)
- r.height = NewTextField()
- r.height.OnChanged(r.setheight)
- r.repaint = NewButton("Rect")
- r.repaint.OnClicked(r.dorect)
- r.all = NewButton("All")
- r.all.OnClicked(r.doall)
- r.stack = NewHorizontalStack(r.x, r.y, r.width, r.height, r.repaint, r.all)
- r.stack.SetStretchy(0)
- r.stack.SetStretchy(1)
- r.stack.SetStretchy(2)
- r.stack.SetStretchy(3)
- r.stack = NewVerticalStack(r.area, r.stack)
- r.stack.SetStretchy(0)
- return r
-}
-
-func (r *repainter) Paint(rect image.Rectangle) *image.RGBA {
- return r.img.SubImage(rect).(*image.RGBA)
-}
-
-func (r *repainter) Mouse(me MouseEvent) {
- if me.Up == 1 {
- r.area.OpenTextFieldAt(me.Pos.X, me.Pos.Y)
- }
-}
-
-func (r *repainter) tfdone() {
- println(r.area.TextFieldText())
-}
-
-func (r *repainter) Key(ke KeyEvent) bool { return false }
-
-func (r *repainter) setx() {
- i, err := strconv.Atoi(r.x.Text())
- if err != nil {
- r.x.Invalid(err.Error())
- return
- }
- r.x.Invalid("")
- r.xv = i
-}
-
-func (r *repainter) sety() {
- i, err := strconv.Atoi(r.y.Text())
- if err != nil {
- r.y.Invalid(err.Error())
- return
- }
- r.y.Invalid("")
- r.yv = i
-}
-
-func (r *repainter) setwidth() {
- i, err := strconv.Atoi(r.width.Text())
- if err != nil {
- r.width.Invalid(err.Error())
- return
- }
- r.width.Invalid("")
- r.wv = i
-}
-
-func (r *repainter) setheight() {
- i, err := strconv.Atoi(r.height.Text())
- if err != nil {
- r.height.Invalid(err.Error())
- return
- }
- r.height.Invalid("")
- r.hv = i
-}
-
-func (r *repainter) alter(rect image.Rectangle, c color.Color) {
- draw.Draw(r.img, rect, &image.Uniform{c}, image.ZP, draw.Over)
-}
-
-func (r *repainter) dorect() {
- 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)
-}
-
-func (r *repainter) doall() {
- r.alter(r.img.Rect, color.RGBA{255, 255, 0, 128})
- r.area.RepaintAll()
-}
diff --git a/redo/zz_test.go b/redo/zz_test.go
deleted file mode 100644
index 16af837..0000000
--- a/redo/zz_test.go
+++ /dev/null
@@ -1,279 +0,0 @@
-// 8 july 2014
-
-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"
- "image"
- "image/color"
- "image/draw"
- "time"
- "strings"
-)
-
-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
-}
-var ddata = []dtype{
- { "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
- grid Grid
- nt Tab
- a Area
- spw Stack
- sph Stack
- s Stack
- l Label
- table Table
- b Button
- c Checkbox
- e TextField
- e2 TextField
-
- wsmall Window
-}
-
-type areaHandler struct {
- 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)
- return i
-}
-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) {
- if fn == "" {
- fn = "<no file selected>"
- }
- tw.fnlabel.SetText(fn)
-}
-
-func (tw *testwin) addfe() {
- tw.festart = NewButton("Start")
- tw.festart.OnClicked(func() {
- if tw.fe != nil {
- tw.fe.Stop()
- }
- ticker := time.NewTicker(1 * time.Second)
- tw.fe = NewForeignEvent(ticker.C, func(d interface{}) {
- t := d.(time.Time)
- tw.felabel.SetText(t.String())
- })
- })
- tw.felabel = NewStandaloneLabel("<stopped>")
- tw.festop = NewButton("Stop")
- tw.festop.OnClicked(func() {
- if tw.fe != nil {
- tw.fe.Stop()
- tw.felabel.SetText("<stopped>")
- tw.fe = nil
- }
- })
- tw.vedit = NewTextField()
- tw.vedit.OnChanged(func() {
- if strings.Contains(tw.vedit.Text(), "bad") {
- tw.vedit.Invalid("bad entered")
- } else {
- tw.vedit.Invalid("")
- }
- })
- tw.openbtn = NewButton("Open")
- tw.openbtn.OnClicked(func() {
- OpenFile(tw.w, tw.openFile)
- })
- tw.fnlabel = NewStandaloneLabel("<no file selected>")
- tw.festack = NewVerticalStack(tw.festart,
- tw.felabel,
- tw.festop,
- NewCheckbox("This is a checkbox test"),
- Space(),
- tw.vedit,
- Space(),
- NewCheckbox("This is a checkbox test"),
- tw.openbtn, tw.fnlabel)
- tw.festack.SetStretchy(4)
- tw.festack.SetStretchy(6)
- tw.festack = NewHorizontalStack(tw.festack, Space())
- tw.festack.SetStretchy(0)
- tw.festack.SetStretchy(1)
- tw.t.Append("Foreign Events", tw.festack)
-}
-
-func (tw *testwin) make(done chan struct{}) {
- tw.t = NewTab()
- tw.w = NewWindow("Hello", 320, 240, tw.t)
- tw.w.OnClosing(func() bool {
- if *closeOnClick {
- panic("window closed normally in close on click mode (should not happen)")
- }
- println("window close event received")
- Stop()
- done <- struct{}{}
- return true
- })
- tw.icons, tw.il = readIcons() // repainter uses these
- tw.repainter = newRepainter(15)
- tw.t.Append("Repaint", tw.repainter.stack)
- tw.addfe()
- tw.icontbl = NewTable(reflect.TypeOf(icon{}))
- tw.icontbl.Lock()
- idq := tw.icontbl.Data().(*[]icon)
- *idq = tw.icons
- tw.icontbl.Unlock()
- tw.icontbl.LoadImageList(tw.il)
- tw.icontbl.OnSelected(func() {
- s := fmt.Sprintf("%d ", tw.icontbl.Selected())
- tw.icontbl.RLock()
- defer tw.icontbl.RUnlock()
- idq := tw.icontbl.Data().(*[]icon)
- for _, v := range *idq {
- s += strings.ToUpper(fmt.Sprintf("%v", v.Bool)[0:1]) + " "
- }
- tw.w.SetTitle(s)
- })
- tw.t.Append("Image List Table", tw.icontbl)
- tw.group2 = NewGroup("Group", NewButton("Button in Group"))
- tw.t.Append("Empty Group", NewGroup("Group", Space()))
- tw.t.Append("Filled Group", tw.group2)
- tw.group = NewGroup("Group", NewVerticalStack(NewCheckbox("Checkbox in Group")))
- tw.t.Append("Group", tw.group)
- tw.grid = NewGrid(3,
- NewLabel("0,0"), NewTextField(), NewLabel("0,2"),
- NewButton("1,0"), NewButton("1,1"), NewButton("1,2"),
- NewLabel("2,0"), NewTextField(), NewStandaloneLabel("2,2"))
- tw.grid.SetFilling(2, 1)
- tw.grid.SetFilling(1, 2)
- tw.grid.SetStretchy(1, 1)
- tw.t.Append("Grid", tw.grid)
- tw.t.Append("Blank Tab", NewTab())
- tw.nt = NewTab()
- tw.nt.Append("Tab 1", Space())
- tw.nt.Append("Tab 2", Space())
- tw.t.Append("Tab", tw.nt)
- tw.t.Append("Space", Space())
- tw.a = NewArea(200, 200, &areaHandler{false})
- tw.t.Append("Area", tw.a)
- tw.spw = NewHorizontalStack(
- NewButton("hello"),
- NewCheckbox("hello"),
- NewTextField(),
- NewPasswordField(),
- NewTable(reflect.TypeOf(struct{A,B,C int}{})),
- NewStandaloneLabel("hello"))
- tw.t.Append("Pref Width", tw.spw)
- tw.sph = NewVerticalStack(
- NewButton("hello"),
- NewCheckbox("hello"),
- NewTextField(),
- NewPasswordField(),
- NewTable(reflect.TypeOf(struct{A,B,C int}{})),
- NewStandaloneLabel("hello ÉÀÔ"))
- tw.t.Append("Pref Height", tw.sph)
- stack1 := NewHorizontalStack(NewLabel("Test"), NewTextField())
- stack1.SetStretchy(1)
- stack2 := NewHorizontalStack(NewLabel("ÉÀÔ"), NewTextField())
- stack2.SetStretchy(1)
- stack3 := NewHorizontalStack(NewLabel("Test 2"),
- NewTable(reflect.TypeOf(struct{A,B,C int}{})))
- stack3.SetStretchy(1)
- tw.s = NewVerticalStack(stack1, stack2, stack3)
- tw.s.SetStretchy(2)
- tw.t.Append("Stack", tw.s)
- tw.l = NewStandaloneLabel("hello")
- tw.t.Append("Label", tw.l)
- tw.table = NewTable(reflect.TypeOf(ddata[0]))
- tw.table.Lock()
- dq := tw.table.Data().(*[]dtype)
- *dq = ddata
- tw.table.Unlock()
- tw.t.Append("Table", tw.table)
- tw.b = NewButton("There")
- if *closeOnClick {
- tw.b.SetText("Click to Close")
- }
- tw.b.OnClicked(func() {
- println("in OnClicked()")
- if *closeOnClick {
- tw.w.Close()
- Stop()
- done <- struct{}{}
- }
- })
- tw.t.Append("Button", tw.b)
- tw.c = NewCheckbox("You Should Now See Me Instead")
- tw.c.OnToggled(func() {
- tw.w.SetTitle(fmt.Sprint(tw.c.Checked()))
- })
- tw.t.Append("Checkbox", tw.c)
- tw.e = NewTextField()
- tw.t.Append("Text Field", tw.e)
- tw.e2 = NewPasswordField()
- tw.t.Append("Password Field", tw.e2)
- tw.w.Show()
- if *smallWindow {
- tw.wsmall = NewWindow("Small", 80, 80,
- NewVerticalStack(
- NewButton("Small"),
- NewButton("Small 2"),
- NewArea(200, 200, &areaHandler{true})))
- tw.wsmall.Show()
- }
-}
-
-// this must be on the heap thanks to moving stacks
-// soon even this won't be enough...
-var tw *testwin
-
-// because Cocoa hates being run off the main thread, even if it's run exclusively off the main thread
-func init() {
- flag.BoolVar(&spaced, "spaced", false, "enable spacing")
- flag.Parse()
- go func() {
- tw = new(testwin)
- done := make(chan struct{})
- Do(func() { tw.make(done) })
- <-done
- }()
- err := Go()
- if err != nil {
- panic(err)
- }
-}
-
-func TestDummy(t *testing.T) {
- // do nothing
-}