azul-desktop 0.0.4

Desktop rendering API for azul
docs.rs failed to build azul-desktop-0.0.4
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

Azul is a free, functional, immediate-mode GUI framework for rapid development of desktop applications written in Rust, supported by the Mozilla WebRender rendering engine, using a flexbox-based CSS / DOM model for layout and styling.

Concept

Azul is largely based on the principle of immediate-mode GUI frameworks, which is that the entire UI (in Azuls case the DOM) is reconstructed and re-rendered on every frame (instead of having functions that mutate the UI state like button.setText()). This method of constructing UIs has a performance overhead over methods that retain the UI, therefore Azul only calls the Layout::layout() function when its absolutely necessary - inside of a callback, you can return whether it is necessary to redraw the screen or not (by returning Redraw or DontRedraw, respectively).

In difference to other immediate-mode frameworks, Azul does not immediately draw to the screen, but rather "draws" to a Dom. This has several advantages, such as making it possible to layout code at runtime, loading a Dom from an XML file, recognizing state changes by diffing two frames, as well as being able to reparent DOMs into almost any configuration to make components reusable independent of the context they are in.

Hello world

extern crate azul;

use azul::prelude::*;

struct MyDataModel { }

impl Layout for MyDataModel {
fn layout(&self, _: LayoutInfo) -> Dom<Self> {
Dom::label("Hello World")
}
}

fn main() {
let app = App::new(MyDataModel { }, AppConfig::default()).unwrap();
app.run(WindowCreateOptions::new(css::native()));
}

Running this code should return a window similar to this:

Opening a blank window

Development lifecycle

A huge problem when working with GUI applications in Rust is managing the compile time. Having to recompile your entire code when you just want to shift an element a pixel to the right is not a good developer experience. Azul has three main methods of combating compile time:

You can create your own hot-reload handler (for example to automatically compile SASS / LESS or other files when reloading) by implementing the HotReloadHandler trait or use the [default HotReloader]

Due to Azuls stateless rendering architecture, hot-reloading also preserves the current application state. Once you are done layouting your applications UI, you can transpile the XML code to valid Rust source code using azulc, the Azul-XML-to-Rust compiler.

Please note that the compiler isn't perfect - the XML system is very limited, and parsing XML has a certain performance overhead, since it's done on every frame. That is fine for debug builds, but the XML system should not be used in release mode.

When you are done with designing the callbacks of your widget, you may want to package the widget up to autmatically react to certain events without having the user of your widget write any code to hook up the callbacks - for this purpose,

Application state management

Azul features a two way data binding system using Ref<MyWidget> which you can upcast to a RefAny (a type-erased Rc<RefCell<Any>>). This RefAny then [gets stored in the Dom], and when invoking a [DefaultCallback] you can access the RefAny through the [DefaultCallbackInfo.state] and [downcast it] to a RefCell<MyWidget>.

Events bubble from inner to outer elements. You can either override the default behaviour of widgets - for example, you can set the ontextinput callback function to a custom callback function. This is one way of implementing "extends / override" in Rust (which doesn't feature such concepts). You can also simply [prevent the default callback from being called] or [prevent an event from bubbling to its parents].

Custom drawing and embedding external applications

Azul is mostly concerned with rendering text, images and rectangular boxes (divs). There is no audio / video playback support, but there are other crates for this purpose, for example [rodio]. Azul is not a complete application development framework like Qt, it only focuses on the GUI aspect.

Other content can be drawn by drawing to an OpenGL texture (using a GlCallback) and hand it over to Azul. This is how components like a video player or other OpenGL-based visualizations can be injected into the UI, without being part of the core library.

You can draw to an OpenGL texture and in order to display it in the UI - the texture doesn't have to come from Azul itself, you can inject it from an external application.

Azul can also render to a headless target - for this purpose, the text-layout, the layout and the core components are separate crates, separate from the azul crate, which depends on webrender and is meant as the desktop deployment target. By default, azul-layout depends on a static build of HarfBuzz and FreeType for layouting glyphs, but you can use the system-native builds by using features = ["native-freetype"].

The output of a headless rendering pass is a CachedDisplayList, which contains all information about how and where to render items - without actually rendering them anywhere. This way you can render to a custom rendering target (such as a non-OpenGL renderer, a software renderer, PDF / SVG or the web). However, you will have to handle input handling and hit-testing yourself and provide a custom event loop.

File picker, popup dialogs, multi-window handling

Azul implements the APIs to open native file picker dialogs, see the [dialogs] module. You can create one or more windows in callbacks by calling [CallbackInfo::create_window()]. Each window carries a unique ID and a unique type, which can be user-defined. This type gets then passed to the Layout::layout() function, and you can use said window type.

For small, frameless popup windows, such as context menus and tearoff-windows, azul also features display: window-*; (ex. display: window-context-menu) - which behaves exactly like display: absolute, except that it displays the content of the div it is applied to in a separate, frameless window.

Rendering of large / infinite data sets

For rendering very large or infinite data sources such as long lists, tables, etc., Azul provides [IFrameCallbacks] so that you don't have to render what you don't see on the screen. For example, imagine you want to render a long list with multiple thousands of items. It isn't necessary to show all items on screen at the same time, instead you only want to display a "window" and load / unload items as the user scrolls.

IFrameCallbacks do exactly that: The callbacks are stored in the Dom and during the layout step, the callback is invoked with the size (of its container) and scroll offset. So, if you know that every item is 20px high, and the IFrameCallback gets invoked with a height of 100px, then you only need to render 5 divs into the Dom instead of thousands.

Limitations

There are a few limitations that should be noted:

  • There are no scrollbars yet.
  • There is no support for CSS animations of any kind yet.
  • There is no text selection yet.
  • Changing dynamic variables will trigger an entire UI relayout and restyling

Tutorials

Explaining all concepts and examples is too much to be included in this API reference. Please refer to the wiki or use the links below to learn about how to use Azul.