C+
macOS

A Facet counter on AppKit

This example uses the 0.0.28 Facet application model. The component and its tree are platform-neutral; facet_runtime selects the macOS facade and facet_appkit mounts native AppKit controls. A named window owns the screen, its navigation state, and its lifecycle.

Manifest

[package]
name    = "counter"
version = "0.0.1"
edition = "2026"

[macos]
entry = "src/main.cplus"

[dependencies]
stdlib        = "*"
facet         = "*"
facet_runtime = "*"
flex_layout   = "*"
events        = "*"

[macos.dependencies]
facet_appkit = "*"
objc         = "*"
appkit       = "*"
quartzcore   = "*"
webkit       = "*"

The application entry is selected by the [macos] section. Version 0.0.28 does not use [[bin]]; a portable application can instead rely on the default src/main.cplus entry.

Source

import "facet/facet" as core;
import "facet/elements" as ui;
import "facet/component" as component;
import "facet/label" as label;
import "facet/screen" as screen;
import "facet_runtime/runtime" as runtime;
import "stdlib/option" as option;
import "stdlib/status" as status;
import "stdlib/vec" as vec;

struct Counter {
    clicks: i32,
}

impl Counter {
    fn new() -> Counter {
        return Counter { clicks: 0 };
    }

    fn on_click(ref this, sender: *u8) {
        this.clicks = this.clicks +% 1;
        match label::find("count") {
            option::Option[label::Label]::Some(l) => {
                let _updated: label::Label =
                    l.set_text("Clicked ${this.clicks} time(s)");
            }
            option::Option::None => { }
        }
    }
}

impl Counter: component::Component {
    fn build(ref this) -> core::Node {
        var body: core::Builder = core::Builder::new();
        body.add(ui::label("Clicked 0 time(s)", key: "count"));
        body.add(ui::button("Click me", key: "increment",
                            on_click: this.on_click));
        return core::column(body).padding(20.0).gap(10.0);
    }
}

impl Counter: component::Lifecycle {
    fn on_attach(ref this, why: component::Attach) { return; }
    fn on_detach(ref this, why: component::Detach) { return; }
}

impl Counter: screen::Screen {
    fn menu_items(this) -> vec::Vec[screen::MenuItem] {
        return vec::new::[screen::MenuItem]();
    }
}

fn counter_screen() -> screen::ScreenBox {
    return screen::screen_box(Counter::new());
}

fn main() -> i32 {
    let app = runtime::App::new("counter");
    app.window("main", counter_screen,
        chrome: screen::Chrome::new(
            title: "Counter", width: 360.0, height: 200.0));

    if app.run("main") == status::Status::Ok { return 0; }
    return 1;
}

The component owns clicks. The keyed label is found in the mounted tree and updated in place by the handler. Window registration supplies the title and size; screens no longer own chrome and applications no longer call app.screen.

Build

cpc build
./target/debug/counter

Facet uses the same component, screen, named-window, and navigation model with facet_uikit, facet_android, facet_gtk, and facet_win32. Platform-specific dependencies and entries belong in their matching manifest sections.


‹ Back to all examples