RmlUi 5.0 introduces the backends concept. This is a complete refactoring of the old sample shell, replacing most of it with a multitude of backends. A backend is a combination of a renderer and a platform. The shell is now only used for common functions specific to the included samples.
This change is beneficial in several aspects:
All samples and tests have been updated to work with the backends interface, which is a very light abstraction over all the different backends.
A new GLFW backend has been added, along with the SFML and SDL platforms ported from the old samples. The old macOS shell has been removed as it used a legacy API that is no longer working on modern Apple devices. Now the samples build again on macOS using one of the windowing libraries such as GLFW or SDL. Further, an OpenGL 3 renderer has been added (#261), and also Emscripten support so RmlUi even runs in web browsers now.
See the Backends section in the readme for more details.
The <textarea> and <input type="text"> elements have been improved in several aspects.
Context::Update(). #220Context::ProcessMouseLeave() which ensures that the hovered state is removed from all elements and stops the context update from automatically hovering elements.Context::ProcessMouseMove() is called next the context update will start updating hover states again.<img> element: Fix wrong dp-scaling being applied when an image is cloned through a parent element. #310SystemInterface::ActivateKeyboard(Rml::Vector2f caret_position, float line_height).Rml::Debugger::Shutdown().font-weight property now supports numeric values. #296 (thanks @MexUK)opacity property is now also applied to font effects. #270ComputedValues.Rml::ReleaseFontResources to release unused font textures, cached glyph data, and related resources.Rml::Shutdown, or manually through the core API. #263 #265 (thanks @jack9267)select element: Fix clipping on select box.DataModelHandle::DirtyAllVariables() to mark all variables in the data model as dirty. #289 (thanks @EhWhoAmI)width and height attributes to the <svg> element. #283 (thanks @EhWhoAmI)lunasvg library be found when located in builtin tree. #282 (thanks @EhWhoAmI)FontEngineInterface::GenerateString now takes an additional argument, opacity.Support for flexible box layout. #182 #257
display: flex;
See usage examples, differences from CSS, performance tips, and all the details in the flexbox documentation.
select element:
change event even when the value of the newly selected option is the same.tabset element: Fix index parameter having no effect in ElementTabSet::SetPanel and ElementTabSet::SetTab. #237 #246 (thanks @nimble0)clip: always to force clipping to the element, see clip documentation. #235 #251 (thanks @MatthiasJFM)\ to align with CSS.clip property is now non-inherited. Users may need to update their RCSS selectors to achieve the same clipping behavior as previously when using this property.clip property, may lead to different results in some circumstances.\ instead of /.Rml::Debugger::Shutdown. This allows the debugger to be restarted on another host context. #200 #201 (thanks @Lyatus)Rml::Assert() in release mode. #209 (thanks @kinbei).clang-format. #223input.range element could result in infinite recursion. #202input.text element will no longer copy to clipboard when the selection is empty.input.checkbox) no longer require a value attribute to properly function. #214 (thanks @ZombieRaccoon)handle element resizing incorrectly when the size target has box-sizing: border-box. #215 (thanks @nimble0)inline-blocks. #199 (thanks @svenvvv).woff files would cause a crash on shutdown. #217RmlUi 4.1 is a maintenance release.
on.. attributes change. #189 (thanks @ZombieRaccoon).RmlUi 4.0 comes packed with several valuable new features as well as many fixes, as detailed below. The library has also been restructured to simplify its usage. For users coming from RmlUi 3.x, see restructuring RmlUi below for details and an upgrade guide.
RmlUi now supports a model-view-controller (MVC) approach through data bindings. This is a powerful approach for making documents respond to data changes, or in reverse, updating data based on user actions.
<div data-model="my_model">
<h2>{{title}}</h2>
<p data-if="show_text">The quick brown fox jumps over the lazy {{animal}}.</p>
<input type="text" data-value="animal"/>
</div>
Thanks to contributions from @actboy, @cloudwu, @C-Core, @Dakror, and @Omegapol; and everyone who helped with testing!
Work has started on a complete test suite for RmlUi. The tests have been separated into three projects.
Visual tests. For visually testing the layout engine in particular, with small test documents that can be easily added. Includes features for capturing and comparing tests for easily spotting differences during development. A best-effort conversion script for the CSS 2.1 tests, which includes thousands of tests, to RML/RCSS is included for testing conformance with the CSS specifications.Unit tests. To ensure smaller units of the library are working properly.Benchmarks. Benchmarking various components of the library to keep track of performance increases or regressions for future development, and find any performance hotspots that could need extra attention.auto.img and some input elements) now follow the normal CSS sizing rules. That is, padding and borders are no longer subtracted from the width and height of the element by default.input.text without affecting their height.overflow property. #116These changes may result in a differently rendered layout when upgrading to RmlUi 4.0. In particular the first two items.
width property or the left/right properties.box-sizing: border-box property in some situations.RmlUi now supports tables like in CSS, with some differences and enhancements. RCSS supports flexible sizing of rows and columns (as if using the CSS fr unit in grid layout). See the tables documentation for details.
<table>
<tr>
<td>Name</td>
<td colspan="2">Items</td>
<td>Age</td>
</tr>
<tr>
<td>Gimli</td>
<td>Helmet</td>
<td>Axe</td>
<td>139 years</td>
</tr>
</table>
Use the RCSS display property to enable table formatting. See the style sheet rules in the tables documentation to use the common HTML tags.
border-radius property is now supported in RmlUi for drawing rounded backgrounds and borders.word-break RCSS property.box-sizing RCSS property.caret-color RCSS property.vw and vh. #162 (thanks @Dakror).We now support @media rules for dynamically or programmatically changing active styles. #169 (thanks @Dakror).
See the media queries documentation for usage details and supported media features.
resolution feature to toggle styles and sprites based on DPI.resolution property.@spritesheet rules, making it easy to eg. define high DPI versions of sprites.<img> elements now scale according to the targeted DPI.<img> elements now automatically update when sprites or DPI changes.<lottie> element #134 (thanks @diamondhat).<svg> element.<label> element for associating a caption with an input element.Element::QuerySelector, Element::QuerySelectorAll, and Element::Closest. #164 (thanks @Dakror).tab-index: auto property can now be set on the <body> element to enable tabbing back to the document.<select> elements now react to changes in the value attribute.<p example=""Quoted text""/>. #154 (thanks @actboy168).display property to inline-block, thus it is now possible to customize the display property.<progress> element now supports the max attribute. Changing its fill-image property now actually updates the image.Context::IsMouseInteracting() to determine whether the mouse cursor hovers or otherwise interacts with documents. #124Context::ProcessMouse...() functions to determine whether the mouse is interacting with documents.Context::Process...() was wrong.Improved Lua plugin in several aspects.
databinding sample for demonstrating data bindings.lottie sample for demonstrating Lottie animations with the Lottie plugin.svg sample for demonstrating the SVG plugin.datagrid in sample projects has now been replaced with data bindings. This includes the treeview sample and the high scores document in the invader sample. Tutorials have not been updated.luainvader sample now demonstrate data bindings combined with Lua scripts.Rml::GetTextureSourceList() function to list all image sources loaded in all documents. #131ElementDocument::ReloadStyleSheet() function to reload styles without affecting the document tree. #159 #171 (thanks @Lyatus and @Dakror)CUSTOM_CONFIGURATION CMake option. #110 (thanks @rokups).unsigned int and uint64_t to Variant. #166 #176 (thanks @Omegapol and @Dakror).text-decoration would not be rendered. #119.Rml::Shutdown(). #133transition: all ...; property would not parse correctly.RmlUi has been restructured to simplify its usage. This involves breaking changes but should benefit everyone using the library in the future. See discussion in #58.
Controls plugin is now gone. But fear not! It has been merged into the Core project.Rml::Core and Rml::Controls namespaces have been removed, their contents are now located directly in the Rml namespace.Controls public header files have been moved to <RmlUi/Core/Elements/...>.Controls source files and private header files have been moved to Source/Core/Elements/....Debugger plugin remains as before at the same location and same namespace Rml::Debugger.The Lua plugins have been changed to reflect the above changes.
RmlCoreLua and RmlControlsLua have been merged into a single library RmlLua.<RmlUi/Lua/...>.Rml::Lua::Initialise() located in <RmlUi/Lua/Lua.h>.RMLUI_.Rml::Controls::Initialise(), this is no longer needed.<RmlUi/Controls.h> with <RmlUi/Core.h> unless it is already included, or include individual header files.<RmlUi/Controls/...> to <RmlUi/Core/Elements/...>.Rml::Core with Rml.Rml::Controls with Rml.namespace Rml { namespace Core { ... } } and namespace Rml { namespace Controls { ... } }. Replace with namespace Rml { ... }.RmlControls library.<RmlUi/Lua.h> or individual header files in <RmlUi/Lua/...>.Rml::Lua::Initialise(). Previously this was Rml::Core::Lua::Interpreter::Initialise() and Rml::Controls::Lua::RegisterTypes(...).RmlLua, remove RmlCoreLua and RmlControlsLua.WidgetSlider classes to avoid duplicate names in Core and Controls.TransformPrimitive.h by moving utility functions that should only be used internally to an internal header file.datagrid element and related functionality has been deprecated in favor of data bindings and RCSS tables.<progressbar> tag name has been deprecated in favor of <progress>. For now they work identically, but usage of <progressbar> will raise a warning, expect future removal of this tag.{{ and }} inside RML documents is now reserved for usage with data bindings.data- are now reserved for RmlUi.BaseXMLParser class has some minor interface changes.tab and panel should now have their display property set in the RCSS document, use display: inline-block for the same behavior as before.Element::GetIntrinsicDimensions() now additionally takes an intrinsic ratio parameter.fill-image property should now be applied to the <progress> element instead of its inner <fill> element.ElementDocument::LoadScript is now changed to handle internal and external scripts separately. #144DecoratorInstancerInterface and then submitted to the Decorator.select element improvementsselect element as appropriate. #91An effort has been made for header files to include what they use, and nothing else. This effort has measurably improved compile times, especially when not using precompiled headers.
This change also makes it easier to include only parts of the library headers in the user application for improved compile times. That is, instead of including the whole core library using #include <RmlUi/Core.h>, one can specify which ones are needed such as #include <RmlUi/Core/Element.h>.
The library now makes use of CMake's precompiled header support (requires CMake 3.16 or higher), which can optionally be disabled. In Visual Studio, compilation times are improved by almost 50% when enabled.
style attribute no longer requires a semi-colon ; after the final property.F8 key to toggle the RmlUi debugger on all platforms.-Wall -Wextra and on MSVC with /W4.Rml::Core::ReleaseCompiledGeometries() #84.white-space: nowrap no longer disables horizontal scrollbars on overflow #94.font-effect property is changed #98.Keyword properties can now be animated. Keywords are always interpolated in discrete steps, and normally applied half-way to the next keyframe. The single exception to this rule is for the visibility property. As in the CSS specifications, this property always applies the visible keyword during transition when present either in the previous or next keyframe.
Thus, the following can produce a fade-out animation, removing visibility of the element at animation end (thanks to @uniquejack for the example).
@keyframes fadeout {
from {
opacity: 1;
}
to {
opacity: 0;
visibility: hidden;
}
}
.fadeout {
animation: 1.2s cubic-in fadeout;
}
A new progressbar element is introduced for visually displaying progress or relative values. The element can take the following attributes.
value. Number [0, 1]. The fraction of the progress bar that is filled where 1 means completely filled.direction. Determines the direction in which the filled part expands. One of:
top | right (default) | bottom | left | clockwise | counter-clockwisestart-edge. Only applies to 'clockwise' or 'counter-clockwise' directions. Defines which edge the
circle should start expanding from. Possible values:
top (default) | right | bottom | leftThe element is only available with the RmlControls library.
Styling
The progressbar generates a non-dom fill element beneath it which can be used to style the filled part of the bar. The fill element can use normal properties such as background-color, border, and decorator to style it, or use the new fill-image-property to set an image which will be clipped according to the progress bar's value.
The fill-image property is the only way to style circular progress bars (clockwise and counter-clockwise directions). The fill element is still available but it will always be fixed in size independent of the value attribute.
New RCSS property
fill-image. String, non-inherited. Must be the name of a sprite or the path to an image.Examples
The following RCSS styles three different progress bars.
@spritesheet progress_bars
{
src: my_progress_bars.tga;
progress: 103px 267px 80px 34px;
progress-fill-l: 110px 302px 6px 34px;
progress-fill-c: 140px 302px 6px 34px;
progress-fill-r: 170px 302px 6px 34px;
gauge: 0px 271px 100px 86px;
gauge-fill: 0px 356px 100px 86px;
}
.progress_horizontal {
decorator: image( progress );
width: 80px;
height: 34px;
}
.progress_horizontal fill {
decorator: tiled-horizontal( progress-fill-l, progress-fill-c, progress-fill-r );
margin: 0 7px;
/* padding ensures that the decorator has a minimum width when the value is zero */
padding-left: 14px;
}
.progress_vertical {
width: 30px;
height: 80px;
background-color: #E3E4E1;
border: 4px #A90909;
}
.progress_vertical fill {
border: 3px #4D9137;
background-color: #7AE857;
}
.gauge {
decorator: image( gauge );
width: 100px;
height: 86px;
}
.gauge fill {
fill-image: gauge-fill;
}
Now, they can be used in RML as follows.
<progressbar class="progress_horizontal" value="0.75"/>
<progressbar class="progress_vertical" direction="top" value="0.6"/>
<progressbar class="gauge" direction="clockwise" start-edge="bottom" value="0.3"/>
Two new font effects have been added.
Glow effect
Renders a blurred outline around the text.
The glow effect is declared as:
font-effect: glow( <width-outline> <width-blur> <offset-x> <offset-y> <color> );
Both the outline pass and the subsequent blur pass can be controlled independently. Additionally, an offset can be applied which makes the effect suitable for generating drop shadows as well.
Blur effect
Renders a Gaussian blurred copy of the text.
The blur effect is declared as:
font-effect: blur( <width> <color> );
Note that, the blur effect will not replace the original text. To only show the blurred version of the text, set the color property of the original text to transparent.
Example usage
/* Declares a glow effect. */
h1
{
font-effect: glow( 3px #ee9 );
}
/* The glow effect can also create nice looking shadows. */
p.glow_shadow
{
color: #ed5;
font-effect: glow(2px 4px 2px 3px #644);
}
/* Renders a blurred version of the text, hides the original text. */
h1
{
color: transparent;
font-effect: blur(3px #ed5);
}
See the demo sample for additional usage examples and results.
New CMake option added.
DISABLE_RTTI_AND_EXCEPTIONS will try to configure the compiler to disable RTTI language support and exceptions. All internal use of RTTI (eg. dynamic_cast) will then be replaced by a custom solution. If set, users of the library should then #define RMLUI_USE_CUSTOM_RTTI before including the library.RmlUi 3.0 is the biggest change yet, featuring a substantial amount of new features and bug fixes. One of the main efforts in RmlUi 3.0 has been on improving the performance of the library. Users should see a noticable performance increase when upgrading.
One of the main efforts in RmlUi 3.0 has been on improving the performance of the library. Some noteable changes include:
All of these changes, in addition to many smaller optimizations, results in a more than 25x measured performance increase for creation and destruction of a large number of elements. A benchmark is included with the samples.
The RCSS at-rule @spritesheet can be used to declare a sprite sheet. A sprite sheet consists of a single image and multiple sprites each specifying a region of the image. Sprites can in turn be used in decorators.
A sprite sheet can be declared in RCSS as in the following example.
@spritesheet theme
{
src: invader.tga;
title-bar-l: 147px 0px 82px 85px;
title-bar-c: 229px 0px 1px 85px;
title-bar-r: 231px 0px 15px 85px;
icon-invader: 179px 152px 51px 39px;
icon-game: 230px 152px 51px 39px;
icon-score: 434px 152px 51px 39px;
icon-help: 128px 152px 51px 39px;
}
The first property src provides the filename of the image for the sprite sheet. Every other property specifies a sprite as <name>: <rectangle>. A sprite's name applies globally to all included style sheets in a given document, and must be unique. A rectangle is declared as x y width height, each of which must be in px units. Here, x and y refers to the position in the image with the origin placed at the top-left corner, and width and height extends the rectangle right and down.
The sprite name can be used in decorators, such as:
decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
This creates a tiled decorator where the title-bar-l and title-bar-r sprites occupies the left and right parts of the element at their native size, while title-bar-c occupies the center and is stretched horizontally as the element is stretched.
The new RCSS decorator property replaces the old decorator declarations in libRocket. A decorator is declared by the name of the decorator type and its properties in parenthesis. Some examples follow.
/* declares an image decorater by a sprite name */
decorator: image( icon-invader );
/* declares a tiled-box decorater by several sprites */
decorator: tiled-box(
window-tl, window-t, window-tr,
window-l, window-c, window-r,
window-bl, window-b, window-br
);
/* declares an image decorator by the url of an image */
decorator: image( invader.tga );
The decorator property follows the normal cascading rules, is non-inherited, and has the default value none which specifies no decorator on the element. The decorator looks for a sprite with the same name first. If none exists, then it treats it as a file name for an image. Decorators can now be set on the element's style, although we recommend declaring them in style sheets for performance reasons.
Furthermore, multiple decorators can be specified on any element by a comma-separated list of decorators.
/* declares two decorators on the same element, the first will be rendered on top of the latter */
decorator: image( icon-invader ), tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
When creating a custom decorator, you can provide a shorthand property named decorator which will be used to parse the text inside the parenthesis of the property declaration. This allows specifying the decorator with inline properties as in the above examples.
Note: This part is experimental. If it turns out there are very few use-cases for this feature, it may be removed in the future. Feedback is welcome.
The @decorator at-rule in RCSS can be used to declare a decorator when the shorthand syntax given above is not sufficient. It is best served with an example, we use the custom starfield decorator type from the invaders sample. In the style sheet, we can populate it with properties as follows.
@decorator stars : starfield {
num-layers: 5;
top-colour: #fffc;
bottom-colour: #fff3;
top-speed: 80.0;
bottom-speed: 20.0;
top-density: 8;
bottom-density: 20;
}
And then use it in a decorator.
decorator: stars;
Note the lack of parenthesis which means it is a decorator name and not a type with shorthand properties declared.
The new ninepatch decorator splits a sprite into a 3x3 grid of patches. The corners of the ninepatch are rendered at their native size, while the inner patches are stretched so that the whole element is filled. In a sense, it can be considered a simplified and more performant version of the tiled-box decorator.
The decorator is specified by two sprites, defining an outer and inner rectangle:
@spritesheet my-button {
src: button.png;
button-outer: 247px 0px 159px 45px;
button-inner: 259px 19px 135px 1px;
}
The inner rectangle defines the parts of the sprite that will be stretched when the element is resized.
The ninepatch decorator is applied as follows:
decorator: ninepatch( button-outer, button-inner );
The two sprites must be located in the same sprite sheet. Only sprites are supported by the ninepatch decorator, image urls cannot be used.
Furthermore, the ninepatch decorator can have the rendered size of its edges specified manually.
decorator: ninepatch( button-outer, button-inner, 19px 12px 25px 12px );
The edge sizes are specified in the common top-right-bottom-left box order. The box shorthands are also available, e.g. a single value will be replicated to all. Percent and numbers can also be used, they will scale relative to the native size of the given edge multiplied by the current dp ratio. Thus, setting
decorator: ninepatch( button-outer, button-inner, 1.0 );
is a simple approach to scale the decorators with higher dp ratios. For crisper graphics, increase the sprite sheet's pixel size at the edges and lower the rendered edge size number correspondingly.
A gradient decorator has been implemented with support for horizontal and vertical color gradients (thanks to @viciious). Example usage:
decorator: gradient( direction start-color stop-color );
direction: horizontal|vertical;
start-color: #ff00ff;
stop-color: #00ff00;
The orientation of each tile in the tiled decorators, image, tiled-horizontal, tiled-vertical, and tiled-box, can be rotated and flipped (thanks to @viciious). The new keywords are:
none, flip-horizontal, flip-vertical, rotate-180
Example usage:
decorator: tiled-horizontal( header-l, header-c, header-l flip-horizontal );
The image decorator now supports fit modes and alignment for scaling and positioning the image within its current element.
The full RCSS specification for the image decorator is now
decorator: image( <src> <orientation> <fit> <align-x> <align-y> );
where
<src>: image source url or sprite name<orientation>: none (default) | flip-horizontal | flip-vertical | rotate-180<fit>: fill (default) | contain | cover | scale-none | scale-down<align-x>: left | center (default) | right | <length-percentage><align-y>: top | center (default) | bottom | <length-percentage>Values must be specified in the given order, any unspecified properties will be left at their default values. See the 'demo' sample for usage examples.
The new RCSS font-effect property replaces the old font-effect declarations in libRocket. A font-effect is declared similar to a decorator, by the name of the font-effect type and its properties in parenthesis. Some examples follow.
/* declares an outline font-effect with width 5px and color #f66 */
font-effect: outline( 5px #f66 );
/* declares a shadow font-effect with 2px offset in both x- and y-direction, and the given color */
font-effect: shadow( 2px 2px #333 );
The font-effect property follows the normal cascading rules, is inherited, and has the default value none which specifies no font-effect on the element. Unlike in libRocket, font-effects can now be set on the element's style, although we recommend declaring them in style sheets for performance reasons.
Furthermore, multiple font-effects can be specified on any element by a comma-separated list of font-effects.
/* declares two font-effects on the same element */
font-effect: shadow(3px 3px green), outline(2px black);
When creating a custom font-effect, you can provide a shorthand property named font-effect which will be used to parse the text inside the parenthesis of the property declaration. This allows specifying the font-effect with inline properties as in the above examples.
There is currently no equivalent of the @decorator at-rule for font-effects. If there is a desire for such a feature, please provide some feedback.
The child combinator > is now introduced in RCSS, which can be used as in CSS to select a child of another element.
p.green_theme > button { image-color: #0f0; }
Here, any button elements which have a parent p.green_theme will have their image color set to green.
Furthermore, the universal selector * can now be used in RCSS. This selector matches any element.
div.red_theme > * > p { color: #f00; }
Here, p grandchildren of div.red_theme will have their color set to red. The universal selector can also be used in combination with other selectors, such as *.great#content:hover.
The debugger has been improved in several aspects:
All manual reference counting has been removed in favor of smart pointers. There is no longer a need to manually decrement the reference count, such as element->RemoveReference() as before. This change also establishes a clear ownership of objects. For the user-facing API, this means raw pointers are non-owning, while unique and shared pointers declare ownership. Internally, there may still be uniquely owning raw pointers, as this is a work-in-progress.
The Core API takes raw pointers as before such as for its interfaces. With the new semantics, this means the library retains a non-owning reference. Thus, all construction and destruction of such objects is the responsibility of the user. Typically, the objects must stay alive until after Core::Shutdown is called. Each relevant function is commented with its lifetime requirements.
As an example, the system interface can be constructed into a unique pointer.
auto system_interface = std::make_unique<MySystemInterface>();
Rml::Core::SetSystemInterface(system_interface.get());
Rml::Core::Initialise();
...
Rml::Core::Shutdown();
system_interface.reset();
Or simply from a stack object.
MySystemInterface system_interface;
Rml::Core::SetSystemInterface(&system_interface);
Rml::Core::Initialise();
...
Rml::Core::Shutdown();
When constructing new elements, there is again no longer a need to decrement the reference count as before. Instead, the element is returned with a unique ownership
ElementPtr ElementDocument::CreateElement(const String& name);
where ElementPtr is a unique pointer and an alias as follows.
using ElementPtr = std::unique_ptr<Element, Releaser<Element>>;
Note that, the custom deleter Releaser is there to ensure the element is released from the ElementInstancer in which it was created.
After having called ElementDocument::CreateElement, the element can be moved into the list of children of another element.
ElementPtr new_child = document->CreateElement("div");
element->AppendChild( std::move(new_child) );
Since we moved new_child, we cannot use the pointer anymore. Instead, Element::AppendChild returns a non-owning raw pointer to the appended child which can be used. Furthermore, the new element can be constructed in-place, e.g.
Element* new_child = element->AppendChild( document->CreateElement("div") );
and now new_child can safely be used until the element is destroyed.
There are aliases to the smart pointers which are used internally for consistency with the library's naming scheme.
template<typename T> using UniquePtr = std::unique_ptr<T>;
template<typename T> using SharedPtr = std::shared_ptr<T>;
The inner workings of transforms have been completely revised, resulting in increased performance, simplified API, closer compliance to the CSS specs, and reduced complexity of the relevant parts of the library.
Some relevant changes for users:
PushTransform() and PopTransform() render interface functions with SetTransform(), which is only called when the transform matrix needs to change and never called if there are no transform properties present.perspective property now applies to the element's children, as in CSS.perspective() behaves like in CSS. It applies a perspective projection to the current element.It is now possible to autofocus on elements when showing a document. By default, the first element with the property tab-index: auto; as well as the attribute autofocus set, will receive focus.
The focus behavior as well as the modal state can be controlled with two new separate flags.
ElementDocument::Show(ModalFlag modal_flag = ModalFlag::None, FocusFlag focus_flag = FocusFlag::Auto);
The flags are specified as follows:
/**
ModalFlag used for controlling the modal state of the document.
None: Remove modal state.
Modal: Set modal state, other documents cannot receive focus.
Keep: Modal state unchanged.
FocusFlag used for displaying the document.
None: No focus.
Document: Focus the document.
Keep: Focus the element in the document which last had focus.
Auto: Focus the first tab element with the 'autofocus' attribute or else the document.
*/
enum class ModalFlag { None, Modal, Keep };
enum class FocusFlag { None, Document, Keep, Auto };
The RmlUi font engine has seen a major overhaul.
FontEngineInterface.h and the CMake flag NO_FONT_INTERFACE_DEFAULT for details.font-charset RCSS property is gone: The font interface now loads new characters as needed. Fallback fonts can be set so that unknown characters are loaded from them.Strings in RmlUi should be considered as encoded in UTF-8.demo sample for some examples.bitmapfont sample, serving as a quick example of how to create your own font interface. The sample should work even without the FreeType dependency.Three new CMake options added.
NO_FONT_INTERFACE_DEFAULT removes the default font engine, thereby allowing users to completely remove the FreeType dependency. If set, a custom font engine must be created and set through Rml::Core::SetFontEngineInterface before initialization. See the bitmapfont sample for an example implementation of a custom font engine.NO_THIRDPARTY_CONTAINERS: RmlUi now comes bundled with some third-party container libraries for improved performance. For users that would rather use the std counter-parts, this option is available. The option replaces the containers via a preprocessor definition. If the library is compiled with this option, then users of the library must specify #define RMLUI_NO_THIRDPARTY_CONTAINERS before including the library.ENABLE_TRACY_PROFILING: RmlUi has parts of the library tagged with markers for profiling with Tracy Profiler. This enables a visual inspection of bottlenecks and slowdowns on individual frames. To compile the library with profiling support, add the Tracy Profiler library to /Dependencies/tracy/, enable this option, and compile. Follow the Tracy Profiler instructions to build and connect the separate viewer. As users may want to only use profiling for specific compilation targets, then instead one can #define RMLUI_ENABLE_PROFILING for the given target.There are some changes to events in RmlUi, however, for most users, existing code should still work as before.
There is now a distinction between actions executed in event listeners, and default actions for events:
virtual void Element::ProcessDefaultAction(Event& event). However, any object that derives from Element can override the default behavior and add new behavior. The default actions are always executed after all event listeners, and only propagated according to the phases set in their default_action_phase value which is defined for each event type. If an event is interrupted with Event::StopPropagation(), then the default actions are not performed.Each event type now has an associated EventId as well as a specification defined as follows:
interruptible: Whether the event can be cancelled by calling Event::StopPropagation().bubbles: Whether the event executes the bubble phase. If true, all three phases: capture, target, and bubble, are executed. If false, only capture and target phases are executed.default_action_phase: One of: None, Target, TargetAndBubble. Specifies during which phases the default action is executed, if any. That is, the phase for which Element::ProcessDefaultAction() is called. See above for details.See EventSpecification.cpp for details of each event type. For example, the event type click has the following specification:
id: EventId::Click
type: "click"
interruptible: true
bubbles: true
default_action_phase: TargetAndBubble
Whenever an event listener is added or event is dispatched, and the provided event type does not already have a specification, the default specification
interruptible: true, bubbles: true, default_action_phase: None is added for that event type. To provide a custom specification for a new event, first call the method:
EventId Rml::Core::RegisterEventType(const String& type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase)
After this call, any usage of this type will use the provided specification by default. The returned EventId can be used to dispatch events instead of the type string.
Various changes:
StopPropagation(). When propagating to the next element, the event is stopped. This behavior is consistent with the standard DOM events model. The event can be stopped immediately with StopImmediatePropagation().Element::DispatchEvent can now optionally take an EventId instead of a String.resize event now only applies to the document size, not individual elements.scrollchange event has been replaced by a function call. To capture scroll changes, instead use the scroll event.textinput event now sends a String in UTF-8 instead of a UCS-2 character, possibly with multiple characters. The parameter key name is changed from "data" to "text".Context::ProcessMouseWheel now takes a float value for the wheel_delta property, thereby enabling continuous/smooth scrolling for input devices with such support. The default scroll length for unity value of wheel_delta is now three times the default line-height multiplied by the current dp-ratio.virtual void SystemInterface::SetClipboardText(const Core::String& text) and virtual void SystemInterface::GetClipboardText(Core::String& text).text-decoration property can now also be used with overline and line-through.<img> element can now take sprite names in the sprite attribute. For images the src attribute can be used as before.sliderbar on the range input element can now use margins to offset it from the track.Breaking changes since RmlUi 2.0.
Rml::Core::LoadFontFace instead of Rml::Core::FontDatabase::LoadFontFace.<img> element's coords attribute is now replaced by a rect attribute specified like for sprites.ElementDocument::Show has been changed, with a new enum name and new options, see above.image, tiled-horizontal, tiled-vertical, and tiled-box) no longer support the old repeat modes.RmlUi 2.0 is the first release after the original libRocket branch.
Based on the work of @shoemark, with additional fixes.
Use perspective, perspective-origin, transform and transform-origin in RCSS, roughly equivalent to their respective CSS properties.
perspective: 1000px;
perspective-origin: 20px 50%;
transform: rotateX(10deg) skew(-10deg, 15deg) translateZ(100px);
transform-origin: left top 0;
All transform properties and their argument types are as follows:
perspective, length1
matrix, abs_numbers6
matrix3d, abs_numbers16
translateX, length1
translateY, length1
translateZ, length1
translate, length2
translate3d, length3
scaleX, number1
scaleY, number1
scaleZ, number1
scale, number2
scale, number1
scale3d, number3
rotateX, angle1
rotateY, angle1
rotateZ, angle1
rotate, angle1
rotate3d, number3angle1
skewX, angle1
skewY, angle1
skew, angle2
Angles take units of 'deg' or 'rad'.
Most RCSS properties can be animated, this includes properties representing lengths, colors, or transforms. From C++, an animation can be started on an Element by calling
bool Element::Animate(const String& property_name, const Property& target_value, float duration, Tween tween = Tween{}, int num_iterations = 1, bool alternate_direction = true, float delay = 0.0f, const Property* start_value = nullptr);
Additional animation keys can be added, extending the duration of the animation, by calling
bool Element::AddAnimationKey(const String& property_name, const Property& target_value, float duration, Tween tween = Tween{});
C++ example usage:
auto p1 = Transform::MakeProperty({ Transforms::Rotate2D{10.f}, Transforms::TranslateX{100.f} });
auto p2 = Transform::MakeProperty({ Transforms::Scale2D{3.f} });
el->Animate("transform", p1, 1.8f, Tween{ Tween::Elastic, Tween::InOut }, -1, true);
el->AddAnimationKey("transform", p2, 1.3f, Tween{ Tween::Elastic, Tween::InOut });
Animations can also be specified entirely in RCSS, with keyframes.
animation: <duration> <delay> <tweening-function> <num_iterations|infinite> <alternate> <paused> <keyframes-name>;
All values, except <duration> and <kyframes-name>, are optional. Delay must be specified after duration, otherwise values can be given in any order. Keyframes are specified as in CSS, see example below. Multiple animations can be specified on the same element by using a comma-separated list.
Tweening functions (or in CSS lingo, animation-timing-functions) specify how the animated value progresses during the animation cycle. A tweening function in RCSS is specified as <name>-in, <name>-out, or <name>-in-out, with one of the following names,
back
bounce
circular
cubic
elastic
exponential
linear
quadratic
quartic
quintic
sine
RCSS example usage:
@keyframes my-progress-bar
{
0%, 30% {
background-color: #d99;
}
50% {
background-color: #9d9;
}
to {
background-color: #f9f;
width: 100%;
}
}
#my_element
{
width: 25px;
animation: 2s cubic-in-out infinite alternate my-progress-bar;
}
Internally, animations apply their properties on the local style of the element. Thus, mixing RML style attributes and animations should be avoided on the same element.
Animations currently support full interpolation of transforms, largely following the CSS specifications. Additionally, interpolation is supported for colors, numbers, lengths, and percentages.
Animations are very powerful coupled with transforms. See the animation sample project for more examples and details. There are also some video demonstrations of these features in the documentation.
Transitions apply an animation between two property values on an element when its property changes. Transitions are implemented in RCSS similar to how they operate in CSS. However, in RCSS, they only apply when a class or pseudo-class is added to or removed from an element.
transition: <space-separated-list-of-properties|all|none> <duration> <delay> <tweening-function>;
The property list specifies the properties to be animated. Delay and tweening-function are optional. Delay must be specified after duration, otherwise values can be given in any order. Multiple transitions can be specified on the same element by using a comma-separated list. The tweening function is specified as in the animation RCSS property.
Example usage:
#transition_test {
transition: padding-left background-color transform 1.6s elastic-out;
transform: scale(1.0);
background-color: #c66;
}
#transition_test:hover {
padding-left: 60px;
transform: scale(1.5);
background-color: #ddb700;
}
See the animation sample project for more examples and details.
The dp unit behaves like px except that its size can be set globally to scale relative to pixels. This makes it easy to achieve a scalable user interface. Set the ratio globally on the context by calling:
float dp_ratio = 1.5f;
context->SetDensityIndependentPixelRatio(dp_ratio);
Usage example in RCSS:
div#header
{
width: 800dp;
height: 50dp;
font-size: 20dp;
}
Set the element property to disregard mouse input events on this and descending elements.
pointer-events: none;
Default is auto.
Non-standard RCSS property which multiplies a color with images in <img> tags and image decorators. Useful for :hover-events and for applying transparency.
image-color: rgba(255, 160, 160, 200);
icon-decorator: image;
icon-image: background.png 34px 0px 66px 28px;
Unlike the original branch, elements with
display: inline-block;
will shrink to the width of their content, like in CSS.
Enables the border property shorthand.
border: 4px #e99;
input.range element can be dragged from anywhere in the element.:checked pseudo class can be used to style the selected item in drop-down lists.Rocket to Rml, include path from <Rocket/...> to <RmlUi/...>, and macro prefix from ROCKET_ to RMLUI_.Rml::Core::SystemInterface::GetElapsedTime() now returns double instead of float.
virtual double GetElapsedTime();
The font-size property no longer accepts a unit-less <number>, instead add the px unit for equivalent behavior. The new behavior is consistent with CSS.
The old functionality for setting and drawing mouse cursors has been replaced by a new function call to the system interface, thereby allowing the user to set the system cursor.
Python support has been removed.