ui.um
offers an immediate GUI library suitable both for simple game menus
and more complex applications.
struct BoxStyle
type BoxStyle* = struct {
img: image::Image
outer, inner: rect::Rect
scale: th::fu
color: uint32
}
BoxStyle
describes how a box within the GUI is styled. In this case box
can be anything, ranging from a button to a container. By default the box
is drawn using the image.Image.drawNinepatch
method. However if the image
is invalid, a rectangle with color color
is drawn.
interface Font
type Font* = interface {
draw(text: str, pos: th::Vf2, color: uint32, scale: th::fu = 1.0)
measure(test: str): th::Vf2
}
This interface is used by all elements that draw text. A font.Font
implements this interface.
struct PixelFont
type PixelFont* = struct { }
This struct implement the Font
interface using the canvas.um
pixel font.
struct Style
type Style* = struct {
// current font
ft: Font
// font scale
ftScale: th::fu
// text color
ftColor: uint32
// Positive box - i. e. unpressed button
posBox: BoxStyle
// Negative box - i. e. pressed button, text box
negBox: BoxStyle
// Used to draw containers
containerBox: BoxStyle
}
Style
is used as a global state for styling the GUI.
interface Container
type Container* = interface {
// This adds a rectangle to the container, and returns the rectangle
// which was actually added (the container can modify the rectangle).
// See individual containers for further documentation.
pushRect(r: rect::Rect): rect::Rect
getDims(): rect::Rect
}
Containers are used to layout elements or other containers.
struct Gui
type Gui* = struct {
// user context passed to layout functions
ctx: any
// the index of the current selection. TODO implement properly
selection: int
// true, if the layout is being evaluated, not drawn
isEval: bool
// contains more unexported fields
This is the main struct of any UI. Styles and containers are in a stack.
fn mk
fn mk*(r: rect::Rect, s: Style): Gui
Creates a new gui spanning r
, with style s
.
type LayoutFn
type LayoutFn* = fn(gui: ^Gui)
The layout function calls different element or container methods to create
the user interface itself. It is called in the eval
and draw
.
fn BoxStyle.draw
fn (this: ^BoxStyle) draw*(r: rect::Rect) {
Draws a rectangle using a BoxStyle
fn Gui.pushStyle
fn (this: ^Gui) pushStyle*(s: Style) {
Pushes a style onto the style stack.
fn Gui.popStyle
fn (this: ^Gui) popStyle*() {
Pops a style from the style stack.
fn Gui.getStyle
fn (this: ^Gui) getStyle*(): ^Style {
Returns a pointer to the style atop the style stack.
fn Gui.getContainer
fn (this: ^Gui) getContainer*(): Container {
Returns the container atop the container stack.
fn Gui.pushRect
fn (this: ^Gui) pushRect*(r: rect::Rect): rect::Rect {
Shortcut to this.getContainer().pushRect(r)
fn Gui.getDims
fn (this: ^Gui) getDims*(): rect::Rect {
Shortcut to this.getContainer().getDims(r)
fn Gui.dupStyle
fn (this: ^Gui) dupStyle*() {
Duplicates the current style.
fn Gui.pushContainer
fn (this: ^Gui) pushContainer*(c: Container) {
Pushes a container onto the container stack.
fn Gui.popContainer
fn (this: ^Gui) popContainer*() {
Pops a container from the container stack.
fn Gui.eval
fn (this: ^Gui) eval*(layout: LayoutFn) {
Runs the evaluation phase on layout
.
fn Gui.draw
fn (this: ^Gui) draw*(layout: LayoutFn) {
Runs the draw phase on layout
.
enum BoxGrow
type BoxGrow* = enum {
dimension
subdiv
span
pxSpan
}
The different types of "growing" the box can do.
enum BoxDirection
type BoxDir* = enum {
down
right
up
left
}
Direction in which the box will grow.
struct BoxConfig
type BoxConfig* = struct {
// dimension to grow by if `BoxGrowDimension` is used
dimension: th::fu
// number of subdivisions if `BoxGrowSubdivisions` is used
subdivisions: uint
// the grow type
growType: BoxGrow
// the grow direction
dir: BoxDir
// Specifies the values used with BoxGrowSpan nad BoxGrowPxSpan.
// If BoxGrowSpan is used, 1 equals the size of the box divided by the sum
// of all spans.
// If BoxGrowPxSpan is used, 1 equals one pixel.
span: []th::fu
// rect passed to the current container
rect: rect::Rect
// padding inserted after each element
padding: th::fu
}
Configuration of the Box
container.
struct Box
type Box* = struct {
grow: th::fu
spanCursor: int
dm: rect::Rect
cfg: BoxConfig
}
Box
is the main layout. It puts the elements next to each other,
according to the config.
If the dimensions of the rect passed to pushRect
are non zero, they will
be kept. Position is always forced.
fn Gui.box
fn (gui: ^Gui) box*(cfg: BoxConfig = {
dimension: 30,
growType: BoxGrow.dimension,
dir: BoxDir.down }) {
Adds the Box
container to the gui.
struct StackConfig
type StackConfig* = struct {
rect: rect::Rect
padding: th::fu
}
Configuration for the Stack
container.
struct Stack
type Stack* = struct {
dm: rect::Rect
cfg: StackConfig
}
The stack container puts elements on top of each other.
If a property of the rect passed to pushRect
is zero, it will be changed
to an equivalent property of the containers' dimensions (minus the padding),
else it will stay the same. This means stack can be used either to put
multiple elements/containers on top of each other, or for absolutely
positioned elements.
fn Gui.stack
fn (gui: ^Gui) stack*(cfg: StackConfig = {}) {
Adds the Stack
container to the gui.
struct ScrollAreaConfig
type ScrollAreaConfig* = struct {
rect: rect::Rect
// scroll speed. Default is 1
speed: real32
// if true, scrolling will be horizontal
horizontal: bool
}
Configuration for the scroll area.
struct ScrollArea
type ScrollArea* = struct {
dm: rect::Rect
cfg: ScrollAreaConfig
scroll: ^real32
maxScroll: real32
}
Scroll area is a container which allows the user to scroll. It acts as a stack container, but all the elements are shifted by the scroll.
fn Gui.scrollArea
fn (gui: ^Gui) scrollArea*(scroll: ^real32, maxScroll: real32, cfg: ScrollAreaConfig = {}) {
Pushes a scroll area. scroll
is both input and output value. Both scroll
and maxScroll
are in pixels.
struct ButtonConfig
type ButtonConfig* = struct {
rect: rect::Rect
}
Configuration for the button.
fn Gui.button
fn (gui: ^Gui) button*(cfg: ButtonConfig = {}): bool {
Adds a button to the gui. The button acts like a Stack
container, but it
is drawn using the pos/nexBox styles and handles clicks. If the button is
pressed and the gui is in the eval phase, the return value will be true.
struct LabelConfig
type LabelConfig* = struct {
// centers the label along the X axis, enables `stretchX`
centerX: bool
// centers the label along the Y axis, enables `stretchY`
centerY: bool
// if false, the rect passed to `pushRect` will have the width of
// the text, else it will be 0
stretchX: bool
// if false, the rect passed to `pushRect` will have the height of
// the text, else it will be 0
stretchY: bool
// forces the rectangle the label will use
rect: rect::Rect
}
fn Gui.label
fn (gui: ^Gui) label*(text: str, cfg: LabelConfig = {
Draws a label using the current font style.
fn Gui.qbutton
fn (gui: ^Gui) qbutton*(text: str, cfg: ButtonConfig = {}): bool {
Adds a button with a label to gui.
struct TextBoxConfig
type TextBoxConfig* = struct {
// force the rect of the text box
rect: rect::Rect
}
struct TextBox
type TextBox* = struct {
// index of the cursor
cursor: int
// contains other unexported rules...
fn TextBox.clear
fn (this: ^TextBox) clear*() {
Clears the textbox
fn TextBox.getBuf()
fn (this: ^TextBox) getBuf*(): str {
Get the content of the textbox.
fn TextBox.setBuf()
fn (this: ^TextBox) setBuf*(s: str) {
Get the content of the textbox.
fn Gui.textBox
fn (gui: ^Gui) textBox*(tb: ^TextBox, cfg: TextBoxConfig = {}) {
Adds a single line textbox to the gui. TODO:
- right-to-left unicode is not supported.
- no selection
- multiline
- copy paste (now implemented but in a limited way due to the lack of selection)
- common input shortcuts
- ctrl+delete / ctrl+backspace (delete word)
struct ImageConfig
type ImageConfig* = struct {
stretchX, stretchY: bool
centerX, centerY: bool
color: uint32
scale: th::Vf2
rect: rect::Rect
}
Configuration for the images element. Behaves similarly to labels.
fn Gui.image
fn (gui: ^Gui) image*(i: image::Image, cfg: ImageConfig = {
stretchX: true,
stretchY: true,
color: th::white,
scale: { 1, 1 } }) {
Draws an image.
fn getDefaultStyle
fn getDefaultStyle*(): Style {
Returns the default tophat ui style.
fn mk
fn mk*(r: rect::Rect, s: Style): Gui {
Creates a GUI instance.