Getting Started with C++

This guide shows how to create your first Azul application in C++.

Quick Start

Download the pre-compiled library from releases and include azul.hpp in your project.

Hello World

#include "azul.hpp"
#include <iostream>

// Your application state
class MyApp {
public:
    int counter = 0;
    MyApp() = default;
};

// Layout function - converts state to UI
StyledDom layout(RefAny& data, LayoutCallbackInfo& info) {
    auto app = data.downcastRef<MyApp>();
    if (!app) {
        return StyledDom::default_();
    }
    
    auto text = "Counter: " + std::to_string(app->ptr.counter);
    
    return Dom::body()
        .withChild(Dom::text(String::fromStdString(text)))
        .style(CssApiWrapper::empty());
}

int main() {
    auto data = RefAny::new_(std::move(MyApp()));
    auto app = App::new_(std::move(data), AppConfig::new_((LayoutCallbackType)layout));
    app.run(WindowCreateOptions::default_());
    return 0;
}

Enums

Enums use C++11 enum class for type safety:

// Explicit constructors are static functions
auto window = WindowCreateOptions::default_(LayoutSolver::Default);

Move Semantics

All by-value arguments require std::move:

auto window = WindowCreateOptions::default_(LayoutSolver::Default);
app.run(std::move(window));

Adding Callbacks

// Callback function
Update onClick(RefAny& data, CallbackInfo& info) {
    auto app = data.downcastRefMut<MyApp>();
    if (app) {
        app->ptr.counter++;
        return Update::RefreshDom;
    }
    return Update::DoNothing;
}

// In layout function
auto button = Dom::div()
    .withInlineStyle(String::fromConstStr(
        "padding: 10px 20px; background: #4a90e2; color: white; cursor: pointer;"
    ))
    .withChild(Dom::text(String::fromConstStr("Click me!")));

// Attach callback
auto event = EventFilter::Hover(HoverEventFilter::MouseUp);
button.root.addCallback(event, data.clone(), (CallbackType)onClick);

Constructors

Default constructors take arguments in field order:

// API: struct ColorU { r: u8, g: u8, b: u8, a: u8 }
auto color = ColorU(/*r*/ 255, /*g*/ 255, /*b*/ 255, /*a*/ 255);

Explicit constructors are static functions:

auto window = WindowCreateOptions::default_(LayoutSolver::Default);

RefAny and Generics

No macros needed - use C++ templates:

class MyStruct {
public:
    int field;
    MyStruct(int f) noexcept : field(f) {}
};

auto object = RefAny::new_(std::move(MyStruct(5)));

// Read-only access
if (auto ref = object.downcastRef<MyStruct>()) {
    std::cout << ref->ptr.field << std::endl;
}

// Mutable access
if (auto refMut = object.downcastRefMut<MyStruct>()) {
    refMut->ptr.field = 10;
}

Vector Conversions

Convert std::vector without copying:

auto scancodes = std::vector<int>{0, 1, 2, 3};
auto converted = ScanCodeVec::fromStdVector(std::move(scancodes));
auto backToStd = converted.intoStdVector();

Convert strings:

auto stdString = std::string("Hello, Azul!");
auto azulString = String::fromStdString(std::move(stdString));

Pattern Matching

Union enums have constexpr constructors and match functions for pattern matching:

// Create a union enum - Exact() is a constexpr function
auto cursor = StyleCursorValue::Exact(StyleCursor::Grab);

// Const reference match (returns std::optional<const StyleCursor*>)
if (auto result = cursor.matchRefExact()) {
    std::cout << "Cursor is Grab" << std::endl;
}

// Mutable match (returns std::optional<StyleCursor* restrict>)
if (auto result = cursor.matchRefMutExact()) {
    *result = StyleCursor::Default;
}

Compilation

# Linux
g++ -std=c++17 -o myapp myapp.cpp -L. -lazul -Wl,-rpath,'$ORIGIN'

# macOS
clang++ -std=c++17 -o myapp myapp.cpp -L. -lazul -Wl,-rpath,@loader_path

# Windows (MSVC)
cl /std:c++17 myapp.cpp azul.lib

Next Steps

Back to overview

Back to guide index