Full Code of andlabs/ui for AI

master 70a69d6ae31e cached
59 files
42.5 MB
69.4k tokens
600 symbols
1 requests
Download .txt
Showing preview only (232K chars total). Download the full file or copy to clipboard to get everything.
Repository: andlabs/ui
Branch: master
Commit: 70a69d6ae31e
Files: 59
Total size: 42.5 MB

Directory structure:
gitextract_ocwn0tif/

├── LICENSE
├── README.md
├── TODO.md
├── area.go
├── areahandler.go
├── box.go
├── button.go
├── checkbox.go
├── colorbutton.go
├── combobox.go
├── control.go
├── datetimepicker.go
├── draw.go
├── drawtext.go
├── dummy_windows.cpp
├── editablecombobox.go
├── entry.go
├── examples/
│   ├── controlgallery.go
│   ├── drawtext.go
│   ├── histogram.go
│   ├── table.go
│   └── updateui.go
├── fontbutton.go
├── form.go
├── grid.go
├── group.go
├── image.go
├── label.go
├── libui_darwin_amd64.a
├── libui_linux_386.a
├── libui_linux_amd64.a
├── libui_windows_386.a
├── libui_windows_amd64.a
├── link_darwin_amd64.go
├── link_linux_386.go
├── link_linux_amd64.go
├── link_windows_386.go
├── link_windows_amd64.go
├── main.go
├── multilineentry.go
├── pkgui.c
├── pkgui.h
├── progressbar.go
├── radiobuttons.go
├── separator.go
├── slider.go
├── spinbox.go
├── stddialogs.go
├── tab.go
├── table.go
├── tablemodel.go
├── ui.h
├── util.go
├── window.go
└── winmanifest/
    ├── doc.go
    ├── resources.rc
    ├── ui.manifest
    ├── winmanifest_windows_386.syso
    └── winmanifest_windows_amd64.syso

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
Copyright (c) 2014 Pietro Gagliardi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

(this is called the MIT License or Expat License; see http://www.opensource.org/licenses/MIT)


================================================
FILE: README.md
================================================
# ui: platform-native GUI library for Go

This is a library that aims to provide simple GUI software development in Go. It is based on my [libui](https://github.com/andlabs/libui), a simple cross-platform library that does the same thing, but written in C.

It runs on/requires:

- Windows: cgo, Windows Vista SP2 with Platform Update and newer
- Mac OS X: cgo, Mac OS X 10.8 and newer
- other Unixes: cgo, GTK+ 3.10 and newer
	- Debian, Ubuntu, etc.: `sudo apt-get install libgtk-3-dev`
	- Red Hat/Fedora, etc.: `sudo dnf install gtk3-devel`

It also requires Go 1.8 or newer.

It currently aligns to libui's Alpha 4.1, with only a small handful of functions not available.

# Status

Package ui is currently **mid-alpha** software. Much of what is currently present runs stabily enough for the examples and perhaps some small programs to work, but the stability is still a work-in-progress, much of what is already there is not feature-complete, some of it will be buggy on certain platforms, and there's a lot of stuff missing. The libui README has more information.

# Installation

Once you have the dependencies installed, a simple

```
go get github.com/andlabs/ui/...
```

should suffice.

# Documentation

The in-code documentation is sufficient to get started, but needs improvement.

Some simple example programs are in the `examples` directory. You can `go build` each of them individually.

## Windows manifests

Package ui requires a manifest that specifies Common Controls v6 to run on Windows. It should at least also state as supported Windows Vista and Windows 7, though to avoid surprises with other packages (or with Go itself; see [this issue](https://github.com/golang/go/issues/17835)) you should state compatibility with higher versions of Windows too.

The simplest option is provided as a subpackage `winmanifest`; you can simply import it without a name, and it'll set things up properly:

```go
import _ "github.com/andlabs/ui/winmanifest"
```

You do not have to worry about importing this in non-Windows-only files; it does nothing on non-Windows platforms.

If you wish to use your own manifest instead, you can use the one in `winmanifest` as a template to see what's required and how. You'll need to specify the template in a `.rc` file and use `windres` in MinGW-w64 to generate a `.syso` file as follows:

```
windres -i resources.rc -o winmanifest_windows_GOARCH.syso -O coff
```

You may also be interested in the `github.com/akavel/rsrc` and `github.com/josephspurrier/goversioninfo` packages, which provide other Go-like options for embedding the manifest.

Note that if you choose to ship a manifest as a separate `.exe.manifest` file instead of embedding it in your binary, and you use Cygwin or MSYS2 as the source of your MinGW-w64, Cygwin and MSYS2 instruct gcc to embed a default manifest of its own if none is specified. **This default will override your manifest file!** See [this issue](https://github.com/Alexpux/MSYS2-packages/issues/454) for more details, including workaround instructions.

## macOS program execution

If you run a macOS program binary directly from the command line, it will start in the background. This is intentional; see [this](https://github.com/andlabs/libui#why-does-my-program-start-in-the-background-on-os-x-if-i-run-from-the-command-line) for more details.


================================================
FILE: TODO.md
================================================
- document that Destroy cannot be called on Controls that have a parent
- identify earliest tag for https://github.com/golang/go/commit/dba926d7a37bd6b3d740c132e8d6346214b6355c


================================================
FILE: area.go
================================================
// 16 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Area is a Control that represents a blank canvas that a program
// can draw on as it wishes. Areas also receive keyboard and mouse
// events, and programs can react to those as they see fit. Drawing
// and event handling are handled through an instance of a type
// that implements AreaHandler that every Area has; see AreaHandler
// for details.
// 
// There are two types of areas. Non-scrolling areas are rectangular
// and have no scrollbars. Programs can draw on and get mouse
// events from any point in the Area, and the size of the Area is
// decided by package ui itself, according to the layout of controls
// in the Window the Area is located in and the size of said Window.
// There is no way to query the Area's size or be notified when its
// size changes; instead, you are given the area size as part of the
// draw and mouse event handlers, for use solely within those
// handlers.
// 
// Scrolling areas have horziontal and vertical scrollbars. The amount
// that can be scrolled is determined by the area's size, which is
// decided by the programmer (both when creating the Area and by
// a call to SetSize). Only a portion of the Area is visible at any time;
// drawing and mouse events are automatically adjusted to match
// what portion is visible, so you do not have to worry about scrolling
// in your event handlers. AreaHandler has more information.
// 
// The internal coordinate system of an Area is points, which are
// floating-point and device-independent. For more details, see
// AreaHandler. The size of a scrolling Area must be an exact integer
// number of points (that is, you cannot have an Area that is 32.5
// points tall) and thus the parameters to NewScrollingArea and
// SetSize are ints. All other instances of points in parameters and
// structures (including sizes of drawn objects) are float64s.
type Area struct {
	ControlBase
	a	*C.uiArea
	ah	*C.uiAreaHandler
	scrolling	bool
}

// NewArea creates a new non-scrolling Area.
func NewArea(handler AreaHandler) *Area {
	a := new(Area)
	a.scrolling = false
	a.ah = registerAreaHandler(handler)

	a.a = C.uiNewArea(a.ah)

	a.ControlBase = NewControlBase(a, uintptr(unsafe.Pointer(a.a)))
	return a
}

// NewScrollingArea creates a new scrolling Area of the given size,
// in points.
func NewScrollingArea(handler AreaHandler, width int, height int) *Area {
	a := new(Area)
	a.scrolling = true
	a.ah = registerAreaHandler(handler)

	a.a = C.uiNewScrollingArea(a.ah, C.int(width), C.int(height))

	a.ControlBase = NewControlBase(a, uintptr(unsafe.Pointer(a.a)))
	return a
}

// Destroy destroys the Area.
func (a *Area) Destroy() {
	unregisterAreaHandler(a.ah)
	a.ControlBase.Destroy()
}

// SetSize sets the size of a scrolling Area to the given size, in points.
// SetSize panics if called on a non-scrolling Area.
func (a *Area) SetSize(width int, height int) {
	if !a.scrolling {
		panic("attempt to call SetSize on non-scrolling Area")
	}
	C.uiAreaSetSize(a.a, C.int(width), C.int(height))
}

// QueueRedrawAll queues the entire Area for redraw.
// The Area is not redrawn before this function returns; it is
// redrawn when next possible.
func (a *Area) QueueRedrawAll() {
	C.uiAreaQueueRedrawAll(a.a)
}

// ScrollTo scrolls the Area to show the given rectangle; what this
// means is implementation-defined, but you can safely assume
// that as much of the given rectangle as possible will be visible
// after this call. (TODO verify this on OS X) ScrollTo panics if called
// on a non-scrolling Area.
func (a *Area) ScrollTo(x float64, y float64, width float64, height float64) {
	if !a.scrolling {
		panic("attempt to call ScrollTo on non-scrolling Area")
	}
	C.uiAreaScrollTo(a.a, C.double(x), C.double(y), C.double(width), C.double(height))
}

// TODO BeginUserWindowMove
// TODO BeginUserWindowResize


================================================
FILE: areahandler.go
================================================
// 13 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// no need to lock this; only the GUI thread can access it
var areahandlers = make(map[*C.uiAreaHandler]AreaHandler)

// AreaHandler defines the functionality needed for handling events
// from an Area. Each of the methods on AreaHandler is called from
// the GUI thread, and every parameter (other than the Area itself)
// should be assumed to only be valid during the life of the method
// call (so for instance, do not save AreaDrawParams.AreaWidth, as
// that might change without generating an event).
// 
// Coordinates to Draw and MouseEvent are given in points. Points
// are generic, floating-point, device-independent coordinates with
// (0,0) at the top left corner. You never have to worry about the
// mapping between points and pixels; simply draw everything using
// points and you get nice effects like looking sharp on high-DPI
// monitors for free. Proper documentation on the matter is being
// written. In the meantime, there are several referenes to this kind of
// drawing, most notably on Apple's website: https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html#//apple_ref/doc/uid/TP40012302-CH4-SW1
// 
// For a scrolling Area, points are automatically offset by the scroll
// position. So if the mouse moves to position (5,5) while the
// horizontal scrollbar is at position 10 and the horizontal scrollbar is
// at position 20, the coordinate stored in the AreaMouseEvent
// structure is (15,25). The same applies to drawing.
type AreaHandler interface {
	// Draw is sent when a part of the Area needs to be drawn.
	// dp will contain a drawing context to draw on, the rectangle
	// that needs to be drawn in, and (for a non-scrolling area) the
	// size of the area. The rectangle that needs to be drawn will
	// have been cleared by the system prior to drawing, so you are
	// always working on a clean slate.
	// 
	// If you call Save on the drawing context, you must call Release
	// before returning from Draw, and the number of calls to Save
	// and Release must match. Failure to do so results in undefined
	// behavior.
	Draw(a *Area, dp *AreaDrawParams)

	// MouseEvent is called when the mouse moves over the Area
	// or when a mouse button is pressed or released. See
	// AreaMouseEvent for more details.
	// 
	// If a mouse button is being held, MouseEvents will continue to
	// be generated, even if the mouse is not within the area. On
	// some systems, the system can interrupt this behavior;
	// see DragBroken.
	MouseEvent(a *Area, me *AreaMouseEvent)

	// MouseCrossed is called when the mouse either enters or
	// leaves the Area. It is called even if the mouse buttons are being
	// held (see MouseEvent above). If the mouse has entered the
	// Area, left is false; if it has left the Area, left is true.
	// 
	// If, when the Area is first shown, the mouse is already inside
	// the Area, MouseCrossed will be called with left=false.
	// TODO what about future shows?
	MouseCrossed(a *Area, left bool)

	// DragBroken is called if a mouse drag is interrupted by the
	// system. As noted above, when a mouse button is held,
	// MouseEvent will continue to be called, even if the mouse is
	// outside the Area. On some systems, this behavior can be
	// stopped by the system itself for a variety of reasons. This
	// method is provided to allow your program to cope with the
	// loss of the mouse in this case. You should cope by cancelling
	// whatever drag-related operation you were doing.
	// 
	// Note that this is only generated on some systems under
	// specific conditions. Do not implement behavior that only
	// takes effect when DragBroken is called.
	DragBroken(a *Area)

	// KeyEvent is called when a key is pressed while the Area has
	// keyboard focus (if the Area has been tabbed into or if the
	// mouse has been clicked on it). See AreaKeyEvent for specifics.
	// 
	// Because some keyboard events are handled by the system
	// (for instance, menu accelerators and global hotkeys), you
	// must return whether you handled the key event; return true
	// if you did or false if you did not. If you wish to ignore the
	// keyboard outright, the correct implementation of KeyEvent is
	// 	func (h *MyHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {
	// 		return false
	// 	}
	// DO NOT RETURN TRUE UNCONDITIONALLY FROM THIS
	// METHOD. BAD THINGS WILL HAPPEN IF YOU DO.
	KeyEvent(a *Area, ke *AreaKeyEvent) (handled bool)
}

func registerAreaHandler(ah AreaHandler) *C.uiAreaHandler {
	uah := C.pkguiAllocAreaHandler()
	areahandlers[uah] = ah
	return uah
}

func unregisterAreaHandler(uah *C.uiAreaHandler) {
	delete(areahandlers, uah)
	C.pkguiFreeAreaHandler(uah)
}

// AreaDrawParams provides a drawing context that can be used
// to draw on an Area and tells you where to draw. See AreaHandler
// for introductory information.
type AreaDrawParams struct {
	// Context is the drawing context to draw on. See DrawContext
	// for how to draw.
	Context		*DrawContext

	// AreaWidth and AreaHeight provide the size of the Area for
	// non-scrolling Areas. For scrolling Areas both values are zero.
	// 
	// To reiterate the AreaHandler documentation, do NOT save
	// these values for later; they can change without generating
	// an event.
	AreaWidth	float64
	AreaHeight	float64

	// These four fields define the rectangle that needs to be
	// redrawn. The system will not draw anything outside this
	// rectangle, but you can make your drawing faster if you
	// also stay within the lines.
	ClipX		float64
	ClipY		float64
	ClipWidth		float64
	ClipHeight	float64
}

//export pkguiDoAreaHandlerDraw
func pkguiDoAreaHandlerDraw(uah *C.uiAreaHandler, ua *C.uiArea, udp *C.uiAreaDrawParams) {
	ah := areahandlers[uah]
	a := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)
	dp := &AreaDrawParams{
		Context:		&DrawContext{udp.Context},
		AreaWidth:	float64(udp.AreaWidth),
		AreaHeight:	float64(udp.AreaHeight),
		ClipX:		float64(udp.ClipX),
		ClipY:		float64(udp.ClipY),
		ClipWidth:		float64(udp.ClipWidth),
		ClipHeight:	float64(udp.ClipHeight),
	}
	ah.Draw(a, dp)
}

// TODO document all these
// 
// TODO note that in the case of a drag, X and Y can be out of bounds, or in the event of a scrolling area, in places that are not visible
type AreaMouseEvent struct {
	X			float64
	Y			float64

	// AreaWidth and AreaHeight provide the size of the Area for
	// non-scrolling Areas. For scrolling Areas both values are zero.
	// 
	// To reiterate the AreaHandler documentation, do NOT save
	// these values for later; they can change without generating
	// an event.
	AreaWidth	float64
	AreaHeight	float64

	Down		uint
	Up			uint
	Count		uint
	Modifiers		Modifiers
	Held			[]uint
}

func appendBits(out []uint, held C.uint64_t) []uint {
	n := uint(1)
	for i := 0; i < 64; i++ {
		if held & 1 != 0 {
			out = append(out, n)
		}
		held >>= 1
		n++
	}
	return out
}

//export pkguiDoAreaHandlerMouseEvent
func pkguiDoAreaHandlerMouseEvent(uah *C.uiAreaHandler, ua *C.uiArea, ume *C.uiAreaMouseEvent) {
	ah := areahandlers[uah]
	a := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)
	me := &AreaMouseEvent{
		X:			float64(ume.X),
		Y:			float64(ume.Y),
		AreaWidth:	float64(ume.AreaWidth),
		AreaHeight:	float64(ume.AreaHeight),
		Down:		uint(ume.Down),
		Up:			uint(ume.Up),
		Count:		uint(ume.Count),
		Modifiers:		Modifiers(ume.Modifiers),
		Held:		make([]uint, 0, 64),
	}
	me.Held = appendBits(me.Held, ume.Held1To64)
	ah.MouseEvent(a, me)
}

//export pkguiDoAreaHandlerMouseCrossed
func pkguiDoAreaHandlerMouseCrossed(uah *C.uiAreaHandler, ua *C.uiArea, left C.int) {
	ah := areahandlers[uah]
	a := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)
	ah.MouseCrossed(a, tobool(left))
}

//export pkguiDoAreaHandlerDragBroken
func pkguiDoAreaHandlerDragBroken(uah *C.uiAreaHandler, ua *C.uiArea) {
	ah := areahandlers[uah]
	a := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)
	ah.DragBroken(a)
}

// TODO document all these
type AreaKeyEvent struct {
	Key		rune
	ExtKey	ExtKey
	Modifier	Modifiers
	Modifiers	Modifiers
	Up		bool
}

//export pkguiDoAreaHandlerKeyEvent
func pkguiDoAreaHandlerKeyEvent(uah *C.uiAreaHandler, ua *C.uiArea, uke *C.uiAreaKeyEvent) C.int {
	ah := areahandlers[uah]
	a := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)
	ke := &AreaKeyEvent{
		Key:			rune(uke.Key),
		ExtKey:		ExtKey(uke.ExtKey),
		Modifier:		Modifiers(uke.Modifier),
		Modifiers:		Modifiers(uke.Modifiers),
		Up:			tobool(uke.Up),
	}
	return frombool(ah.KeyEvent(a, ke))
}

// TODO document
// 
// Note: these must be numerically identical to their libui equivalents.
type Modifiers uint
const (
	Ctrl Modifiers = 1 << iota
	Alt
	Shift
	Super
)

// TODO document
// 
// Note: these must be numerically identical to their libui equivalents.
type ExtKey int
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
)


================================================
FILE: box.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Box is a Control that holds a group of Controls horizontally
// or vertically. If horizontally, then all controls have the same
// height. If vertically, then all controls have the same width.
// By default, each control has its preferred width (horizontal)
// or height (vertical); if a control is marked "stretchy", it will
// take whatever space is left over. If multiple controls are marked
// stretchy, they will be given equal shares of the leftover space.
// There can also be space between each control ("padding").
type Box struct {
	ControlBase
	b	*C.uiBox
	children	[]Control
}

// NewHorizontalBox creates a new horizontal Box.
func NewHorizontalBox() *Box {
	b := new(Box)

	b.b = C.uiNewHorizontalBox()

	b.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))
	return b
}

// NewVerticalBox creates a new vertical Box.
func NewVerticalBox() *Box {
	b := new(Box)

	b.b = C.uiNewVerticalBox()

	b.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))
	return b
}

// Destroy destroys the Box. If the Box has children,
// Destroy calls Destroy on those Controls as well.
func (b *Box) Destroy() {
	for len(b.children) != 0 {
		c := b.children[0]
		b.Delete(0)
		c.Destroy()
	}
	b.ControlBase.Destroy()
}

// Append adds the given control to the end of the Box.
func (b *Box) Append(child Control, stretchy bool) {
	c := (*C.uiControl)(nil)
	// TODO this part is wrong for Box?
	if child != nil {
		c = touiControl(child.LibuiControl())
	}
	C.uiBoxAppend(b.b, c, frombool(stretchy))
	b.children = append(b.children, child)
}

// Delete deletes the nth control of the Box.
func (b *Box) Delete(n int) {
	b.children = append(b.children[:n], b.children[n + 1:]...)
	C.uiBoxDelete(b.b, C.int(n))
}

// Padded returns whether there is space between each control
// of the Box.
func (b *Box) Padded() bool {
	return tobool(C.uiBoxPadded(b.b))
}

// SetPadded controls whether there is space between each control
// of the Box. The size of the padding is determined by the OS and
// its best practices.
func (b *Box) SetPadded(padded bool) {
	C.uiBoxSetPadded(b.b, frombool(padded))
}


================================================
FILE: button.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Button is a Control that represents a button that the user can
// click to perform an action. A Button has a text label that should
// describe what the button does.
type Button struct {
	ControlBase
	b	*C.uiButton
	onClicked		func(*Button)
}

// NewButton creates a new Button with the given text as its label.
func NewButton(text string) *Button {
	b := new(Button)

	ctext := C.CString(text)
	b.b = C.uiNewButton(ctext)
	freestr(ctext)

	C.pkguiButtonOnClicked(b.b)

	b.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))
	return b
}

// Text returns the Button's text.
func (b *Button) Text() string {
	ctext := C.uiButtonText(b.b)
	text := C.GoString(ctext)
	C.uiFreeText(ctext)
	return text
}

// SetText sets the Button's text to text.
func (b *Button) SetText(text string) {
	ctext := C.CString(text)
	C.uiButtonSetText(b.b, ctext)
	freestr(ctext)
}

// OnClicked registers f to be run when the user clicks the Button.
// Only one function can be registered at a time.
func (b *Button) OnClicked(f func(*Button)) {
	b.onClicked = f
}

//export pkguiDoButtonOnClicked
func pkguiDoButtonOnClicked(bb *C.uiButton, data unsafe.Pointer) {
	b := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*Button)
	if b.onClicked != nil {
		b.onClicked(b)
	}
}


================================================
FILE: checkbox.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Checkbox is a Control that represents a box with a text label at its
// side. When the user clicks the checkbox, a check mark will appear
// in the box; clicking it again removes the check.
type Checkbox struct {
	ControlBase
	c	*C.uiCheckbox
	onToggled		func(*Checkbox)
}

// NewCheckbox creates a new Checkbox with the given text as its
// label.
func NewCheckbox(text string) *Checkbox {
	c := new(Checkbox)

	ctext := C.CString(text)
	c.c = C.uiNewCheckbox(ctext)
	freestr(ctext)

	C.pkguiCheckboxOnToggled(c.c)

	c.ControlBase = NewControlBase(c, uintptr(unsafe.Pointer(c.c)))
	return c
}

// Text returns the Checkbox's text.
func (c *Checkbox) Text() string {
	ctext := C.uiCheckboxText(c.c)
	text := C.GoString(ctext)
	C.uiFreeText(ctext)
	return text
}

// SetText sets the Checkbox's text to text.
func (c *Checkbox) SetText(text string) {
	ctext := C.CString(text)
	C.uiCheckboxSetText(c.c, ctext)
	freestr(ctext)
}

// OnToggled registers f to be run when the user clicks the Checkbox.
// Only one function can be registered at a time.
func (c *Checkbox) OnToggled(f func(*Checkbox)) {
	c.onToggled = f
}

//export pkguiDoCheckboxOnToggled
func pkguiDoCheckboxOnToggled(cc *C.uiCheckbox, data unsafe.Pointer) {
	c := ControlFromLibui(uintptr(unsafe.Pointer(cc))).(*Checkbox)
	if c.onToggled != nil {
		c.onToggled(c)
	}
}

// Checked returns whether the Checkbox is checked.
func (c *Checkbox) Checked() bool {
	return tobool(C.uiCheckboxChecked(c.c))
}

// SetChecked sets whether the Checkbox is checked.
func (c *Checkbox) SetChecked(checked bool) {
	C.uiCheckboxSetChecked(c.c, frombool(checked))
}


================================================
FILE: colorbutton.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// ColorButton is a Control that represents a button that the user can
// click to select a color.
type ColorButton struct {
	ControlBase
	b	*C.uiColorButton
	onChanged		func(*ColorButton)
}

// NewColorButton creates a new ColorButton.
func NewColorButton() *ColorButton {
	b := new(ColorButton)

	b.b = C.uiNewColorButton()

	C.pkguiColorButtonOnChanged(b.b)

	b.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))
	return b
}

// Color returns the color currently selected in the ColorButton.
// Colors are not alpha-premultiplied.
// TODO rename b or bl
func (b *ColorButton) Color() (r, g, bl, a float64) {
	c := C.pkguiAllocColorDoubles()
	defer C.pkguiFreeColorDoubles(c)
	C.uiColorButtonColor(b.b, c.r, c.g, c.b, c.a)
	return float64(*(c.r)), float64(*(c.g)), float64(*(c.b)), float64(*(c.a))
}

// SetColor sets the currently selected color in the ColorButton.
// Colors are not alpha-premultiplied.
// TODO rename b or bl
func (b *ColorButton) SetColor(r, g, bl, a float64) {
	C.uiColorButtonSetColor(b.b, C.double(r), C.double(g), C.double(bl), C.double(a))
}

// OnChanged registers f to be run when the user changes the
// currently selected color in the ColorButton. Only one function
// can be registered at a time.
func (b *ColorButton) OnChanged(f func(*ColorButton)) {
	b.onChanged = f
}

//export pkguiDoColorButtonOnChanged
func pkguiDoColorButtonOnChanged(bb *C.uiColorButton, data unsafe.Pointer) {
	b := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*ColorButton)
	if b.onChanged != nil {
		b.onChanged(b)
	}
}


================================================
FILE: combobox.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Combobox is a Control that represents a drop-down list of strings
// that the user can choose one of at any time. For a Combobox that
// users can type values into, see EditableCombobox.
type Combobox struct {
	ControlBase
	c	*C.uiCombobox
	onSelected		func(*Combobox)
}

// NewCombobox creates a new Combobox.
func NewCombobox() *Combobox {
	c := new(Combobox)

	c.c = C.uiNewCombobox()

	C.pkguiComboboxOnSelected(c.c)

	c.ControlBase = NewControlBase(c, uintptr(unsafe.Pointer(c.c)))
	return c
}

// Append adds the named item to the end of the Combobox.
func (c *Combobox) Append(text string) {
	ctext := C.CString(text)
	C.uiComboboxAppend(c.c, ctext)
	freestr(ctext)
}

// Selected returns the index of the currently selected item in the
// Combobox, or -1 if nothing is selected.
func (c *Combobox) Selected() int {
	return int(C.uiComboboxSelected(c.c))
}

// SetSelected sets the currently selected item in the Combobox
// to index. If index is -1 no item will be selected.
func (c *Combobox) SetSelected(index int) {
	C.uiComboboxSetSelected(c.c, C.int(index))
}

// OnSelected registers f to be run when the user selects an item in
// the Combobox. Only one function can be registered at a time.
func (c *Combobox) OnSelected(f func(*Combobox)) {
	c.onSelected = f
}

//export pkguiDoComboboxOnSelected
func pkguiDoComboboxOnSelected(cc *C.uiCombobox, data unsafe.Pointer) {
	c := ControlFromLibui(uintptr(unsafe.Pointer(cc))).(*Combobox)
	if c.onSelected != nil {
		c.onSelected(c)
	}
}


================================================
FILE: control.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// no need to lock this; only the GUI thread can access it
var controls = make(map[*C.uiControl]Control)

// Control represents a GUI control. It provdes methods
// common to all Controls.
// 
// The preferred way to create new Controls is to use
// ControlBase; see ControlBase below.
type Control interface {
	// LibuiControl returns the uiControl pointer for the Control.
	// This is intended for use when adding a control to a
	// container.
	LibuiControl() uintptr

	// Destroy destroys the Control.
	Destroy()

	// Handle returns the OS-level handle that backs the
	// Control. On OSs that use reference counting for
	// controls, Handle does not increment the reference
	// count; you are sharing package ui's reference.
	Handle() uintptr

	// Visible returns whether the Control is visible.
	Visible() bool

	// Show shows the Control.
	Show()

	// Hide shows the Control. Hidden controls do not participate
	// in layout (that is, Box, Grid, etc. does not reserve space for
	// hidden controls).
	Hide()

	// Enabled returns whether the Control is enabled.
	Enabled() bool

	// Enable enables the Control.
	Enable()

	// Disable disables the Control.
	Disable()
}

// ControlBase is an implementation of Control that provides
// all the methods that Control requires. To use it, embed a
// ControlBase (not a *ControlBase) into your structure, then
// assign the result of NewControlBase to that field:
// 
// 	type MyControl struct {
// 		ui.ControlBase
// 		c *C.MyControl
// 	}
// 	
// 	func NewMyControl() *MyControl {
// 		m := &NewMyControl{
// 			c: C.newMyControl(),
// 		}
// 		m.ControlBase = ui.NewControlBase(m, uintptr(unsafe.Pointer(c)))
// 		return m
// 	}
type ControlBase struct {
	iface		Control
	c		*C.uiControl
}

// NewControlBase creates a new ControlBase. See the
// documentation of ControlBase for an example.
// NewControl should only be called once per instance of Control.
func NewControlBase(iface Control, c uintptr) ControlBase {
	b := ControlBase{
		iface:	iface,
		c:		(*C.uiControl)(unsafe.Pointer(c)),
	}
	controls[b.c] = b.iface
	return b
}

func (c *ControlBase) LibuiControl() uintptr {
	return uintptr(unsafe.Pointer(c.c))
}

func (c *ControlBase) Destroy() {
	delete(controls, c.c)
	C.uiControlDestroy(c.c)
}

func (c *ControlBase) Handle() uintptr {
	return uintptr(C.uiControlHandle(c.c))
}

func (c *ControlBase) Visible() bool {
	return tobool(C.uiControlVisible(c.c))
}

func (c *ControlBase) Show() {
	C.uiControlShow(c.c)
}

func (c *ControlBase) Hide() {
	C.uiControlHide(c.c)
}

func (c *ControlBase) Enabled() bool {
	return tobool(C.uiControlEnabled(c.c))
}

func (c *ControlBase) Enable() {
	C.uiControlEnable(c.c)
}

func (c *ControlBase) Disable() {
	C.uiControlDisable(c.c)
}

// ControlFromLibui returns the Control associated with a libui
// uiControl. This is intended for implementing event handlers
// on the Go side, to prevent sharing Go pointers with C.
// This function only works on Controls that use ControlBase.
func ControlFromLibui(c uintptr) Control {
	// comma-ok form to avoid creating nil entries
	cc, _ := controls[(*C.uiControl)(unsafe.Pointer(c))]
	return cc
}

func touiControl(c uintptr) *C.uiControl {
	return (*C.uiControl)(unsafe.Pointer(c))
}

// LibuiFreeText allows implementations of Control
// to call the libui function uiFreeText.
func LibuiFreeText(c uintptr) {
	C.uiFreeText((*C.char)(unsafe.Pointer(c)))
}


================================================
FILE: datetimepicker.go
================================================
// 12 december 2015

package ui

import (
	"time"
	"unsafe"
)

// #include "pkgui.h"
import "C"

// DateTimePicker is a Control that represents a field where the user
// can enter a date and/or a time.
type DateTimePicker struct {
	ControlBase
	d	*C.uiDateTimePicker
	onChanged	func(*DateTimePicker)
}

func finishNewDateTimePicker(dd *C.uiDateTimePicker) *DateTimePicker {
	d := new(DateTimePicker)

	d.d = dd

	C.pkguiDateTimePickerOnChanged(d.d)

	d.ControlBase = NewControlBase(d, uintptr(unsafe.Pointer(d.d)))
	return d
}

// NewDateTimePicker creates a new DateTimePicker that shows
// both a date and a time.
func NewDateTimePicker() *DateTimePicker {
	return finishNewDateTimePicker(C.uiNewDateTimePicker())
}

// NewDatePicker creates a new DateTimePicker that shows
// only a date.
func NewDatePicker() *DateTimePicker {
	return finishNewDateTimePicker(C.uiNewDatePicker())
}

// NewTimePicker creates a new DateTimePicker that shows
// only a time.
func NewTimePicker() *DateTimePicker {
	return finishNewDateTimePicker(C.uiNewTimePicker())
}

// Time returns the time stored in the uiDateTimePicker.
// The time is assumed to be local time.
func (d *DateTimePicker) Time() time.Time {
	tm := C.pkguiAllocTime()
	defer C.pkguiFreeTime(tm)
	C.uiDateTimePickerTime(d.d, tm)
	return time.Date(
		int(tm.tm_year + 1900),
		time.Month(tm.tm_mon + 1),
		int(tm.tm_mday),
		int(tm.tm_hour),
		int(tm.tm_min),
		int(tm.tm_sec),
		0, time.Local)
}

// SetTime sets the time in the DateTimePicker to t.
// t's components are read as-is via t.Date() and t.Clock();
// no time zone manipulations are done.
func (d *DateTimePicker) SetTime(t time.Time) {
	tm := C.pkguiAllocTime()
	defer C.pkguiFreeTime(tm)
	year, mon, mday := t.Date()
	tm.tm_year = C.int(year - 1900)
	tm.tm_mon = C.int(mon - 1)
	tm.tm_mday = C.int(mday)
	hour, min, sec := t.Clock()
	tm.tm_hour = C.int(hour)
	tm.tm_min = C.int(min)
	tm.tm_sec = C.int(sec)
	tm.tm_isdst = -1
	C.uiDateTimePickerSetTime(d.d, tm)
}

// OnChanged registers f to be run when the user changes the time
// in the DateTimePicker. Only one function can be registered at a
// time.
func (d *DateTimePicker) OnChanged(f func(*DateTimePicker)) {
	d.onChanged = f
}

//export pkguiDoDateTimePickerOnChanged
func pkguiDoDateTimePickerOnChanged(dd *C.uiDateTimePicker, data unsafe.Pointer) {
	d := ControlFromLibui(uintptr(unsafe.Pointer(dd))).(*DateTimePicker)
	if d.onChanged != nil {
		d.onChanged(d)
	}
}


================================================
FILE: draw.go
================================================
// 13 december 2015

package ui

// #include "pkgui.h"
import "C"

// DrawPath represents a geometric path in a drawing context.
// This is the basic unit of drawing: all drawing operations consist of
// forming a path, then stroking, filling, or clipping to that path.
// A path is an OS resource; you must explicitly free it when finished.
// Paths consist of multiple figures. Once you have added all the
// figures to a path, you must "end" the path to make it ready to draw
// with.
// TODO rewrite all that
// 
// Or more visually, the lifecycle of a Path is
// 	p := DrawNewPath()
// 	for every figure {
// 		p.NewFigure(...) // or NewFigureWithArc
// 		p.LineTo(...)    // any number of these in any order
// 		p.ArcTo(...)
// 		p.BezierTo(...)
// 		if figure should be closed {
// 			p.CloseFigure()
// 		}
// 	}
// 	p.End()
// 	// ...
// 	dp.Context.Stroke(p, ...) // any number of these in any order
// 	dp.Context.Fill(p, ...)
// 	dp.Context.Clip(p)
// 	// ...
// 	p.Free() // when done with the path
// 
// A DrawPath also defines its fill mode. (This should ideally be a fill
// parameter, but some implementations prevent it.)
// TODO talk about fill modes
type DrawPath struct {
	p	*C.uiDrawPath
}

// TODO
// 
// TODO disclaimer
type DrawFillMode uint
const (
	DrawFillModeWinding DrawFillMode = iota
	DrawFillModeAlternate
)

// DrawNewPath creates a new DrawPath with the given fill mode.
func DrawNewPath(fillMode DrawFillMode) *DrawPath {
	var fm C.uiDrawFillMode

	switch fillMode {
	case DrawFillModeWinding:
		fm = C.uiDrawFillModeWinding
	case DrawFillModeAlternate:
		fm = C.uiDrawFillModeAlternate
	default:
		panic("invalid fill mode passed to ui.NewPath()")
	}
	return &DrawPath{
		p:	C.uiDrawNewPath(fm),
	}
}

// Free destroys a DrawPath. After calling Free the DrawPath cannot
// be used.
func (p *DrawPath) Free() {
	C.uiDrawFreePath(p.p)
}

// NewFigure starts a new figure in the DrawPath. The current point
// is set to the given point.
func (p *DrawPath) NewFigure(x float64, y float64) {
	C.uiDrawPathNewFigure(p.p, C.double(x), C.double(y))
}

// NewFigureWithArc starts a new figure in the DrawPath and adds
// an arc as the first element of the figure. Unlike ArcTo,
// NewFigureWithArc does not draw an initial line segment.
// Otherwise, see ArcTo.
func (p *DrawPath) NewFigureWithArc(xCenter float64, yCenter float64, radius float64, startAngle float64, sweep float64, isNegative bool) {
	C.uiDrawPathNewFigureWithArc(p.p,
		C.double(xCenter), C.double(yCenter),
		C.double(radius),
		C.double(startAngle), C.double(sweep),
		frombool(isNegative))
}

// LineTo adds a line to the current figure of the DrawPath starting
// from the current point and ending at the given point. The current
// point is set to the ending point.
func (p *DrawPath) LineTo(x float64, y float64) {
	C.uiDrawPathLineTo(p.p, C.double(x), C.double(y))
}

// ArcTo adds a circular arc to the current figure of the DrawPath.
// You pass it the center of the arc, its radius in radians, the starting
// angle (couterclockwise) in radians, and the number of radians the
// arc should sweep (counterclockwise). A line segment is drawn from
// the current point to the start of the arc. The current point is set to
// the end of the arc.
func (p *DrawPath) ArcTo(xCenter float64, yCenter float64, radius float64, startAngle float64, sweep float64, isNegative bool) {
	C.uiDrawPathArcTo(p.p,
		C.double(xCenter), C.double(yCenter),
		C.double(radius),
		C.double(startAngle), C.double(sweep),
		frombool(isNegative))
}

// BezierTo adds a cubic Bezier curve to the current figure of the
// DrawPath. Its start point is the current point. c1x and c1y are the
// first control point. c2x and c2y are the second control point. endX
// and endY are the end point. The current point is set to the end
// point.
func (p *DrawPath) BezierTo(c1x float64, c1y float64, c2x float64, c2y float64, endX float64, endY float64) {
	C.uiDrawPathBezierTo(p.p,
		C.double(c1x), C.double(c1y),
		C.double(c2x), C.double(c2y),
		C.double(endX), C.double(endY))
}

// CloseFigure draws a line segment from the current point of the
// current figure of the DrawPath back to its initial point. After calling
// this, the current figure is over and you must either start a new
// figure or end the DrawPath. If this is not called and you start a
// new figure or end the DrawPath, then the current figure will not
// have this closing line segment added to it (but the figure will still
// be over).
func (p *DrawPath) CloseFigure() {
	C.uiDrawPathCloseFigure(p.p)
}

// AddRectangle creates a new figure in the DrawPath that consists
// entirely of a rectangle whose top-left corner is at the given point
// and whose size is the given size. The rectangle is a closed figure;
// you must either start a new figure or end the Path after calling
// this method.
func (p *DrawPath) AddRectangle(x float64, y float64, width float64, height float64) {
	C.uiDrawPathAddRectangle(p.p, C.double(x), C.double(y), C.double(width), C.double(height))
}

// End ends the current DrawPath. You cannot add figures to a
// DrawPath that has been ended. You cannot draw with a
// DrawPath that has not been ended.
func (p *DrawPath) End() {
	C.uiDrawPathEnd(p.p)
}

// DrawContext represents a drawing surface that you can draw to.
// At present the only DrawContexts are surfaces associated with
// Areas and are provided by package ui; see AreaDrawParams.
type DrawContext struct {
	c	*C.uiDrawContext
}

// DrawBrushType defines the various types of brushes.
// 
// TODO disclaimer
type DrawBrushType int
const (
	DrawBrushTypeSolid DrawBrushType = iota
	DrawBrushTypeLinearGradient
	DrawBrushTypeRadialGradient
	DrawBrushTypeImage		// presently unimplemented
)

// TODO
// 
// TODO disclaimer
// TODO rename these to put LineCap at the beginning? or just Cap?
type DrawLineCap int
const (
	DrawLineCapFlat DrawLineCap = iota
	DrawLineCapRound
	DrawLineCapSquare
)

// TODO
// 
// TODO disclaimer
type DrawLineJoin int
const (
	DrawLineJoinMiter DrawLineJoin = iota
	DrawLineJoinRound
	DrawLineJoinBevel
)

// TODO document
const DrawDefaultMiterLimit = 10.0

// TODO
type DrawBrush struct {
	Type		DrawBrushType

	// If Type is Solid.
	// TODO
	R		float64
	G		float64
	B		float64
	A		float64

	// If Type is LinearGradient or RadialGradient.
	// TODO
	X0			float64	// start point for both
	Y0			float64
	X1			float64	// linear: end point; radial: circle center
	Y1			float64
	OuterRadius	float64	// for radial gradients only
	Stops		[]DrawGradientStop
}

// TODO
type DrawGradientStop struct {
	Pos	float64		// between 0 and 1 inclusive
	R	float64
	G	float64
	B	float64
	A	float64
}

func (b *DrawBrush) toLibui() *C.uiDrawBrush {
	cb := C.pkguiAllocBrush()
	cb.Type = C.uiDrawBrushType(b.Type)
	switch b.Type {
	case DrawBrushTypeSolid:
		cb.R = C.double(b.R)
		cb.G = C.double(b.G)
		cb.B = C.double(b.B)
		cb.A = C.double(b.A)
	case DrawBrushTypeLinearGradient, DrawBrushTypeRadialGradient:
		cb.X0 = C.double(b.X0)
		cb.Y0 = C.double(b.Y0)
		cb.X1 = C.double(b.X1)
		cb.Y1 = C.double(b.Y1)
		cb.OuterRadius = C.double(b.OuterRadius)
		cb.NumStops = C.size_t(len(b.Stops))
		cb.Stops = C.pkguiAllocGradientStops(cb.NumStops)
		for i, s := range b.Stops {
			C.pkguiSetGradientStop(cb.Stops, C.size_t(i),
				C.double(s.Pos),
				C.double(s.R),
				C.double(s.G),
				C.double(s.B),
				C.double(s.A))
		}
	case DrawBrushTypeImage:
		panic("unimplemented")
	default:
		panic("invalid brush type in Brush.toLibui()")
	}
	return cb
}

func freeBrush(cb *C.uiDrawBrush) {
	if cb.Type == C.uiDrawBrushTypeLinearGradient || cb.Type == C.uiDrawBrushTypeRadialGradient {
		C.pkguiFreeGradientStops(cb.Stops)
	}
	C.pkguiFreeBrush(cb)
}

// TODO
type DrawStrokeParams struct {
	Cap			DrawLineCap
	Join			DrawLineJoin
	Thickness		float64
	MiterLimit		float64
	Dashes		[]float64
	DashPhase	float64
}

func (sp *DrawStrokeParams) toLibui() *C.uiDrawStrokeParams {
	csp := C.pkguiAllocStrokeParams()
	csp.Cap = C.uiDrawLineCap(sp.Cap)
	csp.Join = C.uiDrawLineJoin(sp.Join)
	csp.Thickness = C.double(sp.Thickness)
	csp.MiterLimit = C.double(sp.MiterLimit)
	csp.Dashes = nil
	csp.NumDashes = C.size_t(len(sp.Dashes))
	if csp.NumDashes != 0 {
		csp.Dashes = C.pkguiAllocDashes(csp.NumDashes)
		for i, d := range sp.Dashes {
			C.pkguiSetDash(csp.Dashes, C.size_t(i), C.double(d))
		}
	}
	csp.DashPhase = C.double(sp.DashPhase)
	return csp
}

func freeStrokeParams(csp *C.uiDrawStrokeParams) {
	if csp.Dashes != nil {
		C.pkguiFreeDashes(csp.Dashes)
	}
	C.pkguiFreeStrokeParams(csp)
}

// TODO
func (c *DrawContext) Stroke(p *DrawPath, b *DrawBrush, sp *DrawStrokeParams) {
	cb := b.toLibui()
	defer freeBrush(cb)
	csp := sp.toLibui()
	defer freeStrokeParams(csp)
	C.uiDrawStroke(c.c, p.p, cb, csp)
}

// TODO
func (c *DrawContext) Fill(p *DrawPath, b *DrawBrush) {
	cb := b.toLibui()
	defer freeBrush(cb)
	C.uiDrawFill(c.c, p.p, cb)
}

// TODO
// TODO should the methods of these return self for chaining?
type DrawMatrix struct {
	M11		float64
	M12		float64
	M21		float64
	M22		float64
	M31		float64
	M32		float64
}

// TODO identity matrix
func DrawNewMatrix() *DrawMatrix {
	m := new(DrawMatrix)
	m.SetIdentity()
	return m
}

// TODO
func (m *DrawMatrix) SetIdentity() {
	m.M11 = 1
	m.M12 = 0
	m.M21 = 0
	m.M22 = 1
	m.M31 = 0
	m.M32 = 0
}

func (m *DrawMatrix) toLibui() *C.uiDrawMatrix {
	cm := C.pkguiAllocMatrix()
	cm.M11 = C.double(m.M11)
	cm.M12 = C.double(m.M12)
	cm.M21 = C.double(m.M21)
	cm.M22 = C.double(m.M22)
	cm.M31 = C.double(m.M31)
	cm.M32 = C.double(m.M32)
	return cm
}

func (m *DrawMatrix) fromLibui(cm *C.uiDrawMatrix) {
	m.M11 = float64(cm.M11)
	m.M12 = float64(cm.M12)
	m.M21 = float64(cm.M21)
	m.M22 = float64(cm.M22)
	m.M31 = float64(cm.M31)
	m.M32 = float64(cm.M32)
	C.pkguiFreeMatrix(cm)
}

// TODO
func (m *DrawMatrix) Translate(x float64, y float64) {
	cm := m.toLibui()
	C.uiDrawMatrixTranslate(cm, C.double(x), C.double(y))
	m.fromLibui(cm)
}

// TODO
func (m *DrawMatrix) Scale(xCenter float64, yCenter float64, x float64, y float64) {
	cm := m.toLibui()
	C.uiDrawMatrixScale(cm,
		C.double(xCenter), C.double(yCenter),
		C.double(x), C.double(y))
	m.fromLibui(cm)
}

// TODO
func (m *DrawMatrix) Rotate(x float64, y float64, amount float64) {
	cm := m.toLibui()
	C.uiDrawMatrixRotate(cm, C.double(x), C.double(y), C.double(amount))
	m.fromLibui(cm)
}

// TODO
func (m *DrawMatrix) Skew(x float64, y float64, xamount float64, yamount float64) {
	cm := m.toLibui()
	C.uiDrawMatrixSkew(cm,
		C.double(x), C.double(y),
		C.double(xamount), C.double(yamount))
	m.fromLibui(cm)
}

// TODO
func (m *DrawMatrix) Multiply(m2 *DrawMatrix) {
	cm := m.toLibui()
	cm2 := m2.toLibui()
	C.uiDrawMatrixMultiply(cm, cm2)
	C.pkguiFreeMatrix(cm2)
	m.fromLibui(cm)
}

// TODO
func (m *DrawMatrix) Invertible() bool {
	cm := m.toLibui()
	res := C.uiDrawMatrixInvertible(cm)
	C.pkguiFreeMatrix(cm)
	return tobool(res)
}

// TODO
// 
// If m is not invertible, false is returned and m is left unchanged.
func (m *DrawMatrix) Invert() bool {
	cm := m.toLibui()
	res := C.uiDrawMatrixInvert(cm)
	m.fromLibui(cm)
	return tobool(res)
}

// TODO unimplemented
func (m *DrawMatrix) TransformPoint(x float64, y float64) (xout float64, yout float64) {
	panic("TODO")
}

// TODO unimplemented
func (m *DrawMatrix) TransformSize(x float64, y float64) (xout float64, yout float64) {
	panic("TODO")
}

// TODO
func (c *DrawContext) Transform(m *DrawMatrix) {
	cm := m.toLibui()
	C.uiDrawTransform(c.c, cm)
	C.pkguiFreeMatrix(cm)
}

// TODO
func (c *DrawContext) Clip(p *DrawPath) {
	C.uiDrawClip(c.c, p.p)
}

// TODO
func (c *DrawContext) Save() {
	C.uiDrawSave(c.c)
}

// TODO
func (c *DrawContext) Restore() {
	C.uiDrawRestore(c.c)
}


================================================
FILE: drawtext.go
================================================
// 12 august 2018

package ui

// #include "pkgui.h"
import "C"

// Attribute stores information about an attribute in an
// AttributedString.
//
// The following types can be used as Attributes:
//
// 	- TextFamily
// 	- TextSize
// 	- TextWeight
// 	- TextItalic
// 	- TextStretch
// 	- TextColor
// 	- TextBackground
// 	- Underline
// 	- UnderlineColor
// 	- UnderlineColorCustom
// 	- OpenTypeFeatures
//
// For every Unicode codepoint in the AttributedString, at most one
// value of each attribute type can be applied.
type Attribute interface {
	toLibui() *C.uiAttribute
}

// TextFamily is an Attribute that changes the font family of the text
// it is applied to. Font family names are case-insensitive.
type TextFamily string

func (f TextFamily) toLibui() *C.uiAttribute {
	fstr := C.CString(string(f))
	defer freestr(fstr)
	return C.uiNewFamilyAttribute(fstr)
}

// TextSize is an Attribute that changes the size of the text it is
// applied to, in typographical points.
type TextSize float64

func (s TextSize) toLibui() *C.uiAttribute {
	return C.uiNewSizeAttribute(C.double(s))
}

// TextWeight is an Attribute that changes the weight of the text
// it is applied to. These roughly map to the OS/2 text weight field
// of TrueType and OpenType fonts, or to CSS weight numbers. The
// named constants are nominal values; the actual values may vary
// by font and by OS, though this isn't particularly likely. Any value
// between TextWeightMinimum and TextWeightMaximum,
// inclusive, is allowed.
//
// Note that due to restrictions in early versions of Windows, some
// fonts have "special" weights be exposed in many programs as
// separate font families. This is perhaps most notable with
// Arial Black. Package ui does not do this, even on Windows
// (because the DirectWrite API libui uses on Windows does not do
// this); to specify Arial Black, use family Arial and weight
// TextWeightBlack.
type TextWeight int
const (
	TextWeightMinimum TextWeight = 0
	TextWeightThin TextWeight = 100
	TextWeightUltraLight TextWeight = 200
	TextWeightLight TextWeight = 300
	TextWeightBook TextWeight = 350
	TextWeightNormal TextWeight = 400
	TextWeightMedium TextWeight = 500
	TextWeightSemiBold TextWeight = 600
	TextWeightBold TextWeight = 700
	TextWeightUltraBold TextWeight = 800
	TextWeightHeavy TextWeight = 900
	TextWeightUltraHeavy TextWeight = 950
	TextWeightMaximum TextWeight = 1000
)

func (w TextWeight) toLibui() *C.uiAttribute {
	return C.uiNewWeightAttribute(C.uiTextWeight(w))
}

// TextItalic is an Attribute that changes the italic mode of the text
// it is applied to. Italic represents "true" italics where the slanted
// glyphs have custom shapes, whereas oblique represents italics
// that are merely slanted versions of the normal glyphs. Most fonts
// usually have one or the other.
type TextItalic int
const (
	TextItalicNormal TextItalic = iota
	TextItalicOblique
	TextItalicItalic
)

func (i TextItalic) toLibui() *C.uiAttribute {
	return C.uiNewItalicAttribute(C.uiTextItalic(i))
}

// TextStretch is an Attribute that changes the stretch (also called
// "width") of the text it is applied to.
//
// Note that due to restrictions in early versions of Windows, some
// fonts have "special" stretches be exposed in many programs as
// separate font families. This is perhaps most notable with
// Arial Condensed. Package ui does not do this, even on Windows
// (because the DirectWrite API package ui uses on Windows does
// not do this); to specify Arial Condensed, use family Arial and
// stretch TextStretchCondensed.
type TextStretch int
const (
	TextStretchUltraCondensed TextStretch = iota
	TextStretchExtraCondensed
	TextStretchCondensed
	TextStretchSemiCondensed
	TextStretchNormal
	TextStretchSemiExpanded
	TextStretchExpanded
	TextStretchExtraExpanded
	TextStretchUltraExpanded
)

func (s TextStretch) toLibui() *C.uiAttribute {
	return C.uiNewStretchAttribute(C.uiTextStretch(s))
}

// TextColor is an Attribute that changes the color of the text it is
// applied to.
type TextColor struct {
	R	float64
	G	float64
	B	float64
	A	float64
}

func (c TextColor) toLibui() *C.uiAttribute {
	return C.uiNewColorAttribute(C.double(c.R), C.double(c.G), C.double(c.B), C.double(c.A))
}

// TextBackground is an Attribute that changes the background
// color of the text it is applied to.
type TextBackground struct {
	R	float64
	G	float64
	B	float64
	A	float64
}

func (b TextBackground) toLibui() *C.uiAttribute {
	return C.uiNewBackgroundAttribute(C.double(b.R), C.double(b.G), C.double(b.B), C.double(b.A))
}

// Underline is an Attribute that specifies a type of underline to use
// on text.
type Underline int
const (
	UnderlineNone Underline = iota
	UnderlineSingle
	UnderlineDouble
	UnderlineSuggestion		// wavy or dotted underlines used for spelling/grammar checkers
)

func (u Underline) toLibui() *C.uiAttribute {
	return C.uiNewUnderlineAttribute(C.uiUnderline(u))
}

// UnderlineColor is an Attribute that changes the color of any
// underline on the text it is applied to, regardless of the type of
// underline. In addition to being able to specify the
// platform-specific colors for suggestion underlines here, you can
// also use a custom color with UnderlineColorCustom.
// 
// To use the constants here correctly, pair them with
// UnderlineSuggestion (though they can be used on other types of
// underline as well).
// 
// If an underline type is applied but no underline color is
// specified, the text color is used instead. If an underline color
// is specified without an underline type, the underline color
// attribute is ignored, but not removed from the uiAttributedString.
type UnderlineColor int
const (
	UnderlineColorSpelling UnderlineColor = iota + 1
	UnderlineColorGrammar
	UnderlineColorAuxiliary		// for instance, the color used by smart replacements on macOS or in Microsoft Office
)

func (u UnderlineColor) toLibui() *C.uiAttribute {
	return C.uiNewUnderlineColorAttribute(C.uiUnderlineColor(u), 0, 0, 0, 0)
}

// UnderlineColorCustom is an Attribute like UnderlineColor, except
// it allows specifying a custom color.
type UnderlineColorCustom struct {
	R	float64
	G	float64
	B	float64
	A	float64
}

func (u UnderlineColorCustom) toLibui() *C.uiAttribute {
	return C.uiNewUnderlineColorAttribute(C.uiUnderlineColorCustom, C.double(u.R), C.double(u.G), C.double(u.B), C.double(u.A))
}

// OpenTypeFeatures is an Attribute that represents a set of
// OpenType feature tag-value pairs, for applying OpenType
// features to text. OpenType feature tags are four-character codes
// defined by OpenType that cover things from design features like
// small caps and swashes to language-specific glyph shapes and
// beyond. Each tag may only appear once in any given
// uiOpenTypeFeatures instance. Each value is a 32-bit integer,
// often used as a Boolean flag, but sometimes as an index to choose
// a glyph shape to use.
// 
// If a font does not support a certain feature, that feature will be
// ignored. (TODO verify this on all OSs)
// 
// See the OpenType specification at
// https://www.microsoft.com/typography/otspec/featuretags.htm
// for the complete list of available features, information on specific
// features, and how to use them.
// TODO invalid features
// 
// Note that if a feature is not present in a OpenTypeFeatures,
// the feature is NOT treated as if its value was zero, unlike in Go.
// Script-specific font shaping rules and font-specific feature
// settings may use a different default value for a feature. You
// should likewise NOT treat a missing feature as having a value of
// zero either. Instead, a missing feature should be treated as
// having some unspecified default value.
// 
// Note that despite OpenTypeFeatures being a map, its contents
// are copied by AttributedString. Modifying an OpenTypeFeatures
// after giving it to an AttributedString, or modifying one that comes
// out of an AttributedString, will have no effect.
type OpenTypeFeatures map[OpenTypeTag]uint32

func (o OpenTypeFeatures) toLibui() *C.uiAttribute {
	otf := C.uiNewOpenTypeFeatures()
	defer C.uiFreeOpenTypeFeatures(otf)
	for tag, value := range o {
		a := byte((tag >> 24) & 0xFF)
		b := byte((tag >> 16) & 0xFF)
		c := byte((tag >> 8) & 0xFF)
		d := byte(tag & 0xFF)
		C.uiOpenTypeFeaturesAdd(otf, C.char(a), C.char(b), C.char(c), C.char(d), C.uint32_t(value))
	}
	return C.uiNewFeaturesAttribute(otf)
}

// OpenTypeTag represents a four-byte OpenType feature tag.
type OpenTypeTag uint32

// ToOpenTypeTag converts the four characters a, b, c, and d into
// an OpenTypeTag.
func ToOpenTypeTag(a, b, c, d byte) OpenTypeTag {
	return (OpenTypeTag(a) << 24) |
		(OpenTypeTag(b) << 16) |
		(OpenTypeTag(c) << 8) |
		OpenTypeTag(d)
}

func attributeFromLibui(a *C.uiAttribute) Attribute {
	switch C.uiAttributeGetType(a) {
	case C.uiAttributeTypeFamily:
		cf := C.uiAttributeFamily(a)
		return TextFamily(C.GoString(cf))
	case C.uiAttributeTypeSize:
		return TextSize(C.uiAttributeSize(a))
	case C.uiAttributeTypeWeight:
		return TextWeight(C.uiAttributeWeight(a))
	case C.uiAttributeTypeItalic:
		return TextItalic(C.uiAttributeItalic(a))
	case C.uiAttributeTypeStretch:
		return TextStretch(C.uiAttributeStretch(a))
	case C.uiAttributeTypeColor:
		cc := C.pkguiAllocColorDoubles()
		defer C.pkguiFreeColorDoubles(cc)
		C.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a)
		return TextColor{
			R:	float64(*(cc.r)),
			G:	float64(*(cc.g)),
			B:	float64(*(cc.b)),
			A:	float64(*(cc.a)),
		}
	case C.uiAttributeTypeBackground:
		cc := C.pkguiAllocColorDoubles()
		defer C.pkguiFreeColorDoubles(cc)
		C.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a)
		return TextBackground{
			R:	float64(*(cc.r)),
			G:	float64(*(cc.g)),
			B:	float64(*(cc.b)),
			A:	float64(*(cc.a)),
		}
	case C.uiAttributeTypeUnderline:
		return Underline(C.uiAttributeUnderline(a))
	case C.uiAttributeTypeUnderlineColor:
		cu := C.pkguiNewUnderlineColor()
		defer C.pkguiFreeUnderlineColor(cu)
		cc := C.pkguiAllocColorDoubles()
		defer C.pkguiFreeColorDoubles(cc)
		C.uiAttributeUnderlineColor(a, cu, cc.r, cc.g, cc.b, cc.a)
		if *cu == C.uiUnderlineColorCustom {
			return UnderlineColorCustom{
				R:	float64(*(cc.r)),
				G:	float64(*(cc.g)),
				B:	float64(*(cc.b)),
				A:	float64(*(cc.a)),
			}
		}
		return UnderlineColor(*cu)
	case C.uiAttributeTypeFeatures:
		// TODO
	}
	panic("unreachable")
}

// AttributedString represents a string of UTF-8 text that can
// optionally be embellished with formatting attributes. Package ui
// provides the list of formatting attributes, which cover common
// formatting traits like boldface and color as well as advanced
// typographical features provided by OpenType like superscripts
// and small caps. These attributes can be combined in a variety of
// ways.
//
// Attributes are applied to runs of Unicode codepoints in the string.
// Zero-length runs are elided. Consecutive runs that have the same
// attribute type and value are merged. Each attribute is independent
// of each other attribute; overlapping attributes of different types
// do not split each other apart, but different values of the same
// attribute type do.
//
// The empty string can also be represented by AttributedString,
// but because of the no-zero-length-attribute rule, it will not have
// attributes.
//
// Unlike Go strings, AttributedStrings are mutable.
//
// AttributedString allocates resources within libui, which package
// ui sits on top of. As such, when you are finished with an
// AttributedString, you must free it with Free. Like other things in
// package ui, AttributedString must only be used from the main
// goroutine.
//
// In addition, AttributedString provides facilities for moving
// between grapheme clusters, which represent a character
// from the point of view of the end user. The cursor of a text editor
// is always placed on a grapheme boundary, so you can use these
// features to move the cursor left or right by one "character".
// TODO does uiAttributedString itself need this
//
// AttributedString does not provide enough information to be able
// to draw itself onto a DrawContext or respond to user actions.
// In order to do that, you'll need to use a DrawTextLayout, which
// is built from the combination of an AttributedString and a set of
// layout-specific properties.
type AttributedString struct {
	s	*C.uiAttributedString
}

// NewAttributedString creates a new AttributedString from
// initialString. The string will be entirely unattributed.
func NewAttributedString(initialString string) *AttributedString {
	cs := C.CString(initialString)
	defer freestr(cs)
	return &AttributedString{
		s:	C.uiNewAttributedString(cs),
	}
}

// Free destroys s.
func (s *AttributedString) Free() {
	C.uiFreeAttributedString(s.s)
}

// String returns the textual content of s.
func (s *AttributedString) String() string {
	return C.GoString(C.uiAttributedStringString(s.s))
}

// AppendUnattributed adds str to the end of s. The new substring
// will be unattributed.
func (s *AttributedString) AppendUnattributed(str string) {
	cs := C.CString(str)
	defer freestr(cs)
	C.uiAttributedStringAppendUnattributed(s.s, cs)
}

// InsertAtUnattributed adds str to s at the byte position specified by
// at. The new substring will be unattributed; existing attributes will
// be moved along with their text.
func (s *AttributedString) InsertAtUnattributed(str string, at int) {
	cs := C.CString(str)
	defer freestr(cs)
	C.uiAttributedStringInsertAtUnattributed(s.s, cs, C.size_t(at))
}

// Delete deletes the characters and attributes of s in the byte range
// [start, end).
func (s *AttributedString) Delete(start, end int) {
	C.uiAttributedStringDelete(s.s, C.size_t(start), C.size_t(end))
}

// SetAttribute sets a in the byte range [start, end) of s. Any existing
// attributes in that byte range of the same type are removed.
func (s *AttributedString) SetAttribute(a Attribute, start, end int) {
	C.uiAttributedStringSetAttribute(s.s, a.toLibui(), C.size_t(start), C.size_t(end))
}

// TODO uiAttributedStringForEachAttribute
// TODO uiAttributedStringNumGraphemes
// TODO uiAttributedStringByteIndexToGrapheme
// TODO uiAttributedStringGraphemeToByteIndex

// FontDescriptor provides a complete description of a font where
// one is needed. Currently, this means as the default font of a
// DrawTextLayout and as the data returned by FontButton.
type FontDescriptor struct {
	Family	TextFamily
	Size		TextSize
	Weight	TextWeight
	Italic		TextItalic
	Stretch	TextStretch
}

func (d *FontDescriptor) fromLibui(fd *C.uiFontDescriptor) {
	d.Family = TextFamily(C.GoString(fd.Family))
	d.Size = TextSize(fd.Size)
	d.Weight = TextWeight(fd.Weight)
	d.Italic = TextItalic(fd.Italic)
	d.Stretch = TextStretch(fd.Stretch)
}

func (d *FontDescriptor) toLibui() *C.uiFontDescriptor {
	fd := C.pkguiNewFontDescriptor()
	fd.Family = C.CString(string(d.Family))
	fd.Size = C.double(d.Size)
	fd.Weight = C.uiTextWeight(d.Weight)
	fd.Italic = C.uiTextItalic(d.Italic)
	fd.Stretch = C.uiTextStretch(d.Stretch)
	return fd
}

func freeLibuiFontDescriptor(fd *C.uiFontDescriptor) {
	freestr(fd.Family)
	C.pkguiFreeFontDescriptor(fd)
}

// DrawTextLayout is a concrete representation of an
// AttributedString that can be displayed in a DrawContext.
// It includes information important for the drawing of a block of
// text, including the bounding box to wrap the text within, the
// alignment of lines of text within that box, areas to mark as
// being selected, and other things.
//
// Unlike AttributedString, the content of a DrawTextLayout is
// immutable once it has been created.
//
// TODO talk about OS-specific differences with text drawing that libui can't account for...
type DrawTextLayout struct {
	tl	*C.uiDrawTextLayout
}

// DrawTextAlign specifies the alignment of lines of text in a
// DrawTextLayout.
// TODO should this really have Draw in the name?
type DrawTextAlign int
const (
	DrawTextAlignLeft DrawTextAlign = iota
	DrawTextAlignCenter
	DrawTextAlignRight
)

// DrawTextLayoutParams describes a DrawTextLayout.
// DefaultFont is used to render any text that is not attributed
// sufficiently in String. Width determines the width of the bounding
// box of the text; the height is determined automatically.
type DrawTextLayoutParams struct {
	String		*AttributedString
	DefaultFont	*FontDescriptor
	Width		float64
	Align		DrawTextAlign
}

// DrawNewTextLayout() creates a new DrawTextLayout from
// the given parameters.
func DrawNewTextLayout(p *DrawTextLayoutParams) *DrawTextLayout {
	dp := C.pkguiNewDrawTextLayoutParams()
	defer C.pkguiFreeDrawTextLayoutParams(dp)
	dp.String = p.String.s
	dp.DefaultFont = p.DefaultFont.toLibui()
	defer freeLibuiFontDescriptor(dp.DefaultFont)
	dp.Width = C.double(p.Width)
	dp.Align = C.uiDrawTextAlign(p.Align)
	return &DrawTextLayout{
		tl:	C.uiDrawNewTextLayout(dp),
	}
}

// Free frees tl. The underlying AttributedString is not freed.
func (tl *DrawTextLayout) Free() {
	C.uiDrawFreeTextLayout(tl.tl)
}

// Text draws tl in c with the top-left point of tl at (x, y).
func (c *DrawContext) Text(tl *DrawTextLayout, x, y float64) {
	C.uiDrawText(c.c, tl.tl, C.double(x), C.double(y))
}

// TODO uiDrawTextLayoutExtents


================================================
FILE: dummy_windows.cpp
================================================
// 5 june 2016
// This file is only present to force cgo to use the C++ linker instead of the C linker on Windows.


================================================
FILE: editablecombobox.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// EditableCombobox is a Control that represents a drop-down list
// of strings that the user can choose one of at any time. It also has
// an entry field that the user can type an alternate choice into.
type EditableCombobox struct {
	ControlBase
	c	*C.uiEditableCombobox
	onChanged		func(*EditableCombobox)
}

// NewEditableCombobox creates a new EditableCombobox.
func NewEditableCombobox() *EditableCombobox {
	c := new(EditableCombobox)

	c.c = C.uiNewEditableCombobox()

	C.pkguiEditableComboboxOnChanged(c.c)

	c.ControlBase = NewControlBase(c, uintptr(unsafe.Pointer(c.c)))
	return c
}

// Append adds the named item to the end of the EditableCombobox.
func (e *EditableCombobox) Append(text string) {
	ctext := C.CString(text)
	C.uiEditableComboboxAppend(e.c, ctext)
	freestr(ctext)
}

// Text returns the text in the entry of the EditableCombobox, which
// could be one of the choices in the list if the user has selected one.
func (e *EditableCombobox) Text() string {
	ctext := C.uiEditableComboboxText(e.c)
	text := C.GoString(ctext)
	C.uiFreeText(ctext)
	return text
}

// SetText sets the text in the entry of the EditableCombobox.
func (e *EditableCombobox) SetText(text string) {
	ctext := C.CString(text)
	C.uiEditableComboboxSetText(e.c, ctext)
	freestr(ctext)
}

// OnChanged registers f to be run when the user either selects an
// item or changes the text in the EditableCombobox. Only one
// function can be registered at a time.
func (e *EditableCombobox) OnChanged(f func(*EditableCombobox)) {
	e.onChanged = f
}

//export pkguiDoEditableComboboxOnChanged
func pkguiDoEditableComboboxOnChanged(cc *C.uiEditableCombobox, data unsafe.Pointer) {
	e := ControlFromLibui(uintptr(unsafe.Pointer(cc))).(*EditableCombobox)
	if e.onChanged != nil {
		e.onChanged(e)
	}
}


================================================
FILE: entry.go
================================================
// 12 december 2015

// TODO typing in entry in OS X crashes libui
// I've had similar issues with checkboxes on libui
// something's wrong with NSMapTable

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Entry is a Control that represents a space that the user can
// type a single line of text into.
type Entry struct {
	ControlBase
	e	*C.uiEntry
	onChanged		func(*Entry)
}

func finishNewEntry(ee *C.uiEntry) *Entry {
	e := new(Entry)

	e.e = ee

	C.pkguiEntryOnChanged(e.e)

	e.ControlBase = NewControlBase(e, uintptr(unsafe.Pointer(e.e)))
	return e
}

// NewEntry creates a new Entry.
func NewEntry() *Entry {
	return finishNewEntry(C.uiNewEntry())
}

// NewPasswordEntry creates a new Entry whose contents are
// visibly obfuscated, suitable for passwords.
func NewPasswordEntry() *Entry {
	return finishNewEntry(C.uiNewPasswordEntry())
}

// NewSearchEntry creates a new Entry suitable for searching with.
// Changed events may, depending on the system, be delayed
// with a search Entry, to produce a smoother user experience.
func NewSearchEntry() *Entry {
	return finishNewEntry(C.uiNewSearchEntry())
}

// Text returns the Entry's text.
func (e *Entry) Text() string {
	ctext := C.uiEntryText(e.e)
	text := C.GoString(ctext)
	C.uiFreeText(ctext)
	return text
}

// SetText sets the Entry's text to text.
func (e *Entry) SetText(text string) {
	ctext := C.CString(text)
	C.uiEntrySetText(e.e, ctext)
	freestr(ctext)
}

// OnChanged registers f to be run when the user makes a change to
// the Entry. Only one function can be registered at a time.
func (e *Entry) OnChanged(f func(*Entry)) {
	e.onChanged = f
}

//export pkguiDoEntryOnChanged
func pkguiDoEntryOnChanged(ee *C.uiEntry, data unsafe.Pointer) {
	e := ControlFromLibui(uintptr(unsafe.Pointer(ee))).(*Entry)
	if e.onChanged != nil {
		e.onChanged(e)
	}
}

// ReadOnly returns whether the Entry can be changed.
func (e *Entry) ReadOnly() bool {
	return tobool(C.uiEntryReadOnly(e.e))
}

// SetReadOnly sets whether the Entry can be changed.
func (e *Entry) SetReadOnly(ro bool) {
	C.uiEntrySetReadOnly(e.e, frombool(ro))
}


================================================
FILE: examples/controlgallery.go
================================================
// 12 august 2018

// +build OMIT

package main

import (
	"github.com/andlabs/ui"
	_ "github.com/andlabs/ui/winmanifest"
)

var mainwin *ui.Window

func makeBasicControlsPage() ui.Control {
	vbox := ui.NewVerticalBox()
	vbox.SetPadded(true)

	hbox := ui.NewHorizontalBox()
	hbox.SetPadded(true)
	vbox.Append(hbox, false)

	hbox.Append(ui.NewButton("Button"), false)
	hbox.Append(ui.NewCheckbox("Checkbox"), false)

	vbox.Append(ui.NewLabel("This is a label. Right now, labels can only span one line."), false)

	vbox.Append(ui.NewHorizontalSeparator(), false)

	group := ui.NewGroup("Entries")
	group.SetMargined(true)
	vbox.Append(group, true)

group.SetChild(ui.NewNonWrappingMultilineEntry())

	entryForm := ui.NewForm()
	entryForm.SetPadded(true)
	group.SetChild(entryForm)

	entryForm.Append("Entry", ui.NewEntry(), false)
	entryForm.Append("Password Entry", ui.NewPasswordEntry(), false)
	entryForm.Append("Search Entry", ui.NewSearchEntry(), false)
	entryForm.Append("Multiline Entry", ui.NewMultilineEntry(), true)
	entryForm.Append("Multiline Entry No Wrap", ui.NewNonWrappingMultilineEntry(), true)

	return vbox
}

func makeNumbersPage() ui.Control {
	hbox := ui.NewHorizontalBox()
	hbox.SetPadded(true)

	group := ui.NewGroup("Numbers")
	group.SetMargined(true)
	hbox.Append(group, true)

	vbox := ui.NewVerticalBox()
	vbox.SetPadded(true)
	group.SetChild(vbox)

	spinbox := ui.NewSpinbox(0, 100)
	slider := ui.NewSlider(0, 100)
	pbar := ui.NewProgressBar()
	spinbox.OnChanged(func(*ui.Spinbox) {
		slider.SetValue(spinbox.Value())
		pbar.SetValue(spinbox.Value())
	})
	slider.OnChanged(func(*ui.Slider) {
		spinbox.SetValue(slider.Value())
		pbar.SetValue(slider.Value())
	})
	vbox.Append(spinbox, false)
	vbox.Append(slider, false)
	vbox.Append(pbar, false)

	ip := ui.NewProgressBar()
	ip.SetValue(-1)
	vbox.Append(ip, false)

	group = ui.NewGroup("Lists")
	group.SetMargined(true)
	hbox.Append(group, true)

	vbox = ui.NewVerticalBox()
	vbox.SetPadded(true)
	group.SetChild(vbox)

	cbox := ui.NewCombobox()
	cbox.Append("Combobox Item 1")
	cbox.Append("Combobox Item 2")
	cbox.Append("Combobox Item 3")
	vbox.Append(cbox, false)

	ecbox := ui.NewEditableCombobox()
	ecbox.Append("Editable Item 1")
	ecbox.Append("Editable Item 2")
	ecbox.Append("Editable Item 3")
	vbox.Append(ecbox, false)

	rb := ui.NewRadioButtons()
	rb.Append("Radio Button 1")
	rb.Append("Radio Button 2")
	rb.Append("Radio Button 3")
	vbox.Append(rb, false)

	return hbox
}

func makeDataChoosersPage() ui.Control {
	hbox := ui.NewHorizontalBox()
	hbox.SetPadded(true)

	vbox := ui.NewVerticalBox()
	vbox.SetPadded(true)
	hbox.Append(vbox, false)

	vbox.Append(ui.NewDatePicker(), false)
	vbox.Append(ui.NewTimePicker(), false)
	vbox.Append(ui.NewDateTimePicker(), false)
	vbox.Append(ui.NewFontButton(), false)
	vbox.Append(ui.NewColorButton(), false)

	hbox.Append(ui.NewVerticalSeparator(), false)

	vbox = ui.NewVerticalBox()
	vbox.SetPadded(true)
	hbox.Append(vbox, true)

	grid := ui.NewGrid()
	grid.SetPadded(true)
	vbox.Append(grid, false)

	button := ui.NewButton("Open File")
	entry := ui.NewEntry()
	entry.SetReadOnly(true)
	button.OnClicked(func(*ui.Button) {
		filename := ui.OpenFile(mainwin)
		if filename == "" {
			filename = "(cancelled)"
		}
		entry.SetText(filename)
	})
	grid.Append(button,
		0, 0, 1, 1,
		false, ui.AlignFill, false, ui.AlignFill)
	grid.Append(entry,
		1, 0, 1, 1,
		true, ui.AlignFill, false, ui.AlignFill)

	button = ui.NewButton("Save File")
	entry2 := ui.NewEntry()
	entry2.SetReadOnly(true)
	button.OnClicked(func(*ui.Button) {
		filename := ui.SaveFile(mainwin)
		if filename == "" {
			filename = "(cancelled)"
		}
		entry2.SetText(filename)
	})
	grid.Append(button,
		0, 1, 1, 1,
		false, ui.AlignFill, false, ui.AlignFill)
	grid.Append(entry2,
		1, 1, 1, 1,
		true, ui.AlignFill, false, ui.AlignFill)

	msggrid := ui.NewGrid()
	msggrid.SetPadded(true)
	grid.Append(msggrid,
		0, 2, 2, 1,
		false, ui.AlignCenter, false, ui.AlignStart)

	button = ui.NewButton("Message Box")
	button.OnClicked(func(*ui.Button) {
		ui.MsgBox(mainwin,
			"This is a normal message box.",
			"More detailed information can be shown here.")
	})
	msggrid.Append(button,
		0, 0, 1, 1,
		false, ui.AlignFill, false, ui.AlignFill)
	button = ui.NewButton("Error Box")
	button.OnClicked(func(*ui.Button) {
		ui.MsgBoxError(mainwin,
			"This message box describes an error.",
			"More detailed information can be shown here.")
	})
	msggrid.Append(button,
		1, 0, 1, 1,
		false, ui.AlignFill, false, ui.AlignFill)

	return hbox
}

func setupUI() {
	mainwin = ui.NewWindow("libui Control Gallery", 640, 480, true)
	mainwin.OnClosing(func(*ui.Window) bool {
		ui.Quit()
		return true
	})
	ui.OnShouldQuit(func() bool {
		mainwin.Destroy()
		return true
	})

	tab := ui.NewTab()
	mainwin.SetChild(tab)
	mainwin.SetMargined(true)

	tab.Append("Basic Controls", makeBasicControlsPage())
	tab.SetMargined(0, true)

	tab.Append("Numbers and Lists", makeNumbersPage())
	tab.SetMargined(1, true)

	tab.Append("Data Choosers", makeDataChoosersPage())
	tab.SetMargined(2, true)

	mainwin.Show()
}

func main() {
	ui.Main(setupUI)
}


================================================
FILE: examples/drawtext.go
================================================
// 19 august 2018

// +build OMIT

package main

// TODO probably a bug in libui: changing the font away from skia leads to a crash

import (
	"github.com/andlabs/ui"
	_ "github.com/andlabs/ui/winmanifest"
)

var (
	fontButton *ui.FontButton
	alignment *ui.Combobox

	attrstr *ui.AttributedString
)

func appendWithAttributes(what string, attrs ...ui.Attribute) {
	start := len(attrstr.String())
	end := start + len(what)
	attrstr.AppendUnattributed(what)
	for _, a := range attrs {
		attrstr.SetAttribute(a, start, end)
	}
}

func makeAttributedString() {
	attrstr = ui.NewAttributedString(
		"Drawing strings with package ui is done with the ui.AttributedString and ui.DrawTextLayout objects.\n" +
		"ui.AttributedString lets you have a variety of attributes: ")

	appendWithAttributes("font family", ui.TextFamily("Courier New"))
	attrstr.AppendUnattributed(", ")

	appendWithAttributes("font size", ui.TextSize(18))
	attrstr.AppendUnattributed(", ")

	appendWithAttributes("font weight", ui.TextWeightBold)
	attrstr.AppendUnattributed(", ")

	appendWithAttributes("font italicness", ui.TextItalicItalic)
	attrstr.AppendUnattributed(", ")

	appendWithAttributes("font stretch", ui.TextStretchCondensed)
	attrstr.AppendUnattributed(", ")

	appendWithAttributes("text color", ui.TextColor{0.75, 0.25, 0.5, 0.75})
	attrstr.AppendUnattributed(", ")

	appendWithAttributes("text background color", ui.TextBackground{0.5, 0.5, 0.25, 0.5})
	attrstr.AppendUnattributed(", ")

	appendWithAttributes("underline style", ui.UnderlineSingle)
	attrstr.AppendUnattributed(", ")

	attrstr.AppendUnattributed("and ")
	appendWithAttributes("underline color",
		ui.UnderlineDouble,
		ui.UnderlineColorCustom{1.0, 0.0, 0.5, 1.0})
	attrstr.AppendUnattributed(". ")

	attrstr.AppendUnattributed("Furthermore, there are attributes allowing for ")
	appendWithAttributes("special underlines for indicating spelling errors",
		ui.UnderlineSuggestion,
		ui.UnderlineColorSpelling)
	attrstr.AppendUnattributed(" (and other types of errors) ")

	attrstr.AppendUnattributed("and control over OpenType features such as ligatures (for instance, ")
	appendWithAttributes("afford", ui.OpenTypeFeatures{
		ui.ToOpenTypeTag('l', 'i', 'g', 'a'):		0,
	})
	attrstr.AppendUnattributed(" vs. ")
	appendWithAttributes("afford", ui.OpenTypeFeatures{
		ui.ToOpenTypeTag('l', 'i', 'g', 'a'):		1,
	})
	attrstr.AppendUnattributed(").\n")

	attrstr.AppendUnattributed("Use the controls opposite to the text to control properties of the text.")
}

type areaHandler struct{}

func (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) {
	tl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{
		String:		attrstr,
		DefaultFont:	fontButton.Font(),
		Width:		p.AreaWidth,
		Align:		ui.DrawTextAlign(alignment.Selected()),
	})
	defer tl.Free()
	p.Context.Text(tl, 0, 0)
}

func (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
	// do nothing
}

func (areaHandler) MouseCrossed(a *ui.Area, left bool) {
	// do nothing
}

func (areaHandler) DragBroken(a *ui.Area) {
	// do nothing
}

func (areaHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {
	// reject all keys
	return false
}

func setupUI() {
	makeAttributedString()

	mainwin := ui.NewWindow("libui Text-Drawing Example", 640, 480, true)
	mainwin.SetMargined(true)
	mainwin.OnClosing(func(*ui.Window) bool {
		mainwin.Destroy()
		ui.Quit()
		return false
	})
	ui.OnShouldQuit(func() bool {
		mainwin.Destroy()
		return true
	})

	hbox := ui.NewHorizontalBox()
	hbox.SetPadded(true)
	mainwin.SetChild(hbox)

	vbox := ui.NewVerticalBox()
	vbox.SetPadded(true)
	hbox.Append(vbox, false)

	area := ui.NewArea(areaHandler{})

	fontButton = ui.NewFontButton()
	fontButton.OnChanged(func(*ui.FontButton) {
		area.QueueRedrawAll()
	})
	vbox.Append(fontButton, false)

	form := ui.NewForm()
	form.SetPadded(true)
	// TODO on OS X if this is set to 1 then the window can't resize; does the form not have the concept of stretchy trailing space?
	vbox.Append(form, false)

	alignment = ui.NewCombobox()
	// note that the items match with the values of the uiDrawTextAlign values
	alignment.Append("Left")
	alignment.Append("Center")
	alignment.Append("Right")
	alignment.SetSelected(0)		// start with left alignment
	alignment.OnSelected(func(*ui.Combobox) {
		area.QueueRedrawAll()
	})
	form.Append("Alignment", alignment, false)

	hbox.Append(area, true)

	mainwin.Show()
}

func main() {
	ui.Main(setupUI)
}


================================================
FILE: examples/histogram.go
================================================
// 12 august 2018

// +build OMIT

package main

import (
	"math/rand"
	"time"

	"github.com/andlabs/ui"
	_ "github.com/andlabs/ui/winmanifest"
)

var (
	histogram *ui.Area
	datapoints [10]*ui.Spinbox
	colorButton *ui.ColorButton

	currentPoint = -1
)

// some metrics
const (
	xoffLeft = 20		// histogram margins
	yoffTop = 20
	xoffRight = 20
	yoffBottom = 20
	pointRadius = 5
)

// helper to quickly set a brush color
func mkSolidBrush(color uint32, alpha float64) *ui.DrawBrush {
	brush := new(ui.DrawBrush)
	brush.Type = ui.DrawBrushTypeSolid
	component := uint8((color >> 16) & 0xFF)
	brush.R = float64(component) / 255
	component = uint8((color >> 8) & 0xFF)
	brush.G = float64(component) / 255
	component = uint8(color & 0xFF)
	brush.B = float64(component) / 255
	brush.A = alpha
	return brush
}

// and some colors
// names and values from https://msdn.microsoft.com/en-us/library/windows/desktop/dd370907%28v=vs.85%29.aspx
const (
	colorWhite = 0xFFFFFF
	colorBlack = 0x000000
	colorDodgerBlue = 0x1E90FF
)

func pointLocations(width, height float64) (xs, ys [10]float64) {
	xincr := width / 9		// 10 - 1 to make the last point be at the end
	yincr := height / 100
	for i := 0; i < 10; i++ {
		// get the value of the point
		n := datapoints[i].Value()
		// because y=0 is the top but n=0 is the bottom, we need to flip
		n = 100 - n
		xs[i] = xincr * float64(i)
		ys[i] = yincr * float64(n)
	}
	return xs, ys
}

func constructGraph(width, height float64, extend bool) *ui.DrawPath {
	xs, ys := pointLocations(width, height)
	path := ui.DrawNewPath(ui.DrawFillModeWinding)

	path.NewFigure(xs[0], ys[0])
	for i := 1; i < 10; i++ {
		path.LineTo(xs[i], ys[i])
	}

	if extend {
		path.LineTo(width, height)
		path.LineTo(0, height)
		path.CloseFigure()
	}

	path.End()
	return path
}

func graphSize(clientWidth, clientHeight float64) (graphWidth, graphHeight float64) {
	return clientWidth - xoffLeft - xoffRight,
		clientHeight - yoffTop - yoffBottom
}

type areaHandler struct{}

func (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) {
	// fill the area with white
	brush := mkSolidBrush(colorWhite, 1.0)
	path := ui.DrawNewPath(ui.DrawFillModeWinding)
	path.AddRectangle(0, 0, p.AreaWidth, p.AreaHeight)
	path.End()
	p.Context.Fill(path, brush)
	path.Free()

	graphWidth, graphHeight := graphSize(p.AreaWidth, p.AreaHeight)

	sp := &ui.DrawStrokeParams{
		Cap:			ui.DrawLineCapFlat,
		Join:			ui.DrawLineJoinMiter,
		Thickness:	2,
		MiterLimit:	ui.DrawDefaultMiterLimit,
	}

	// draw the axes
	brush = mkSolidBrush(colorBlack, 1.0)
	path = ui.DrawNewPath(ui.DrawFillModeWinding)
	path.NewFigure(xoffLeft, yoffTop)
	path.LineTo(xoffLeft, yoffTop + graphHeight)
	path.LineTo(xoffLeft + graphWidth, yoffTop + graphHeight)
	path.End()
	p.Context.Stroke(path, brush, sp)
	path.Free()

	// now transform the coordinate space so (0, 0) is the top-left corner of the graph
	m := ui.DrawNewMatrix()
	m.Translate(xoffLeft, yoffTop)
	p.Context.Transform(m)

	// now get the color for the graph itself and set up the brush
	graphR, graphG, graphB, graphA := colorButton.Color()
	brush.Type = ui.DrawBrushTypeSolid
	brush.R = graphR
	brush.G = graphG
	brush.B = graphB
	// we set brush.A below to different values for the fill and stroke

	// now create the fill for the graph below the graph line
	path = constructGraph(graphWidth, graphHeight, true)
	brush.A = graphA / 2
	p.Context.Fill(path, brush)
	path.Free()

	// now draw the histogram line
	path = constructGraph(graphWidth, graphHeight, false)
	brush.A = graphA
	p.Context.Stroke(path, brush, sp)
	path.Free()

	// now draw the point being hovered over
	if currentPoint != -1 {
		xs, ys := pointLocations(graphWidth, graphHeight)
		path = ui.DrawNewPath(ui.DrawFillModeWinding)
		path.NewFigureWithArc(
			xs[currentPoint], ys[currentPoint],
			pointRadius,
			0, 6.23,		// TODO pi
			false)
		path.End()
		// use the same brush as for the histogram lines
		p.Context.Fill(path, brush)
		path.Free()
	}
}

func inPoint(x, y float64, xtest, ytest float64) bool {
	// TODO switch to using a matrix
	x -= xoffLeft
	y -= yoffTop
	return (x >= xtest - pointRadius) &&
		(x <= xtest + pointRadius) &&
		(y >= ytest - pointRadius) &&
		(y <= ytest + pointRadius)
}

func (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
	graphWidth, graphHeight := graphSize(me.AreaWidth, me.AreaHeight)
	xs, ys := pointLocations(graphWidth, graphHeight)

	currentPoint = -1
	for i := 0; i < 10; i++ {
		if inPoint(me.X, me.Y, xs[i], ys[i]) {
			currentPoint = i
			break
		}
	}

	// TODO only redraw the relevant area
	histogram.QueueRedrawAll()
}

func (areaHandler) MouseCrossed(a *ui.Area, left bool) {
	// do nothing
}

func (areaHandler) DragBroken(a *ui.Area) {
	// do nothing
}

func (areaHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {
	// reject all keys
	return false
}

func setupUI() {
	mainwin := ui.NewWindow("libui Histogram Example", 640, 480, true)
	mainwin.SetMargined(true)
	mainwin.OnClosing(func(*ui.Window) bool {
		mainwin.Destroy()
		ui.Quit()
		return false
	})
	ui.OnShouldQuit(func() bool {
		mainwin.Destroy()
		return true
	})

	hbox := ui.NewHorizontalBox()
	hbox.SetPadded(true)
	mainwin.SetChild(hbox)

	vbox := ui.NewVerticalBox()
	vbox.SetPadded(true)
	hbox.Append(vbox, false)

	histogram = ui.NewArea(areaHandler{})

	rand.Seed(time.Now().Unix())
	for i := 0; i < 10; i++ {
		datapoints[i] = ui.NewSpinbox(0, 100)
		datapoints[i].SetValue(rand.Intn(101))
		datapoints[i].OnChanged(func(*ui.Spinbox) {
			histogram.QueueRedrawAll()
		})
		vbox.Append(datapoints[i], false)
	}

	colorButton = ui.NewColorButton()
	// TODO inline these
	brush := mkSolidBrush(colorDodgerBlue, 1.0)
	colorButton.SetColor(brush.R,
		brush.G,
		brush.B,
		brush.A)
	colorButton.OnChanged(func(*ui.ColorButton) {
		histogram.QueueRedrawAll()
	})
	vbox.Append(colorButton, false)

	hbox.Append(histogram, true)

	mainwin.Show()
}

func main() {
	ui.Main(setupUI)
}


================================================
FILE: examples/table.go
================================================
// 26 august 2018

// +build OMIT

// TODO possible bugs in libui:
// - the checkboxes on macOS retain their values when they shouldn't
// - the table on GTK+ is very thin; the scrolled window needs hexpand=TRUE

package main

import (
	"fmt"
	"image"
	_ "image/png"
	"image/draw"
	"bytes"

	"github.com/andlabs/ui"
	_ "github.com/andlabs/ui/winmanifest"
)

type modelHandler struct {
	row9Text		string
	yellowRow	int
	checkStates	[15]int
}

func newModelHandler() *modelHandler {
	m := new(modelHandler)
	m.row9Text = "You can edit this one"
	m.yellowRow = -1
	return m
}

func (mh *modelHandler) ColumnTypes(m *ui.TableModel) []ui.TableValue {
	return []ui.TableValue{
		ui.TableString(""),		// column 0 text
		ui.TableString(""),		// column 1 text
		ui.TableString(""),		// column 2 text
		ui.TableColor{},			// row background color
		ui.TableColor{},			// column 1 text color
		ui.TableImage{},		// column 1 image
		ui.TableString(""),		// column 4 button text
		ui.TableInt(0),			// column 3 checkbox state
		ui.TableInt(0),			// column 5 progress
	}
}

func (mh *modelHandler) NumRows(m *ui.TableModel) int {
	return 15
}

var img [2]*ui.Image

func (mh *modelHandler) CellValue(m *ui.TableModel, row, column int) ui.TableValue {
	if column == 3 {
		if row == mh.yellowRow {
			return ui.TableColor{1, 1, 0, 1}
		}
		if row == 3 {
			return ui.TableColor{1, 0, 0, 1}
		}
		if row == 11 {
			return ui.TableColor{0, 0.5, 1, 0.5}
		}
		return nil
	}
	if column == 4 {
		if (row % 2) == 1 {
			return ui.TableColor{0.5, 0, 0.75, 1}
		}
		return nil
	}
	if column == 5 {
		if row < 8 {
			return ui.TableImage{img[0]}
		}
		return ui.TableImage{img[1]}
	}
	if column == 7 {
		return ui.TableInt(mh.checkStates[row])
	}
	if column == 8 {
		if row == 0 {
			return ui.TableInt(0)
		}
		if row == 13 {
			return ui.TableInt(100)
		}
		if row == 14 {
			return ui.TableInt(-1)
		}
		return ui.TableInt(50)
	}
	switch column {
	case 0:
		return ui.TableString(fmt.Sprintf("Row %d", row))
	case 2:
		if row == 9 {
			return ui.TableString(mh.row9Text)
		}
		return ui.TableString("Editing this won't change anything")
	case 1:
		return ui.TableString("Colors!")
	case 6:
		return ui.TableString("Make Yellow")
	}
	panic("unreachable")
}

func (mh *modelHandler) SetCellValue(m *ui.TableModel, row, column int, value ui.TableValue) {
	if row == 9 && column == 2 {
		mh.row9Text = string(value.(ui.TableString))
	}
	if column == 6 {		// row background color
		prevYellowRow := mh.yellowRow
		mh.yellowRow = row
		if prevYellowRow != -1 {
			m.RowChanged(prevYellowRow)
		}
		m.RowChanged(mh.yellowRow)
	}
	if column == 7 {		// checkboxes
		mh.checkStates[row] = int(value.(ui.TableInt))
	}
}

func appendImageNamed(i *ui.Image, which string) {
	b := rawImages[which]
	img, _, err := image.Decode(bytes.NewReader(b))
	if err != nil {
		panic(err)
	}
	nr, ok := img.(*image.RGBA)
	if !ok {
		i2 := image.NewRGBA(img.Bounds())
		draw.Draw(i2, i2.Bounds(), img, img.Bounds().Min, draw.Src)
		nr = i2
	}
	i.Append(nr)
}

func setupUI() {
	mainwin := ui.NewWindow("libui Control Gallery", 640, 480, true)
	mainwin.OnClosing(func(*ui.Window) bool {
		ui.Quit()
		return true
	})
	ui.OnShouldQuit(func() bool {
		mainwin.Destroy()
		return true
	})

	img[0] = ui.NewImage(16, 16)
	appendImageNamed(img[0], "andlabs_16x16test_24june2016.png")
	appendImageNamed(img[0], "andlabs_32x32test_24june2016.png")
	img[1] = ui.NewImage(16, 16)
	appendImageNamed(img[1], "tango-icon-theme-0.8.90_16x16_x-office-spreadsheet.png")
	appendImageNamed(img[1], "tango-icon-theme-0.8.90_32x32_x-office-spreadsheet.png")

	mh := newModelHandler()
	model := ui.NewTableModel(mh)

	table := ui.NewTable(&ui.TableParams{
		Model:	model,
		RowBackgroundColorModelColumn:	3,
	})
	mainwin.SetChild(table)
	mainwin.SetMargined(true)

	table.AppendTextColumn("Column 1",
		0, ui.TableModelColumnNeverEditable, nil)

	table.AppendImageTextColumn("Column 2",
		5,
		1, ui.TableModelColumnNeverEditable, &ui.TableTextColumnOptionalParams{
			ColorModelColumn:		4,
		});
	table.AppendTextColumn("Editable",
		2, ui.TableModelColumnAlwaysEditable, nil)

	table.AppendCheckboxColumn("Checkboxes",
		7, ui.TableModelColumnAlwaysEditable)
	table.AppendButtonColumn("Buttons",
		6, ui.TableModelColumnAlwaysEditable)

	table.AppendProgressBarColumn("Progress Bar",
		8)

	mainwin.Show()
}

func main() {
	ui.Main(setupUI)
}

var rawImages = map[string][]byte{
	"andlabs_16x16test_24june2016.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,
  0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
  0x00, 0xca, 0x49, 0x44, 0x41, 0x54, 0x38, 0x11, 0xa5, 0x93, 0xb1, 0x0d,
  0xc2, 0x40, 0x0c, 0x45, 0x1d, 0xc4, 0x14, 0x0c, 0x12, 0x41, 0x0f, 0x62,
  0x12, 0x46, 0x80, 0x8a, 0x2e, 0x15, 0x30, 0x02, 0x93, 0x20, 0x68, 0x11,
  0x51, 0x06, 0x61, 0x0d, 0x88, 0x2d, 0x7f, 0xdb, 0x07, 0x87, 0x08, 0xdc,
  0x49, 0x91, 0x7d, 0xf6, 0xf7, 0xf3, 0x4f, 0xa4, 0x54, 0xbb, 0xeb, 0xf6,
  0x41, 0x05, 0x67, 0xcc, 0xb3, 0x9b, 0xfa, 0xf6, 0x17, 0x62, 0xdf, 0xcd,
  0x48, 0x00, 0x32, 0xbd, 0xa8, 0x1d, 0x72, 0xee, 0x3c, 0x47, 0x16, 0xfb,
  0x5c, 0x53, 0x8d, 0x03, 0x30, 0x14, 0x84, 0xf7, 0xd5, 0x89, 0x26, 0xc7,
  0x25, 0x10, 0x36, 0xe4, 0x05, 0xa2, 0x51, 0xbc, 0xc4, 0x1c, 0xc3, 0x1c,
  0xed, 0x30, 0x1c, 0x8f, 0x16, 0x3f, 0x02, 0x78, 0x33, 0x20, 0x06, 0x60,
  0x97, 0x70, 0xaa, 0x45, 0x7f, 0x85, 0x60, 0x5d, 0xb6, 0xf4, 0xc2, 0xc4,
  0x3e, 0x0f, 0x44, 0xcd, 0x1b, 0x20, 0x90, 0x0f, 0xed, 0x85, 0xa8, 0x55,
  0x05, 0x42, 0x43, 0xb4, 0x9e, 0xce, 0x71, 0xb3, 0xe8, 0x0e, 0xb4, 0xc4,
  0xc3, 0x39, 0x21, 0xb7, 0x73, 0xbd, 0xe4, 0x1b, 0xe4, 0x04, 0xb6, 0xaa,
  0x4f, 0x18, 0x2c, 0xee, 0x42, 0x31, 0x01, 0x84, 0xfa, 0xe0, 0xd4, 0x00,
  0xdf, 0xb6, 0x83, 0xf8, 0xea, 0xc2, 0x00, 0x10, 0xfc, 0x1a, 0x05, 0x30,
  0x74, 0x3b, 0xe0, 0xd1, 0x45, 0xb1, 0x83, 0xaa, 0xf4, 0x77, 0x7e, 0x02,
  0x87, 0x1f, 0x42, 0x7f, 0x9e, 0x2b, 0xe8, 0xdf, 0x00, 0x00, 0x00, 0x00,
  0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
},
	"andlabs_32x32test_24june2016.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,
  0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
  0x01, 0x6a, 0x49, 0x44, 0x41, 0x54, 0x58, 0x09, 0xc5, 0x97, 0xc1, 0x0d,
  0xc2, 0x30, 0x0c, 0x45, 0x03, 0x62, 0x0a, 0x06, 0x41, 0x70, 0x07, 0x31,
  0x09, 0x23, 0xc0, 0x89, 0x05, 0x80, 0x11, 0x98, 0x04, 0xc1, 0x15, 0x81,
  0x18, 0x84, 0x35, 0x00, 0x57, 0xfd, 0x8d, 0x13, 0x92, 0x3a, 0x4e, 0x03,
  0x8d, 0x54, 0x39, 0x35, 0xb1, 0xff, 0x8b, 0xed, 0x1e, 0x18, 0xec, 0xae,
  0xdb, 0x97, 0xe9, 0x71, 0x8d, 0x48, 0x7b, 0x33, 0xb9, 0xf5, 0x82, 0xb0,
  0x7f, 0xcc, 0x4c, 0x05, 0x50, 0xa9, 0x2f, 0x26, 0x32, 0xc4, 0xf9, 0x21,
  0x9f, 0xa1, 0x13, 0x8a, 0x5c, 0x16, 0x40, 0x4a, 0x9e, 0x92, 0x14, 0x78,
  0x8a, 0x5c, 0x43, 0xc4, 0xf4, 0x65, 0x3b, 0x01, 0x3c, 0x57, 0x27, 0x43,
  0x4f, 0x97, 0x95, 0x0d, 0x40, 0xc2, 0xe3, 0xe3, 0xb2, 0x7a, 0xba, 0x40,
  0xd8, 0x19, 0x50, 0x5c, 0x03, 0xe2, 0x08, 0x21, 0x10, 0xdf, 0xd7, 0x3a,
  0x88, 0x6c, 0x46, 0xd4, 0x00, 0x5f, 0x42, 0x35, 0x85, 0x03, 0x41, 0x03,
  0xcb, 0x44, 0x00, 0x1a, 0xb2, 0x2e, 0x80, 0x66, 0xd2, 0x43, 0xd9, 0x32,
  0x7c, 0x2e, 0x40, 0x1b, 0x75, 0x0d, 0xe7, 0xdc, 0x94, 0x09, 0xc6, 0x2a,
  0xc3, 0x8e, 0x04, 0xb7, 0x59, 0x43, 0x08, 0x08, 0x64, 0xcc, 0x15, 0xa7,
  0x78, 0x5b, 0x01, 0x45, 0xdf, 0x28, 0x90, 0x43, 0xd0, 0x3e, 0x77, 0x59,
  0x80, 0x8c, 0x0c, 0x5d, 0x84, 0x21, 0xe7, 0x02, 0x94, 0x1c, 0x42, 0x29,
  0x57, 0x3d, 0x6f, 0x16, 0xa0, 0x6d, 0x00, 0x81, 0xcb, 0xec, 0xe1, 0x7e,
  0x61, 0x6f, 0xc6, 0xac, 0xa7, 0x73, 0xfb, 0xae, 0xc8, 0x65, 0x01, 0x6c,
  0xb8, 0xb8, 0x23, 0x71, 0x47, 0xf0, 0x13, 0x11, 0xf2, 0x89, 0x89, 0x3e,
  0x07, 0xd4, 0x5f, 0x41, 0x4c, 0x88, 0x80, 0xfc, 0xaa, 0x14, 0x07, 0x88,
  0x89, 0x43, 0x28, 0x07, 0x42, 0x5d, 0x01, 0x88, 0x95, 0xb2, 0xc9, 0x00,
  0xd2, 0xed, 0x01, 0xa4, 0xad, 0x82, 0x38, 0x84, 0xe8, 0xab, 0x3f, 0x74,
  0x10, 0x0c, 0x59, 0x0e, 0x21, 0xc5, 0xb5, 0x02, 0xa4, 0xde, 0x3a, 0x06,
  0x41, 0x7e, 0x29, 0x47, 0x72, 0x0b, 0x42, 0x22, 0x25, 0x7c, 0x51, 0x00,
  0x89, 0x3c, 0x55, 0x9c, 0xb7, 0x23, 0x14, 0xf3, 0xd5, 0x82, 0x9c, 0x9e,
  0x87, 0x12, 0x73, 0x1f, 0x87, 0xf0, 0x67, 0xc2, 0x01, 0x28, 0x75, 0x6b,
  0x2e, 0x8e, 0x3d, 0x84, 0x7d, 0x8d, 0x68, 0x0b, 0x10, 0xf8, 0x6b, 0xdb,
  0x00, 0xf8, 0x64, 0xbf, 0x12, 0xe6, 0xed, 0x20, 0x8d, 0x0a, 0xe0, 0x5f,
  0xe2, 0xb8, 0x14, 0x87, 0x68, 0x2a, 0x80, 0x1f, 0xff, 0x6d, 0x07, 0x7d,
  0xff, 0x3d, 0x7f, 0x03, 0x93, 0xca, 0x91, 0xa9, 0x89, 0x2a, 0x2e, 0xd2,
  0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
},
	"tango-icon-theme-0.8.90_16x16_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,
},
	"tango-icon-theme-0.8.90_32x32_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,
},
}


================================================
FILE: examples/updateui.go
================================================
package main

import (
	"fmt"
	"time"

	"github.com/andlabs/ui"
)

// Example showing how to update the UI using the QueueMain function
// especially if the update is coming from another goroutine
//
// see QueueMain in 'main.go' for detailed description

var countLabel *ui.Label
var count int

func setupUI() {
	mainWindow := ui.NewWindow("libui Updating UI", 640, 480, true)
	mainWindow.OnClosing(func(*ui.Window) bool {
		ui.Quit()
		return true
	})
	ui.OnShouldQuit(func() bool {
		mainWindow.Destroy()
		return true
	})

	vbContainer := ui.NewVerticalBox()
	vbContainer.SetPadded(true)

	inputGroup := ui.NewGroup("Input")
	inputGroup.SetMargined(true)

	vbInput := ui.NewVerticalBox()
	vbInput.SetPadded(true)

	inputForm := ui.NewForm()
	inputForm.SetPadded(true)

	message := ui.NewEntry()
	message.SetText("Hello World")
	inputForm.Append("What message do you want to show?", message, false)

	showMessageButton := ui.NewButton("Show message")
	clearMessageButton := ui.NewButton("Clear message")

	vbInput.Append(inputForm, false)
	vbInput.Append(showMessageButton, false)
	vbInput.Append(clearMessageButton, false)

	inputGroup.SetChild(vbInput)

	messageGroup := ui.NewGroup("Message")
	messageGroup.SetMargined(true)

	vbMessage := ui.NewVerticalBox()
	vbMessage.SetPadded(true)

	messageLabel := ui.NewLabel("")

	vbMessage.Append(messageLabel, false)

	messageGroup.SetChild(vbMessage)

	countGroup := ui.NewGroup("Counter")
	countGroup.SetMargined(true)

	vbCounter := ui.NewVerticalBox()
	vbCounter.SetPadded(true)

	countLabel = ui.NewLabel(fmt.Sprintf("%d", count))

	vbCounter.Append(countLabel, false)
	countGroup.SetChild(vbCounter)

	vbContainer.Append(inputGroup, false)
	vbContainer.Append(messageGroup, false)
	vbContainer.Append(countGroup, false)

	mainWindow.SetChild(vbContainer)

	showMessageButton.OnClicked(func(*ui.Button) {
		// Update the UI directly as it is called from the main thread
		messageLabel.SetText(message.Text())
	})

	clearMessageButton.OnClicked(func(*ui.Button) {
		// Update the UI directly as it is called from the main thread
		messageLabel.SetText("")
	})

	mainWindow.Show()

	// Counting and updating the UI from another goroutine
	go counter()
}

func counter() {
	for {
		time.Sleep(1 * time.Second)
		count++

		// Update the UI using the QueueMain function
		ui.QueueMain(func() {
			countLabel.SetText(fmt.Sprintf("%d", count))
		})
	}
}

func main() {
	count = 0

	ui.Main(setupUI)
}


================================================
FILE: fontbutton.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// FontButton is a Control that represents a button that the user can
// click to select a font.
type FontButton struct {
	ControlBase
	b	*C.uiFontButton
	onChanged		func(*FontButton)
}

// NewFontButton creates a new FontButton.
func NewFontButton() *FontButton {
	b := new(FontButton)

	b.b = C.uiNewFontButton()

	C.pkguiFontButtonOnChanged(b.b)

	b.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))
	return b
}

// Font returns the font currently selected in the FontButton.
func (b *FontButton) Font() *FontDescriptor {
	cfd := C.pkguiNewFontDescriptor()
	defer C.pkguiFreeFontDescriptor(cfd)
	C.uiFontButtonFont(b.b, cfd)
	defer C.uiFreeFontButtonFont(cfd)
	fd := &FontDescriptor{}
	fd.fromLibui(cfd)
	return fd
}

// OnChanged registers f to be run when the user changes the
// currently selected font in the FontButton. Only one function can
// be registered at a time.
func (b *FontButton) OnChanged(f func(*FontButton)) {
	b.onChanged = f
}

//export pkguiDoFontButtonOnChanged
func pkguiDoFontButtonOnChanged(bb *C.uiFontButton, data unsafe.Pointer) {
	b := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*FontButton)
	if b.onChanged != nil {
		b.onChanged(b)
	}
}


================================================
FILE: form.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Form is a Control that holds a group of Controls vertically
// with labels next to each. By default, each control has its
// preferred height; if a control is marked "stretchy", it will take
// whatever space is left over. If multiple controls are marked
// stretchy, they will be given equal shares of the leftover space.
// There can also be space between each control ("padding").
type Form struct {
	ControlBase
	f	*C.uiForm
	children	[]Control
}

// NewForm creates a new horizontal Form.
func NewForm() *Form {
	f := new(Form)

	f.f = C.uiNewForm()

	f.ControlBase = NewControlBase(f, uintptr(unsafe.Pointer(f.f)))
	return f
}

// Destroy destroys the Form. If the Form has children,
// Destroy calls Destroy on those Controls as well.
func (f *Form) Destroy() {
	for len(f.children) != 0 {
		c := f.children[0]
		f.Delete(0)
		c.Destroy()
	}
	f.ControlBase.Destroy()
}

// Append adds the given control to the end of the Form.
func (f *Form) Append(label string, child Control, stretchy bool) {
	clabel := C.CString(label)
	defer freestr(clabel)
	c := touiControl(child.LibuiControl())
	C.uiFormAppend(f.f, clabel, c, frombool(stretchy))
	f.children = append(f.children, child)
}

// Delete deletes the nth control of the Form.
func (f *Form) Delete(n int) {
	f.children = append(f.children[:n], f.children[n + 1:]...)
	C.uiFormDelete(f.f, C.int(n))
}

// Padded returns whether there is space between each control
// of the Form.
func (f *Form) Padded() bool {
	return tobool(C.uiFormPadded(f.f))
}

// SetPadded controls whether there is space between each control
// of the Form. The size of the padding is determined by the OS and
// its best practices.
func (f *Form) SetPadded(padded bool) {
	C.uiFormSetPadded(f.f, frombool(padded))
}


================================================
FILE: grid.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Grid is a Control that arranges other Controls in a grid.
// Grid is a very powerful container: it can position and size each
// Control in several ways and can (and must) have Controls added
// to it in any direction. It can also have Controls spanning multiple
// rows and columns.
//
// Each Control in a Grid has associated "expansion" and
// "alignment" values in both the X and Y direction.
// Expansion determines whether all cells in the same row/column
// are given whatever space is left over after figuring out how big
// the rest of the Grid should be. Alignment determines the position
// of a Control relative to its cell after computing the above. The
// special alignment Fill can be used to grow a Control to fit its cell.
// Note that expansion and alignment are independent variables.
// For more information on expansion and alignment, read
// https://developer.gnome.org/gtk3/unstable/ch28s02.html.
type Grid struct {
	ControlBase
	g	*C.uiGrid
	children	[]Control
}

// Align represents the alignment of a Control in its cell of a Grid.
type Align int
const (
	AlignFill Align = iota
	AlignStart
	AlignCenter
	AlignEnd
)

// At represents a side of a Control to add other Controls to a Grid to.
type At int
const (
	Leading At = iota
	Top
	Trailing
	Bottom
)

// NewGrid creates a new Grid.
func NewGrid() *Grid {
	g := new(Grid)

	g.g = C.uiNewGrid()

	g.ControlBase = NewControlBase(g, uintptr(unsafe.Pointer(g.g)))
	return g
}

// TODO Destroy

// Append adds the given control to the Grid, at the given coordinate.
func (g *Grid) Append(child Control, left, top int, xspan, yspan int, hexpand bool, halign Align, vexpand bool, valign Align) {
	C.uiGridAppend(g.g, touiControl(child.LibuiControl()),
		C.int(left), C.int(top),
		C.int(xspan), C.int(yspan),
		frombool(hexpand), C.uiAlign(halign),
		frombool(vexpand), C.uiAlign(valign))
	g.children = append(g.children, child)
}

// InsertAt adds the given control to the Grid relative to an existing
// control.
func (g *Grid) InsertAt(child Control, existing Control, at At, xspan, yspan int, hexpand bool, halign Align, vexpand bool, valign Align) {
	C.uiGridInsertAt(g.g, touiControl(child.LibuiControl()),
		touiControl(existing.LibuiControl()), C.uiAt(at),
		C.int(xspan), C.int(yspan),
		frombool(hexpand), C.uiAlign(halign),
		frombool(vexpand), C.uiAlign(valign))
	g.children = append(g.children, child)
}

// Padded returns whether there is space between each control
// of the Grid.
func (g *Grid) Padded() bool {
	return tobool(C.uiGridPadded(g.g))
}

// SetPadded controls whether there is space between each control
// of the Grid. The size of the padding is determined by the OS and
// its best practices.
func (g *Grid) SetPadded(padded bool) {
	C.uiGridSetPadded(g.g, frombool(padded))
}


================================================
FILE: group.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Group is a Control that holds another Control and wraps it around
// a labelled box (though some systems make this box invisible).
// You can use this to group related controls together.
type Group struct {
	ControlBase
	g	*C.uiGroup
	child		Control
}

// NewGroup creates a new Group.
func NewGroup(title string) *Group {
	g := new(Group)

	ctitle := C.CString(title)
	g.g = C.uiNewGroup(ctitle)
	freestr(ctitle)

	g.ControlBase = NewControlBase(g, uintptr(unsafe.Pointer(g.g)))
	return g
}

// Destroy destroys the Group. If the Group has a child,
// Destroy calls Destroy on that as well.
func (g *Group) Destroy() {
	if g.child != nil {
		c := g.child
		g.SetChild(nil)
		c.Destroy()
	}
	g.ControlBase.Destroy()
}

// Title returns the Group's title.
func (g *Group) Title() string {
	ctitle := C.uiGroupTitle(g.g)
	title := C.GoString(ctitle)
	C.uiFreeText(ctitle)
	return title
}

// SetTitle sets the Group's title to title.
func (g *Group) SetTitle(title string) {
	ctitle := C.CString(title)
	C.uiGroupSetTitle(g.g, ctitle)
	freestr(ctitle)
}

// SetChild sets the Group's child to child. If child is nil, the Group
// will not have a child.
func (g *Group) SetChild(child Control) {
	g.child = child
	c := (*C.uiControl)(nil)
	if g.child != nil {
		c = touiControl(g.child.LibuiControl())
	}
	C.uiGroupSetChild(g.g, c)
}

// Margined returns whether the Group has margins around its child.
func (g *Group) Margined() bool {
	return tobool(C.uiGroupMargined(g.g))
}

// SetMargined controls whether the Group has margins around its
// child. The size of the margins are determined by the OS and its
// best practices.
func (g *Group) SetMargined(margined bool) {
	C.uiGroupSetMargined(g.g, frombool(margined))
}


================================================
FILE: image.go
================================================
// 21 august 2018

package ui

import (
	"image"
)

// #include "pkgui.h"
import "C"

// Image stores an image for display on screen.
// 
// Images are built from one or more representations, each with the
// same aspect ratio but a different pixel size. Package ui
// automatically selects the most appropriate representation for
// drawing the image when it comes time to draw the image; what
// this means depends on the pixel density of the target context.
// Therefore, one can use Image to draw higher-detailed images on
// higher-density displays. The typical use cases are either:
// 
// 	- have just a single representation, at which point all screens
// 	  use the same image, and thus uiImage acts like a simple
// 	  bitmap image, or
// 	- have two images, one at normal resolution and one at 2x
// 	  resolution; this matches the current expectations of some
// 	  desktop systems at the time of writing (mid-2018)
//
// Image allocates OS resources; you must explicitly free an Image
// when you are finished with it.
type Image struct {
	i	*C.uiImage
}

// NewImage creates a new Image with the given width and
// height. This width and height should be the size in points of the
// image in the device-independent case; typically this is the 1x size.
func NewImage(width, height float64) *Image {
	return &Image{
		i:	C.uiNewImage(C.double(width), C.double(height)),
	}
}

// Free frees the Image.
func (i *Image) Free() {
	C.uiFreeImage(i.i)
}

// Append adds the given image as a representation of the Image.
func (i *Image) Append(img *image.RGBA) {
	cpix := C.CBytes(img.Pix)
	defer C.free(cpix)
	C.uiImageAppend(i.i, cpix,
		C.int(img.Rect.Dx()),
		C.int(img.Rect.Dy()),
		C.int(img.Stride))
}


================================================
FILE: label.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Label is a Control that represents a line of text that cannot be
// interacted with.
type Label struct {
	ControlBase
	l	*C.uiLabel
}

// NewLabel creates a new Label with the given text.
func NewLabel(text string) *Label {
	l := new(Label)

	ctext := C.CString(text)
	l.l = C.uiNewLabel(ctext)
	freestr(ctext)

	l.ControlBase = NewControlBase(l, uintptr(unsafe.Pointer(l.l)))
	return l
}

// Text returns the Label's text.
func (l *Label) Text() string {
	ctext := C.uiLabelText(l.l)
	text := C.GoString(ctext)
	C.uiFreeText(ctext)
	return text
}

// SetText sets the Label's text to text.
func (l *Label) SetText(text string) {
	ctext := C.CString(text)
	C.uiLabelSetText(l.l, ctext)
	freestr(ctext)
}


================================================
FILE: libui_windows_386.a
================================================
[File too large to display: 20.1 MB]

================================================
FILE: libui_windows_amd64.a
================================================
[File too large to display: 22.3 MB]

================================================
FILE: link_darwin_amd64.go
================================================
// 13 december 2015

package ui

// #cgo CFLAGS: -mmacosx-version-min=10.8
// #cgo LDFLAGS: ${SRCDIR}/libui_darwin_amd64.a -framework Foundation -framework AppKit -mmacosx-version-min=10.8
import "C"


================================================
FILE: link_linux_386.go
================================================
// +build !windows
// +build !darwin

// 11 december 2015

package ui

// #cgo LDFLAGS: ${SRCDIR}/libui_linux_386.a -lm -ldl
// #cgo pkg-config: gtk+-3.0
import "C"


================================================
FILE: link_linux_amd64.go
================================================
// +build !windows
// +build !darwin

// 11 december 2015

package ui

// #cgo LDFLAGS: ${SRCDIR}/libui_linux_amd64.a -lm -ldl
// #cgo pkg-config: gtk+-3.0
import "C"


================================================
FILE: link_windows_386.go
================================================
// 13 december 2015

package ui

// #cgo LDFLAGS: ${SRCDIR}/libui_windows_386.a
// #cgo LDFLAGS: -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lmsimg32 -lcomdlg32 -ld2d1 -ldwrite -lole32 -loleaut32 -loleacc -luuid -lwindowscodecs -static -static-libgcc -static-libstdc++
import "C"


================================================
FILE: link_windows_amd64.go
================================================
// 13 december 2015

package ui

// #cgo LDFLAGS: ${SRCDIR}/libui_windows_amd64.a
// #cgo LDFLAGS: -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lmsimg32 -lcomdlg32 -ld2d1 -ldwrite -lole32 -loleaut32 -loleacc -luuid -lwindowscodecs -static -static-libgcc -static-libstdc++
import "C"


================================================
FILE: main.go
================================================
// 11 december 2015

package ui

import (
	"runtime"
	"errors"
	"sync"
	"unsafe"
)

// #include "pkgui.h"
import "C"

// make sure main() runs on the first thread created by the OS
// if main() calls Main(), things will just work on macOS, where the first thread created by the OS is the only thread allowed to be the main GUI thread
// we might as well lock the OS thread for the other platforms here too (though on those it doesn't matter *which* thread we lock to)
// TODO describe the source of this trick
func init() {
	runtime.LockOSThread()
}

// Main initializes package ui, runs f to set up the program,
// and executes the GUI main loop. f should set up the program's
// initial state: open the main window, create controls, and set up
// events. It should then return, at which point Main will
// process events until Quit is called, at which point Main will return
// nil. If package ui fails to initialize, Main returns an appropriate
// error.
func Main(f func()) error {
	opts := C.pkguiAllocInitOptions()
	estr := C.uiInit(opts)
	C.pkguiFreeInitOptions(opts)
	if estr != nil {
		err := errors.New(C.GoString(estr))
		C.uiFreeInitError(estr)
		return err
	}
	C.pkguiOnShouldQuit()
	QueueMain(f)
	C.uiMain()
	return nil
}

// Quit queues a return from Main. It does not exit the program.
// It also does not immediately cause Main to return; Main will
// return when it next can. Quit must be called from the GUI thread.
func Quit() {
	C.uiQuit()
}

// These prevent the passing of Go functions into C land.
// TODO make an actual sparse list instead of this monotonic map thingy
var (
	qmmap = make(map[uintptr]func())
	qmcurrent = uintptr(0)
	qmlock sync.Mutex
)

// QueueMain queues f to be executed on the GUI thread when
// next possible. It returns immediately; that is, it does not wait
// for the function to actually be executed. QueueMain is the only
// function that can be called from other goroutines, and its
// primary purpose is to allow communication between other
// goroutines and the GUI thread. Calling QueueMain after Quit
// has been called results in undefined behavior.
// 
// If you start a goroutine in f, it also cannot call package ui
// functions. So for instance, the following will result in
// undefined behavior:
// 
// 	ui.QueueMain(func() {
// 		go ui.MsgBox(...)
// 	})
func QueueMain(f func()) {
	qmlock.Lock()
	defer qmlock.Unlock()

	n := uintptr(0)
	for {
		n = qmcurrent
		qmcurrent++
		if qmmap[n] == nil {
			break
		}
	}
	qmmap[n] = f
	C.pkguiQueueMain(C.uintptr_t(n))
}

//export pkguiDoQueueMain
func pkguiDoQueueMain(nn unsafe.Pointer) {
	qmlock.Lock()

	n := uintptr(nn)
	f := qmmap[n]
	delete(qmmap, n)

	// allow uiQueueMain() to be called by a queued function
	// TODO explicitly allow this in libui too
	qmlock.Unlock()

	f()
}

// no need to lock this; this API is only safe on the main thread
var shouldQuitFunc func() bool

// OnShouldQuit schedules f to be exeucted when the OS wants
// the program to quit or when a Quit menu item has been clicked.
// Only one function may be registered at a time. If the function
// returns true, Quit will be called. If the function returns false, or
// if OnShouldQuit is never called. Quit will not be called and the
// OS will be told that the program needs to continue running.
func OnShouldQuit(f func() bool) {
	shouldQuitFunc = f
}

//export pkguiDoOnShouldQuit
func pkguiDoOnShouldQuit(unused unsafe.Pointer) C.int {
	if shouldQuitFunc == nil {
		return 0
	}
	return frombool(shouldQuitFunc())
}

// TODO Timer?


================================================
FILE: multilineentry.go
================================================
// 12 december 2015

// TODO typing in entry in OS X crashes libui
// I've had similar issues with checkboxes on libui
// something's wrong with NSMapTable

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// MultilineEntry is a Control that represents a space that the user
// can type multiple lines of text into.
type MultilineEntry struct {
	ControlBase
	e	*C.uiMultilineEntry
	onChanged		func(*MultilineEntry)
}

func finishNewMultilineEntry(ee *C.uiMultilineEntry) *MultilineEntry {
	m := new(MultilineEntry)

	m.e = ee

	C.pkguiMultilineEntryOnChanged(m.e)

	m.ControlBase = NewControlBase(m, uintptr(unsafe.Pointer(m.e)))
	return m
}

// NewMultilineEntry creates a new MultilineEntry.
// The MultilineEntry soft-word-wraps and has no horizontal
// scrollbar.
func NewMultilineEntry() *MultilineEntry {
	return finishNewMultilineEntry(C.uiNewMultilineEntry())
}

// NewNonWrappingMultilineEntry creates a new MultilineEntry.
// The MultilineEntry does not word-wrap and thus has horizontal
// scrollbar.
func NewNonWrappingMultilineEntry() *MultilineEntry {
	return finishNewMultilineEntry(C.uiNewNonWrappingMultilineEntry())
}

// Text returns the MultilineEntry's text.
func (m *MultilineEntry) Text() string {
	ctext := C.uiMultilineEntryText(m.e)
	text := C.GoString(ctext)
	C.uiFreeText(ctext)
	return text
}

// SetText sets the MultilineEntry's text to text.
func (m *MultilineEntry) SetText(text string) {
	ctext := C.CString(text)
	C.uiMultilineEntrySetText(m.e, ctext)
	freestr(ctext)
}

// Append adds text to the end of the MultilineEntry's text.
// TODO selection and scroll behavior
func (m *MultilineEntry) Append(text string) {
	ctext := C.CString(text)
	C.uiMultilineEntryAppend(m.e, ctext)
	freestr(ctext)
}

// OnChanged registers f to be run when the user makes a change to
// the MultilineEntry. Only one function can be registered at a time.
func (m *MultilineEntry) OnChanged(f func(*MultilineEntry)) {
	m.onChanged = f
}

//export pkguiDoMultilineEntryOnChanged
func pkguiDoMultilineEntryOnChanged(ee *C.uiMultilineEntry, data unsafe.Pointer) {
	m := ControlFromLibui(uintptr(unsafe.Pointer(ee))).(*MultilineEntry)
	if m.onChanged != nil {
		m.onChanged(m)
	}
}

// ReadOnly returns whether the MultilineEntry can be changed.
func (m *MultilineEntry) ReadOnly() bool {
	return tobool(C.uiMultilineEntryReadOnly(m.e))
}

// SetReadOnly sets whether the MultilineEntry can be changed.
func (m *MultilineEntry) SetReadOnly(ro bool) {
	C.uiMultilineEntrySetReadOnly(m.e, frombool(ro))
}


================================================
FILE: pkgui.c
================================================
// 26 august 2018
#include "pkgui.h"
#include "_cgo_export.h"

uiInitOptions *pkguiAllocInitOptions(void)
{
	return (uiInitOptions *) pkguiAlloc(sizeof (uiInitOptions));
}

void pkguiFreeInitOptions(uiInitOptions *o)
{
	free(o);
}

void pkguiQueueMain(uintptr_t n)
{
	uiQueueMain(pkguiDoQueueMain, (void *) n);
}

void pkguiOnShouldQuit(void)
{
	uiOnShouldQuit(pkguiDoOnShouldQuit, NULL);
}

void pkguiWindowOnClosing(uiWindow *w)
{
	uiWindowOnClosing(w, pkguiDoWindowOnClosing, NULL);
}

void pkguiButtonOnClicked(uiButton *b)
{
	uiButtonOnClicked(b, pkguiDoButtonOnClicked, NULL);
}

void pkguiCheckboxOnToggled(uiCheckbox *c)
{
	uiCheckboxOnToggled(c, pkguiDoCheckboxOnToggled, NULL);
}

void pkguiColorButtonOnChanged(uiColorButton *c)
{
	uiColorButtonOnChanged(c, pkguiDoColorButtonOnChanged, NULL);
}

pkguiColorDoubles pkguiAllocColorDoubles(void)
{
	pkguiColorDoubles c;

	c.r = (double *) pkguiAlloc(4 * sizeof (double));
	c.g = c.r + 1;
	c.b = c.g + 1;
	c.a = c.b + 1;
	return c;
}

void pkguiFreeColorDoubles(pkguiColorDoubles c)
{
	free(c.r);
}

void pkguiComboboxOnSelected(uiCombobox *c)
{
	uiComboboxOnSelected(c, pkguiDoComboboxOnSelected, NULL);
}

void pkguiDateTimePickerOnChanged(uiDateTimePicker *d)
{
	uiDateTimePickerOnChanged(d, pkguiDoDateTimePickerOnChanged, NULL);
}

struct tm *pkguiAllocTime(void)
{
	return (struct tm *) pkguiAlloc(sizeof (struct tm));
}

void pkguiFreeTime(struct tm *t)
{
	free(t);
}

void pkguiEditableComboboxOnChanged(uiEditableCombobox *c)
{
	uiEditableComboboxOnChanged(c, pkguiDoEditableComboboxOnChanged, NULL);
}

void pkguiEntryOnChanged(uiEntry *e)
{
	uiEntryOnChanged(e, pkguiDoEntryOnChanged, NULL);
}

void pkguiFontButtonOnChanged(uiFontButton *b)
{
	uiFontButtonOnChanged(b, pkguiDoFontButtonOnChanged, NULL);
}

void pkguiMultilineEntryOnChanged(uiMultilineEntry *e)
{
	uiMultilineEntryOnChanged(e, pkguiDoMultilineEntryOnChanged, NULL);
}

void pkguiRadioButtonsOnSelected(uiRadioButtons *r)
{
	uiRadioButtonsOnSelected(r, pkguiDoRadioButtonsOnSelected, NULL);
}

void pkguiSliderOnChanged(uiSlider *s)
{
	uiSliderOnChanged(s, pkguiDoSliderOnChanged, NULL);
}

void pkguiSpinboxOnChanged(uiSpinbox *s)
{
	uiSpinboxOnChanged(s, pkguiDoSpinboxOnChanged, NULL);
}

uiDrawBrush *pkguiAllocBrush(void)
{
	return (uiDrawBrush *) pkguiAlloc(sizeof (uiDrawBrush));
}

void pkguiFreeBrush(uiDrawBrush *b)
{
	free(b);
}

uiDrawBrushGradientStop *pkguiAllocGradientStops(size_t n)
{
	return (uiDrawBrushGradientStop *) pkguiAlloc(n * sizeof (uiDrawBrushGradientStop));
}

void pkguiFreeGradientStops(uiDrawBrushGradientStop *stops)
{
	free(stops);
}

void pkguiSetGradientStop(uiDrawBrushGradientStop *stops, size_t i, double pos, double r, double g, double b, double a)
{
	stops[i].Pos = pos;
	stops[i].R = r;
	stops[i].G = g;
	stops[i].B = b;
	stops[i].A = a;
}

uiDrawStrokeParams *pkguiAllocStrokeParams(void)
{
	return (uiDrawStrokeParams *) pkguiAlloc(sizeof (uiDrawStrokeParams));
}

void pkguiFreeStrokeParams(uiDrawStrokeParams *p)
{
	free(p);
}

double *pkguiAllocDashes(size_t n)
{
	return (double *) pkguiAlloc(n * sizeof (double));
}

void pkguiFreeDashes(double *dashes)
{
	free(dashes);
}

void pkguiSetDash(double *dashes, size_t i, double dash)
{
	dashes[i] = dash;
}

uiDrawMatrix *pkguiAllocMatrix(void)
{
	return (uiDrawMatrix *) pkguiAlloc(sizeof (uiDrawMatrix));
}

void pkguiFreeMatrix(uiDrawMatrix *m)
{
	free(m);
}

uiUnderlineColor *pkguiNewUnderlineColor(void)
{
	return (uiUnderlineColor *) pkguiAlloc(sizeof (uiUnderlineColor));
}

void pkguiFreeUnderlineColor(uiUnderlineColor *c)
{
	free(c);
}

uiFontDescriptor *pkguiNewFontDescriptor(void)
{
	return (uiFontDescriptor *) pkguiAlloc(sizeof (uiFontDescriptor));
}

void pkguiFreeFontDescriptor(uiFontDescriptor *fd)
{
	free(fd);
}

uiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void)
{
	return (uiDrawTextLayoutParams *) pkguiAlloc(sizeof (uiDrawTextLayoutParams));
}

void pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *p)
{
	free(p);
}

uiAreaHandler *pkguiAllocAreaHandler(void)
{
	uiAreaHandler *ah;

	ah = (uiAreaHandler *) pkguiAlloc(sizeof (uiAreaHandler));
	ah->Draw = pkguiDoAreaHandlerDraw;
	ah->MouseEvent = pkguiDoAreaHandlerMouseEvent;
	ah->MouseCrossed = pkguiDoAreaHandlerMouseCrossed;
	ah->DragBroken = pkguiDoAreaHandlerDragBroken;
	ah->KeyEvent = pkguiDoAreaHandlerKeyEvent;
	return ah;
}

void pkguiFreeAreaHandler(uiAreaHandler *ah)
{
	free(ah);
}

// cgo can't generate const, so we need this trampoline
static void realDoTableModelSetCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, const uiTableValue *value)
{
	pkguiDoTableModelSetCellValue(mh, m, row, column, (uiTableValue *) value);
}

const uiTableModelHandler pkguiTableModelHandler = {
	.NumColumns = pkguiDoTableModelNumColumns,
	.ColumnType = pkguiDoTableModelColumnType,
	.NumRows = pkguiDoTableModelNumRows,
	.CellValue = pkguiDoTableModelCellValue,
	.SetCellValue = realDoTableModelSetCellValue,
};

uiTableTextColumnOptionalParams *pkguiAllocTableTextColumnOptionalParams(void)
{
	return (uiTableTextColumnOptionalParams *) pkguiAlloc(sizeof (uiTableTextColumnOptionalParams));
}

void pkguiFreeTableTextColumnOptionalParams(uiTableTextColumnOptionalParams *p)
{
	free(p);
}

uiTableParams *pkguiAllocTableParams(void)
{
	return (uiTableParams *) pkguiAlloc(sizeof (uiTableParams));
}

void pkguiFreeTableParams(uiTableParams *p)
{
	free(p);
}


================================================
FILE: pkgui.h
================================================
// 12 august 2018
#ifndef pkguiHFileIncluded
#define pkguiHFileIncluded

#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ui.h"

// main.go
extern uiInitOptions *pkguiAllocInitOptions(void);
extern void pkguiFreeInitOptions(uiInitOptions *o);
extern void pkguiQueueMain(uintptr_t n);
extern void pkguiOnShouldQuit(void);

// window.go
extern void pkguiWindowOnClosing(uiWindow *w);

// button.go
extern void pkguiButtonOnClicked(uiButton *b);

// checkbox.go
extern void pkguiCheckboxOnToggled(uiCheckbox *c);

// colorbutton.go
extern void pkguiColorButtonOnChanged(uiColorButton *c);
typedef struct pkguiColorDoubles pkguiColorDoubles;
struct pkguiColorDoubles {
	double *r;
	double *g;
	double *b;
	double *a;
};
extern pkguiColorDoubles pkguiAllocColorDoubles(void);
extern void pkguiFreeColorDoubles(pkguiColorDoubles c);

// combobox.go
extern void pkguiComboboxOnSelected(uiCombobox *c);

// datetimepicker.go
extern void pkguiDateTimePickerOnChanged(uiDateTimePicker *d);
extern struct tm *pkguiAllocTime(void);
extern void pkguiFreeTime(struct tm *t);

// editablecombobox.go
extern void pkguiEditableComboboxOnChanged(uiEditableCombobox *c);

// entry.go
extern void pkguiEntryOnChanged(uiEntry *e);

// fontbutton.go
extern void pkguiFontButtonOnChanged(uiFontButton *b);

// multilineentry.go
extern void pkguiMultilineEntryOnChanged(uiMultilineEntry *e);

// radiobuttons.go
extern void pkguiRadioButtonsOnSelected(uiRadioButtons *r);

// slider.go
extern void pkguiSliderOnChanged(uiSlider *s);

// spinbox.go
extern void pkguiSpinboxOnChanged(uiSpinbox *s);

// draw.go
extern uiDrawBrush *pkguiAllocBrush(void);
extern void pkguiFreeBrush(uiDrawBrush *b);
extern uiDrawBrushGradientStop *pkguiAllocGradientStops(size_t n);
extern void pkguiFreeGradientStops(uiDrawBrushGradientStop *stops);
extern void pkguiSetGradientStop(uiDrawBrushGradientStop *stops, size_t i, double pos, double r, double g, double b, double a);
extern uiDrawStrokeParams *pkguiAllocStrokeParams(void);
extern void pkguiFreeStrokeParams(uiDrawStrokeParams *p);
extern double *pkguiAllocDashes(size_t n);
extern void pkguiFreeDashes(double *dashes);
extern void pkguiSetDash(double *dashes, size_t i, double dash);
extern uiDrawMatrix *pkguiAllocMatrix(void);
extern void pkguiFreeMatrix(uiDrawMatrix *m);

// drawtext.go
extern uiUnderlineColor *pkguiNewUnderlineColor(void);
extern void pkguiFreeUnderlineColor(uiUnderlineColor *c);
extern uiFontDescriptor *pkguiNewFontDescriptor(void);
extern void pkguiFreeFontDescriptor(uiFontDescriptor *fd);
extern uiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void);
extern void pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *p);

// areahandler.go
extern uiAreaHandler *pkguiAllocAreaHandler(void);
extern void pkguiFreeAreaHandler(uiAreaHandler *ah);

// tablemodel.go
extern const uiTableModelHandler pkguiTableModelHandler;

// table.go
extern uiTableTextColumnOptionalParams *pkguiAllocTableTextColumnOptionalParams(void);
extern void pkguiFreeTableTextColumnOptionalParams(uiTableTextColumnOptionalParams *p);
extern uiTableParams *pkguiAllocTableParams(void);
extern void pkguiFreeTableParams(uiTableParams *p);

#endif


================================================
FILE: progressbar.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// ProgressBar is a Control that represents a horizontal bar that
// is filled in progressively over time as a process completes.
type ProgressBar struct {
	ControlBase
	p	*C.uiProgressBar
}

// NewProgressBar creates a new ProgressBar.
func NewProgressBar() *ProgressBar {
	p := new(ProgressBar)

	p.p = C.uiNewProgressBar()

	p.ControlBase = NewControlBase(p, uintptr(unsafe.Pointer(p.p)))
	return p
}

// Value returns the value currently shown in the ProgressBar.
func (p *ProgressBar) Value() int {
	return int(C.uiProgressBarValue(p.p))
}

// SetValue sets the ProgressBar's currently displayed percentage
// to value. value must be between 0 and 100 inclusive, or -1 for
// an indeterminate progressbar.
func (p *ProgressBar) SetValue(value int) {
	C.uiProgressBarSetValue(p.p, C.int(value))
}


================================================
FILE: radiobuttons.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// RadioButtons is a Control that represents a set of checkable
// buttons from which exactly one may be chosen by the user.
type RadioButtons struct {
	ControlBase
	r	*C.uiRadioButtons
	onSelected	func(*RadioButtons)
}

// NewRadioButtons creates a new RadioButtons.
func NewRadioButtons() *RadioButtons {
	r := new(RadioButtons)

	r.r = C.uiNewRadioButtons()

	C.pkguiRadioButtonsOnSelected(r.r)

	r.ControlBase = NewControlBase(r, uintptr(unsafe.Pointer(r.r)))
	return r
}

// Append adds the named button to the end of the RadioButtons.
func (r *RadioButtons) Append(text string) {
	ctext := C.CString(text)
	C.uiRadioButtonsAppend(r.r, ctext)
	freestr(ctext)
}

// Selected returns the index of the currently selected option in the
// RadioButtons, or -1 if no item is selected.
func (r *RadioButtons) Selected() int {
	return int(C.uiRadioButtonsSelected(r.r))
}

// SetSelected sets the currently selected option in the RadioButtons
// to index.
func (r *RadioButtons) SetSelected(index int) {
	C.uiRadioButtonsSetSelected(r.r, C.int(index))
}

// OnSelected registers f to be run when the user selects an option in
// the RadioButtons. Only one function can be registered at a time.
func (r *RadioButtons) OnSelected(f func(*RadioButtons)) {
	r.onSelected = f
}

//export pkguiDoRadioButtonsOnSelected
func pkguiDoRadioButtonsOnSelected(rr *C.uiRadioButtons, data unsafe.Pointer) {
	r := ControlFromLibui(uintptr(unsafe.Pointer(rr))).(*RadioButtons)
	if r.onSelected != nil {
		r.onSelected(r)
	}
}


================================================
FILE: separator.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Separator is a Control that represents a horizontal line that
// visually separates controls.
type Separator struct {
	ControlBase
	s	*C.uiSeparator
}

// NewHorizontalSeparator creates a new horizontal Separator.
func NewHorizontalSeparator() *Separator {
	s := new(Separator)

	s.s = C.uiNewHorizontalSeparator()

	s.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))
	return s
}

// NewVerticalSeparator creates a new vertical Separator.
func NewVerticalSeparator() *Separator {
	s := new(Separator)

	s.s = C.uiNewVerticalSeparator()

	s.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))
	return s
}


================================================
FILE: slider.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Slider is a Control that represents a horizontal bar that represents
// a range of integers. The user can drag a pointer on the bar to
// select an integer.
type Slider struct {
	ControlBase
	s	*C.uiSlider
	onChanged		func(*Slider)
}

// NewSlider creates a new Slider. If min >= max, they are swapped.
func NewSlider(min int, max int) *Slider {
	s := new(Slider)

	s.s = C.uiNewSlider(C.int(min), C.int(max))

	C.pkguiSliderOnChanged(s.s)

	s.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))
	return s
}

// Value returns the Slider's current value.
func (s *Slider) Value() int {
	return int(C.uiSliderValue(s.s))
}

// SetValue sets the Slider's current value to value.
func (s *Slider) SetValue(value int) {
	C.uiSliderSetValue(s.s, C.int(value))
}

// OnChanged registers f to be run when the user changes the value
// of the Slider. Only one function can be registered at a time.
func (s *Slider) OnChanged(f func(*Slider)) {
	s.onChanged = f
}

//export pkguiDoSliderOnChanged
func pkguiDoSliderOnChanged(ss *C.uiSlider, data unsafe.Pointer) {
	s := ControlFromLibui(uintptr(unsafe.Pointer(ss))).(*Slider)
	if s.onChanged != nil {
		s.onChanged(s)
	}
}


================================================
FILE: spinbox.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Spinbox is a Control that represents a space where the user can
// enter integers. The space also comes with buttons to add or
// subtract 1 from the integer.
type Spinbox struct {
	ControlBase
	s	*C.uiSpinbox
	onChanged		func(*Spinbox)
}

// NewSpinbox creates a new Spinbox. If min >= max, they are swapped.
func NewSpinbox(min int, max int) *Spinbox {
	s := new(Spinbox)

	s.s = C.uiNewSpinbox(C.int(min), C.int(max))

	C.pkguiSpinboxOnChanged(s.s)

	s.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))
	return s
}

// Value returns the Spinbox's current value.
func (s *Spinbox) Value() int {
	return int(C.uiSpinboxValue(s.s))
}

// SetValue sets the Spinbox's current value to value.
func (s *Spinbox) SetValue(value int) {
	C.uiSpinboxSetValue(s.s, C.int(value))
}

// OnChanged registers f to be run when the user changes the value
// of the Spinbox. Only one function can be registered at a time.
func (s *Spinbox) OnChanged(f func(*Spinbox)) {
	s.onChanged = f
}

//export pkguiDoSpinboxOnChanged
func pkguiDoSpinboxOnChanged(ss *C.uiSpinbox, data unsafe.Pointer) {
	s := ControlFromLibui(uintptr(unsafe.Pointer(ss))).(*Spinbox)
	if s.onChanged != nil {
		s.onChanged(s)
	}
}


================================================
FILE: stddialogs.go
================================================
// 20 december 2015

package ui

// #include "pkgui.h"
import "C"

// TODO
func MsgBoxError(w *Window, title string, description string) {
	ctitle := C.CString(title)
	defer freestr(ctitle)
	cdescription := C.CString(description)
	defer freestr(cdescription)
	C.uiMsgBoxError(w.w, ctitle, cdescription)
}

func OpenFile(w *Window) string {
	cname := C.uiOpenFile(w.w)
	if cname == nil {
		return ""
	}
	defer C.uiFreeText(cname)
	return C.GoString(cname)
}

func SaveFile(w *Window) string {
	cname := C.uiSaveFile(w.w)
	if cname == nil {
		return ""
	}
	defer C.uiFreeText(cname)
	return C.GoString(cname)
}

func MsgBox(w *Window, title string, description string) {
	ctitle := C.CString(title)
	defer freestr(ctitle)
	cdescription := C.CString(description)
	defer freestr(cdescription)
	C.uiMsgBox(w.w, ctitle, cdescription)
}


================================================
FILE: tab.go
================================================
// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// Tab is a Control that holds tabbed pages of Controls. Each tab
// has a label. The user can click on the tabs themselves to switch
// pages. Individual pages can also have margins.
type Tab struct {
	ControlBase
	t	*C.uiTab
	children	[]Control
}

// NewTab creates a new Tab.
func NewTab() *Tab {
	t := new(Tab)

	t.t = C.uiNewTab()

	t.ControlBase = NewControlBase(t, uintptr(unsafe.Pointer(t.t)))
	return t
}

// Destroy destroys the Tab. If the Tab has pages,
// Destroy calls Destroy on the pages's Controls as well.
func (t *Tab) Destroy() {
	for len(t.children) != 0 {
		c := t.children[0]
		t.Delete(0)
		c.Destroy()
	}
	t.ControlBase.Destroy()
}

// Append adds the given page to the end of the Tab.
func (t *Tab) Append(name string, child Control) {
	t.InsertAt(name, len(t.children), child)
}

// InsertAt adds the given page to the Tab such that it is the
// nth page of the Tab (starting at 0).
func (t *Tab) InsertAt(name string, n int, child Control) {
	c := (*C.uiControl)(nil)
	if child != nil {
		c = touiControl(child.LibuiControl())
	}
	cname := C.CString(name)
	C.uiTabInsertAt(t.t, cname, C.int(n), c)
	freestr(cname)
	ch := make([]Control, len(t.children) + 1)
	// and insert into t.children at the right place
	copy(ch[:n], t.children[:n])
	ch[n] = child
	copy(ch[n + 1:], t.children[n:])
	t.children = ch
}

// Delete deletes the nth page of the Tab.
func (t *Tab) Delete(n int) {
	t.children = append(t.children[:n], t.children[n + 1:]...)
	C.uiTabDelete(t.t, C.int(n))
}

// NumPages returns the number of pages in the Tab.
func (t *Tab) NumPages() int {
	return len(t.children)
}

// Margined returns whether page n (starting at 0) of the Tab
// has margins around its child.
func (t *Tab) Margined(n int) bool {
	return tobool(C.uiTabMargined(t.t, C.int(n)))
}

// SetMargined controls whether page n (starting at 0) of the Tab
// has margins around its child. The size of the margins are
// determined by the OS and its best practices.
func (t *Tab) SetMargined(n int, margined bool) {
	C.uiTabSetMargined(t.t, C.int(n), frombool(margined))
}


================================================
FILE: table.go
================================================
// 26 august 2018

package ui

import (
	"unsafe"
)

// #include "pkgui.h"
import "C"

// TableModelColumnNeverEditable and
// TableModelColumnAlwaysEditable are the value of an editable
// model column parameter to one of the Table create column
// functions; if used, that jparticular Table colum is not editable
// by the user and always editable by the user, respectively.
const (
	TableModelColumnNeverEditable = -1
	TableModelColumnAlwaysEditable = -2
)

// TableTextColumnOptionalParams are the optional parameters
// that control the appearance of the text column of a Table.
type TableTextColumnOptionalParams struct {
	// ColorModelColumn is the model column containing the
	// text color of this Table column's text, or -1 to use the
	// default color.
	//
	// If CellValue for this column for any cell returns nil, that
	// cell will also use the default text color.
	ColorModelColumn		int
}

func (p *TableTextColumnOptionalParams) toLibui() *C.uiTableTextColumnOptionalParams {
	if p == nil {
		return nil
	}
	cp := C.pkguiAllocTableTextColumnOptionalParams()
	cp.ColorModelColumn = C.int(p.ColorModelColumn)
	return cp
}

// TableParams defines the parameters passed to NewTable.
type TableParams struct {
	// Model is the TableModel to use for this uiTable.
	// This parameter cannot be nil.
	Model		*TableModel

	// RowBackgroundColorModelColumn is a model column
	// number that defines the background color used for the
	// entire row in the Table, or -1 to use the default color for
	// all rows.
	//
	// If CellValue for this column for any row returns NULL, that
	// row will also use the default background color.
	RowBackgroundColorModelColumn		int
}

func (p *TableParams) toLibui() *C.uiTableParams {
	cp := C.pkguiAllocTableParams()
	cp.Model = p.Model.m
	cp.RowBackgroundColorModelColumn = C.int(p.RowBackgroundColorModelColumn)
	return cp
}

// Table is a Control that shows tabular data, allowing users to
// manipulate rows of such data at a time.
type Table struct {
	ControlBase
	t	*C.uiTable
}

// NewTable creates a new Table with the specified parameters.
func NewTable(p *TableParams) *Table {
	t := new(Table)

	cp := p.toLibui()
	t.t = C.uiNewTable(cp)
	C.pkguiFreeTableParams(cp)

	t.ControlBase = NewControlBase(t, uintptr(unsafe.Pointer(t.t)))
	return t
}

// AppendTextColumn appends a text column to t. name is
// displayed in the table header. textModelColumn is where the text
// comes from. If a row is editable according to
// textEditableModelColumn, SetCellValue is called with
// textModelColumn as the column.
func (t *Table) AppendTextColumn(name string, textModelColumn int, textEditableModelColumn int, textParams *TableTextColumnOptionalParams) {
	cname := C.CString(name)
	defer freestr(cname)
	cp := textParams.toLibui()
	defer C.pkguiFreeTableTextColumnOptionalParams(cp)
	C.uiTableAppendTextColumn(t.t, cname, C.int(textModelColumn), C.int(textEditableModelColumn), cp)
}

// AppendImageColumn appends an image column to t.
// Images are drawn at icon size, appropriate to the pixel density
// of the screen showing the Table.
func (t *Table) AppendImageColumn(name string, imageModelColumn int) {
	cname := C.CString(name)
	defer freestr(cname)
	C.uiTableAppendImageColumn(t.t, cname, C.int(imageModelColumn))
}

// AppendImageTextColumn appends a column to t that
// shows both an image and text.
func (t *Table) AppendImageTextColumn(name string, imageModelColumn int, textModelColumn int, textEditableModelColumn int, textParams *TableTextColumnOptionalParams) {
	cname := C.CString(name)
	defer freestr(cname)
	cp := textParams.toLibui()
	defer C.pkguiFreeTableTextColumnOptionalParams(cp)
	C.uiTableAppendImageTextColumn(t.t, cname, C.int(imageModelColumn), C.int(textModelColumn), C.int(textEditableModelColumn), cp)
}

// AppendCheckboxColumn appends a column to t that
// contains a checkbox that the user can interact with (assuming the
// checkbox is editable). SetCellValue will be called with
// checkboxModelColumn as the column in this case.
func (t *Table) AppendCheckboxColumn(name string, checkboxModelColumn int, checkboxEditableModelColumn int) {
	cname := C.CString(name)
	defer freestr(cname)
	C.uiTableAppendCheckboxColumn(t.t, cname, C.int(checkboxModelColumn), C.int(checkboxEditableModelColumn))
}

// AppendCheckboxTextColumn appends a column to t
// that contains both a checkbox and text.
func (t *Table) AppendCheckboxTextColumn(name string, checkboxModelColumn int, checkboxEditableModelColumn int, textModelColumn int, textEditableModelColumn int, textParams *TableTextColumnOptionalParams) {
	cname := C.CString(name)
	defer freestr(cname)
	cp := textParams.toLibui()
	defer C.pkguiFreeTableTextColumnOptionalParams(cp)
	C.uiTableAppendCheckboxTextColumn(t.t, cname, C.int(checkboxModelColumn), C.int(checkboxEditableModelColumn), C.int(textModelColumn), C.int(textEditableModelColumn), cp)
}

// AppendProgressBarColumn appends a column to t
// that displays a progress bar. These columns work like
// ProgressBar: a cell value of 0..100 displays that percentage, and
// a cell value of -1 displays an indeterminate progress bar.
func (t *Table) AppendProgressBarColumn(name string, progressModelColumn int) {
	cname := C.CString(name)
	defer freestr(cname)
	C.uiTableAppendProgressBarColumn(t.t, cname, C.int(progressModelColumn))
}

// AppendButtonColumn appends a column to t
// that shows a button that the user can click on. When the user
// does click on the button, SetCellValue is called with a nil
// value and buttonModelColumn as the column.
// CellValue on buttonModelColumn should return the text to show
// in the button.
func (t *Table) AppendButtonColumn(name string, buttonModelColumn int, buttonClickableModelColumn int) {
	cname := C.CString(name)
	defer freestr(cname)
	C.uiTableAppendButtonColumn(t.t, cname, C.int(buttonModelColumn), C.int(buttonClickableModelColumn))
}


================================================
FILE: tablemodel.go
================================================
// 24 august 2018

package ui

// #include "pkgui.h"
import "C"

// TableValue is a type that represents a piece of data that can come
// out of a TableModel.
type TableValue interface {
	toLibui() *C.uiTableValue
}

// TableString is a TableValue that stores a string. TableString is
// used for displaying text in a Table.
type TableString string

func (s TableString) toLibui() *C.uiTableValue {
	cs := C.CString(string(s))
	defer freestr(cs)
	return C.uiNewTableValueString(cs)
}

// TableImage is a TableValue that represents an Image. Ownership
// of the Image is not copied; you must keep it alive alongside the
// TableImage.
type TableImage struct {
	I	*Image
}

func (i TableImage) toLibui() *C.uiTableValue {
	return C.uiNewTableValueImage(i.I.i)
}

// TableInt is a TableValue that stores integers. These are used for
// progressbars. Due to current limitations of libui, they also
// represent checkbox states, via TableFalse and TableTrue.
type TableInt int

// TableFalse and TableTrue are the Boolean constants for TableInt.
const (
	TableFalse TableInt = 0
	TableTrue TableInt = 1
)

func (i TableInt) toLibui() *C.uiTableValue {
	return C.uiNewTableValueInt(C.int(i))
}

// TableColor is a TableValue that represents a color.
type TableColor struct {
	R	float64
	G	float64
	B	float64
	A	float64
}

func (c TableColor) toLibui() *C.uiTableValue {
	return C.uiNewTableValueColor(C.double(c.R), C.double(c.G), C.double(c.B), C.double(c.A))
}

func tableValueFromLibui(value *C.uiTableValue) TableValue {
	if value == nil {
		return nil
	}
	switch C.uiTableValueGetType(value) {
	case C.uiTableValueTypeString:
		cs := C.uiTableValueString(value)
		return TableString(C.GoString(cs))
	case C.uiTableValueTypeImage:
		panic("TODO")
	case C.uiTableValueTypeInt:
		return TableInt(C.uiTableValueInt(value))
	case C.uiTableValueTypeColor:
		panic("TODO")
	}
	panic("unreachable")
}

// no need to lock these; only the GUI thread can access them
var modelhandlers = make(map[*C.uiTableModel]TableModelHandler)
var models = make(map[*C.uiTableModel]*TableModel)

// TableModel is an object that provides the data for a Table.
// This data is returned via methods you provide in the
// TableModelHandler interface.
//
// TableModel represents data using a table, but this table does
// not map directly to Table itself. Instead, you can have data
// columns which provide instructions for how to render a given
// Table's column — for instance, one model column can be used
// to give certain rows of a Table a different background color.
// Row numbers DO match with uiTable row numbers.
//
// Once created, the number and data types of columns of a
// TableModel cannot change.
//
// Row and column numbers start at 0. A TableModel can be
// associated with more than one Table at a time.
type TableModel struct {
	m	*C.uiTableModel
}

// TableModelHandler defines the methods that TableModel
// calls when it needs data.
type TableModelHandler interface {
	// ColumnTypes returns a slice of value types of the data
	// stored in the model columns of the TableModel.
	// Each entry in the slice should ideally be a zero value for
	// the TableValue type of the column in question; the number
	// of elements in the slice determines the number of model
	// columns in the TableModel. The returned slice must remain
	// constant through the lifetime of the TableModel. This
	// method is not guaranteed to be called depending on the
	// system.
	ColumnTypes(m *TableModel) []TableValue

	// NumRows returns the number or rows in the TableModel.
	// This value must be non-negative.
	NumRows(m *TableModel) int

	// CellValue returns a TableValue corresponding to the model
	// cell at (row, column). The type of the returned TableValue
	// must match column's value type. Under some circumstances,
	// nil may be returned; refer to the various methods that add
	// columns to Table for details.
	CellValue(m *TableModel, row, column int) TableValue

	// SetCellValue changes the model cell value at (row, column)
	// in the TableModel. Within this function, either do nothing
	// to keep the current cell value or save the new cell value as
	// appropriate. After SetCellValue is called, the Table will
	// itself reload the table cell. Under certain conditions, the
	// TableValue passed in can be nil; refer to the various
	// methods that add columns to Table for details.
	SetCellValue(m *TableModel, row, column int, value TableValue)
}

//export pkguiDoTableModelNumColumns
func pkguiDoTableModelNumColumns(umh *C.uiTableModelHandler, um *C.uiTableModel) C.int {
	mh := modelhandlers[um]
	return C.int(len(mh.ColumnTypes(models[um])))
}

//export pkguiDoTableModelColumnType
func pkguiDoTableModelColumnType(umh *C.uiTableModelHandler, um *C.uiTableModel, n C.int) C.uiTableValueType {
	mh := modelhandlers[um]
	c := mh.ColumnTypes(models[um])
	switch c[n].(type) {
	case TableString:
		return C.uiTableValueTypeString
	case TableImage:
		return C.uiTableValueTypeImage
	case TableInt:
		return C.uiTableValueTypeInt
	case TableColor:
		return C.uiTableValueTypeColor
	}
	panic("unreachable")
}

//export pkguiDoTableModelNumRows
func pkguiDoTableModelNumRows(umh *C.uiTableModelHandler, um *C.uiTableModel) C.int {
	mh := modelhandlers[um]
	return C.int(mh.NumRows(models[um]))
}

//export pkguiDoTableModelCellValue
func pkguiDoTableModelCellValue(umh *C.uiTableModelHandler, um *C.uiTableModel, row, column C.int) *C.uiTableValue {
	mh := modelhandlers[um]
	v := mh.CellValue(models[um], int(row), int(column))
	if v == nil {
		return nil
	}
	return v.toLibui()
}

//export pkguiDoTableModelSetCellValue
func pkguiDoTableModelSetCellValue(umh *C.uiTableModelHandler, um *C.uiTableModel, row, column C.int, value *C.uiTableValue) {
	mh := modelhandlers[um]
	v := tableValueFromLibui(value)
	mh.SetCellValue(models[um], int(row), int(column), v)
}

// NewTableModel creates a new TableModel.
func NewTableModel(handler TableModelHandler) *TableModel {
	m := &TableModel{
		m:	C.uiNewTableModel(&C.pkguiTableModelHandler),
	}
	modelhandlers[m.m] = handler
	models[m.m] = m
	return m
}

// Free frees m. It is an error to Free any models associated with a
// Table.
func (m *TableModel) Free() {
	delete(models, m.m)
	delete(modelhandlers, m.m)
	C.uiFreeTableModel(m.m)
}

// RowInserted tells any Tables associated with m that a new row
// has been added to m at index index. You call this method when
// the number of rows in your model has changed; after calling it,
// NumRows should returm the new row count.
func (m *TableModel) RowInserted(index int) {
	C.uiTableModelRowInserted(m.m, C.int(index))
}

// RowChanged tells any Tables associated with m that the data in
// the row at index has changed. You do not need to call this in
// your SetCellValue handlers, but you do need to call this if your
// data changes at some other point.
func (m *TableModel) RowChanged(index int) {
	C.uiTableModelRowChanged(m.m, C.int(index))
}

// RowDeleted tells any Tables associated with m that the row at
// index index has been deleted. You call this function when the
// number of rows in your model has changed; after calling it,
// NumRows should returm the new row count.
func (m *TableModel) RowDeleted(index int) {
	C.uiTableModelRowDeleted(m.m, C.int(index))
}


================================================
FILE: ui.h
================================================
// 6 april 2015

// TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls

// TODOs
// - make getters that return whether something exists accept a NULL pointer to discard the value (and thus only return that the thing exists?)
// - const-correct everything
// - normalize documentation between typedefs and structs

#ifndef __LIBUI_UI_H__
#define __LIBUI_UI_H__

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

// this macro is generated by cmake
#ifdef libui_EXPORTS
#ifdef _WIN32
#define _UI_EXTERN __declspec(dllexport) extern
#else
#define _UI_EXTERN __attribute__((visibility("default"))) extern
#endif
#else
// TODO add __declspec(dllimport) on windows, but only if not static
#define _UI_EXTERN extern
#endif

// C++ is really really really really really really dumb about enums, so screw that and just make them anonymous
// This has the advantage of being ABI-able should we ever need an ABI...
#define _UI_ENUM(s) typedef unsigned int s; enum

// This constant is provided because M_PI is nonstandard.
// This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796.
#define uiPi 3.14159265358979323846264338327950288419716939937510582097494459

// TODO uiBool?

// uiForEach represents the return value from one of libui's various ForEach functions.
_UI_ENUM(uiForEach) {
	uiForEachContinue,
	uiForEachStop,
};

typedef struct uiInitOptions uiInitOptions;

struct uiInitOptions {
	size_t Size;
};

_UI_EXTERN const char *uiInit(uiInitOptions *options);
_UI_EXTERN void uiUninit(void);
_UI_EXTERN void uiFreeInitError(const char *err);

_UI_EXTERN void uiMain(void);
_UI_EXTERN void uiMainSteps(void);
_UI_EXTERN int uiMainStep(int wait);
_UI_EXTERN void uiQuit(void);

_UI_EXTERN void uiQueueMain(void (*f)(void *data), void *data);

// TODO standardize the looping behavior return type, either with some enum or something, and the test expressions throughout the code
// TODO figure out what to do about looping and the exact point that the timer is rescheduled so we can document it; see https://github.com/andlabs/libui/pull/277
// TODO (also in the above link) document that this cannot be called from any thread, unlike uiQueueMain()
// TODO document that the minimum exact timing, either accuracy (timer burst, etc.) or granularity (15ms on Windows, etc.), is OS-defined
// TODO also figure out how long until the initial tick is registered on all platforms to document
// TODO also add a comment about how useful this could be in bindings, depending on the language being bound to
_UI_EXTERN void uiTimer(int milliseconds, int (*f)(void *data), void *data);

_UI_EXTERN void uiOnShouldQuit(int (*f)(void *data), void *data);

_UI_EXTERN void uiFreeText(char *text);

typedef struct uiControl uiControl;

struct uiControl {
	uint32_t Signature;
	uint32_t OSSignature;
	uint32_t TypeSignature;
	void (*Destroy)(uiControl *);
	uintptr_t (*Handle)(uiControl *);
	uiControl *(*Parent)(uiControl *);
	void (*SetParent)(uiControl *, uiControl *);
	int (*Toplevel)(uiControl *);
	int (*Visible)(uiControl *);
	void (*Show)(uiControl *);
	void (*Hide)(uiControl *);
	int (*Enabled)(uiControl *);
	void (*Enable)(uiControl *);
	void (*Disable)(uiControl *);
};
// TOOD add argument names to all arguments
#define uiControl(this) ((uiControl *) (this))
_UI_EXTERN void uiControlDestroy(uiControl *);
_UI_EXTERN uintptr_t uiControlHandle(uiControl *);
_UI_EXTERN uiControl *uiControlParent(uiControl *);
_UI_EXTERN void uiControlSetParent(uiControl *, uiControl *);
_UI_EXTERN int uiControlToplevel(uiControl *);
_UI_EXTERN int uiControlVisible(uiControl *);
_UI_EXTERN void uiControlShow(uiControl *);
_UI_EXTERN void uiControlHide(uiControl *);
_UI_EXTERN int uiControlEnabled(uiControl *);
_UI_EXTERN void uiControlEnable(uiControl *);
_UI_EXTERN void uiControlDisable(uiControl *);

_UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr);
_UI_EXTERN void uiFreeControl(uiControl *);

// TODO make sure all controls have these
_UI_EXTERN void uiControlVerifySetParent(uiControl *, uiControl *);
_UI_EXTERN int uiControlEnabledToUser(uiControl *);

_UI_EXTERN void uiUserBugCannotSetParentOnToplevel(const char *type);

typedef struct uiWindow uiWindow;
#define uiWindow(this) ((uiWindow *) (this))
_UI_EXTERN char *uiWindowTitle(uiWindow *w);
_UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title);
_UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height);
_UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height);
_UI_EXTERN int uiWindowFullscreen(uiWindow *w);
_UI_EXTERN void uiWindowSetFullscreen(uiWindow *w, int fullscreen);
_UI_EXTERN void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data);
_UI_EXTERN void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *w, void *data), void *data);
_UI_EXTERN int uiWindowBorderless(uiWindow *w);
_UI_EXTERN void uiWindowSetBorderless(uiWindow *w, int borderless);
_UI_EXTERN void uiWindowSetChild(uiWindow *w, uiControl *child);
_UI_EXTERN int uiWindowMargined(uiWindow *w);
_UI_EXTERN void uiWindowSetMargined(uiWindow *w, int margined);
_UI_EXTERN uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar);

typedef struct uiButton uiButton;
#define uiButton(this) ((uiButton *) (this))
_UI_EXTERN char *uiButtonText(uiButton *b);
_UI_EXTERN void uiButtonSetText(uiButton *b, const char *text);
_UI_EXTERN void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *b, void *data), void *data);
_UI_EXTERN uiButton *uiNewButton(const char *text);

typedef struct uiBox uiBox;
#define uiBox(this) ((uiBox *) (this))
_UI_EXTERN void uiBoxAppend(uiBox *b, uiControl *child, int stretchy);
_UI_EXTERN void uiBoxDelete(uiBox *b, int index);
_UI_EXTERN int uiBoxPadded(uiBox *b);
_UI_EXTERN void uiBoxSetPadded(uiBox *b, int padded);
_UI_EXTERN uiBox *uiNewHorizontalBox(void);
_UI_EXTERN uiBox *uiNewVerticalBox(void);

typedef struct uiCheckbox uiCheckbox;
#define uiCheckbox(this) ((uiCheckbox *) (this))
_UI_EXTERN char *uiCheckboxText(uiCheckbox *c);
_UI_EXTERN void uiCheckboxSetText(uiCheckbox *c, const char *text);
_UI_EXTERN void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *c, void *data), void *data);
_UI_EXTERN int uiCheckboxChecked(uiCheckbox *c);
_UI_EXTERN void uiCheckboxSetChecked(uiCheckbox *c, int checked);
_UI_EXTERN uiCheckbox *uiNewCheckbox(const char *text);

typedef struct uiEntry uiEntry;
#define uiEntry(this) ((uiEntry *) (this))
_UI_EXTERN char *uiEntryText(uiEntry *e);
_UI_EXTERN void uiEntrySetText(uiEntry *e, const char *text);
_UI_EXTERN void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *e, void *data), void *data);
_UI_EXTERN int uiEntryReadOnly(uiEntry *e);
_UI_EXTERN void uiEntrySetReadOnly(uiEntry *e, int readonly);
_UI_EXTERN uiEntry *uiNewEntry(void);
_UI_EXTERN uiEntry *uiNewPasswordEntry(void);
_UI_EXTERN uiEntry *uiNewSearchEntry(void);

typedef struct uiLabel uiLabel;
#define uiLabel(this) ((uiLabel *) (this))
_UI_EXTERN char *uiLabelText(uiLabel *l);
_UI_EXTERN void uiLabelSetText(uiLabel *l, const char *text);
_UI_EXTERN uiLabel *uiNewLabel(const char *text);

typedef struct uiTab uiTab;
#define uiTab(this) ((uiTab *) (this))
_UI_EXTERN void uiTabAppend(uiTab *t, const char *name, uiControl *c);
_UI_EXTERN void uiTabInsertAt(uiTab *t, const char *name, int before, uiControl *c);
_UI_EXTERN void uiTabDelete(uiTab *t, int index);
_UI_EXTERN int uiTabNumPages(uiTab *t);
_UI_EXTERN int uiTabMargined(uiTab *t, int page);
_UI_EXTERN void uiTabSetMargined(uiTab *t, int page, int margined);
_UI_EXTERN uiTab *uiNewTab(void);

typedef struct uiGroup uiGroup;
#define uiGroup(this) ((uiGroup *) (this))
_UI_EXTERN char *uiGroupTitle(uiGroup *g);
_UI_EXTERN void uiGroupSetTitle(uiGroup *g, const char *title);
_UI_EXTERN void uiGroupSetChild(uiGroup *g, uiControl *c);
_UI_EXTERN int uiGroupMargined(uiGroup *g);
_UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined);
_UI_EXTERN uiGroup *uiNewGroup(const char *title);

// spinbox/slider rules:
// setting value outside of range will automatically clamp
// initial value is minimum
// complaint if min >= max?

typedef struct uiSpinbox uiSpinbox;
#define uiSpinbox(this) ((uiSpinbox *) (this))
_UI_EXTERN int uiSpinboxValue(uiSpinbox *s);
_UI_EXTERN void uiSpinboxSetValue(uiSpinbox *s, int value);
_UI_EXTERN void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *s, void *data), void *data);
_UI_EXTERN uiSpinbox *uiNewSpinbox(int min, int max);

typedef struct uiSlider uiSlider;
#define uiSlider(this) ((uiSlider *) (this))
_UI_EXTERN int uiSliderValue(uiSlider *s);
_UI_EXTERN void uiSliderSetValue(uiSlider *s, int value);
_UI_EXTERN void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *s, void *data), void *data);
_UI_EXTERN uiSlider *uiNewSlider(int min, int max);

typedef struct uiProgressBar uiProgressBar;
#define uiProgressBar(this) ((uiProgressBar *) (this))
_UI_EXTERN int uiProgressBarValue(uiProgressBar *p);
_UI_EXTERN void uiProgressBarSetValue(uiProgressBar *p, int n);
_UI_EXTERN uiProgressBar *uiNewProgressBar(void);

typedef struct uiSeparator uiSeparator;
#define uiSeparator(this) ((uiSeparator *) (this))
_UI_EXTERN uiSeparator *uiNewHorizontalSeparator(void);
_UI_EXTERN uiSeparator *uiNewVerticalSeparator(void);

typedef struct uiCombobox uiCombobox;
#define uiCombobox(this) ((uiCombobox *) (this))
_UI_EXTERN void uiComboboxAppend(uiCombobox *c, const char *text);
_UI_EXTERN int uiComboboxSelected(uiCombobox *c);
_UI_EXTERN void uiComboboxSetSelected(uiCombobox *c, int n);
_UI_EXTERN void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data);
_UI_EXTERN uiCombobox *uiNewCombobox(void);

typedef struct uiEditableCombobox uiEditableCombobox;
#define uiEditableCombobox(this) ((uiEditableCombobox *) (this))
_UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text);
_UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c);
_UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text);
// TODO what do we call a function that sets the currently selected item and fills the text field with it? editable comboboxes have no consistent concept of selected item
_UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data);
_UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void);

typedef struct uiRadioButtons uiRadioButtons;
#define uiRadioButtons(this) ((uiRadioButtons *) (this))
_UI_EXTERN void uiRadioButtonsAppend(uiRadioButtons *r, const char *text);
_UI_EXTERN int uiRadioButtonsSelected(uiRadioButtons *r);
_UI_EXTERN void uiRadioButtonsSetSelected(uiRadioButtons *r, int n);
_UI_EXTERN void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data);
_UI_EXTERN uiRadioButtons *uiNewRadioButtons(void);

struct tm;
typedef struct uiDateTimePicker uiDateTimePicker;
#define uiDateTimePicker(this) ((uiDateTimePicker *) (this))
// TODO document that tm_wday and tm_yday are undefined, and tm_isdst should be -1
// TODO document that for both sides
// TODO document time zone conversions or lack thereof
// TODO for Time: define what values are returned when a part is missing
_UI_EXTERN void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time);
_UI_EXTERN void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time);
_UI_EXTERN void uiDateTimePickerOnChanged(uiDateTimePicker *d, void (*f)(uiDateTimePicker *, void *), void *data);
_UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void);
_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void);
_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void);

// TODO provide a facility for entering tab stops?
typedef struct uiMultilineEntry uiMultilineEntry;
#define uiMultilineEntry(this) ((uiMultilineEntry *) (this))
_UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e);
_UI_EXTERN void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text);
_UI_EXTERN void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text);
_UI_EXTERN void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data);
_UI_EXTERN int uiMultilineEntryReadOnly(uiMultilineEntry *e);
_UI_EXTERN void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly);
_UI_EXTERN uiMultilineEntry *uiNewMultilineEntry(void);
_UI_EXTERN uiMultilineEntry *uiNewNonWrappingMultilineEntry(void);

typedef struct uiMenuItem uiMenuItem;
#define uiMenuItem(this) ((uiMenuItem *) (this))
_UI_EXTERN void uiMenuItemEnable(uiMenuItem *m);
_UI_EXTERN void uiMenuItemDisable(uiMenuItem *m);
_UI_EXTERN void uiMenuItemOnClicked(uiMenuItem *m, void (*f)(uiMenuItem *sender, uiWindow *window, void *data), void *data);
_UI_EXTERN int uiMenuItemChecked(uiMenuItem *m);
_UI_EXTERN void uiMenuItemSetChecked(uiMenuItem *m, int checked);

typedef struct uiMenu uiMenu;
#define uiMenu(this) ((uiMenu *) (this))
_UI_EXTERN uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name);
_UI_EXTERN uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name);
_UI_EXTERN uiMenuItem *uiMenuAppendQuitItem(uiMenu *m);
_UI_EXTERN uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m);
_UI_EXTERN uiMenuItem *uiMenuAppendAboutItem(uiMenu *m);
_UI_EXTERN void uiMenuAppendSeparator(uiMenu *m);
_UI_EXTERN uiMenu *uiNewMenu(const char *name);

_UI_EXTERN char *uiOpenFile(uiWindow *parent);
_UI_EXTERN char *uiSaveFile(uiWindow *parent);
_UI_EXTERN void uiMsgBox(uiWindow *parent, const char *title, const char *description);
_UI_EXTERN void uiMsgBoxError(uiWindow *parent, const char *title, const char *description);

typedef struct uiArea uiArea;
typedef struct uiAreaHandler uiAreaHandler;
typedef struct uiAreaDrawParams uiAreaDrawParams;
typedef struct uiAreaMouseEvent uiAreaMouseEvent;
typedef struct uiAreaKeyEvent uiAreaKeyEvent;

typedef struct uiDrawContext uiDrawContext;

struct uiAreaHandler {
	void (*Draw)(uiAreaHandler *, uiArea *, uiAreaDrawParams *);
	// TODO document that resizes cause a full redraw for non-scrolling areas; implementation-defined for scrolling areas
	void (*MouseEvent)(uiAreaHandler *, uiArea *, uiAreaMouseEvent *);
	// TODO document that on first show if the mouse is already in the uiArea then one gets sent with left=0
	// TODO what about when the area is hidden and then shown again?
	void (*MouseCrossed)(uiAreaHandler *, uiArea *, int left);
	void (*DragBroken)(uiAreaHandler *, uiArea *);
	int (*KeyEvent)(uiAreaHandler *, uiArea *, uiAreaKeyEvent *);
};

// TODO RTL layouts?
// TODO reconcile edge and corner naming
_UI_ENUM(uiWindowResizeEdge) {
	uiWindowResizeEdgeLeft,
	uiWindowResizeEdgeTop,
	uiWindowResizeEdgeRight,
	uiWindowResizeEdgeBottom,
	uiWindowResizeEdgeTopLeft,
	uiWindowResizeEdgeTopRight,
	uiWindowResizeEdgeBottomLeft,
	uiWindowResizeEdgeBottomRight,
	// TODO have one for keyboard resizes?
	// TODO GDK doesn't seem to have any others, including for keyboards...
	// TODO way to bring up the system menu instead?
};

#define uiArea(this) ((uiArea *) (this))
// TODO give a better name
// TODO document the types of width and height
_UI_EXTERN void uiAreaSetSize(uiArea *a, int width, int height);
// TODO uiAreaQueueRedraw()
_UI_EXTERN void uiAreaQueueRedrawAll(uiArea *a);
_UI_EXTERN void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height);
// TODO document these can only be called within Mouse() handlers
// TODO should these be allowed on scrolling areas?
// TODO decide which mouse events should be accepted; Down is the only one guaranteed to work right now
// TODO what happens to events after calling this up to and including the next mouse up?
// TODO release capture?
_UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a);
_UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge);
_UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah);
_UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height);

struct uiAreaDrawParams {
	uiDrawContext *Context;

	// TODO document that this is only defined for nonscrolling areas
	double AreaWidth;
	double AreaHeight;

	double ClipX;
	double ClipY;
	double ClipWidth;
	double ClipHeight;
};

typedef struct uiDrawPath uiDrawPath;
typedef struct uiDrawBrush uiDrawBrush;
typedef struct uiDrawStrokeParams uiDrawStrokeParams;
typedef struct uiDrawMatrix uiDrawMatrix;

typedef struct uiDrawBrushGradientStop uiDrawBrushGradientStop;

_UI_ENUM(uiDrawBrushType) {
	uiDrawBrushTypeSolid,
	uiDrawBrushTypeLinearGradient,
	uiDrawBrushTypeRadialGradient,
	uiDrawBrushTypeImage,
};

_UI_ENUM(uiDrawLineCap) {
	uiDrawLineCapFlat,
	uiDrawLineCapRound,
	uiDrawLineCapSquare,
};

_UI_ENUM(uiDrawLineJoin) {
	uiDrawLineJoinMiter,
	uiDrawLineJoinRound,
	uiDrawLineJoinBevel,
};

// this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions)
// Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value
// so we're good to use it too!
#define uiDrawDefaultMiterLimit 10.0

_UI_ENUM(uiDrawFillMode) {
	uiDrawFillModeWinding,
	uiDrawFillModeAlternate,
};

struct uiDrawMatrix {
	double M11;
	double M12;
	double M21;
	double M22;
	double M31;
	double M32;
};

struct uiDrawBrush {
	uiDrawBrushType Type;

	// solid brushes
	double R;
	double G;
	double B;
	double A;

	// gradient brushes
	double X0;		// linear: start X, radial: start X
	double Y0;		// linear: start Y, radial: start Y
	double X1;		// linear: end X, radial: outer circle center X
	double Y1;		// linear: end Y, radial: outer circle center Y
	double OuterRadius;		// radial gradients only
	uiDrawBrushGradientStop *Stops;
	size_t NumStops;
	// TODO extend mode
	// cairo: none, repeat, reflect, pad; no individual control
	// Direct2D: repeat, reflect, pad; no individual control
	// Core Graphics: none, pad; before and after individually
	// TODO cairo documentation is inconsistent about pad

	// TODO images

	// TODO transforms
};

struct uiDrawBrushGradientStop {
	double Pos;
	double R;
	double G;
	double B;
	double A;
};

struct uiDrawStrokeParams {
	uiDrawLineCap Cap;
	uiDrawLineJoin Join;
	// TODO what if this is 0? on windows there will be a crash with dashing
	double Thickness;
	double MiterLimit;
	double *Dashes;
	// TOOD what if this is 1 on Direct2D?
	// TODO what if a dash is 0 on Cairo or Quartz?
	size_t NumDashes;
	double DashPhase;
};

_UI_EXTERN uiDrawPath *uiDrawNewPath(uiDrawFillMode fillMode);
_UI_EXTERN void uiDrawFreePath(uiDrawPath *p);

_UI_EXTERN void uiDrawPathNewFigure(uiDrawPath *p, double x, double y);
_UI_EXTERN void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);
_UI_EXTERN void uiDrawPathLineTo(uiDrawPath *p, double x, double y);
// notes: angles are both relative to 0 and go counterclockwise
// TODO is the initial line segment on cairo and OS X a proper join?
// TODO what if sweep < 0?
_UI_EXTERN void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);
_UI_EXTERN void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY);
// TODO quadratic bezier
_UI_EXTERN void uiDrawPathCloseFigure(uiDrawPath *p);

// TODO effect of these when a figure is already started
_UI_EXTERN void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height);

_UI_EXTERN void uiDrawPathEnd(uiDrawPath *p);

_UI_EXTERN void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p);
_UI_EXTERN void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b);

// TODO primitives:
// - rounded rectangles
// - elliptical arcs
// - quadratic bezier curves

_UI_EXTERN void uiDrawMatrixSetIdentity(uiDrawMatrix *m);
_UI_EXTERN void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y);
_UI_EXTERN void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y);
_UI_EXTERN void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount);
_UI_EXTERN void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount);
_UI_EXTERN void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src);
_UI_EXTERN int uiDrawMatrixInvertible(uiDrawMatrix *m);
_UI_EXTERN int uiDrawMatrixInvert(uiDrawMatrix *m);
_UI_EXTERN void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y);
_UI_EXTERN void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y);

_UI_EXTERN void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m);

// TODO add a uiDrawPathStrokeToFill() or something like that
_UI_EXTERN void uiDrawClip(uiDrawContext *c, uiDrawPath *path);

_UI_EXTERN void uiDrawSave(uiDrawContext *c);
_UI_EXTERN void uiDrawRestore(uiDrawContext *c);

// uiAttribute stores information about an attribute in a
// uiAttributedString.
//
// You do not create uiAttributes directly; instead, you create a
// uiAttribute of a given type using the specialized constructor
// functions. For every Unicode codepoint in the uiAttributedString,
// at most one value of each attribute type can be applied.
//
// uiAttributes are immutable and the uiAttributedString takes
// ownership of the uiAttribute object once assigned, copying its
// contents as necessary.
typedef struct uiAttribute uiAttribute;

// @role uiAttribute destructor
// uiFreeAttribute() frees a uiAttribute. You generally do not need to
// call this yourself, as uiAttributedString does this for you. In fact,
// it is an error to call this function on a uiAttribute that has been
// given to a uiAttributedString. You can call this, however, if you
// created a uiAttribute that you aren't going to use later.
_UI_EXTERN void uiFreeAttribute(uiAttribute *a);

// uiAttributeType holds the possible uiAttribute types that may be
// returned by uiAttributeGetType(). Refer to the documentation for
// each type's constructor function for details on each type.
_UI_ENUM(uiAttributeType) {
	uiAttributeTypeFamily,
	uiAttributeTypeSize,
	uiAttributeTypeWeight,
	uiAttributeTypeItalic,
	uiAttributeTypeStretch,
	uiAttributeTypeColor,
	uiAttributeTypeBackground,
	uiAttributeTypeUnderline,
	uiAttributeTypeUnderlineColor,
	uiAttributeTypeFeatures,
};

// uiAttributeGetType() returns the type of a.
// TODO I don't like this name
_UI_EXTERN uiAttributeType uiAttributeGetType(const uiAttribute *a);

// uiNewFamilyAttribute() creates a new uiAttribute that changes the
// font family of the text it is applied to. family is copied; you do not
// need to keep it alive after uiNewFamilyAttribute() returns. Font
// family names are case-insensitive.
_UI_EXTERN uiAttribute *uiNewFamilyAttribute(const char *family);

// uiAttributeFamily() returns the font family stored in a. The
// returned string is owned by a. It is an error to call this on a
// uiAttribute that does not hold a font family.
_UI_EXTERN const char *uiAttributeFamily(const uiAttribute *a);

// uiNewSizeAttribute() creates a new uiAttribute that changes the
// size of the text it is applied to, in typographical points.
_UI_EXTERN uiAttribute *uiNewSizeAttribute(double size);

// uiAttributeSize() returns the font size stored in a. It is an error to
// call this on a uiAttribute that does not hold a font size.
_UI_EXTERN double uiAttributeSize(const uiAttribute *a);

// uiTextWeight represents possible text weights. These roughly
// map to the OS/2 text weight field of TrueType and OpenType
// fonts, or to CSS weight numbers. The named constants are
// nominal values; the actual values may vary by font and by OS,
// though this isn't particularly likely. Any value between
// uiTextWeightMinimum and uiTextWeightMaximum, inclusive,
// is allowed.
//
// Note that due to restrictions in early versions of Windows, some
// fonts have "special" weights be exposed in many programs as
// separate font families. This is perhaps most notable with
// Arial Black. libui does not do this, even on Windows (because the
// DirectWrite API libui uses on Windows does not do this); to
// specify Arial Black, use family Arial and weight uiTextWeightBlack.
_UI_ENUM(uiTextWeight) {
	uiTextWeightMinimum = 0,
	uiTextWeightThin = 100,
	uiTextWeightUltraLight = 200,
	uiTextWeightLight = 300,
	uiTextWeightBook = 350,
	uiTextWeightNormal = 400,
	uiTextWeightMedium = 500,
	uiTextWeightSemiBold = 600,
	uiTextWeightBold = 700,
	uiTextWeightUltraBold = 800,
	uiTextWeightHeavy = 900,
	uiTextWeightUltraHeavy = 950,
	uiTextWeightMaximum = 1000,
};

// uiNewWeightAttribute() creates a new uiAttribute that changes the
// weight of the text it is applied to. It is an error to specify a weight
// outside the range [uiTextWeightMinimum,
// uiTextWeightMaximum].
_UI_EXTERN uiAttribute *uiNewWeightAttribute(uiTextWeight weight);

// uiAttributeWeight() returns the font weight stored in a. It is an error
// to call this on a uiAttribute that does not hold a font weight.
_UI_EXTERN uiTextWeight uiAttributeWeight(const uiAttribute *a);

// uiTextItalic represents possible italic modes for a font. Italic
// represents "true" italics where the slanted glyphs have custom
// shapes, whereas oblique represents italics that are merely slanted
// versions of the normal glyphs. Most fonts usually have one or the
// other.
_UI_ENUM(uiTextItalic) {
	uiTextItalicNormal,
	uiTextItalicOblique,
	uiTextItalicItalic,
};

// uiNewItalicAttribute() creates a new uiAttribute that changes the
// italic mode of the text it is applied to. It is an error to specify an
// italic mode not specified in uiTextItalic.
_UI_EXTERN uiAttribute *uiNewItalicAttribute(uiTextItalic italic);

// uiAttributeItalic() returns the font italic mode stored in a. It is an
// error to call this on a uiAttribute that does not hold a font italic
// mode.
_UI_EXTERN uiTextItalic uiAttributeItalic(const uiAttribute *a);

// uiTextStretch represents possible stretches (also called "widths")
// of a font.
//
// Note that due to restrictions in early versions of Windows, some
// fonts have "special" stretches be exposed in many programs as
// separate font families. This is perhaps most notable with
// Arial Condensed. libui does not do this, even on Windows (because
// the DirectWrite API libui uses on Windows does not do this); to
// specify Arial Condensed, use family Arial and stretch
// uiTextStretchCondensed.
_UI_ENUM(uiTextStretch) {
	uiTextStretchUltraCondensed,
	uiTextStretchExtraCondensed,
	uiTextStretchCondensed,
	uiTextStretchSemiCondensed,
	uiTextStretchNormal,
	uiTextStretchSemiExpanded,
	uiTextStretchExpanded,
	uiTextStretchExtraExpanded,
	uiTextStretchUltraExpanded,
};

// uiNewStretchAttribute() creates a new uiAttribute that changes the
// stretch of the text it is applied to. It is an error to specify a strech
// not specified in uiTextStretch.
_UI_EXTERN uiAttribute *uiNewStretchAttribute(uiTextStretch stretch);

// uiAttributeStretch() returns the font stretch stored in a. It is an
// error to call this on a uiAttribute that does not hold a font stretch.
_UI_EXTERN uiTextStretch uiAttributeStretch(const uiAttribute *a);

// uiNewColorAttribute() creates a new uiAttribute that changes the
// color of the text it is applied to. It is an error to specify an invalid
// color.
_UI_EXTERN uiAttribute *uiNewColorAttribute(double r, double g, double b, double a);

// uiAttributeColor() returns the text color stored in a. It is an
// error to call this on a uiAttribute that does not hold a text color.
_UI_EXTERN void uiAttributeColor(const uiAttribute *a, double *r, double *g, double *b, double *alpha);

// uiNewBackgroundAttribute() creates a new uiAttribute that
// changes the background color of the text it is applied to. It is an
// error to specify an invalid color.
_UI_EXTERN uiAttribute *uiNewBackgroundAttribute(double r, double g, double b, double a);

// TODO reuse uiAttributeColor() for background colors, or make a new function...

// uiUnderline specifies a type of underline to use on text.
_UI_ENUM(uiUnderline) {
	uiUnderlineNone,
	uiUnderlineSingle,
	uiUnderlineDouble,
	uiUnderlineSuggestion,		// wavy or dotted underlines used for spelling/grammar checkers
};

// uiNewUnderlineAttribute() creates a new uiAttribute that changes
// the type of underline on the text it is applied to. It is an error to
// specify an underline type not specified in uiUnderline.
_UI_EXTERN uiAttribute *uiNewUnderlineAttribute(uiUnderline u);

// uiAttributeUnderline() returns the underline type stored in a. It is
// an error to call this on a uiAttribute that does not hold an underline
// style.
_UI_EXTERN uiUnderline uiAttributeUnderline(const uiAttribute *a);

// uiUnderlineColor specifies the color of any underline on the text it
// is applied to, regardless of the type of underline. In addition to
// being able to specify a custom color, you can explicitly specify
// platform-specific colors for suggestion underlines; to use them
// correctly, pair them with uiUnderlineSuggestion (though they can
// be used on other types of underline as well).
// 
// If an underline type is applied but no underline color is
// specified, the text color is used instead. If an underline color
// is specified without an underline type, the underline color
// attribute is ignored, but not removed from the uiAttributedString.
_UI_ENUM(uiUnderlineColor) {
	uiUnderlineColorCustom,
	uiUnderlineColorSpelling,
	uiUnderlineColorGrammar,
	uiUnderlineColorAuxiliary,		// for instance, the color used by smart replacements on macOS or in Microsoft Office
};

// uiNewUnderlineColorAttribute() creates a new uiAttribute that
// changes the color of the underline on the text it is applied to.
// It is an error to specify an underline color not specified in
// uiUnderlineColor.
//
// If the specified color type is uiUnderlineColorCustom, it is an
// error to specify an invalid color value. Otherwise, the color values
// are ignored and should be specified as zero.
_UI_EXTERN uiAttribute *uiNewUnderlineColorAttribute(uiUnderlineColor u, double r, double g, double b, double a);

// uiAttributeUnderlineColor() returns the underline color stored in
// a. It is an error to call this on a uiAttribute that does not hold an
// underline color.
_UI_EXTERN void uiAttributeUnderlineColor(const uiAttribute *a, uiUnderlineColor *u, double *r, double *g, double *b, double *alpha);

// uiOpenTypeFeatures represents a set of OpenType feature
// tag-value pairs, for applying OpenType features to text.
// OpenType feature tags are four-character codes defined by
// OpenType that cover things from design features like small
// caps and swashes to language-specific glyph shapes and
// beyond. Each tag may only appear once in any given
// uiOpenTypeFeatures instance. Each value is a 32-bit integer,
// often used as a Boolean flag, but sometimes as an index to choose
// a glyph shape to use.
// 
// If a font does not support a certain feature, that feature will be
// ignored. (TODO verify this on all OSs)
// 
// See the OpenType specification at
// https://www.microsoft.com/typography/otspec/featuretags.htm
// for the complete list of available features, information on specific
// features, and how to use them.
// TODO invalid features
typedef struct uiOpenTypeFeatures uiOpenTypeFeatures;

// uiOpenTypeFeaturesForEachFunc is the type of the function
// invoked by uiOpenTypeFeaturesForEach() for every OpenType
// feature in otf. Refer to that function's documentation for more
// details.
typedef uiForEach (*uiOpenTypeFeaturesForEachFunc)(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data);

// @role uiOpenTypeFeatures constructor
// uiNewOpenTypeFeatures() returns a new uiOpenTypeFeatures
// instance, with no tags yet added.
_UI_EXTERN uiOpenTypeFeatures *uiNewOpenTypeFeatures(void);

// @role uiOpenTypeFeatures destructor
// uiFreeOpenTypeFeatures() frees otf.
_UI_EXTERN void uiFreeOpenTypeFeatures(uiOpenTypeFeatures *otf);

// uiOpenTypeFeaturesClone() makes a copy of otf and returns it.
// Changing one will not affect the other.
_UI_EXTERN uiOpenTypeFeatures *uiOpenTypeFeaturesClone(const uiOpenTypeFeatures *otf);

// uiOpenTypeFeaturesAdd() adds the given feature tag and value
// to otf. The feature tag is specified by a, b, c, and d. If there is
// already a value associated with the specified tag in otf, the old
// value is removed.
_UI_EXTERN void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value);

// uiOpenTypeFeaturesRemove() removes the given feature tag
// and value from otf. If the tag is not present in otf,
// uiOpenTypeFeaturesRemove() does nothing.
_UI_EXTERN void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d);

// uiOpenTypeFeaturesGet() determines whether the given feature
// tag is present in otf. If it is, *value is set to the tag's value and
// nonzero is returned. Otherwise, zero is returned.
// 
// Note that if uiOpenTypeFeaturesGet() returns zero, value isn't
// changed. This is important: if a feature is not present in a
// uiOpenTypeFeatures, the feature is NOT treated as if its
// value was zero anyway. Script-specific font shaping rules and
// font-specific feature settings may use a different default value
// for a feature. You should likewise not treat a missing feature as
// having a value of zero either. Instead, a missing feature should
// be treated as having some unspecified default value.
_UI_EXTERN int uiOpenTypeFeaturesGet(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value);

// uiOpenTypeFeaturesForEach() executes f for every tag-value
// pair in otf. The enumeration order is unspecified. You cannot
// modify otf while uiOpenTypeFeaturesForEach() is running.
_UI_EXTERN void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data);

// uiNewFeaturesAttribute() creates a new uiAttribute that changes
// the font family of the text it is applied to. otf is copied; you may
// free it after uiNewFeaturesAttribute() returns.
_UI_EXTERN uiAttribute *uiNewFeaturesAttribute(const uiOpenTypeFeatures *otf);

// uiAttributeFeatures() returns the OpenType features stored in a.
// The returned uiOpenTypeFeatures object is owned by a. It is an
// error to call this on a uiAttribute that does not hold OpenType
// features.
_UI_EXTERN const uiOpenTypeFeatures *uiAttributeFeatures(const uiAttribute *a);

// uiAttributedString represents a string of UTF-8 text that can
// optionally be embellished with formatting attributes. libui
// provides the list of formatting attributes, which cover common
// formatting traits like boldface and color as well as advanced
// typographical features provided by OpenType like superscripts
// and small caps. These attributes can be combined in a variety of
// ways.
//
// Attributes are applied to runs of Unicode codepoints in the string.
// Zero-length runs are elided. Consecutive runs that have the same
// attribute type and value are merged. Each attribute is independent
// of each other attribute; overlapping attributes of different types
// do not split each other apart, but different values of the same
// attribute type do.
//
// The empty string can also be represented by uiAttributedString,
// but because of the no-zero-length-attribute rule, it will not have
// attributes.
//
// A uiAttributedString takes ownership of all attributes given to
// it, as it may need to duplicate or delete uiAttribute objects at
// any time. By extension, when you free a uiAttributedString,
// all uiAttributes within will also be freed. Each method will
// describe its own rules in more details.
//
// In addition, uiAttributedString provides facilities for moving
// between grapheme clusters, which represent a character
// from the point of view of the end user. The cursor of a text editor
// is always placed on a grapheme boundary, so you can use these
// features to move the cursor left or right by one "character".
// TODO does uiAttributedString itself need this
//
// uiAttributedString does not provide enough information to be able
// to draw itself onto a uiDrawContext or respond to user actions.
// In order to do that, you'll need to use a uiDrawTextLayout, which
// is built from the combination of a uiAttributedString and a set of
// layout-specific properties.
typedef struct uiAttributedString uiAttributedString;

// uiAttributedStringForEachAttributeFunc is the type of the function
// invoked by uiAttributedStringForEachAttribute() for every
// attribute in s. Refer to that function's documentation for more
// details.
typedef uiForEach (*uiAttributedStringForEachAttributeFunc)(const uiAttributedString *s, const uiAttribute *a, size_t start, size_t end, void *data);

// @role uiAttributedString constructor
// uiNewAttributedString() creates a new uiAttributedString from
// initialString. The string will be entirely unattributed.
_UI_EXTERN uiAttributedString *uiNewAttributedString(const char *initialString);

// @role uiAttributedString destructor
// uiFreeAttributedString() destroys the uiAttributedString s.
// It will also free all uiAttributes within.
_UI_EXTERN void uiFreeAttributedString(uiAttributedString *s);

// uiAttributedStringString() returns the textual content of s as a
// '\0'-terminated UTF-8 string. The returned pointer is valid until
// the next change to the textual content of s.
_UI_EXTERN const char *uiAttributedStringString(const uiAttributedString *s);

// uiAttributedStringLength() returns the number of UTF-8 bytes in
// the textual content of s, excluding the terminating '\0'.
_UI_EXTERN size_t uiAttributedStringLen(const uiAttributedString *s);

// uiAttributedStringAppendUnattributed() adds the '\0'-terminated
// UTF-8 string str to the end of s. The new substring will be
// unattributed.
_UI_EXTERN void uiAttributedStringAppendUnattributed(uiAttributedString *s, const char *str);

// uiAttributedStringInsertAtUnattributed() adds the '\0'-terminated
// UTF-8 string str to s at the byte position specified by at. The new
// substring will be unattributed; existing attributes will be moved
// along with their text.
_UI_EXTERN void uiAttributedStringInsertAtUnattributed(uiAttributedString *s, const char *str, size_t at);

// TODO add the Append and InsertAtExtendingAttributes functions
// TODO and add functions that take a string + length

// uiAttributedStringDelete() deletes the characters and attributes of
// s in the byte range [start, end).
_UI_EXTERN void uiAttributedStringDelete(uiAttributedString *s, size_t start, size_t end);

// TODO add a function to uiAttributedString to get an attribute's value at a specific index or in a specific range, so we can edit

// uiAttributedStringSetAttribute() sets a in the byte range [start, end)
// of s. Any existing attributes in that byte range of the same type are
// removed. s takes ownership of a; you should not use it after
// uiAttributedStringSetAttribute() returns.
_UI_EXTERN void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute *a, size_t start, size_t end);

// uiAttributedStringForEachAttribute() enumerates all the
// uiAttributes in s. It is an error to modify s in f. Within f, s still
// owns the attribute; you can neither free it nor save it for later
// use.
// TODO reword the above for consistency (TODO and find out what I meant by that)
// TODO define an enumeration order (or mark it as undefined); also define how consecutive runs of identical attributes are handled here and sync with the definition of uiAttributedString itself
_UI_EXTERN void uiAttributedStringForEachAttribute(const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data);

// TODO const correct this somehow (the implementation needs to mutate the structure)
_UI_EXTERN size_t uiAttributedStringNumGraphemes(uiAttributedString *s);

// 
Download .txt
gitextract_ocwn0tif/

├── LICENSE
├── README.md
├── TODO.md
├── area.go
├── areahandler.go
├── box.go
├── button.go
├── checkbox.go
├── colorbutton.go
├── combobox.go
├── control.go
├── datetimepicker.go
├── draw.go
├── drawtext.go
├── dummy_windows.cpp
├── editablecombobox.go
├── entry.go
├── examples/
│   ├── controlgallery.go
│   ├── drawtext.go
│   ├── histogram.go
│   ├── table.go
│   └── updateui.go
├── fontbutton.go
├── form.go
├── grid.go
├── group.go
├── image.go
├── label.go
├── libui_darwin_amd64.a
├── libui_linux_386.a
├── libui_linux_amd64.a
├── libui_windows_386.a
├── libui_windows_amd64.a
├── link_darwin_amd64.go
├── link_linux_386.go
├── link_linux_amd64.go
├── link_windows_386.go
├── link_windows_amd64.go
├── main.go
├── multilineentry.go
├── pkgui.c
├── pkgui.h
├── progressbar.go
├── radiobuttons.go
├── separator.go
├── slider.go
├── spinbox.go
├── stddialogs.go
├── tab.go
├── table.go
├── tablemodel.go
├── ui.h
├── util.go
├── window.go
└── winmanifest/
    ├── doc.go
    ├── resources.rc
    ├── ui.manifest
    ├── winmanifest_windows_386.syso
    └── winmanifest_windows_amd64.syso
Download .txt
SYMBOL INDEX (600 symbols across 40 files)

FILE: area.go
  type Area (line 44) | type Area struct
    method Destroy (line 77) | func (a *Area) Destroy() {
    method SetSize (line 84) | func (a *Area) SetSize(width int, height int) {
    method QueueRedrawAll (line 94) | func (a *Area) QueueRedrawAll() {
    method ScrollTo (line 103) | func (a *Area) ScrollTo(x float64, y float64, width float64, height fl...
  function NewArea (line 52) | func NewArea(handler AreaHandler) *Area {
  function NewScrollingArea (line 65) | func NewScrollingArea(handler AreaHandler, width int, height int) *Area {

FILE: areahandler.go
  type AreaHandler (line 36) | type AreaHandler interface
  function registerAreaHandler (line 101) | func registerAreaHandler(ah AreaHandler) *C.uiAreaHandler {
  function unregisterAreaHandler (line 107) | func unregisterAreaHandler(uah *C.uiAreaHandler) {
  type AreaDrawParams (line 115) | type AreaDrawParams struct
  function pkguiDoAreaHandlerDraw (line 140) | func pkguiDoAreaHandlerDraw(uah *C.uiAreaHandler, ua *C.uiArea, udp *C.u...
  type AreaMouseEvent (line 158) | type AreaMouseEvent struct
  function appendBits (line 178) | func appendBits(out []uint, held C.uint64_t) []uint {
  function pkguiDoAreaHandlerMouseEvent (line 191) | func pkguiDoAreaHandlerMouseEvent(uah *C.uiAreaHandler, ua *C.uiArea, um...
  function pkguiDoAreaHandlerMouseCrossed (line 210) | func pkguiDoAreaHandlerMouseCrossed(uah *C.uiAreaHandler, ua *C.uiArea, ...
  function pkguiDoAreaHandlerDragBroken (line 217) | func pkguiDoAreaHandlerDragBroken(uah *C.uiAreaHandler, ua *C.uiArea) {
  type AreaKeyEvent (line 224) | type AreaKeyEvent struct
  function pkguiDoAreaHandlerKeyEvent (line 233) | func pkguiDoAreaHandlerKeyEvent(uah *C.uiAreaHandler, ua *C.uiArea, uke ...
  type Modifiers (line 249) | type Modifiers
  constant Ctrl (line 251) | Ctrl Modifiers = 1 << iota
  constant Alt (line 252) | Alt
  constant Shift (line 253) | Shift
  constant Super (line 254) | Super
  type ExtKey (line 260) | type ExtKey
  constant Escape (line 262) | Escape ExtKey = iota + 1
  constant Insert (line 263) | Insert
  constant Delete (line 264) | Delete
  constant Home (line 265) | Home
  constant End (line 266) | End
  constant PageUp (line 267) | PageUp
  constant PageDown (line 268) | PageDown
  constant Up (line 269) | Up
  constant Down (line 270) | Down
  constant Left (line 271) | Left
  constant Right (line 272) | Right
  constant F1 (line 273) | F1
  constant F2 (line 274) | F2
  constant F3 (line 275) | F3
  constant F4 (line 276) | F4
  constant F5 (line 277) | F5
  constant F6 (line 278) | F6
  constant F7 (line 279) | F7
  constant F8 (line 280) | F8
  constant F9 (line 281) | F9
  constant F10 (line 282) | F10
  constant F11 (line 283) | F11
  constant F12 (line 284) | F12
  constant N0 (line 285) | N0
  constant N1 (line 286) | N1
  constant N2 (line 287) | N2
  constant N3 (line 288) | N3
  constant N4 (line 289) | N4
  constant N5 (line 290) | N5
  constant N6 (line 291) | N6
  constant N7 (line 292) | N7
  constant N8 (line 293) | N8
  constant N9 (line 294) | N9
  constant NDot (line 295) | NDot
  constant NEnter (line 296) | NEnter
  constant NAdd (line 297) | NAdd
  constant NSubtract (line 298) | NSubtract
  constant NMultiply (line 299) | NMultiply
  constant NDivide (line 300) | NDivide

FILE: box.go
  type Box (line 20) | type Box struct
    method Destroy (line 48) | func (b *Box) Destroy() {
    method Append (line 58) | func (b *Box) Append(child Control, stretchy bool) {
    method Delete (line 69) | func (b *Box) Delete(n int) {
    method Padded (line 76) | func (b *Box) Padded() bool {
    method SetPadded (line 83) | func (b *Box) SetPadded(padded bool) {
  function NewHorizontalBox (line 27) | func NewHorizontalBox() *Box {
  function NewVerticalBox (line 37) | func NewVerticalBox() *Box {

FILE: button.go
  type Button (line 15) | type Button struct
    method Text (line 36) | func (b *Button) Text() string {
    method SetText (line 44) | func (b *Button) SetText(text string) {
    method OnClicked (line 52) | func (b *Button) OnClicked(f func(*Button)) {
  function NewButton (line 22) | func NewButton(text string) *Button {
  function pkguiDoButtonOnClicked (line 57) | func pkguiDoButtonOnClicked(bb *C.uiButton, data unsafe.Pointer) {

FILE: checkbox.go
  type Checkbox (line 15) | type Checkbox struct
    method Text (line 37) | func (c *Checkbox) Text() string {
    method SetText (line 45) | func (c *Checkbox) SetText(text string) {
    method OnToggled (line 53) | func (c *Checkbox) OnToggled(f func(*Checkbox)) {
    method Checked (line 66) | func (c *Checkbox) Checked() bool {
    method SetChecked (line 71) | func (c *Checkbox) SetChecked(checked bool) {
  function NewCheckbox (line 23) | func NewCheckbox(text string) *Checkbox {
  function pkguiDoCheckboxOnToggled (line 58) | func pkguiDoCheckboxOnToggled(cc *C.uiCheckbox, data unsafe.Pointer) {

FILE: colorbutton.go
  type ColorButton (line 14) | type ColorButton struct
    method Color (line 35) | func (b *ColorButton) Color() (r, g, bl, a float64) {
    method SetColor (line 45) | func (b *ColorButton) SetColor(r, g, bl, a float64) {
    method OnChanged (line 52) | func (b *ColorButton) OnChanged(f func(*ColorButton)) {
  function NewColorButton (line 21) | func NewColorButton() *ColorButton {
  function pkguiDoColorButtonOnChanged (line 57) | func pkguiDoColorButtonOnChanged(bb *C.uiColorButton, data unsafe.Pointe...

FILE: combobox.go
  type Combobox (line 15) | type Combobox struct
    method Append (line 34) | func (c *Combobox) Append(text string) {
    method Selected (line 42) | func (c *Combobox) Selected() int {
    method SetSelected (line 48) | func (c *Combobox) SetSelected(index int) {
    method OnSelected (line 54) | func (c *Combobox) OnSelected(f func(*Combobox)) {
  function NewCombobox (line 22) | func NewCombobox() *Combobox {
  function pkguiDoComboboxOnSelected (line 59) | func pkguiDoComboboxOnSelected(cc *C.uiCombobox, data unsafe.Pointer) {

FILE: control.go
  type Control (line 20) | type Control interface
  type ControlBase (line 73) | type ControlBase struct
    method LibuiControl (line 90) | func (c *ControlBase) LibuiControl() uintptr {
    method Destroy (line 94) | func (c *ControlBase) Destroy() {
    method Handle (line 99) | func (c *ControlBase) Handle() uintptr {
    method Visible (line 103) | func (c *ControlBase) Visible() bool {
    method Show (line 107) | func (c *ControlBase) Show() {
    method Hide (line 111) | func (c *ControlBase) Hide() {
    method Enabled (line 115) | func (c *ControlBase) Enabled() bool {
    method Enable (line 119) | func (c *ControlBase) Enable() {
    method Disable (line 123) | func (c *ControlBase) Disable() {
  function NewControlBase (line 81) | func NewControlBase(iface Control, c uintptr) ControlBase {
  function ControlFromLibui (line 131) | func ControlFromLibui(c uintptr) Control {
  function touiControl (line 137) | func touiControl(c uintptr) *C.uiControl {
  function LibuiFreeText (line 143) | func LibuiFreeText(c uintptr) {

FILE: datetimepicker.go
  type DateTimePicker (line 15) | type DateTimePicker struct
    method Time (line 52) | func (d *DateTimePicker) Time() time.Time {
    method SetTime (line 69) | func (d *DateTimePicker) SetTime(t time.Time) {
    method OnChanged (line 87) | func (d *DateTimePicker) OnChanged(f func(*DateTimePicker)) {
  function finishNewDateTimePicker (line 21) | func finishNewDateTimePicker(dd *C.uiDateTimePicker) *DateTimePicker {
  function NewDateTimePicker (line 34) | func NewDateTimePicker() *DateTimePicker {
  function NewDatePicker (line 40) | func NewDatePicker() *DateTimePicker {
  function NewTimePicker (line 46) | func NewTimePicker() *DateTimePicker {
  function pkguiDoDateTimePickerOnChanged (line 92) | func pkguiDoDateTimePickerOnChanged(dd *C.uiDateTimePicker, data unsafe....

FILE: draw.go
  type DrawPath (line 39) | type DrawPath struct
    method Free (line 71) | func (p *DrawPath) Free() {
    method NewFigure (line 77) | func (p *DrawPath) NewFigure(x float64, y float64) {
    method NewFigureWithArc (line 85) | func (p *DrawPath) NewFigureWithArc(xCenter float64, yCenter float64, ...
    method LineTo (line 96) | func (p *DrawPath) LineTo(x float64, y float64) {
    method ArcTo (line 106) | func (p *DrawPath) ArcTo(xCenter float64, yCenter float64, radius floa...
    method BezierTo (line 119) | func (p *DrawPath) BezierTo(c1x float64, c1y float64, c2x float64, c2y...
    method CloseFigure (line 133) | func (p *DrawPath) CloseFigure() {
    method AddRectangle (line 142) | func (p *DrawPath) AddRectangle(x float64, y float64, width float64, h...
    method End (line 149) | func (p *DrawPath) End() {
  type DrawFillMode (line 46) | type DrawFillMode
  constant DrawFillModeWinding (line 48) | DrawFillModeWinding DrawFillMode = iota
  constant DrawFillModeAlternate (line 49) | DrawFillModeAlternate
  function DrawNewPath (line 53) | func DrawNewPath(fillMode DrawFillMode) *DrawPath {
  type DrawContext (line 156) | type DrawContext struct
    method Stroke (line 301) | func (c *DrawContext) Stroke(p *DrawPath, b *DrawBrush, sp *DrawStroke...
    method Fill (line 310) | func (c *DrawContext) Fill(p *DrawPath, b *DrawBrush) {
    method Transform (line 435) | func (c *DrawContext) Transform(m *DrawMatrix) {
    method Clip (line 442) | func (c *DrawContext) Clip(p *DrawPath) {
    method Save (line 447) | func (c *DrawContext) Save() {
    method Restore (line 452) | func (c *DrawContext) Restore() {
  type DrawBrushType (line 163) | type DrawBrushType
  constant DrawBrushTypeSolid (line 165) | DrawBrushTypeSolid DrawBrushType = iota
  constant DrawBrushTypeLinearGradient (line 166) | DrawBrushTypeLinearGradient
  constant DrawBrushTypeRadialGradient (line 167) | DrawBrushTypeRadialGradient
  constant DrawBrushTypeImage (line 168) | DrawBrushTypeImage
  type DrawLineCap (line 175) | type DrawLineCap
  constant DrawLineCapFlat (line 177) | DrawLineCapFlat DrawLineCap = iota
  constant DrawLineCapRound (line 178) | DrawLineCapRound
  constant DrawLineCapSquare (line 179) | DrawLineCapSquare
  type DrawLineJoin (line 185) | type DrawLineJoin
  constant DrawLineJoinMiter (line 187) | DrawLineJoinMiter DrawLineJoin = iota
  constant DrawLineJoinRound (line 188) | DrawLineJoinRound
  constant DrawLineJoinBevel (line 189) | DrawLineJoinBevel
  constant DrawDefaultMiterLimit (line 193) | DrawDefaultMiterLimit = 10.0
  type DrawBrush (line 196) | type DrawBrush struct
    method toLibui (line 225) | func (b *DrawBrush) toLibui() *C.uiDrawBrush {
  type DrawGradientStop (line 217) | type DrawGradientStop struct
  function freeBrush (line 258) | func freeBrush(cb *C.uiDrawBrush) {
  type DrawStrokeParams (line 266) | type DrawStrokeParams struct
    method toLibui (line 275) | func (sp *DrawStrokeParams) toLibui() *C.uiDrawStrokeParams {
  function freeStrokeParams (line 293) | func freeStrokeParams(csp *C.uiDrawStrokeParams) {
  type DrawMatrix (line 318) | type DrawMatrix struct
    method SetIdentity (line 335) | func (m *DrawMatrix) SetIdentity() {
    method toLibui (line 344) | func (m *DrawMatrix) toLibui() *C.uiDrawMatrix {
    method fromLibui (line 355) | func (m *DrawMatrix) fromLibui(cm *C.uiDrawMatrix) {
    method Translate (line 366) | func (m *DrawMatrix) Translate(x float64, y float64) {
    method Scale (line 373) | func (m *DrawMatrix) Scale(xCenter float64, yCenter float64, x float64...
    method Rotate (line 382) | func (m *DrawMatrix) Rotate(x float64, y float64, amount float64) {
    method Skew (line 389) | func (m *DrawMatrix) Skew(x float64, y float64, xamount float64, yamou...
    method Multiply (line 398) | func (m *DrawMatrix) Multiply(m2 *DrawMatrix) {
    method Invertible (line 407) | func (m *DrawMatrix) Invertible() bool {
    method Invert (line 417) | func (m *DrawMatrix) Invert() bool {
    method TransformPoint (line 425) | func (m *DrawMatrix) TransformPoint(x float64, y float64) (xout float6...
    method TransformSize (line 430) | func (m *DrawMatrix) TransformSize(x float64, y float64) (xout float64...
  function DrawNewMatrix (line 328) | func DrawNewMatrix() *DrawMatrix {

FILE: drawtext.go
  type Attribute (line 27) | type Attribute interface
  type TextFamily (line 33) | type TextFamily
    method toLibui (line 35) | func (f TextFamily) toLibui() *C.uiAttribute {
  type TextSize (line 43) | type TextSize
    method toLibui (line 45) | func (s TextSize) toLibui() *C.uiAttribute {
  type TextWeight (line 64) | type TextWeight
    method toLibui (line 81) | func (w TextWeight) toLibui() *C.uiAttribute {
  constant TextWeightMinimum (line 66) | TextWeightMinimum TextWeight = 0
  constant TextWeightThin (line 67) | TextWeightThin TextWeight = 100
  constant TextWeightUltraLight (line 68) | TextWeightUltraLight TextWeight = 200
  constant TextWeightLight (line 69) | TextWeightLight TextWeight = 300
  constant TextWeightBook (line 70) | TextWeightBook TextWeight = 350
  constant TextWeightNormal (line 71) | TextWeightNormal TextWeight = 400
  constant TextWeightMedium (line 72) | TextWeightMedium TextWeight = 500
  constant TextWeightSemiBold (line 73) | TextWeightSemiBold TextWeight = 600
  constant TextWeightBold (line 74) | TextWeightBold TextWeight = 700
  constant TextWeightUltraBold (line 75) | TextWeightUltraBold TextWeight = 800
  constant TextWeightHeavy (line 76) | TextWeightHeavy TextWeight = 900
  constant TextWeightUltraHeavy (line 77) | TextWeightUltraHeavy TextWeight = 950
  constant TextWeightMaximum (line 78) | TextWeightMaximum TextWeight = 1000
  type TextItalic (line 90) | type TextItalic
    method toLibui (line 97) | func (i TextItalic) toLibui() *C.uiAttribute {
  constant TextItalicNormal (line 92) | TextItalicNormal TextItalic = iota
  constant TextItalicOblique (line 93) | TextItalicOblique
  constant TextItalicItalic (line 94) | TextItalicItalic
  type TextStretch (line 111) | type TextStretch
    method toLibui (line 124) | func (s TextStretch) toLibui() *C.uiAttribute {
  constant TextStretchUltraCondensed (line 113) | TextStretchUltraCondensed TextStretch = iota
  constant TextStretchExtraCondensed (line 114) | TextStretchExtraCondensed
  constant TextStretchCondensed (line 115) | TextStretchCondensed
  constant TextStretchSemiCondensed (line 116) | TextStretchSemiCondensed
  constant TextStretchNormal (line 117) | TextStretchNormal
  constant TextStretchSemiExpanded (line 118) | TextStretchSemiExpanded
  constant TextStretchExpanded (line 119) | TextStretchExpanded
  constant TextStretchExtraExpanded (line 120) | TextStretchExtraExpanded
  constant TextStretchUltraExpanded (line 121) | TextStretchUltraExpanded
  type TextColor (line 130) | type TextColor struct
    method toLibui (line 137) | func (c TextColor) toLibui() *C.uiAttribute {
  type TextBackground (line 143) | type TextBackground struct
    method toLibui (line 150) | func (b TextBackground) toLibui() *C.uiAttribute {
  type Underline (line 156) | type Underline
    method toLibui (line 164) | func (u Underline) toLibui() *C.uiAttribute {
  constant UnderlineNone (line 158) | UnderlineNone Underline = iota
  constant UnderlineSingle (line 159) | UnderlineSingle
  constant UnderlineDouble (line 160) | UnderlineDouble
  constant UnderlineSuggestion (line 161) | UnderlineSuggestion
  type UnderlineColor (line 182) | type UnderlineColor
    method toLibui (line 189) | func (u UnderlineColor) toLibui() *C.uiAttribute {
  constant UnderlineColorSpelling (line 184) | UnderlineColorSpelling UnderlineColor = iota + 1
  constant UnderlineColorGrammar (line 185) | UnderlineColorGrammar
  constant UnderlineColorAuxiliary (line 186) | UnderlineColorAuxiliary
  type UnderlineColorCustom (line 195) | type UnderlineColorCustom struct
    method toLibui (line 202) | func (u UnderlineColorCustom) toLibui() *C.uiAttribute {
  type OpenTypeFeatures (line 237) | type OpenTypeFeatures
    method toLibui (line 239) | func (o OpenTypeFeatures) toLibui() *C.uiAttribute {
  type OpenTypeTag (line 253) | type OpenTypeTag
  function ToOpenTypeTag (line 257) | func ToOpenTypeTag(a, b, c, d byte) OpenTypeTag {
  function attributeFromLibui (line 264) | func attributeFromLibui(a *C.uiAttribute) Attribute {
  type AttributedString (line 359) | type AttributedString struct
    method Free (line 374) | func (s *AttributedString) Free() {
    method String (line 379) | func (s *AttributedString) String() string {
    method AppendUnattributed (line 385) | func (s *AttributedString) AppendUnattributed(str string) {
    method InsertAtUnattributed (line 394) | func (s *AttributedString) InsertAtUnattributed(str string, at int) {
    method Delete (line 402) | func (s *AttributedString) Delete(start, end int) {
    method SetAttribute (line 408) | func (s *AttributedString) SetAttribute(a Attribute, start, end int) {
  function NewAttributedString (line 365) | func NewAttributedString(initialString string) *AttributedString {
  type FontDescriptor (line 420) | type FontDescriptor struct
    method fromLibui (line 428) | func (d *FontDescriptor) fromLibui(fd *C.uiFontDescriptor) {
    method toLibui (line 436) | func (d *FontDescriptor) toLibui() *C.uiFontDescriptor {
  function freeLibuiFontDescriptor (line 446) | func freeLibuiFontDescriptor(fd *C.uiFontDescriptor) {
  type DrawTextLayout (line 462) | type DrawTextLayout struct
    method Free (line 503) | func (tl *DrawTextLayout) Free() {
  type DrawTextAlign (line 469) | type DrawTextAlign
  constant DrawTextAlignLeft (line 471) | DrawTextAlignLeft DrawTextAlign = iota
  constant DrawTextAlignCenter (line 472) | DrawTextAlignCenter
  constant DrawTextAlignRight (line 473) | DrawTextAlignRight
  type DrawTextLayoutParams (line 480) | type DrawTextLayoutParams struct
  function DrawNewTextLayout (line 489) | func DrawNewTextLayout(p *DrawTextLayoutParams) *DrawTextLayout {
  method Text (line 508) | func (c *DrawContext) Text(tl *DrawTextLayout, x, y float64) {

FILE: editablecombobox.go
  type EditableCombobox (line 15) | type EditableCombobox struct
    method Append (line 34) | func (e *EditableCombobox) Append(text string) {
    method Text (line 42) | func (e *EditableCombobox) Text() string {
    method SetText (line 50) | func (e *EditableCombobox) SetText(text string) {
    method OnChanged (line 59) | func (e *EditableCombobox) OnChanged(f func(*EditableCombobox)) {
  function NewEditableCombobox (line 22) | func NewEditableCombobox() *EditableCombobox {
  function pkguiDoEditableComboboxOnChanged (line 64) | func pkguiDoEditableComboboxOnChanged(cc *C.uiEditableCombobox, data uns...

FILE: entry.go
  type Entry (line 18) | type Entry struct
    method Text (line 54) | func (e *Entry) Text() string {
    method SetText (line 62) | func (e *Entry) SetText(text string) {
    method OnChanged (line 70) | func (e *Entry) OnChanged(f func(*Entry)) {
    method ReadOnly (line 83) | func (e *Entry) ReadOnly() bool {
    method SetReadOnly (line 88) | func (e *Entry) SetReadOnly(ro bool) {
  function finishNewEntry (line 24) | func finishNewEntry(ee *C.uiEntry) *Entry {
  function NewEntry (line 36) | func NewEntry() *Entry {
  function NewPasswordEntry (line 42) | func NewPasswordEntry() *Entry {
  function NewSearchEntry (line 49) | func NewSearchEntry() *Entry {
  function pkguiDoEntryOnChanged (line 75) | func pkguiDoEntryOnChanged(ee *C.uiEntry, data unsafe.Pointer) {

FILE: examples/controlgallery.go
  function makeBasicControlsPage (line 14) | func makeBasicControlsPage() ui.Control {
  function makeNumbersPage (line 48) | func makeNumbersPage() ui.Control {
  function makeDataChoosersPage (line 108) | func makeDataChoosersPage() ui.Control {
  function setupUI (line 194) | func setupUI() {
  function main (line 221) | func main() {

FILE: examples/drawtext.go
  function appendWithAttributes (line 21) | func appendWithAttributes(what string, attrs ...ui.Attribute) {
  function makeAttributedString (line 30) | func makeAttributedString() {
  type areaHandler (line 84) | type areaHandler struct
    method Draw (line 86) | func (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) {
    method MouseEvent (line 97) | func (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
    method MouseCrossed (line 101) | func (areaHandler) MouseCrossed(a *ui.Area, left bool) {
    method DragBroken (line 105) | func (areaHandler) DragBroken(a *ui.Area) {
    method KeyEvent (line 109) | func (areaHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled ...
  function setupUI (line 114) | func setupUI() {
  function main (line 166) | func main() {

FILE: examples/histogram.go
  constant xoffLeft (line 25) | xoffLeft = 20
  constant yoffTop (line 26) | yoffTop = 20
  constant xoffRight (line 27) | xoffRight = 20
  constant yoffBottom (line 28) | yoffBottom = 20
  constant pointRadius (line 29) | pointRadius = 5
  function mkSolidBrush (line 33) | func mkSolidBrush(color uint32, alpha float64) *ui.DrawBrush {
  constant colorWhite (line 49) | colorWhite = 0xFFFFFF
  constant colorBlack (line 50) | colorBlack = 0x000000
  constant colorDodgerBlue (line 51) | colorDodgerBlue = 0x1E90FF
  function pointLocations (line 54) | func pointLocations(width, height float64) (xs, ys [10]float64) {
  function constructGraph (line 68) | func constructGraph(width, height float64, extend bool) *ui.DrawPath {
  function graphSize (line 87) | func graphSize(clientWidth, clientHeight float64) (graphWidth, graphHeig...
  type areaHandler (line 92) | type areaHandler struct
    method Draw (line 94) | func (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) {
    method MouseEvent (line 173) | func (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {
    method MouseCrossed (line 189) | func (areaHandler) MouseCrossed(a *ui.Area, left bool) {
    method DragBroken (line 193) | func (areaHandler) DragBroken(a *ui.Area) {
    method KeyEvent (line 197) | func (areaHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled ...
  function inPoint (line 163) | func inPoint(x, y float64, xtest, ytest float64) bool {
  function setupUI (line 202) | func setupUI() {
  function main (line 252) | func main() {

FILE: examples/table.go
  type modelHandler (line 22) | type modelHandler struct
    method ColumnTypes (line 35) | func (mh *modelHandler) ColumnTypes(m *ui.TableModel) []ui.TableValue {
    method NumRows (line 49) | func (mh *modelHandler) NumRows(m *ui.TableModel) int {
    method CellValue (line 55) | func (mh *modelHandler) CellValue(m *ui.TableModel, row, column int) u...
    method SetCellValue (line 111) | func (mh *modelHandler) SetCellValue(m *ui.TableModel, row, column int...
  function newModelHandler (line 28) | func newModelHandler() *modelHandler {
  function appendImageNamed (line 128) | func appendImageNamed(i *ui.Image, which string) {
  function setupUI (line 143) | func setupUI() {
  function main (line 193) | func main() {

FILE: examples/updateui.go
  function setupUI (line 18) | func setupUI() {
  function counter (line 99) | func counter() {
  function main (line 111) | func main() {

FILE: fontbutton.go
  type FontButton (line 14) | type FontButton struct
    method Font (line 33) | func (b *FontButton) Font() *FontDescriptor {
    method OnChanged (line 46) | func (b *FontButton) OnChanged(f func(*FontButton)) {
  function NewFontButton (line 21) | func NewFontButton() *FontButton {
  function pkguiDoFontButtonOnChanged (line 51) | func pkguiDoFontButtonOnChanged(bb *C.uiFontButton, data unsafe.Pointer) {

FILE: form.go
  type Form (line 18) | type Form struct
    method Destroy (line 36) | func (f *Form) Destroy() {
    method Append (line 46) | func (f *Form) Append(label string, child Control, stretchy bool) {
    method Delete (line 55) | func (f *Form) Delete(n int) {
    method Padded (line 62) | func (f *Form) Padded() bool {
    method SetPadded (line 69) | func (f *Form) SetPadded(padded bool) {
  function NewForm (line 25) | func NewForm() *Form {

FILE: grid.go
  type Grid (line 28) | type Grid struct
    method Append (line 65) | func (g *Grid) Append(child Control, left, top int, xspan, yspan int, ...
    method InsertAt (line 76) | func (g *Grid) InsertAt(child Control, existing Control, at At, xspan,...
    method Padded (line 87) | func (g *Grid) Padded() bool {
    method SetPadded (line 94) | func (g *Grid) SetPadded(padded bool) {
  type Align (line 35) | type Align
  constant AlignFill (line 37) | AlignFill Align = iota
  constant AlignStart (line 38) | AlignStart
  constant AlignCenter (line 39) | AlignCenter
  constant AlignEnd (line 40) | AlignEnd
  type At (line 44) | type At
  constant Leading (line 46) | Leading At = iota
  constant Top (line 47) | Top
  constant Trailing (line 48) | Trailing
  constant Bottom (line 49) | Bottom
  function NewGrid (line 53) | func NewGrid() *Grid {

FILE: group.go
  type Group (line 15) | type Group struct
    method Destroy (line 35) | func (g *Group) Destroy() {
    method Title (line 45) | func (g *Group) Title() string {
    method SetTitle (line 53) | func (g *Group) SetTitle(title string) {
    method SetChild (line 61) | func (g *Group) SetChild(child Control) {
    method Margined (line 71) | func (g *Group) Margined() bool {
    method SetMargined (line 78) | func (g *Group) SetMargined(margined bool) {
  function NewGroup (line 22) | func NewGroup(title string) *Group {

FILE: image.go
  type Image (line 31) | type Image struct
    method Free (line 45) | func (i *Image) Free() {
    method Append (line 50) | func (i *Image) Append(img *image.RGBA) {
  function NewImage (line 38) | func NewImage(width, height float64) *Image {

FILE: label.go
  type Label (line 14) | type Label struct
    method Text (line 32) | func (l *Label) Text() string {
    method SetText (line 40) | func (l *Label) SetText(text string) {
  function NewLabel (line 20) | func NewLabel(text string) *Label {

FILE: main.go
  function init (line 19) | func init() {
  function Main (line 30) | func Main(f func()) error {
  function Quit (line 48) | func Quit() {
  function QueueMain (line 75) | func QueueMain(f func()) {
  function pkguiDoQueueMain (line 92) | func pkguiDoQueueMain(nn unsafe.Pointer) {
  function OnShouldQuit (line 115) | func OnShouldQuit(f func() bool) {
  function pkguiDoOnShouldQuit (line 120) | func pkguiDoOnShouldQuit(unused unsafe.Pointer) C.int {

FILE: multilineentry.go
  type MultilineEntry (line 18) | type MultilineEntry struct
    method Text (line 50) | func (m *MultilineEntry) Text() string {
    method SetText (line 58) | func (m *MultilineEntry) SetText(text string) {
    method Append (line 66) | func (m *MultilineEntry) Append(text string) {
    method OnChanged (line 74) | func (m *MultilineEntry) OnChanged(f func(*MultilineEntry)) {
    method ReadOnly (line 87) | func (m *MultilineEntry) ReadOnly() bool {
    method SetReadOnly (line 92) | func (m *MultilineEntry) SetReadOnly(ro bool) {
  function finishNewMultilineEntry (line 24) | func finishNewMultilineEntry(ee *C.uiMultilineEntry) *MultilineEntry {
  function NewMultilineEntry (line 38) | func NewMultilineEntry() *MultilineEntry {
  function NewNonWrappingMultilineEntry (line 45) | func NewNonWrappingMultilineEntry() *MultilineEntry {
  function pkguiDoMultilineEntryOnChanged (line 79) | func pkguiDoMultilineEntryOnChanged(ee *C.uiMultilineEntry, data unsafe....

FILE: pkgui.c
  function uiInitOptions (line 5) | uiInitOptions *pkguiAllocInitOptions(void)
  function pkguiFreeInitOptions (line 10) | void pkguiFreeInitOptions(uiInitOptions *o)
  function pkguiQueueMain (line 15) | void pkguiQueueMain(uintptr_t n)
  function pkguiOnShouldQuit (line 20) | void pkguiOnShouldQuit(void)
  function pkguiWindowOnClosing (line 25) | void pkguiWindowOnClosing(uiWindow *w)
  function pkguiButtonOnClicked (line 30) | void pkguiButtonOnClicked(uiButton *b)
  function pkguiCheckboxOnToggled (line 35) | void pkguiCheckboxOnToggled(uiCheckbox *c)
  function pkguiColorButtonOnChanged (line 40) | void pkguiColorButtonOnChanged(uiColorButton *c)
  function pkguiColorDoubles (line 45) | pkguiColorDoubles pkguiAllocColorDoubles(void)
  function pkguiFreeColorDoubles (line 56) | void pkguiFreeColorDoubles(pkguiColorDoubles c)
  function pkguiComboboxOnSelected (line 61) | void pkguiComboboxOnSelected(uiCombobox *c)
  function pkguiDateTimePickerOnChanged (line 66) | void pkguiDateTimePickerOnChanged(uiDateTimePicker *d)
  type tm (line 71) | struct tm
  type tm (line 73) | struct tm
  type tm (line 73) | struct tm
  function pkguiFreeTime (line 76) | void pkguiFreeTime(struct tm *t)
  function pkguiEditableComboboxOnChanged (line 81) | void pkguiEditableComboboxOnChanged(uiEditableCombobox *c)
  function pkguiEntryOnChanged (line 86) | void pkguiEntryOnChanged(uiEntry *e)
  function pkguiFontButtonOnChanged (line 91) | void pkguiFontButtonOnChanged(uiFontButton *b)
  function pkguiMultilineEntryOnChanged (line 96) | void pkguiMultilineEntryOnChanged(uiMultilineEntry *e)
  function pkguiRadioButtonsOnSelected (line 101) | void pkguiRadioButtonsOnSelected(uiRadioButtons *r)
  function pkguiSliderOnChanged (line 106) | void pkguiSliderOnChanged(uiSlider *s)
  function pkguiSpinboxOnChanged (line 111) | void pkguiSpinboxOnChanged(uiSpinbox *s)
  function uiDrawBrush (line 116) | uiDrawBrush *pkguiAllocBrush(void)
  function pkguiFreeBrush (line 121) | void pkguiFreeBrush(uiDrawBrush *b)
  function uiDrawBrushGradientStop (line 126) | uiDrawBrushGradientStop *pkguiAllocGradientStops(size_t n)
  function pkguiFreeGradientStops (line 131) | void pkguiFreeGradientStops(uiDrawBrushGradientStop *stops)
  function pkguiSetGradientStop (line 136) | void pkguiSetGradientStop(uiDrawBrushGradientStop *stops, size_t i, doub...
  function uiDrawStrokeParams (line 145) | uiDrawStrokeParams *pkguiAllocStrokeParams(void)
  function pkguiFreeStrokeParams (line 150) | void pkguiFreeStrokeParams(uiDrawStrokeParams *p)
  function pkguiFreeDashes (line 160) | void pkguiFreeDashes(double *dashes)
  function pkguiSetDash (line 165) | void pkguiSetDash(double *dashes, size_t i, double dash)
  function uiDrawMatrix (line 170) | uiDrawMatrix *pkguiAllocMatrix(void)
  function pkguiFreeMatrix (line 175) | void pkguiFreeMatrix(uiDrawMatrix *m)
  function uiUnderlineColor (line 180) | uiUnderlineColor *pkguiNewUnderlineColor(void)
  function pkguiFreeUnderlineColor (line 185) | void pkguiFreeUnderlineColor(uiUnderlineColor *c)
  function uiFontDescriptor (line 190) | uiFontDescriptor *pkguiNewFontDescriptor(void)
  function pkguiFreeFontDescriptor (line 195) | void pkguiFreeFontDescriptor(uiFontDescriptor *fd)
  function uiDrawTextLayoutParams (line 200) | uiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void)
  function pkguiFreeDrawTextLayoutParams (line 205) | void pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *p)
  function uiAreaHandler (line 210) | uiAreaHandler *pkguiAllocAreaHandler(void)
  function pkguiFreeAreaHandler (line 223) | void pkguiFreeAreaHandler(uiAreaHandler *ah)
  function realDoTableModelSetCellValue (line 229) | static void realDoTableModelSetCellValue(uiTableModelHandler *mh, uiTabl...
  function uiTableTextColumnOptionalParams (line 242) | uiTableTextColumnOptionalParams *pkguiAllocTableTextColumnOptionalParams...
  function pkguiFreeTableTextColumnOptionalParams (line 247) | void pkguiFreeTableTextColumnOptionalParams(uiTableTextColumnOptionalPar...
  function uiTableParams (line 252) | uiTableParams *pkguiAllocTableParams(void)
  function pkguiFreeTableParams (line 257) | void pkguiFreeTableParams(uiTableParams *p)

FILE: pkgui.h
  type pkguiColorDoubles (line 27) | typedef struct pkguiColorDoubles pkguiColorDoubles;
  type pkguiColorDoubles (line 28) | struct pkguiColorDoubles {
  type tm (line 42) | struct tm
  type tm (line 43) | struct tm

FILE: progressbar.go
  type ProgressBar (line 14) | type ProgressBar struct
    method Value (line 30) | func (p *ProgressBar) Value() int {
    method SetValue (line 37) | func (p *ProgressBar) SetValue(value int) {
  function NewProgressBar (line 20) | func NewProgressBar() *ProgressBar {

FILE: radiobuttons.go
  type RadioButtons (line 14) | type RadioButtons struct
    method Append (line 33) | func (r *RadioButtons) Append(text string) {
    method Selected (line 41) | func (r *RadioButtons) Selected() int {
    method SetSelected (line 47) | func (r *RadioButtons) SetSelected(index int) {
    method OnSelected (line 53) | func (r *RadioButtons) OnSelected(f func(*RadioButtons)) {
  function NewRadioButtons (line 21) | func NewRadioButtons() *RadioButtons {
  function pkguiDoRadioButtonsOnSelected (line 58) | func pkguiDoRadioButtonsOnSelected(rr *C.uiRadioButtons, data unsafe.Poi...

FILE: separator.go
  type Separator (line 14) | type Separator struct
  function NewHorizontalSeparator (line 20) | func NewHorizontalSeparator() *Separator {
  function NewVerticalSeparator (line 30) | func NewVerticalSeparator() *Separator {

FILE: slider.go
  type Slider (line 15) | type Slider struct
    method Value (line 34) | func (s *Slider) Value() int {
    method SetValue (line 39) | func (s *Slider) SetValue(value int) {
    method OnChanged (line 45) | func (s *Slider) OnChanged(f func(*Slider)) {
  function NewSlider (line 22) | func NewSlider(min int, max int) *Slider {
  function pkguiDoSliderOnChanged (line 50) | func pkguiDoSliderOnChanged(ss *C.uiSlider, data unsafe.Pointer) {

FILE: spinbox.go
  type Spinbox (line 15) | type Spinbox struct
    method Value (line 34) | func (s *Spinbox) Value() int {
    method SetValue (line 39) | func (s *Spinbox) SetValue(value int) {
    method OnChanged (line 45) | func (s *Spinbox) OnChanged(f func(*Spinbox)) {
  function NewSpinbox (line 22) | func NewSpinbox(min int, max int) *Spinbox {
  function pkguiDoSpinboxOnChanged (line 50) | func pkguiDoSpinboxOnChanged(ss *C.uiSpinbox, data unsafe.Pointer) {

FILE: stddialogs.go
  function MsgBoxError (line 9) | func MsgBoxError(w *Window, title string, description string) {
  function OpenFile (line 17) | func OpenFile(w *Window) string {
  function SaveFile (line 26) | func SaveFile(w *Window) string {
  function MsgBox (line 35) | func MsgBox(w *Window, title string, description string) {

FILE: tab.go
  type Tab (line 15) | type Tab struct
    method Destroy (line 33) | func (t *Tab) Destroy() {
    method Append (line 43) | func (t *Tab) Append(name string, child Control) {
    method InsertAt (line 49) | func (t *Tab) InsertAt(name string, n int, child Control) {
    method Delete (line 66) | func (t *Tab) Delete(n int) {
    method NumPages (line 72) | func (t *Tab) NumPages() int {
    method Margined (line 78) | func (t *Tab) Margined(n int) bool {
    method SetMargined (line 85) | func (t *Tab) SetMargined(n int, margined bool) {
  function NewTab (line 22) | func NewTab() *Tab {

FILE: table.go
  constant TableModelColumnNeverEditable (line 18) | TableModelColumnNeverEditable = -1
  constant TableModelColumnAlwaysEditable (line 19) | TableModelColumnAlwaysEditable = -2
  type TableTextColumnOptionalParams (line 24) | type TableTextColumnOptionalParams struct
    method toLibui (line 34) | func (p *TableTextColumnOptionalParams) toLibui() *C.uiTableTextColumn...
  type TableParams (line 44) | type TableParams struct
    method toLibui (line 59) | func (p *TableParams) toLibui() *C.uiTableParams {
  type Table (line 68) | type Table struct
    method AppendTextColumn (line 90) | func (t *Table) AppendTextColumn(name string, textModelColumn int, tex...
    method AppendImageColumn (line 101) | func (t *Table) AppendImageColumn(name string, imageModelColumn int) {
    method AppendImageTextColumn (line 109) | func (t *Table) AppendImageTextColumn(name string, imageModelColumn in...
    method AppendCheckboxColumn (line 121) | func (t *Table) AppendCheckboxColumn(name string, checkboxModelColumn ...
    method AppendCheckboxTextColumn (line 129) | func (t *Table) AppendCheckboxTextColumn(name string, checkboxModelCol...
    method AppendProgressBarColumn (line 141) | func (t *Table) AppendProgressBarColumn(name string, progressModelColu...
    method AppendButtonColumn (line 153) | func (t *Table) AppendButtonColumn(name string, buttonModelColumn int,...
  function NewTable (line 74) | func NewTable(p *TableParams) *Table {

FILE: tablemodel.go
  type TableValue (line 10) | type TableValue interface
  type TableString (line 16) | type TableString
    method toLibui (line 18) | func (s TableString) toLibui() *C.uiTableValue {
  type TableImage (line 27) | type TableImage struct
    method toLibui (line 31) | func (i TableImage) toLibui() *C.uiTableValue {
  type TableInt (line 38) | type TableInt
    method toLibui (line 46) | func (i TableInt) toLibui() *C.uiTableValue {
  constant TableFalse (line 42) | TableFalse TableInt = 0
  constant TableTrue (line 43) | TableTrue TableInt = 1
  type TableColor (line 51) | type TableColor struct
    method toLibui (line 58) | func (c TableColor) toLibui() *C.uiTableValue {
  function tableValueFromLibui (line 62) | func tableValueFromLibui(value *C.uiTableValue) TableValue {
  type TableModel (line 100) | type TableModel struct
    method Free (line 197) | func (m *TableModel) Free() {
    method RowInserted (line 207) | func (m *TableModel) RowInserted(index int) {
    method RowChanged (line 215) | func (m *TableModel) RowChanged(index int) {
    method RowDeleted (line 223) | func (m *TableModel) RowDeleted(index int) {
  type TableModelHandler (line 106) | type TableModelHandler interface
  function pkguiDoTableModelNumColumns (line 140) | func pkguiDoTableModelNumColumns(umh *C.uiTableModelHandler, um *C.uiTab...
  function pkguiDoTableModelColumnType (line 146) | func pkguiDoTableModelColumnType(umh *C.uiTableModelHandler, um *C.uiTab...
  function pkguiDoTableModelNumRows (line 163) | func pkguiDoTableModelNumRows(umh *C.uiTableModelHandler, um *C.uiTableM...
  function pkguiDoTableModelCellValue (line 169) | func pkguiDoTableModelCellValue(umh *C.uiTableModelHandler, um *C.uiTabl...
  function pkguiDoTableModelSetCellValue (line 179) | func pkguiDoTableModelSetCellValue(umh *C.uiTableModelHandler, um *C.uiT...
  function NewTableModel (line 186) | func NewTableModel(handler TableModelHandler) *TableModel {

FILE: ui.h
  type uiInitOptions (line 48) | typedef struct uiInitOptions uiInitOptions;
  type uiInitOptions (line 50) | struct uiInitOptions {
  type uiControl (line 77) | typedef struct uiControl uiControl;
  type uiControl (line 79) | struct uiControl {
  type uiWindow (line 118) | typedef struct uiWindow uiWindow;
  type uiButton (line 135) | typedef struct uiButton uiButton;
  type uiBox (line 142) | typedef struct uiBox uiBox;
  type uiCheckbox (line 151) | typedef struct uiCheckbox uiCheckbox;
  type uiEntry (line 160) | typedef struct uiEntry uiEntry;
  type uiLabel (line 171) | typedef struct uiLabel uiLabel;
  type uiTab (line 177) | typedef struct uiTab uiTab;
  type uiGroup (line 187) | typedef struct uiGroup uiGroup;
  type uiSpinbox (line 201) | typedef struct uiSpinbox uiSpinbox;
  type uiSlider (line 208) | typedef struct uiSlider uiSlider;
  type uiProgressBar (line 215) | typedef struct uiProgressBar uiProgressBar;
  type uiSeparator (line 221) | typedef struct uiSeparator uiSeparator;
  type uiCombobox (line 226) | typedef struct uiCombobox uiCombobox;
  type uiEditableCombobox (line 234) | typedef struct uiEditableCombobox uiEditableCombobox;
  type uiRadioButtons (line 243) | typedef struct uiRadioButtons uiRadioButtons;
  type tm (line 251) | struct tm
  type uiDateTimePicker (line 252) | typedef struct uiDateTimePicker uiDateTimePicker;
  type tm (line 258) | struct tm
  type tm (line 259) | struct tm
  type uiMultilineEntry (line 266) | typedef struct uiMultilineEntry uiMultilineEntry;
  type uiMenuItem (line 277) | typedef struct uiMenuItem uiMenuItem;
  type uiMenu (line 285) | typedef struct uiMenu uiMenu;
  type uiArea (line 300) | typedef struct uiArea uiArea;
  type uiAreaHandler (line 301) | typedef struct uiAreaHandler uiAreaHandler;
  type uiAreaDrawParams (line 302) | typedef struct uiAreaDrawParams uiAreaDrawParams;
  type uiAreaMouseEvent (line 303) | typedef struct uiAreaMouseEvent uiAreaMouseEvent;
  type uiAreaKeyEvent (line 304) | typedef struct uiAreaKeyEvent uiAreaKeyEvent;
  type uiDrawContext (line 306) | typedef struct uiDrawContext uiDrawContext;
  type uiAreaHandler (line 308) | struct uiAreaHandler {
  type uiAreaDrawParams (line 352) | struct uiAreaDrawParams {
  type uiDrawPath (line 365) | typedef struct uiDrawPath uiDrawPath;
  type uiDrawBrush (line 366) | typedef struct uiDrawBrush uiDrawBrush;
  type uiDrawStrokeParams (line 367) | typedef struct uiDrawStrokeParams uiDrawStrokeParams;
  type uiDrawMatrix (line 368) | typedef struct uiDrawMatrix uiDrawMatrix;
  type uiDrawBrushGradientStop (line 370) | typedef struct uiDrawBrushGradientStop uiDrawBrushGradientStop;
  type uiDrawMatrix (line 401) | struct uiDrawMatrix {
  type uiDrawBrush (line 410) | struct uiDrawBrush {
  type uiDrawBrushGradientStop (line 438) | struct uiDrawBrushGradientStop {
  type uiDrawStrokeParams (line 446) | struct uiDrawStrokeParams {
  type uiAttribute (line 516) | typedef struct uiAttribute uiAttribute;
  type uiOpenTypeFeatures (line 742) | typedef struct uiOpenTypeFeatures uiOpenTypeFeatures;
  type uiForEach (line 748) | typedef uiForEach (*uiOpenTypeFeaturesForEachFunc)(const uiOpenTypeFeatu...
  type uiAttributedString (line 841) | typedef struct uiAttributedString uiAttributedString;
  type uiForEach (line 847) | typedef uiForEach (*uiAttributedStringForEachAttributeFunc)(const uiAttr...
  type uiFontDescriptor (line 915) | typedef struct uiFontDescriptor uiFontDescriptor;
  type uiFontDescriptor (line 917) | struct uiFontDescriptor {
  type uiDrawTextLayout (line 937) | typedef struct uiDrawTextLayout uiDrawTextLayout;
  type uiDrawTextLayoutParams (line 952) | typedef struct uiDrawTextLayoutParams uiDrawTextLayoutParams;
  type uiDrawTextLayoutParams (line 955) | struct uiDrawTextLayoutParams {
  type uiFontButton (line 997) | typedef struct uiFontButton uiFontButton;
  type uiAreaMouseEvent (line 1022) | struct uiAreaMouseEvent {
  type uiAreaKeyEvent (line 1083) | struct uiAreaKeyEvent {
  type uiColorButton (line 1093) | typedef struct uiColorButton uiColorButton;
  type uiForm (line 1100) | typedef struct uiForm uiForm;
  type uiGrid (line 1122) | typedef struct uiGrid uiGrid;
  type uiImage (line 1150) | typedef struct uiImage uiImage;
  type uiTableValue (line 1183) | typedef struct uiTableValue uiTableValue;
  type uiTableModel (line 1274) | typedef struct uiTableModel uiTableModel;
  type uiTableModelHandler (line 1279) | typedef struct uiTableModelHandler uiTableModelHandler;
  type uiTableModelHandler (line 1282) | struct uiTableModelHandler {
  type uiTableTextColumnOptionalParams (line 1359) | typedef struct uiTableTextColumnOptionalParams uiTableTextColumnOptional...
  type uiTableParams (line 1362) | typedef struct uiTableParams uiTableParams;
  type uiTableTextColumnOptionalParams (line 1364) | struct uiTableTextColumnOptionalParams {
  type uiTableParams (line 1374) | struct uiTableParams {
  type uiTable (line 1390) | typedef struct uiTable uiTable;

FILE: util.go
  function pkguiAlloc (line 13) | func pkguiAlloc(n C.size_t) unsafe.Pointer {
  function freestr (line 21) | func freestr(str *C.char) {
  function tobool (line 25) | func tobool(b C.int) bool {
  function frombool (line 29) | func frombool(b bool) C.int {

FILE: window.go
  type Window (line 16) | type Window struct
    method Destroy (line 39) | func (w *Window) Destroy() {
    method Title (line 50) | func (w *Window) Title() string {
    method SetTitle (line 58) | func (w *Window) SetTitle(title string) {
    method OnClosing (line 75) | func (w *Window) OnClosing(f func(*Window) bool) {
    method Borderless (line 92) | func (w *Window) Borderless() bool {
    method SetBorderless (line 97) | func (w *Window) SetBorderless(borderless bool) {
    method SetChild (line 103) | func (w *Window) SetChild(child Control) {
    method Margined (line 113) | func (w *Window) Margined() bool {
    method SetMargined (line 120) | func (w *Window) SetMargined(margined bool) {
  function NewWindow (line 24) | func NewWindow(title string, width int, height int, hasMenubar bool) *Wi...
  function pkguiDoWindowOnClosing (line 80) | func pkguiDoWindowOnClosing(ww *C.uiWindow, data unsafe.Pointer) C.int {
Condensed preview — 59 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (237K chars).
[
  {
    "path": "LICENSE",
    "chars": 1155,
    "preview": "Copyright (c) 2014 Pietro Gagliardi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of thi"
  },
  {
    "path": "README.md",
    "chars": 3337,
    "preview": "# ui: platform-native GUI library for Go\n\nThis is a library that aims to provide simple GUI software development in Go. "
  },
  {
    "path": "TODO.md",
    "chars": 177,
    "preview": "- document that Destroy cannot be called on Controls that have a parent\n- identify earliest tag for https://github.com/g"
  },
  {
    "path": "area.go",
    "chars": 3896,
    "preview": "// 16 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Area is a Control that repre"
  },
  {
    "path": "areahandler.go",
    "chars": 9337,
    "preview": "// 13 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// no need to lock this; only t"
  },
  {
    "path": "box.go",
    "chars": 2198,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Box is a Control that holds "
  },
  {
    "path": "button.go",
    "chars": 1353,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Button is a Control that rep"
  },
  {
    "path": "checkbox.go",
    "chars": 1707,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Checkbox is a Control that r"
  },
  {
    "path": "colorbutton.go",
    "chars": 1634,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// ColorButton is a Control tha"
  },
  {
    "path": "combobox.go",
    "chars": 1591,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Combobox is a Control that r"
  },
  {
    "path": "control.go",
    "chars": 3495,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// no need to lock this; only t"
  },
  {
    "path": "datetimepicker.go",
    "chars": 2446,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"time\"\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// DateTimePicker is a "
  },
  {
    "path": "draw.go",
    "chars": 11697,
    "preview": "// 13 december 2015\n\npackage ui\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// DrawPath represents a geometric path in a drawing "
  },
  {
    "path": "drawtext.go",
    "chars": 17190,
    "preview": "// 12 august 2018\n\npackage ui\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Attribute stores information about an attribute in a"
  },
  {
    "path": "dummy_windows.cpp",
    "chars": 115,
    "preview": "// 5 june 2016\n// This file is only present to force cgo to use the C++ linker instead of the C linker on Windows.\n"
  },
  {
    "path": "editablecombobox.go",
    "chars": 1876,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// EditableCombobox is a Contro"
  },
  {
    "path": "entry.go",
    "chars": 2115,
    "preview": "// 12 december 2015\n\n// TODO typing in entry in OS X crashes libui\n// I've had similar issues with checkboxes on libui\n/"
  },
  {
    "path": "examples/controlgallery.go",
    "chars": 5129,
    "preview": "// 12 august 2018\n\n// +build OMIT\n\npackage main\n\nimport (\n\t\"github.com/andlabs/ui\"\n\t_ \"github.com/andlabs/ui/winmanifest"
  },
  {
    "path": "examples/drawtext.go",
    "chars": 4431,
    "preview": "// 19 august 2018\n\n// +build OMIT\n\npackage main\n\n// TODO probably a bug in libui: changing the font away from skia leads"
  },
  {
    "path": "examples/histogram.go",
    "chars": 5948,
    "preview": "// 12 august 2018\n\n// +build OMIT\n\npackage main\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n\n\t\"github.com/andlabs/ui\"\n\t_ \"github.com/"
  },
  {
    "path": "examples/table.go",
    "chars": 22694,
    "preview": "// 26 august 2018\n\n// +build OMIT\n\n// TODO possible bugs in libui:\n// - the checkboxes on macOS retain their values when"
  },
  {
    "path": "examples/updateui.go",
    "chars": 2450,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/andlabs/ui\"\n)\n\n// Example showing how to update the UI using the Que"
  },
  {
    "path": "fontbutton.go",
    "chars": 1277,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// FontButton is a Control that"
  },
  {
    "path": "form.go",
    "chars": 1841,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Form is a Control that holds"
  },
  {
    "path": "grid.go",
    "chars": 2871,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Grid is a Control that arran"
  },
  {
    "path": "group.go",
    "chars": 1813,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Group is a Control that hold"
  },
  {
    "path": "image.go",
    "chars": 1715,
    "preview": "// 21 august 2018\n\npackage ui\n\nimport (\n\t\"image\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Image stores an image for displ"
  },
  {
    "path": "label.go",
    "chars": 796,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Label is a Control that repr"
  },
  {
    "path": "link_darwin_amd64.go",
    "chars": 200,
    "preview": "// 13 december 2015\n\npackage ui\n\n// #cgo CFLAGS: -mmacosx-version-min=10.8\n// #cgo LDFLAGS: ${SRCDIR}/libui_darwin_amd64"
  },
  {
    "path": "link_linux_386.go",
    "chars": 165,
    "preview": "// +build !windows\n// +build !darwin\n\n// 11 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_linux_386.a -lm "
  },
  {
    "path": "link_linux_amd64.go",
    "chars": 167,
    "preview": "// +build !windows\n// +build !darwin\n\n// 11 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_linux_amd64.a -l"
  },
  {
    "path": "link_windows_386.go",
    "chars": 286,
    "preview": "// 13 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_windows_386.a\n// #cgo LDFLAGS: -luser32 -lkernel32 -lg"
  },
  {
    "path": "link_windows_amd64.go",
    "chars": 288,
    "preview": "// 13 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_windows_amd64.a\n// #cgo LDFLAGS: -luser32 -lkernel32 -"
  },
  {
    "path": "main.go",
    "chars": 3528,
    "preview": "// 11 december 2015\n\npackage ui\n\nimport (\n\t\"runtime\"\n\t\"errors\"\n\t\"sync\"\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n//"
  },
  {
    "path": "multilineentry.go",
    "chars": 2534,
    "preview": "// 12 december 2015\n\n// TODO typing in entry in OS X crashes libui\n// I've had similar issues with checkboxes on libui\n/"
  },
  {
    "path": "pkgui.c",
    "chars": 5404,
    "preview": "// 26 august 2018\n#include \"pkgui.h\"\n#include \"_cgo_export.h\"\n\nuiInitOptions *pkguiAllocInitOptions(void)\n{\n\treturn (uiI"
  },
  {
    "path": "pkgui.h",
    "chars": 3190,
    "preview": "// 12 august 2018\n#ifndef pkguiHFileIncluded\n#define pkguiHFileIncluded\n\n#include <stdlib.h>\n#include <string.h>\n#includ"
  },
  {
    "path": "progressbar.go",
    "chars": 890,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// ProgressBar is a Control tha"
  },
  {
    "path": "radiobuttons.go",
    "chars": 1596,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// RadioButtons is a Control th"
  },
  {
    "path": "separator.go",
    "chars": 719,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Separator is a Control that "
  },
  {
    "path": "slider.go",
    "chars": 1265,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Slider is a Control that rep"
  },
  {
    "path": "spinbox.go",
    "chars": 1290,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Spinbox is a Control that re"
  },
  {
    "path": "stddialogs.go",
    "chars": 830,
    "preview": "// 20 december 2015\n\npackage ui\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// TODO\nfunc MsgBoxError(w *Window, title string, des"
  },
  {
    "path": "tab.go",
    "chars": 2164,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Tab is a Control that holds "
  },
  {
    "path": "table.go",
    "chars": 5887,
    "preview": "// 26 august 2018\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// TableModelColumnNeverEditable "
  },
  {
    "path": "tablemodel.go",
    "chars": 7279,
    "preview": "// 24 august 2018\n\npackage ui\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// TableValue is a type that represents a piece of data"
  },
  {
    "path": "ui.h",
    "chars": 63380,
    "preview": "// 6 april 2015\n\n// TODO add a uiVerifyControlType() function that can be used by control implementations to verify cont"
  },
  {
    "path": "util.go",
    "chars": 493,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n//export pkguiAlloc\nfunc pkguiA"
  },
  {
    "path": "window.go",
    "chars": 3191,
    "preview": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Window is a Control that rep"
  },
  {
    "path": "winmanifest/doc.go",
    "chars": 483,
    "preview": "// 2 september 2018\n\n// Package winmanifest provides a basic manifest for use with\n// package ui. You import it for its "
  },
  {
    "path": "winmanifest/resources.rc",
    "chars": 339,
    "preview": "// 30 may 2015\n\n// this is a UTF-8 file\n#pragma code_page(65001)\n\n// this is the Common Controls 6 manifest\n// TODO set "
  },
  {
    "path": "winmanifest/ui.manifest",
    "chars": 1775,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersi"
  }
]

// ... and 7 more files (download for full content)

About this extraction

This page contains the full source code of the andlabs/ui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 59 files (42.5 MB), approximately 69.4k tokens, and a symbol index with 600 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!