duit

package module
v0.0.0-...-c6bd4dd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2022 License: MIT Imports: 20 Imported by: 0

README

GoDoc

duit - developer ui toolkit

WARNING: this library is work in progress. backwards incompatible changes will be made.

details

duit is a pure go (*), cross platform, MIT-licensed ui toolkit for developers. the api is small and uncomplicated.

duit works on the bsd's, linux and macos. it should be easy to get running on plan 9. for now, use the windows subsystem for linux on windows.

(*) duit currently needs a helper tool called devdraw, from plan9port (aka plan 9 from user space). plan9port is available for most unix systems, with devdraw in an x11 and native macos variant.

screenshots

duit screenshot

you should just try duit. using it and interacting with it gives a more complete impression.

instructions

setting this up currently requires some effort:

  • install plan9port, see https://9fans.github.io/plan9port/ (use their install instructions)
  • install a nice font. i use & recommend lato for a modern look. duit will automatically pick it up through $font (through plan9port's fontsrv), e.g.: export font=/mnt/font/Lato-Regular/15a/font

you should now be able to run the code in examples/

devdraw is not yet available as a native binary for windows. for now, use the windows subsystem for linux (ubuntu) on windows along with Xming. see https://github.com/elrzn/acme-wsl for instructions.

created with duit

see https://github.com/mjl- for applications. applications created with duit by other developers:

  • be the first to add your application here! (:

more

Documentation

Overview

Package duit is a pure go, cross-platform, MIT-licensed, UI toolkit for developers.

The examples/ directory has small code examples for working with duit and its UIs. Examples are the recommended starting point.

Instructions and information

Start with NewDUI to create a DUI: essentially a window and all the UI state.

The user interface consists of a hierarchy of "UIs" like Box, Scroll, Button, Label, etc. They are called UIs, after the interface UI they all implement. The zero structs for UIs have sane default behaviour so you only have to fill in the fields you need.

UIs are kept/wrapped in a Kid, to track their layout/draw state. Use NewKids() to build up the UIs for your application. You won't see much of the Kid-types/functions otherwise, unless you implement a new UI.

You are in charge of the main event loop, receiving mouse/keyboard/window events from the dui.Inputs channel, and typically passing them on unchanged to dui.Input. All callbacks and functions on UIs are called from inside dui.Input. From there you can also safely change the the UIs, no locking required. After changing a UI you are responsible for calling MarkLayout or MarkDraw to tell duit the UI needs a new layout or draw. This may sound like more work, but this tradeoff keeps the API small and easy to use. If you need to change the UI from a goroutine outside of the main loop, e.g. for blocking calls, you can send a function that makes those modifications on the dui.Call channel, which will be run on the main channel through dui.Inputs. After handling an input, duit will layout or draw as necessary, no need to render explicitly.

Embedding a UI into your own data structure is often an easy way to build up UI hiearchies.

Scrolling

Scroll and Edit show a scrollbar. Use button 1 on the scrollbar to scroll up, button 3 to scroll down. If you click more near the top, you scroll less. More near the bottom, more. Button 2 scrolls to the absolute place, where you clicked. Button 4 and 5 are wheel up and wheel down, and also scroll less/more depending on position in the UI.

Index

Constants

View Source
const (
	BorderSize = 1 // regardless of lowDPI/hiDPI, won't be scaled

	ScrollbarSize = 10 // in lowDPI pixels
)
View Source
const (
	Button1 = 1 << iota
	Button2
	Button3
	Button4 // wheel up
	Button5 // wheel down
)

Mouse buttons, see draw.Mouse.Buttons.

View Source
const (
	Dirty    = State(iota) // UI itself needs layout/draw;  kids will also get a UI.Layout/UI.Draw call, with force set.
	DirtyKid               // UI itself does not need layout/draw, but one of its children does, so pass the call on.
	Clean                  // UI and its children do not need layout/draw.

)

Variables

View Source
var (
	EditPadding = Space{0, 3, 0, 3} // LowDPI padding, drawn with a distinct color when in vi modes.
)

Functions

func Alert

func Alert(text string) (err error)

Alert creates a new window that show text and a button labeled OK that closes the window.

func AppDataDir

func AppDataDir(app string) string

AppdataDir returns the directory where the application can store its files, like configuration, inside os.UserConfigDir. Deprecated: Use os.UserConfigDir or os.UserHomeDir. This used to be $HOME/lib/<app> on unix and $APPDATA/<app> on windows.

func KidsDraw

func KidsDraw(dui *DUI, self *Kid, kids []*Kid, uiSize image.Point, bg, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

KidsDraw draws a UI by drawing all its kids. uiSize is the size of the entire UI, used in case it has to be redrawn entirely. Bg can override the default duit background color. Img is the whether the UI should be drawn on, with orig as origin (offset). M is used for passing a mouse position to the kid's UI draw, for possibly drawing hover states. KidsDraw only draws if draw state indicates a need for drawing, or if force is set.

func KidsFirstFocus

func KidsFirstFocus(dui *DUI, self *Kid, kids []*Kid) *image.Point

KidsFirstFocus delivers the FirstFocus request to the first leaf UI, and returns the location where the mouse should warp to.

func KidsFocus

func KidsFocus(dui *DUI, self *Kid, kids []*Kid, ui UI) *image.Point

KidsFocus delivers the Focus request to the first leaf UI, and returns the location where the mouse should warp to.

func KidsLayout

func KidsLayout(dui *DUI, self *Kid, kids []*Kid, force bool) (done bool)

KidsLayout is called by layout UIs before they do their own layouts. KidsLayout returns whether there is any work left to do, determined by looking at self.Layout. Children will be layed out if necessary. KidsLayout updates layout and draw state of self and kids.

func KidsMark

func KidsMark(self *Kid, kids []*Kid, o UI, forLayout bool) (marked bool)

KidsMark finds o in this UI subtree (self and kids), marks it as needing layout or draw (forLayout false), and returns whether it found and marked the UI.

func KidsPrint

func KidsPrint(kids []*Kid, indent int)

KidsPrint calls Print on each kid UI.

func PrintUI

func PrintUI(s string, self *Kid, indent int)

PrintUI is a helper function UIs can use to implement UI.Print. "s" is typically the ui type, possibly with additional properties. Indent should be increased for each child UI that is printed.

func ReadImage

func ReadImage(display *draw.Display, f io.Reader) (*draw.Image, error)

ReadImage decodes an image from f for use on display. The returned image is ready for use in an Image UI.

func ReadImagePath

func ReadImagePath(display *draw.Display, path string) (*draw.Image, error)

ReadImagePath is a convenience function that opens path and calls ReadImage.

Types

type Box

type Box struct {
	Kids       []*Kid      // Kids and UIs in this box.
	Reverse    bool        // Lay out children from bottom to top. First kid will be at the bottom.
	Margin     image.Point // In lowDPI pixels, will be adjusted for highDPI screens.
	Padding    Space       // Padding inside box, so children don't touch the sides; in lowDPI pixels, also adjusted for highDPI screens.
	Valign     Valign      // How to align children on a line.
	Width      int         // 0 means dynamic (as much as needed), -1 means full width, >0 means that exact amount of lowDPI pixels.
	Height     int         // 0 means dynamic (as much as needed), -1 means full height, >0 means that exact amount of lowDPI pixels.
	MaxWidth   int         // if >0, the max number of lowDPI pixels that will be used.
	Background *draw.Image `json:"-"` // Background for this box, instead of default duit background.
	// contains filtered or unexported fields
}

Box keeps elements on a line as long as they fit, then moves on to the next line.

func NewBox

func NewBox(uis ...UI) *Box

NewBox returns a box containing all uis in its Kids field.

func NewReverseBox

func NewReverseBox(uis ...UI) *Box

NewReverseBox returns a box containing all uis in original order in its Kids field, with the Reverse field set.

func (*Box) Draw

func (ui *Box) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Box) FirstFocus

func (ui *Box) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Box) Focus

func (ui *Box) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Box) Key

func (ui *Box) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Box) Layout

func (ui *Box) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Box) Mark

func (ui *Box) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Box) Mouse

func (ui *Box) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Box) Print

func (ui *Box) Print(self *Kid, indent int)

type Button

type Button struct {
	Text     string           // Displayed on button.
	Icon     Icon             `json:"-"` // Displayed before text, if Icon.Font is not nil.
	Disabled bool             // If disabled, colors used indicate disabledness, clicks don't result in Click being called.
	Colorset *Colorset        `json:"-"` // Colors used, for example DUI.Primary. Defaults to DUI.Regular.
	Font     *draw.Font       `json:"-"` // Used to draw Text, if not nil.
	Click    func() (e Event) `json:"-"` // Called on click on the button.
	// contains filtered or unexported fields
}

Button with text and optional icon with a click function.

func (*Button) Draw

func (ui *Button) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Button) FirstFocus

func (ui *Button) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Button) Focus

func (ui *Button) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Button) Key

func (ui *Button) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Button) Layout

func (ui *Button) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Button) Mark

func (ui *Button) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Button) Mouse

func (ui *Button) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Button) Print

func (ui *Button) Print(self *Kid, indent int)

type Buttongroup

type Buttongroup struct {
	Texts    []string                  // Texts to display on the buttons.
	Selected int                       // Index in Text of the currently selected button.
	Disabled bool                      // If disabled, the duit.Disabled colors are used and clicks have no effect.
	Font     *draw.Font                `json:"-"` // Used for drawing Texts.
	Changed  func(index int) (e Event) `json:"-"` // Called on click on a different button in the group then previously selected.
	// contains filtered or unexported fields
}

Buttongroup shows multiple joined buttons, with one of them active.

func (*Buttongroup) Draw

func (ui *Buttongroup) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Buttongroup) FirstFocus

func (ui *Buttongroup) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Buttongroup) Focus

func (ui *Buttongroup) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Buttongroup) Key

func (ui *Buttongroup) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Buttongroup) Layout

func (ui *Buttongroup) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Buttongroup) Mark

func (ui *Buttongroup) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Buttongroup) Mouse

func (ui *Buttongroup) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Buttongroup) Print

func (ui *Buttongroup) Print(self *Kid, indent int)

type Checkbox

type Checkbox struct {
	Checked  bool             // Whether checked or not.
	Disabled bool             // Whether clicks have any effect.
	Font     *draw.Font       `json:"-"` // Only used to determine height of the checkbox. Specify same font as for label.
	Changed  func() (e Event) `json:"-"` // Called after the value changed.
	// contains filtered or unexported fields
}

Checkbox holds a true/false value. A label is not part of the checkbox, you should create it explicitly and add a click handler to toggle the checkbox.

func (*Checkbox) Draw

func (ui *Checkbox) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Checkbox) FirstFocus

func (ui *Checkbox) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Checkbox) Focus

func (ui *Checkbox) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Checkbox) Key

func (ui *Checkbox) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Checkbox) Layout

func (ui *Checkbox) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Checkbox) Mark

func (ui *Checkbox) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Checkbox) Mouse

func (ui *Checkbox) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Checkbox) Print

func (ui *Checkbox) Print(self *Kid, indent int)

type Colors

type Colors struct {
	Text       *draw.Image `json:"-"`
	Background *draw.Image `json:"-"`
	Border     *draw.Image `json:"-"`
}

Colors represents the style in one state of the UI.

type Colorset

type Colorset struct {
	Normal, Hover Colors
}

Colorset is typically used to style buttons. Duit provides some builtin colorsets like Primary, Danger, Success.

type Cursor

type Cursor struct {
	Cur   int64 // Current location/end of selection.
	Start int64 // Start of selection, not necessarily larger than Cur!
}

Cursor represents the current editing location, and optionally text selection.

func (Cursor) Ordered

func (c Cursor) Ordered() (int64, int64)

Ordered returns the ordered start, end position of the cursor.

type DUI

type DUI struct {
	Inputs  chan Input  // Duit sends input events on this channel, needs to be read from the main loop.
	Top     Kid         // Root of the UI hierarchy. Wrapped in a Kid for state management.
	Call    chan func() // Functions sent here will go through DUI.Inputs and run by DUI.Input() in the main event loop. For code that changes UI state.
	Error   chan error  // Receives errors from UIs. For example when memory for an image could not be allocated. Closed when window is closed. Needs to be read from the main loop.
	Display *draw.Display

	// Colors.
	Disabled,
	Inverse,
	Selection,
	SelectionHover,
	Placeholder,
	Striped Colors

	// Colors with hover-variants.
	Regular,
	Primary,
	Secondary,
	Success,
	Danger Colorset

	// Background color UIs should have.
	BackgroundColor draw.Color
	Background      *draw.Image

	// Scrollbar colors.
	ScrollBGNormal,
	ScrollBGHover,
	ScrollVisibleNormal,
	ScrollVisibleHover *draw.Image

	// Gutter color.
	Gutter *draw.Image

	Debug       bool // Log errors interesting to developers.
	DebugDraw   int  // If 1, UIs print each draw they do. If 2, UIs print all calls to their Draw function. Cycle through 0-2 with F7.
	DebugLayout int  // If 1, UIs print each Layout they do. If 2, UIs print all calls to their Layout function. Cycle through 0-2 with F8.
	DebugKids   bool // Whether to print distinct backgrounds in kids* functions.

	// Border colors for vi modes for Edit.
	CommandMode,
	VisualMode *draw.Image
	// contains filtered or unexported fields
}

DUI represents a window and all UI state for that window.

func NewDUI

func NewDUI(name string, opts *DUIOpts) (dui *DUI, err error)

NewDUI creates a DUI for an application called name, and optional opts. A DUI is a new window and its UI state. Window dimensions and UI settings are automatically written to $APPDATA/duit/<name>, with $APPDATA being $HOME/lib on unix.

func (*DUI) Close

func (d *DUI) Close()

Close stops mouse/keyboard event reading and closes the window. After closing a DUI you should no longer call functions on it.

func (*DUI) Draw

func (d *DUI) Draw()

Draw the entire UI tree, as necessary. Only UIs marked as requiring a draw are actually drawn, and their children.

func (*DUI) Focus

func (d *DUI) Focus(ui UI)

Focus renders the UI, then changes focus to ui by warping the mouse pointer to it. Container UIs ensure the UI is in place, e.g. scrolling if necessary.

func (*DUI) Font

func (d *DUI) Font(font *draw.Font) *draw.Font

Font is a helper function for UI implementations. It returns the passed font. Unless font is nil, then it returns the default font.

func (*DUI) Input

func (d *DUI) Input(e Input)

Input propagates the input event through the UI tree. Mouse and key events are delivered the right UIs. Resize is handled by reattaching to devdraw and doing a layout and draw. Func calls the function. Error implies an error from devdraw and terminates the program.

func (*DUI) Key

func (d *DUI) Key(k rune)

Key delivers a key press event to the UI tree. Key is typically called by Input.

func (*DUI) Layout

func (d *DUI) Layout()

Layout the entire UI tree, as necessary. Only UIs marked as requiring a layout are actually layed out. UIs that receive a layout are marked as requiring a draw.

func (*DUI) MarkDraw

func (d *DUI) MarkDraw(ui UI)

MarkDraw is like MarkLayout, but marks ui as requiring a draw.

func (*DUI) MarkLayout

func (d *DUI) MarkLayout(ui UI)

MarkLayout marks ui as requiring a layout. If you have access to the Kid that holds this UI, it is more efficient to change the Kid itself. MarkLayout is more convenient. Using it can cut down on bookkeeping. If ui is nil, the top UI is marked.

func (*DUI) Mouse

func (d *DUI) Mouse(m draw.Mouse)

Mouse delivers a mouse event to the UI tree. Mouse is typically called by Input.

func (*DUI) ReadSettings

func (d *DUI) ReadSettings(self *Kid, v interface{}) bool

ReadSettings reads the settings for self.ID if any into v. Settings are stored as JSON, (un)marshalled with encoding/json. ReadSettings returns whether reading settings was successful.

func (*DUI) ReadSnarf

func (d *DUI) ReadSnarf() (buf []byte, success bool)

ReadSnarf reads the entire snarf buffer and logs an error in case of failure.

func (*DUI) Render

func (d *DUI) Render()

Render calls Layout followed by Draw. This only does a layout/draw for UIs marked as needing it. If you want to force a layout/draw, mark the top UI as requiring a layout/draw.

func (*DUI) Resize

func (d *DUI) Resize()

Resize handles a resize of the window. Resize is called automatically through Input when the user resizes a window.

func (*DUI) Scale

func (d *DUI) Scale(n int) int

Scale turns a low DPI pixel size into a size scaled for the current display.

func (*DUI) ScaleSpace

func (d *DUI) ScaleSpace(s Space) Space

ScaleSpace is like Scale, but for a Space.

func (*DUI) WriteSettings

func (d *DUI) WriteSettings(self *Kid, v interface{}) bool

WriteSettings writes settings v for self.ID as JSON. WriteSettings delays a write for an ID for 2 seconds. Delayed writes are canceled by new writes.

func (*DUI) WriteSnarf

func (d *DUI) WriteSnarf(buf []byte)

WriteSnarf writes the snarf buffer and logs an error in case of failure.

type DUIOpts

type DUIOpts struct {
	FontName   string // eg "/mnt/font/Lato-Regular/15a/font"
	Dimensions string // eg "800x600", duit has a sane default and remembers size per application name after resize.
}

DUIOpts are options for creating a new DUI. Zero values have sane behaviour.

type Edit

type Edit struct {
	NoScrollbar  bool                                       // If set, no scrollbar is shown. Content will still scroll.
	LastSearch   string                                     // If starting with slash, the remainder is interpreted as regexp. used by cmd+[/?] and vi [*nN] commands. Literal text search should start with a space.
	Error        chan error                                 // If set, errors from Edit (including read errors from underlying files) are sent here. If nil, errors go to dui.Error.
	Colors       *EditColors                                `json:"-"` // Colors to use for drawing the Edit UI, allows for creating an acme look.
	Font         *draw.Font                                 `json:"-"` // Used for drawing all text.
	Keys         func(k rune, m draw.Mouse) (e Event)       `json:"-"` // Called before handling keys. If you set e.Consumed, the key is not handled further.
	Click        func(m draw.Mouse, offset int64) (e Event) `json:"-"` // Called for clicks with button 1,2,3. Offset is the file offset that was clicked on.
	DirtyChanged func(dirty bool)                           `json:"-"` // Called when the dirty-state of the underlying file changes.
	// contains filtered or unexported fields
}

Edit is a text editor inspired by acme, with vi key bindings. An edit has its own scrollbar, unlimited undo. It can read utf-8 encoded files of arbritary length, only reading data when necessary, to display or search.

The usual arrow and pageup/pagedown keys can be used for navigation. Key shortcuts when combined with control:

a, to start of line
e, to end of line
h, remove character before cursor
w, remove word before cursor
u, delete to start of line
k, delete to end of line

Key shortcuts when combined with the command key:

a, select all text
n, no selection
c, copy selection
x, cut selection
v, paste selection
z, undo last change
Z, redo last undone change
[, unindent selection or line
], indent selection or line
m, warp mouse to the cursor
y, select last modification
/, repeat last search forward
?, repeat last search backward

Edit has a vi command and visual mode, entered through the familiar escape key. Not all commands have been implemented yet, Edit does not aim to be feature-complete or a clone of any specific existing vi-clone.

func NewEdit

func NewEdit(f SeekReaderAt) (ui *Edit, err error)

NewEdit returns an Edit initialized with f.

func (*Edit) Append

func (ui *Edit) Append(buf []byte)

Append adds buf to the edit contents.

func (*Edit) Cursor

func (ui *Edit) Cursor() Cursor

Cursor returns the current cursor position, including text selection.

func (*Edit) Draw

func (ui *Edit) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Edit) EditReader

func (ui *Edit) EditReader(offset int64) EditReader

EditReader from which contents of edit can be read, starting at offset.

func (*Edit) ExpandedText

func (ui *Edit) ExpandedText() ([]byte, error)

todo: maybe not have this here?

func (*Edit) FirstFocus

func (ui *Edit) FirstFocus(dui *DUI, self *Kid) (warp *image.Point)

func (*Edit) Focus

func (ui *Edit) Focus(dui *DUI, self *Kid, o UI) (warp *image.Point)

func (*Edit) Key

func (ui *Edit) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Edit) Layout

func (ui *Edit) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Edit) Mark

func (ui *Edit) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Edit) Mouse

func (ui *Edit) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Edit) Print

func (ui *Edit) Print(self *Kid, indent int)

func (*Edit) Reader

func (ui *Edit) Reader() ReaderReaderAt

Reader from which contents of edit can be read.

func (*Edit) Replace

func (ui *Edit) Replace(c Cursor, buf []byte)

Replace replaces the selection from c with buf.

func (*Edit) ReverseEditReader

func (ui *Edit) ReverseEditReader(offset int64) EditReader

ReverseEditReader from which contents of edit can be read in reverse (whole utf-8 characters), starting at offset, to 0.

func (*Edit) Saved

func (ui *Edit) Saved()

Saved marks content as saved, calling the DirtyChanged callback if set, and updating the history state.

func (*Edit) ScrollCursor

func (ui *Edit) ScrollCursor(dui *DUI)

ScrollCursor ensure cursor is visible, scrolling if necessary.

func (*Edit) Search

func (ui *Edit) Search(dui *DUI, reverse bool) (match bool)

Search finds the next occurrence of LastSearch and selects it and scrolls to it. The first character determines the kind of search. If slash, the remainder is interpreted as regular expression. If space (and currently anything else), the remainder is interpreted as a literal string.

func (*Edit) Selection

func (ui *Edit) Selection() ([]byte, error)

Selection returns the buffer of the current selection.

func (*Edit) SetCursor

func (ui *Edit) SetCursor(c Cursor)

SetCursor sets the new cursor or selection. Current is the new cursor. Start is the start of the selection. If start < 0, it is set to current.

func (*Edit) Size

func (ui *Edit) Size() int64

Size returns the size in bytes of the edit text.

func (*Edit) Text

func (ui *Edit) Text() ([]byte, error)

Text returns the entire contents.

type EditColors

type EditColors struct {
	Fg, Bg,
	SelFg, SelBg,
	ScrollVis, ScrollBg,
	HoverScrollVis, HoverScrollBg,
	CommandBorder, VisualBorder *draw.Image
}

EditColors hold all the colors used for rendering an Edit.

type EditReader

type EditReader interface {
	Peek() (r rune, eof bool)                                 // Return next character without consuming.
	TryGet() (r rune, err error)                              // Returns and consume next character.
	Get() (r rune)                                            // Return and consume next character. On error, returns -1 and sends on Edit.Error.
	Offset() (offset int64)                                   // Current offset.
	Whitespace(newline bool) (s string, eof bool)             // Consume and return whitespace, possibly including newlines.
	Nonwhitespace() (s string, eof bool)                      // Consume all except whitespace.
	Whitespacepunct(newline bool) (s string, eof bool)        // Consume whitespace and punctation.
	Nonwhitespacepunct() (s string, eof bool)                 // Consume non-whitespace and punctutation.
	Punctuation() (s string, eof bool)                        // Consume punctuation.
	Line(includeNewline bool) (runes int, s string, eof bool) // Reads to end of newline, possibly including the newline itself.
}

EditReader provides a reader to the current contents of an Edit. It is used by navigation commands and keyboard shortcuts. Both Edit.EditReader and Edit.ReverseEditReader return an EditReader. ReverseEditReader reads utf-8 characters in reverse, towards the start of the file.

type Event

type Event struct {
	Consumed   bool // Whether event was consumed, and should not be further handled by upper UI's.  Container UIs can handle some mouse/key events and decide whether they want to pass them on, or first pass them on and only consume them when a child UI hasn't done so yet.
	NeedLayout bool // Whether UI now needs a layout. Only the UI generating the event will be marked. If you another UI needs to be marked, call MarkLayout.
	NeedDraw   bool // Like NeedLayout, but for draw.
}

Event is returned by handlers, such as click or key handlers.

type Field

type Field struct {
	Text            string                               // Current text.
	Placeholder     string                               // Text displayed in lighter color as example.
	Disabled        bool                                 // If disabled, mouse and key input have no effect.
	Cursor1         int                                  // Index in string of cursor in bytes, start at 1, 0 means end of string.
	SelectionStart1 int                                  // If > 0, 1 beyond the start of the selection in bytes, with Cursor being the end.
	Password        bool                                 // Render text as bullet items to hide the password (but not length).
	Font            *draw.Font                           `json:"-"` // Font to use for drawing text.
	Changed         func(text string) (e Event)          `json:"-"` // Called after contents of field have changed.
	Keys            func(k rune, m draw.Mouse) (e Event) `json:"-"` // Called before handling key. If you consume the event, Changed will not be called.
	// contains filtered or unexported fields
}

Field is a single line text field. The cursor is always visible, and determines which part of the text is shown.

func (*Field) Draw

func (ui *Field) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Field) FirstFocus

func (ui *Field) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Field) Focus

func (ui *Field) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Field) Key

func (ui *Field) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Field) Layout

func (ui *Field) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Field) Mark

func (ui *Field) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Field) Mouse

func (ui *Field) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Field) Print

func (ui *Field) Print(self *Kid, indent int)

type Grid

type Grid struct {
	Kids       []*Kid      // Holds UIs in the grid, per row.
	Columns    int         // Number of clumns.
	Valign     []Valign    // Vertical alignment per column.
	Halign     []Halign    // Horizontal alignment per column.
	Padding    []Space     // Padding in lowDPI pixels per column.
	Width      int         // -1 means full width, 0 means automatic width, >0 means exactly that many lowDPI pixels.
	Background *draw.Image `json:"-"` // Background color.
	// contains filtered or unexported fields
}

Grid lays out other UIs in a table-like grid.

func (*Grid) Draw

func (ui *Grid) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Grid) FirstFocus

func (ui *Grid) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Grid) Focus

func (ui *Grid) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Grid) Key

func (ui *Grid) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Grid) Layout

func (ui *Grid) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Grid) Mark

func (ui *Grid) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Grid) Mouse

func (ui *Grid) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Grid) Print

func (ui *Grid) Print(self *Kid, indent int)

type Gridfit

type Gridfit byte

Gridfit is the layout strategy for a Gridlist.

const (
	FitNormal Gridfit = iota // FitNormal lays out over full available width.
	FitSlim                  // FitSlim lays out only as much as needed.
)

type Gridlist

type Gridlist struct {
	Header   *Gridrow   // Optional header to display at the the top.
	Rows     []*Gridrow // Rows, each holds whether it is selected.
	Multiple bool       // Whether multiple rows can be selected at a time.
	Halign   []Halign   // Horizontal alignment for the values.
	Padding  Space      // Padding for each cell, in lowDPI pixels.
	Striped  bool       // If set, odd cells have a slightly contrasting background color.
	Fit      Gridfit    // Layout strategy, how much space columns receive.
	Font     *draw.Font `json:"-"` // Used for drawing text.

	Changed func(index int) (e Event)               `json:"-"` // Called after the selection changed. -1 is multiple may have changed.
	Click   func(index int, m draw.Mouse) (e Event) `json:"-"` // Called on click at given index. If consumed, processing stops.
	Keys    func(k rune, m draw.Mouse) (e Event)    `json:"-"` // Called before handling a key event. If consumed, processing stops.
	// contains filtered or unexported fields
}

Gridlist is a table-like list of selectable values. Currently each cell in each row is drawn as a single-line string. Column widths can be adjusted by dragging the separator in the header.

Keys:

arrow up, move selection up
arrow down, move selection down
home, move selection to first element
end, move selection to last element
cmd-n, clear selection
cmd-a, select all
cmd-c, copy selected rows, as tab-separated values

func (*Gridlist) Draw

func (ui *Gridlist) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Gridlist) FirstFocus

func (ui *Gridlist) FirstFocus(dui *DUI, self *Kid) (warp *image.Point)

func (*Gridlist) Focus

func (ui *Gridlist) Focus(dui *DUI, self *Kid, o UI) (warp *image.Point)

func (*Gridlist) Key

func (ui *Gridlist) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Gridlist) Layout

func (ui *Gridlist) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Gridlist) Mark

func (ui *Gridlist) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Gridlist) Mouse

func (ui *Gridlist) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Gridlist) Print

func (ui *Gridlist) Print(self *Kid, indent int)

func (*Gridlist) Selected

func (ui *Gridlist) Selected() (indices []int)

type Gridrow

type Gridrow struct {
	Selected bool        // If currently selected.
	Values   []string    // Values displayed in the row.
	Value    interface{} `json:"-"` // Auxiliary data.
}

Gridrow is used for each row in a Gridlist.

type Halign

type Halign byte

Halign represents horizontal align of elements in a Grid.

const (
	HalignLeft Halign = iota // Align to the left by default, for example in a grid.
	HalignMiddle
	HalignRight
)

type Icon

type Icon struct {
	Rune rune       // Codepoint to draw.
	Font *draw.Font `json:"-"` // Font to draw in. If nil, nothing is typically drawn.
}

Icon is a single codepoint in the given font. Typically for an "icon font" like fontawesome.

type Image

type Image struct {
	Image *draw.Image `json:"-"`
}

Image shows an image. Currently always in its original size.

func (*Image) Draw

func (ui *Image) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Image) FirstFocus

func (ui *Image) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Image) Focus

func (ui *Image) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Image) Key

func (ui *Image) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Image) Layout

func (ui *Image) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Image) Mark

func (ui *Image) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Image) Mouse

func (ui *Image) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Image) Print

func (ui *Image) Print(self *Kid, indent int)

type Input

type Input struct {
	Type  InputType
	Mouse draw.Mouse
	Key   rune
	Func  func()
	Error error
}

Input is an input event that is typically passed into DUI through Input().

type InputType

type InputType byte

InputType presents the type of an input event.

const (
	InputMouse  InputType = iota // Mouse movement and/or button changes.
	InputKey                     // Key typed.
	InputFunc                    // Call the function.
	InputResize                  // window was resized, reattach; does not have/need a field in Input.
	InputError                   // An error occurred that may be recovered from.
)

type Kid

type Kid struct {
	UI     UI              // UI this state is about.
	R      image.Rectangle // Location and size within this UI.
	Draw   State           // Whether UI or its children need a draw.
	Layout State           // Whether UI or its children need a layout.
	ID     string          // For (re)storing settings with ReadSettings and WriteSettings. If empty, no settings for the UI will be (re)stored.
}

Kid holds a UI and its layout/draw state.

func NewKids

func NewKids(uis ...UI) []*Kid

NewKids turns UIs into Kids containing those UIs. Useful for creating UI trees.

func (*Kid) Mark

func (k *Kid) Mark(o UI, forLayout bool) (marked bool)

Mark checks if o is its UI, and if so marks it as needing a layout or draw (forLayout false).

func (*Kid) MarshalJSON

func (k *Kid) MarshalJSON() ([]byte, error)

MarshalJSON writes k with an additional field Type containing the name of the UI type.

type Label

type Label struct {
	Text  string           // Text to draw, wrapped at glyph boundary.
	Font  *draw.Font       `json:"-"` // For drawing text.
	Click func() (e Event) `json:"-"` // Called on button1 click.
	// contains filtered or unexported fields
}

Label draws multiline text in a single font.:

Keys:

cmd-c, copy text
\n, like button1 click, calls the Click function

func (*Label) Draw

func (ui *Label) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Label) FirstFocus

func (ui *Label) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Label) Focus

func (ui *Label) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Label) Key

func (ui *Label) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Label) Layout

func (ui *Label) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Label) Mark

func (ui *Label) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Label) Mouse

func (ui *Label) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Label) Print

func (ui *Label) Print(self *Kid, indent int)

type List

type List struct {
	Values   []*ListValue                            // Values, each contains whether it is selected.
	Multiple bool                                    // Whether multiple values can be selected at a time.
	Font     *draw.Font                              `json:"-"` // For drawing the values.
	Changed  func(index int) (e Event)               `json:"-"` // Called after the selection changes, index being the new single selected item if >= 0.
	Click    func(index int, m draw.Mouse) (e Event) `json:"-"` // Called on click at value at index, before handling selection change. If consumed, processing stops.
	Keys     func(k rune, m draw.Mouse) (e Event)    `json:"-"` // Called on key. If consumed, processing stops.
	// contains filtered or unexported fields
}

List shows values, allowing for single or multiple selection, with callbacks when the selection changes.

Keys:

arrow up, move selection up
arrow down, move selection down
home, move selection to first element
end, move selection to last element

func (*List) Draw

func (ui *List) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*List) FirstFocus

func (ui *List) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*List) Focus

func (ui *List) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*List) Key

func (ui *List) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*List) Layout

func (ui *List) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*List) Mark

func (ui *List) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*List) Mouse

func (ui *List) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*List) Print

func (ui *List) Print(self *Kid, indent int)

func (*List) Selected

func (ui *List) Selected() (indices []int)

Selected returns the indices of the selected values.

func (*List) Unselect

func (ui *List) Unselect(indices []int)

Unselect indices, or if indices is nil, unselects all.

type ListValue

type ListValue struct {
	Text     string      // Text shown, as single line.
	Value    interface{} `json:"-"` // Auxiliary data.
	Selected bool
}

ListValue is used for values in a List.

type Middle

type Middle struct {
	Kid        *Kid        // Contains the UI displayed in the middle.
	Background *draw.Image `json:"-"` // For background color.
	// contains filtered or unexported fields
}

Middle lays out a single child in the middle of the available space, both vertically and horizontally.

func NewMiddle

func NewMiddle(padding Space, ui UI) *Middle

NewMiddle returns a Middle set up with padding around the sides.

func (*Middle) Draw

func (ui *Middle) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Middle) FirstFocus

func (ui *Middle) FirstFocus(dui *DUI, self *Kid) (warp *image.Point)

func (*Middle) Focus

func (ui *Middle) Focus(dui *DUI, self *Kid, o UI) (warp *image.Point)

func (*Middle) Key

func (ui *Middle) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Middle) Layout

func (ui *Middle) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Middle) Mark

func (ui *Middle) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Middle) Mouse

func (ui *Middle) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Middle) Print

func (ui *Middle) Print(self *Kid, indent int)

type Pick

type Pick struct {
	Pick func(sizeAvail image.Point) UI `json:"-"` // Called during layout, must return a non-nil UI.
	// contains filtered or unexported fields
}

Pick makes it possible to create responsive UI layouts. You must provide the function Pick that is called at layout with the available window space. It must return the current UI to show. You could return different layouts depending on the size of the window.

func (*Pick) Draw

func (ui *Pick) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Pick) FirstFocus

func (ui *Pick) FirstFocus(dui *DUI, self *Kid) (warp *image.Point)

func (*Pick) Focus

func (ui *Pick) Focus(dui *DUI, self *Kid, o UI) (warp *image.Point)

func (*Pick) Key

func (ui *Pick) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Pick) Layout

func (ui *Pick) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Pick) Mark

func (ui *Pick) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Pick) Mouse

func (ui *Pick) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Pick) Print

func (ui *Pick) Print(self *Kid, indent int)

type Place

type Place struct {
	// Place is called during layout. It must configure Kids, and set self.R, based on sizeAvail.
	Place      func(self *Kid, sizeAvail image.Point) `json:"-"`
	Kids       []*Kid                                 // Kids to draw, set by the Place function.
	Background *draw.Image                            `json:"-"` // For background color.
	// contains filtered or unexported fields
}

Place contains other UIs it can position absolute, possibly on top of each other.

func (*Place) Draw

func (ui *Place) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Place) FirstFocus

func (ui *Place) FirstFocus(dui *DUI, self *Kid) (warp *image.Point)

func (*Place) Focus

func (ui *Place) Focus(dui *DUI, self *Kid, o UI) (warp *image.Point)

func (*Place) Key

func (ui *Place) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Place) Layout

func (ui *Place) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Place) Mark

func (ui *Place) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Place) Mouse

func (ui *Place) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Place) Print

func (ui *Place) Print(self *Kid, indent int)

type Radiobutton

type Radiobutton struct {
	Selected bool
	Disabled bool             // If set, cannot be selected.
	Group    RadiobuttonGroup // Other radiobuttons as part of this group. If a radiobutton is selected, others in the group are unselected.
	Font     *draw.Font       `json:"-"` // Used only to determine size of radiobutton to draw.
	Value    interface{}      `json:"-"` // Auxiliary data.

	// Called for the radiobutton in the group that is newly selected, not for the other radiobuttons in the group.
	// Not called if selected with Select().
	Changed func(v interface{}) (e Event) `json:"-"`
	// contains filtered or unexported fields
}

Radiobutton is typically part of a group of radiobuttons, with exactly one of them selected. Labels are not part of the radiobutton itself.

func (*Radiobutton) Draw

func (ui *Radiobutton) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Radiobutton) FirstFocus

func (ui *Radiobutton) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Radiobutton) Focus

func (ui *Radiobutton) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Radiobutton) Key

func (ui *Radiobutton) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Radiobutton) Layout

func (ui *Radiobutton) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Radiobutton) Mark

func (ui *Radiobutton) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Radiobutton) Mouse

func (ui *Radiobutton) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Radiobutton) Print

func (ui *Radiobutton) Print(self *Kid, indent int)

func (*Radiobutton) Select

func (ui *Radiobutton) Select(dui *DUI)

Select this radiobutton from the group, unselecting the previously selected radiobutton. Select does not call Changed.

type RadiobuttonGroup

type RadiobuttonGroup []*Radiobutton

RadiobuttonGroup is the group of all possible radiobuttons of which only one can be selected.

func (RadiobuttonGroup) Selected

func (g RadiobuttonGroup) Selected() *Radiobutton

Selected returns the currently selected radiobutton in the group.

type ReaderReaderAt

type ReaderReaderAt interface {
	io.Reader
	io.ReaderAt
}

type Result

type Result struct {
	Hit      UI           // the UI where the event ended up
	Consumed bool         // whether event was consumed, and should not be further handled by upper UI's
	Warp     *image.Point // if set, mouse will warp to location
}

Result holds the effects of a mouse/key event, as implement by UIs.

func KidsKey

func KidsKey(dui *DUI, self *Kid, kids []*Kid, key rune, m draw.Mouse, orig image.Point) (r Result)

KidsKey delivers key event key to the UI at m. Orig is passed so UIs can calculate locations to warp the mouse to.

func KidsMouse

func KidsMouse(dui *DUI, self *Kid, kids []*Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

KidsMouse delivers mouse event m to the UI at origM (often the same, but not in case button is held pressed). Mouse positions are always relative to their own origin. Orig is passed so UIs can calculate locations to warp the mouse to.

type Scroll

type Scroll struct {
	Kid    Kid
	Height int // < 0 means full height, 0 means as much as necessary, >0 means exactly that many lowdpi pixels
	// contains filtered or unexported fields
}

Scroll shows a part of its single child, typically a box, and lets you scroll the content.

func NewScroll

func NewScroll(ui UI) *Scroll

NewScroll returns a full-height scroll bar containing ui.

func (*Scroll) Draw

func (ui *Scroll) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Scroll) FirstFocus

func (ui *Scroll) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Scroll) Focus

func (ui *Scroll) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Scroll) Key

func (ui *Scroll) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Scroll) Layout

func (ui *Scroll) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Scroll) Mark

func (ui *Scroll) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Scroll) Mouse

func (ui *Scroll) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Scroll) Print

func (ui *Scroll) Print(self *Kid, indent int)

type SeekReaderAt

type SeekReaderAt interface {
	io.Seeker
	io.ReaderAt
}

SeekReaderAt is used as a source for edits. The seeker is used to determine file size, the readerAt for reading.

type Space

type Space struct {
	Top, Right, Bottom, Left int
}

Space represents the padding or margin on a UI element. In duit functions, these are typically in lowDPI pixels.

func NSpace

func NSpace(n int, space Space) []Space

NSpace is a convenience function to create N identical spaces.

func NSpaceXY

func NSpaceXY(n, x, y int) []Space

NSpaceXY is a convenience function to create N identical SpaceXY's.

func SpacePt

func SpacePt(p image.Point) Space

SpacePt returns a space with p.X for left/right and p.Y for top/bottom.

func SpaceXY

func SpaceXY(x, y int) Space

SpaceXY returns a space with x for left/right and y for top/bottom.

func (Space) Dx

func (s Space) Dx() int

Dx returns the total horizontal space.

func (Space) Dy

func (s Space) Dy() int

Dy returns the total vertical space.

func (Space) Inset

func (s Space) Inset(r image.Rectangle) image.Rectangle

Inset returns a rectangle that is r inset with this space.

func (Space) Mul

func (s Space) Mul(n int) Space

Mul returns a this space multiplied by n.

func (Space) Size

func (s Space) Size() image.Point

Size returns the total horizontal and vertical size.

func (Space) Topleft

func (s Space) Topleft() image.Point

Topleft returns a point containing the topleft space.

type Split

type Split struct {
	// Space between the UIs, in lowDPI pixels.
	// If >0, users can drag the gutter. Manual changes are automatically stored and restored on next load, if you set ID in the containing Kid.
	Gutter int

	// Optional, must return the division of available space. Sum of dims must be dim.
	Split func(dim int) (dims []int) `json:"-"`

	Vertical   bool
	Kids       []*Kid      // Hold UIs shown in split.
	Background *draw.Image `json:"-"` // For background color.
	// contains filtered or unexported fields
}

Split is a horizontal or vertical split of the available space, with 1 or more UIs.

func (*Split) Dimensions

func (ui *Split) Dimensions(dui *DUI, dims []int) []int

func (*Split) Draw

func (ui *Split) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

func (*Split) FirstFocus

func (ui *Split) FirstFocus(dui *DUI, self *Kid) *image.Point

func (*Split) Focus

func (ui *Split) Focus(dui *DUI, self *Kid, o UI) *image.Point

func (*Split) Key

func (ui *Split) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

func (*Split) Layout

func (ui *Split) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Split) Mark

func (ui *Split) Mark(self *Kid, o UI, forLayout bool) (marked bool)

func (*Split) Mouse

func (ui *Split) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

func (*Split) Print

func (ui *Split) Print(self *Kid, indent int)

type State

type State byte

State represents the layout/draw state of the UI of a Kid.

type Tabs

type Tabs struct {
	Buttongroup *Buttongroup // Shown at top of Tabs.
	UIs         []UI         // UIs selected by Buttongroup, must have same number of elements as buttons in Buttongroup.
	Box
}

Tabs has a Buttongroup and displays only the active selected UI.

func (*Tabs) Layout

func (ui *Tabs) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

func (*Tabs) Print

func (ui *Tabs) Print(self *Kid, indent int)

type UI

type UI interface {
	// Layout asks the UI to layout itself and its children in `availSize`.
	// Layout must check `self.Layout` and `force`.
	// If force is set, it must layout itself and its kids, and pass on force.
	// Else, if self.Layout is DirtyKid, it only needs to call Layout on its kids (common for layout UIs).
	// The UI can lay itself out beyond size.Y, not beyond size.X.
	// size.Y is the amount of screen real estate that will still be visible.
	// Layout must update self.Draw if it needs to be drawn after.
	// Layout must update self.R with a image.ZP-origin image.Rectangle of the size it allocated.
	Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool)

	// Draw asks the UI to draw itself on `img`, with `orig` as offset and `m` as the current mouse (for hover states)
	// as self.Kid indicates, and pass further Draw calls on to its children as necessary.
	// If `force` is set, the UI must draw itself, overriding self.Draw.
	Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool)

	// Mouse tells the UI about mouse movement over it.
	// Layout UI's are in charge of passing these mouse events to their children.
	// `self.Layout` and `self.Draw` can be updated if the mouse event resulted in UIs needing relayout/redraw.
	// Again it's layout UI's responsibility to propagate requests from self.Layout and self.Draw to its parent.
	// `m` is the current mouse state, relative to this UIs zero point.
	// `origM` is the mouse of first button down change, to facilitate tracking dragging. If no button is down, origM is the same as m.
	// `orig` is the origin location of this UI. If you want to warp the mouse, add the origin to the UI-relative point.
	// Result is used to communicate results of the event back to the top.
	Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result)

	// Key tells the UI about a key press over it.
	// Like in Mouse, `self.Layout` and `self.Draw` can be updated.
	// `k` is the key pressed. There are no key down/up events, only keys typed.
	// See the Key-constants in the draw library for use special keys like the arrow keys,
	// function keys and combinations with the cmd key.
	// `m` is the mouse location at the time of the key, relative to this UIs zero point.
	// `orig` is the origin location of this UI. If you want to warp the mouse, add the origin to the UI-relative point.
	Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result)

	// FirstFocus returns where the focus should go next when "tab" is hit, if anything.
	FirstFocus(dui *DUI, self *Kid) (warp *image.Point)

	// Focus returns the focus-point for `ui`.
	Focus(dui *DUI, self *Kid, o UI) (warp *image.Point)

	// Mark looks for ui (itself or children), marks it as dirty for layout or draw (forLayout),
	// and propagates whether it marked anything back to the caller.
	Mark(self *Kid, o UI, forLayout bool) (marked bool)

	// Print line about ui that includes r and is prefixed with indent spaces, following by a Print on each child.
	Print(self *Kid, indent int)
}

UI is the interface implemented by a user interface element. For example Button, List, Grid, Scroll. UIs must be able to layout themselves, draw themselves, handle mouse events, key presses, deal with focus requests. UIs also help with propagating UI state and logging. For contain UIs (those that mostly just contain other UIs), many of these functions can be implemented by a single call to the corresponding Kids*-function.

func CenterUI

func CenterUI(space Space, ui UI) UI

CenterUI returns a UI that shows ui horizontally centered, with space as padding.

type Valign

type Valign byte

Valign represents vertical align of elements in a Grid, or in a Box.

const (
	ValignMiddle Valign = iota // Align vertically in the middle by default, for example in a box (line) or grid.
	ValignTop
	ValignBottom
)

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL