# Connecting to Business Logic (Rust / C++ / JS / Python)

Use `export global`s for host interop instead of threading properties and
callbacks through every component — e.g. one global for state the host pushes
in and one for actions the host handles (a single mixed global is equally
idiomatic).

```slint
// globals.slint
export struct Row { id: int, name: string, selected: bool }
export global AppData {           // host pushes models/state in
    in property <[Row]> rows;
}
export global Logic {             // UI calls these; host handles them
    callback row-clicked(int);
    callback refresh();
}
```

Any component can read `AppData.rows` / call `Logic.row-clicked(...)` directly.

## Rust

```rust
slint::include_modules!();
use slint::{ModelRc, VecModel};

let ui = MainWindow::new()?;
ui.global::<AppData>().set_rows(ModelRc::new(VecModel::from(rows))); // Vec<Row>
ui.global::<Logic>().on_row_clicked(move |i| { /* … */ });
ui.run()
```

- Kebab-case → snake_case: `row-clicked` → registrar `on_row_clicked`,
  setter `set_...`.
- `[T]` → `ModelRc<T>`. For live updates keep an `Rc<VecModel<T>>` and mutate
  it (`push`/`set_row_data`) instead of replacing the whole model.
- `string` ↔ `SharedString`; `length`/`float` ↔ `f32`; `int` ↔ `i32`;
  `brush`/`color` ↔ `slint::Brush`/`Color`.
- Keep logic and the source of truth in the host language; expose an already
  sorted/filtered model and let `.slint` render and forward interactions. Use
  `slint::Timer` for timers; from other threads,
  `slint::invoke_from_event_loop` + a `Weak`.

## C++

```cpp
#include "main.h"   // generated by slint_target_sources; named after the .slint file
#include <slint.h>  // also brings in slint::Timer, VectorModel, SharedString, Color

struct App {
    slint::ComponentHandle<ns::AppWindow> ui;       // `ns` = the NAMESPACE you passed
    App() : ui(ns::AppWindow::create()) {           // no default ctor: init in the list
        const auto &logic = ui->global<ns::Logic>();
        logic.set_rows(std::make_shared<slint::VectorModel<ns::Row>>(rows)); // a `[Row]` field
        logic.on_row_clicked([this](int i) { /* … */ });
    }
};
```

- **`global<T>()` returns `const T&`, and globals are non-copyable.** Bind with
  `const auto &g = ui->global<T>();` — `auto g = …` fails to compile. The
  generated `set_*` / `on_*` methods are `const`, so the const ref is enough.
- **`ComponentHandle<T>` has no default constructor.** Create the window in a
  member-initializer list (`App() : ui(ns::AppWindow::create()) {}`), not by
  assigning in the body.
- Names are kebab→snake: `row-clicked` → `on_row_clicked`, a `kind-label` struct
  field → `.kind_label`. `[T]` ↔ `std::shared_ptr<slint::Model<T>>`; use
  `slint::VectorModel<T>` + `set_rows(...)`, or keep and mutate one model for live
  updates. `string` ↔ `slint::SharedString`, `color` ↔ `slint::Color`
  (`Color::from_rgb_uint8(r,g,b)`).
- `slint::Timer` comes from `<slint.h>` (no separate header). Keep it alive as a
  member: `t.start(slint::TimerMode::Repeated, std::chrono::milliseconds(900), cb)`.
- Build wiring: `slint_target_sources(tgt ui/main.slint NAMESPACE ns)` generates
  the header; link `Slint::Slint`. A property `foo` generates `set_foo`, so don't
  also declare a `callback set-foo()` — the two collide in the generated header.

## JS / Python

Same globals/structs via each language's API (getters/setters + callback
registration); names follow the language's convention (snake_case in Python,
camelCase in JS). The same host-logic/view split applies.
