[
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014 Pietro Gagliardi\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n\n(this is called the MIT License or Expat License; see http://www.opensource.org/licenses/MIT)\n"
  },
  {
    "path": "README.md",
    "content": "# ui: platform-native GUI library for Go\n\nThis 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.\n\nIt runs on/requires:\n\n- Windows: cgo, Windows Vista SP2 with Platform Update and newer\n- Mac OS X: cgo, Mac OS X 10.8 and newer\n- other Unixes: cgo, GTK+ 3.10 and newer\n\t- Debian, Ubuntu, etc.: `sudo apt-get install libgtk-3-dev`\n\t- Red Hat/Fedora, etc.: `sudo dnf install gtk3-devel`\n\nIt also requires Go 1.8 or newer.\n\nIt currently aligns to libui's Alpha 4.1, with only a small handful of functions not available.\n\n# Status\n\nPackage 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.\n\n# Installation\n\nOnce you have the dependencies installed, a simple\n\n```\ngo get github.com/andlabs/ui/...\n```\n\nshould suffice.\n\n# Documentation\n\nThe in-code documentation is sufficient to get started, but needs improvement.\n\nSome simple example programs are in the `examples` directory. You can `go build` each of them individually.\n\n## Windows manifests\n\nPackage 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.\n\nThe simplest option is provided as a subpackage `winmanifest`; you can simply import it without a name, and it'll set things up properly:\n\n```go\nimport _ \"github.com/andlabs/ui/winmanifest\"\n```\n\nYou do not have to worry about importing this in non-Windows-only files; it does nothing on non-Windows platforms.\n\nIf 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:\n\n```\nwindres -i resources.rc -o winmanifest_windows_GOARCH.syso -O coff\n```\n\nYou 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.\n\nNote 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.\n\n## macOS program execution\n\nIf 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.\n"
  },
  {
    "path": "TODO.md",
    "content": "- document that Destroy cannot be called on Controls that have a parent\n- identify earliest tag for https://github.com/golang/go/commit/dba926d7a37bd6b3d740c132e8d6346214b6355c\n"
  },
  {
    "path": "area.go",
    "content": "// 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 represents a blank canvas that a program\n// can draw on as it wishes. Areas also receive keyboard and mouse\n// events, and programs can react to those as they see fit. Drawing\n// and event handling are handled through an instance of a type\n// that implements AreaHandler that every Area has; see AreaHandler\n// for details.\n// \n// There are two types of areas. Non-scrolling areas are rectangular\n// and have no scrollbars. Programs can draw on and get mouse\n// events from any point in the Area, and the size of the Area is\n// decided by package ui itself, according to the layout of controls\n// in the Window the Area is located in and the size of said Window.\n// There is no way to query the Area's size or be notified when its\n// size changes; instead, you are given the area size as part of the\n// draw and mouse event handlers, for use solely within those\n// handlers.\n// \n// Scrolling areas have horziontal and vertical scrollbars. The amount\n// that can be scrolled is determined by the area's size, which is\n// decided by the programmer (both when creating the Area and by\n// a call to SetSize). Only a portion of the Area is visible at any time;\n// drawing and mouse events are automatically adjusted to match\n// what portion is visible, so you do not have to worry about scrolling\n// in your event handlers. AreaHandler has more information.\n// \n// The internal coordinate system of an Area is points, which are\n// floating-point and device-independent. For more details, see\n// AreaHandler. The size of a scrolling Area must be an exact integer\n// number of points (that is, you cannot have an Area that is 32.5\n// points tall) and thus the parameters to NewScrollingArea and\n// SetSize are ints. All other instances of points in parameters and\n// structures (including sizes of drawn objects) are float64s.\ntype Area struct {\n\tControlBase\n\ta\t*C.uiArea\n\tah\t*C.uiAreaHandler\n\tscrolling\tbool\n}\n\n// NewArea creates a new non-scrolling Area.\nfunc NewArea(handler AreaHandler) *Area {\n\ta := new(Area)\n\ta.scrolling = false\n\ta.ah = registerAreaHandler(handler)\n\n\ta.a = C.uiNewArea(a.ah)\n\n\ta.ControlBase = NewControlBase(a, uintptr(unsafe.Pointer(a.a)))\n\treturn a\n}\n\n// NewScrollingArea creates a new scrolling Area of the given size,\n// in points.\nfunc NewScrollingArea(handler AreaHandler, width int, height int) *Area {\n\ta := new(Area)\n\ta.scrolling = true\n\ta.ah = registerAreaHandler(handler)\n\n\ta.a = C.uiNewScrollingArea(a.ah, C.int(width), C.int(height))\n\n\ta.ControlBase = NewControlBase(a, uintptr(unsafe.Pointer(a.a)))\n\treturn a\n}\n\n// Destroy destroys the Area.\nfunc (a *Area) Destroy() {\n\tunregisterAreaHandler(a.ah)\n\ta.ControlBase.Destroy()\n}\n\n// SetSize sets the size of a scrolling Area to the given size, in points.\n// SetSize panics if called on a non-scrolling Area.\nfunc (a *Area) SetSize(width int, height int) {\n\tif !a.scrolling {\n\t\tpanic(\"attempt to call SetSize on non-scrolling Area\")\n\t}\n\tC.uiAreaSetSize(a.a, C.int(width), C.int(height))\n}\n\n// QueueRedrawAll queues the entire Area for redraw.\n// The Area is not redrawn before this function returns; it is\n// redrawn when next possible.\nfunc (a *Area) QueueRedrawAll() {\n\tC.uiAreaQueueRedrawAll(a.a)\n}\n\n// ScrollTo scrolls the Area to show the given rectangle; what this\n// means is implementation-defined, but you can safely assume\n// that as much of the given rectangle as possible will be visible\n// after this call. (TODO verify this on OS X) ScrollTo panics if called\n// on a non-scrolling Area.\nfunc (a *Area) ScrollTo(x float64, y float64, width float64, height float64) {\n\tif !a.scrolling {\n\t\tpanic(\"attempt to call ScrollTo on non-scrolling Area\")\n\t}\n\tC.uiAreaScrollTo(a.a, C.double(x), C.double(y), C.double(width), C.double(height))\n}\n\n// TODO BeginUserWindowMove\n// TODO BeginUserWindowResize\n"
  },
  {
    "path": "areahandler.go",
    "content": "// 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 the GUI thread can access it\nvar areahandlers = make(map[*C.uiAreaHandler]AreaHandler)\n\n// AreaHandler defines the functionality needed for handling events\n// from an Area. Each of the methods on AreaHandler is called from\n// the GUI thread, and every parameter (other than the Area itself)\n// should be assumed to only be valid during the life of the method\n// call (so for instance, do not save AreaDrawParams.AreaWidth, as\n// that might change without generating an event).\n// \n// Coordinates to Draw and MouseEvent are given in points. Points\n// are generic, floating-point, device-independent coordinates with\n// (0,0) at the top left corner. You never have to worry about the\n// mapping between points and pixels; simply draw everything using\n// points and you get nice effects like looking sharp on high-DPI\n// monitors for free. Proper documentation on the matter is being\n// written. In the meantime, there are several referenes to this kind of\n// 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\n// \n// For a scrolling Area, points are automatically offset by the scroll\n// position. So if the mouse moves to position (5,5) while the\n// horizontal scrollbar is at position 10 and the horizontal scrollbar is\n// at position 20, the coordinate stored in the AreaMouseEvent\n// structure is (15,25). The same applies to drawing.\ntype AreaHandler interface {\n\t// Draw is sent when a part of the Area needs to be drawn.\n\t// dp will contain a drawing context to draw on, the rectangle\n\t// that needs to be drawn in, and (for a non-scrolling area) the\n\t// size of the area. The rectangle that needs to be drawn will\n\t// have been cleared by the system prior to drawing, so you are\n\t// always working on a clean slate.\n\t// \n\t// If you call Save on the drawing context, you must call Release\n\t// before returning from Draw, and the number of calls to Save\n\t// and Release must match. Failure to do so results in undefined\n\t// behavior.\n\tDraw(a *Area, dp *AreaDrawParams)\n\n\t// MouseEvent is called when the mouse moves over the Area\n\t// or when a mouse button is pressed or released. See\n\t// AreaMouseEvent for more details.\n\t// \n\t// If a mouse button is being held, MouseEvents will continue to\n\t// be generated, even if the mouse is not within the area. On\n\t// some systems, the system can interrupt this behavior;\n\t// see DragBroken.\n\tMouseEvent(a *Area, me *AreaMouseEvent)\n\n\t// MouseCrossed is called when the mouse either enters or\n\t// leaves the Area. It is called even if the mouse buttons are being\n\t// held (see MouseEvent above). If the mouse has entered the\n\t// Area, left is false; if it has left the Area, left is true.\n\t// \n\t// If, when the Area is first shown, the mouse is already inside\n\t// the Area, MouseCrossed will be called with left=false.\n\t// TODO what about future shows?\n\tMouseCrossed(a *Area, left bool)\n\n\t// DragBroken is called if a mouse drag is interrupted by the\n\t// system. As noted above, when a mouse button is held,\n\t// MouseEvent will continue to be called, even if the mouse is\n\t// outside the Area. On some systems, this behavior can be\n\t// stopped by the system itself for a variety of reasons. This\n\t// method is provided to allow your program to cope with the\n\t// loss of the mouse in this case. You should cope by cancelling\n\t// whatever drag-related operation you were doing.\n\t// \n\t// Note that this is only generated on some systems under\n\t// specific conditions. Do not implement behavior that only\n\t// takes effect when DragBroken is called.\n\tDragBroken(a *Area)\n\n\t// KeyEvent is called when a key is pressed while the Area has\n\t// keyboard focus (if the Area has been tabbed into or if the\n\t// mouse has been clicked on it). See AreaKeyEvent for specifics.\n\t// \n\t// Because some keyboard events are handled by the system\n\t// (for instance, menu accelerators and global hotkeys), you\n\t// must return whether you handled the key event; return true\n\t// if you did or false if you did not. If you wish to ignore the\n\t// keyboard outright, the correct implementation of KeyEvent is\n\t// \tfunc (h *MyHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {\n\t// \t\treturn false\n\t// \t}\n\t// DO NOT RETURN TRUE UNCONDITIONALLY FROM THIS\n\t// METHOD. BAD THINGS WILL HAPPEN IF YOU DO.\n\tKeyEvent(a *Area, ke *AreaKeyEvent) (handled bool)\n}\n\nfunc registerAreaHandler(ah AreaHandler) *C.uiAreaHandler {\n\tuah := C.pkguiAllocAreaHandler()\n\tareahandlers[uah] = ah\n\treturn uah\n}\n\nfunc unregisterAreaHandler(uah *C.uiAreaHandler) {\n\tdelete(areahandlers, uah)\n\tC.pkguiFreeAreaHandler(uah)\n}\n\n// AreaDrawParams provides a drawing context that can be used\n// to draw on an Area and tells you where to draw. See AreaHandler\n// for introductory information.\ntype AreaDrawParams struct {\n\t// Context is the drawing context to draw on. See DrawContext\n\t// for how to draw.\n\tContext\t\t*DrawContext\n\n\t// AreaWidth and AreaHeight provide the size of the Area for\n\t// non-scrolling Areas. For scrolling Areas both values are zero.\n\t// \n\t// To reiterate the AreaHandler documentation, do NOT save\n\t// these values for later; they can change without generating\n\t// an event.\n\tAreaWidth\tfloat64\n\tAreaHeight\tfloat64\n\n\t// These four fields define the rectangle that needs to be\n\t// redrawn. The system will not draw anything outside this\n\t// rectangle, but you can make your drawing faster if you\n\t// also stay within the lines.\n\tClipX\t\tfloat64\n\tClipY\t\tfloat64\n\tClipWidth\t\tfloat64\n\tClipHeight\tfloat64\n}\n\n//export pkguiDoAreaHandlerDraw\nfunc pkguiDoAreaHandlerDraw(uah *C.uiAreaHandler, ua *C.uiArea, udp *C.uiAreaDrawParams) {\n\tah := areahandlers[uah]\n\ta := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)\n\tdp := &AreaDrawParams{\n\t\tContext:\t\t&DrawContext{udp.Context},\n\t\tAreaWidth:\tfloat64(udp.AreaWidth),\n\t\tAreaHeight:\tfloat64(udp.AreaHeight),\n\t\tClipX:\t\tfloat64(udp.ClipX),\n\t\tClipY:\t\tfloat64(udp.ClipY),\n\t\tClipWidth:\t\tfloat64(udp.ClipWidth),\n\t\tClipHeight:\tfloat64(udp.ClipHeight),\n\t}\n\tah.Draw(a, dp)\n}\n\n// TODO document all these\n// \n// 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\ntype AreaMouseEvent struct {\n\tX\t\t\tfloat64\n\tY\t\t\tfloat64\n\n\t// AreaWidth and AreaHeight provide the size of the Area for\n\t// non-scrolling Areas. For scrolling Areas both values are zero.\n\t// \n\t// To reiterate the AreaHandler documentation, do NOT save\n\t// these values for later; they can change without generating\n\t// an event.\n\tAreaWidth\tfloat64\n\tAreaHeight\tfloat64\n\n\tDown\t\tuint\n\tUp\t\t\tuint\n\tCount\t\tuint\n\tModifiers\t\tModifiers\n\tHeld\t\t\t[]uint\n}\n\nfunc appendBits(out []uint, held C.uint64_t) []uint {\n\tn := uint(1)\n\tfor i := 0; i < 64; i++ {\n\t\tif held & 1 != 0 {\n\t\t\tout = append(out, n)\n\t\t}\n\t\theld >>= 1\n\t\tn++\n\t}\n\treturn out\n}\n\n//export pkguiDoAreaHandlerMouseEvent\nfunc pkguiDoAreaHandlerMouseEvent(uah *C.uiAreaHandler, ua *C.uiArea, ume *C.uiAreaMouseEvent) {\n\tah := areahandlers[uah]\n\ta := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)\n\tme := &AreaMouseEvent{\n\t\tX:\t\t\tfloat64(ume.X),\n\t\tY:\t\t\tfloat64(ume.Y),\n\t\tAreaWidth:\tfloat64(ume.AreaWidth),\n\t\tAreaHeight:\tfloat64(ume.AreaHeight),\n\t\tDown:\t\tuint(ume.Down),\n\t\tUp:\t\t\tuint(ume.Up),\n\t\tCount:\t\tuint(ume.Count),\n\t\tModifiers:\t\tModifiers(ume.Modifiers),\n\t\tHeld:\t\tmake([]uint, 0, 64),\n\t}\n\tme.Held = appendBits(me.Held, ume.Held1To64)\n\tah.MouseEvent(a, me)\n}\n\n//export pkguiDoAreaHandlerMouseCrossed\nfunc pkguiDoAreaHandlerMouseCrossed(uah *C.uiAreaHandler, ua *C.uiArea, left C.int) {\n\tah := areahandlers[uah]\n\ta := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)\n\tah.MouseCrossed(a, tobool(left))\n}\n\n//export pkguiDoAreaHandlerDragBroken\nfunc pkguiDoAreaHandlerDragBroken(uah *C.uiAreaHandler, ua *C.uiArea) {\n\tah := areahandlers[uah]\n\ta := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)\n\tah.DragBroken(a)\n}\n\n// TODO document all these\ntype AreaKeyEvent struct {\n\tKey\t\trune\n\tExtKey\tExtKey\n\tModifier\tModifiers\n\tModifiers\tModifiers\n\tUp\t\tbool\n}\n\n//export pkguiDoAreaHandlerKeyEvent\nfunc pkguiDoAreaHandlerKeyEvent(uah *C.uiAreaHandler, ua *C.uiArea, uke *C.uiAreaKeyEvent) C.int {\n\tah := areahandlers[uah]\n\ta := ControlFromLibui(uintptr(unsafe.Pointer(ua))).(*Area)\n\tke := &AreaKeyEvent{\n\t\tKey:\t\t\trune(uke.Key),\n\t\tExtKey:\t\tExtKey(uke.ExtKey),\n\t\tModifier:\t\tModifiers(uke.Modifier),\n\t\tModifiers:\t\tModifiers(uke.Modifiers),\n\t\tUp:\t\t\ttobool(uke.Up),\n\t}\n\treturn frombool(ah.KeyEvent(a, ke))\n}\n\n// TODO document\n// \n// Note: these must be numerically identical to their libui equivalents.\ntype Modifiers uint\nconst (\n\tCtrl Modifiers = 1 << iota\n\tAlt\n\tShift\n\tSuper\n)\n\n// TODO document\n// \n// Note: these must be numerically identical to their libui equivalents.\ntype ExtKey int\nconst (\n\tEscape ExtKey = iota + 1\n\tInsert\t\t\t// equivalent to \"Help\" on Apple keyboards\n\tDelete\n\tHome\n\tEnd\n\tPageUp\n\tPageDown\n\tUp\n\tDown\n\tLeft\n\tRight\n\tF1\t\t\t// F1..F12 are guaranteed to be consecutive\n\tF2\n\tF3\n\tF4\n\tF5\n\tF6\n\tF7\n\tF8\n\tF9\n\tF10\n\tF11\n\tF12\n\tN0\t\t\t// numpad keys; independent of Num Lock state\n\tN1\t\t\t// N0..N9 are guaranteed to be consecutive\n\tN2\n\tN3\n\tN4\n\tN5\n\tN6\n\tN7\n\tN8\n\tN9\n\tNDot\n\tNEnter\n\tNAdd\n\tNSubtract\n\tNMultiply\n\tNDivide\n)\n"
  },
  {
    "path": "box.go",
    "content": "// 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 a group of Controls horizontally\n// or vertically. If horizontally, then all controls have the same\n// height. If vertically, then all controls have the same width.\n// By default, each control has its preferred width (horizontal)\n// or height (vertical); if a control is marked \"stretchy\", it will\n// take whatever space is left over. If multiple controls are marked\n// stretchy, they will be given equal shares of the leftover space.\n// There can also be space between each control (\"padding\").\ntype Box struct {\n\tControlBase\n\tb\t*C.uiBox\n\tchildren\t[]Control\n}\n\n// NewHorizontalBox creates a new horizontal Box.\nfunc NewHorizontalBox() *Box {\n\tb := new(Box)\n\n\tb.b = C.uiNewHorizontalBox()\n\n\tb.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))\n\treturn b\n}\n\n// NewVerticalBox creates a new vertical Box.\nfunc NewVerticalBox() *Box {\n\tb := new(Box)\n\n\tb.b = C.uiNewVerticalBox()\n\n\tb.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))\n\treturn b\n}\n\n// Destroy destroys the Box. If the Box has children,\n// Destroy calls Destroy on those Controls as well.\nfunc (b *Box) Destroy() {\n\tfor len(b.children) != 0 {\n\t\tc := b.children[0]\n\t\tb.Delete(0)\n\t\tc.Destroy()\n\t}\n\tb.ControlBase.Destroy()\n}\n\n// Append adds the given control to the end of the Box.\nfunc (b *Box) Append(child Control, stretchy bool) {\n\tc := (*C.uiControl)(nil)\n\t// TODO this part is wrong for Box?\n\tif child != nil {\n\t\tc = touiControl(child.LibuiControl())\n\t}\n\tC.uiBoxAppend(b.b, c, frombool(stretchy))\n\tb.children = append(b.children, child)\n}\n\n// Delete deletes the nth control of the Box.\nfunc (b *Box) Delete(n int) {\n\tb.children = append(b.children[:n], b.children[n + 1:]...)\n\tC.uiBoxDelete(b.b, C.int(n))\n}\n\n// Padded returns whether there is space between each control\n// of the Box.\nfunc (b *Box) Padded() bool {\n\treturn tobool(C.uiBoxPadded(b.b))\n}\n\n// SetPadded controls whether there is space between each control\n// of the Box. The size of the padding is determined by the OS and\n// its best practices.\nfunc (b *Box) SetPadded(padded bool) {\n\tC.uiBoxSetPadded(b.b, frombool(padded))\n}\n"
  },
  {
    "path": "button.go",
    "content": "// 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 represents a button that the user can\n// click to perform an action. A Button has a text label that should\n// describe what the button does.\ntype Button struct {\n\tControlBase\n\tb\t*C.uiButton\n\tonClicked\t\tfunc(*Button)\n}\n\n// NewButton creates a new Button with the given text as its label.\nfunc NewButton(text string) *Button {\n\tb := new(Button)\n\n\tctext := C.CString(text)\n\tb.b = C.uiNewButton(ctext)\n\tfreestr(ctext)\n\n\tC.pkguiButtonOnClicked(b.b)\n\n\tb.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))\n\treturn b\n}\n\n// Text returns the Button's text.\nfunc (b *Button) Text() string {\n\tctext := C.uiButtonText(b.b)\n\ttext := C.GoString(ctext)\n\tC.uiFreeText(ctext)\n\treturn text\n}\n\n// SetText sets the Button's text to text.\nfunc (b *Button) SetText(text string) {\n\tctext := C.CString(text)\n\tC.uiButtonSetText(b.b, ctext)\n\tfreestr(ctext)\n}\n\n// OnClicked registers f to be run when the user clicks the Button.\n// Only one function can be registered at a time.\nfunc (b *Button) OnClicked(f func(*Button)) {\n\tb.onClicked = f\n}\n\n//export pkguiDoButtonOnClicked\nfunc pkguiDoButtonOnClicked(bb *C.uiButton, data unsafe.Pointer) {\n\tb := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*Button)\n\tif b.onClicked != nil {\n\t\tb.onClicked(b)\n\t}\n}\n"
  },
  {
    "path": "checkbox.go",
    "content": "// 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 represents a box with a text label at its\n// side. When the user clicks the checkbox, a check mark will appear\n// in the box; clicking it again removes the check.\ntype Checkbox struct {\n\tControlBase\n\tc\t*C.uiCheckbox\n\tonToggled\t\tfunc(*Checkbox)\n}\n\n// NewCheckbox creates a new Checkbox with the given text as its\n// label.\nfunc NewCheckbox(text string) *Checkbox {\n\tc := new(Checkbox)\n\n\tctext := C.CString(text)\n\tc.c = C.uiNewCheckbox(ctext)\n\tfreestr(ctext)\n\n\tC.pkguiCheckboxOnToggled(c.c)\n\n\tc.ControlBase = NewControlBase(c, uintptr(unsafe.Pointer(c.c)))\n\treturn c\n}\n\n// Text returns the Checkbox's text.\nfunc (c *Checkbox) Text() string {\n\tctext := C.uiCheckboxText(c.c)\n\ttext := C.GoString(ctext)\n\tC.uiFreeText(ctext)\n\treturn text\n}\n\n// SetText sets the Checkbox's text to text.\nfunc (c *Checkbox) SetText(text string) {\n\tctext := C.CString(text)\n\tC.uiCheckboxSetText(c.c, ctext)\n\tfreestr(ctext)\n}\n\n// OnToggled registers f to be run when the user clicks the Checkbox.\n// Only one function can be registered at a time.\nfunc (c *Checkbox) OnToggled(f func(*Checkbox)) {\n\tc.onToggled = f\n}\n\n//export pkguiDoCheckboxOnToggled\nfunc pkguiDoCheckboxOnToggled(cc *C.uiCheckbox, data unsafe.Pointer) {\n\tc := ControlFromLibui(uintptr(unsafe.Pointer(cc))).(*Checkbox)\n\tif c.onToggled != nil {\n\t\tc.onToggled(c)\n\t}\n}\n\n// Checked returns whether the Checkbox is checked.\nfunc (c *Checkbox) Checked() bool {\n\treturn tobool(C.uiCheckboxChecked(c.c))\n}\n\n// SetChecked sets whether the Checkbox is checked.\nfunc (c *Checkbox) SetChecked(checked bool) {\n\tC.uiCheckboxSetChecked(c.c, frombool(checked))\n}\n"
  },
  {
    "path": "colorbutton.go",
    "content": "// 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 that represents a button that the user can\n// click to select a color.\ntype ColorButton struct {\n\tControlBase\n\tb\t*C.uiColorButton\n\tonChanged\t\tfunc(*ColorButton)\n}\n\n// NewColorButton creates a new ColorButton.\nfunc NewColorButton() *ColorButton {\n\tb := new(ColorButton)\n\n\tb.b = C.uiNewColorButton()\n\n\tC.pkguiColorButtonOnChanged(b.b)\n\n\tb.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))\n\treturn b\n}\n\n// Color returns the color currently selected in the ColorButton.\n// Colors are not alpha-premultiplied.\n// TODO rename b or bl\nfunc (b *ColorButton) Color() (r, g, bl, a float64) {\n\tc := C.pkguiAllocColorDoubles()\n\tdefer C.pkguiFreeColorDoubles(c)\n\tC.uiColorButtonColor(b.b, c.r, c.g, c.b, c.a)\n\treturn float64(*(c.r)), float64(*(c.g)), float64(*(c.b)), float64(*(c.a))\n}\n\n// SetColor sets the currently selected color in the ColorButton.\n// Colors are not alpha-premultiplied.\n// TODO rename b or bl\nfunc (b *ColorButton) SetColor(r, g, bl, a float64) {\n\tC.uiColorButtonSetColor(b.b, C.double(r), C.double(g), C.double(bl), C.double(a))\n}\n\n// OnChanged registers f to be run when the user changes the\n// currently selected color in the ColorButton. Only one function\n// can be registered at a time.\nfunc (b *ColorButton) OnChanged(f func(*ColorButton)) {\n\tb.onChanged = f\n}\n\n//export pkguiDoColorButtonOnChanged\nfunc pkguiDoColorButtonOnChanged(bb *C.uiColorButton, data unsafe.Pointer) {\n\tb := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*ColorButton)\n\tif b.onChanged != nil {\n\t\tb.onChanged(b)\n\t}\n}\n"
  },
  {
    "path": "combobox.go",
    "content": "// 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 represents a drop-down list of strings\n// that the user can choose one of at any time. For a Combobox that\n// users can type values into, see EditableCombobox.\ntype Combobox struct {\n\tControlBase\n\tc\t*C.uiCombobox\n\tonSelected\t\tfunc(*Combobox)\n}\n\n// NewCombobox creates a new Combobox.\nfunc NewCombobox() *Combobox {\n\tc := new(Combobox)\n\n\tc.c = C.uiNewCombobox()\n\n\tC.pkguiComboboxOnSelected(c.c)\n\n\tc.ControlBase = NewControlBase(c, uintptr(unsafe.Pointer(c.c)))\n\treturn c\n}\n\n// Append adds the named item to the end of the Combobox.\nfunc (c *Combobox) Append(text string) {\n\tctext := C.CString(text)\n\tC.uiComboboxAppend(c.c, ctext)\n\tfreestr(ctext)\n}\n\n// Selected returns the index of the currently selected item in the\n// Combobox, or -1 if nothing is selected.\nfunc (c *Combobox) Selected() int {\n\treturn int(C.uiComboboxSelected(c.c))\n}\n\n// SetSelected sets the currently selected item in the Combobox\n// to index. If index is -1 no item will be selected.\nfunc (c *Combobox) SetSelected(index int) {\n\tC.uiComboboxSetSelected(c.c, C.int(index))\n}\n\n// OnSelected registers f to be run when the user selects an item in\n// the Combobox. Only one function can be registered at a time.\nfunc (c *Combobox) OnSelected(f func(*Combobox)) {\n\tc.onSelected = f\n}\n\n//export pkguiDoComboboxOnSelected\nfunc pkguiDoComboboxOnSelected(cc *C.uiCombobox, data unsafe.Pointer) {\n\tc := ControlFromLibui(uintptr(unsafe.Pointer(cc))).(*Combobox)\n\tif c.onSelected != nil {\n\t\tc.onSelected(c)\n\t}\n}\n"
  },
  {
    "path": "control.go",
    "content": "// 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 the GUI thread can access it\nvar controls = make(map[*C.uiControl]Control)\n\n// Control represents a GUI control. It provdes methods\n// common to all Controls.\n// \n// The preferred way to create new Controls is to use\n// ControlBase; see ControlBase below.\ntype Control interface {\n\t// LibuiControl returns the uiControl pointer for the Control.\n\t// This is intended for use when adding a control to a\n\t// container.\n\tLibuiControl() uintptr\n\n\t// Destroy destroys the Control.\n\tDestroy()\n\n\t// Handle returns the OS-level handle that backs the\n\t// Control. On OSs that use reference counting for\n\t// controls, Handle does not increment the reference\n\t// count; you are sharing package ui's reference.\n\tHandle() uintptr\n\n\t// Visible returns whether the Control is visible.\n\tVisible() bool\n\n\t// Show shows the Control.\n\tShow()\n\n\t// Hide shows the Control. Hidden controls do not participate\n\t// in layout (that is, Box, Grid, etc. does not reserve space for\n\t// hidden controls).\n\tHide()\n\n\t// Enabled returns whether the Control is enabled.\n\tEnabled() bool\n\n\t// Enable enables the Control.\n\tEnable()\n\n\t// Disable disables the Control.\n\tDisable()\n}\n\n// ControlBase is an implementation of Control that provides\n// all the methods that Control requires. To use it, embed a\n// ControlBase (not a *ControlBase) into your structure, then\n// assign the result of NewControlBase to that field:\n// \n// \ttype MyControl struct {\n// \t\tui.ControlBase\n// \t\tc *C.MyControl\n// \t}\n// \t\n// \tfunc NewMyControl() *MyControl {\n// \t\tm := &NewMyControl{\n// \t\t\tc: C.newMyControl(),\n// \t\t}\n// \t\tm.ControlBase = ui.NewControlBase(m, uintptr(unsafe.Pointer(c)))\n// \t\treturn m\n// \t}\ntype ControlBase struct {\n\tiface\t\tControl\n\tc\t\t*C.uiControl\n}\n\n// NewControlBase creates a new ControlBase. See the\n// documentation of ControlBase for an example.\n// NewControl should only be called once per instance of Control.\nfunc NewControlBase(iface Control, c uintptr) ControlBase {\n\tb := ControlBase{\n\t\tiface:\tiface,\n\t\tc:\t\t(*C.uiControl)(unsafe.Pointer(c)),\n\t}\n\tcontrols[b.c] = b.iface\n\treturn b\n}\n\nfunc (c *ControlBase) LibuiControl() uintptr {\n\treturn uintptr(unsafe.Pointer(c.c))\n}\n\nfunc (c *ControlBase) Destroy() {\n\tdelete(controls, c.c)\n\tC.uiControlDestroy(c.c)\n}\n\nfunc (c *ControlBase) Handle() uintptr {\n\treturn uintptr(C.uiControlHandle(c.c))\n}\n\nfunc (c *ControlBase) Visible() bool {\n\treturn tobool(C.uiControlVisible(c.c))\n}\n\nfunc (c *ControlBase) Show() {\n\tC.uiControlShow(c.c)\n}\n\nfunc (c *ControlBase) Hide() {\n\tC.uiControlHide(c.c)\n}\n\nfunc (c *ControlBase) Enabled() bool {\n\treturn tobool(C.uiControlEnabled(c.c))\n}\n\nfunc (c *ControlBase) Enable() {\n\tC.uiControlEnable(c.c)\n}\n\nfunc (c *ControlBase) Disable() {\n\tC.uiControlDisable(c.c)\n}\n\n// ControlFromLibui returns the Control associated with a libui\n// uiControl. This is intended for implementing event handlers\n// on the Go side, to prevent sharing Go pointers with C.\n// This function only works on Controls that use ControlBase.\nfunc ControlFromLibui(c uintptr) Control {\n\t// comma-ok form to avoid creating nil entries\n\tcc, _ := controls[(*C.uiControl)(unsafe.Pointer(c))]\n\treturn cc\n}\n\nfunc touiControl(c uintptr) *C.uiControl {\n\treturn (*C.uiControl)(unsafe.Pointer(c))\n}\n\n// LibuiFreeText allows implementations of Control\n// to call the libui function uiFreeText.\nfunc LibuiFreeText(c uintptr) {\n\tC.uiFreeText((*C.char)(unsafe.Pointer(c)))\n}\n"
  },
  {
    "path": "datetimepicker.go",
    "content": "// 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 Control that represents a field where the user\n// can enter a date and/or a time.\ntype DateTimePicker struct {\n\tControlBase\n\td\t*C.uiDateTimePicker\n\tonChanged\tfunc(*DateTimePicker)\n}\n\nfunc finishNewDateTimePicker(dd *C.uiDateTimePicker) *DateTimePicker {\n\td := new(DateTimePicker)\n\n\td.d = dd\n\n\tC.pkguiDateTimePickerOnChanged(d.d)\n\n\td.ControlBase = NewControlBase(d, uintptr(unsafe.Pointer(d.d)))\n\treturn d\n}\n\n// NewDateTimePicker creates a new DateTimePicker that shows\n// both a date and a time.\nfunc NewDateTimePicker() *DateTimePicker {\n\treturn finishNewDateTimePicker(C.uiNewDateTimePicker())\n}\n\n// NewDatePicker creates a new DateTimePicker that shows\n// only a date.\nfunc NewDatePicker() *DateTimePicker {\n\treturn finishNewDateTimePicker(C.uiNewDatePicker())\n}\n\n// NewTimePicker creates a new DateTimePicker that shows\n// only a time.\nfunc NewTimePicker() *DateTimePicker {\n\treturn finishNewDateTimePicker(C.uiNewTimePicker())\n}\n\n// Time returns the time stored in the uiDateTimePicker.\n// The time is assumed to be local time.\nfunc (d *DateTimePicker) Time() time.Time {\n\ttm := C.pkguiAllocTime()\n\tdefer C.pkguiFreeTime(tm)\n\tC.uiDateTimePickerTime(d.d, tm)\n\treturn time.Date(\n\t\tint(tm.tm_year + 1900),\n\t\ttime.Month(tm.tm_mon + 1),\n\t\tint(tm.tm_mday),\n\t\tint(tm.tm_hour),\n\t\tint(tm.tm_min),\n\t\tint(tm.tm_sec),\n\t\t0, time.Local)\n}\n\n// SetTime sets the time in the DateTimePicker to t.\n// t's components are read as-is via t.Date() and t.Clock();\n// no time zone manipulations are done.\nfunc (d *DateTimePicker) SetTime(t time.Time) {\n\ttm := C.pkguiAllocTime()\n\tdefer C.pkguiFreeTime(tm)\n\tyear, mon, mday := t.Date()\n\ttm.tm_year = C.int(year - 1900)\n\ttm.tm_mon = C.int(mon - 1)\n\ttm.tm_mday = C.int(mday)\n\thour, min, sec := t.Clock()\n\ttm.tm_hour = C.int(hour)\n\ttm.tm_min = C.int(min)\n\ttm.tm_sec = C.int(sec)\n\ttm.tm_isdst = -1\n\tC.uiDateTimePickerSetTime(d.d, tm)\n}\n\n// OnChanged registers f to be run when the user changes the time\n// in the DateTimePicker. Only one function can be registered at a\n// time.\nfunc (d *DateTimePicker) OnChanged(f func(*DateTimePicker)) {\n\td.onChanged = f\n}\n\n//export pkguiDoDateTimePickerOnChanged\nfunc pkguiDoDateTimePickerOnChanged(dd *C.uiDateTimePicker, data unsafe.Pointer) {\n\td := ControlFromLibui(uintptr(unsafe.Pointer(dd))).(*DateTimePicker)\n\tif d.onChanged != nil {\n\t\td.onChanged(d)\n\t}\n}\n"
  },
  {
    "path": "draw.go",
    "content": "// 13 december 2015\n\npackage ui\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// DrawPath represents a geometric path in a drawing context.\n// This is the basic unit of drawing: all drawing operations consist of\n// forming a path, then stroking, filling, or clipping to that path.\n// A path is an OS resource; you must explicitly free it when finished.\n// Paths consist of multiple figures. Once you have added all the\n// figures to a path, you must \"end\" the path to make it ready to draw\n// with.\n// TODO rewrite all that\n// \n// Or more visually, the lifecycle of a Path is\n// \tp := DrawNewPath()\n// \tfor every figure {\n// \t\tp.NewFigure(...) // or NewFigureWithArc\n// \t\tp.LineTo(...)    // any number of these in any order\n// \t\tp.ArcTo(...)\n// \t\tp.BezierTo(...)\n// \t\tif figure should be closed {\n// \t\t\tp.CloseFigure()\n// \t\t}\n// \t}\n// \tp.End()\n// \t// ...\n// \tdp.Context.Stroke(p, ...) // any number of these in any order\n// \tdp.Context.Fill(p, ...)\n// \tdp.Context.Clip(p)\n// \t// ...\n// \tp.Free() // when done with the path\n// \n// A DrawPath also defines its fill mode. (This should ideally be a fill\n// parameter, but some implementations prevent it.)\n// TODO talk about fill modes\ntype DrawPath struct {\n\tp\t*C.uiDrawPath\n}\n\n// TODO\n// \n// TODO disclaimer\ntype DrawFillMode uint\nconst (\n\tDrawFillModeWinding DrawFillMode = iota\n\tDrawFillModeAlternate\n)\n\n// DrawNewPath creates a new DrawPath with the given fill mode.\nfunc DrawNewPath(fillMode DrawFillMode) *DrawPath {\n\tvar fm C.uiDrawFillMode\n\n\tswitch fillMode {\n\tcase DrawFillModeWinding:\n\t\tfm = C.uiDrawFillModeWinding\n\tcase DrawFillModeAlternate:\n\t\tfm = C.uiDrawFillModeAlternate\n\tdefault:\n\t\tpanic(\"invalid fill mode passed to ui.NewPath()\")\n\t}\n\treturn &DrawPath{\n\t\tp:\tC.uiDrawNewPath(fm),\n\t}\n}\n\n// Free destroys a DrawPath. After calling Free the DrawPath cannot\n// be used.\nfunc (p *DrawPath) Free() {\n\tC.uiDrawFreePath(p.p)\n}\n\n// NewFigure starts a new figure in the DrawPath. The current point\n// is set to the given point.\nfunc (p *DrawPath) NewFigure(x float64, y float64) {\n\tC.uiDrawPathNewFigure(p.p, C.double(x), C.double(y))\n}\n\n// NewFigureWithArc starts a new figure in the DrawPath and adds\n// an arc as the first element of the figure. Unlike ArcTo,\n// NewFigureWithArc does not draw an initial line segment.\n// Otherwise, see ArcTo.\nfunc (p *DrawPath) NewFigureWithArc(xCenter float64, yCenter float64, radius float64, startAngle float64, sweep float64, isNegative bool) {\n\tC.uiDrawPathNewFigureWithArc(p.p,\n\t\tC.double(xCenter), C.double(yCenter),\n\t\tC.double(radius),\n\t\tC.double(startAngle), C.double(sweep),\n\t\tfrombool(isNegative))\n}\n\n// LineTo adds a line to the current figure of the DrawPath starting\n// from the current point and ending at the given point. The current\n// point is set to the ending point.\nfunc (p *DrawPath) LineTo(x float64, y float64) {\n\tC.uiDrawPathLineTo(p.p, C.double(x), C.double(y))\n}\n\n// ArcTo adds a circular arc to the current figure of the DrawPath.\n// You pass it the center of the arc, its radius in radians, the starting\n// angle (couterclockwise) in radians, and the number of radians the\n// arc should sweep (counterclockwise). A line segment is drawn from\n// the current point to the start of the arc. The current point is set to\n// the end of the arc.\nfunc (p *DrawPath) ArcTo(xCenter float64, yCenter float64, radius float64, startAngle float64, sweep float64, isNegative bool) {\n\tC.uiDrawPathArcTo(p.p,\n\t\tC.double(xCenter), C.double(yCenter),\n\t\tC.double(radius),\n\t\tC.double(startAngle), C.double(sweep),\n\t\tfrombool(isNegative))\n}\n\n// BezierTo adds a cubic Bezier curve to the current figure of the\n// DrawPath. Its start point is the current point. c1x and c1y are the\n// first control point. c2x and c2y are the second control point. endX\n// and endY are the end point. The current point is set to the end\n// point.\nfunc (p *DrawPath) BezierTo(c1x float64, c1y float64, c2x float64, c2y float64, endX float64, endY float64) {\n\tC.uiDrawPathBezierTo(p.p,\n\t\tC.double(c1x), C.double(c1y),\n\t\tC.double(c2x), C.double(c2y),\n\t\tC.double(endX), C.double(endY))\n}\n\n// CloseFigure draws a line segment from the current point of the\n// current figure of the DrawPath back to its initial point. After calling\n// this, the current figure is over and you must either start a new\n// figure or end the DrawPath. If this is not called and you start a\n// new figure or end the DrawPath, then the current figure will not\n// have this closing line segment added to it (but the figure will still\n// be over).\nfunc (p *DrawPath) CloseFigure() {\n\tC.uiDrawPathCloseFigure(p.p)\n}\n\n// AddRectangle creates a new figure in the DrawPath that consists\n// entirely of a rectangle whose top-left corner is at the given point\n// and whose size is the given size. The rectangle is a closed figure;\n// you must either start a new figure or end the Path after calling\n// this method.\nfunc (p *DrawPath) AddRectangle(x float64, y float64, width float64, height float64) {\n\tC.uiDrawPathAddRectangle(p.p, C.double(x), C.double(y), C.double(width), C.double(height))\n}\n\n// End ends the current DrawPath. You cannot add figures to a\n// DrawPath that has been ended. You cannot draw with a\n// DrawPath that has not been ended.\nfunc (p *DrawPath) End() {\n\tC.uiDrawPathEnd(p.p)\n}\n\n// DrawContext represents a drawing surface that you can draw to.\n// At present the only DrawContexts are surfaces associated with\n// Areas and are provided by package ui; see AreaDrawParams.\ntype DrawContext struct {\n\tc\t*C.uiDrawContext\n}\n\n// DrawBrushType defines the various types of brushes.\n// \n// TODO disclaimer\ntype DrawBrushType int\nconst (\n\tDrawBrushTypeSolid DrawBrushType = iota\n\tDrawBrushTypeLinearGradient\n\tDrawBrushTypeRadialGradient\n\tDrawBrushTypeImage\t\t// presently unimplemented\n)\n\n// TODO\n// \n// TODO disclaimer\n// TODO rename these to put LineCap at the beginning? or just Cap?\ntype DrawLineCap int\nconst (\n\tDrawLineCapFlat DrawLineCap = iota\n\tDrawLineCapRound\n\tDrawLineCapSquare\n)\n\n// TODO\n// \n// TODO disclaimer\ntype DrawLineJoin int\nconst (\n\tDrawLineJoinMiter DrawLineJoin = iota\n\tDrawLineJoinRound\n\tDrawLineJoinBevel\n)\n\n// TODO document\nconst DrawDefaultMiterLimit = 10.0\n\n// TODO\ntype DrawBrush struct {\n\tType\t\tDrawBrushType\n\n\t// If Type is Solid.\n\t// TODO\n\tR\t\tfloat64\n\tG\t\tfloat64\n\tB\t\tfloat64\n\tA\t\tfloat64\n\n\t// If Type is LinearGradient or RadialGradient.\n\t// TODO\n\tX0\t\t\tfloat64\t// start point for both\n\tY0\t\t\tfloat64\n\tX1\t\t\tfloat64\t// linear: end point; radial: circle center\n\tY1\t\t\tfloat64\n\tOuterRadius\tfloat64\t// for radial gradients only\n\tStops\t\t[]DrawGradientStop\n}\n\n// TODO\ntype DrawGradientStop struct {\n\tPos\tfloat64\t\t// between 0 and 1 inclusive\n\tR\tfloat64\n\tG\tfloat64\n\tB\tfloat64\n\tA\tfloat64\n}\n\nfunc (b *DrawBrush) toLibui() *C.uiDrawBrush {\n\tcb := C.pkguiAllocBrush()\n\tcb.Type = C.uiDrawBrushType(b.Type)\n\tswitch b.Type {\n\tcase DrawBrushTypeSolid:\n\t\tcb.R = C.double(b.R)\n\t\tcb.G = C.double(b.G)\n\t\tcb.B = C.double(b.B)\n\t\tcb.A = C.double(b.A)\n\tcase DrawBrushTypeLinearGradient, DrawBrushTypeRadialGradient:\n\t\tcb.X0 = C.double(b.X0)\n\t\tcb.Y0 = C.double(b.Y0)\n\t\tcb.X1 = C.double(b.X1)\n\t\tcb.Y1 = C.double(b.Y1)\n\t\tcb.OuterRadius = C.double(b.OuterRadius)\n\t\tcb.NumStops = C.size_t(len(b.Stops))\n\t\tcb.Stops = C.pkguiAllocGradientStops(cb.NumStops)\n\t\tfor i, s := range b.Stops {\n\t\t\tC.pkguiSetGradientStop(cb.Stops, C.size_t(i),\n\t\t\t\tC.double(s.Pos),\n\t\t\t\tC.double(s.R),\n\t\t\t\tC.double(s.G),\n\t\t\t\tC.double(s.B),\n\t\t\t\tC.double(s.A))\n\t\t}\n\tcase DrawBrushTypeImage:\n\t\tpanic(\"unimplemented\")\n\tdefault:\n\t\tpanic(\"invalid brush type in Brush.toLibui()\")\n\t}\n\treturn cb\n}\n\nfunc freeBrush(cb *C.uiDrawBrush) {\n\tif cb.Type == C.uiDrawBrushTypeLinearGradient || cb.Type == C.uiDrawBrushTypeRadialGradient {\n\t\tC.pkguiFreeGradientStops(cb.Stops)\n\t}\n\tC.pkguiFreeBrush(cb)\n}\n\n// TODO\ntype DrawStrokeParams struct {\n\tCap\t\t\tDrawLineCap\n\tJoin\t\t\tDrawLineJoin\n\tThickness\t\tfloat64\n\tMiterLimit\t\tfloat64\n\tDashes\t\t[]float64\n\tDashPhase\tfloat64\n}\n\nfunc (sp *DrawStrokeParams) toLibui() *C.uiDrawStrokeParams {\n\tcsp := C.pkguiAllocStrokeParams()\n\tcsp.Cap = C.uiDrawLineCap(sp.Cap)\n\tcsp.Join = C.uiDrawLineJoin(sp.Join)\n\tcsp.Thickness = C.double(sp.Thickness)\n\tcsp.MiterLimit = C.double(sp.MiterLimit)\n\tcsp.Dashes = nil\n\tcsp.NumDashes = C.size_t(len(sp.Dashes))\n\tif csp.NumDashes != 0 {\n\t\tcsp.Dashes = C.pkguiAllocDashes(csp.NumDashes)\n\t\tfor i, d := range sp.Dashes {\n\t\t\tC.pkguiSetDash(csp.Dashes, C.size_t(i), C.double(d))\n\t\t}\n\t}\n\tcsp.DashPhase = C.double(sp.DashPhase)\n\treturn csp\n}\n\nfunc freeStrokeParams(csp *C.uiDrawStrokeParams) {\n\tif csp.Dashes != nil {\n\t\tC.pkguiFreeDashes(csp.Dashes)\n\t}\n\tC.pkguiFreeStrokeParams(csp)\n}\n\n// TODO\nfunc (c *DrawContext) Stroke(p *DrawPath, b *DrawBrush, sp *DrawStrokeParams) {\n\tcb := b.toLibui()\n\tdefer freeBrush(cb)\n\tcsp := sp.toLibui()\n\tdefer freeStrokeParams(csp)\n\tC.uiDrawStroke(c.c, p.p, cb, csp)\n}\n\n// TODO\nfunc (c *DrawContext) Fill(p *DrawPath, b *DrawBrush) {\n\tcb := b.toLibui()\n\tdefer freeBrush(cb)\n\tC.uiDrawFill(c.c, p.p, cb)\n}\n\n// TODO\n// TODO should the methods of these return self for chaining?\ntype DrawMatrix struct {\n\tM11\t\tfloat64\n\tM12\t\tfloat64\n\tM21\t\tfloat64\n\tM22\t\tfloat64\n\tM31\t\tfloat64\n\tM32\t\tfloat64\n}\n\n// TODO identity matrix\nfunc DrawNewMatrix() *DrawMatrix {\n\tm := new(DrawMatrix)\n\tm.SetIdentity()\n\treturn m\n}\n\n// TODO\nfunc (m *DrawMatrix) SetIdentity() {\n\tm.M11 = 1\n\tm.M12 = 0\n\tm.M21 = 0\n\tm.M22 = 1\n\tm.M31 = 0\n\tm.M32 = 0\n}\n\nfunc (m *DrawMatrix) toLibui() *C.uiDrawMatrix {\n\tcm := C.pkguiAllocMatrix()\n\tcm.M11 = C.double(m.M11)\n\tcm.M12 = C.double(m.M12)\n\tcm.M21 = C.double(m.M21)\n\tcm.M22 = C.double(m.M22)\n\tcm.M31 = C.double(m.M31)\n\tcm.M32 = C.double(m.M32)\n\treturn cm\n}\n\nfunc (m *DrawMatrix) fromLibui(cm *C.uiDrawMatrix) {\n\tm.M11 = float64(cm.M11)\n\tm.M12 = float64(cm.M12)\n\tm.M21 = float64(cm.M21)\n\tm.M22 = float64(cm.M22)\n\tm.M31 = float64(cm.M31)\n\tm.M32 = float64(cm.M32)\n\tC.pkguiFreeMatrix(cm)\n}\n\n// TODO\nfunc (m *DrawMatrix) Translate(x float64, y float64) {\n\tcm := m.toLibui()\n\tC.uiDrawMatrixTranslate(cm, C.double(x), C.double(y))\n\tm.fromLibui(cm)\n}\n\n// TODO\nfunc (m *DrawMatrix) Scale(xCenter float64, yCenter float64, x float64, y float64) {\n\tcm := m.toLibui()\n\tC.uiDrawMatrixScale(cm,\n\t\tC.double(xCenter), C.double(yCenter),\n\t\tC.double(x), C.double(y))\n\tm.fromLibui(cm)\n}\n\n// TODO\nfunc (m *DrawMatrix) Rotate(x float64, y float64, amount float64) {\n\tcm := m.toLibui()\n\tC.uiDrawMatrixRotate(cm, C.double(x), C.double(y), C.double(amount))\n\tm.fromLibui(cm)\n}\n\n// TODO\nfunc (m *DrawMatrix) Skew(x float64, y float64, xamount float64, yamount float64) {\n\tcm := m.toLibui()\n\tC.uiDrawMatrixSkew(cm,\n\t\tC.double(x), C.double(y),\n\t\tC.double(xamount), C.double(yamount))\n\tm.fromLibui(cm)\n}\n\n// TODO\nfunc (m *DrawMatrix) Multiply(m2 *DrawMatrix) {\n\tcm := m.toLibui()\n\tcm2 := m2.toLibui()\n\tC.uiDrawMatrixMultiply(cm, cm2)\n\tC.pkguiFreeMatrix(cm2)\n\tm.fromLibui(cm)\n}\n\n// TODO\nfunc (m *DrawMatrix) Invertible() bool {\n\tcm := m.toLibui()\n\tres := C.uiDrawMatrixInvertible(cm)\n\tC.pkguiFreeMatrix(cm)\n\treturn tobool(res)\n}\n\n// TODO\n// \n// If m is not invertible, false is returned and m is left unchanged.\nfunc (m *DrawMatrix) Invert() bool {\n\tcm := m.toLibui()\n\tres := C.uiDrawMatrixInvert(cm)\n\tm.fromLibui(cm)\n\treturn tobool(res)\n}\n\n// TODO unimplemented\nfunc (m *DrawMatrix) TransformPoint(x float64, y float64) (xout float64, yout float64) {\n\tpanic(\"TODO\")\n}\n\n// TODO unimplemented\nfunc (m *DrawMatrix) TransformSize(x float64, y float64) (xout float64, yout float64) {\n\tpanic(\"TODO\")\n}\n\n// TODO\nfunc (c *DrawContext) Transform(m *DrawMatrix) {\n\tcm := m.toLibui()\n\tC.uiDrawTransform(c.c, cm)\n\tC.pkguiFreeMatrix(cm)\n}\n\n// TODO\nfunc (c *DrawContext) Clip(p *DrawPath) {\n\tC.uiDrawClip(c.c, p.p)\n}\n\n// TODO\nfunc (c *DrawContext) Save() {\n\tC.uiDrawSave(c.c)\n}\n\n// TODO\nfunc (c *DrawContext) Restore() {\n\tC.uiDrawRestore(c.c)\n}\n"
  },
  {
    "path": "drawtext.go",
    "content": "// 12 august 2018\n\npackage ui\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Attribute stores information about an attribute in an\n// AttributedString.\n//\n// The following types can be used as Attributes:\n//\n// \t- TextFamily\n// \t- TextSize\n// \t- TextWeight\n// \t- TextItalic\n// \t- TextStretch\n// \t- TextColor\n// \t- TextBackground\n// \t- Underline\n// \t- UnderlineColor\n// \t- UnderlineColorCustom\n// \t- OpenTypeFeatures\n//\n// For every Unicode codepoint in the AttributedString, at most one\n// value of each attribute type can be applied.\ntype Attribute interface {\n\ttoLibui() *C.uiAttribute\n}\n\n// TextFamily is an Attribute that changes the font family of the text\n// it is applied to. Font family names are case-insensitive.\ntype TextFamily string\n\nfunc (f TextFamily) toLibui() *C.uiAttribute {\n\tfstr := C.CString(string(f))\n\tdefer freestr(fstr)\n\treturn C.uiNewFamilyAttribute(fstr)\n}\n\n// TextSize is an Attribute that changes the size of the text it is\n// applied to, in typographical points.\ntype TextSize float64\n\nfunc (s TextSize) toLibui() *C.uiAttribute {\n\treturn C.uiNewSizeAttribute(C.double(s))\n}\n\n// TextWeight is an Attribute that changes the weight of the text\n// it is applied to. These roughly map to the OS/2 text weight field\n// of TrueType and OpenType fonts, or to CSS weight numbers. The\n// named constants are nominal values; the actual values may vary\n// by font and by OS, though this isn't particularly likely. Any value\n// between TextWeightMinimum and TextWeightMaximum,\n// inclusive, is allowed.\n//\n// Note that due to restrictions in early versions of Windows, some\n// fonts have \"special\" weights be exposed in many programs as\n// separate font families. This is perhaps most notable with\n// Arial Black. Package ui does not do this, even on Windows\n// (because the DirectWrite API libui uses on Windows does not do\n// this); to specify Arial Black, use family Arial and weight\n// TextWeightBlack.\ntype TextWeight int\nconst (\n\tTextWeightMinimum TextWeight = 0\n\tTextWeightThin TextWeight = 100\n\tTextWeightUltraLight TextWeight = 200\n\tTextWeightLight TextWeight = 300\n\tTextWeightBook TextWeight = 350\n\tTextWeightNormal TextWeight = 400\n\tTextWeightMedium TextWeight = 500\n\tTextWeightSemiBold TextWeight = 600\n\tTextWeightBold TextWeight = 700\n\tTextWeightUltraBold TextWeight = 800\n\tTextWeightHeavy TextWeight = 900\n\tTextWeightUltraHeavy TextWeight = 950\n\tTextWeightMaximum TextWeight = 1000\n)\n\nfunc (w TextWeight) toLibui() *C.uiAttribute {\n\treturn C.uiNewWeightAttribute(C.uiTextWeight(w))\n}\n\n// TextItalic is an Attribute that changes the italic mode of the text\n// it is applied to. Italic represents \"true\" italics where the slanted\n// glyphs have custom shapes, whereas oblique represents italics\n// that are merely slanted versions of the normal glyphs. Most fonts\n// usually have one or the other.\ntype TextItalic int\nconst (\n\tTextItalicNormal TextItalic = iota\n\tTextItalicOblique\n\tTextItalicItalic\n)\n\nfunc (i TextItalic) toLibui() *C.uiAttribute {\n\treturn C.uiNewItalicAttribute(C.uiTextItalic(i))\n}\n\n// TextStretch is an Attribute that changes the stretch (also called\n// \"width\") of the text it is applied to.\n//\n// Note that due to restrictions in early versions of Windows, some\n// fonts have \"special\" stretches be exposed in many programs as\n// separate font families. This is perhaps most notable with\n// Arial Condensed. Package ui does not do this, even on Windows\n// (because the DirectWrite API package ui uses on Windows does\n// not do this); to specify Arial Condensed, use family Arial and\n// stretch TextStretchCondensed.\ntype TextStretch int\nconst (\n\tTextStretchUltraCondensed TextStretch = iota\n\tTextStretchExtraCondensed\n\tTextStretchCondensed\n\tTextStretchSemiCondensed\n\tTextStretchNormal\n\tTextStretchSemiExpanded\n\tTextStretchExpanded\n\tTextStretchExtraExpanded\n\tTextStretchUltraExpanded\n)\n\nfunc (s TextStretch) toLibui() *C.uiAttribute {\n\treturn C.uiNewStretchAttribute(C.uiTextStretch(s))\n}\n\n// TextColor is an Attribute that changes the color of the text it is\n// applied to.\ntype TextColor struct {\n\tR\tfloat64\n\tG\tfloat64\n\tB\tfloat64\n\tA\tfloat64\n}\n\nfunc (c TextColor) toLibui() *C.uiAttribute {\n\treturn C.uiNewColorAttribute(C.double(c.R), C.double(c.G), C.double(c.B), C.double(c.A))\n}\n\n// TextBackground is an Attribute that changes the background\n// color of the text it is applied to.\ntype TextBackground struct {\n\tR\tfloat64\n\tG\tfloat64\n\tB\tfloat64\n\tA\tfloat64\n}\n\nfunc (b TextBackground) toLibui() *C.uiAttribute {\n\treturn C.uiNewBackgroundAttribute(C.double(b.R), C.double(b.G), C.double(b.B), C.double(b.A))\n}\n\n// Underline is an Attribute that specifies a type of underline to use\n// on text.\ntype Underline int\nconst (\n\tUnderlineNone Underline = iota\n\tUnderlineSingle\n\tUnderlineDouble\n\tUnderlineSuggestion\t\t// wavy or dotted underlines used for spelling/grammar checkers\n)\n\nfunc (u Underline) toLibui() *C.uiAttribute {\n\treturn C.uiNewUnderlineAttribute(C.uiUnderline(u))\n}\n\n// UnderlineColor is an Attribute that changes the color of any\n// underline on the text it is applied to, regardless of the type of\n// underline. In addition to being able to specify the\n// platform-specific colors for suggestion underlines here, you can\n// also use a custom color with UnderlineColorCustom.\n// \n// To use the constants here correctly, pair them with\n// UnderlineSuggestion (though they can be used on other types of\n// underline as well).\n// \n// If an underline type is applied but no underline color is\n// specified, the text color is used instead. If an underline color\n// is specified without an underline type, the underline color\n// attribute is ignored, but not removed from the uiAttributedString.\ntype UnderlineColor int\nconst (\n\tUnderlineColorSpelling UnderlineColor = iota + 1\n\tUnderlineColorGrammar\n\tUnderlineColorAuxiliary\t\t// for instance, the color used by smart replacements on macOS or in Microsoft Office\n)\n\nfunc (u UnderlineColor) toLibui() *C.uiAttribute {\n\treturn C.uiNewUnderlineColorAttribute(C.uiUnderlineColor(u), 0, 0, 0, 0)\n}\n\n// UnderlineColorCustom is an Attribute like UnderlineColor, except\n// it allows specifying a custom color.\ntype UnderlineColorCustom struct {\n\tR\tfloat64\n\tG\tfloat64\n\tB\tfloat64\n\tA\tfloat64\n}\n\nfunc (u UnderlineColorCustom) toLibui() *C.uiAttribute {\n\treturn C.uiNewUnderlineColorAttribute(C.uiUnderlineColorCustom, C.double(u.R), C.double(u.G), C.double(u.B), C.double(u.A))\n}\n\n// OpenTypeFeatures is an Attribute that represents a set of\n// OpenType feature tag-value pairs, for applying OpenType\n// features to text. OpenType feature tags are four-character codes\n// defined by OpenType that cover things from design features like\n// small caps and swashes to language-specific glyph shapes and\n// beyond. Each tag may only appear once in any given\n// uiOpenTypeFeatures instance. Each value is a 32-bit integer,\n// often used as a Boolean flag, but sometimes as an index to choose\n// a glyph shape to use.\n// \n// If a font does not support a certain feature, that feature will be\n// ignored. (TODO verify this on all OSs)\n// \n// See the OpenType specification at\n// https://www.microsoft.com/typography/otspec/featuretags.htm\n// for the complete list of available features, information on specific\n// features, and how to use them.\n// TODO invalid features\n// \n// Note that if a feature is not present in a OpenTypeFeatures,\n// the feature is NOT treated as if its value was zero, unlike in Go.\n// Script-specific font shaping rules and font-specific feature\n// settings may use a different default value for a feature. You\n// should likewise NOT treat a missing feature as having a value of\n// zero either. Instead, a missing feature should be treated as\n// having some unspecified default value.\n// \n// Note that despite OpenTypeFeatures being a map, its contents\n// are copied by AttributedString. Modifying an OpenTypeFeatures\n// after giving it to an AttributedString, or modifying one that comes\n// out of an AttributedString, will have no effect.\ntype OpenTypeFeatures map[OpenTypeTag]uint32\n\nfunc (o OpenTypeFeatures) toLibui() *C.uiAttribute {\n\totf := C.uiNewOpenTypeFeatures()\n\tdefer C.uiFreeOpenTypeFeatures(otf)\n\tfor tag, value := range o {\n\t\ta := byte((tag >> 24) & 0xFF)\n\t\tb := byte((tag >> 16) & 0xFF)\n\t\tc := byte((tag >> 8) & 0xFF)\n\t\td := byte(tag & 0xFF)\n\t\tC.uiOpenTypeFeaturesAdd(otf, C.char(a), C.char(b), C.char(c), C.char(d), C.uint32_t(value))\n\t}\n\treturn C.uiNewFeaturesAttribute(otf)\n}\n\n// OpenTypeTag represents a four-byte OpenType feature tag.\ntype OpenTypeTag uint32\n\n// ToOpenTypeTag converts the four characters a, b, c, and d into\n// an OpenTypeTag.\nfunc ToOpenTypeTag(a, b, c, d byte) OpenTypeTag {\n\treturn (OpenTypeTag(a) << 24) |\n\t\t(OpenTypeTag(b) << 16) |\n\t\t(OpenTypeTag(c) << 8) |\n\t\tOpenTypeTag(d)\n}\n\nfunc attributeFromLibui(a *C.uiAttribute) Attribute {\n\tswitch C.uiAttributeGetType(a) {\n\tcase C.uiAttributeTypeFamily:\n\t\tcf := C.uiAttributeFamily(a)\n\t\treturn TextFamily(C.GoString(cf))\n\tcase C.uiAttributeTypeSize:\n\t\treturn TextSize(C.uiAttributeSize(a))\n\tcase C.uiAttributeTypeWeight:\n\t\treturn TextWeight(C.uiAttributeWeight(a))\n\tcase C.uiAttributeTypeItalic:\n\t\treturn TextItalic(C.uiAttributeItalic(a))\n\tcase C.uiAttributeTypeStretch:\n\t\treturn TextStretch(C.uiAttributeStretch(a))\n\tcase C.uiAttributeTypeColor:\n\t\tcc := C.pkguiAllocColorDoubles()\n\t\tdefer C.pkguiFreeColorDoubles(cc)\n\t\tC.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a)\n\t\treturn TextColor{\n\t\t\tR:\tfloat64(*(cc.r)),\n\t\t\tG:\tfloat64(*(cc.g)),\n\t\t\tB:\tfloat64(*(cc.b)),\n\t\t\tA:\tfloat64(*(cc.a)),\n\t\t}\n\tcase C.uiAttributeTypeBackground:\n\t\tcc := C.pkguiAllocColorDoubles()\n\t\tdefer C.pkguiFreeColorDoubles(cc)\n\t\tC.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a)\n\t\treturn TextBackground{\n\t\t\tR:\tfloat64(*(cc.r)),\n\t\t\tG:\tfloat64(*(cc.g)),\n\t\t\tB:\tfloat64(*(cc.b)),\n\t\t\tA:\tfloat64(*(cc.a)),\n\t\t}\n\tcase C.uiAttributeTypeUnderline:\n\t\treturn Underline(C.uiAttributeUnderline(a))\n\tcase C.uiAttributeTypeUnderlineColor:\n\t\tcu := C.pkguiNewUnderlineColor()\n\t\tdefer C.pkguiFreeUnderlineColor(cu)\n\t\tcc := C.pkguiAllocColorDoubles()\n\t\tdefer C.pkguiFreeColorDoubles(cc)\n\t\tC.uiAttributeUnderlineColor(a, cu, cc.r, cc.g, cc.b, cc.a)\n\t\tif *cu == C.uiUnderlineColorCustom {\n\t\t\treturn UnderlineColorCustom{\n\t\t\t\tR:\tfloat64(*(cc.r)),\n\t\t\t\tG:\tfloat64(*(cc.g)),\n\t\t\t\tB:\tfloat64(*(cc.b)),\n\t\t\t\tA:\tfloat64(*(cc.a)),\n\t\t\t}\n\t\t}\n\t\treturn UnderlineColor(*cu)\n\tcase C.uiAttributeTypeFeatures:\n\t\t// TODO\n\t}\n\tpanic(\"unreachable\")\n}\n\n// AttributedString represents a string of UTF-8 text that can\n// optionally be embellished with formatting attributes. Package ui\n// provides the list of formatting attributes, which cover common\n// formatting traits like boldface and color as well as advanced\n// typographical features provided by OpenType like superscripts\n// and small caps. These attributes can be combined in a variety of\n// ways.\n//\n// Attributes are applied to runs of Unicode codepoints in the string.\n// Zero-length runs are elided. Consecutive runs that have the same\n// attribute type and value are merged. Each attribute is independent\n// of each other attribute; overlapping attributes of different types\n// do not split each other apart, but different values of the same\n// attribute type do.\n//\n// The empty string can also be represented by AttributedString,\n// but because of the no-zero-length-attribute rule, it will not have\n// attributes.\n//\n// Unlike Go strings, AttributedStrings are mutable.\n//\n// AttributedString allocates resources within libui, which package\n// ui sits on top of. As such, when you are finished with an\n// AttributedString, you must free it with Free. Like other things in\n// package ui, AttributedString must only be used from the main\n// goroutine.\n//\n// In addition, AttributedString provides facilities for moving\n// between grapheme clusters, which represent a character\n// from the point of view of the end user. The cursor of a text editor\n// is always placed on a grapheme boundary, so you can use these\n// features to move the cursor left or right by one \"character\".\n// TODO does uiAttributedString itself need this\n//\n// AttributedString does not provide enough information to be able\n// to draw itself onto a DrawContext or respond to user actions.\n// In order to do that, you'll need to use a DrawTextLayout, which\n// is built from the combination of an AttributedString and a set of\n// layout-specific properties.\ntype AttributedString struct {\n\ts\t*C.uiAttributedString\n}\n\n// NewAttributedString creates a new AttributedString from\n// initialString. The string will be entirely unattributed.\nfunc NewAttributedString(initialString string) *AttributedString {\n\tcs := C.CString(initialString)\n\tdefer freestr(cs)\n\treturn &AttributedString{\n\t\ts:\tC.uiNewAttributedString(cs),\n\t}\n}\n\n// Free destroys s.\nfunc (s *AttributedString) Free() {\n\tC.uiFreeAttributedString(s.s)\n}\n\n// String returns the textual content of s.\nfunc (s *AttributedString) String() string {\n\treturn C.GoString(C.uiAttributedStringString(s.s))\n}\n\n// AppendUnattributed adds str to the end of s. The new substring\n// will be unattributed.\nfunc (s *AttributedString) AppendUnattributed(str string) {\n\tcs := C.CString(str)\n\tdefer freestr(cs)\n\tC.uiAttributedStringAppendUnattributed(s.s, cs)\n}\n\n// InsertAtUnattributed adds str to s at the byte position specified by\n// at. The new substring will be unattributed; existing attributes will\n// be moved along with their text.\nfunc (s *AttributedString) InsertAtUnattributed(str string, at int) {\n\tcs := C.CString(str)\n\tdefer freestr(cs)\n\tC.uiAttributedStringInsertAtUnattributed(s.s, cs, C.size_t(at))\n}\n\n// Delete deletes the characters and attributes of s in the byte range\n// [start, end).\nfunc (s *AttributedString) Delete(start, end int) {\n\tC.uiAttributedStringDelete(s.s, C.size_t(start), C.size_t(end))\n}\n\n// SetAttribute sets a in the byte range [start, end) of s. Any existing\n// attributes in that byte range of the same type are removed.\nfunc (s *AttributedString) SetAttribute(a Attribute, start, end int) {\n\tC.uiAttributedStringSetAttribute(s.s, a.toLibui(), C.size_t(start), C.size_t(end))\n}\n\n// TODO uiAttributedStringForEachAttribute\n// TODO uiAttributedStringNumGraphemes\n// TODO uiAttributedStringByteIndexToGrapheme\n// TODO uiAttributedStringGraphemeToByteIndex\n\n// FontDescriptor provides a complete description of a font where\n// one is needed. Currently, this means as the default font of a\n// DrawTextLayout and as the data returned by FontButton.\ntype FontDescriptor struct {\n\tFamily\tTextFamily\n\tSize\t\tTextSize\n\tWeight\tTextWeight\n\tItalic\t\tTextItalic\n\tStretch\tTextStretch\n}\n\nfunc (d *FontDescriptor) fromLibui(fd *C.uiFontDescriptor) {\n\td.Family = TextFamily(C.GoString(fd.Family))\n\td.Size = TextSize(fd.Size)\n\td.Weight = TextWeight(fd.Weight)\n\td.Italic = TextItalic(fd.Italic)\n\td.Stretch = TextStretch(fd.Stretch)\n}\n\nfunc (d *FontDescriptor) toLibui() *C.uiFontDescriptor {\n\tfd := C.pkguiNewFontDescriptor()\n\tfd.Family = C.CString(string(d.Family))\n\tfd.Size = C.double(d.Size)\n\tfd.Weight = C.uiTextWeight(d.Weight)\n\tfd.Italic = C.uiTextItalic(d.Italic)\n\tfd.Stretch = C.uiTextStretch(d.Stretch)\n\treturn fd\n}\n\nfunc freeLibuiFontDescriptor(fd *C.uiFontDescriptor) {\n\tfreestr(fd.Family)\n\tC.pkguiFreeFontDescriptor(fd)\n}\n\n// DrawTextLayout is a concrete representation of an\n// AttributedString that can be displayed in a DrawContext.\n// It includes information important for the drawing of a block of\n// text, including the bounding box to wrap the text within, the\n// alignment of lines of text within that box, areas to mark as\n// being selected, and other things.\n//\n// Unlike AttributedString, the content of a DrawTextLayout is\n// immutable once it has been created.\n//\n// TODO talk about OS-specific differences with text drawing that libui can't account for...\ntype DrawTextLayout struct {\n\ttl\t*C.uiDrawTextLayout\n}\n\n// DrawTextAlign specifies the alignment of lines of text in a\n// DrawTextLayout.\n// TODO should this really have Draw in the name?\ntype DrawTextAlign int\nconst (\n\tDrawTextAlignLeft DrawTextAlign = iota\n\tDrawTextAlignCenter\n\tDrawTextAlignRight\n)\n\n// DrawTextLayoutParams describes a DrawTextLayout.\n// DefaultFont is used to render any text that is not attributed\n// sufficiently in String. Width determines the width of the bounding\n// box of the text; the height is determined automatically.\ntype DrawTextLayoutParams struct {\n\tString\t\t*AttributedString\n\tDefaultFont\t*FontDescriptor\n\tWidth\t\tfloat64\n\tAlign\t\tDrawTextAlign\n}\n\n// DrawNewTextLayout() creates a new DrawTextLayout from\n// the given parameters.\nfunc DrawNewTextLayout(p *DrawTextLayoutParams) *DrawTextLayout {\n\tdp := C.pkguiNewDrawTextLayoutParams()\n\tdefer C.pkguiFreeDrawTextLayoutParams(dp)\n\tdp.String = p.String.s\n\tdp.DefaultFont = p.DefaultFont.toLibui()\n\tdefer freeLibuiFontDescriptor(dp.DefaultFont)\n\tdp.Width = C.double(p.Width)\n\tdp.Align = C.uiDrawTextAlign(p.Align)\n\treturn &DrawTextLayout{\n\t\ttl:\tC.uiDrawNewTextLayout(dp),\n\t}\n}\n\n// Free frees tl. The underlying AttributedString is not freed.\nfunc (tl *DrawTextLayout) Free() {\n\tC.uiDrawFreeTextLayout(tl.tl)\n}\n\n// Text draws tl in c with the top-left point of tl at (x, y).\nfunc (c *DrawContext) Text(tl *DrawTextLayout, x, y float64) {\n\tC.uiDrawText(c.c, tl.tl, C.double(x), C.double(y))\n}\n\n// TODO uiDrawTextLayoutExtents\n"
  },
  {
    "path": "dummy_windows.cpp",
    "content": "// 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",
    "content": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// EditableCombobox is a Control that represents a drop-down list\n// of strings that the user can choose one of at any time. It also has\n// an entry field that the user can type an alternate choice into.\ntype EditableCombobox struct {\n\tControlBase\n\tc\t*C.uiEditableCombobox\n\tonChanged\t\tfunc(*EditableCombobox)\n}\n\n// NewEditableCombobox creates a new EditableCombobox.\nfunc NewEditableCombobox() *EditableCombobox {\n\tc := new(EditableCombobox)\n\n\tc.c = C.uiNewEditableCombobox()\n\n\tC.pkguiEditableComboboxOnChanged(c.c)\n\n\tc.ControlBase = NewControlBase(c, uintptr(unsafe.Pointer(c.c)))\n\treturn c\n}\n\n// Append adds the named item to the end of the EditableCombobox.\nfunc (e *EditableCombobox) Append(text string) {\n\tctext := C.CString(text)\n\tC.uiEditableComboboxAppend(e.c, ctext)\n\tfreestr(ctext)\n}\n\n// Text returns the text in the entry of the EditableCombobox, which\n// could be one of the choices in the list if the user has selected one.\nfunc (e *EditableCombobox) Text() string {\n\tctext := C.uiEditableComboboxText(e.c)\n\ttext := C.GoString(ctext)\n\tC.uiFreeText(ctext)\n\treturn text\n}\n\n// SetText sets the text in the entry of the EditableCombobox.\nfunc (e *EditableCombobox) SetText(text string) {\n\tctext := C.CString(text)\n\tC.uiEditableComboboxSetText(e.c, ctext)\n\tfreestr(ctext)\n}\n\n// OnChanged registers f to be run when the user either selects an\n// item or changes the text in the EditableCombobox. Only one\n// function can be registered at a time.\nfunc (e *EditableCombobox) OnChanged(f func(*EditableCombobox)) {\n\te.onChanged = f\n}\n\n//export pkguiDoEditableComboboxOnChanged\nfunc pkguiDoEditableComboboxOnChanged(cc *C.uiEditableCombobox, data unsafe.Pointer) {\n\te := ControlFromLibui(uintptr(unsafe.Pointer(cc))).(*EditableCombobox)\n\tif e.onChanged != nil {\n\t\te.onChanged(e)\n\t}\n}\n"
  },
  {
    "path": "entry.go",
    "content": "// 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// something's wrong with NSMapTable\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// Entry is a Control that represents a space that the user can\n// type a single line of text into.\ntype Entry struct {\n\tControlBase\n\te\t*C.uiEntry\n\tonChanged\t\tfunc(*Entry)\n}\n\nfunc finishNewEntry(ee *C.uiEntry) *Entry {\n\te := new(Entry)\n\n\te.e = ee\n\n\tC.pkguiEntryOnChanged(e.e)\n\n\te.ControlBase = NewControlBase(e, uintptr(unsafe.Pointer(e.e)))\n\treturn e\n}\n\n// NewEntry creates a new Entry.\nfunc NewEntry() *Entry {\n\treturn finishNewEntry(C.uiNewEntry())\n}\n\n// NewPasswordEntry creates a new Entry whose contents are\n// visibly obfuscated, suitable for passwords.\nfunc NewPasswordEntry() *Entry {\n\treturn finishNewEntry(C.uiNewPasswordEntry())\n}\n\n// NewSearchEntry creates a new Entry suitable for searching with.\n// Changed events may, depending on the system, be delayed\n// with a search Entry, to produce a smoother user experience.\nfunc NewSearchEntry() *Entry {\n\treturn finishNewEntry(C.uiNewSearchEntry())\n}\n\n// Text returns the Entry's text.\nfunc (e *Entry) Text() string {\n\tctext := C.uiEntryText(e.e)\n\ttext := C.GoString(ctext)\n\tC.uiFreeText(ctext)\n\treturn text\n}\n\n// SetText sets the Entry's text to text.\nfunc (e *Entry) SetText(text string) {\n\tctext := C.CString(text)\n\tC.uiEntrySetText(e.e, ctext)\n\tfreestr(ctext)\n}\n\n// OnChanged registers f to be run when the user makes a change to\n// the Entry. Only one function can be registered at a time.\nfunc (e *Entry) OnChanged(f func(*Entry)) {\n\te.onChanged = f\n}\n\n//export pkguiDoEntryOnChanged\nfunc pkguiDoEntryOnChanged(ee *C.uiEntry, data unsafe.Pointer) {\n\te := ControlFromLibui(uintptr(unsafe.Pointer(ee))).(*Entry)\n\tif e.onChanged != nil {\n\t\te.onChanged(e)\n\t}\n}\n\n// ReadOnly returns whether the Entry can be changed.\nfunc (e *Entry) ReadOnly() bool {\n\treturn tobool(C.uiEntryReadOnly(e.e))\n}\n\n// SetReadOnly sets whether the Entry can be changed.\nfunc (e *Entry) SetReadOnly(ro bool) {\n\tC.uiEntrySetReadOnly(e.e, frombool(ro))\n}\n"
  },
  {
    "path": "examples/controlgallery.go",
    "content": "// 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\"\n)\n\nvar mainwin *ui.Window\n\nfunc makeBasicControlsPage() ui.Control {\n\tvbox := ui.NewVerticalBox()\n\tvbox.SetPadded(true)\n\n\thbox := ui.NewHorizontalBox()\n\thbox.SetPadded(true)\n\tvbox.Append(hbox, false)\n\n\thbox.Append(ui.NewButton(\"Button\"), false)\n\thbox.Append(ui.NewCheckbox(\"Checkbox\"), false)\n\n\tvbox.Append(ui.NewLabel(\"This is a label. Right now, labels can only span one line.\"), false)\n\n\tvbox.Append(ui.NewHorizontalSeparator(), false)\n\n\tgroup := ui.NewGroup(\"Entries\")\n\tgroup.SetMargined(true)\n\tvbox.Append(group, true)\n\ngroup.SetChild(ui.NewNonWrappingMultilineEntry())\n\n\tentryForm := ui.NewForm()\n\tentryForm.SetPadded(true)\n\tgroup.SetChild(entryForm)\n\n\tentryForm.Append(\"Entry\", ui.NewEntry(), false)\n\tentryForm.Append(\"Password Entry\", ui.NewPasswordEntry(), false)\n\tentryForm.Append(\"Search Entry\", ui.NewSearchEntry(), false)\n\tentryForm.Append(\"Multiline Entry\", ui.NewMultilineEntry(), true)\n\tentryForm.Append(\"Multiline Entry No Wrap\", ui.NewNonWrappingMultilineEntry(), true)\n\n\treturn vbox\n}\n\nfunc makeNumbersPage() ui.Control {\n\thbox := ui.NewHorizontalBox()\n\thbox.SetPadded(true)\n\n\tgroup := ui.NewGroup(\"Numbers\")\n\tgroup.SetMargined(true)\n\thbox.Append(group, true)\n\n\tvbox := ui.NewVerticalBox()\n\tvbox.SetPadded(true)\n\tgroup.SetChild(vbox)\n\n\tspinbox := ui.NewSpinbox(0, 100)\n\tslider := ui.NewSlider(0, 100)\n\tpbar := ui.NewProgressBar()\n\tspinbox.OnChanged(func(*ui.Spinbox) {\n\t\tslider.SetValue(spinbox.Value())\n\t\tpbar.SetValue(spinbox.Value())\n\t})\n\tslider.OnChanged(func(*ui.Slider) {\n\t\tspinbox.SetValue(slider.Value())\n\t\tpbar.SetValue(slider.Value())\n\t})\n\tvbox.Append(spinbox, false)\n\tvbox.Append(slider, false)\n\tvbox.Append(pbar, false)\n\n\tip := ui.NewProgressBar()\n\tip.SetValue(-1)\n\tvbox.Append(ip, false)\n\n\tgroup = ui.NewGroup(\"Lists\")\n\tgroup.SetMargined(true)\n\thbox.Append(group, true)\n\n\tvbox = ui.NewVerticalBox()\n\tvbox.SetPadded(true)\n\tgroup.SetChild(vbox)\n\n\tcbox := ui.NewCombobox()\n\tcbox.Append(\"Combobox Item 1\")\n\tcbox.Append(\"Combobox Item 2\")\n\tcbox.Append(\"Combobox Item 3\")\n\tvbox.Append(cbox, false)\n\n\tecbox := ui.NewEditableCombobox()\n\tecbox.Append(\"Editable Item 1\")\n\tecbox.Append(\"Editable Item 2\")\n\tecbox.Append(\"Editable Item 3\")\n\tvbox.Append(ecbox, false)\n\n\trb := ui.NewRadioButtons()\n\trb.Append(\"Radio Button 1\")\n\trb.Append(\"Radio Button 2\")\n\trb.Append(\"Radio Button 3\")\n\tvbox.Append(rb, false)\n\n\treturn hbox\n}\n\nfunc makeDataChoosersPage() ui.Control {\n\thbox := ui.NewHorizontalBox()\n\thbox.SetPadded(true)\n\n\tvbox := ui.NewVerticalBox()\n\tvbox.SetPadded(true)\n\thbox.Append(vbox, false)\n\n\tvbox.Append(ui.NewDatePicker(), false)\n\tvbox.Append(ui.NewTimePicker(), false)\n\tvbox.Append(ui.NewDateTimePicker(), false)\n\tvbox.Append(ui.NewFontButton(), false)\n\tvbox.Append(ui.NewColorButton(), false)\n\n\thbox.Append(ui.NewVerticalSeparator(), false)\n\n\tvbox = ui.NewVerticalBox()\n\tvbox.SetPadded(true)\n\thbox.Append(vbox, true)\n\n\tgrid := ui.NewGrid()\n\tgrid.SetPadded(true)\n\tvbox.Append(grid, false)\n\n\tbutton := ui.NewButton(\"Open File\")\n\tentry := ui.NewEntry()\n\tentry.SetReadOnly(true)\n\tbutton.OnClicked(func(*ui.Button) {\n\t\tfilename := ui.OpenFile(mainwin)\n\t\tif filename == \"\" {\n\t\t\tfilename = \"(cancelled)\"\n\t\t}\n\t\tentry.SetText(filename)\n\t})\n\tgrid.Append(button,\n\t\t0, 0, 1, 1,\n\t\tfalse, ui.AlignFill, false, ui.AlignFill)\n\tgrid.Append(entry,\n\t\t1, 0, 1, 1,\n\t\ttrue, ui.AlignFill, false, ui.AlignFill)\n\n\tbutton = ui.NewButton(\"Save File\")\n\tentry2 := ui.NewEntry()\n\tentry2.SetReadOnly(true)\n\tbutton.OnClicked(func(*ui.Button) {\n\t\tfilename := ui.SaveFile(mainwin)\n\t\tif filename == \"\" {\n\t\t\tfilename = \"(cancelled)\"\n\t\t}\n\t\tentry2.SetText(filename)\n\t})\n\tgrid.Append(button,\n\t\t0, 1, 1, 1,\n\t\tfalse, ui.AlignFill, false, ui.AlignFill)\n\tgrid.Append(entry2,\n\t\t1, 1, 1, 1,\n\t\ttrue, ui.AlignFill, false, ui.AlignFill)\n\n\tmsggrid := ui.NewGrid()\n\tmsggrid.SetPadded(true)\n\tgrid.Append(msggrid,\n\t\t0, 2, 2, 1,\n\t\tfalse, ui.AlignCenter, false, ui.AlignStart)\n\n\tbutton = ui.NewButton(\"Message Box\")\n\tbutton.OnClicked(func(*ui.Button) {\n\t\tui.MsgBox(mainwin,\n\t\t\t\"This is a normal message box.\",\n\t\t\t\"More detailed information can be shown here.\")\n\t})\n\tmsggrid.Append(button,\n\t\t0, 0, 1, 1,\n\t\tfalse, ui.AlignFill, false, ui.AlignFill)\n\tbutton = ui.NewButton(\"Error Box\")\n\tbutton.OnClicked(func(*ui.Button) {\n\t\tui.MsgBoxError(mainwin,\n\t\t\t\"This message box describes an error.\",\n\t\t\t\"More detailed information can be shown here.\")\n\t})\n\tmsggrid.Append(button,\n\t\t1, 0, 1, 1,\n\t\tfalse, ui.AlignFill, false, ui.AlignFill)\n\n\treturn hbox\n}\n\nfunc setupUI() {\n\tmainwin = ui.NewWindow(\"libui Control Gallery\", 640, 480, true)\n\tmainwin.OnClosing(func(*ui.Window) bool {\n\t\tui.Quit()\n\t\treturn true\n\t})\n\tui.OnShouldQuit(func() bool {\n\t\tmainwin.Destroy()\n\t\treturn true\n\t})\n\n\ttab := ui.NewTab()\n\tmainwin.SetChild(tab)\n\tmainwin.SetMargined(true)\n\n\ttab.Append(\"Basic Controls\", makeBasicControlsPage())\n\ttab.SetMargined(0, true)\n\n\ttab.Append(\"Numbers and Lists\", makeNumbersPage())\n\ttab.SetMargined(1, true)\n\n\ttab.Append(\"Data Choosers\", makeDataChoosersPage())\n\ttab.SetMargined(2, true)\n\n\tmainwin.Show()\n}\n\nfunc main() {\n\tui.Main(setupUI)\n}\n"
  },
  {
    "path": "examples/drawtext.go",
    "content": "// 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 to a crash\n\nimport (\n\t\"github.com/andlabs/ui\"\n\t_ \"github.com/andlabs/ui/winmanifest\"\n)\n\nvar (\n\tfontButton *ui.FontButton\n\talignment *ui.Combobox\n\n\tattrstr *ui.AttributedString\n)\n\nfunc appendWithAttributes(what string, attrs ...ui.Attribute) {\n\tstart := len(attrstr.String())\n\tend := start + len(what)\n\tattrstr.AppendUnattributed(what)\n\tfor _, a := range attrs {\n\t\tattrstr.SetAttribute(a, start, end)\n\t}\n}\n\nfunc makeAttributedString() {\n\tattrstr = ui.NewAttributedString(\n\t\t\"Drawing strings with package ui is done with the ui.AttributedString and ui.DrawTextLayout objects.\\n\" +\n\t\t\"ui.AttributedString lets you have a variety of attributes: \")\n\n\tappendWithAttributes(\"font family\", ui.TextFamily(\"Courier New\"))\n\tattrstr.AppendUnattributed(\", \")\n\n\tappendWithAttributes(\"font size\", ui.TextSize(18))\n\tattrstr.AppendUnattributed(\", \")\n\n\tappendWithAttributes(\"font weight\", ui.TextWeightBold)\n\tattrstr.AppendUnattributed(\", \")\n\n\tappendWithAttributes(\"font italicness\", ui.TextItalicItalic)\n\tattrstr.AppendUnattributed(\", \")\n\n\tappendWithAttributes(\"font stretch\", ui.TextStretchCondensed)\n\tattrstr.AppendUnattributed(\", \")\n\n\tappendWithAttributes(\"text color\", ui.TextColor{0.75, 0.25, 0.5, 0.75})\n\tattrstr.AppendUnattributed(\", \")\n\n\tappendWithAttributes(\"text background color\", ui.TextBackground{0.5, 0.5, 0.25, 0.5})\n\tattrstr.AppendUnattributed(\", \")\n\n\tappendWithAttributes(\"underline style\", ui.UnderlineSingle)\n\tattrstr.AppendUnattributed(\", \")\n\n\tattrstr.AppendUnattributed(\"and \")\n\tappendWithAttributes(\"underline color\",\n\t\tui.UnderlineDouble,\n\t\tui.UnderlineColorCustom{1.0, 0.0, 0.5, 1.0})\n\tattrstr.AppendUnattributed(\". \")\n\n\tattrstr.AppendUnattributed(\"Furthermore, there are attributes allowing for \")\n\tappendWithAttributes(\"special underlines for indicating spelling errors\",\n\t\tui.UnderlineSuggestion,\n\t\tui.UnderlineColorSpelling)\n\tattrstr.AppendUnattributed(\" (and other types of errors) \")\n\n\tattrstr.AppendUnattributed(\"and control over OpenType features such as ligatures (for instance, \")\n\tappendWithAttributes(\"afford\", ui.OpenTypeFeatures{\n\t\tui.ToOpenTypeTag('l', 'i', 'g', 'a'):\t\t0,\n\t})\n\tattrstr.AppendUnattributed(\" vs. \")\n\tappendWithAttributes(\"afford\", ui.OpenTypeFeatures{\n\t\tui.ToOpenTypeTag('l', 'i', 'g', 'a'):\t\t1,\n\t})\n\tattrstr.AppendUnattributed(\").\\n\")\n\n\tattrstr.AppendUnattributed(\"Use the controls opposite to the text to control properties of the text.\")\n}\n\ntype areaHandler struct{}\n\nfunc (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) {\n\ttl := ui.DrawNewTextLayout(&ui.DrawTextLayoutParams{\n\t\tString:\t\tattrstr,\n\t\tDefaultFont:\tfontButton.Font(),\n\t\tWidth:\t\tp.AreaWidth,\n\t\tAlign:\t\tui.DrawTextAlign(alignment.Selected()),\n\t})\n\tdefer tl.Free()\n\tp.Context.Text(tl, 0, 0)\n}\n\nfunc (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {\n\t// do nothing\n}\n\nfunc (areaHandler) MouseCrossed(a *ui.Area, left bool) {\n\t// do nothing\n}\n\nfunc (areaHandler) DragBroken(a *ui.Area) {\n\t// do nothing\n}\n\nfunc (areaHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {\n\t// reject all keys\n\treturn false\n}\n\nfunc setupUI() {\n\tmakeAttributedString()\n\n\tmainwin := ui.NewWindow(\"libui Text-Drawing Example\", 640, 480, true)\n\tmainwin.SetMargined(true)\n\tmainwin.OnClosing(func(*ui.Window) bool {\n\t\tmainwin.Destroy()\n\t\tui.Quit()\n\t\treturn false\n\t})\n\tui.OnShouldQuit(func() bool {\n\t\tmainwin.Destroy()\n\t\treturn true\n\t})\n\n\thbox := ui.NewHorizontalBox()\n\thbox.SetPadded(true)\n\tmainwin.SetChild(hbox)\n\n\tvbox := ui.NewVerticalBox()\n\tvbox.SetPadded(true)\n\thbox.Append(vbox, false)\n\n\tarea := ui.NewArea(areaHandler{})\n\n\tfontButton = ui.NewFontButton()\n\tfontButton.OnChanged(func(*ui.FontButton) {\n\t\tarea.QueueRedrawAll()\n\t})\n\tvbox.Append(fontButton, false)\n\n\tform := ui.NewForm()\n\tform.SetPadded(true)\n\t// 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?\n\tvbox.Append(form, false)\n\n\talignment = ui.NewCombobox()\n\t// note that the items match with the values of the uiDrawTextAlign values\n\talignment.Append(\"Left\")\n\talignment.Append(\"Center\")\n\talignment.Append(\"Right\")\n\talignment.SetSelected(0)\t\t// start with left alignment\n\talignment.OnSelected(func(*ui.Combobox) {\n\t\tarea.QueueRedrawAll()\n\t})\n\tform.Append(\"Alignment\", alignment, false)\n\n\thbox.Append(area, true)\n\n\tmainwin.Show()\n}\n\nfunc main() {\n\tui.Main(setupUI)\n}\n"
  },
  {
    "path": "examples/histogram.go",
    "content": "// 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/andlabs/ui/winmanifest\"\n)\n\nvar (\n\thistogram *ui.Area\n\tdatapoints [10]*ui.Spinbox\n\tcolorButton *ui.ColorButton\n\n\tcurrentPoint = -1\n)\n\n// some metrics\nconst (\n\txoffLeft = 20\t\t// histogram margins\n\tyoffTop = 20\n\txoffRight = 20\n\tyoffBottom = 20\n\tpointRadius = 5\n)\n\n// helper to quickly set a brush color\nfunc mkSolidBrush(color uint32, alpha float64) *ui.DrawBrush {\n\tbrush := new(ui.DrawBrush)\n\tbrush.Type = ui.DrawBrushTypeSolid\n\tcomponent := uint8((color >> 16) & 0xFF)\n\tbrush.R = float64(component) / 255\n\tcomponent = uint8((color >> 8) & 0xFF)\n\tbrush.G = float64(component) / 255\n\tcomponent = uint8(color & 0xFF)\n\tbrush.B = float64(component) / 255\n\tbrush.A = alpha\n\treturn brush\n}\n\n// and some colors\n// names and values from https://msdn.microsoft.com/en-us/library/windows/desktop/dd370907%28v=vs.85%29.aspx\nconst (\n\tcolorWhite = 0xFFFFFF\n\tcolorBlack = 0x000000\n\tcolorDodgerBlue = 0x1E90FF\n)\n\nfunc pointLocations(width, height float64) (xs, ys [10]float64) {\n\txincr := width / 9\t\t// 10 - 1 to make the last point be at the end\n\tyincr := height / 100\n\tfor i := 0; i < 10; i++ {\n\t\t// get the value of the point\n\t\tn := datapoints[i].Value()\n\t\t// because y=0 is the top but n=0 is the bottom, we need to flip\n\t\tn = 100 - n\n\t\txs[i] = xincr * float64(i)\n\t\tys[i] = yincr * float64(n)\n\t}\n\treturn xs, ys\n}\n\nfunc constructGraph(width, height float64, extend bool) *ui.DrawPath {\n\txs, ys := pointLocations(width, height)\n\tpath := ui.DrawNewPath(ui.DrawFillModeWinding)\n\n\tpath.NewFigure(xs[0], ys[0])\n\tfor i := 1; i < 10; i++ {\n\t\tpath.LineTo(xs[i], ys[i])\n\t}\n\n\tif extend {\n\t\tpath.LineTo(width, height)\n\t\tpath.LineTo(0, height)\n\t\tpath.CloseFigure()\n\t}\n\n\tpath.End()\n\treturn path\n}\n\nfunc graphSize(clientWidth, clientHeight float64) (graphWidth, graphHeight float64) {\n\treturn clientWidth - xoffLeft - xoffRight,\n\t\tclientHeight - yoffTop - yoffBottom\n}\n\ntype areaHandler struct{}\n\nfunc (areaHandler) Draw(a *ui.Area, p *ui.AreaDrawParams) {\n\t// fill the area with white\n\tbrush := mkSolidBrush(colorWhite, 1.0)\n\tpath := ui.DrawNewPath(ui.DrawFillModeWinding)\n\tpath.AddRectangle(0, 0, p.AreaWidth, p.AreaHeight)\n\tpath.End()\n\tp.Context.Fill(path, brush)\n\tpath.Free()\n\n\tgraphWidth, graphHeight := graphSize(p.AreaWidth, p.AreaHeight)\n\n\tsp := &ui.DrawStrokeParams{\n\t\tCap:\t\t\tui.DrawLineCapFlat,\n\t\tJoin:\t\t\tui.DrawLineJoinMiter,\n\t\tThickness:\t2,\n\t\tMiterLimit:\tui.DrawDefaultMiterLimit,\n\t}\n\n\t// draw the axes\n\tbrush = mkSolidBrush(colorBlack, 1.0)\n\tpath = ui.DrawNewPath(ui.DrawFillModeWinding)\n\tpath.NewFigure(xoffLeft, yoffTop)\n\tpath.LineTo(xoffLeft, yoffTop + graphHeight)\n\tpath.LineTo(xoffLeft + graphWidth, yoffTop + graphHeight)\n\tpath.End()\n\tp.Context.Stroke(path, brush, sp)\n\tpath.Free()\n\n\t// now transform the coordinate space so (0, 0) is the top-left corner of the graph\n\tm := ui.DrawNewMatrix()\n\tm.Translate(xoffLeft, yoffTop)\n\tp.Context.Transform(m)\n\n\t// now get the color for the graph itself and set up the brush\n\tgraphR, graphG, graphB, graphA := colorButton.Color()\n\tbrush.Type = ui.DrawBrushTypeSolid\n\tbrush.R = graphR\n\tbrush.G = graphG\n\tbrush.B = graphB\n\t// we set brush.A below to different values for the fill and stroke\n\n\t// now create the fill for the graph below the graph line\n\tpath = constructGraph(graphWidth, graphHeight, true)\n\tbrush.A = graphA / 2\n\tp.Context.Fill(path, brush)\n\tpath.Free()\n\n\t// now draw the histogram line\n\tpath = constructGraph(graphWidth, graphHeight, false)\n\tbrush.A = graphA\n\tp.Context.Stroke(path, brush, sp)\n\tpath.Free()\n\n\t// now draw the point being hovered over\n\tif currentPoint != -1 {\n\t\txs, ys := pointLocations(graphWidth, graphHeight)\n\t\tpath = ui.DrawNewPath(ui.DrawFillModeWinding)\n\t\tpath.NewFigureWithArc(\n\t\t\txs[currentPoint], ys[currentPoint],\n\t\t\tpointRadius,\n\t\t\t0, 6.23,\t\t// TODO pi\n\t\t\tfalse)\n\t\tpath.End()\n\t\t// use the same brush as for the histogram lines\n\t\tp.Context.Fill(path, brush)\n\t\tpath.Free()\n\t}\n}\n\nfunc inPoint(x, y float64, xtest, ytest float64) bool {\n\t// TODO switch to using a matrix\n\tx -= xoffLeft\n\ty -= yoffTop\n\treturn (x >= xtest - pointRadius) &&\n\t\t(x <= xtest + pointRadius) &&\n\t\t(y >= ytest - pointRadius) &&\n\t\t(y <= ytest + pointRadius)\n}\n\nfunc (areaHandler) MouseEvent(a *ui.Area, me *ui.AreaMouseEvent) {\n\tgraphWidth, graphHeight := graphSize(me.AreaWidth, me.AreaHeight)\n\txs, ys := pointLocations(graphWidth, graphHeight)\n\n\tcurrentPoint = -1\n\tfor i := 0; i < 10; i++ {\n\t\tif inPoint(me.X, me.Y, xs[i], ys[i]) {\n\t\t\tcurrentPoint = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// TODO only redraw the relevant area\n\thistogram.QueueRedrawAll()\n}\n\nfunc (areaHandler) MouseCrossed(a *ui.Area, left bool) {\n\t// do nothing\n}\n\nfunc (areaHandler) DragBroken(a *ui.Area) {\n\t// do nothing\n}\n\nfunc (areaHandler) KeyEvent(a *ui.Area, ke *ui.AreaKeyEvent) (handled bool) {\n\t// reject all keys\n\treturn false\n}\n\nfunc setupUI() {\n\tmainwin := ui.NewWindow(\"libui Histogram Example\", 640, 480, true)\n\tmainwin.SetMargined(true)\n\tmainwin.OnClosing(func(*ui.Window) bool {\n\t\tmainwin.Destroy()\n\t\tui.Quit()\n\t\treturn false\n\t})\n\tui.OnShouldQuit(func() bool {\n\t\tmainwin.Destroy()\n\t\treturn true\n\t})\n\n\thbox := ui.NewHorizontalBox()\n\thbox.SetPadded(true)\n\tmainwin.SetChild(hbox)\n\n\tvbox := ui.NewVerticalBox()\n\tvbox.SetPadded(true)\n\thbox.Append(vbox, false)\n\n\thistogram = ui.NewArea(areaHandler{})\n\n\trand.Seed(time.Now().Unix())\n\tfor i := 0; i < 10; i++ {\n\t\tdatapoints[i] = ui.NewSpinbox(0, 100)\n\t\tdatapoints[i].SetValue(rand.Intn(101))\n\t\tdatapoints[i].OnChanged(func(*ui.Spinbox) {\n\t\t\thistogram.QueueRedrawAll()\n\t\t})\n\t\tvbox.Append(datapoints[i], false)\n\t}\n\n\tcolorButton = ui.NewColorButton()\n\t// TODO inline these\n\tbrush := mkSolidBrush(colorDodgerBlue, 1.0)\n\tcolorButton.SetColor(brush.R,\n\t\tbrush.G,\n\t\tbrush.B,\n\t\tbrush.A)\n\tcolorButton.OnChanged(func(*ui.ColorButton) {\n\t\thistogram.QueueRedrawAll()\n\t})\n\tvbox.Append(colorButton, false)\n\n\thbox.Append(histogram, true)\n\n\tmainwin.Show()\n}\n\nfunc main() {\n\tui.Main(setupUI)\n}\n"
  },
  {
    "path": "examples/table.go",
    "content": "// 26 august 2018\n\n// +build OMIT\n\n// TODO possible bugs in libui:\n// - the checkboxes on macOS retain their values when they shouldn't\n// - the table on GTK+ is very thin; the scrolled window needs hexpand=TRUE\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\t_ \"image/png\"\n\t\"image/draw\"\n\t\"bytes\"\n\n\t\"github.com/andlabs/ui\"\n\t_ \"github.com/andlabs/ui/winmanifest\"\n)\n\ntype modelHandler struct {\n\trow9Text\t\tstring\n\tyellowRow\tint\n\tcheckStates\t[15]int\n}\n\nfunc newModelHandler() *modelHandler {\n\tm := new(modelHandler)\n\tm.row9Text = \"You can edit this one\"\n\tm.yellowRow = -1\n\treturn m\n}\n\nfunc (mh *modelHandler) ColumnTypes(m *ui.TableModel) []ui.TableValue {\n\treturn []ui.TableValue{\n\t\tui.TableString(\"\"),\t\t// column 0 text\n\t\tui.TableString(\"\"),\t\t// column 1 text\n\t\tui.TableString(\"\"),\t\t// column 2 text\n\t\tui.TableColor{},\t\t\t// row background color\n\t\tui.TableColor{},\t\t\t// column 1 text color\n\t\tui.TableImage{},\t\t// column 1 image\n\t\tui.TableString(\"\"),\t\t// column 4 button text\n\t\tui.TableInt(0),\t\t\t// column 3 checkbox state\n\t\tui.TableInt(0),\t\t\t// column 5 progress\n\t}\n}\n\nfunc (mh *modelHandler) NumRows(m *ui.TableModel) int {\n\treturn 15\n}\n\nvar img [2]*ui.Image\n\nfunc (mh *modelHandler) CellValue(m *ui.TableModel, row, column int) ui.TableValue {\n\tif column == 3 {\n\t\tif row == mh.yellowRow {\n\t\t\treturn ui.TableColor{1, 1, 0, 1}\n\t\t}\n\t\tif row == 3 {\n\t\t\treturn ui.TableColor{1, 0, 0, 1}\n\t\t}\n\t\tif row == 11 {\n\t\t\treturn ui.TableColor{0, 0.5, 1, 0.5}\n\t\t}\n\t\treturn nil\n\t}\n\tif column == 4 {\n\t\tif (row % 2) == 1 {\n\t\t\treturn ui.TableColor{0.5, 0, 0.75, 1}\n\t\t}\n\t\treturn nil\n\t}\n\tif column == 5 {\n\t\tif row < 8 {\n\t\t\treturn ui.TableImage{img[0]}\n\t\t}\n\t\treturn ui.TableImage{img[1]}\n\t}\n\tif column == 7 {\n\t\treturn ui.TableInt(mh.checkStates[row])\n\t}\n\tif column == 8 {\n\t\tif row == 0 {\n\t\t\treturn ui.TableInt(0)\n\t\t}\n\t\tif row == 13 {\n\t\t\treturn ui.TableInt(100)\n\t\t}\n\t\tif row == 14 {\n\t\t\treturn ui.TableInt(-1)\n\t\t}\n\t\treturn ui.TableInt(50)\n\t}\n\tswitch column {\n\tcase 0:\n\t\treturn ui.TableString(fmt.Sprintf(\"Row %d\", row))\n\tcase 2:\n\t\tif row == 9 {\n\t\t\treturn ui.TableString(mh.row9Text)\n\t\t}\n\t\treturn ui.TableString(\"Editing this won't change anything\")\n\tcase 1:\n\t\treturn ui.TableString(\"Colors!\")\n\tcase 6:\n\t\treturn ui.TableString(\"Make Yellow\")\n\t}\n\tpanic(\"unreachable\")\n}\n\nfunc (mh *modelHandler) SetCellValue(m *ui.TableModel, row, column int, value ui.TableValue) {\n\tif row == 9 && column == 2 {\n\t\tmh.row9Text = string(value.(ui.TableString))\n\t}\n\tif column == 6 {\t\t// row background color\n\t\tprevYellowRow := mh.yellowRow\n\t\tmh.yellowRow = row\n\t\tif prevYellowRow != -1 {\n\t\t\tm.RowChanged(prevYellowRow)\n\t\t}\n\t\tm.RowChanged(mh.yellowRow)\n\t}\n\tif column == 7 {\t\t// checkboxes\n\t\tmh.checkStates[row] = int(value.(ui.TableInt))\n\t}\n}\n\nfunc appendImageNamed(i *ui.Image, which string) {\n\tb := rawImages[which]\n\timg, _, err := image.Decode(bytes.NewReader(b))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tnr, ok := img.(*image.RGBA)\n\tif !ok {\n\t\ti2 := image.NewRGBA(img.Bounds())\n\t\tdraw.Draw(i2, i2.Bounds(), img, img.Bounds().Min, draw.Src)\n\t\tnr = i2\n\t}\n\ti.Append(nr)\n}\n\nfunc setupUI() {\n\tmainwin := ui.NewWindow(\"libui Control Gallery\", 640, 480, true)\n\tmainwin.OnClosing(func(*ui.Window) bool {\n\t\tui.Quit()\n\t\treturn true\n\t})\n\tui.OnShouldQuit(func() bool {\n\t\tmainwin.Destroy()\n\t\treturn true\n\t})\n\n\timg[0] = ui.NewImage(16, 16)\n\tappendImageNamed(img[0], \"andlabs_16x16test_24june2016.png\")\n\tappendImageNamed(img[0], \"andlabs_32x32test_24june2016.png\")\n\timg[1] = ui.NewImage(16, 16)\n\tappendImageNamed(img[1], \"tango-icon-theme-0.8.90_16x16_x-office-spreadsheet.png\")\n\tappendImageNamed(img[1], \"tango-icon-theme-0.8.90_32x32_x-office-spreadsheet.png\")\n\n\tmh := newModelHandler()\n\tmodel := ui.NewTableModel(mh)\n\n\ttable := ui.NewTable(&ui.TableParams{\n\t\tModel:\tmodel,\n\t\tRowBackgroundColorModelColumn:\t3,\n\t})\n\tmainwin.SetChild(table)\n\tmainwin.SetMargined(true)\n\n\ttable.AppendTextColumn(\"Column 1\",\n\t\t0, ui.TableModelColumnNeverEditable, nil)\n\n\ttable.AppendImageTextColumn(\"Column 2\",\n\t\t5,\n\t\t1, ui.TableModelColumnNeverEditable, &ui.TableTextColumnOptionalParams{\n\t\t\tColorModelColumn:\t\t4,\n\t\t});\n\ttable.AppendTextColumn(\"Editable\",\n\t\t2, ui.TableModelColumnAlwaysEditable, nil)\n\n\ttable.AppendCheckboxColumn(\"Checkboxes\",\n\t\t7, ui.TableModelColumnAlwaysEditable)\n\ttable.AppendButtonColumn(\"Buttons\",\n\t\t6, ui.TableModelColumnAlwaysEditable)\n\n\ttable.AppendProgressBarColumn(\"Progress Bar\",\n\t\t8)\n\n\tmainwin.Show()\n}\n\nfunc main() {\n\tui.Main(setupUI)\n}\n\nvar rawImages = map[string][]byte{\n\t\"andlabs_16x16test_24june2016.png\": []byte{\n  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,\n  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n  0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00, 0x00, 0x00,\n  0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,\n  0x00, 0xca, 0x49, 0x44, 0x41, 0x54, 0x38, 0x11, 0xa5, 0x93, 0xb1, 0x0d,\n  0xc2, 0x40, 0x0c, 0x45, 0x1d, 0xc4, 0x14, 0x0c, 0x12, 0x41, 0x0f, 0x62,\n  0x12, 0x46, 0x80, 0x8a, 0x2e, 0x15, 0x30, 0x02, 0x93, 0x20, 0x68, 0x11,\n  0x51, 0x06, 0x61, 0x0d, 0x88, 0x2d, 0x7f, 0xdb, 0x07, 0x87, 0x08, 0xdc,\n  0x49, 0x91, 0x7d, 0xf6, 0xf7, 0xf3, 0x4f, 0xa4, 0x54, 0xbb, 0xeb, 0xf6,\n  0x41, 0x05, 0x67, 0xcc, 0xb3, 0x9b, 0xfa, 0xf6, 0x17, 0x62, 0xdf, 0xcd,\n  0x48, 0x00, 0x32, 0xbd, 0xa8, 0x1d, 0x72, 0xee, 0x3c, 0x47, 0x16, 0xfb,\n  0x5c, 0x53, 0x8d, 0x03, 0x30, 0x14, 0x84, 0xf7, 0xd5, 0x89, 0x26, 0xc7,\n  0x25, 0x10, 0x36, 0xe4, 0x05, 0xa2, 0x51, 0xbc, 0xc4, 0x1c, 0xc3, 0x1c,\n  0xed, 0x30, 0x1c, 0x8f, 0x16, 0x3f, 0x02, 0x78, 0x33, 0x20, 0x06, 0x60,\n  0x97, 0x70, 0xaa, 0x45, 0x7f, 0x85, 0x60, 0x5d, 0xb6, 0xf4, 0xc2, 0xc4,\n  0x3e, 0x0f, 0x44, 0xcd, 0x1b, 0x20, 0x90, 0x0f, 0xed, 0x85, 0xa8, 0x55,\n  0x05, 0x42, 0x43, 0xb4, 0x9e, 0xce, 0x71, 0xb3, 0xe8, 0x0e, 0xb4, 0xc4,\n  0xc3, 0x39, 0x21, 0xb7, 0x73, 0xbd, 0xe4, 0x1b, 0xe4, 0x04, 0xb6, 0xaa,\n  0x4f, 0x18, 0x2c, 0xee, 0x42, 0x31, 0x01, 0x84, 0xfa, 0xe0, 0xd4, 0x00,\n  0xdf, 0xb6, 0x83, 0xf8, 0xea, 0xc2, 0x00, 0x10, 0xfc, 0x1a, 0x05, 0x30,\n  0x74, 0x3b, 0xe0, 0xd1, 0x45, 0xb1, 0x83, 0xaa, 0xf4, 0x77, 0x7e, 0x02,\n  0x87, 0x1f, 0x42, 0x7f, 0x9e, 0x2b, 0xe8, 0xdf, 0x00, 0x00, 0x00, 0x00,\n  0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,\n},\n\t\"andlabs_32x32test_24june2016.png\": []byte{\n  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,\n  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,\n  0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x00,\n  0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,\n  0x01, 0x6a, 0x49, 0x44, 0x41, 0x54, 0x58, 0x09, 0xc5, 0x97, 0xc1, 0x0d,\n  0xc2, 0x30, 0x0c, 0x45, 0x03, 0x62, 0x0a, 0x06, 0x41, 0x70, 0x07, 0x31,\n  0x09, 0x23, 0xc0, 0x89, 0x05, 0x80, 0x11, 0x98, 0x04, 0xc1, 0x15, 0x81,\n  0x18, 0x84, 0x35, 0x00, 0x57, 0xfd, 0x8d, 0x13, 0x92, 0x3a, 0x4e, 0x03,\n  0x8d, 0x54, 0x39, 0x35, 0xb1, 0xff, 0x8b, 0xed, 0x1e, 0x18, 0xec, 0xae,\n  0xdb, 0x97, 0xe9, 0x71, 0x8d, 0x48, 0x7b, 0x33, 0xb9, 0xf5, 0x82, 0xb0,\n  0x7f, 0xcc, 0x4c, 0x05, 0x50, 0xa9, 0x2f, 0x26, 0x32, 0xc4, 0xf9, 0x21,\n  0x9f, 0xa1, 0x13, 0x8a, 0x5c, 0x16, 0x40, 0x4a, 0x9e, 0x92, 0x14, 0x78,\n  0x8a, 0x5c, 0x43, 0xc4, 0xf4, 0x65, 0x3b, 0x01, 0x3c, 0x57, 0x27, 0x43,\n  0x4f, 0x97, 0x95, 0x0d, 0x40, 0xc2, 0xe3, 0xe3, 0xb2, 0x7a, 0xba, 0x40,\n  0xd8, 0x19, 0x50, 0x5c, 0x03, 0xe2, 0x08, 0x21, 0x10, 0xdf, 0xd7, 0x3a,\n  0x88, 0x6c, 0x46, 0xd4, 0x00, 0x5f, 0x42, 0x35, 0x85, 0x03, 0x41, 0x03,\n  0xcb, 0x44, 0x00, 0x1a, 0xb2, 0x2e, 0x80, 0x66, 0xd2, 0x43, 0xd9, 0x32,\n  0x7c, 0x2e, 0x40, 0x1b, 0x75, 0x0d, 0xe7, 0xdc, 0x94, 0x09, 0xc6, 0x2a,\n  0xc3, 0x8e, 0x04, 0xb7, 0x59, 0x43, 0x08, 0x08, 0x64, 0xcc, 0x15, 0xa7,\n  0x78, 0x5b, 0x01, 0x45, 0xdf, 0x28, 0x90, 0x43, 0xd0, 0x3e, 0x77, 0x59,\n  0x80, 0x8c, 0x0c, 0x5d, 0x84, 0x21, 0xe7, 0x02, 0x94, 0x1c, 0x42, 0x29,\n  0x57, 0x3d, 0x6f, 0x16, 0xa0, 0x6d, 0x00, 0x81, 0xcb, 0xec, 0xe1, 0x7e,\n  0x61, 0x6f, 0xc6, 0xac, 0xa7, 0x73, 0xfb, 0xae, 0xc8, 0x65, 0x01, 0x6c,\n  0xb8, 0xb8, 0x23, 0x71, 0x47, 0xf0, 0x13, 0x11, 0xf2, 0x89, 0x89, 0x3e,\n  0x07, 0xd4, 0x5f, 0x41, 0x4c, 0x88, 0x80, 0xfc, 0xaa, 0x14, 0x07, 0x88,\n  0x89, 0x43, 0x28, 0x07, 0x42, 0x5d, 0x01, 0x88, 0x95, 0xb2, 0xc9, 0x00,\n  0xd2, 0xed, 0x01, 0xa4, 0xad, 0x82, 0x38, 0x84, 0xe8, 0xab, 0x3f, 0x74,\n  0x10, 0x0c, 0x59, 0x0e, 0x21, 0xc5, 0xb5, 0x02, 0xa4, 0xde, 0x3a, 0x06,\n  0x41, 0x7e, 0x29, 0x47, 0x72, 0x0b, 0x42, 0x22, 0x25, 0x7c, 0x51, 0x00,\n  0x89, 0x3c, 0x55, 0x9c, 0xb7, 0x23, 0x14, 0xf3, 0xd5, 0x82, 0x9c, 0x9e,\n  0x87, 0x12, 0x73, 0x1f, 0x87, 0xf0, 0x67, 0xc2, 0x01, 0x28, 0x75, 0x6b,\n  0x2e, 0x8e, 0x3d, 0x84, 0x7d, 0x8d, 0x68, 0x0b, 0x10, 0xf8, 0x6b, 0xdb,\n  0x00, 0xf8, 0x64, 0xbf, 0x12, 0xe6, 0xed, 0x20, 0x8d, 0x0a, 0xe0, 0x5f,\n  0xe2, 0xb8, 0x14, 0x87, 0x68, 0x2a, 0x80, 0x1f, 0xff, 0x6d, 0x07, 0x7d,\n  0xff, 0x3d, 0x7f, 0x03, 0x93, 0xca, 0x91, 0xa9, 0x89, 0x2a, 0x2e, 0xd2,\n  0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,\n},\n\t\"tango-icon-theme-0.8.90_16x16_x-office-spreadsheet.png\": []byte{\n  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,\n  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n  0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00, 0x00, 0x00,\n  0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0,\n  0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00,\n  0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18,\n  0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x16,\n  0x14, 0x0d, 0x09, 0xd9, 0x88, 0x44, 0xfa, 0x00, 0x00, 0x02, 0x4d, 0x49,\n  0x44, 0x41, 0x54, 0x38, 0xcb, 0x95, 0x92, 0xdf, 0x4b, 0x53, 0x61, 0x18,\n  0xc7, 0x3f, 0x67, 0x9b, 0x6e, 0x7a, 0xd6, 0xfc, 0x55, 0xe0, 0x59, 0x8a,\n  0x95, 0x71, 0x08, 0x52, 0x21, 0x91, 0x2c, 0x8a, 0x0a, 0x94, 0x11, 0x14,\n  0x78, 0x21, 0x99, 0x14, 0x81, 0xdd, 0x48, 0x7f, 0x45, 0x63, 0x5d, 0x75,\n  0x1b, 0x34, 0xd0, 0x9b, 0x52, 0x83, 0x0a, 0xad, 0x0b, 0x43, 0x72, 0xd0,\n  0x85, 0x14, 0x14, 0x68, 0x77, 0x39, 0xcd, 0x6c, 0x94, 0x0c, 0xf4, 0x48,\n  0x4d, 0x5b, 0x5b, 0x4b, 0xcf, 0x39, 0x3b, 0xef, 0xe9, 0x62, 0x3f, 0xec,\n  0xd7, 0x2e, 0x7c, 0xae, 0xbe, 0x2f, 0xef, 0xf3, 0xfd, 0xbc, 0xdf, 0xf7,\n  0x7d, 0x5e, 0x69, 0x78, 0x78, 0xf8, 0xc9, 0xfa, 0xfa, 0x7a, 0x2f, 0xbb,\n  0xab, 0xcb, 0xc1, 0x60, 0x70, 0x1c, 0x80, 0x50, 0x28, 0x64, 0xef, 0xb6,\n  0x42, 0xa1, 0x90, 0x5d, 0x20, 0xb9, 0x0a, 0x22, 0x12, 0x89, 0xe4, 0x95,\n  0x84, 0xa6, 0x69, 0xf8, 0xfd, 0x0a, 0x00, 0x9a, 0xa6, 0xa1, 0x28, 0xfe,\n  0xbc, 0x5e, 0x63, 0x60, 0x60, 0xe0, 0x8f, 0x28, 0x45, 0x80, 0xa6, 0x69,\n  0x48, 0x52, 0x0e, 0x20, 0x49, 0xb9, 0xf5, 0xce, 0xde, 0x5a, 0xc9, 0xbb,\n  0x14, 0x01, 0x8a, 0x5f, 0xc1, 0x2b, 0x7b, 0x01, 0x88, 0xc5, 0x62, 0xf4,\n  0xf4, 0xf4, 0x00, 0x10, 0x8d, 0x46, 0x69, 0x69, 0x6d, 0x41, 0xb2, 0x25,\n  0xe6, 0xa3, 0xf3, 0xa5, 0x01, 0x86, 0x6e, 0x90, 0x21, 0x83, 0x84, 0x04,\n  0x40, 0x2a, 0x95, 0x22, 0x2f, 0x49, 0x7f, 0x4f, 0x91, 0x8f, 0x57, 0x1a,\n  0xe0, 0x71, 0xbb, 0x91, 0xbd, 0x5e, 0x0a, 0xaf, 0xe3, 0xf3, 0x55, 0x15,\n  0xfc, 0xf8, 0xaa, 0x76, 0x74, 0x49, 0xc0, 0xb6, 0xae, 0xe7, 0x4f, 0xcc,\n  0xb5, 0x7e, 0x8c, 0x3c, 0x67, 0xf5, 0xee, 0x1d, 0xb6, 0x16, 0x16, 0x89,\n  0xa7, 0x33, 0xb9, 0x26, 0xb9, 0x82, 0xc9, 0xb6, 0x56, 0xbc, 0x6d, 0xed,\n  0xff, 0x49, 0xe0, 0xf1, 0x20, 0xcb, 0x32, 0x00, 0xf6, 0xe8, 0x3d, 0x3e,\n  0xcd, 0xcd, 0xd1, 0x74, 0xe5, 0x22, 0x65, 0x9d, 0x2a, 0xc2, 0x21, 0x91,\n  0x15, 0x02, 0xc3, 0x14, 0x48, 0x0e, 0x0f, 0x4d, 0xcf, 0xa6, 0x78, 0x74,\n  0xbc, 0xe3, 0x65, 0xff, 0xec, 0xdb, 0xfe, 0x22, 0x40, 0xd7, 0x75, 0x00,\n  0x36, 0x1e, 0x8c, 0x51, 0xb3, 0xb2, 0x4c, 0xc3, 0x8d, 0x3e, 0xb2, 0xe9,\n  0x24, 0xc9, 0xf8, 0x2a, 0xa6, 0x10, 0x18, 0x96, 0x8d, 0xb3, 0xaa, 0x16,\n  0x53, 0x08, 0xac, 0x4e, 0x15, 0xe7, 0xd2, 0xea, 0x99, 0x11, 0xf5, 0xf0,\n  0xed, 0x22, 0xc0, 0xed, 0x76, 0x23, 0xcb, 0x32, 0x89, 0xc8, 0x34, 0xfb,\n  0xaf, 0x9e, 0xe7, 0x47, 0x3c, 0x56, 0x34, 0x9a, 0x42, 0xf0, 0xa1, 0xfe,\n  0x10, 0x9b, 0x86, 0x0b, 0x53, 0x64, 0x31, 0x24, 0x0b, 0xef, 0xb1, 0x7a,\n  0xd4, 0xa7, 0x93, 0x7d, 0xff, 0x24, 0xb0, 0x37, 0xbf, 0x61, 0x19, 0x5b,\n  0xe8, 0xd6, 0x8e, 0x59, 0x52, 0xca, 0xd9, 0xd3, 0xe1, 0x26, 0xfc, 0xb5,\n  0x0b, 0xc3, 0xd4, 0x51, 0x6b, 0xbd, 0x08, 0xcb, 0xe4, 0xe8, 0xe8, 0x43,\n  0x8f, 0xe3, 0xef, 0x04, 0x66, 0x75, 0x0d, 0xce, 0x7d, 0x0d, 0xe0, 0xab,\n  0x41, 0x17, 0x16, 0xba, 0x25, 0x70, 0xaa, 0x95, 0x34, 0x37, 0xa7, 0xa9,\n  0xcf, 0xae, 0x71, 0xb2, 0x71, 0x2f, 0x5f, 0x52, 0x29, 0x7c, 0x2b, 0xef,\n  0xc9, 0x78, 0x3c, 0xdb, 0xc5, 0x04, 0x81, 0x40, 0x20, 0x37, 0x8d, 0xc1,\n  0x41, 0xde, 0xdd, 0x1f, 0xe3, 0xe0, 0xf5, 0x5e, 0xea, 0x0e, 0x1c, 0xc1,\n  0x76, 0xb9, 0xa8, 0x3e, 0x5d, 0x87, 0xa8, 0x70, 0x10, 0xec, 0x90, 0x78,\n  0xfc, 0x39, 0x4d, 0x63, 0x7c, 0x91, 0xf6, 0xc9, 0x09, 0x2a, 0x55, 0x75,\n  0x5c, 0x0a, 0x87, 0xc3, 0x53, 0x89, 0x44, 0xe2, 0xc2, 0xef, 0xb3, 0xad,\n  0x9d, 0x99, 0x41, 0x7e, 0xf3, 0x1a, 0xf3, 0xdc, 0x09, 0xca, 0x1a, 0xaa,\n  0xf1, 0x9c, 0xb5, 0xd1, 0x0d, 0x41, 0x66, 0xc3, 0x64, 0x7a, 0x4a, 0xd0,\n  0x33, 0xfb, 0x8a, 0x0a, 0x55, 0x7d, 0x71, 0x6d, 0x61, 0x21, 0x50, 0xea,\n  0x7f, 0x30, 0xd2, 0xdd, 0x7d, 0x49, 0x5f, 0x5a, 0xba, 0xe9, 0x4e, 0x26,\n  0x55, 0xe7, 0xcf, 0x4c, 0xb9, 0x6d, 0x83, 0x90, 0x65, 0xc3, 0xa5, 0x28,\n  0xcb, 0x07, 0xbb, 0xba, 0x6e, 0x9d, 0x1a, 0x1a, 0x9a, 0x00, 0xf8, 0x05,\n  0xf4, 0xf5, 0x23, 0xe9, 0x30, 0xeb, 0x2d, 0xf9, 0x00, 0x00, 0x00, 0x00,\n  0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,\n},\n\t\"tango-icon-theme-0.8.90_32x32_x-office-spreadsheet.png\": []byte{\n  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,\n  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,\n  0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x00,\n  0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,\n  0x88, 0x00, 0x00, 0x05, 0xa5, 0x49, 0x44, 0x41, 0x54, 0x58, 0x85, 0xe5,\n  0x97, 0xcd, 0x6b, 0x54, 0x57, 0x18, 0xc6, 0x7f, 0xe7, 0xde, 0x3b, 0x93,\n  0x51, 0x67, 0x92, 0x8c, 0x66, 0x32, 0x6a, 0x26, 0x4d, 0x94, 0x18, 0x27,\n  0xa9, 0x50, 0xbf, 0x5a, 0x2d, 0x94, 0x76, 0xd1, 0x85, 0x05, 0x41, 0x8b,\n  0x60, 0x75, 0x53, 0x70, 0x21, 0x0a, 0x55, 0xba, 0x71, 0x51, 0xa8, 0xb4,\n  0x7f, 0x40, 0xd7, 0xd5, 0x45, 0xa5, 0x90, 0x6e, 0x5a, 0xa8, 0x20, 0x34,\n  0x15, 0x0a, 0x6d, 0xa1, 0x25, 0x58, 0x2c, 0xa4, 0xd6, 0x42, 0x4d, 0xa2,\n  0xf9, 0x20, 0xc9, 0xc4, 0x64, 0x3e, 0x4c, 0xa2, 0x13, 0x93, 0xcc, 0xdc,\n  0xef, 0x2e, 0x32, 0xf7, 0xf4, 0xde, 0xc9, 0x97, 0x59, 0x74, 0xd5, 0x03,\n  0x87, 0x7b, 0xde, 0xf3, 0x9e, 0x73, 0xde, 0xe7, 0x3c, 0xef, 0xf3, 0xde,\n  0xb9, 0x03, 0xff, 0xf7, 0x26, 0xaa, 0x27, 0xae, 0x5d, 0xbb, 0x76, 0x4a,\n  0xd3, 0xb4, 0x2e, 0x20, 0xa6, 0xaa, 0x2a, 0x8a, 0xa2, 0xe0, 0x38, 0x0e,\n  0xb6, 0x6d, 0xcb, 0x6e, 0x59, 0x96, 0x7c, 0xfa, 0xc7, 0x6b, 0xcd, 0x01,\n  0xcf, 0x2d, 0xcb, 0x3a, 0xd7, 0xd5, 0xd5, 0x75, 0xcb, 0x1f, 0x4f, 0x5b,\n  0x86, 0x48, 0x88, 0x2f, 0xcf, 0x9f, 0x3f, 0x1f, 0xab, 0x8c, 0xe5, 0xbc,\n  0xeb, 0xba, 0x81, 0x75, 0x7e, 0xfb, 0x05, 0xc7, 0xb1, 0x4b, 0x97, 0x2e,\n  0x7d, 0x09, 0xac, 0x0d, 0xc0, 0xb6, 0xed, 0x7a, 0x80, 0xd1, 0xd1, 0x51,\n  0x84, 0x10, 0x12, 0x84, 0xff, 0xe9, 0x07, 0xe6, 0x1f, 0xaf, 0x64, 0x7b,\n  0x40, 0x1a, 0x1b, 0x1b, 0x31, 0x0c, 0xa3, 0xbe, 0xda, 0xb7, 0x0c, 0x80,\n  0xeb, 0xba, 0x32, 0xc8, 0x8d, 0x1b, 0x37, 0x48, 0x24, 0x12, 0x81, 0xa0,\n  0xf9, 0x7c, 0x9e, 0x64, 0x32, 0x29, 0xed, 0x42, 0xa1, 0x40, 0x32, 0x99,\n  0x94, 0xfb, 0x0b, 0x85, 0x02, 0x8d, 0x8d, 0x8d, 0xd2, 0x9e, 0x9e, 0x9e,\n  0xe6, 0xc2, 0x85, 0x0b, 0xcb, 0x40, 0xad, 0x0a, 0xc0, 0x71, 0x1c, 0x79,\n  0x93, 0x54, 0x2a, 0x45, 0x2a, 0x95, 0x0a, 0xdc, 0xaa, 0xa6, 0xa6, 0x26,\n  0x30, 0x17, 0x89, 0x44, 0x48, 0xa5, 0x52, 0x72, 0x8f, 0xdf, 0xf6, 0xfc,\n  0xde, 0xda, 0xea, 0x34, 0xae, 0x0a, 0xc0, 0x63, 0xc1, 0x3b, 0xb4, 0xfa,\n  0x59, 0x9d, 0x9a, 0x95, 0x68, 0xf7, 0xb7, 0xb5, 0xfc, 0x2b, 0x69, 0x40,\n  0x8e, 0xa7, 0xa6, 0xa6, 0xb0, 0x6d, 0x3b, 0x10, 0xac, 0x50, 0x28, 0x04,\n  0xd6, 0xe4, 0xf3, 0x79, 0x4c, 0xd3, 0x94, 0xfe, 0x7c, 0x3e, 0xef, 0xa9,\n  0x5e, 0xfa, 0x37, 0xcc, 0x80, 0x77, 0xd8, 0xce, 0x9d, 0x3b, 0x03, 0xf4,\n  0x0a, 0x21, 0xd0, 0x34, 0x8d, 0xe3, 0xc7, 0x8f, 0xcb, 0x43, 0x47, 0x46,\n  0x46, 0x68, 0x6b, 0x6b, 0x93, 0x6b, 0x86, 0x87, 0x87, 0xa5, 0x0d, 0x30,\n  0x3c, 0x3c, 0x8c, 0xa2, 0x28, 0x2f, 0x0e, 0xc0, 0xbb, 0x9d, 0x10, 0x82,\n  0x6c, 0x36, 0x8b, 0xe3, 0x38, 0xcb, 0x44, 0x38, 0x34, 0x34, 0x24, 0xd7,\n  0x4f, 0x4c, 0x4c, 0x04, 0x40, 0x67, 0x32, 0x19, 0x69, 0x03, 0x64, 0x32,\n  0x19, 0xd2, 0xe9, 0xf4, 0xc6, 0x01, 0x00, 0xec, 0xd8, 0xb1, 0x83, 0xe6,\n  0xe6, 0xe6, 0x00, 0x00, 0x55, 0x55, 0xd9, 0xbb, 0x77, 0xaf, 0xb4, 0x43,\n  0xa1, 0x50, 0x80, 0x01, 0x4d, 0xd3, 0x02, 0x0c, 0x68, 0x9a, 0xb6, 0xb1,\n  0x14, 0xd8, 0xb6, 0x2d, 0x45, 0x98, 0xcb, 0xe5, 0x96, 0x6d, 0x28, 0x14,\n  0x0a, 0x0c, 0x0e, 0x0e, 0xca, 0x80, 0xff, 0x19, 0x03, 0x9e, 0x06, 0x9a,\n  0x9b, 0x9b, 0xa5, 0x4f, 0x08, 0x41, 0x28, 0x14, 0x92, 0x07, 0x7a, 0xb6,\n  0x9f, 0x01, 0x55, 0x55, 0xd9, 0xb3, 0x67, 0x8f, 0xdc, 0xa3, 0xaa, 0xaa,\n  0x64, 0xc0, 0x0f, 0x6c, 0x5d, 0x00, 0x80, 0xd4, 0x80, 0x77, 0xb8, 0xa7,\n  0xf2, 0x47, 0x8f, 0x1e, 0x49, 0x3b, 0x93, 0xc9, 0x04, 0x40, 0xaf, 0xc4,\n  0x40, 0x47, 0x47, 0xc7, 0xc6, 0x18, 0xf0, 0x52, 0xe0, 0x55, 0x81, 0xbf,\n  0xf6, 0x55, 0x55, 0x25, 0x9d, 0x4e, 0x07, 0xec, 0xf6, 0xf6, 0x76, 0x09,\n  0x40, 0xd3, 0xb4, 0x00, 0x03, 0x7e, 0x0d, 0xbc, 0x10, 0x03, 0xfe, 0x1a,\n  0xf6, 0xbf, 0x07, 0xbc, 0x9e, 0xcb, 0xe5, 0x02, 0x1a, 0x18, 0x1f, 0x1b,\n  0x23, 0x7b, 0xef, 0x1e, 0xf9, 0xfb, 0xf7, 0x79, 0x36, 0x32, 0xc2, 0x7c,\n  0x2e, 0x47, 0x44, 0x51, 0x70, 0x34, 0x8d, 0xf0, 0xd6, 0xad, 0x28, 0x89,\n  0x04, 0xe1, 0x73, 0xe7, 0xe8, 0x7c, 0xfb, 0xed, 0x8d, 0xa5, 0xc0, 0xaf,\n  0x81, 0xea, 0x2a, 0x48, 0xa7, 0xd3, 0xd8, 0xa6, 0x49, 0xef, 0x57, 0x5f,\n  0x31, 0x70, 0xfd, 0x3a, 0xfb, 0x1a, 0x1a, 0x78, 0x6b, 0xd7, 0x2e, 0x5a,\n  0x3a, 0x3b, 0x89, 0x1d, 0x3a, 0x84, 0xeb, 0x38, 0x38, 0xa6, 0x49, 0x71,\n  0x6e, 0x8e, 0xb1, 0x5c, 0x8e, 0xbe, 0x2b, 0x57, 0xe8, 0x2e, 0x97, 0x89,\n  0xd4, 0xd5, 0x71, 0x1a, 0xc2, 0x37, 0xc1, 0x58, 0x17, 0x80, 0xc7, 0xc0,\n  0x4a, 0xef, 0x81, 0x3f, 0x7b, 0x7a, 0xb8, 0xf3, 0xc9, 0x27, 0x1c, 0x88,\n  0x46, 0xb9, 0x7a, 0xf2, 0x24, 0x9b, 0xc3, 0x61, 0x60, 0x29, 0xc7, 0xb6,\n  0x61, 0xe0, 0x98, 0x26, 0x8e, 0x69, 0x12, 0x11, 0x82, 0xf6, 0x86, 0x06,\n  0xda, 0xea, 0xea, 0x58, 0x58, 0x5c, 0xe4, 0xa7, 0x81, 0x01, 0xee, 0xc2,\n  0x6f, 0x1f, 0xc0, 0xa9, 0xeb, 0x30, 0xb1, 0x2a, 0x00, 0x4f, 0x03, 0x4d,\n  0x4d, 0x4d, 0x92, 0x01, 0x8f, 0x15, 0x61, 0x9a, 0xdc, 0xbd, 0x7a, 0x95,\n  0x77, 0x3b, 0x3b, 0x39, 0xdc, 0xd6, 0x06, 0x95, 0x94, 0x39, 0xa6, 0x89,\n  0x6d, 0x59, 0x32, 0xb8, 0x63, 0x9a, 0xd8, 0xbe, 0x71, 0xc8, 0xb2, 0x78,\n  0xa7, 0xb5, 0x95, 0x44, 0x28, 0x74, 0xf8, 0xbb, 0xe1, 0xe1, 0x1f, 0x2f,\n  0xc0, 0xd1, 0x2f, 0xa0, 0xb8, 0xae, 0x06, 0x3c, 0x06, 0x3c, 0x00, 0x43,\n  0x37, 0x6f, 0x72, 0x28, 0x1e, 0xe7, 0x70, 0x47, 0x07, 0xe8, 0x3a, 0x8e,\n  0x6d, 0xaf, 0x18, 0x30, 0x30, 0xe7, 0x03, 0xb6, 0x2f, 0x1e, 0x67, 0x68,\n  0xdb, 0xb6, 0x74, 0xff, 0xcc, 0xcc, 0x47, 0xc0, 0xc7, 0x6b, 0xa6, 0xa0,\n  0x5a, 0x03, 0x42, 0x08, 0xfa, 0x1f, 0x3e, 0xe4, 0xf5, 0xb3, 0x67, 0x71,\n  0x2d, 0x0b, 0xbb, 0x54, 0x5a, 0x37, 0xe0, 0x32, 0x50, 0xae, 0xcb, 0x81,\n  0x44, 0x82, 0xbe, 0x99, 0x99, 0xb3, 0xab, 0x02, 0xf0, 0xea, 0x75, 0x6a,\n  0x6a, 0x4a, 0x8e, 0x3d, 0x16, 0xf4, 0xe9, 0x69, 0x6a, 0x6b, 0x6b, 0xb1,\n  0x9e, 0x3e, 0xc5, 0x29, 0x95, 0xfe, 0x0d, 0x50, 0x09, 0x6a, 0x9b, 0x26,\n  0xe3, 0x6f, 0xec, 0xe7, 0xdb, 0xf2, 0x6b, 0xe0, 0xba, 0x98, 0x86, 0x81,\n  0x6e, 0x18, 0x58, 0x86, 0x81, 0x6e, 0x98, 0x38, 0xb6, 0x49, 0xab, 0x53,\n  0x44, 0x3c, 0xfc, 0xf4, 0x25, 0x40, 0x59, 0x93, 0x01, 0x4f, 0x03, 0x32,\n  0xff, 0x42, 0x70, 0xdf, 0x75, 0x79, 0x92, 0xcd, 0xb2, 0x79, 0xcb, 0x16,\n  0xec, 0x72, 0x79, 0xd9, 0x0d, 0x6d, 0xd7, 0xa6, 0xfc, 0x7e, 0x03, 0xdb,\n  0xba, 0x8b, 0xfc, 0xb9, 0x98, 0x46, 0xd7, 0x0d, 0x0c, 0x43, 0x47, 0xd7,\n  0x0d, 0x74, 0xdd, 0x20, 0xa2, 0xb9, 0x44, 0x67, 0x17, 0x01, 0x54, 0x20,\n  0xba, 0xaa, 0x06, 0x84, 0x10, 0x4c, 0x4e, 0x4e, 0x06, 0xde, 0x84, 0x00,\n  0x4a, 0x2c, 0x46, 0x6f, 0x4f, 0x0f, 0xc9, 0x33, 0x67, 0x50, 0x66, 0x66,\n  0xb0, 0xab, 0x58, 0x28, 0xbe, 0x12, 0x27, 0x17, 0xce, 0xb2, 0x6b, 0xff,\n  0xdf, 0xf4, 0xf6, 0xec, 0xc2, 0xb2, 0xec, 0x4a, 0xb7, 0x08, 0x6b, 0xd0,\n  0x1e, 0xd1, 0xc9, 0x67, 0xc6, 0x88, 0x43, 0x1e, 0x88, 0x28, 0x6b, 0xa5,\n  0xa0, 0xa9, 0xa9, 0x89, 0x96, 0x96, 0x16, 0xd9, 0x5b, 0x5b, 0x5b, 0xa9,\n  0xdd, 0xb7, 0x8f, 0x81, 0xc9, 0x49, 0xfe, 0xf8, 0xe1, 0x07, 0x4a, 0xc9,\n  0x24, 0x6e, 0x32, 0xb9, 0xf4, 0xe9, 0x5d, 0x2e, 0x63, 0x95, 0x4a, 0x64,\n  0x0e, 0x0b, 0xa6, 0xf5, 0x31, 0x1e, 0xef, 0x78, 0xcc, 0x2b, 0xa1, 0xaf,\n  0x97, 0x2e, 0xe4, 0xda, 0x6c, 0x8f, 0x6f, 0xe2, 0xb5, 0x58, 0x99, 0xc1,\n  0xc7, 0x05, 0xe2, 0x7d, 0x3f, 0x53, 0x82, 0x3b, 0x80, 0xbd, 0x6a, 0x0a,\n  0x5c, 0xd7, 0x5d, 0x91, 0x01, 0xf7, 0xe0, 0x41, 0x9e, 0xf7, 0xf5, 0x71,\n  0x6f, 0x74, 0x94, 0x85, 0x62, 0x91, 0x9d, 0xbb, 0x77, 0xb3, 0xbd, 0xad,\n  0x8d, 0x70, 0xa9, 0x84, 0x3d, 0x37, 0x4b, 0xf6, 0x48, 0x84, 0xb2, 0x55,\n  0xc4, 0xb2, 0x75, 0xa2, 0x6f, 0x3d, 0xe0, 0xe5, 0xde, 0xd3, 0xd4, 0x1b,\n  0x30, 0x3d, 0xd8, 0x47, 0xcf, 0xa2, 0xc6, 0x9e, 0xde, 0x6e, 0xc8, 0x8f,\n  0x3c, 0xfb, 0x0b, 0x3e, 0x07, 0x16, 0xd6, 0x2c, 0xc3, 0x8b, 0x17, 0x2f,\n  0x06, 0x2a, 0x40, 0x08, 0x81, 0x7d, 0xe2, 0x04, 0x03, 0x6f, 0xbe, 0xc9,\n  0xed, 0xcb, 0x97, 0x79, 0x9e, 0xcf, 0xb3, 0xd7, 0x30, 0x98, 0xe8, 0xef,\n  0x67, 0x53, 0x34, 0x8a, 0x95, 0x8e, 0x32, 0xf7, 0x57, 0x8c, 0x90, 0x02,\n  0xb8, 0xb0, 0x50, 0xd6, 0x31, 0xfe, 0xee, 0xe2, 0xfb, 0x85, 0xa3, 0x34,\n  0x17, 0xb3, 0xec, 0xef, 0xbd, 0x85, 0x9e, 0x1b, 0x99, 0x7e, 0x00, 0x1f,\n  0x3e, 0x80, 0x7e, 0xa0, 0x5c, 0x0d, 0x20, 0xa6, 0x28, 0xca, 0x9c, 0xeb,\n  0xba, 0xb5, 0xf5, 0xf5, 0xff, 0x7e, 0xc2, 0x57, 0x7f, 0x54, 0x1e, 0x3a,\n  0x76, 0x8c, 0x86, 0xdb, 0xb7, 0xf9, 0xe5, 0xb3, 0xcf, 0xf8, 0xbd, 0xbb,\n  0x9b, 0x58, 0x28, 0x44, 0x52, 0xd7, 0x51, 0x1f, 0x2f, 0x30, 0x3e, 0xfe,\n  0x0c, 0x67, 0x93, 0xc0, 0x71, 0x5d, 0x42, 0x33, 0x16, 0x4a, 0x5f, 0x3f,\n  0xaf, 0x3e, 0xfc, 0x15, 0xa7, 0x58, 0xa0, 0xb0, 0x75, 0xab, 0x75, 0x07,\n  0x2e, 0x66, 0xa1, 0x17, 0x78, 0x02, 0xc1, 0xbf, 0x66, 0x31, 0x20, 0x71,\n  0xe4, 0xc8, 0x91, 0xf7, 0x5a, 0x5a, 0x5a, 0x3e, 0x05, 0x36, 0x55, 0xb3,\n  0xe3, 0x6f, 0xae, 0xeb, 0x62, 0x18, 0x06, 0xd6, 0xfc, 0x3c, 0x35, 0x93,\n  0x93, 0x44, 0x66, 0x67, 0xa9, 0x99, 0x9f, 0x47, 0x33, 0x0c, 0x14, 0xcb,\n  0xc2, 0xd1, 0x34, 0xcc, 0x50, 0x08, 0x3d, 0x1a, 0xa5, 0x14, 0x8f, 0x53,\n  0xda, 0xbe, 0xdd, 0x18, 0xcd, 0xe5, 0xbe, 0x18, 0x1c, 0x1c, 0xfc, 0x06,\n  0x18, 0x07, 0xb2, 0x80, 0xe3, 0x07, 0x10, 0x06, 0x92, 0xc0, 0x36, 0xa0,\n  0x1e, 0xa8, 0x61, 0xa9, 0x54, 0xd6, 0x6b, 0x0a, 0x10, 0x01, 0x36, 0x57,\n  0xf6, 0x68, 0x95, 0x39, 0x00, 0x87, 0xa5, 0x1f, 0x9e, 0xa7, 0x80, 0x0e,\n  0x3c, 0x03, 0x66, 0x59, 0xfa, 0x1d, 0x98, 0xaf, 0x66, 0xc0, 0x6b, 0x35,\n  0x95, 0x03, 0xc3, 0xab, 0xf8, 0xd7, 0x6b, 0xa2, 0xd2, 0xbd, 0xaf, 0x0f,\n  0xb7, 0x02, 0xc4, 0xac, 0x80, 0xd0, 0x7d, 0x3e, 0xfe, 0x01, 0x9f, 0x1e,\n  0x98, 0x64, 0x1e, 0x77, 0xb2, 0x47, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,\n  0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,\n},\n}\n"
  },
  {
    "path": "examples/updateui.go",
    "content": "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 QueueMain function\n// especially if the update is coming from another goroutine\n//\n// see QueueMain in 'main.go' for detailed description\n\nvar countLabel *ui.Label\nvar count int\n\nfunc setupUI() {\n\tmainWindow := ui.NewWindow(\"libui Updating UI\", 640, 480, true)\n\tmainWindow.OnClosing(func(*ui.Window) bool {\n\t\tui.Quit()\n\t\treturn true\n\t})\n\tui.OnShouldQuit(func() bool {\n\t\tmainWindow.Destroy()\n\t\treturn true\n\t})\n\n\tvbContainer := ui.NewVerticalBox()\n\tvbContainer.SetPadded(true)\n\n\tinputGroup := ui.NewGroup(\"Input\")\n\tinputGroup.SetMargined(true)\n\n\tvbInput := ui.NewVerticalBox()\n\tvbInput.SetPadded(true)\n\n\tinputForm := ui.NewForm()\n\tinputForm.SetPadded(true)\n\n\tmessage := ui.NewEntry()\n\tmessage.SetText(\"Hello World\")\n\tinputForm.Append(\"What message do you want to show?\", message, false)\n\n\tshowMessageButton := ui.NewButton(\"Show message\")\n\tclearMessageButton := ui.NewButton(\"Clear message\")\n\n\tvbInput.Append(inputForm, false)\n\tvbInput.Append(showMessageButton, false)\n\tvbInput.Append(clearMessageButton, false)\n\n\tinputGroup.SetChild(vbInput)\n\n\tmessageGroup := ui.NewGroup(\"Message\")\n\tmessageGroup.SetMargined(true)\n\n\tvbMessage := ui.NewVerticalBox()\n\tvbMessage.SetPadded(true)\n\n\tmessageLabel := ui.NewLabel(\"\")\n\n\tvbMessage.Append(messageLabel, false)\n\n\tmessageGroup.SetChild(vbMessage)\n\n\tcountGroup := ui.NewGroup(\"Counter\")\n\tcountGroup.SetMargined(true)\n\n\tvbCounter := ui.NewVerticalBox()\n\tvbCounter.SetPadded(true)\n\n\tcountLabel = ui.NewLabel(fmt.Sprintf(\"%d\", count))\n\n\tvbCounter.Append(countLabel, false)\n\tcountGroup.SetChild(vbCounter)\n\n\tvbContainer.Append(inputGroup, false)\n\tvbContainer.Append(messageGroup, false)\n\tvbContainer.Append(countGroup, false)\n\n\tmainWindow.SetChild(vbContainer)\n\n\tshowMessageButton.OnClicked(func(*ui.Button) {\n\t\t// Update the UI directly as it is called from the main thread\n\t\tmessageLabel.SetText(message.Text())\n\t})\n\n\tclearMessageButton.OnClicked(func(*ui.Button) {\n\t\t// Update the UI directly as it is called from the main thread\n\t\tmessageLabel.SetText(\"\")\n\t})\n\n\tmainWindow.Show()\n\n\t// Counting and updating the UI from another goroutine\n\tgo counter()\n}\n\nfunc counter() {\n\tfor {\n\t\ttime.Sleep(1 * time.Second)\n\t\tcount++\n\n\t\t// Update the UI using the QueueMain function\n\t\tui.QueueMain(func() {\n\t\t\tcountLabel.SetText(fmt.Sprintf(\"%d\", count))\n\t\t})\n\t}\n}\n\nfunc main() {\n\tcount = 0\n\n\tui.Main(setupUI)\n}\n"
  },
  {
    "path": "fontbutton.go",
    "content": "// 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 represents a button that the user can\n// click to select a font.\ntype FontButton struct {\n\tControlBase\n\tb\t*C.uiFontButton\n\tonChanged\t\tfunc(*FontButton)\n}\n\n// NewFontButton creates a new FontButton.\nfunc NewFontButton() *FontButton {\n\tb := new(FontButton)\n\n\tb.b = C.uiNewFontButton()\n\n\tC.pkguiFontButtonOnChanged(b.b)\n\n\tb.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b)))\n\treturn b\n}\n\n// Font returns the font currently selected in the FontButton.\nfunc (b *FontButton) Font() *FontDescriptor {\n\tcfd := C.pkguiNewFontDescriptor()\n\tdefer C.pkguiFreeFontDescriptor(cfd)\n\tC.uiFontButtonFont(b.b, cfd)\n\tdefer C.uiFreeFontButtonFont(cfd)\n\tfd := &FontDescriptor{}\n\tfd.fromLibui(cfd)\n\treturn fd\n}\n\n// OnChanged registers f to be run when the user changes the\n// currently selected font in the FontButton. Only one function can\n// be registered at a time.\nfunc (b *FontButton) OnChanged(f func(*FontButton)) {\n\tb.onChanged = f\n}\n\n//export pkguiDoFontButtonOnChanged\nfunc pkguiDoFontButtonOnChanged(bb *C.uiFontButton, data unsafe.Pointer) {\n\tb := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*FontButton)\n\tif b.onChanged != nil {\n\t\tb.onChanged(b)\n\t}\n}\n"
  },
  {
    "path": "form.go",
    "content": "// 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 a group of Controls vertically\n// with labels next to each. By default, each control has its\n// preferred height; if a control is marked \"stretchy\", it will take\n// whatever space is left over. If multiple controls are marked\n// stretchy, they will be given equal shares of the leftover space.\n// There can also be space between each control (\"padding\").\ntype Form struct {\n\tControlBase\n\tf\t*C.uiForm\n\tchildren\t[]Control\n}\n\n// NewForm creates a new horizontal Form.\nfunc NewForm() *Form {\n\tf := new(Form)\n\n\tf.f = C.uiNewForm()\n\n\tf.ControlBase = NewControlBase(f, uintptr(unsafe.Pointer(f.f)))\n\treturn f\n}\n\n// Destroy destroys the Form. If the Form has children,\n// Destroy calls Destroy on those Controls as well.\nfunc (f *Form) Destroy() {\n\tfor len(f.children) != 0 {\n\t\tc := f.children[0]\n\t\tf.Delete(0)\n\t\tc.Destroy()\n\t}\n\tf.ControlBase.Destroy()\n}\n\n// Append adds the given control to the end of the Form.\nfunc (f *Form) Append(label string, child Control, stretchy bool) {\n\tclabel := C.CString(label)\n\tdefer freestr(clabel)\n\tc := touiControl(child.LibuiControl())\n\tC.uiFormAppend(f.f, clabel, c, frombool(stretchy))\n\tf.children = append(f.children, child)\n}\n\n// Delete deletes the nth control of the Form.\nfunc (f *Form) Delete(n int) {\n\tf.children = append(f.children[:n], f.children[n + 1:]...)\n\tC.uiFormDelete(f.f, C.int(n))\n}\n\n// Padded returns whether there is space between each control\n// of the Form.\nfunc (f *Form) Padded() bool {\n\treturn tobool(C.uiFormPadded(f.f))\n}\n\n// SetPadded controls whether there is space between each control\n// of the Form. The size of the padding is determined by the OS and\n// its best practices.\nfunc (f *Form) SetPadded(padded bool) {\n\tC.uiFormSetPadded(f.f, frombool(padded))\n}\n"
  },
  {
    "path": "grid.go",
    "content": "// 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 arranges other Controls in a grid.\n// Grid is a very powerful container: it can position and size each\n// Control in several ways and can (and must) have Controls added\n// to it in any direction. It can also have Controls spanning multiple\n// rows and columns.\n//\n// Each Control in a Grid has associated \"expansion\" and\n// \"alignment\" values in both the X and Y direction.\n// Expansion determines whether all cells in the same row/column\n// are given whatever space is left over after figuring out how big\n// the rest of the Grid should be. Alignment determines the position\n// of a Control relative to its cell after computing the above. The\n// special alignment Fill can be used to grow a Control to fit its cell.\n// Note that expansion and alignment are independent variables.\n// For more information on expansion and alignment, read\n// https://developer.gnome.org/gtk3/unstable/ch28s02.html.\ntype Grid struct {\n\tControlBase\n\tg\t*C.uiGrid\n\tchildren\t[]Control\n}\n\n// Align represents the alignment of a Control in its cell of a Grid.\ntype Align int\nconst (\n\tAlignFill Align = iota\n\tAlignStart\n\tAlignCenter\n\tAlignEnd\n)\n\n// At represents a side of a Control to add other Controls to a Grid to.\ntype At int\nconst (\n\tLeading At = iota\n\tTop\n\tTrailing\n\tBottom\n)\n\n// NewGrid creates a new Grid.\nfunc NewGrid() *Grid {\n\tg := new(Grid)\n\n\tg.g = C.uiNewGrid()\n\n\tg.ControlBase = NewControlBase(g, uintptr(unsafe.Pointer(g.g)))\n\treturn g\n}\n\n// TODO Destroy\n\n// Append adds the given control to the Grid, at the given coordinate.\nfunc (g *Grid) Append(child Control, left, top int, xspan, yspan int, hexpand bool, halign Align, vexpand bool, valign Align) {\n\tC.uiGridAppend(g.g, touiControl(child.LibuiControl()),\n\t\tC.int(left), C.int(top),\n\t\tC.int(xspan), C.int(yspan),\n\t\tfrombool(hexpand), C.uiAlign(halign),\n\t\tfrombool(vexpand), C.uiAlign(valign))\n\tg.children = append(g.children, child)\n}\n\n// InsertAt adds the given control to the Grid relative to an existing\n// control.\nfunc (g *Grid) InsertAt(child Control, existing Control, at At, xspan, yspan int, hexpand bool, halign Align, vexpand bool, valign Align) {\n\tC.uiGridInsertAt(g.g, touiControl(child.LibuiControl()),\n\t\ttouiControl(existing.LibuiControl()), C.uiAt(at),\n\t\tC.int(xspan), C.int(yspan),\n\t\tfrombool(hexpand), C.uiAlign(halign),\n\t\tfrombool(vexpand), C.uiAlign(valign))\n\tg.children = append(g.children, child)\n}\n\n// Padded returns whether there is space between each control\n// of the Grid.\nfunc (g *Grid) Padded() bool {\n\treturn tobool(C.uiGridPadded(g.g))\n}\n\n// SetPadded controls whether there is space between each control\n// of the Grid. The size of the padding is determined by the OS and\n// its best practices.\nfunc (g *Grid) SetPadded(padded bool) {\n\tC.uiGridSetPadded(g.g, frombool(padded))\n}\n"
  },
  {
    "path": "group.go",
    "content": "// 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 holds another Control and wraps it around\n// a labelled box (though some systems make this box invisible).\n// You can use this to group related controls together.\ntype Group struct {\n\tControlBase\n\tg\t*C.uiGroup\n\tchild\t\tControl\n}\n\n// NewGroup creates a new Group.\nfunc NewGroup(title string) *Group {\n\tg := new(Group)\n\n\tctitle := C.CString(title)\n\tg.g = C.uiNewGroup(ctitle)\n\tfreestr(ctitle)\n\n\tg.ControlBase = NewControlBase(g, uintptr(unsafe.Pointer(g.g)))\n\treturn g\n}\n\n// Destroy destroys the Group. If the Group has a child,\n// Destroy calls Destroy on that as well.\nfunc (g *Group) Destroy() {\n\tif g.child != nil {\n\t\tc := g.child\n\t\tg.SetChild(nil)\n\t\tc.Destroy()\n\t}\n\tg.ControlBase.Destroy()\n}\n\n// Title returns the Group's title.\nfunc (g *Group) Title() string {\n\tctitle := C.uiGroupTitle(g.g)\n\ttitle := C.GoString(ctitle)\n\tC.uiFreeText(ctitle)\n\treturn title\n}\n\n// SetTitle sets the Group's title to title.\nfunc (g *Group) SetTitle(title string) {\n\tctitle := C.CString(title)\n\tC.uiGroupSetTitle(g.g, ctitle)\n\tfreestr(ctitle)\n}\n\n// SetChild sets the Group's child to child. If child is nil, the Group\n// will not have a child.\nfunc (g *Group) SetChild(child Control) {\n\tg.child = child\n\tc := (*C.uiControl)(nil)\n\tif g.child != nil {\n\t\tc = touiControl(g.child.LibuiControl())\n\t}\n\tC.uiGroupSetChild(g.g, c)\n}\n\n// Margined returns whether the Group has margins around its child.\nfunc (g *Group) Margined() bool {\n\treturn tobool(C.uiGroupMargined(g.g))\n}\n\n// SetMargined controls whether the Group has margins around its\n// child. The size of the margins are determined by the OS and its\n// best practices.\nfunc (g *Group) SetMargined(margined bool) {\n\tC.uiGroupSetMargined(g.g, frombool(margined))\n}\n"
  },
  {
    "path": "image.go",
    "content": "// 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 display on screen.\n// \n// Images are built from one or more representations, each with the\n// same aspect ratio but a different pixel size. Package ui\n// automatically selects the most appropriate representation for\n// drawing the image when it comes time to draw the image; what\n// this means depends on the pixel density of the target context.\n// Therefore, one can use Image to draw higher-detailed images on\n// higher-density displays. The typical use cases are either:\n// \n// \t- have just a single representation, at which point all screens\n// \t  use the same image, and thus uiImage acts like a simple\n// \t  bitmap image, or\n// \t- have two images, one at normal resolution and one at 2x\n// \t  resolution; this matches the current expectations of some\n// \t  desktop systems at the time of writing (mid-2018)\n//\n// Image allocates OS resources; you must explicitly free an Image\n// when you are finished with it.\ntype Image struct {\n\ti\t*C.uiImage\n}\n\n// NewImage creates a new Image with the given width and\n// height. This width and height should be the size in points of the\n// image in the device-independent case; typically this is the 1x size.\nfunc NewImage(width, height float64) *Image {\n\treturn &Image{\n\t\ti:\tC.uiNewImage(C.double(width), C.double(height)),\n\t}\n}\n\n// Free frees the Image.\nfunc (i *Image) Free() {\n\tC.uiFreeImage(i.i)\n}\n\n// Append adds the given image as a representation of the Image.\nfunc (i *Image) Append(img *image.RGBA) {\n\tcpix := C.CBytes(img.Pix)\n\tdefer C.free(cpix)\n\tC.uiImageAppend(i.i, cpix,\n\t\tC.int(img.Rect.Dx()),\n\t\tC.int(img.Rect.Dy()),\n\t\tC.int(img.Stride))\n}\n"
  },
  {
    "path": "label.go",
    "content": "// 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 represents a line of text that cannot be\n// interacted with.\ntype Label struct {\n\tControlBase\n\tl\t*C.uiLabel\n}\n\n// NewLabel creates a new Label with the given text.\nfunc NewLabel(text string) *Label {\n\tl := new(Label)\n\n\tctext := C.CString(text)\n\tl.l = C.uiNewLabel(ctext)\n\tfreestr(ctext)\n\n\tl.ControlBase = NewControlBase(l, uintptr(unsafe.Pointer(l.l)))\n\treturn l\n}\n\n// Text returns the Label's text.\nfunc (l *Label) Text() string {\n\tctext := C.uiLabelText(l.l)\n\ttext := C.GoString(ctext)\n\tC.uiFreeText(ctext)\n\treturn text\n}\n\n// SetText sets the Label's text to text.\nfunc (l *Label) SetText(text string) {\n\tctext := C.CString(text)\n\tC.uiLabelSetText(l.l, ctext)\n\tfreestr(ctext)\n}\n"
  },
  {
    "path": "link_darwin_amd64.go",
    "content": "// 13 december 2015\n\npackage ui\n\n// #cgo CFLAGS: -mmacosx-version-min=10.8\n// #cgo LDFLAGS: ${SRCDIR}/libui_darwin_amd64.a -framework Foundation -framework AppKit -mmacosx-version-min=10.8\nimport \"C\"\n"
  },
  {
    "path": "link_linux_386.go",
    "content": "// +build !windows\n// +build !darwin\n\n// 11 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_linux_386.a -lm -ldl\n// #cgo pkg-config: gtk+-3.0\nimport \"C\"\n"
  },
  {
    "path": "link_linux_amd64.go",
    "content": "// +build !windows\n// +build !darwin\n\n// 11 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_linux_amd64.a -lm -ldl\n// #cgo pkg-config: gtk+-3.0\nimport \"C\"\n"
  },
  {
    "path": "link_windows_386.go",
    "content": "// 13 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_windows_386.a\n// #cgo LDFLAGS: -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lmsimg32 -lcomdlg32 -ld2d1 -ldwrite -lole32 -loleaut32 -loleacc -luuid -lwindowscodecs -static -static-libgcc -static-libstdc++\nimport \"C\"\n"
  },
  {
    "path": "link_windows_amd64.go",
    "content": "// 13 december 2015\n\npackage ui\n\n// #cgo LDFLAGS: ${SRCDIR}/libui_windows_amd64.a\n// #cgo LDFLAGS: -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lmsimg32 -lcomdlg32 -ld2d1 -ldwrite -lole32 -loleaut32 -loleacc -luuid -lwindowscodecs -static -static-libgcc -static-libstdc++\nimport \"C\"\n"
  },
  {
    "path": "main.go",
    "content": "// 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// make sure main() runs on the first thread created by the OS\n// 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\n// 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)\n// TODO describe the source of this trick\nfunc init() {\n\truntime.LockOSThread()\n}\n\n// Main initializes package ui, runs f to set up the program,\n// and executes the GUI main loop. f should set up the program's\n// initial state: open the main window, create controls, and set up\n// events. It should then return, at which point Main will\n// process events until Quit is called, at which point Main will return\n// nil. If package ui fails to initialize, Main returns an appropriate\n// error.\nfunc Main(f func()) error {\n\topts := C.pkguiAllocInitOptions()\n\testr := C.uiInit(opts)\n\tC.pkguiFreeInitOptions(opts)\n\tif estr != nil {\n\t\terr := errors.New(C.GoString(estr))\n\t\tC.uiFreeInitError(estr)\n\t\treturn err\n\t}\n\tC.pkguiOnShouldQuit()\n\tQueueMain(f)\n\tC.uiMain()\n\treturn nil\n}\n\n// Quit queues a return from Main. It does not exit the program.\n// It also does not immediately cause Main to return; Main will\n// return when it next can. Quit must be called from the GUI thread.\nfunc Quit() {\n\tC.uiQuit()\n}\n\n// These prevent the passing of Go functions into C land.\n// TODO make an actual sparse list instead of this monotonic map thingy\nvar (\n\tqmmap = make(map[uintptr]func())\n\tqmcurrent = uintptr(0)\n\tqmlock sync.Mutex\n)\n\n// QueueMain queues f to be executed on the GUI thread when\n// next possible. It returns immediately; that is, it does not wait\n// for the function to actually be executed. QueueMain is the only\n// function that can be called from other goroutines, and its\n// primary purpose is to allow communication between other\n// goroutines and the GUI thread. Calling QueueMain after Quit\n// has been called results in undefined behavior.\n// \n// If you start a goroutine in f, it also cannot call package ui\n// functions. So for instance, the following will result in\n// undefined behavior:\n// \n// \tui.QueueMain(func() {\n// \t\tgo ui.MsgBox(...)\n// \t})\nfunc QueueMain(f func()) {\n\tqmlock.Lock()\n\tdefer qmlock.Unlock()\n\n\tn := uintptr(0)\n\tfor {\n\t\tn = qmcurrent\n\t\tqmcurrent++\n\t\tif qmmap[n] == nil {\n\t\t\tbreak\n\t\t}\n\t}\n\tqmmap[n] = f\n\tC.pkguiQueueMain(C.uintptr_t(n))\n}\n\n//export pkguiDoQueueMain\nfunc pkguiDoQueueMain(nn unsafe.Pointer) {\n\tqmlock.Lock()\n\n\tn := uintptr(nn)\n\tf := qmmap[n]\n\tdelete(qmmap, n)\n\n\t// allow uiQueueMain() to be called by a queued function\n\t// TODO explicitly allow this in libui too\n\tqmlock.Unlock()\n\n\tf()\n}\n\n// no need to lock this; this API is only safe on the main thread\nvar shouldQuitFunc func() bool\n\n// OnShouldQuit schedules f to be exeucted when the OS wants\n// the program to quit or when a Quit menu item has been clicked.\n// Only one function may be registered at a time. If the function\n// returns true, Quit will be called. If the function returns false, or\n// if OnShouldQuit is never called. Quit will not be called and the\n// OS will be told that the program needs to continue running.\nfunc OnShouldQuit(f func() bool) {\n\tshouldQuitFunc = f\n}\n\n//export pkguiDoOnShouldQuit\nfunc pkguiDoOnShouldQuit(unused unsafe.Pointer) C.int {\n\tif shouldQuitFunc == nil {\n\t\treturn 0\n\t}\n\treturn frombool(shouldQuitFunc())\n}\n\n// TODO Timer?\n"
  },
  {
    "path": "multilineentry.go",
    "content": "// 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// something's wrong with NSMapTable\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// MultilineEntry is a Control that represents a space that the user\n// can type multiple lines of text into.\ntype MultilineEntry struct {\n\tControlBase\n\te\t*C.uiMultilineEntry\n\tonChanged\t\tfunc(*MultilineEntry)\n}\n\nfunc finishNewMultilineEntry(ee *C.uiMultilineEntry) *MultilineEntry {\n\tm := new(MultilineEntry)\n\n\tm.e = ee\n\n\tC.pkguiMultilineEntryOnChanged(m.e)\n\n\tm.ControlBase = NewControlBase(m, uintptr(unsafe.Pointer(m.e)))\n\treturn m\n}\n\n// NewMultilineEntry creates a new MultilineEntry.\n// The MultilineEntry soft-word-wraps and has no horizontal\n// scrollbar.\nfunc NewMultilineEntry() *MultilineEntry {\n\treturn finishNewMultilineEntry(C.uiNewMultilineEntry())\n}\n\n// NewNonWrappingMultilineEntry creates a new MultilineEntry.\n// The MultilineEntry does not word-wrap and thus has horizontal\n// scrollbar.\nfunc NewNonWrappingMultilineEntry() *MultilineEntry {\n\treturn finishNewMultilineEntry(C.uiNewNonWrappingMultilineEntry())\n}\n\n// Text returns the MultilineEntry's text.\nfunc (m *MultilineEntry) Text() string {\n\tctext := C.uiMultilineEntryText(m.e)\n\ttext := C.GoString(ctext)\n\tC.uiFreeText(ctext)\n\treturn text\n}\n\n// SetText sets the MultilineEntry's text to text.\nfunc (m *MultilineEntry) SetText(text string) {\n\tctext := C.CString(text)\n\tC.uiMultilineEntrySetText(m.e, ctext)\n\tfreestr(ctext)\n}\n\n// Append adds text to the end of the MultilineEntry's text.\n// TODO selection and scroll behavior\nfunc (m *MultilineEntry) Append(text string) {\n\tctext := C.CString(text)\n\tC.uiMultilineEntryAppend(m.e, ctext)\n\tfreestr(ctext)\n}\n\n// OnChanged registers f to be run when the user makes a change to\n// the MultilineEntry. Only one function can be registered at a time.\nfunc (m *MultilineEntry) OnChanged(f func(*MultilineEntry)) {\n\tm.onChanged = f\n}\n\n//export pkguiDoMultilineEntryOnChanged\nfunc pkguiDoMultilineEntryOnChanged(ee *C.uiMultilineEntry, data unsafe.Pointer) {\n\tm := ControlFromLibui(uintptr(unsafe.Pointer(ee))).(*MultilineEntry)\n\tif m.onChanged != nil {\n\t\tm.onChanged(m)\n\t}\n}\n\n// ReadOnly returns whether the MultilineEntry can be changed.\nfunc (m *MultilineEntry) ReadOnly() bool {\n\treturn tobool(C.uiMultilineEntryReadOnly(m.e))\n}\n\n// SetReadOnly sets whether the MultilineEntry can be changed.\nfunc (m *MultilineEntry) SetReadOnly(ro bool) {\n\tC.uiMultilineEntrySetReadOnly(m.e, frombool(ro))\n}\n"
  },
  {
    "path": "pkgui.c",
    "content": "// 26 august 2018\n#include \"pkgui.h\"\n#include \"_cgo_export.h\"\n\nuiInitOptions *pkguiAllocInitOptions(void)\n{\n\treturn (uiInitOptions *) pkguiAlloc(sizeof (uiInitOptions));\n}\n\nvoid pkguiFreeInitOptions(uiInitOptions *o)\n{\n\tfree(o);\n}\n\nvoid pkguiQueueMain(uintptr_t n)\n{\n\tuiQueueMain(pkguiDoQueueMain, (void *) n);\n}\n\nvoid pkguiOnShouldQuit(void)\n{\n\tuiOnShouldQuit(pkguiDoOnShouldQuit, NULL);\n}\n\nvoid pkguiWindowOnClosing(uiWindow *w)\n{\n\tuiWindowOnClosing(w, pkguiDoWindowOnClosing, NULL);\n}\n\nvoid pkguiButtonOnClicked(uiButton *b)\n{\n\tuiButtonOnClicked(b, pkguiDoButtonOnClicked, NULL);\n}\n\nvoid pkguiCheckboxOnToggled(uiCheckbox *c)\n{\n\tuiCheckboxOnToggled(c, pkguiDoCheckboxOnToggled, NULL);\n}\n\nvoid pkguiColorButtonOnChanged(uiColorButton *c)\n{\n\tuiColorButtonOnChanged(c, pkguiDoColorButtonOnChanged, NULL);\n}\n\npkguiColorDoubles pkguiAllocColorDoubles(void)\n{\n\tpkguiColorDoubles c;\n\n\tc.r = (double *) pkguiAlloc(4 * sizeof (double));\n\tc.g = c.r + 1;\n\tc.b = c.g + 1;\n\tc.a = c.b + 1;\n\treturn c;\n}\n\nvoid pkguiFreeColorDoubles(pkguiColorDoubles c)\n{\n\tfree(c.r);\n}\n\nvoid pkguiComboboxOnSelected(uiCombobox *c)\n{\n\tuiComboboxOnSelected(c, pkguiDoComboboxOnSelected, NULL);\n}\n\nvoid pkguiDateTimePickerOnChanged(uiDateTimePicker *d)\n{\n\tuiDateTimePickerOnChanged(d, pkguiDoDateTimePickerOnChanged, NULL);\n}\n\nstruct tm *pkguiAllocTime(void)\n{\n\treturn (struct tm *) pkguiAlloc(sizeof (struct tm));\n}\n\nvoid pkguiFreeTime(struct tm *t)\n{\n\tfree(t);\n}\n\nvoid pkguiEditableComboboxOnChanged(uiEditableCombobox *c)\n{\n\tuiEditableComboboxOnChanged(c, pkguiDoEditableComboboxOnChanged, NULL);\n}\n\nvoid pkguiEntryOnChanged(uiEntry *e)\n{\n\tuiEntryOnChanged(e, pkguiDoEntryOnChanged, NULL);\n}\n\nvoid pkguiFontButtonOnChanged(uiFontButton *b)\n{\n\tuiFontButtonOnChanged(b, pkguiDoFontButtonOnChanged, NULL);\n}\n\nvoid pkguiMultilineEntryOnChanged(uiMultilineEntry *e)\n{\n\tuiMultilineEntryOnChanged(e, pkguiDoMultilineEntryOnChanged, NULL);\n}\n\nvoid pkguiRadioButtonsOnSelected(uiRadioButtons *r)\n{\n\tuiRadioButtonsOnSelected(r, pkguiDoRadioButtonsOnSelected, NULL);\n}\n\nvoid pkguiSliderOnChanged(uiSlider *s)\n{\n\tuiSliderOnChanged(s, pkguiDoSliderOnChanged, NULL);\n}\n\nvoid pkguiSpinboxOnChanged(uiSpinbox *s)\n{\n\tuiSpinboxOnChanged(s, pkguiDoSpinboxOnChanged, NULL);\n}\n\nuiDrawBrush *pkguiAllocBrush(void)\n{\n\treturn (uiDrawBrush *) pkguiAlloc(sizeof (uiDrawBrush));\n}\n\nvoid pkguiFreeBrush(uiDrawBrush *b)\n{\n\tfree(b);\n}\n\nuiDrawBrushGradientStop *pkguiAllocGradientStops(size_t n)\n{\n\treturn (uiDrawBrushGradientStop *) pkguiAlloc(n * sizeof (uiDrawBrushGradientStop));\n}\n\nvoid pkguiFreeGradientStops(uiDrawBrushGradientStop *stops)\n{\n\tfree(stops);\n}\n\nvoid pkguiSetGradientStop(uiDrawBrushGradientStop *stops, size_t i, double pos, double r, double g, double b, double a)\n{\n\tstops[i].Pos = pos;\n\tstops[i].R = r;\n\tstops[i].G = g;\n\tstops[i].B = b;\n\tstops[i].A = a;\n}\n\nuiDrawStrokeParams *pkguiAllocStrokeParams(void)\n{\n\treturn (uiDrawStrokeParams *) pkguiAlloc(sizeof (uiDrawStrokeParams));\n}\n\nvoid pkguiFreeStrokeParams(uiDrawStrokeParams *p)\n{\n\tfree(p);\n}\n\ndouble *pkguiAllocDashes(size_t n)\n{\n\treturn (double *) pkguiAlloc(n * sizeof (double));\n}\n\nvoid pkguiFreeDashes(double *dashes)\n{\n\tfree(dashes);\n}\n\nvoid pkguiSetDash(double *dashes, size_t i, double dash)\n{\n\tdashes[i] = dash;\n}\n\nuiDrawMatrix *pkguiAllocMatrix(void)\n{\n\treturn (uiDrawMatrix *) pkguiAlloc(sizeof (uiDrawMatrix));\n}\n\nvoid pkguiFreeMatrix(uiDrawMatrix *m)\n{\n\tfree(m);\n}\n\nuiUnderlineColor *pkguiNewUnderlineColor(void)\n{\n\treturn (uiUnderlineColor *) pkguiAlloc(sizeof (uiUnderlineColor));\n}\n\nvoid pkguiFreeUnderlineColor(uiUnderlineColor *c)\n{\n\tfree(c);\n}\n\nuiFontDescriptor *pkguiNewFontDescriptor(void)\n{\n\treturn (uiFontDescriptor *) pkguiAlloc(sizeof (uiFontDescriptor));\n}\n\nvoid pkguiFreeFontDescriptor(uiFontDescriptor *fd)\n{\n\tfree(fd);\n}\n\nuiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void)\n{\n\treturn (uiDrawTextLayoutParams *) pkguiAlloc(sizeof (uiDrawTextLayoutParams));\n}\n\nvoid pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *p)\n{\n\tfree(p);\n}\n\nuiAreaHandler *pkguiAllocAreaHandler(void)\n{\n\tuiAreaHandler *ah;\n\n\tah = (uiAreaHandler *) pkguiAlloc(sizeof (uiAreaHandler));\n\tah->Draw = pkguiDoAreaHandlerDraw;\n\tah->MouseEvent = pkguiDoAreaHandlerMouseEvent;\n\tah->MouseCrossed = pkguiDoAreaHandlerMouseCrossed;\n\tah->DragBroken = pkguiDoAreaHandlerDragBroken;\n\tah->KeyEvent = pkguiDoAreaHandlerKeyEvent;\n\treturn ah;\n}\n\nvoid pkguiFreeAreaHandler(uiAreaHandler *ah)\n{\n\tfree(ah);\n}\n\n// cgo can't generate const, so we need this trampoline\nstatic void realDoTableModelSetCellValue(uiTableModelHandler *mh, uiTableModel *m, int row, int column, const uiTableValue *value)\n{\n\tpkguiDoTableModelSetCellValue(mh, m, row, column, (uiTableValue *) value);\n}\n\nconst uiTableModelHandler pkguiTableModelHandler = {\n\t.NumColumns = pkguiDoTableModelNumColumns,\n\t.ColumnType = pkguiDoTableModelColumnType,\n\t.NumRows = pkguiDoTableModelNumRows,\n\t.CellValue = pkguiDoTableModelCellValue,\n\t.SetCellValue = realDoTableModelSetCellValue,\n};\n\nuiTableTextColumnOptionalParams *pkguiAllocTableTextColumnOptionalParams(void)\n{\n\treturn (uiTableTextColumnOptionalParams *) pkguiAlloc(sizeof (uiTableTextColumnOptionalParams));\n}\n\nvoid pkguiFreeTableTextColumnOptionalParams(uiTableTextColumnOptionalParams *p)\n{\n\tfree(p);\n}\n\nuiTableParams *pkguiAllocTableParams(void)\n{\n\treturn (uiTableParams *) pkguiAlloc(sizeof (uiTableParams));\n}\n\nvoid pkguiFreeTableParams(uiTableParams *p)\n{\n\tfree(p);\n}\n"
  },
  {
    "path": "pkgui.h",
    "content": "// 12 august 2018\n#ifndef pkguiHFileIncluded\n#define pkguiHFileIncluded\n\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include \"ui.h\"\n\n// main.go\nextern uiInitOptions *pkguiAllocInitOptions(void);\nextern void pkguiFreeInitOptions(uiInitOptions *o);\nextern void pkguiQueueMain(uintptr_t n);\nextern void pkguiOnShouldQuit(void);\n\n// window.go\nextern void pkguiWindowOnClosing(uiWindow *w);\n\n// button.go\nextern void pkguiButtonOnClicked(uiButton *b);\n\n// checkbox.go\nextern void pkguiCheckboxOnToggled(uiCheckbox *c);\n\n// colorbutton.go\nextern void pkguiColorButtonOnChanged(uiColorButton *c);\ntypedef struct pkguiColorDoubles pkguiColorDoubles;\nstruct pkguiColorDoubles {\n\tdouble *r;\n\tdouble *g;\n\tdouble *b;\n\tdouble *a;\n};\nextern pkguiColorDoubles pkguiAllocColorDoubles(void);\nextern void pkguiFreeColorDoubles(pkguiColorDoubles c);\n\n// combobox.go\nextern void pkguiComboboxOnSelected(uiCombobox *c);\n\n// datetimepicker.go\nextern void pkguiDateTimePickerOnChanged(uiDateTimePicker *d);\nextern struct tm *pkguiAllocTime(void);\nextern void pkguiFreeTime(struct tm *t);\n\n// editablecombobox.go\nextern void pkguiEditableComboboxOnChanged(uiEditableCombobox *c);\n\n// entry.go\nextern void pkguiEntryOnChanged(uiEntry *e);\n\n// fontbutton.go\nextern void pkguiFontButtonOnChanged(uiFontButton *b);\n\n// multilineentry.go\nextern void pkguiMultilineEntryOnChanged(uiMultilineEntry *e);\n\n// radiobuttons.go\nextern void pkguiRadioButtonsOnSelected(uiRadioButtons *r);\n\n// slider.go\nextern void pkguiSliderOnChanged(uiSlider *s);\n\n// spinbox.go\nextern void pkguiSpinboxOnChanged(uiSpinbox *s);\n\n// draw.go\nextern uiDrawBrush *pkguiAllocBrush(void);\nextern void pkguiFreeBrush(uiDrawBrush *b);\nextern uiDrawBrushGradientStop *pkguiAllocGradientStops(size_t n);\nextern void pkguiFreeGradientStops(uiDrawBrushGradientStop *stops);\nextern void pkguiSetGradientStop(uiDrawBrushGradientStop *stops, size_t i, double pos, double r, double g, double b, double a);\nextern uiDrawStrokeParams *pkguiAllocStrokeParams(void);\nextern void pkguiFreeStrokeParams(uiDrawStrokeParams *p);\nextern double *pkguiAllocDashes(size_t n);\nextern void pkguiFreeDashes(double *dashes);\nextern void pkguiSetDash(double *dashes, size_t i, double dash);\nextern uiDrawMatrix *pkguiAllocMatrix(void);\nextern void pkguiFreeMatrix(uiDrawMatrix *m);\n\n// drawtext.go\nextern uiUnderlineColor *pkguiNewUnderlineColor(void);\nextern void pkguiFreeUnderlineColor(uiUnderlineColor *c);\nextern uiFontDescriptor *pkguiNewFontDescriptor(void);\nextern void pkguiFreeFontDescriptor(uiFontDescriptor *fd);\nextern uiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void);\nextern void pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *p);\n\n// areahandler.go\nextern uiAreaHandler *pkguiAllocAreaHandler(void);\nextern void pkguiFreeAreaHandler(uiAreaHandler *ah);\n\n// tablemodel.go\nextern const uiTableModelHandler pkguiTableModelHandler;\n\n// table.go\nextern uiTableTextColumnOptionalParams *pkguiAllocTableTextColumnOptionalParams(void);\nextern void pkguiFreeTableTextColumnOptionalParams(uiTableTextColumnOptionalParams *p);\nextern uiTableParams *pkguiAllocTableParams(void);\nextern void pkguiFreeTableParams(uiTableParams *p);\n\n#endif\n"
  },
  {
    "path": "progressbar.go",
    "content": "// 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 that represents a horizontal bar that\n// is filled in progressively over time as a process completes.\ntype ProgressBar struct {\n\tControlBase\n\tp\t*C.uiProgressBar\n}\n\n// NewProgressBar creates a new ProgressBar.\nfunc NewProgressBar() *ProgressBar {\n\tp := new(ProgressBar)\n\n\tp.p = C.uiNewProgressBar()\n\n\tp.ControlBase = NewControlBase(p, uintptr(unsafe.Pointer(p.p)))\n\treturn p\n}\n\n// Value returns the value currently shown in the ProgressBar.\nfunc (p *ProgressBar) Value() int {\n\treturn int(C.uiProgressBarValue(p.p))\n}\n\n// SetValue sets the ProgressBar's currently displayed percentage\n// to value. value must be between 0 and 100 inclusive, or -1 for\n// an indeterminate progressbar.\nfunc (p *ProgressBar) SetValue(value int) {\n\tC.uiProgressBarSetValue(p.p, C.int(value))\n}\n"
  },
  {
    "path": "radiobuttons.go",
    "content": "// 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 that represents a set of checkable\n// buttons from which exactly one may be chosen by the user.\ntype RadioButtons struct {\n\tControlBase\n\tr\t*C.uiRadioButtons\n\tonSelected\tfunc(*RadioButtons)\n}\n\n// NewRadioButtons creates a new RadioButtons.\nfunc NewRadioButtons() *RadioButtons {\n\tr := new(RadioButtons)\n\n\tr.r = C.uiNewRadioButtons()\n\n\tC.pkguiRadioButtonsOnSelected(r.r)\n\n\tr.ControlBase = NewControlBase(r, uintptr(unsafe.Pointer(r.r)))\n\treturn r\n}\n\n// Append adds the named button to the end of the RadioButtons.\nfunc (r *RadioButtons) Append(text string) {\n\tctext := C.CString(text)\n\tC.uiRadioButtonsAppend(r.r, ctext)\n\tfreestr(ctext)\n}\n\n// Selected returns the index of the currently selected option in the\n// RadioButtons, or -1 if no item is selected.\nfunc (r *RadioButtons) Selected() int {\n\treturn int(C.uiRadioButtonsSelected(r.r))\n}\n\n// SetSelected sets the currently selected option in the RadioButtons\n// to index.\nfunc (r *RadioButtons) SetSelected(index int) {\n\tC.uiRadioButtonsSetSelected(r.r, C.int(index))\n}\n\n// OnSelected registers f to be run when the user selects an option in\n// the RadioButtons. Only one function can be registered at a time.\nfunc (r *RadioButtons) OnSelected(f func(*RadioButtons)) {\n\tr.onSelected = f\n}\n\n//export pkguiDoRadioButtonsOnSelected\nfunc pkguiDoRadioButtonsOnSelected(rr *C.uiRadioButtons, data unsafe.Pointer) {\n\tr := ControlFromLibui(uintptr(unsafe.Pointer(rr))).(*RadioButtons)\n\tif r.onSelected != nil {\n\t\tr.onSelected(r)\n\t}\n}\n"
  },
  {
    "path": "separator.go",
    "content": "// 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 represents a horizontal line that\n// visually separates controls.\ntype Separator struct {\n\tControlBase\n\ts\t*C.uiSeparator\n}\n\n// NewHorizontalSeparator creates a new horizontal Separator.\nfunc NewHorizontalSeparator() *Separator {\n\ts := new(Separator)\n\n\ts.s = C.uiNewHorizontalSeparator()\n\n\ts.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))\n\treturn s\n}\n\n// NewVerticalSeparator creates a new vertical Separator.\nfunc NewVerticalSeparator() *Separator {\n\ts := new(Separator)\n\n\ts.s = C.uiNewVerticalSeparator()\n\n\ts.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))\n\treturn s\n}\n"
  },
  {
    "path": "slider.go",
    "content": "// 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 represents a horizontal bar that represents\n// a range of integers. The user can drag a pointer on the bar to\n// select an integer.\ntype Slider struct {\n\tControlBase\n\ts\t*C.uiSlider\n\tonChanged\t\tfunc(*Slider)\n}\n\n// NewSlider creates a new Slider. If min >= max, they are swapped.\nfunc NewSlider(min int, max int) *Slider {\n\ts := new(Slider)\n\n\ts.s = C.uiNewSlider(C.int(min), C.int(max))\n\n\tC.pkguiSliderOnChanged(s.s)\n\n\ts.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))\n\treturn s\n}\n\n// Value returns the Slider's current value.\nfunc (s *Slider) Value() int {\n\treturn int(C.uiSliderValue(s.s))\n}\n\n// SetValue sets the Slider's current value to value.\nfunc (s *Slider) SetValue(value int) {\n\tC.uiSliderSetValue(s.s, C.int(value))\n}\n\n// OnChanged registers f to be run when the user changes the value\n// of the Slider. Only one function can be registered at a time.\nfunc (s *Slider) OnChanged(f func(*Slider)) {\n\ts.onChanged = f\n}\n\n//export pkguiDoSliderOnChanged\nfunc pkguiDoSliderOnChanged(ss *C.uiSlider, data unsafe.Pointer) {\n\ts := ControlFromLibui(uintptr(unsafe.Pointer(ss))).(*Slider)\n\tif s.onChanged != nil {\n\t\ts.onChanged(s)\n\t}\n}\n"
  },
  {
    "path": "spinbox.go",
    "content": "// 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 represents a space where the user can\n// enter integers. The space also comes with buttons to add or\n// subtract 1 from the integer.\ntype Spinbox struct {\n\tControlBase\n\ts\t*C.uiSpinbox\n\tonChanged\t\tfunc(*Spinbox)\n}\n\n// NewSpinbox creates a new Spinbox. If min >= max, they are swapped.\nfunc NewSpinbox(min int, max int) *Spinbox {\n\ts := new(Spinbox)\n\n\ts.s = C.uiNewSpinbox(C.int(min), C.int(max))\n\n\tC.pkguiSpinboxOnChanged(s.s)\n\n\ts.ControlBase = NewControlBase(s, uintptr(unsafe.Pointer(s.s)))\n\treturn s\n}\n\n// Value returns the Spinbox's current value.\nfunc (s *Spinbox) Value() int {\n\treturn int(C.uiSpinboxValue(s.s))\n}\n\n// SetValue sets the Spinbox's current value to value.\nfunc (s *Spinbox) SetValue(value int) {\n\tC.uiSpinboxSetValue(s.s, C.int(value))\n}\n\n// OnChanged registers f to be run when the user changes the value\n// of the Spinbox. Only one function can be registered at a time.\nfunc (s *Spinbox) OnChanged(f func(*Spinbox)) {\n\ts.onChanged = f\n}\n\n//export pkguiDoSpinboxOnChanged\nfunc pkguiDoSpinboxOnChanged(ss *C.uiSpinbox, data unsafe.Pointer) {\n\ts := ControlFromLibui(uintptr(unsafe.Pointer(ss))).(*Spinbox)\n\tif s.onChanged != nil {\n\t\ts.onChanged(s)\n\t}\n}\n"
  },
  {
    "path": "stddialogs.go",
    "content": "// 20 december 2015\n\npackage ui\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// TODO\nfunc MsgBoxError(w *Window, title string, description string) {\n\tctitle := C.CString(title)\n\tdefer freestr(ctitle)\n\tcdescription := C.CString(description)\n\tdefer freestr(cdescription)\n\tC.uiMsgBoxError(w.w, ctitle, cdescription)\n}\n\nfunc OpenFile(w *Window) string {\n\tcname := C.uiOpenFile(w.w)\n\tif cname == nil {\n\t\treturn \"\"\n\t}\n\tdefer C.uiFreeText(cname)\n\treturn C.GoString(cname)\n}\n\nfunc SaveFile(w *Window) string {\n\tcname := C.uiSaveFile(w.w)\n\tif cname == nil {\n\t\treturn \"\"\n\t}\n\tdefer C.uiFreeText(cname)\n\treturn C.GoString(cname)\n}\n\nfunc MsgBox(w *Window, title string, description string) {\n\tctitle := C.CString(title)\n\tdefer freestr(ctitle)\n\tcdescription := C.CString(description)\n\tdefer freestr(cdescription)\n\tC.uiMsgBox(w.w, ctitle, cdescription)\n}\n"
  },
  {
    "path": "tab.go",
    "content": "// 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 tabbed pages of Controls. Each tab\n// has a label. The user can click on the tabs themselves to switch\n// pages. Individual pages can also have margins.\ntype Tab struct {\n\tControlBase\n\tt\t*C.uiTab\n\tchildren\t[]Control\n}\n\n// NewTab creates a new Tab.\nfunc NewTab() *Tab {\n\tt := new(Tab)\n\n\tt.t = C.uiNewTab()\n\n\tt.ControlBase = NewControlBase(t, uintptr(unsafe.Pointer(t.t)))\n\treturn t\n}\n\n// Destroy destroys the Tab. If the Tab has pages,\n// Destroy calls Destroy on the pages's Controls as well.\nfunc (t *Tab) Destroy() {\n\tfor len(t.children) != 0 {\n\t\tc := t.children[0]\n\t\tt.Delete(0)\n\t\tc.Destroy()\n\t}\n\tt.ControlBase.Destroy()\n}\n\n// Append adds the given page to the end of the Tab.\nfunc (t *Tab) Append(name string, child Control) {\n\tt.InsertAt(name, len(t.children), child)\n}\n\n// InsertAt adds the given page to the Tab such that it is the\n// nth page of the Tab (starting at 0).\nfunc (t *Tab) InsertAt(name string, n int, child Control) {\n\tc := (*C.uiControl)(nil)\n\tif child != nil {\n\t\tc = touiControl(child.LibuiControl())\n\t}\n\tcname := C.CString(name)\n\tC.uiTabInsertAt(t.t, cname, C.int(n), c)\n\tfreestr(cname)\n\tch := make([]Control, len(t.children) + 1)\n\t// and insert into t.children at the right place\n\tcopy(ch[:n], t.children[:n])\n\tch[n] = child\n\tcopy(ch[n + 1:], t.children[n:])\n\tt.children = ch\n}\n\n// Delete deletes the nth page of the Tab.\nfunc (t *Tab) Delete(n int) {\n\tt.children = append(t.children[:n], t.children[n + 1:]...)\n\tC.uiTabDelete(t.t, C.int(n))\n}\n\n// NumPages returns the number of pages in the Tab.\nfunc (t *Tab) NumPages() int {\n\treturn len(t.children)\n}\n\n// Margined returns whether page n (starting at 0) of the Tab\n// has margins around its child.\nfunc (t *Tab) Margined(n int) bool {\n\treturn tobool(C.uiTabMargined(t.t, C.int(n)))\n}\n\n// SetMargined controls whether page n (starting at 0) of the Tab\n// has margins around its child. The size of the margins are\n// determined by the OS and its best practices.\nfunc (t *Tab) SetMargined(n int, margined bool) {\n\tC.uiTabSetMargined(t.t, C.int(n), frombool(margined))\n}\n"
  },
  {
    "path": "table.go",
    "content": "// 26 august 2018\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n// TableModelColumnNeverEditable and\n// TableModelColumnAlwaysEditable are the value of an editable\n// model column parameter to one of the Table create column\n// functions; if used, that jparticular Table colum is not editable\n// by the user and always editable by the user, respectively.\nconst (\n\tTableModelColumnNeverEditable = -1\n\tTableModelColumnAlwaysEditable = -2\n)\n\n// TableTextColumnOptionalParams are the optional parameters\n// that control the appearance of the text column of a Table.\ntype TableTextColumnOptionalParams struct {\n\t// ColorModelColumn is the model column containing the\n\t// text color of this Table column's text, or -1 to use the\n\t// default color.\n\t//\n\t// If CellValue for this column for any cell returns nil, that\n\t// cell will also use the default text color.\n\tColorModelColumn\t\tint\n}\n\nfunc (p *TableTextColumnOptionalParams) toLibui() *C.uiTableTextColumnOptionalParams {\n\tif p == nil {\n\t\treturn nil\n\t}\n\tcp := C.pkguiAllocTableTextColumnOptionalParams()\n\tcp.ColorModelColumn = C.int(p.ColorModelColumn)\n\treturn cp\n}\n\n// TableParams defines the parameters passed to NewTable.\ntype TableParams struct {\n\t// Model is the TableModel to use for this uiTable.\n\t// This parameter cannot be nil.\n\tModel\t\t*TableModel\n\n\t// RowBackgroundColorModelColumn is a model column\n\t// number that defines the background color used for the\n\t// entire row in the Table, or -1 to use the default color for\n\t// all rows.\n\t//\n\t// If CellValue for this column for any row returns NULL, that\n\t// row will also use the default background color.\n\tRowBackgroundColorModelColumn\t\tint\n}\n\nfunc (p *TableParams) toLibui() *C.uiTableParams {\n\tcp := C.pkguiAllocTableParams()\n\tcp.Model = p.Model.m\n\tcp.RowBackgroundColorModelColumn = C.int(p.RowBackgroundColorModelColumn)\n\treturn cp\n}\n\n// Table is a Control that shows tabular data, allowing users to\n// manipulate rows of such data at a time.\ntype Table struct {\n\tControlBase\n\tt\t*C.uiTable\n}\n\n// NewTable creates a new Table with the specified parameters.\nfunc NewTable(p *TableParams) *Table {\n\tt := new(Table)\n\n\tcp := p.toLibui()\n\tt.t = C.uiNewTable(cp)\n\tC.pkguiFreeTableParams(cp)\n\n\tt.ControlBase = NewControlBase(t, uintptr(unsafe.Pointer(t.t)))\n\treturn t\n}\n\n// AppendTextColumn appends a text column to t. name is\n// displayed in the table header. textModelColumn is where the text\n// comes from. If a row is editable according to\n// textEditableModelColumn, SetCellValue is called with\n// textModelColumn as the column.\nfunc (t *Table) AppendTextColumn(name string, textModelColumn int, textEditableModelColumn int, textParams *TableTextColumnOptionalParams) {\n\tcname := C.CString(name)\n\tdefer freestr(cname)\n\tcp := textParams.toLibui()\n\tdefer C.pkguiFreeTableTextColumnOptionalParams(cp)\n\tC.uiTableAppendTextColumn(t.t, cname, C.int(textModelColumn), C.int(textEditableModelColumn), cp)\n}\n\n// AppendImageColumn appends an image column to t.\n// Images are drawn at icon size, appropriate to the pixel density\n// of the screen showing the Table.\nfunc (t *Table) AppendImageColumn(name string, imageModelColumn int) {\n\tcname := C.CString(name)\n\tdefer freestr(cname)\n\tC.uiTableAppendImageColumn(t.t, cname, C.int(imageModelColumn))\n}\n\n// AppendImageTextColumn appends a column to t that\n// shows both an image and text.\nfunc (t *Table) AppendImageTextColumn(name string, imageModelColumn int, textModelColumn int, textEditableModelColumn int, textParams *TableTextColumnOptionalParams) {\n\tcname := C.CString(name)\n\tdefer freestr(cname)\n\tcp := textParams.toLibui()\n\tdefer C.pkguiFreeTableTextColumnOptionalParams(cp)\n\tC.uiTableAppendImageTextColumn(t.t, cname, C.int(imageModelColumn), C.int(textModelColumn), C.int(textEditableModelColumn), cp)\n}\n\n// AppendCheckboxColumn appends a column to t that\n// contains a checkbox that the user can interact with (assuming the\n// checkbox is editable). SetCellValue will be called with\n// checkboxModelColumn as the column in this case.\nfunc (t *Table) AppendCheckboxColumn(name string, checkboxModelColumn int, checkboxEditableModelColumn int) {\n\tcname := C.CString(name)\n\tdefer freestr(cname)\n\tC.uiTableAppendCheckboxColumn(t.t, cname, C.int(checkboxModelColumn), C.int(checkboxEditableModelColumn))\n}\n\n// AppendCheckboxTextColumn appends a column to t\n// that contains both a checkbox and text.\nfunc (t *Table) AppendCheckboxTextColumn(name string, checkboxModelColumn int, checkboxEditableModelColumn int, textModelColumn int, textEditableModelColumn int, textParams *TableTextColumnOptionalParams) {\n\tcname := C.CString(name)\n\tdefer freestr(cname)\n\tcp := textParams.toLibui()\n\tdefer C.pkguiFreeTableTextColumnOptionalParams(cp)\n\tC.uiTableAppendCheckboxTextColumn(t.t, cname, C.int(checkboxModelColumn), C.int(checkboxEditableModelColumn), C.int(textModelColumn), C.int(textEditableModelColumn), cp)\n}\n\n// AppendProgressBarColumn appends a column to t\n// that displays a progress bar. These columns work like\n// ProgressBar: a cell value of 0..100 displays that percentage, and\n// a cell value of -1 displays an indeterminate progress bar.\nfunc (t *Table) AppendProgressBarColumn(name string, progressModelColumn int) {\n\tcname := C.CString(name)\n\tdefer freestr(cname)\n\tC.uiTableAppendProgressBarColumn(t.t, cname, C.int(progressModelColumn))\n}\n\n// AppendButtonColumn appends a column to t\n// that shows a button that the user can click on. When the user\n// does click on the button, SetCellValue is called with a nil\n// value and buttonModelColumn as the column.\n// CellValue on buttonModelColumn should return the text to show\n// in the button.\nfunc (t *Table) AppendButtonColumn(name string, buttonModelColumn int, buttonClickableModelColumn int) {\n\tcname := C.CString(name)\n\tdefer freestr(cname)\n\tC.uiTableAppendButtonColumn(t.t, cname, C.int(buttonModelColumn), C.int(buttonClickableModelColumn))\n}\n"
  },
  {
    "path": "tablemodel.go",
    "content": "// 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 that can come\n// out of a TableModel.\ntype TableValue interface {\n\ttoLibui() *C.uiTableValue\n}\n\n// TableString is a TableValue that stores a string. TableString is\n// used for displaying text in a Table.\ntype TableString string\n\nfunc (s TableString) toLibui() *C.uiTableValue {\n\tcs := C.CString(string(s))\n\tdefer freestr(cs)\n\treturn C.uiNewTableValueString(cs)\n}\n\n// TableImage is a TableValue that represents an Image. Ownership\n// of the Image is not copied; you must keep it alive alongside the\n// TableImage.\ntype TableImage struct {\n\tI\t*Image\n}\n\nfunc (i TableImage) toLibui() *C.uiTableValue {\n\treturn C.uiNewTableValueImage(i.I.i)\n}\n\n// TableInt is a TableValue that stores integers. These are used for\n// progressbars. Due to current limitations of libui, they also\n// represent checkbox states, via TableFalse and TableTrue.\ntype TableInt int\n\n// TableFalse and TableTrue are the Boolean constants for TableInt.\nconst (\n\tTableFalse TableInt = 0\n\tTableTrue TableInt = 1\n)\n\nfunc (i TableInt) toLibui() *C.uiTableValue {\n\treturn C.uiNewTableValueInt(C.int(i))\n}\n\n// TableColor is a TableValue that represents a color.\ntype TableColor struct {\n\tR\tfloat64\n\tG\tfloat64\n\tB\tfloat64\n\tA\tfloat64\n}\n\nfunc (c TableColor) toLibui() *C.uiTableValue {\n\treturn C.uiNewTableValueColor(C.double(c.R), C.double(c.G), C.double(c.B), C.double(c.A))\n}\n\nfunc tableValueFromLibui(value *C.uiTableValue) TableValue {\n\tif value == nil {\n\t\treturn nil\n\t}\n\tswitch C.uiTableValueGetType(value) {\n\tcase C.uiTableValueTypeString:\n\t\tcs := C.uiTableValueString(value)\n\t\treturn TableString(C.GoString(cs))\n\tcase C.uiTableValueTypeImage:\n\t\tpanic(\"TODO\")\n\tcase C.uiTableValueTypeInt:\n\t\treturn TableInt(C.uiTableValueInt(value))\n\tcase C.uiTableValueTypeColor:\n\t\tpanic(\"TODO\")\n\t}\n\tpanic(\"unreachable\")\n}\n\n// no need to lock these; only the GUI thread can access them\nvar modelhandlers = make(map[*C.uiTableModel]TableModelHandler)\nvar models = make(map[*C.uiTableModel]*TableModel)\n\n// TableModel is an object that provides the data for a Table.\n// This data is returned via methods you provide in the\n// TableModelHandler interface.\n//\n// TableModel represents data using a table, but this table does\n// not map directly to Table itself. Instead, you can have data\n// columns which provide instructions for how to render a given\n// Table's column — for instance, one model column can be used\n// to give certain rows of a Table a different background color.\n// Row numbers DO match with uiTable row numbers.\n//\n// Once created, the number and data types of columns of a\n// TableModel cannot change.\n//\n// Row and column numbers start at 0. A TableModel can be\n// associated with more than one Table at a time.\ntype TableModel struct {\n\tm\t*C.uiTableModel\n}\n\n// TableModelHandler defines the methods that TableModel\n// calls when it needs data.\ntype TableModelHandler interface {\n\t// ColumnTypes returns a slice of value types of the data\n\t// stored in the model columns of the TableModel.\n\t// Each entry in the slice should ideally be a zero value for\n\t// the TableValue type of the column in question; the number\n\t// of elements in the slice determines the number of model\n\t// columns in the TableModel. The returned slice must remain\n\t// constant through the lifetime of the TableModel. This\n\t// method is not guaranteed to be called depending on the\n\t// system.\n\tColumnTypes(m *TableModel) []TableValue\n\n\t// NumRows returns the number or rows in the TableModel.\n\t// This value must be non-negative.\n\tNumRows(m *TableModel) int\n\n\t// CellValue returns a TableValue corresponding to the model\n\t// cell at (row, column). The type of the returned TableValue\n\t// must match column's value type. Under some circumstances,\n\t// nil may be returned; refer to the various methods that add\n\t// columns to Table for details.\n\tCellValue(m *TableModel, row, column int) TableValue\n\n\t// SetCellValue changes the model cell value at (row, column)\n\t// in the TableModel. Within this function, either do nothing\n\t// to keep the current cell value or save the new cell value as\n\t// appropriate. After SetCellValue is called, the Table will\n\t// itself reload the table cell. Under certain conditions, the\n\t// TableValue passed in can be nil; refer to the various\n\t// methods that add columns to Table for details.\n\tSetCellValue(m *TableModel, row, column int, value TableValue)\n}\n\n//export pkguiDoTableModelNumColumns\nfunc pkguiDoTableModelNumColumns(umh *C.uiTableModelHandler, um *C.uiTableModel) C.int {\n\tmh := modelhandlers[um]\n\treturn C.int(len(mh.ColumnTypes(models[um])))\n}\n\n//export pkguiDoTableModelColumnType\nfunc pkguiDoTableModelColumnType(umh *C.uiTableModelHandler, um *C.uiTableModel, n C.int) C.uiTableValueType {\n\tmh := modelhandlers[um]\n\tc := mh.ColumnTypes(models[um])\n\tswitch c[n].(type) {\n\tcase TableString:\n\t\treturn C.uiTableValueTypeString\n\tcase TableImage:\n\t\treturn C.uiTableValueTypeImage\n\tcase TableInt:\n\t\treturn C.uiTableValueTypeInt\n\tcase TableColor:\n\t\treturn C.uiTableValueTypeColor\n\t}\n\tpanic(\"unreachable\")\n}\n\n//export pkguiDoTableModelNumRows\nfunc pkguiDoTableModelNumRows(umh *C.uiTableModelHandler, um *C.uiTableModel) C.int {\n\tmh := modelhandlers[um]\n\treturn C.int(mh.NumRows(models[um]))\n}\n\n//export pkguiDoTableModelCellValue\nfunc pkguiDoTableModelCellValue(umh *C.uiTableModelHandler, um *C.uiTableModel, row, column C.int) *C.uiTableValue {\n\tmh := modelhandlers[um]\n\tv := mh.CellValue(models[um], int(row), int(column))\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn v.toLibui()\n}\n\n//export pkguiDoTableModelSetCellValue\nfunc pkguiDoTableModelSetCellValue(umh *C.uiTableModelHandler, um *C.uiTableModel, row, column C.int, value *C.uiTableValue) {\n\tmh := modelhandlers[um]\n\tv := tableValueFromLibui(value)\n\tmh.SetCellValue(models[um], int(row), int(column), v)\n}\n\n// NewTableModel creates a new TableModel.\nfunc NewTableModel(handler TableModelHandler) *TableModel {\n\tm := &TableModel{\n\t\tm:\tC.uiNewTableModel(&C.pkguiTableModelHandler),\n\t}\n\tmodelhandlers[m.m] = handler\n\tmodels[m.m] = m\n\treturn m\n}\n\n// Free frees m. It is an error to Free any models associated with a\n// Table.\nfunc (m *TableModel) Free() {\n\tdelete(models, m.m)\n\tdelete(modelhandlers, m.m)\n\tC.uiFreeTableModel(m.m)\n}\n\n// RowInserted tells any Tables associated with m that a new row\n// has been added to m at index index. You call this method when\n// the number of rows in your model has changed; after calling it,\n// NumRows should returm the new row count.\nfunc (m *TableModel) RowInserted(index int) {\n\tC.uiTableModelRowInserted(m.m, C.int(index))\n}\n\n// RowChanged tells any Tables associated with m that the data in\n// the row at index has changed. You do not need to call this in\n// your SetCellValue handlers, but you do need to call this if your\n// data changes at some other point.\nfunc (m *TableModel) RowChanged(index int) {\n\tC.uiTableModelRowChanged(m.m, C.int(index))\n}\n\n// RowDeleted tells any Tables associated with m that the row at\n// index index has been deleted. You call this function when the\n// number of rows in your model has changed; after calling it,\n// NumRows should returm the new row count.\nfunc (m *TableModel) RowDeleted(index int) {\n\tC.uiTableModelRowDeleted(m.m, C.int(index))\n}\n"
  },
  {
    "path": "ui.h",
    "content": "// 6 april 2015\n\n// TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls\n\n// TODOs\n// - make getters that return whether something exists accept a NULL pointer to discard the value (and thus only return that the thing exists?)\n// - const-correct everything\n// - normalize documentation between typedefs and structs\n\n#ifndef __LIBUI_UI_H__\n#define __LIBUI_UI_H__\n\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// this macro is generated by cmake\n#ifdef libui_EXPORTS\n#ifdef _WIN32\n#define _UI_EXTERN __declspec(dllexport) extern\n#else\n#define _UI_EXTERN __attribute__((visibility(\"default\"))) extern\n#endif\n#else\n// TODO add __declspec(dllimport) on windows, but only if not static\n#define _UI_EXTERN extern\n#endif\n\n// C++ is really really really really really really dumb about enums, so screw that and just make them anonymous\n// This has the advantage of being ABI-able should we ever need an ABI...\n#define _UI_ENUM(s) typedef unsigned int s; enum\n\n// This constant is provided because M_PI is nonstandard.\n// This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796.\n#define uiPi 3.14159265358979323846264338327950288419716939937510582097494459\n\n// TODO uiBool?\n\n// uiForEach represents the return value from one of libui's various ForEach functions.\n_UI_ENUM(uiForEach) {\n\tuiForEachContinue,\n\tuiForEachStop,\n};\n\ntypedef struct uiInitOptions uiInitOptions;\n\nstruct uiInitOptions {\n\tsize_t Size;\n};\n\n_UI_EXTERN const char *uiInit(uiInitOptions *options);\n_UI_EXTERN void uiUninit(void);\n_UI_EXTERN void uiFreeInitError(const char *err);\n\n_UI_EXTERN void uiMain(void);\n_UI_EXTERN void uiMainSteps(void);\n_UI_EXTERN int uiMainStep(int wait);\n_UI_EXTERN void uiQuit(void);\n\n_UI_EXTERN void uiQueueMain(void (*f)(void *data), void *data);\n\n// TODO standardize the looping behavior return type, either with some enum or something, and the test expressions throughout the code\n// 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\n// TODO (also in the above link) document that this cannot be called from any thread, unlike uiQueueMain()\n// TODO document that the minimum exact timing, either accuracy (timer burst, etc.) or granularity (15ms on Windows, etc.), is OS-defined\n// TODO also figure out how long until the initial tick is registered on all platforms to document\n// TODO also add a comment about how useful this could be in bindings, depending on the language being bound to\n_UI_EXTERN void uiTimer(int milliseconds, int (*f)(void *data), void *data);\n\n_UI_EXTERN void uiOnShouldQuit(int (*f)(void *data), void *data);\n\n_UI_EXTERN void uiFreeText(char *text);\n\ntypedef struct uiControl uiControl;\n\nstruct uiControl {\n\tuint32_t Signature;\n\tuint32_t OSSignature;\n\tuint32_t TypeSignature;\n\tvoid (*Destroy)(uiControl *);\n\tuintptr_t (*Handle)(uiControl *);\n\tuiControl *(*Parent)(uiControl *);\n\tvoid (*SetParent)(uiControl *, uiControl *);\n\tint (*Toplevel)(uiControl *);\n\tint (*Visible)(uiControl *);\n\tvoid (*Show)(uiControl *);\n\tvoid (*Hide)(uiControl *);\n\tint (*Enabled)(uiControl *);\n\tvoid (*Enable)(uiControl *);\n\tvoid (*Disable)(uiControl *);\n};\n// TOOD add argument names to all arguments\n#define uiControl(this) ((uiControl *) (this))\n_UI_EXTERN void uiControlDestroy(uiControl *);\n_UI_EXTERN uintptr_t uiControlHandle(uiControl *);\n_UI_EXTERN uiControl *uiControlParent(uiControl *);\n_UI_EXTERN void uiControlSetParent(uiControl *, uiControl *);\n_UI_EXTERN int uiControlToplevel(uiControl *);\n_UI_EXTERN int uiControlVisible(uiControl *);\n_UI_EXTERN void uiControlShow(uiControl *);\n_UI_EXTERN void uiControlHide(uiControl *);\n_UI_EXTERN int uiControlEnabled(uiControl *);\n_UI_EXTERN void uiControlEnable(uiControl *);\n_UI_EXTERN void uiControlDisable(uiControl *);\n\n_UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr);\n_UI_EXTERN void uiFreeControl(uiControl *);\n\n// TODO make sure all controls have these\n_UI_EXTERN void uiControlVerifySetParent(uiControl *, uiControl *);\n_UI_EXTERN int uiControlEnabledToUser(uiControl *);\n\n_UI_EXTERN void uiUserBugCannotSetParentOnToplevel(const char *type);\n\ntypedef struct uiWindow uiWindow;\n#define uiWindow(this) ((uiWindow *) (this))\n_UI_EXTERN char *uiWindowTitle(uiWindow *w);\n_UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title);\n_UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height);\n_UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height);\n_UI_EXTERN int uiWindowFullscreen(uiWindow *w);\n_UI_EXTERN void uiWindowSetFullscreen(uiWindow *w, int fullscreen);\n_UI_EXTERN void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data);\n_UI_EXTERN void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *w, void *data), void *data);\n_UI_EXTERN int uiWindowBorderless(uiWindow *w);\n_UI_EXTERN void uiWindowSetBorderless(uiWindow *w, int borderless);\n_UI_EXTERN void uiWindowSetChild(uiWindow *w, uiControl *child);\n_UI_EXTERN int uiWindowMargined(uiWindow *w);\n_UI_EXTERN void uiWindowSetMargined(uiWindow *w, int margined);\n_UI_EXTERN uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar);\n\ntypedef struct uiButton uiButton;\n#define uiButton(this) ((uiButton *) (this))\n_UI_EXTERN char *uiButtonText(uiButton *b);\n_UI_EXTERN void uiButtonSetText(uiButton *b, const char *text);\n_UI_EXTERN void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *b, void *data), void *data);\n_UI_EXTERN uiButton *uiNewButton(const char *text);\n\ntypedef struct uiBox uiBox;\n#define uiBox(this) ((uiBox *) (this))\n_UI_EXTERN void uiBoxAppend(uiBox *b, uiControl *child, int stretchy);\n_UI_EXTERN void uiBoxDelete(uiBox *b, int index);\n_UI_EXTERN int uiBoxPadded(uiBox *b);\n_UI_EXTERN void uiBoxSetPadded(uiBox *b, int padded);\n_UI_EXTERN uiBox *uiNewHorizontalBox(void);\n_UI_EXTERN uiBox *uiNewVerticalBox(void);\n\ntypedef struct uiCheckbox uiCheckbox;\n#define uiCheckbox(this) ((uiCheckbox *) (this))\n_UI_EXTERN char *uiCheckboxText(uiCheckbox *c);\n_UI_EXTERN void uiCheckboxSetText(uiCheckbox *c, const char *text);\n_UI_EXTERN void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *c, void *data), void *data);\n_UI_EXTERN int uiCheckboxChecked(uiCheckbox *c);\n_UI_EXTERN void uiCheckboxSetChecked(uiCheckbox *c, int checked);\n_UI_EXTERN uiCheckbox *uiNewCheckbox(const char *text);\n\ntypedef struct uiEntry uiEntry;\n#define uiEntry(this) ((uiEntry *) (this))\n_UI_EXTERN char *uiEntryText(uiEntry *e);\n_UI_EXTERN void uiEntrySetText(uiEntry *e, const char *text);\n_UI_EXTERN void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *e, void *data), void *data);\n_UI_EXTERN int uiEntryReadOnly(uiEntry *e);\n_UI_EXTERN void uiEntrySetReadOnly(uiEntry *e, int readonly);\n_UI_EXTERN uiEntry *uiNewEntry(void);\n_UI_EXTERN uiEntry *uiNewPasswordEntry(void);\n_UI_EXTERN uiEntry *uiNewSearchEntry(void);\n\ntypedef struct uiLabel uiLabel;\n#define uiLabel(this) ((uiLabel *) (this))\n_UI_EXTERN char *uiLabelText(uiLabel *l);\n_UI_EXTERN void uiLabelSetText(uiLabel *l, const char *text);\n_UI_EXTERN uiLabel *uiNewLabel(const char *text);\n\ntypedef struct uiTab uiTab;\n#define uiTab(this) ((uiTab *) (this))\n_UI_EXTERN void uiTabAppend(uiTab *t, const char *name, uiControl *c);\n_UI_EXTERN void uiTabInsertAt(uiTab *t, const char *name, int before, uiControl *c);\n_UI_EXTERN void uiTabDelete(uiTab *t, int index);\n_UI_EXTERN int uiTabNumPages(uiTab *t);\n_UI_EXTERN int uiTabMargined(uiTab *t, int page);\n_UI_EXTERN void uiTabSetMargined(uiTab *t, int page, int margined);\n_UI_EXTERN uiTab *uiNewTab(void);\n\ntypedef struct uiGroup uiGroup;\n#define uiGroup(this) ((uiGroup *) (this))\n_UI_EXTERN char *uiGroupTitle(uiGroup *g);\n_UI_EXTERN void uiGroupSetTitle(uiGroup *g, const char *title);\n_UI_EXTERN void uiGroupSetChild(uiGroup *g, uiControl *c);\n_UI_EXTERN int uiGroupMargined(uiGroup *g);\n_UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined);\n_UI_EXTERN uiGroup *uiNewGroup(const char *title);\n\n// spinbox/slider rules:\n// setting value outside of range will automatically clamp\n// initial value is minimum\n// complaint if min >= max?\n\ntypedef struct uiSpinbox uiSpinbox;\n#define uiSpinbox(this) ((uiSpinbox *) (this))\n_UI_EXTERN int uiSpinboxValue(uiSpinbox *s);\n_UI_EXTERN void uiSpinboxSetValue(uiSpinbox *s, int value);\n_UI_EXTERN void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *s, void *data), void *data);\n_UI_EXTERN uiSpinbox *uiNewSpinbox(int min, int max);\n\ntypedef struct uiSlider uiSlider;\n#define uiSlider(this) ((uiSlider *) (this))\n_UI_EXTERN int uiSliderValue(uiSlider *s);\n_UI_EXTERN void uiSliderSetValue(uiSlider *s, int value);\n_UI_EXTERN void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *s, void *data), void *data);\n_UI_EXTERN uiSlider *uiNewSlider(int min, int max);\n\ntypedef struct uiProgressBar uiProgressBar;\n#define uiProgressBar(this) ((uiProgressBar *) (this))\n_UI_EXTERN int uiProgressBarValue(uiProgressBar *p);\n_UI_EXTERN void uiProgressBarSetValue(uiProgressBar *p, int n);\n_UI_EXTERN uiProgressBar *uiNewProgressBar(void);\n\ntypedef struct uiSeparator uiSeparator;\n#define uiSeparator(this) ((uiSeparator *) (this))\n_UI_EXTERN uiSeparator *uiNewHorizontalSeparator(void);\n_UI_EXTERN uiSeparator *uiNewVerticalSeparator(void);\n\ntypedef struct uiCombobox uiCombobox;\n#define uiCombobox(this) ((uiCombobox *) (this))\n_UI_EXTERN void uiComboboxAppend(uiCombobox *c, const char *text);\n_UI_EXTERN int uiComboboxSelected(uiCombobox *c);\n_UI_EXTERN void uiComboboxSetSelected(uiCombobox *c, int n);\n_UI_EXTERN void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data);\n_UI_EXTERN uiCombobox *uiNewCombobox(void);\n\ntypedef struct uiEditableCombobox uiEditableCombobox;\n#define uiEditableCombobox(this) ((uiEditableCombobox *) (this))\n_UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text);\n_UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c);\n_UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text);\n// 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\n_UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data);\n_UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void);\n\ntypedef struct uiRadioButtons uiRadioButtons;\n#define uiRadioButtons(this) ((uiRadioButtons *) (this))\n_UI_EXTERN void uiRadioButtonsAppend(uiRadioButtons *r, const char *text);\n_UI_EXTERN int uiRadioButtonsSelected(uiRadioButtons *r);\n_UI_EXTERN void uiRadioButtonsSetSelected(uiRadioButtons *r, int n);\n_UI_EXTERN void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data);\n_UI_EXTERN uiRadioButtons *uiNewRadioButtons(void);\n\nstruct tm;\ntypedef struct uiDateTimePicker uiDateTimePicker;\n#define uiDateTimePicker(this) ((uiDateTimePicker *) (this))\n// TODO document that tm_wday and tm_yday are undefined, and tm_isdst should be -1\n// TODO document that for both sides\n// TODO document time zone conversions or lack thereof\n// TODO for Time: define what values are returned when a part is missing\n_UI_EXTERN void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time);\n_UI_EXTERN void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time);\n_UI_EXTERN void uiDateTimePickerOnChanged(uiDateTimePicker *d, void (*f)(uiDateTimePicker *, void *), void *data);\n_UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void);\n_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void);\n_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void);\n\n// TODO provide a facility for entering tab stops?\ntypedef struct uiMultilineEntry uiMultilineEntry;\n#define uiMultilineEntry(this) ((uiMultilineEntry *) (this))\n_UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e);\n_UI_EXTERN void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text);\n_UI_EXTERN void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text);\n_UI_EXTERN void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data);\n_UI_EXTERN int uiMultilineEntryReadOnly(uiMultilineEntry *e);\n_UI_EXTERN void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly);\n_UI_EXTERN uiMultilineEntry *uiNewMultilineEntry(void);\n_UI_EXTERN uiMultilineEntry *uiNewNonWrappingMultilineEntry(void);\n\ntypedef struct uiMenuItem uiMenuItem;\n#define uiMenuItem(this) ((uiMenuItem *) (this))\n_UI_EXTERN void uiMenuItemEnable(uiMenuItem *m);\n_UI_EXTERN void uiMenuItemDisable(uiMenuItem *m);\n_UI_EXTERN void uiMenuItemOnClicked(uiMenuItem *m, void (*f)(uiMenuItem *sender, uiWindow *window, void *data), void *data);\n_UI_EXTERN int uiMenuItemChecked(uiMenuItem *m);\n_UI_EXTERN void uiMenuItemSetChecked(uiMenuItem *m, int checked);\n\ntypedef struct uiMenu uiMenu;\n#define uiMenu(this) ((uiMenu *) (this))\n_UI_EXTERN uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name);\n_UI_EXTERN uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name);\n_UI_EXTERN uiMenuItem *uiMenuAppendQuitItem(uiMenu *m);\n_UI_EXTERN uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m);\n_UI_EXTERN uiMenuItem *uiMenuAppendAboutItem(uiMenu *m);\n_UI_EXTERN void uiMenuAppendSeparator(uiMenu *m);\n_UI_EXTERN uiMenu *uiNewMenu(const char *name);\n\n_UI_EXTERN char *uiOpenFile(uiWindow *parent);\n_UI_EXTERN char *uiSaveFile(uiWindow *parent);\n_UI_EXTERN void uiMsgBox(uiWindow *parent, const char *title, const char *description);\n_UI_EXTERN void uiMsgBoxError(uiWindow *parent, const char *title, const char *description);\n\ntypedef struct uiArea uiArea;\ntypedef struct uiAreaHandler uiAreaHandler;\ntypedef struct uiAreaDrawParams uiAreaDrawParams;\ntypedef struct uiAreaMouseEvent uiAreaMouseEvent;\ntypedef struct uiAreaKeyEvent uiAreaKeyEvent;\n\ntypedef struct uiDrawContext uiDrawContext;\n\nstruct uiAreaHandler {\n\tvoid (*Draw)(uiAreaHandler *, uiArea *, uiAreaDrawParams *);\n\t// TODO document that resizes cause a full redraw for non-scrolling areas; implementation-defined for scrolling areas\n\tvoid (*MouseEvent)(uiAreaHandler *, uiArea *, uiAreaMouseEvent *);\n\t// TODO document that on first show if the mouse is already in the uiArea then one gets sent with left=0\n\t// TODO what about when the area is hidden and then shown again?\n\tvoid (*MouseCrossed)(uiAreaHandler *, uiArea *, int left);\n\tvoid (*DragBroken)(uiAreaHandler *, uiArea *);\n\tint (*KeyEvent)(uiAreaHandler *, uiArea *, uiAreaKeyEvent *);\n};\n\n// TODO RTL layouts?\n// TODO reconcile edge and corner naming\n_UI_ENUM(uiWindowResizeEdge) {\n\tuiWindowResizeEdgeLeft,\n\tuiWindowResizeEdgeTop,\n\tuiWindowResizeEdgeRight,\n\tuiWindowResizeEdgeBottom,\n\tuiWindowResizeEdgeTopLeft,\n\tuiWindowResizeEdgeTopRight,\n\tuiWindowResizeEdgeBottomLeft,\n\tuiWindowResizeEdgeBottomRight,\n\t// TODO have one for keyboard resizes?\n\t// TODO GDK doesn't seem to have any others, including for keyboards...\n\t// TODO way to bring up the system menu instead?\n};\n\n#define uiArea(this) ((uiArea *) (this))\n// TODO give a better name\n// TODO document the types of width and height\n_UI_EXTERN void uiAreaSetSize(uiArea *a, int width, int height);\n// TODO uiAreaQueueRedraw()\n_UI_EXTERN void uiAreaQueueRedrawAll(uiArea *a);\n_UI_EXTERN void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height);\n// TODO document these can only be called within Mouse() handlers\n// TODO should these be allowed on scrolling areas?\n// TODO decide which mouse events should be accepted; Down is the only one guaranteed to work right now\n// TODO what happens to events after calling this up to and including the next mouse up?\n// TODO release capture?\n_UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a);\n_UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge);\n_UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah);\n_UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height);\n\nstruct uiAreaDrawParams {\n\tuiDrawContext *Context;\n\n\t// TODO document that this is only defined for nonscrolling areas\n\tdouble AreaWidth;\n\tdouble AreaHeight;\n\n\tdouble ClipX;\n\tdouble ClipY;\n\tdouble ClipWidth;\n\tdouble ClipHeight;\n};\n\ntypedef struct uiDrawPath uiDrawPath;\ntypedef struct uiDrawBrush uiDrawBrush;\ntypedef struct uiDrawStrokeParams uiDrawStrokeParams;\ntypedef struct uiDrawMatrix uiDrawMatrix;\n\ntypedef struct uiDrawBrushGradientStop uiDrawBrushGradientStop;\n\n_UI_ENUM(uiDrawBrushType) {\n\tuiDrawBrushTypeSolid,\n\tuiDrawBrushTypeLinearGradient,\n\tuiDrawBrushTypeRadialGradient,\n\tuiDrawBrushTypeImage,\n};\n\n_UI_ENUM(uiDrawLineCap) {\n\tuiDrawLineCapFlat,\n\tuiDrawLineCapRound,\n\tuiDrawLineCapSquare,\n};\n\n_UI_ENUM(uiDrawLineJoin) {\n\tuiDrawLineJoinMiter,\n\tuiDrawLineJoinRound,\n\tuiDrawLineJoinBevel,\n};\n\n// this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions)\n// Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value\n// so we're good to use it too!\n#define uiDrawDefaultMiterLimit 10.0\n\n_UI_ENUM(uiDrawFillMode) {\n\tuiDrawFillModeWinding,\n\tuiDrawFillModeAlternate,\n};\n\nstruct uiDrawMatrix {\n\tdouble M11;\n\tdouble M12;\n\tdouble M21;\n\tdouble M22;\n\tdouble M31;\n\tdouble M32;\n};\n\nstruct uiDrawBrush {\n\tuiDrawBrushType Type;\n\n\t// solid brushes\n\tdouble R;\n\tdouble G;\n\tdouble B;\n\tdouble A;\n\n\t// gradient brushes\n\tdouble X0;\t\t// linear: start X, radial: start X\n\tdouble Y0;\t\t// linear: start Y, radial: start Y\n\tdouble X1;\t\t// linear: end X, radial: outer circle center X\n\tdouble Y1;\t\t// linear: end Y, radial: outer circle center Y\n\tdouble OuterRadius;\t\t// radial gradients only\n\tuiDrawBrushGradientStop *Stops;\n\tsize_t NumStops;\n\t// TODO extend mode\n\t// cairo: none, repeat, reflect, pad; no individual control\n\t// Direct2D: repeat, reflect, pad; no individual control\n\t// Core Graphics: none, pad; before and after individually\n\t// TODO cairo documentation is inconsistent about pad\n\n\t// TODO images\n\n\t// TODO transforms\n};\n\nstruct uiDrawBrushGradientStop {\n\tdouble Pos;\n\tdouble R;\n\tdouble G;\n\tdouble B;\n\tdouble A;\n};\n\nstruct uiDrawStrokeParams {\n\tuiDrawLineCap Cap;\n\tuiDrawLineJoin Join;\n\t// TODO what if this is 0? on windows there will be a crash with dashing\n\tdouble Thickness;\n\tdouble MiterLimit;\n\tdouble *Dashes;\n\t// TOOD what if this is 1 on Direct2D?\n\t// TODO what if a dash is 0 on Cairo or Quartz?\n\tsize_t NumDashes;\n\tdouble DashPhase;\n};\n\n_UI_EXTERN uiDrawPath *uiDrawNewPath(uiDrawFillMode fillMode);\n_UI_EXTERN void uiDrawFreePath(uiDrawPath *p);\n\n_UI_EXTERN void uiDrawPathNewFigure(uiDrawPath *p, double x, double y);\n_UI_EXTERN void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);\n_UI_EXTERN void uiDrawPathLineTo(uiDrawPath *p, double x, double y);\n// notes: angles are both relative to 0 and go counterclockwise\n// TODO is the initial line segment on cairo and OS X a proper join?\n// TODO what if sweep < 0?\n_UI_EXTERN void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);\n_UI_EXTERN void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY);\n// TODO quadratic bezier\n_UI_EXTERN void uiDrawPathCloseFigure(uiDrawPath *p);\n\n// TODO effect of these when a figure is already started\n_UI_EXTERN void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height);\n\n_UI_EXTERN void uiDrawPathEnd(uiDrawPath *p);\n\n_UI_EXTERN void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p);\n_UI_EXTERN void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b);\n\n// TODO primitives:\n// - rounded rectangles\n// - elliptical arcs\n// - quadratic bezier curves\n\n_UI_EXTERN void uiDrawMatrixSetIdentity(uiDrawMatrix *m);\n_UI_EXTERN void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y);\n_UI_EXTERN void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y);\n_UI_EXTERN void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount);\n_UI_EXTERN void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount);\n_UI_EXTERN void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src);\n_UI_EXTERN int uiDrawMatrixInvertible(uiDrawMatrix *m);\n_UI_EXTERN int uiDrawMatrixInvert(uiDrawMatrix *m);\n_UI_EXTERN void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y);\n_UI_EXTERN void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y);\n\n_UI_EXTERN void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m);\n\n// TODO add a uiDrawPathStrokeToFill() or something like that\n_UI_EXTERN void uiDrawClip(uiDrawContext *c, uiDrawPath *path);\n\n_UI_EXTERN void uiDrawSave(uiDrawContext *c);\n_UI_EXTERN void uiDrawRestore(uiDrawContext *c);\n\n// uiAttribute stores information about an attribute in a\n// uiAttributedString.\n//\n// You do not create uiAttributes directly; instead, you create a\n// uiAttribute of a given type using the specialized constructor\n// functions. For every Unicode codepoint in the uiAttributedString,\n// at most one value of each attribute type can be applied.\n//\n// uiAttributes are immutable and the uiAttributedString takes\n// ownership of the uiAttribute object once assigned, copying its\n// contents as necessary.\ntypedef struct uiAttribute uiAttribute;\n\n// @role uiAttribute destructor\n// uiFreeAttribute() frees a uiAttribute. You generally do not need to\n// call this yourself, as uiAttributedString does this for you. In fact,\n// it is an error to call this function on a uiAttribute that has been\n// given to a uiAttributedString. You can call this, however, if you\n// created a uiAttribute that you aren't going to use later.\n_UI_EXTERN void uiFreeAttribute(uiAttribute *a);\n\n// uiAttributeType holds the possible uiAttribute types that may be\n// returned by uiAttributeGetType(). Refer to the documentation for\n// each type's constructor function for details on each type.\n_UI_ENUM(uiAttributeType) {\n\tuiAttributeTypeFamily,\n\tuiAttributeTypeSize,\n\tuiAttributeTypeWeight,\n\tuiAttributeTypeItalic,\n\tuiAttributeTypeStretch,\n\tuiAttributeTypeColor,\n\tuiAttributeTypeBackground,\n\tuiAttributeTypeUnderline,\n\tuiAttributeTypeUnderlineColor,\n\tuiAttributeTypeFeatures,\n};\n\n// uiAttributeGetType() returns the type of a.\n// TODO I don't like this name\n_UI_EXTERN uiAttributeType uiAttributeGetType(const uiAttribute *a);\n\n// uiNewFamilyAttribute() creates a new uiAttribute that changes the\n// font family of the text it is applied to. family is copied; you do not\n// need to keep it alive after uiNewFamilyAttribute() returns. Font\n// family names are case-insensitive.\n_UI_EXTERN uiAttribute *uiNewFamilyAttribute(const char *family);\n\n// uiAttributeFamily() returns the font family stored in a. The\n// returned string is owned by a. It is an error to call this on a\n// uiAttribute that does not hold a font family.\n_UI_EXTERN const char *uiAttributeFamily(const uiAttribute *a);\n\n// uiNewSizeAttribute() creates a new uiAttribute that changes the\n// size of the text it is applied to, in typographical points.\n_UI_EXTERN uiAttribute *uiNewSizeAttribute(double size);\n\n// uiAttributeSize() returns the font size stored in a. It is an error to\n// call this on a uiAttribute that does not hold a font size.\n_UI_EXTERN double uiAttributeSize(const uiAttribute *a);\n\n// uiTextWeight represents possible text weights. These roughly\n// map to the OS/2 text weight field of TrueType and OpenType\n// fonts, or to CSS weight numbers. The named constants are\n// nominal values; the actual values may vary by font and by OS,\n// though this isn't particularly likely. Any value between\n// uiTextWeightMinimum and uiTextWeightMaximum, inclusive,\n// is allowed.\n//\n// Note that due to restrictions in early versions of Windows, some\n// fonts have \"special\" weights be exposed in many programs as\n// separate font families. This is perhaps most notable with\n// Arial Black. libui does not do this, even on Windows (because the\n// DirectWrite API libui uses on Windows does not do this); to\n// specify Arial Black, use family Arial and weight uiTextWeightBlack.\n_UI_ENUM(uiTextWeight) {\n\tuiTextWeightMinimum = 0,\n\tuiTextWeightThin = 100,\n\tuiTextWeightUltraLight = 200,\n\tuiTextWeightLight = 300,\n\tuiTextWeightBook = 350,\n\tuiTextWeightNormal = 400,\n\tuiTextWeightMedium = 500,\n\tuiTextWeightSemiBold = 600,\n\tuiTextWeightBold = 700,\n\tuiTextWeightUltraBold = 800,\n\tuiTextWeightHeavy = 900,\n\tuiTextWeightUltraHeavy = 950,\n\tuiTextWeightMaximum = 1000,\n};\n\n// uiNewWeightAttribute() creates a new uiAttribute that changes the\n// weight of the text it is applied to. It is an error to specify a weight\n// outside the range [uiTextWeightMinimum,\n// uiTextWeightMaximum].\n_UI_EXTERN uiAttribute *uiNewWeightAttribute(uiTextWeight weight);\n\n// uiAttributeWeight() returns the font weight stored in a. It is an error\n// to call this on a uiAttribute that does not hold a font weight.\n_UI_EXTERN uiTextWeight uiAttributeWeight(const uiAttribute *a);\n\n// uiTextItalic represents possible italic modes for a font. Italic\n// represents \"true\" italics where the slanted glyphs have custom\n// shapes, whereas oblique represents italics that are merely slanted\n// versions of the normal glyphs. Most fonts usually have one or the\n// other.\n_UI_ENUM(uiTextItalic) {\n\tuiTextItalicNormal,\n\tuiTextItalicOblique,\n\tuiTextItalicItalic,\n};\n\n// uiNewItalicAttribute() creates a new uiAttribute that changes the\n// italic mode of the text it is applied to. It is an error to specify an\n// italic mode not specified in uiTextItalic.\n_UI_EXTERN uiAttribute *uiNewItalicAttribute(uiTextItalic italic);\n\n// uiAttributeItalic() returns the font italic mode stored in a. It is an\n// error to call this on a uiAttribute that does not hold a font italic\n// mode.\n_UI_EXTERN uiTextItalic uiAttributeItalic(const uiAttribute *a);\n\n// uiTextStretch represents possible stretches (also called \"widths\")\n// of a font.\n//\n// Note that due to restrictions in early versions of Windows, some\n// fonts have \"special\" stretches be exposed in many programs as\n// separate font families. This is perhaps most notable with\n// Arial Condensed. libui does not do this, even on Windows (because\n// the DirectWrite API libui uses on Windows does not do this); to\n// specify Arial Condensed, use family Arial and stretch\n// uiTextStretchCondensed.\n_UI_ENUM(uiTextStretch) {\n\tuiTextStretchUltraCondensed,\n\tuiTextStretchExtraCondensed,\n\tuiTextStretchCondensed,\n\tuiTextStretchSemiCondensed,\n\tuiTextStretchNormal,\n\tuiTextStretchSemiExpanded,\n\tuiTextStretchExpanded,\n\tuiTextStretchExtraExpanded,\n\tuiTextStretchUltraExpanded,\n};\n\n// uiNewStretchAttribute() creates a new uiAttribute that changes the\n// stretch of the text it is applied to. It is an error to specify a strech\n// not specified in uiTextStretch.\n_UI_EXTERN uiAttribute *uiNewStretchAttribute(uiTextStretch stretch);\n\n// uiAttributeStretch() returns the font stretch stored in a. It is an\n// error to call this on a uiAttribute that does not hold a font stretch.\n_UI_EXTERN uiTextStretch uiAttributeStretch(const uiAttribute *a);\n\n// uiNewColorAttribute() creates a new uiAttribute that changes the\n// color of the text it is applied to. It is an error to specify an invalid\n// color.\n_UI_EXTERN uiAttribute *uiNewColorAttribute(double r, double g, double b, double a);\n\n// uiAttributeColor() returns the text color stored in a. It is an\n// error to call this on a uiAttribute that does not hold a text color.\n_UI_EXTERN void uiAttributeColor(const uiAttribute *a, double *r, double *g, double *b, double *alpha);\n\n// uiNewBackgroundAttribute() creates a new uiAttribute that\n// changes the background color of the text it is applied to. It is an\n// error to specify an invalid color.\n_UI_EXTERN uiAttribute *uiNewBackgroundAttribute(double r, double g, double b, double a);\n\n// TODO reuse uiAttributeColor() for background colors, or make a new function...\n\n// uiUnderline specifies a type of underline to use on text.\n_UI_ENUM(uiUnderline) {\n\tuiUnderlineNone,\n\tuiUnderlineSingle,\n\tuiUnderlineDouble,\n\tuiUnderlineSuggestion,\t\t// wavy or dotted underlines used for spelling/grammar checkers\n};\n\n// uiNewUnderlineAttribute() creates a new uiAttribute that changes\n// the type of underline on the text it is applied to. It is an error to\n// specify an underline type not specified in uiUnderline.\n_UI_EXTERN uiAttribute *uiNewUnderlineAttribute(uiUnderline u);\n\n// uiAttributeUnderline() returns the underline type stored in a. It is\n// an error to call this on a uiAttribute that does not hold an underline\n// style.\n_UI_EXTERN uiUnderline uiAttributeUnderline(const uiAttribute *a);\n\n// uiUnderlineColor specifies the color of any underline on the text it\n// is applied to, regardless of the type of underline. In addition to\n// being able to specify a custom color, you can explicitly specify\n// platform-specific colors for suggestion underlines; to use them\n// correctly, pair them with uiUnderlineSuggestion (though they can\n// be used on other types of underline as well).\n// \n// If an underline type is applied but no underline color is\n// specified, the text color is used instead. If an underline color\n// is specified without an underline type, the underline color\n// attribute is ignored, but not removed from the uiAttributedString.\n_UI_ENUM(uiUnderlineColor) {\n\tuiUnderlineColorCustom,\n\tuiUnderlineColorSpelling,\n\tuiUnderlineColorGrammar,\n\tuiUnderlineColorAuxiliary,\t\t// for instance, the color used by smart replacements on macOS or in Microsoft Office\n};\n\n// uiNewUnderlineColorAttribute() creates a new uiAttribute that\n// changes the color of the underline on the text it is applied to.\n// It is an error to specify an underline color not specified in\n// uiUnderlineColor.\n//\n// If the specified color type is uiUnderlineColorCustom, it is an\n// error to specify an invalid color value. Otherwise, the color values\n// are ignored and should be specified as zero.\n_UI_EXTERN uiAttribute *uiNewUnderlineColorAttribute(uiUnderlineColor u, double r, double g, double b, double a);\n\n// uiAttributeUnderlineColor() returns the underline color stored in\n// a. It is an error to call this on a uiAttribute that does not hold an\n// underline color.\n_UI_EXTERN void uiAttributeUnderlineColor(const uiAttribute *a, uiUnderlineColor *u, double *r, double *g, double *b, double *alpha);\n\n// uiOpenTypeFeatures represents a set of OpenType feature\n// tag-value pairs, for applying OpenType features to text.\n// OpenType feature tags are four-character codes defined by\n// OpenType that cover things from design features like small\n// caps and swashes to language-specific glyph shapes and\n// beyond. Each tag may only appear once in any given\n// uiOpenTypeFeatures instance. Each value is a 32-bit integer,\n// often used as a Boolean flag, but sometimes as an index to choose\n// a glyph shape to use.\n// \n// If a font does not support a certain feature, that feature will be\n// ignored. (TODO verify this on all OSs)\n// \n// See the OpenType specification at\n// https://www.microsoft.com/typography/otspec/featuretags.htm\n// for the complete list of available features, information on specific\n// features, and how to use them.\n// TODO invalid features\ntypedef struct uiOpenTypeFeatures uiOpenTypeFeatures;\n\n// uiOpenTypeFeaturesForEachFunc is the type of the function\n// invoked by uiOpenTypeFeaturesForEach() for every OpenType\n// feature in otf. Refer to that function's documentation for more\n// details.\ntypedef uiForEach (*uiOpenTypeFeaturesForEachFunc)(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data);\n\n// @role uiOpenTypeFeatures constructor\n// uiNewOpenTypeFeatures() returns a new uiOpenTypeFeatures\n// instance, with no tags yet added.\n_UI_EXTERN uiOpenTypeFeatures *uiNewOpenTypeFeatures(void);\n\n// @role uiOpenTypeFeatures destructor\n// uiFreeOpenTypeFeatures() frees otf.\n_UI_EXTERN void uiFreeOpenTypeFeatures(uiOpenTypeFeatures *otf);\n\n// uiOpenTypeFeaturesClone() makes a copy of otf and returns it.\n// Changing one will not affect the other.\n_UI_EXTERN uiOpenTypeFeatures *uiOpenTypeFeaturesClone(const uiOpenTypeFeatures *otf);\n\n// uiOpenTypeFeaturesAdd() adds the given feature tag and value\n// to otf. The feature tag is specified by a, b, c, and d. If there is\n// already a value associated with the specified tag in otf, the old\n// value is removed.\n_UI_EXTERN void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value);\n\n// uiOpenTypeFeaturesRemove() removes the given feature tag\n// and value from otf. If the tag is not present in otf,\n// uiOpenTypeFeaturesRemove() does nothing.\n_UI_EXTERN void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d);\n\n// uiOpenTypeFeaturesGet() determines whether the given feature\n// tag is present in otf. If it is, *value is set to the tag's value and\n// nonzero is returned. Otherwise, zero is returned.\n// \n// Note that if uiOpenTypeFeaturesGet() returns zero, value isn't\n// changed. This is important: if a feature is not present in a\n// uiOpenTypeFeatures, the feature is NOT treated as if its\n// value was zero anyway. Script-specific font shaping rules and\n// font-specific feature settings may use a different default value\n// for a feature. You should likewise not treat a missing feature as\n// having a value of zero either. Instead, a missing feature should\n// be treated as having some unspecified default value.\n_UI_EXTERN int uiOpenTypeFeaturesGet(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value);\n\n// uiOpenTypeFeaturesForEach() executes f for every tag-value\n// pair in otf. The enumeration order is unspecified. You cannot\n// modify otf while uiOpenTypeFeaturesForEach() is running.\n_UI_EXTERN void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data);\n\n// uiNewFeaturesAttribute() creates a new uiAttribute that changes\n// the font family of the text it is applied to. otf is copied; you may\n// free it after uiNewFeaturesAttribute() returns.\n_UI_EXTERN uiAttribute *uiNewFeaturesAttribute(const uiOpenTypeFeatures *otf);\n\n// uiAttributeFeatures() returns the OpenType features stored in a.\n// The returned uiOpenTypeFeatures object is owned by a. It is an\n// error to call this on a uiAttribute that does not hold OpenType\n// features.\n_UI_EXTERN const uiOpenTypeFeatures *uiAttributeFeatures(const uiAttribute *a);\n\n// uiAttributedString represents a string of UTF-8 text that can\n// optionally be embellished with formatting attributes. libui\n// provides the list of formatting attributes, which cover common\n// formatting traits like boldface and color as well as advanced\n// typographical features provided by OpenType like superscripts\n// and small caps. These attributes can be combined in a variety of\n// ways.\n//\n// Attributes are applied to runs of Unicode codepoints in the string.\n// Zero-length runs are elided. Consecutive runs that have the same\n// attribute type and value are merged. Each attribute is independent\n// of each other attribute; overlapping attributes of different types\n// do not split each other apart, but different values of the same\n// attribute type do.\n//\n// The empty string can also be represented by uiAttributedString,\n// but because of the no-zero-length-attribute rule, it will not have\n// attributes.\n//\n// A uiAttributedString takes ownership of all attributes given to\n// it, as it may need to duplicate or delete uiAttribute objects at\n// any time. By extension, when you free a uiAttributedString,\n// all uiAttributes within will also be freed. Each method will\n// describe its own rules in more details.\n//\n// In addition, uiAttributedString provides facilities for moving\n// between grapheme clusters, which represent a character\n// from the point of view of the end user. The cursor of a text editor\n// is always placed on a grapheme boundary, so you can use these\n// features to move the cursor left or right by one \"character\".\n// TODO does uiAttributedString itself need this\n//\n// uiAttributedString does not provide enough information to be able\n// to draw itself onto a uiDrawContext or respond to user actions.\n// In order to do that, you'll need to use a uiDrawTextLayout, which\n// is built from the combination of a uiAttributedString and a set of\n// layout-specific properties.\ntypedef struct uiAttributedString uiAttributedString;\n\n// uiAttributedStringForEachAttributeFunc is the type of the function\n// invoked by uiAttributedStringForEachAttribute() for every\n// attribute in s. Refer to that function's documentation for more\n// details.\ntypedef uiForEach (*uiAttributedStringForEachAttributeFunc)(const uiAttributedString *s, const uiAttribute *a, size_t start, size_t end, void *data);\n\n// @role uiAttributedString constructor\n// uiNewAttributedString() creates a new uiAttributedString from\n// initialString. The string will be entirely unattributed.\n_UI_EXTERN uiAttributedString *uiNewAttributedString(const char *initialString);\n\n// @role uiAttributedString destructor\n// uiFreeAttributedString() destroys the uiAttributedString s.\n// It will also free all uiAttributes within.\n_UI_EXTERN void uiFreeAttributedString(uiAttributedString *s);\n\n// uiAttributedStringString() returns the textual content of s as a\n// '\\0'-terminated UTF-8 string. The returned pointer is valid until\n// the next change to the textual content of s.\n_UI_EXTERN const char *uiAttributedStringString(const uiAttributedString *s);\n\n// uiAttributedStringLength() returns the number of UTF-8 bytes in\n// the textual content of s, excluding the terminating '\\0'.\n_UI_EXTERN size_t uiAttributedStringLen(const uiAttributedString *s);\n\n// uiAttributedStringAppendUnattributed() adds the '\\0'-terminated\n// UTF-8 string str to the end of s. The new substring will be\n// unattributed.\n_UI_EXTERN void uiAttributedStringAppendUnattributed(uiAttributedString *s, const char *str);\n\n// uiAttributedStringInsertAtUnattributed() adds the '\\0'-terminated\n// UTF-8 string str to s at the byte position specified by at. The new\n// substring will be unattributed; existing attributes will be moved\n// along with their text.\n_UI_EXTERN void uiAttributedStringInsertAtUnattributed(uiAttributedString *s, const char *str, size_t at);\n\n// TODO add the Append and InsertAtExtendingAttributes functions\n// TODO and add functions that take a string + length\n\n// uiAttributedStringDelete() deletes the characters and attributes of\n// s in the byte range [start, end).\n_UI_EXTERN void uiAttributedStringDelete(uiAttributedString *s, size_t start, size_t end);\n\n// 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\n\n// uiAttributedStringSetAttribute() sets a in the byte range [start, end)\n// of s. Any existing attributes in that byte range of the same type are\n// removed. s takes ownership of a; you should not use it after\n// uiAttributedStringSetAttribute() returns.\n_UI_EXTERN void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute *a, size_t start, size_t end);\n\n// uiAttributedStringForEachAttribute() enumerates all the\n// uiAttributes in s. It is an error to modify s in f. Within f, s still\n// owns the attribute; you can neither free it nor save it for later\n// use.\n// TODO reword the above for consistency (TODO and find out what I meant by that)\n// 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\n_UI_EXTERN void uiAttributedStringForEachAttribute(const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data);\n\n// TODO const correct this somehow (the implementation needs to mutate the structure)\n_UI_EXTERN size_t uiAttributedStringNumGraphemes(uiAttributedString *s);\n\n// TODO const correct this somehow (the implementation needs to mutate the structure)\n_UI_EXTERN size_t uiAttributedStringByteIndexToGrapheme(uiAttributedString *s, size_t pos);\n\n// TODO const correct this somehow (the implementation needs to mutate the structure)\n_UI_EXTERN size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos);\n\n// uiFontDescriptor provides a complete description of a font where\n// one is needed. Currently, this means as the default font of a\n// uiDrawTextLayout and as the data returned by uiFontButton.\n// All the members operate like the respective uiAttributes.\ntypedef struct uiFontDescriptor uiFontDescriptor;\n\nstruct uiFontDescriptor {\n\t// TODO const-correct this or figure out how to deal with this when getting a value\n\tchar *Family;\n\tdouble Size;\n\tuiTextWeight Weight;\n\tuiTextItalic Italic;\n\tuiTextStretch Stretch;\n};\n\n// uiDrawTextLayout is a concrete representation of a\n// uiAttributedString that can be displayed in a uiDrawContext.\n// It includes information important for the drawing of a block of\n// text, including the bounding box to wrap the text within, the\n// alignment of lines of text within that box, areas to mark as\n// being selected, and other things.\n//\n// Unlike uiAttributedString, the content of a uiDrawTextLayout is\n// immutable once it has been created.\n//\n// TODO talk about OS-specific differences with text drawing that libui can't account for...\ntypedef struct uiDrawTextLayout uiDrawTextLayout;\n\n// uiDrawTextAlign specifies the alignment of lines of text in a\n// uiDrawTextLayout.\n// TODO should this really have Draw in the name?\n_UI_ENUM(uiDrawTextAlign) {\n\tuiDrawTextAlignLeft,\n\tuiDrawTextAlignCenter,\n\tuiDrawTextAlignRight,\n};\n\n// uiDrawTextLayoutParams describes a uiDrawTextLayout.\n// DefaultFont is used to render any text that is not attributed\n// sufficiently in String. Width determines the width of the bounding\n// box of the text; the height is determined automatically.\ntypedef struct uiDrawTextLayoutParams uiDrawTextLayoutParams;\n\n// TODO const-correct this somehow\nstruct uiDrawTextLayoutParams {\n\tuiAttributedString *String;\n\tuiFontDescriptor *DefaultFont;\n\tdouble Width;\n\tuiDrawTextAlign Align;\n};\n\n// @role uiDrawTextLayout constructor\n// uiDrawNewTextLayout() creates a new uiDrawTextLayout from\n// the given parameters.\n//\n// TODO\n// - allow creating a layout out of a substring\n// - allow marking compositon strings\n// - allow marking selections, even after creation\n// - add the following functions:\n// \t- uiDrawTextLayoutHeightForWidth() (returns the height that a layout would need to be to display the entire string at a given width)\n// \t- uiDrawTextLayoutRangeForSize() (returns what substring would fit in a given size)\n// \t- uiDrawTextLayoutNewWithHeight() (limits amount of string used by the height)\n// - some function to fix up a range (for text editing)\n_UI_EXTERN uiDrawTextLayout *uiDrawNewTextLayout(uiDrawTextLayoutParams *params);\n\n// @role uiDrawFreeTextLayout destructor\n// uiDrawFreeTextLayout() frees tl. The underlying\n// uiAttributedString is not freed.\n_UI_EXTERN void uiDrawFreeTextLayout(uiDrawTextLayout *tl);\n\n// uiDrawText() draws tl in c with the top-left point of tl at (x, y).\n_UI_EXTERN void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y);\n\n// uiDrawTextLayoutExtents() returns the width and height of tl\n// in width and height. The returned width may be smaller than\n// the width passed into uiDrawNewTextLayout() depending on\n// how the text in tl is wrapped. Therefore, you can use this\n// function to get the actual size of the text layout.\n_UI_EXTERN void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height);\n\n// TODO metrics functions\n\n// TODO number of lines visible for clipping rect, range visible for clipping rect?\n\n// uiFontButton is a button that allows users to choose a font when they click on it.\ntypedef struct uiFontButton uiFontButton;\n#define uiFontButton(this) ((uiFontButton *) (this))\n// uiFontButtonFont() returns the font currently selected in the uiFontButton in desc.\n// uiFontButtonFont() allocates resources in desc; when you are done with the font, call uiFreeFontButtonFont() to release them.\n// uiFontButtonFont() does not allocate desc itself; you must do so.\n// TODO have a function that sets an entire font descriptor to a range in a uiAttributedString at once, for SetFont?\n_UI_EXTERN void uiFontButtonFont(uiFontButton *b, uiFontDescriptor *desc);\n// TOOD SetFont, mechanics\n// uiFontButtonOnChanged() sets the function that is called when the font in the uiFontButton is changed.\n_UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data);\n// uiNewFontButton() creates a new uiFontButton. The default font selected into the uiFontButton is OS-defined.\n_UI_EXTERN uiFontButton *uiNewFontButton(void);\n// uiFreeFontButtonFont() frees resources allocated in desc by uiFontButtonFont().\n// After calling uiFreeFontButtonFont(), the contents of desc should be assumed to be undefined (though since you allocate desc itself, you can safely reuse desc for other font descriptors).\n// Calling uiFreeFontButtonFont() on a uiFontDescriptor not returned by uiFontButtonFont() results in undefined behavior.\n_UI_EXTERN void uiFreeFontButtonFont(uiFontDescriptor *desc);\n\n_UI_ENUM(uiModifiers) {\n\tuiModifierCtrl = 1 << 0,\n\tuiModifierAlt = 1 << 1,\n\tuiModifierShift = 1 << 2,\n\tuiModifierSuper = 1 << 3,\n};\n\n// TODO document drag captures\nstruct uiAreaMouseEvent {\n\t// TODO document what these mean for scrolling areas\n\tdouble X;\n\tdouble Y;\n\n\t// TODO see draw above\n\tdouble AreaWidth;\n\tdouble AreaHeight;\n\n\tint Down;\n\tint Up;\n\n\tint Count;\n\n\tuiModifiers Modifiers;\n\n\tuint64_t Held1To64;\n};\n\n_UI_ENUM(uiExtKey) {\n\tuiExtKeyEscape = 1,\n\tuiExtKeyInsert,\t\t\t// equivalent to \"Help\" on Apple keyboards\n\tuiExtKeyDelete,\n\tuiExtKeyHome,\n\tuiExtKeyEnd,\n\tuiExtKeyPageUp,\n\tuiExtKeyPageDown,\n\tuiExtKeyUp,\n\tuiExtKeyDown,\n\tuiExtKeyLeft,\n\tuiExtKeyRight,\n\tuiExtKeyF1,\t\t\t// F1..F12 are guaranteed to be consecutive\n\tuiExtKeyF2,\n\tuiExtKeyF3,\n\tuiExtKeyF4,\n\tuiExtKeyF5,\n\tuiExtKeyF6,\n\tuiExtKeyF7,\n\tuiExtKeyF8,\n\tuiExtKeyF9,\n\tuiExtKeyF10,\n\tuiExtKeyF11,\n\tuiExtKeyF12,\n\tuiExtKeyN0,\t\t\t// numpad keys; independent of Num Lock state\n\tuiExtKeyN1,\t\t\t// N0..N9 are guaranteed to be consecutive\n\tuiExtKeyN2,\n\tuiExtKeyN3,\n\tuiExtKeyN4,\n\tuiExtKeyN5,\n\tuiExtKeyN6,\n\tuiExtKeyN7,\n\tuiExtKeyN8,\n\tuiExtKeyN9,\n\tuiExtKeyNDot,\n\tuiExtKeyNEnter,\n\tuiExtKeyNAdd,\n\tuiExtKeyNSubtract,\n\tuiExtKeyNMultiply,\n\tuiExtKeyNDivide,\n};\n\nstruct uiAreaKeyEvent {\n\tchar Key;\n\tuiExtKey ExtKey;\n\tuiModifiers Modifier;\n\n\tuiModifiers Modifiers;\n\n\tint Up;\n};\n\ntypedef struct uiColorButton uiColorButton;\n#define uiColorButton(this) ((uiColorButton *) (this))\n_UI_EXTERN void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a);\n_UI_EXTERN void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a);\n_UI_EXTERN void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data);\n_UI_EXTERN uiColorButton *uiNewColorButton(void);\n\ntypedef struct uiForm uiForm;\n#define uiForm(this) ((uiForm *) (this))\n_UI_EXTERN void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy);\n_UI_EXTERN void uiFormDelete(uiForm *f, int index);\n_UI_EXTERN int uiFormPadded(uiForm *f);\n_UI_EXTERN void uiFormSetPadded(uiForm *f, int padded);\n_UI_EXTERN uiForm *uiNewForm(void);\n\n_UI_ENUM(uiAlign) {\n\tuiAlignFill,\n\tuiAlignStart,\n\tuiAlignCenter,\n\tuiAlignEnd,\n};\n\n_UI_ENUM(uiAt) {\n\tuiAtLeading,\n\tuiAtTop,\n\tuiAtTrailing,\n\tuiAtBottom,\n};\n\ntypedef struct uiGrid uiGrid;\n#define uiGrid(this) ((uiGrid *) (this))\n_UI_EXTERN void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign);\n_UI_EXTERN void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign);\n_UI_EXTERN int uiGridPadded(uiGrid *g);\n_UI_EXTERN void uiGridSetPadded(uiGrid *g, int padded);\n_UI_EXTERN uiGrid *uiNewGrid(void);\n\n// uiImage stores an image for display on screen.\n// \n// Images are built from one or more representations, each with the\n// same aspect ratio but a different pixel size. libui automatically\n// selects the most appropriate representation for drawing the image\n// when it comes time to draw the image; what this means depends\n// on the pixel density of the target context. Therefore, one can use\n// uiImage to draw higher-detailed images on higher-density\n// displays. The typical use cases are either:\n// \n// \t- have just a single representation, at which point all screens\n// \t  use the same image, and thus uiImage acts like a simple\n// \t  bitmap image, or\n// \t- have two images, one at normal resolution and one at 2x\n// \t  resolution; this matches the current expectations of some\n// \t  desktop systems at the time of writing (mid-2018)\n// \n// uiImage is very simple: it only supports premultiplied 32-bit\n// RGBA images, and libui does not provide any image file loading\n// or image format conversion utilities on top of that.\ntypedef struct uiImage uiImage;\n\n// @role uiImage constructor\n// uiNewImage creates a new uiImage with the given width and\n// height. This width and height should be the size in points of the\n// image in the device-independent case; typically this is the 1x size.\n// TODO for all uiImage functions: use const void * for const correctness\n_UI_EXTERN uiImage *uiNewImage(double width, double height);\n\n// @role uiImage destructor\n// uiFreeImage frees the given image and all associated resources.\n_UI_EXTERN void uiFreeImage(uiImage *i);\n\n// uiImageAppend adds a representation to the uiImage.\n// pixels should point to a byte array of premultiplied pixels\n// stored in [R G B A] order (so ((uint8_t *) pixels)[0] is the R of the\n// first pixel and [3] is the A of the first pixel). pixelWidth and\n// pixelHeight is the size *in pixels* of the image, and pixelStride is\n// the number *of bytes* per row of the pixels array. Therefore,\n// pixels itself must be at least byteStride * pixelHeight bytes long.\n// TODO see if we either need the stride or can provide a way to get the OS-preferred stride (in cairo we do)\n_UI_EXTERN void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int byteStride);\n\n// uiTableValue stores a value to be passed along uiTable and\n// uiTableModel.\n//\n// You do not create uiTableValues directly; instead, you create a\n// uiTableValue of a given type using the specialized constructor\n// functions.\n//\n// uiTableValues are immutable and the uiTableModel and uiTable\n// take ownership of the uiTableValue object once returned, copying\n// its contents as necessary.\ntypedef struct uiTableValue uiTableValue;\n\n// @role uiTableValue destructor\n// uiFreeTableValue() frees a uiTableValue. You generally do not\n// need to call this yourself, as uiTable and uiTableModel do this\n// for you. In fact, it is an error to call this function on a uiTableValue\n// that has been given to a uiTable or uiTableModel. You can call this,\n// however, if you created a uiTableValue that you aren't going to\n// use later, or if you called a uiTableModelHandler method directly\n// and thus never transferred ownership of the uiTableValue.\n_UI_EXTERN void uiFreeTableValue(uiTableValue *v);\n\n// uiTableValueType holds the possible uiTableValue types that may\n// be returned by uiTableValueGetType(). Refer to the documentation\n// for each type's constructor function for details on each type.\n// TODO actually validate these\n_UI_ENUM(uiTableValueType) {\n\tuiTableValueTypeString,\n\tuiTableValueTypeImage,\n\tuiTableValueTypeInt,\n\tuiTableValueTypeColor,\n};\n\n// uiTableValueGetType() returns the type of v.\n// TODO I don't like this name\n_UI_EXTERN uiTableValueType uiTableValueGetType(const uiTableValue *v);\n\n// uiNewTableValueString() returns a new uiTableValue that contains\n// str. str is copied; you do not need to keep it alive after\n// uiNewTableValueString() returns.\n_UI_EXTERN uiTableValue *uiNewTableValueString(const char *str);\n\n// uiTableValueString() returns the string stored in v. The returned\n// string is owned by v. It is an error to call this on a uiTableValue\n// that does not hold a string.\n_UI_EXTERN const char *uiTableValueString(const uiTableValue *v);\n\n// uiNewTableValueImage() returns a new uiTableValue that contains\n// the given uiImage.\n// \n// Unlike other similar constructors, uiNewTableValueImage() does\n// NOT copy the image. This is because images are comparatively\n// larger than the other objects in question. Therefore, you MUST\n// keep the image alive as long as the returned uiTableValue is alive.\n// As a general rule, if libui calls a uiTableModelHandler method, the\n// uiImage is safe to free once any of your code is once again\n// executed.\n_UI_EXTERN uiTableValue *uiNewTableValueImage(uiImage *img);\n\n// uiTableValueImage() returns the uiImage stored in v. As these\n// images are not owned by v, you should not assume anything\n// about the lifetime of the image (unless you created the image,\n// and thus control its lifetime). It is an error to call this on a\n// uiTableValue that does not hold an image.\n_UI_EXTERN uiImage *uiTableValueImage(const uiTableValue *v);\n\n// uiNewTableValueInt() returns a uiTableValue that stores the given\n// int. This can be used both for boolean values (nonzero is true, as\n// in C) or progresses (in which case the valid range is -1..100\n// inclusive).\n_UI_EXTERN uiTableValue *uiNewTableValueInt(int i);\n\n// uiTableValueInt() returns the int stored in v. It is an error to call\n// this on a uiTableValue that does not store an int.\n_UI_EXTERN int uiTableValueInt(const uiTableValue *v);\n\n// uiNewTableValueColor() returns a uiTableValue that stores the\n// given color.\n_UI_EXTERN uiTableValue *uiNewTableValueColor(double r, double g, double b, double a);\n\n// uiTableValueColor() returns the color stored in v. It is an error to\n// call this on a uiTableValue that does not store a color.\n// TODO define whether all this, for both uiTableValue and uiAttribute, is undefined behavior or a caught error\n_UI_EXTERN void uiTableValueColor(const uiTableValue *v, double *r, double *g, double *b, double *a);\n\n// uiTableModel is an object that provides the data for a uiTable.\n// This data is returned via methods you provide in the\n// uiTableModelHandler struct.\n//\n// uiTableModel represents data using a table, but this table does\n// not map directly to uiTable itself. Instead, you can have data\n// columns which provide instructions for how to render a given\n// uiTable's column — for instance, one model column can be used\n// to give certain rows of a uiTable a different background color.\n// Row numbers DO match with uiTable row numbers.\n//\n// Once created, the number and data types of columns of a\n// uiTableModel cannot change.\n//\n// Row and column numbers start at 0. A uiTableModel can be\n// associated with more than one uiTable at a time.\ntypedef struct uiTableModel uiTableModel;\n\n// uiTableModelHandler defines the methods that uiTableModel\n// calls when it needs data. Once a uiTableModel is created, these\n// methods cannot change.\ntypedef struct uiTableModelHandler uiTableModelHandler;\n\n// TODO validate ranges; validate types on each getter/setter call (? table columns only?)\nstruct uiTableModelHandler {\n\t// NumColumns returns the number of model columns in the\n\t// uiTableModel. This value must remain constant through the\n\t// lifetime of the uiTableModel. This method is not guaranteed\n\t// to be called depending on the system.\n\t// TODO strongly check column numbers and types on all platforms so these clauses can go away\n\tint (*NumColumns)(uiTableModelHandler *, uiTableModel *);\n\t// ColumnType returns the value type of the data stored in\n\t// the given model column of the uiTableModel. The returned\n\t// values must remain constant through the lifetime of the\n\t// uiTableModel. This method is not guaranteed to be called\n\t// depending on the system.\n\tuiTableValueType (*ColumnType)(uiTableModelHandler *, uiTableModel *, int);\n\t// NumRows returns the number or rows in the uiTableModel.\n\t// This value must be non-negative.\n\tint (*NumRows)(uiTableModelHandler *, uiTableModel *);\n\t// CellValue returns a uiTableValue corresponding to the model\n\t// cell at (row, column). The type of the returned uiTableValue\n\t// must match column's value type. Under some circumstances,\n\t// NULL may be returned; refer to the various methods that add\n\t// columns to uiTable for details. Once returned, the uiTable\n\t// that calls CellValue will free the uiTableValue returned.\n\tuiTableValue *(*CellValue)(uiTableModelHandler *mh, uiTableModel *m, int row, int column);\n\t// SetCellValue changes the model cell value at (row, column)\n\t// in the uiTableModel. Within this function, either do nothing\n\t// to keep the current cell value or save the new cell value as\n\t// appropriate. After SetCellValue is called, the uiTable will\n\t// itself reload the table cell. Under certain conditions, the\n\t// uiTableValue passed in can be NULL; refer to the various\n\t// methods that add columns to uiTable for details. Once\n\t// returned, the uiTable that called SetCellValue will free the\n\t// uiTableValue passed in.\n\tvoid (*SetCellValue)(uiTableModelHandler *, uiTableModel *, int, int, const uiTableValue *);\n};\n\n// @role uiTableModel constructor\n// uiNewTableModel() creates a new uiTableModel with the given\n// handler methods.\n_UI_EXTERN uiTableModel *uiNewTableModel(uiTableModelHandler *mh);\n\n// @role uiTableModel destructor\n// uiFreeTableModel() frees the given table model. It is an error to\n// free table models currently associated with a uiTable.\n_UI_EXTERN void uiFreeTableModel(uiTableModel *m);\n\n// uiTableModelRowInserted() tells any uiTable associated with m\n// that a new row has been added to m at index index. You call\n// this function when the number of rows in your model has\n// changed; after calling it, NumRows() should returm the new row\n// count.\n_UI_EXTERN void uiTableModelRowInserted(uiTableModel *m, int newIndex);\n\n// uiTableModelRowChanged() tells any uiTable associated with m\n// that the data in the row at index has changed. You do not need to\n// call this in your SetCellValue() handlers, but you do need to call\n// this if your data changes at some other point.\n_UI_EXTERN void uiTableModelRowChanged(uiTableModel *m, int index);\n\n// uiTableModelRowDeleted() tells any uiTable associated with m\n// that the row at index index has been deleted. You call this\n// function when the number of rows in your model has changed;\n// after calling it, NumRows() should returm the new row\n// count.\n// TODO for this and Inserted: make sure the \"after\" part is right; clarify if it's after returning or after calling\n_UI_EXTERN void uiTableModelRowDeleted(uiTableModel *m, int oldIndex);\n// TODO reordering/moving\n\n// uiTableModelColumnNeverEditable and\n// uiTableModelColumnAlwaysEditable are the value of an editable\n// model column parameter to one of the uiTable create column\n// functions; if used, that jparticular uiTable colum is not editable\n// by the user and always editable by the user, respectively.\n#define uiTableModelColumnNeverEditable (-1)\n#define uiTableModelColumnAlwaysEditable (-2)\n\n// uiTableTextColumnOptionalParams are the optional parameters\n// that control the appearance of the text column of a uiTable.\ntypedef struct uiTableTextColumnOptionalParams uiTableTextColumnOptionalParams;\n\n// uiTableParams defines the parameters passed to uiNewTable().\ntypedef struct uiTableParams uiTableParams;\n\nstruct uiTableTextColumnOptionalParams {\n\t// ColorModelColumn is the model column containing the\n\t// text color of this uiTable column's text, or -1 to use the\n\t// default color.\n\t//\n\t// If CellValue() for this column for any cell returns NULL, that\n\t// cell will also use the default text color.\n\tint ColorModelColumn;\n};\n\nstruct uiTableParams {\n\t// Model is the uiTableModel to use for this uiTable.\n\t// This parameter cannot be NULL.\n\tuiTableModel *Model;\n\t// RowBackgroundColorModelColumn is a model column\n\t// number that defines the background color used for the\n\t// entire row in the uiTable, or -1 to use the default color for\n\t// all rows.\n\t//\n\t// If CellValue() for this column for any row returns NULL, that\n\t// row will also use the default background color.\n\tint RowBackgroundColorModelColumn;\n};\n\n// uiTable is a uiControl that shows tabular data, allowing users to\n// manipulate rows of such data at a time.\ntypedef struct uiTable uiTable;\n#define uiTable(this) ((uiTable *) (this))\n\n// uiTableAppendTextColumn() appends a text column to t.\n// name is displayed in the table header.\n// textModelColumn is where the text comes from.\n// If a row is editable according to textEditableModelColumn,\n// SetCellValue() is called with textModelColumn as the column.\n_UI_EXTERN void uiTableAppendTextColumn(uiTable *t,\n\tconst char *name,\n\tint textModelColumn,\n\tint textEditableModelColumn,\n\tuiTableTextColumnOptionalParams *textParams);\n\n// uiTableAppendImageColumn() appends an image column to t.\n// Images are drawn at icon size, appropriate to the pixel density\n// of the screen showing the uiTable.\n_UI_EXTERN void uiTableAppendImageColumn(uiTable *t,\n\tconst char *name,\n\tint imageModelColumn);\n\n// uiTableAppendImageTextColumn() appends a column to t that\n// shows both an image and text.\n_UI_EXTERN void uiTableAppendImageTextColumn(uiTable *t,\n\tconst char *name,\n\tint imageModelColumn,\n\tint textModelColumn,\n\tint textEditableModelColumn,\n\tuiTableTextColumnOptionalParams *textParams);\n\n// uiTableAppendCheckboxColumn appends a column to t that\n// contains a checkbox that the user can interact with (assuming the\n// checkbox is editable). SetCellValue() will be called with\n// checkboxModelColumn as the column in this case.\n_UI_EXTERN void uiTableAppendCheckboxColumn(uiTable *t,\n\tconst char *name,\n\tint checkboxModelColumn,\n\tint checkboxEditableModelColumn);\n\n// uiTableAppendCheckboxTextColumn() appends a column to t\n// that contains both a checkbox and text.\n_UI_EXTERN void uiTableAppendCheckboxTextColumn(uiTable *t,\n\tconst char *name,\n\tint checkboxModelColumn,\n\tint checkboxEditableModelColumn,\n\tint textModelColumn,\n\tint textEditableModelColumn,\n\tuiTableTextColumnOptionalParams *textParams);\n\n// uiTableAppendProgressBarColumn() appends a column to t\n// that displays a progress bar. These columns work like\n// uiProgressBar: a cell value of 0..100 displays that percentage, and\n// a cell value of -1 displays an indeterminate progress bar.\n_UI_EXTERN void uiTableAppendProgressBarColumn(uiTable *t,\n\tconst char *name,\n\tint progressModelColumn);\n\n// uiTableAppendButtonColumn() appends a column to t\n// that shows a button that the user can click on. When the user\n// does click on the button, SetCellValue() is called with a NULL\n// value and buttonModelColumn as the column.\n// CellValue() on buttonModelColumn should return the text to show\n// in the button.\n_UI_EXTERN void uiTableAppendButtonColumn(uiTable *t,\n\tconst char *name,\n\tint buttonModelColumn,\n\tint buttonClickableModelColumn);\n\n// uiNewTable() creates a new uiTable with the specified parameters.\n_UI_EXTERN uiTable *uiNewTable(uiTableParams *params);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "util.go",
    "content": "// 12 december 2015\n\npackage ui\n\nimport (\n\t\"unsafe\"\n)\n\n// #include \"pkgui.h\"\nimport \"C\"\n\n//export pkguiAlloc\nfunc pkguiAlloc(n C.size_t) unsafe.Pointer {\n\t// cgo turns C.malloc() into a panic-on-OOM version; use it\n\tret := C.malloc(n)\n\t// and this won't zero-initialize; do it ourselves\n\tC.memset(ret, 0, n)\n\treturn ret\n}\n\nfunc freestr(str *C.char) {\n\tC.free(unsafe.Pointer(str))\n}\n\nfunc tobool(b C.int) bool {\n\treturn b != 0\n}\n\nfunc frombool(b bool) C.int {\n\tif b {\n\t\treturn 1\n\t}\n\treturn 0\n}\n"
  },
  {
    "path": "window.go",
    "content": "// 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 represents a top-level window.\n// A Window contains one child Control that occupies the\n// entirety of the window. Though a Window is a Control,\n// a Window cannot be the child of another Control.\ntype Window struct {\n\tControlBase\n\tw\t*C.uiWindow\n\tchild\t\tControl\n\tonClosing\t\tfunc(w *Window) bool\n}\n\n// NewWindow creates a new Window.\nfunc NewWindow(title string, width int, height int, hasMenubar bool) *Window {\n\tw := new(Window)\n\n\tctitle := C.CString(title)\n\tw.w = C.uiNewWindow(ctitle, C.int(width), C.int(height), frombool(hasMenubar))\n\tfreestr(ctitle)\n\n\tC.pkguiWindowOnClosing(w.w)\n\n\tw.ControlBase = NewControlBase(w, uintptr(unsafe.Pointer(w.w)))\n\treturn w\n}\n\n// Destroy destroys the Window. If the Window has a child,\n// Destroy calls Destroy on that as well.\nfunc (w *Window) Destroy() {\n\tw.Hide()\t\t// first hide the window, in case anything in the below if statement forces an immediate redraw\n\tif w.child != nil {\n\t\tc := w.child\n\t\tw.SetChild(nil)\n\t\tc.Destroy()\n\t}\n\tw.ControlBase.Destroy()\n}\n\n// Title returns the Window's title.\nfunc (w *Window) Title() string {\n\tctitle := C.uiWindowTitle(w.w)\n\ttitle := C.GoString(ctitle)\n\tC.uiFreeText(ctitle)\n\treturn title\n}\n\n// SetTitle sets the Window's title to title.\nfunc (w *Window) SetTitle(title string) {\n\tctitle := C.CString(title)\n\tC.uiWindowSetTitle(w.w, ctitle)\n\tfreestr(ctitle)\n}\n\n// TODO ContentSize\n// TODO SetContentSize\n// TODO Fullscreen\n// TODO SetFullscreen\n// TODO OnContentSizeChanged\n\n// OnClosing registers f to be run when the user clicks the Window's\n// close button. Only one function can be registered at a time.\n// If f returns true, the window is destroyed with the Destroy method.\n// If f returns false, or if OnClosing is never called, the window is not\n// destroyed and is kept visible.\nfunc (w *Window) OnClosing(f func(*Window) bool) {\n\tw.onClosing = f\n}\n\n//export pkguiDoWindowOnClosing\nfunc pkguiDoWindowOnClosing(ww *C.uiWindow, data unsafe.Pointer) C.int {\n\tw := ControlFromLibui(uintptr(unsafe.Pointer(ww))).(*Window)\n\tif w.onClosing == nil {\n\t\treturn 0\n\t}\n\tif w.onClosing(w) {\n\t\tw.Destroy()\n\t}\n\treturn 0\n}\n\n// Borderless returns whether the Window is borderless.\nfunc (w *Window) Borderless() bool {\n\treturn tobool(C.uiWindowBorderless(w.w))\n}\n\n// SetBorderless sets the Window to be borderless or not.\nfunc (w *Window) SetBorderless(borderless bool) {\n\tC.uiWindowSetBorderless(w.w, frombool(borderless))\n}\n\n// SetChild sets the Window's child to child. If child is nil, the Window\n// will not have a child.\nfunc (w *Window) SetChild(child Control) {\n\tw.child = child\n\tc := (*C.uiControl)(nil)\n\tif w.child != nil {\n\t\tc = touiControl(w.child.LibuiControl())\n\t}\n\tC.uiWindowSetChild(w.w, c)\n}\n\n// Margined returns whether the Window has margins around its child.\nfunc (w *Window) Margined() bool {\n\treturn tobool(C.uiWindowMargined(w.w))\n}\n\n// SetMargined controls whether the Window has margins around its\n// child. The size of the margins are determined by the OS and its\n// best practices.\nfunc (w *Window) SetMargined(margined bool) {\n\tC.uiWindowSetMargined(w.w, frombool(margined))\n}\n"
  },
  {
    "path": "winmanifest/doc.go",
    "content": "// 2 september 2018\n\n// Package winmanifest provides a basic manifest for use with\n// package ui. You import it for its side effects only, as\n// \n// \timport _ \"github.com/andlabs/ui/winmanifest\"\n// \n// On non-Windows platforms this package does nothing.\n// \n// If you intend on using a custom manifest instead of the generic\n// one in this package, be sure to read package ui's README so your\n// manifest can have the directives necessary for package ui to work.\npackage winmanifest\n"
  },
  {
    "path": "winmanifest/resources.rc",
    "content": "// 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 up the string values here\n// 1 is the value of CREATEPROCESS_MANIFEST_RESOURCE_ID and 24 is the value of RT_MANIFEST; we use it directly to avoid needing to share winapi.h with the tests and examples\n1 24 \"ui.manifest\"\n"
  },
  {
    "path": "winmanifest/ui.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n    version=\"1.0.0.0\"\n    processorArchitecture=\"*\"\n    name=\"CompanyName.ProductName.YourApplication\"\n    type=\"win32\"\n/>\n<description>Your application description here.</description>\n<!-- we DO need comctl6 in the static case -->\n<dependency>\n    <dependentAssembly>\n        <assemblyIdentity\n            type=\"win32\"\n            name=\"Microsoft.Windows.Common-Controls\"\n            version=\"6.0.0.0\"\n            processorArchitecture=\"*\"\n            publicKeyToken=\"6595b64144ccf1df\"\n            language=\"*\"\n        />\n    </dependentAssembly>\n</dependency>\n<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n        <!--The ID below indicates application support for Windows Vista -->\n        <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>\n        <!--The ID below indicates application support for Windows 7 -->\n        <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n\n        <!-- The ones below are not needed for package ui, but are provided to avoid surprises when interoperating with other packages, or with the Go runtime itself; see also https://github.com/golang/go/issues/17835 -->\n\n        <!--The ID below indicates application support for Windows 8 -->\n        <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n        <!--The ID below indicates application support for Windows 8.1 -->\n        <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n        <!--The ID below indicates application support for Windows 10 -->\n        <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n    </application>\n</compatibility>\n</assembly>\n\n"
  }
]