137 lines
4.7 KiB
Markdown
137 lines
4.7 KiB
Markdown
# UI
|
|
|
|
## Overview
|
|
|
|
This is a small Jai library to do some basic immediate mode UI. It has a variety of widgets
|
|
and writing new ones should be relatively easy, if you follow the existing ones.
|
|
|
|
As opposed to a UI library you might find on the Internet, like Dear ImGui, this library is
|
|
sadly not platform independent. It is relatively coupled with OpenGL, so you in order to
|
|
integrate it to a project, you will need to also provide a GL context with GLFW, RGFW, SDL,
|
|
or the like.
|
|
|
|
## Architecture
|
|
|
|
The main concept behind this UI system is that as you call the ui_* functions like ui_begin/ui_end, etc.
|
|
You are implicitly building the tree that represents the UI hierarchy. That is the magic of an
|
|
immediate mode API. You take advantage of the fact that functions are called in a stack across time.
|
|
Which is implicitly a Tree. At the end of the frame you give this tree to the rendering function, which
|
|
recurses through it pre-order, drawing the panels, icons, text, etc., in the correct order.
|
|
|
|
Using this architecutre as the base places some undesirable constraints on the further design of the
|
|
system though. For example, the most useful part of this library is the auto-layout algorithm. It's not
|
|
super sophisticated, but it works. And in order to do this auto layout you need two basic pieces of
|
|
information. Where are the ui elements and how big are they. Properties that the layout algorithm can
|
|
itself change!
|
|
|
|
So, the easiest solution to this problem is to separate everything into distinct phases (or passes).
|
|
In the first pass you are declaring the tree structure of the UI as you go in a bottom up fashion,
|
|
recording the initial positions and sizes. Then after you're done you can traverse the tree from the
|
|
top down adjusting the layout. This is only possible because at this point in time you have all the
|
|
information including nodes' siblings, the size they are, they size they'd like to be, etc.
|
|
|
|
## Public API
|
|
|
|
Some functions have a begin/end pair, becuase you necesarily have to wait until things finish happening
|
|
inside of them to be able to calculate their initial size, etc. Other functions don't have this begin/end
|
|
pair, because they don't allow children, they're a leaf node, and they don't need further information to finish
|
|
their calculations.
|
|
|
|
```
|
|
ui_new_frame :: ()
|
|
```
|
|
|
|
This has to be called every frame, before calling any other UI function.
|
|
|
|
```
|
|
ui_begin :: (s: string)
|
|
```
|
|
|
|
This begins a panel, which other widgets can go inside of.
|
|
|
|
```
|
|
ui_end :: ()
|
|
```
|
|
|
|
Has to be called after a ui_begin to finish its UI Node.
|
|
|
|
```
|
|
ui_text_input :: (s: string, font_colour := Vector4.{1, 1, 1, 1})
|
|
```
|
|
|
|
This starts a text editor!
|
|
|
|
```
|
|
ui_begin_container :: (s: string, gradient := false, colour_left := Vector4.{}, colour_right := Vector4.{}, max_x: s32 = -1, max_y: s32 = -1, flags: ContainerFlags = 0)
|
|
```
|
|
|
|
Similar to a normal ui_begin, but you can have this one inside the main panel, recursively.
|
|
Very useful to change the layout direction (Left To Right vs Top to Bottom)
|
|
|
|
```
|
|
ui_end_container :: ()
|
|
```
|
|
|
|
Must be called after a ui_begin_container, to calculate sizing and finish the node in the UI Tree.
|
|
|
|
```
|
|
ui_icon :: (s: string, texture: *Texture, size: Vector2)
|
|
```
|
|
|
|
Renders an OpenGL texture.
|
|
|
|
```
|
|
ui_label :: (s: string = "", colour := Vector4.{1.0, 1.0, 1.0, 1.0})
|
|
```
|
|
|
|
Renders text.
|
|
|
|
```
|
|
ui_spacing :: (s: string)
|
|
```
|
|
|
|
Forces spacing between elements. The auto layout algorithm tries to maximize the space between
|
|
the node before the spacing and after the spacing, taking into account the max size of the parent
|
|
container.
|
|
|
|
```
|
|
ui_button :: (s: string = "", icon_texture: *Texture = null, font_colour := Vector4.{1, 1, 1, 1}, draw_frame := true) -> bool
|
|
```
|
|
|
|
Renders a panel with optional text in it and an optional OpenGL texture. When clicked it returns true.
|
|
Very useful to run conditional code like:
|
|
|
|
if ui_button(...) {
|
|
do_something();
|
|
}
|
|
|
|
```
|
|
ui_font_icon :: (font: *Font, s: string, size: Vector2, colour: Vector4 = .{1, 1, 1, 1})
|
|
```
|
|
|
|
Renders an icon stored in a font. you have to figure out what the name of the glyph is and pray
|
|
FreeType can find it. You can look up the names using a tool like [FontDrop!](https://fontdrop.info/).
|
|
|
|
```
|
|
ui_progress_bar :: (s: string = "", progress: float, size: Vector2, background := Vector4.{1, 1, 1, 1}, foreground := Vector4.{1, 1, 1, 1})
|
|
```
|
|
|
|
Renders a progress bar.
|
|
|
|
```
|
|
ui_end_frame :: ()
|
|
```
|
|
|
|
Must be called after finishing the UI Tree. You must not call any UI Tree building functions (any of the previous ones)
|
|
after this call and before a new ui_begin_frame.
|
|
|
|
```
|
|
ui_render :: ()
|
|
```
|
|
|
|
Renders the UI with OpenGL.
|
|
|
|
## Example
|
|
|
|
Please look at main.jai for an example.
|