Crate fyrox::gui

source ·
Expand description

Extendable, retained mode, graphics API agnostic UI library with lots (35+) of built-in widgets, HiDPI support, rich layout system and many more.

§Basic Concepts

FyroxUI is quite complex UI library and before using it, you should understand basic concepts of it. Especially, if you’re got used to immediate-mode UIs.

§Stateful

*Stateful UI means that we can create and destroy widgets when we need to, it is the opposite approach of immediate-mode or stateless UIs when you don’t have long-lasting state for your widgets (usually stateless UI hold its state only for one or few frames).

Stateful UI is much more powerful and flexible, it allows you to have complex layout system without having to create hacks to create complex layout as you’d do in immediate-mode UIs. It is also much faster in terms of performance. Stateful UI is a must for complex user interfaces that requires rich layout and high performance.

§Node-based architecture

Every user interface could be represented as a set of small blocks that have hierarchical bonding between each other. For example a button could be represented using two parts: a background and a foreground. Usually the background is just a simple rectangle (either a vector or bitmap), and a foreground is a text. The text (the foreground widget) is a child object of the rectangle (the background widget). These two widgets forms another, more complex widget that we call button.

Such approach allows us to modify the look of the button as we wish, we can create a button with image background, or with any vector image, or even other widgets. The foreground can be anything too, it can also contain its own complex hierarchy, like a pair of an icon with a text and so on.

§Composition

Every widget in the engine uses composition to build more complex widgets. All widgets (and respective builders) contains Widget instance inside, it provides basic functionality the widget such as layout information, hierarchy, default foreground and background brushes (their usage depends on derived widget), render and layout transform and so on.

§Message passing

The engine uses message passing mechanism for UI logic. What does that mean? Let’s see at the button from the previous section and imagine we want to change its text. To do that we need to explicitly “tell” the button’s text widget to change its content to something new. This is done by sending a message to the widget.

There is no “classic” callbacks to handle various types of messages, which may come from widgets. Instead, you should write your own message dispatcher where you’ll handle all messages. Why so? At first - decoupling, in this case business logic is decoupled from the UI. You just receive messages one-by-one and do specific logic. The next reason is that any callback would require context capturing which could be somewhat restrictive - since you need to share context with the UI, it would force you to wrap it in Rc<RefCell<..>>/Arc<Mutex<..>>.

§Message routing strategies

Message passing mechanism works in pair with various routing strategies that allows you to define how the message will “travel” across the tree of nodes.

  1. Bubble - a message starts its way from a widget and goes up on hierarchy until it reaches the root node of the hierarchy. Nodes that lies outside that path won’t receive the message. This is the most important message routing strategy, that is used for every node by default.
  2. Direct - a message passed directly to every node that are capable to handle it. There is actual routing in this case. Direct routing is used in rare cases when you need to catch a message outside its normal “bubble” route. It is off by default for every widget, but can be enabled on per-widget instance basis.

§Widgets Overview

The following subsections explains how to use every widget built into FyroxUI. We will order them by primary function to help introduce them to new users.

§Containers

The Container widgets primary purpose is to contain other widgets. They are mostly used as a tool to layout the UI in visually different ways.

  • crate::stack_panel::StackPanel: The Stack Panel arranges widgets in a linear fashion, either vertically or horizontally depending on how it’s setup.
  • crate::wrap_panel::WrapPanel: The Wrap Panel arranges widgets in a linear fashion but if it overflows the widgets are continued adjacent to the first line. Can arrange widgets either vertically or horizontally depending on how it’s setup.
  • crate::grid::Grid: The Grid arranges widgets into rows and columns with given size constraints.
  • crate::canvas::Canvas: The Canvas arranges widgets at their desired positions; it has infinite size and does not restrict their children widgets position and size.
  • crate::window::Window: The Window holds other widgets in a panel that can be configured at setup to be move-able, expanded and contracted via user input, exited, and have a displayed label. The window has a title bar to assist with these features.
  • crate::messagebox::MessageBox: The Message Box is a Window that has been streamlined to show standard confirmation/information dialogues, for example, closing a document with unsaved changes. It has a title, some text, and a fixed set of buttons (Yes, No, Cancel in different combinations).
  • crate::menu::Menu: The Menu is a root container for Menu Items, an example could be a menu strip with File, Edit, View, etc items.
  • crate::popup::Popup: The Popup is a panel that locks input to its content while it is open. A simple example of it could be a context menu.
  • crate::scroll_viewer::ScrollViewer: The ScrollViewer is a wrapper for Scroll Panel that adds two scroll bars to it.
  • crate::scroll_panel::ScrollPanel: The Scroll Panel is a panel that allows you apply some offset to children widgets. It is used to create “scrollable” area in conjunction with the Scroll Viewer.
  • crate::expander::Expander: The Expander handles hiding and showing multiple panels of widgets in an according style UI element. Multiple panels can be shown or hidden at any time based on user input.
  • crate::tab_control::TabControl: The Tab Control handles hiding several panels of widgets, only showing the one that the user has selected.
  • crate::dock::DockingManager: The Docking manager allows you to dock windows and hold them in-place.
  • crate::tree::Tree: The Tree allows you to create views for hierarchical data.
  • crate::screen::Screen: The Screen widgets always has its bounds match the current screen size thus making it possible to create widget hierarchy that always fits the screen bounds.

§Visual

The Visual widgets primary purpose is to provide the user feedback generally without the user directly interacting with them.

  • crate::text::Text: The Text widget is used to display a string to the user.
  • crate::image::Image: The Image widget is used to display a pixel image to the user.
  • crate::vector_image::VectorImage: The Vector Image is used to render vector instructions as a graphical element.
  • crate::rect::RectEditor: The Rect allows you to specify numeric values for X, Y, Width, and Height of a rectangle.
  • crate::progress_bar::ProgressBar: The Progress Bar shows a bar whose fill state can be adjusted to indicate visually how full something is, for example how close to 100% is a loading process.
  • crate::decorator::Decorator: The Decorator is used to style any widget. It has support for different styles depending on various events like mouse hover or click.
  • crate::border::Border: The Border widget is used in conjunction with the Decorator widget to provide configurable boarders to any widget for styling purposes.

§Controls

Control widgets primary purpose is to provide users with intractable UI elements to control some aspect of the program.

  • crate::border::Border: The Button provides a press-able control that can contain other UI elements, for example a Text or Image Widget.
  • crate::check_box::CheckBox: The Check Box is a toggle-able control that can contain other UI elements, for example a Text or Image Widget.
  • crate::text_box::TextBox: The Text Box is a control that allows the editing of text.
  • crate::scroll_bar::ScrollBar: The Scroll Bar provides a scroll bar like control that can be used on it’s own as a data input or with certain other widgets to provide content scrolling capabilities.
  • crate::numeric::NumericUpDown: The Numeric Field provides the ability to adjust a number via increment and decrement buttons or direct input. The number can be constrained to remain inside a specific range or have a specific step.
  • crate::range::RangeEditor: The Range allows the user to edit a numeric range - specify its begin and end values.
  • crate::list_view::ListView: The List View provides a control where users can select from a list of items.
  • crate::dropdown_list::DropdownList: The Drop-down List is a control which shows the currently selected item and provides a drop-down list to select an item.
  • crate::file_browser::FileBrowser: The File Browser is a tree view of the file system allowing the user to select a file or folder.
  • crate::curve::CurveEditor: The CurveEditor allows editing parametric curves - adding points, and setting up transitions (constant, linear, cubic) between them.
  • crate::inspector::Inspector: The Inspector automatically creates and handles the input of UI elements based on a populated Inspector Context given to it allowing the user to adjust values of a variety of models without manually creating UI’s for each type.

§Examples

A simple usage example could be the following code:

use fyrox_ui::{
    button::{ButtonBuilder, ButtonMessage},
    core::algebra::Vector2,
    widget::WidgetBuilder,
    UserInterface,
};

// Create the UI first.
let mut ui = UserInterface::new(Vector2::new(1024.0, 768.0));

// Add some widgets.
let button = ButtonBuilder::new(WidgetBuilder::new())
    .with_text("Click Me!")
    .build(&mut ui.build_ctx());

// Poll the messages coming from the widgets and react to them.
while let Some(message) = ui.poll_message() {
    if let Some(ButtonMessage::Click) = message.data() {
        if message.destination() == button {
            println!("The button was clicked!");
        }
    }
}

Important: This example does not include any drawing or OS event processing! It is because this crate is OS- and GAPI-agnostic and do not create native OS windows and cannot draw anything on screen. For more specific examples, please see examples of the crate.

Modules§

  • Animation blending state machine is a node that takes multiple animations from an animation player and mixes them in arbitrary way into one animation. See AnimationBlendingStateMachine docs for more info.
  • Animation player is a node that contains multiple animations. It updates and plays all the animations. See AnimationPlayer docs for more info.
  • A widget that shows numeric value as a set of individual bits allowing switching separate bits.
  • The Border widget provides a stylized, static border around its child widget. See Border docs for more info and usage examples.
  • Brush defines a way to fill an arbitrary surface. See Brush docs for more info and usage examples.
  • Defines a clickable widget with arbitrary content. See Button dos for more info and examples.
  • Canvas widget allows its children to have an arbitrary position on an imaginable infinite plane, it also gives the children constraints of infinite size, which forces them to take all the desired size. See Canvas docs for more info and usage examples.
  • Checkbox is a UI widget that have three states - Checked, Unchecked and Undefined. In most cases it is used only with two values which fits in bool type. Third, undefined, state is used for specific situations when your data have such state. See CheckBox docs for more info and usage examples.
  • A special container that is able to create widgets by their type UUID.
  • A wrapper for node pool record that allows to define custom visit method to have full control over instantiation process at deserialization.
  • A visual element that is used to highlight standard states of interactive widgets. It has “pressed”, “hover”, “selected”, “normal” appearances. See Decorator docs for more info and usage examples.
  • Docking manager allows you to dock windows and hold them in-place.
  • Drop-down list. This is control which shows currently selected item and provides drop-down list to select its current item. It is build using composition with standard list view.
  • A simple widget that opens a popup when clicked. It could be used to create drop down menus that consolidates content of a group.
  • Expander is a simple container that has a header and collapsible/expandable content zone. It is used to create collapsible regions with headers. See Expander docs for more info and usage examples.
  • File browser is a tree view over file system. It allows to select file or folder.
  • Grid widget is able to position children widgets into a grid of specifically sized rows and columns. See Grid doc for more info and usage examples.
  • Image widget is a rectangle with a texture, it is used draw custom bitmaps. See Image docs for more info and usage examples.
  • Inspector is a widget, that allows you to generate visual representation for internal fields an arbitrary structure or enumeration recursively. It’s primary usage is provide unified and simple way of introspection. See Inspector docs for more info and usage examples.
  • A set of editors for hot keys and key bindings. See HotKeyEditor and KeyBindingEditor widget’s docs for more info and usage examples.
  • List view is used to display lists with arbitrary items. It supports single-selection and by default, it stacks the items vertically.
  • User Interface loader.
  • Menu and MenuItem widgets are used to create menu chains like standard File, Edit, etc. menus. See doc of respective widget for more info and usage examples.
  • Message and events module contains all possible widget messages and OS events. See UiMessage docs for more info and examples.
  • Message box is a window that is used to show standard confirmation/information dialogues, for example, closing a document with unsaved changes. It has a title, some text, and a fixed set of buttons (Yes, No, Cancel in different combinations). See MessageBox docs for more info and usage examples.
  • A widget, that handles keyboard navigation on its descendant widgets using Tab key. See NavigationLayer docs for more info and usage examples.
  • A widget that handles numbers of any machine type. See NumericUpDown docs for more info and usage examples.
  • Path editor is a simple widget that has a text box, that shows the current path and a “…” button, that opens a file selector. See PathEditor docs for more info and usage examples.
  • Popup is used to display other widgets in floating panel, that could lock input in self bounds. See Popup docs for more info and usage examples.
  • Progress bar is used to show a bar that fills in from left to right according to the progress value. It is used to show progress for long actions. See ProgressBar widget docs for more info and usage examples.
  • Range editor is used to display and edit closed ranges like 0..1. See Range docs for more info and usage examples.
  • Rect editor widget is used to show and edit Rect values. It shows four numeric fields: two for top left corner of a rect, two for its size. See RectEditor docs for more info and usage examples.
  • Screen is a widget that always has the size of the screen of the UI in which it is used. See docs for Screen for more info and usage examples.
  • Scroll bar is used to represent a value on a finite range. It has a thumb that shows the current value on on the bar. See ScrollBar docs for more info and usage examples.
  • Scroll panel widget is used to arrange its children widgets, so they can be offset by a certain amount of units from top-left corner. It is used to provide basic scrolling functionality. See ScrollPanel docs for more info and usage examples.
  • Scroll viewer is a scrollable region with two scroll bars for each axis. It is used to wrap a content of unknown size to ensure that all of it will be accessible in a parent widget bounds. See ScrollViewer docs for more info and usage examples.
  • Search bar widget is a text box with a “clear text” button. It is used as an input field for search functionality. Keep in mind, that it does not provide any built-in searching functionality by itself! See SearchBar docs for more info and usage examples.
  • Stack panel orders its children widgets linearly; either top-to-bottom or left-to-right. See StackPanel docs for more info and usage examples.
  • The Tab Control handles the visibility of several tabs, only showing a single tab that the user has selected via the tab header buttons. See docs for TabControl widget for more info and usage examples.
  • Text is a simple widget that allows you to print text on screen. See Text docs for more info and examples.
  • TextBox is a text widget that allows you to edit text and create specialized input fields. See TextBox docs for more info and usage examples.
  • Tree widget allows you to create views for hierarchical data. See Tree docs for more info and usage examples.
  • UUID editor is used to show an arbitrary UUID and give an ability to generate a new value. See UuidEditor docs for more info and usage examples.
  • Vector image is used to create images, that consists from a fixed set of basic primitives, such as lines, triangles, rectangles, etc. It could be used to create simple images that can be infinitely scaled without aliasing issues. See VectorImage docs for more info and usage examples.
  • Base widget for every other widget in the crate. It contains layout-specific info, parent-child relations visibility, various transforms, drag’n’drop-related data, etc. See Widget docs for more info.
  • The Window widget provides a standard window that can contain another widget. See Window docs for more info and usage examples.
  • Wrap panel is used to stack children widgets either in vertical or horizontal direction with overflow. See WrapPanel docs for more info and usage examples.

Macros§

  • Defines a new message constructor for a enum variant. It is widely used in this crate to create shortcuts to create messages. Why is it needed anyway? Just to reduce boilerplate code as much as possible.
  • Implements Deref<Target = Widget> + DerefMut for your widget. It is used to reduce boilerplate code and make it less bug-prone.

Structs§

  • Build context is used to decouple explicit UI state modification. Its main use is in the various widget builders. Internally, it is just a mutable reference to the UI state. UI can be modified (add nodes, clone, link, etc.) via build context. This is needed to explicitly highlight that it used to modify the UI state. It is not recommended to use BuildContext for mutable access to widgets at runtime! Use message passing to modify widgets at runtime, otherwise you will easily break invariant (inner state) of widgets. The only place where it’s allowed to directly mutate widget’s state is at build stage (inside build method of your widget builder).
  • Reference counted handle to a widget. It is used to automatically destroy the widget it points to when the reference counter reaches zero. It’s main usage in the library is to store handles to context menus, that could be shared across multiple widgets.
  • Describes the thickness of a frame around a rectangle (for all four sides). It is primarily used to define margins and to define stroke thickness for various widgets.
  • UI node is a type-agnostic wrapper for any widget type. Internally, it is just a trait object that provides common widget interface. Its main use is to reduce code bloat (no need to type Box<dyn Control> everywhere, just UiNode) and to provide some useful methods such as type casting, component querying, etc. You could also be interested in Control docs, since it contains all the interesting stuff and detailed description for each method.
  • A set of switches that allows you to disable a particular step of UI update pipeline.

Enums§

  • Horizontal alignment defines relative location and size of the widget to its parent widget along horizontal (X) axis.
  • Orientation of something.
  • Horizontal alignment defines relative location and size of the widget to its parent widget along vertical (Y) axis.

Constants§

Traits§

  • Base trait for all UI widgets. It has auto-impl and you don’t need to implement it manually. Your widget must implement Clone and Control traits for impl to be generated for you, also your widget must not contain any references (due to 'static lifetime requirement).
  • Trait for all UI controls in library.