- Odin 99%
- Makefile 1%
| backend | ||
| examples | ||
| tests | ||
| button.odin | ||
| draggable.odin | ||
| helpers.odin | ||
| Makefile | ||
| odinfmt.json | ||
| raven.odin | ||
| README.md | ||
| scroll.odin | ||
| text.odin | ||
| text_editor.odin | ||
| theme.odin | ||
Raven UI Library
🚧 This project is still experimental
Raven is a minimalistic immediate-mode UI library for Raylib written in Odin.
It is a loose collection of tools, rather than a complete framework. You are encouraged to copy the source code into your project and modify and extend it as required.
Instead of a complex layout algorithm, it gives the user full control over how and where UI elements are drawn, by providing various helpers:
count: int
text := fmt.aprintf("count: %d", count, allocator = context.temp_allocator)
text_rec := raven.draw_text(text, {0, 0})
// Every draw_* procedure takes a Vector2 position and returns a Rectangle position+size.
// So every subsequent draw can simply offset its position from the previous Rectangle.
button_rec := raven.draw_button("increment", raven.pos_below(text_rec))
if raven.is_clicked(button_rec) do count += 1
Raven is backend independent. You may use SDL3, or Raylib as your rendering
backend. The default backend is Raylib. To switch the used backend, the RAVEN_BACKEND
compile flag can be used:
odin build my_project -define:RAVEN_BACKEND=sdl3
When using OLS, you may want to define a profile in ols.json to tell OLS which
backend you are using:
{
"$schema": "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json",
"profile": "sdl3",
"profiles": [
{ "name": "sdl3", "defines": { "RAVEN_BACKEND": "sdl3" } },
{ "name": "raylib", "defines": { "RAVEN_BACKEND": "raylib" } }
]
}
Features
- Text drawing and measuring, with word wrapping and Unicode support
- Buttons
- Scroll containers
- Text editor with selection, clipboard, and keyboard navigation support
- Font loading with Unicode codepoint ranges
- Theming via
raven.default_theme
Usage
Copy the library directory into your project and import it:
import "raven"
Run an example:
odin run examples/counter
See the examples directory for more examples.
Run the tests:
odin test tests/
Stateful elements
Elements with state are split into an update and a draw procedure. Call both once per frame:
raven.update_text_editor(&editor)
raven.draw_text_editor(&editor, bounds)
Custom UI elements
Custom elements work just like the built-in ones: a procedure that draws at a
position and returns a Rectangle. See examples/custom_ui_element for a complete example.
draw_my_number_selector :: proc(number: ^int, pos: raylib.Vector2) -> raylib.Rectangle {
button_theme := raven.default_theme
button_theme.button_background_color = {0, 0, 0, 255} // black
button_theme.button_hover_background_color = raylib.Color{20, 20, 20, 255}
text := fmt.aprint(number^, allocator = context.temp_allocator)
// Set a max width for the text and pad on both sides.
// This fixes the button jumping when text width changes.
text_size := raven.measure_text(text)
max_text_width :: 30
text_offset_x := (max_text_width - text_size.x) / 2
minus_rec := raven.draw_button("-", pos, theme = button_theme)
text_rec := raven.draw_text(text, raven.pos_right(minus_rec, gap = 10 + text_offset_x))
text_rec.width += text_offset_x
plus_rec := raven.draw_button("+", raven.pos_right(text_rec, gap = 10), theme = button_theme)
if raven.is_clicked(minus_rec) do number^ -= 1
if raven.is_clicked(plus_rec) do number^ += 1
return raven.combine_recs(minus_rec, text_rec, plus_rec)
}
Theming
The raven.Theme struct is a convenient way to apply styling to UI elements.
Many procedures in Raven take an optional theme argument. When omitted, it
defaults to the global raven.default_theme.
To customize the default styling of elements, mutate raven.default_theme:
raven.default_theme.font_size = 24
raven.default_theme.text_color = raylib.WHITE
To give specific elements a different look, create a new theme as required:
button_theme := raven.default_theme
button_theme.button_background_color = raylib.DARKGRAY
raven.draw_button("delete", {10, 10}, theme = button_theme)