Frame UI - Kyoril/mmo GitHub Wiki

What is Frame UI?

Frame UI is the library that is responsible for everything that has anything to do with the graphical user interface in the project. It can render text, frames with complex layouts and more. It also allows to write custom renderer classes, for example to render 3d models in frames. It completely relies on the graphics library, which makes it portable so that it should work out of the box with every implemented graphics api.

How to use it

The key component is probably the FrameManager class, defined in the header file frame_ui/frame_mgr.h. This is a static class, which has a static Get method that you can use to access it's singleton instance. Before using it, you should call the static method FrameManager::Initialize() for internal initializations and FrameManager::Destroy() afterwards for destruction (when you're done using the FrameUI library, obviously). You also need to make sure that the graphics library is properly initialized before using Frame UI. In the client, this is done in the Console class, implemented in the console.cpp file.

Loading resources

Frame UI supports loading resources from xml files. It uses the AssetRegistry class of the assets library to do so, so you need to make sure, the AssetRegistry is properly initialized before trying to load any files. Using the AssetRegistry enables a whole new set of features, like loading files from virtual files (archives), which is currently used in distributed Release builds of the client. Currently, there are three file types supported:

toc

*.toc files are simple text files which can contain empty lines, comment lines (prefixed with a '#' sign) and text lines which may not start space characters at the moment. Each text line is considered a file name relative to the AssetRegistry's root directory. When loading a toc file, all referenced files are loaded in order. A load cycle check is also performed, to prevent infinitely loading the same file over and over again, which would ultimately result in a stack overflow. A toc file may reference every of the three supported file types, so a toc file may actually reference another toc file.

lua

Lua files are script files that contain lua code. Right now, this is just a planned feature and not yet implemented. The idea is to have the ui logic be performed entirely by lua code, and that the calling library or application provide links for the ui lua context.

For example, a click on the Login button in the client will be handled in lua code, and then call a function that is provided by the client's c++ code to start the actual login process. The client will then trigger events in c++ that are again handled by lua to update the state of the ui (like disabling or hiding frames, showing new ones etc.).

xml

Xml files are actually split into two types of xml files: Style Xml and Layout Xml. Which type a xml file is, is determined by the first (root) tag of the file, which has to be either UiStyle for style xml, or UiLayout for layout xml files.

Frame UI will automatically handle these in a static instance of the StyleXmlLoader or LayoutXmlLoader class, defined in frame_ui/layout_xml_loader.h and frame_ui/style_xml_loader.h respectively.

Programmatically creating frames

If you don't want or need to use xml, you can create the ui completely in c++. To do so, have a look at the xml loader classes mentioned above and how they make use of the StyleManager and FrameManager classes to create styles and frames.

However, since FrameUI is quite complex at this point, it is not really recommended to create frames and styles directly in c++, for obvious reasons.

Using the Font class

One part that is used directly by c++ though, is the Font class, defined in frame_ui/font.h. This class, again, makes use of the AssetRegistry class in the assets library, so make sure it is initialized before using the Font class.

The font class is quite useful for rendering text without using Frames, Layout and all that stuff. For example, it is currently used by the client's Console class to render the console contents (see console.cpp of the client).

It is also really easy to use: Just create a new std::shared_pointer<Font> (also referenced as FontPtr type, defined in frame_ui/font.h) like this:

const int fontSize = 10;
const int outlineSizeInPixels = 1;

m_font = std::make_shared<Font>("name/of/fontfile.ttf", fontSize, outlineWidthInPixels);

Remember, that the filename of the ttf file is again relative to the root directory of AssetRegistry.

More about frames

Almost every element represented on the screen is a frame (base class: Frame, defined in frame_ui/frame.h). The Frame class itself only contains properties of a frame.

For most flexibility, FrameUI uses some sort of MVC (model, view, controller) model the frames. The frame would be the model in this example, containing the required data.

A style would be the view, describing how a control can be rendered.

A FrameRenderer subclass would be the controller, which uses a frame and it's style to render the contents of a frame on screen. Currently, there are three FrameRenderer classes:

FrameRenderer

This is the abstract base class for a frame renderer and thus needs to be inherited. It is defined in frame_ui/frame_renderer.h. The most important method to implement is FrameRenderer::Render(optional<Color> color = optional<Color>(), optional<Rect> clipper = optional<Rect>()).

DefaultRenderer

This is the most basic renderer class that draws a frame on screen. It works by determining a state name, depending on the frame's properties.

The default renderer uses the Enabled state as default, and the Disabled state if the frame's Frame::IsEnabled() property returns false.

The renderer then uses the frame's style and tries to find a StateImagery instance with the name of the active state. If no such StateImagery exists, it tries to use the default state name (which for this class is Enabled) and tries again. If still no such StateImagery exists, nothing is rendered at all. It's the same if the frame does not have a valid style assigned: Nothing will be rendered then.

ButtonRenderer

The ButtonRenderer works exactly the same as the DefaultRenderer, except that it sets different states. The states it sets are: Normal (default and fallback), Hovered (if Frame::IsHovered() returns true), Pushed (not yet implemented) and Disabled (again, if Frame::IsEnabled() returns false).

More about styles

A Style (frame_ui/style.h) basically consists of a unique name, a number of uniquely named, case insensitive StateImagery instances and a number of uniquely named, case insensitive ImagerySections.

ImagerySection

An ImagerySection (frame_ui/imagery_section.h) contains a number of FrameComponents that will actually draw the contents of a frame.

FrameComponent

There are multiple FrameComponent classes defined, which are: FrameComponent, ImageComponent, TextComponent and BorderComponent.

TODO: Add more details about components in here

StateImagery

A StateImagery (frame_ui/state_imagery.h) contains a number of FrameLayer instances, which are rendered in order.

FrameLayer

A FrameLayer (frame_ui/frame_layer.h) contains a number of ImagerySection references that are owned by the Style instance. When asked to render, the FrameLayer will call ImagerySection::Render(...) for every section assigned, in assignment order, to make each section redirect the call to all it's FrameComponents, to actually render them.

So, the final render call for a frame, looks something like this:

Frame::Render()
> FrameRenderer::Render()
>> StateImagery::Render()
>>> FrameLayer::Render()
>>>> ImagerySection::Render()
>>>>> FrameComponent::Render()
>>>>> FrameComponent::Render()
⚠️ **GitHub.com Fallback** ⚠️