September 25, 2024
09 Hello Controls
With the substantial increase in content in modern applications, the performance of the user interface has become crucial. Tellusim Controls system manages all user interfaces, offering excellent performance alongside a comprehensive set of extendable and customizable controls (widgets). Tellusim Canvas layer provides a rendering backend, while the Controls layer handles the UI logic. All features of the Canvas layer, such as cross-platform support, high performance, resolution-independent rendering, and customization, are fully integrated into the Controls layer.
Controls require a Canvas instance since it is responsible for rendering. The ControlRoot acts as the primary control, managing the hierarchy of controls while handling resources and input. Multiple ControlRoot instances can exist within an application, for example, in multi-window applications or for 3D controls. Basic resources, including fonts and textures, can be embedded within the binary. The following code demonstrates the initialization of controls and the translation of basic events in C++:
// create root control ControlRoot root(canvas, true); // keyboard callbacks window.setKeyboardPressedCallback([&](uint32_t key, uint32_t code) { if(root) root.setKeyboardKey(translate_key(key, true), code, true); }); window.setKeyboardReleasedCallback([&](uint32_t key) { if(root) root.setKeyboardKey(translate_key(key, false), 0, false); });
Key and mouse button translation is required because controls utilize their own set of event parameters. This design allows controls to be embedded in different applications with their own events.
The controls update loop is straightforward and should be executed before Canvas::create() method:
// update controls
root.setViewport(width, height);
root.setMouse(mouse_x, mouse_y, translate_button(window.getMouseButtons()));
root.setMouseAxis(Control::AxisY, window.getMouseAxis(Window::AxisY));
while(root.update(canvas.getScale(target))) { }
// create canvas resource
if(!canvas.create(device, target)) return false;
Multiple calls to Controls::update() are necessary because resize and callback actions may take a few frames to stabilize the layout.
That concludes the required steps for initialization and rendering. We can now create the actual control widgets. The basic set of controls includes:
- ControlText for text labels and descriptions
- ControlRect for backgrounds and simple elements
- ControlGrid for all possible layouts
- ControlGroup for grouping multiple controls
- ControlPanel for static control islands
- ControlDialog for internal movable dialogs
- ControlWindow for external (platform) windows
- ControlCheck for simple toggles
- ControlCombo for variant selection
- ControlButton for simple actions
- ControlSlider for variable parameters
- ControlScroll for navigation
- ControlSplit for layout customization
- ControlArea for scrollable areas
- ControlTree for dynamic lists and trees
- ControlEdit for text and number inputs
The controls element forms a hierarchy where container controls are responsible for placement and event propagation, while leaf controls handle user events. Below is the instantiation of ControlDialog, along with custom styling that incorporates stroke and gradient effects:
// create dialog ControlDialog dialog(&root, 1, 0.0f, 8.0f); dialog.setAlign(Control::AlignCenter); dialog.setGradientStyle(GradientStyle(2.0f, Vector2f(0.0f, 1.0f), Color::magenta, Color::blue)); dialog.setStrokeStyle(StrokeStyle(2.0f, Color(0.6f, 0.5f))); dialog.setMode(CanvasElement::ModeGradient); dialog.setColor(Color::gray);
There are two types of event processing: one involves checking the control state in the main loop, while the preferred method is to assign control-specific callback handlers.
This WebGL/GPU manual example is available on GitHub and includes main Control widgets and Callback processing:
Tellusim Explorer showcases all aspects of the control system and serves as an excellent demonstration of its features:
Interface plugins are control extensions provided with full source code, enabling complete customization and modification. Below is a list of the interface plugins included in the Tellusim SDK:
- ControlTooltip for textual descriptions and resource previews
- Manipulator for editing 3D translation, rotation, and scale
- ControlElement for embedding Canvas elements with callbacks
- ControlButtonBase for customizable button widgets
- ControlSliderBase for customizable slider widgets
- ControlProgress for visualizing progress
- ControlModal for modal dialogs
- ControlPlotter for chart visualization
- ControlFont for vector text rendering
- ControlSVG for handling SVG images and interfaces
- PolyHaven for browsing and importing PolyHaven assets
- Sketchfab for browsing and importing Sketchfab assets
- ControlFlow for node-based systems
Here are a several plugins from Tellusim Emscripten SDK compiled by for WebGL (?-gles) and WebGPU:
ControlFlow editor functions as a powerful runtime environment for node-based systems, enabling users to visually create, modify, and manage intricate workflows. It is equipped with touchscreen input support and features a complete undo-redo operation stack, enhancing usability and flexibility.
ControlFont offers a vector font representation that eliminates the need for a resolution-dependent texture atlas or Signed Distance Field (SDF) calculation. It ensures pixel-perfect rendering and proper anti-aliasing, making it ideal for VR applications and 3D interfaces:
ControlSVG converts an SVG image into a dynamic control that can be easily manipulated using various user interface elements, such as ControlButtonBase and ControlSliderBase. This functionality enables developers to seamlessly integrate scalable vector graphics into their applications (Heart Demo):
Manipulator is a tool for 3D coordinate editing. It supports global and relative transformations with uniform and non-uniform scaling: