Pages
Above is result of hello_world.sh in examples folder
Here its code
source ../src/lib.sh
init_screen
layout.create_from_screen Layout
rect.new rect1
rect.get_layout rect1 layout_inside_rect
label.new label1 "Hello world!"
label.set_text_align label1 center center
rect.draw rect1 Layout
label.draw label1 layout_inside_rect
buffer.flush
sleep 10
exit_screenLets break it down
source ../src/lib.sh - First, we import library, you should source a single entry file, located at src - lib.sh
then when you are ready to enter into rendering mode, you call init_screen which set up screen alternative mode, buffer properties, subscribes to terminal events, for example reszie or exit event when you press ctrl+c. Also the last line - exit_screens clears all changes that were made during init_screen
To render component, you need to know where you want to render it. For that purpose layout is created, which will be described in later pages, but for now you need to create a layout, that will take full width and height of terminal.
layout.create_from_screen Layout, where Layout is name of layout, you can have many layouts with different names.
rect.new rect1 - creates new rectangle component, with name of rect1
rect.get_layout rect1 layout_inside_rect - creates layout, inside rect1 component. This layout will take size of rect, excluding its borders.
label.new label1 "Hello world!"
label.set_text_align label1 center center
First line creates a new label component with name of label1 and text "Hello world!".
On second line we say, that label1 component should show its text in horizontal and vertical center. Supported values are start center end.
rect.draw rect1 Layout
label.draw label1 layout_inside_rect
Theese two lines renders corresponding components in given layouts. Here, rect1 is rendered in Layout that was created with full screen size, meaning that rect will take full width and height, and label within layout_inside_rect, which size is rect1 layout excluding borders.
Note that if we change render order to
label.draw label1 layout_inside_rect
rect.draw rect1 Layout
The label wont be drawn. Why? Because layout layout_inside_rect handled by rect1 and recalculated every draw. That means that this layout size is not computed yet and equals to zeros.
And last line
buffer.flush
This library works in immediate mode, which means that all components needs to be drawn every frame. After we draw all components, that we wanted to be show in screen, we say to buffer, that it can finally show our bellowed frame and print it to screen.
We take our script written above and slightly modify it.
Code of hello_world_increment.sh below
source ../src/lib.sh
init_screen
layout.create_from_screen Layout
rect.new rect1
rect.get_layout rect1 layout_inside_rect
label.new label1 "Hello world!"
label.set_text_align label1 center center
i=0
while [ 1 ]; do
rect.draw rect1 Layout
i=$((i + 1))
label.set_text label1 "Hello world!: $i"
label.draw label1 layout_inside_rect
buffer.flush
sleep 1
done
exit_screenNow we created a rendering loop, in which all components are drawn.
After modifying our i variable we need to say label1, that text is changed.
For that we call label.set_text label1 "Hello world!: $i" which replaces text of label1.
Then we flush our frame, and go to beginning of loop.
Lets say you want to process user input events.
You can use built-in bash function read, but default command blocks the loop and waits until enter is pressed. Also, because frame isn't redrawn, resize events also won't be processed, which can lead to unwanted behaviour.
Instead you can use read with args, so it reads a single key and waits for a short period of time
while true; do
if read -rsn1 -t 0.005 key; then
# Handle key button
fi
# Render frame
doneNote that you need to filter(or process) its output. If, for example, you blindly bind key to label and user presses right arrow, key will be equal to [0m[c, which breaks ui if rendered as single character
Example of unfiltered input in examples/preview.sh

