fschutt / azul

Desktop GUI Framework
https://azul.rs/
Mozilla Public License 2.0
5.9k stars 220 forks source link
c cpp desktop desktop-gui-framework gui gui-framework gui-library opengl rust

Azul - Desktop GUI framework

CI Coverage Status LICENSE [Rust Compiler Version]() dependency status

Azul is a free, functional, reactive GUI framework for Rust, C and C++, built using the WebRender rendering engine and a CSS / HTML-like document object model for rapid development of beautiful, native desktop applications

Website | Releases | User guide | API documentation | Video demo | Matrix Chat

Features

Azul uses webrender (the rendering engine behind Firefox) to render your UI, so it supports lots of common CSS features like:

See the list of supported CSS keys / values for more info.

On top of that, Azul features...

* static linking not yet available

** C++ bindings and Python are not yet stabilized and might not work depending on the branch you're using. They will be stabilized before the release.

Screenshots

image image image image

Hello World

Python

from azul import *

class DataModel:
    def __init__(self, counter):
        self.counter = counter

def render_dom(data, info):

    label = Dom.text("{}".format(data.counter))
    label.set_inline_style("font-size: 50px;")

    button = Button("Increment counter")
    button.set_on_click(data, increment_counter)

    dom = Dom.body()
    dom.add_child(label)
    dom.add_child(button.dom())

    return dom.style(Css.empty())

def increment_counter(data, info):
    data.counter += 1;
    return Update.RefreshDom

app = App(DataModel(5), AppConfig(LayoutSolver.Default))
app.run(WindowCreateOptions(render_dom))

Rust

use azul::prelude::*;
use azul::widgets::{button::Button, label::Label};

struct DataModel {
    counter: usize,
}

extern "C" 
fn render_dom(data: &mut RefAny, _: &mut LayoutInfo) -> StyledDom {

    let data = data.downcast_ref::<DataModel>()?;

    let label = Dom::text(format!("{}", data.counter))
        .with_inline_style("font-size: 50px;");

    let button = Button::new("Increment counter")
        .onmouseup(increment_counter, data.clone());

    Dom::body()
    .with_child(label)
    .with_child(button.dom())
    .style(Css::empty())
}

extern "C" 
fn increment_counter(data: &mut RefAny, _: &mut CallbackInfo) -> Update {
    let mut data = data.downcast_mut::<DataModel>()?;
    data.counter += 1;
    Update::RefreshDom // call render_dom() again
}

fn main() {
    let initial_data = RefAny::new(DataModel { counter: 0 });
    let app = App::new(initial_data, AppConfig::default());
    app.run(WindowCreateOptions::new(render_dom));
}

C

#include "azul.h"

typedef struct {
    uint32_t counter;
} DataModel;

void DataModel_delete(DataModel* restrict A) { }
AZ_REFLECT(DataModel, DataModel_delete);

AzStyledDom render_dom(AzRefAny* data, AzLayoutInfo* info) {

    DataModelRef d = DataModelRef_create(data);
    if !(DataModel_downcastRef(data, &d)) {
        return AzStyledDom_empty();
    }

    char buffer [20];
    int written = snprintf(buffer, 20, "%d", d->counter);
    AzString const labelstring = AzString_copyFromBytes(&buffer, 0, written);
    AzDom label = AzDom_text(labelstring);
    AzString const inline_css = AzString_fromConstStr("font-size: 50px;");
    AzDom_setInlineStyle(&label, inline_css);

    AzString const buttontext = AzString_fromConstStr("Increment counter");
    AzButton button = AzButton_new(buttontext, AzRefAny_clone(data));
    AzButton_setOnClick(&button, incrementCounter);

    AzDom body = Dom_body();
    AzDom_addChild(body, AzButton_dom(&button));
    AzDom_addChild(body, label);

    AzCss global_css = AzCss_empty();
    return AzDom_style(body, global_css);
}

Update incrementCounter(RefAny* data, CallbackInfo* event) {
    DataModelRefMut d = DataModelRefMut_create(data);
    if !(DataModel_downcastRefMut(data, &d)) {
        return Update_DoNothing;
    }
    d->ptr.counter += 1;
    DataModelRefMut_delete(&d);
    return Update_RefreshDom;
}

int main() {
    DataModel model = { .counter = 5 };
    AzApp app = AzApp_new(DataModel_upcast(model), AzAppConfig_default());
    AzApp_run(app, AzWindowCreateOptions_new(render_dom));
    return 0;
}

License

Azul is licensed under the MPL-2.0. Which means that yes, you can build proprietary applications using azul without having to publish your code: you only have to publish changes made to the library itself.

Copyright 2017 - current Felix Schütt