![]() |
Lysa UI
0.0
Lysa UI —UI components for the Lysa Engine
|
Lysa UI is organized as a set of C++23 modules (.ixx interfaces paired with .cpp implementations) that live in the lysa::ui namespace. The single top-level module lysa.ui re-exports every public widget type and serves as the only import needed by application code.
The library sits on top of the Lysa Engine and relies on the engine context (lysa::ctx()) for rendering, resource management, and event dispatch.
lysa::ui::WindowManager is the root of every UI setup. It attaches to a RenderingWindow and owns a list of virtual lysa::ui::Window objects. The WindowManager:
RenderingWindow it draws into.Style, font and font scale inherited by every Window that does not set its own. The default font is embedded in the library, so no font resource has to be loaded to display text.PROCESS and INPUT events to drive per-frame rendering and input routing.Window.Window resizing via configurable border deltas.drawFrame() and onInput() for explicit frame-by-frame control when needed.lysa::ui::Widget is the base of every UI element. Key responsibilities:
| Concern | Details |
|---|---|
| Identity | Inherits UniqueResource; each widget has a unique id used for event subscription |
| Layout | Rect for position and size; Alignment enum controls placement within the parent |
| Hierarchy | add<T>() / create<T>() templates; remove() / removeAll() |
| Appearance | setDrawBackground(), setTransparency(), setPadding(), setHBorder(), setVBorder() |
| Input | Virtual eventMouseDown, eventMouseUp, eventMouseMove, eventKeyDown, eventKeyUp, eventTextInput hooks |
| Focus | setFocus(), isFocused(), allowFocus flag; tab-order traversal via setNextFocus() |
| State | show() / isVisible(), enable() / isEnabled(), setFreezed() / isFreezed() |
| User data | setUserData() / getUserData() and setGroupIndex() / getGroupIndex() for application tagging |
| Attachment | isAttached(), and getWindow(), getStyle(), getWindowManager() returning the objects inherited from the tree the widget is attached to |
Window has its own hierarchy for the dialogs displayed in a dedicated window :
Menu, TabBar, TabContainer, FoldableContainer, TreeView, ListBox, ScrollContainer, ScrollBar, CheckBox, Slider, ColorSlider, SpinBox, SpinButtons, ColorPicker, ColorPickerButton, DropDownList, RichTextArea and DialogBox are composite widgets : they build their own children (rows, marks, scroll bars, grips, highlights). Their sub-widget resource strings are assigned by the style through a setResources() call in StyleBase::addResource(), so the application never has to call it.
lysa::ui::Window is a virtual panel displayed inside a RenderingWindow. It holds a root lysa::ui::Widget that covers its entire client area and acts as the parent for all widgets in that window. Key features:
setWidget() sets the root widget and its resource string.create<T>() / add<T>() template helpers delegate to the root widget.setStyle() installs a style for this window only; getStyle() returns it, or the WindowManager default style when none was set. setStyle(nullptr) goes back to that default.setFont() / setFontScale() override the WindowManager defaults for this window only.setResizeableBorders() controls which edges the user can drag to resize the window.show(), hide(), setVisible()) take effect at the start of the next frame.onAttach, onDetach, onShow, onHide, onResize, onMove, onKeyDown, onKeyUp, onMouseDown, onMouseUp, onMouseMove, onGotFocus, onLostFocus are intended to be overridden by application-level subclasses.lysa::ui::Style is the abstract drawing backend. It defines three responsibilities:
| Method | Description |
|---|---|
draw() | Renders a widget before (when=true) or after (when=false) its children are drawn |
resize() | Adjusts a widget's size rectangle to style-specific constraints |
addResource() | Parses a resource string and attaches a UIResource to a widget |
lysa::ui::Style itself holds everything the styles have in common : the name-value option map, the color palette and the widget sizes read from it. lysa::ui::StyleBase adds everything that does not depend on the look : the Widget::Type dispatching of the three methods above, the resource strings handed to the composite widgets, and the drawing of the widgets whose appearance comes from their content (texts, icons, tree view branches, grid lines, color slider & wheel, marks, arrows).
Two looks are built on top of it :
| Style | Style::create() name | Look |
|---|---|---|
| lysa::ui::StyleClassic | vector | Classic 3D beveled vector look |
| lysa::ui::StyleMaterial | material | Material Design inspired flat look |
Both read the three appearance modes of a lysa::ui::StyleResource, each giving them its own meaning:
| Mode | StyleClassic | StyleMaterial |
|---|---|---|
FLAT | No 3D effect | Plain surface, no outline |
RAISED | Beveled raised appearance | Filled (elevated) container |
LOWERED | Beveled lowered (sunken) appearance | Outlined container |
Style options are set via setOption() / getOption(). Every style reads the colors color_focus, color_selected, color_highlight, color_foreground_up, color_foreground_down, color_button, color_shadow_dark, color_shadow_bright, color_cursor, color_tree_lines, color_grid_lines and color_text, and the sizes size_scroll_bar, size_radio_button, size_check_box, size_tree_indent, size_sort_arrow and size_knob. StyleMaterial adds color_primary, color_on_primary, color_surface, color_surface_container, color_outline, color_outline_variant, size_corner_radius and size_corner_radius_small.
Style::getTextColor() returns the default color of the texts, read from the color_text option : the color belongs to the style, not to the Window. A Text or a RichTextArea that was not given an explicit color picks it up when it is attached to a tree.
The WindowManager instantiates the default StyleClassic and hands it out with getDefaultStyle(). Another built-in style is installed with window->setStyle(lysa::ui::Style::create("material")). A custom style is created by subclassing StyleBase (to keep the widget dispatching) or Style (to redo it) and passing an instance to Window::setStyle().
All widget events are dispatched through the engine's EventManager. Widgets fire events using UIEvent signal-name constants:
| Signal | Payload struct | Description |
|---|---|---|
UIEvent::OnClick | UIEventClick | Button or ToggleButton clicked |
UIEvent::OnClick | UIEventLink | [url] link of a RichTextArea clicked; target holds the tag value or the link text |
UIEvent::OnStateChange | UIEventState | CheckWidget state changed |
UIEvent::OnValueChange | UIEventValue | ValueSelect value changed |
UIEvent::OnRangeChange | UIEventRange | ValueSelect range changed |
UIEvent::OnColorChange | UIEventColor | Color of a ColorWheel, ColorPicker or ColorPickerButton changed |
UIEvent::OnUserDataChange | UIEvent | User data attached to a widget changed |
UIEvent::OnTextChange | UIEventText | Text widget content changed |
UIEvent::OnTextInput | UIEventText | User text input in a TextEdit |
UIEvent::OnKeyDown | UIEventKeyb | Key pressed with widget focused |
UIEvent::OnKeyUp | UIEventKeyb | Key released with widget focused |
UIEvent::OnMouseDown | UIEventMouseButton | Mouse button pressed over widget |
UIEvent::OnMouseUp | UIEventMouseButton | Mouse button released over widget |
UIEvent::OnMouseMove | UIEventMouseMove | Mouse moved over widget |
UIEvent::OnMouseLeave | UIEvent | Mouse cursor left the widget |
UIEvent::OnGotFocus | UIEvent | Widget acquired keyboard focus |
UIEvent::OnLostFocus | UIEvent | Widget lost keyboard focus |
UIEvent::OnShow | UIEvent | Widget became visible |
UIEvent::OnHide | UIEvent | Widget became hidden |
UIEvent::OnEnable | UIEvent | Widget enabled |
UIEvent::OnDisable | UIEvent | Widget disabled |
UIEvent::OnResize | UIEvent | Window resized |
UIEvent::OnMove | UIEvent | Window moved |
UIEvent::OnInsertItem | UIEventItem | Item inserted into a List / ListBox |
UIEvent::OnRemoveItem | UIEventItem | Item removed from a List / ListBox |
UIEvent::OnSelectItem | UIEventItem | Selected item changed in a List / ListBox / DropDownList / TreeView / Menu / TabBar / TabContainer |
UIEvent::OnExpandItem | UIEventExpand | Item of a TreeView expanded or collapsed, or content of a FoldableContainer folded or unfolded |
UIEvent::OnDoubleClickItem | UIEventItem | Item of a TreeView double-clicked |
Subscribe using lysa::ctx().events.subscribe(UIEvent::OnClick, widget->id, handler). Events are queued and delivered on the next frame; the payload is read with std::any_cast<UIEventItem>(event.payload).
When the engine is compiled with LUA_BINDINGS=ON, every widget type inherits from LuaScript and exposes its full public API to Lua via LuaBridge. All UIEvent signal constants and Alignment, CheckWidget::State, Line::LineStyle, ScrollBar::Type, Slider::Type, ProgressBar::Orientation, ProgressBar::Display, Arrow::Orientation, TreeView::SelectionMode, TabPlacement, ColorPicker::Component, ColorPicker::Mode, SVGBounds and Window::ResizeableBorder enums are available in the lysa.ui Lua namespace. Every widget type (ListBox, ProgressBar, ScrollBox, Menu, TabBar, TabContainer, Slider, SpinBox, SpinButtons, ColorWheel, ColorPicker, ColorPickerButton, DropDownList, IconImage, IconSVG, RichTextArea, and their variants) is fully accessible with the same create_* factory pattern, in snake_case : create_tab_container(), create_radio_button(), create_check_box(), create_color_picker(), create_drop_down_list(), create_icon_svg(), create_rich_text_area(), …
Style is exposed too, with set_option(), get_option() and the read-only text_color property; it is reached through WindowManager.default_style or Window.style.
The complete Lua surface is described in Lua API.