# ltk onboarding

This guide is for the first hour with `ltk`: what environment you need, how to
run the examples, how to build a minimal app, when to use layer-shell vs a
regular window, and what theme/font assumptions the toolkit currently makes.

If you already know the basics and want the deeper rationale, read
[`docs/architecture.md`](./architecture.md) next.

## What `ltk` is

`ltk` is a Rust UI toolkit for Wayland. It is aimed first at the Eydos shell
stack, but it can also be used to build normal client applications and
runtime-free UI surfaces.

At a high level:

- Implement the `App` trait.
- Return an `Element<Msg>` tree from `view()`.
- React to user input by handling messages in `update()`.
- Start the event loop with `ltk::run(app)`.

The model is declarative and Elm-shaped: the widget tree is rebuilt from your
state, then `ltk` handles layout, drawing and input dispatch.

If you are browsing the crate through `cargo doc`, the public API is also
grouped conceptually into three entry points:

- `ltk::window` — basic application windows
- `ltk::shell` — layer-shell and overlays
- `ltk::runtime` — advanced runtime hooks and runtime-free embedding

Most users should start with `ltk::window` and ignore the other two until they
have a normal app window running.

## Before you start

`ltk` is not a browser toolkit and not a cross-platform desktop toolkit. Today
it assumes:

- a running **Wayland** session
- Wayland client libraries available through Rust dependencies
- a usable system font — on Debian (the crate's own packaging target):
  `fonts-sora`, `fonts-liberation` or `fonts-dejavu`
- an installed `default` theme, or a development theme directory exposed
  through `LTK_THEMES_DIR`

The rendering backend is selected automatically:

- **GLES** when EGL/GLES is available
- **software** fallback otherwise, or when `LTK_FORCE_SOFTWARE=1`

## Fastest way to see it working

From the repo root:

```bash
LTK_THEMES_DIR=themes cargo run --example showcase
```

The `LTK_THEMES_DIR=themes` prefix points theme lookup at the in-repo
`themes/` directory (see *Theme and font setup* below); without it, on a
machine without the `default` theme installed, the example runs on the
embedded B/W fallback with a red banner.

The other examples, same prefix:

- `cargo run --example widgets` — broad widget survey
- `cargo run --example inputs` — plain and secure text fields with a
  show/hide-password toggle
- `cargo run --example scroll` — the two main scroll use cases: a long list
  and an app-drawer-style grid
- `cargo run --example sliders` — the Glass effect on horizontal and
  vertical sliders
- `cargo run --example combo` — select/dropdown with editable query and
  multi-select chips
- `cargo run --example pickers` — notebook tabs, date, time and color
  pickers
- `cargo run --example dialog` — modal confirm, non-modal pick and the
  other dialog shapes
- `cargo run --example carousel` — focused-tile carousel
- `cargo run --example responsive` — fluid vs physical scaling side by side
- `cargo run --example clip_path` — per-path canvas clipping
- `cargo run --example mini_shell` — overlays, animation and theme switching

All examples require a running Wayland compositor.

## Build and test

The `Makefile` wraps the cargo invocations the repo expects:

- `make all` — release build
- `make test` — `cargo test --features test-support`; a bare `cargo test`
  fails because the integration tests import the feature-gated
  `ltk::test_support`
- `make doctest-md` — typechecks the code snippets in `docs/*.md`, so API
  drift surfaces in CI like a normal doctest failure
- `make examples` — runs every example in sequence with
  `LTK_THEMES_DIR=themes`
- `make doc` — `cargo doc --no-deps`

## Theme and font setup

`ltk` currently expects a theme named `default`. Lookup order is:

1. `LTK_THEMES_DIR/<id>/`
2. `$XDG_DATA_HOME/ltk/themes/<id>/`
3. `/usr/share/ltk/themes/<id>/`

For development inside this repository, the simplest setup is:

```bash
export LTK_THEMES_DIR="$PWD/themes"
```

That makes `ThemeDocument::find("default")` resolve to
`$PWD/themes/default/theme.json`.

Font loading is separate from theme lookup. `src/system_fonts.rs` walks a
chain of common system font *file paths* — the files installed by the
Debian packages `fonts-sora`, `fonts-liberation`, `fonts-freefont` and
`fonts-dejavu`, plus the equivalent locations other distros use — and
loads the first one it finds. If nothing matches, it falls back to an
embedded Sora Regular (~50 KB, SIL OFL 1.1) shipped inside the crate, so
font resolution never panics on a system without the expected fonts.
Installing one of the listed packages is still recommended for richer
glyph coverage.

## Your first app

The smallest useful `ltk` app implements `App`, returns a tree from `view()`,
updates its state in `update()`, and calls `ltk::run(...)`.

```rust,no_run
use ltk::{ App, Element, Keysym, button, column, spacer, text };

#[derive(Clone)]
enum Msg
{
    Increment,
}

struct CounterApp
{
    value: u32,
}

impl App for CounterApp
{
    type Message = Msg;

    fn view( &self ) -> Element<Msg>
    {
        column::<Msg>()
            .padding( 32.0 )
            .spacing( 16.0 )
            .center_y( true )
            .push( text( "Hello from ltk" ).size( 28.0 ) )
            .push( text( format!( "Count: {}", self.value ) ).size( 18.0 ) )
            .push( spacer() )
            .push( button( "Increment" ).on_press( Msg::Increment ) )
            .into()
    }

    fn update( &mut self, msg: Msg )
    {
        match msg
        {
            Msg::Increment => self.value += 1,
        }
    }

    fn on_key( &mut self, keysym: Keysym ) -> Option<Msg>
    {
        if keysym == Keysym::Escape
        {
            std::process::exit( 0 );
        }
        None
    }
}

fn main()
{
    ltk::run( CounterApp { value: 0 } );
}
```

### Minimal `Cargo.toml`

```toml
[package]
name = "my-ltk-app"
version = "0.1.0"
edition = "2021"

[dependencies]
ltk = { path = "../ltk" }
```

If you vend `ltk` from crates.io later, replace the `path` dependency with a
versioned one.

## Public API Layers

`ltk` exposes most items at the crate root, but for documentation and discovery
it is useful to think of the library in three layers.

### 1. `ltk::window`

This is the default entry point for third-party applications.

Use it for:

- normal application windows
- tools and prototypes
- most widget/layout work

The APIs you will usually touch first live here conceptually:

- `App`
- `Element<Msg>`
- `button`, `text`, `text_edit`, `img_widget`
- `column`, `row`, `stack`, `grid`, `spacer`
- `container`, `scroll`, `slider`, `toggle`, `checkbox`, `radio`
- `Color`
- `run`

### 2. `ltk::shell`

This layer groups the APIs that matter when your surface is part of the shell
rather than a normal app window.

Use it for:

- bars and docks
- homescreens
- notifications
- greeters and lock screens
- transient overlays

The most important APIs in this layer are:

- `ShellMode`
- `Layer`
- `Anchor`
- `OverlaySpec`
- `OverlayId`
- `overlays()`

### 3. `ltk::runtime`

This layer is for advanced integration points.

Use it when you need:

- external wakeups via `set_channel_sender()`
- timer-driven or async state via `poll_external()` / `poll_interval()`
- redraw narrowing via `invalidate_after()`
- runtime theme state access
- runtime-free embedding through `core::UiSurface`

Most applications do not need to start here.

## Regular app window vs shell surface

Most consumers should start with a **regular window**.

Default behaviour:

- `shell_mode()` defaults to `ShellMode::Window`
- `ltk::run(app)` creates an xdg-shell toplevel

Use this for:

- normal applications
- internal tools
- prototypes while learning the toolkit

Switch to **layer-shell** only when you are building a shell component:

- top bar
- dock
- homescreen
- notification surface
- lock screen / greeter

The knobs you will usually override are:

- `shell_mode()`
- `layer_anchor()`
- `layer_size()`
- `exclusive_zone()`
- `keyboard_exclusive()`
- `background_color()`

For a non-trivial multi-surface example, use `examples/mini_shell.rs` as the
reference entry point — note it runs as a regular window (it never overrides
`shell_mode()`) and demonstrates screen routing, coordinated overlays, an
animated OSD and live theme switching. The layer-shell knobs themselves are
exercised by the downstream shell components, not by the in-repo examples.

## The APIs you will touch first

In practice, most first apps only need a small subset of the surface area.

Start here:

- `App`
- `Element<Msg>`
- `button`, `text`, `text_edit`, `img_widget`
- `column`, `row`, `stack`, `grid`, `spacer`
- `container`, `scroll`, `slider`, `toggle`, `checkbox`, `radio`
- `Color`
- `run`

Do not start with these unless you need them:

- `ltk::shell`
- `ltk::runtime`
- `overlays()`
- gesture hooks such as `on_swipe_*`
- `set_channel_sender()` / `poll_external()`
- `core::UiSurface`
- custom theming APIs

## Message flow and state

The expected shape is:

1. user interaction emits a `Message`
2. `update()` mutates app state
3. `view()` rebuilds the UI from that state

Example:

```rust
#[derive(Clone)]
enum Msg
{
    NameChanged( String ),
    Submit,
}
```

For small apps, one top-level `enum Msg` is enough. Once the app grows, split
state by screen/panel and wrap sub-messages in the top-level enum:

```rust,no_run
# #[ derive( Clone ) ] pub enum HomeMsg {}
# #[ derive( Clone ) ] pub enum SettingsMsg {}
enum AppMsg
{
    Home( HomeMsg ),
    Settings( SettingsMsg ),
    Quit,
}
```

This is the pattern used by `examples/mini_shell.rs`.

## Responsive sizing: fluid vs physical

`ltk` gives you two ways to make an interface adapt to the display, and you can
mix them per value. **Fluid** sizes are a fraction of the surface (best for
full-screen system surfaces); **physical** sizes stay a constant real-world
size (best for conventional windowed apps). In practice you write a size as a
`Length` and bound it with `.clamp`:

```rust
use ltk::{ text, Length };

// Fluid: 6 % of the surface's short side, never below 20 px nor above 44 px.
text("Welcome").size(Length::vmin(6.0).clamp(20.0, 44.0));
```

Stock widgets follow a process-wide mode (`set_widget_scaling`, fluid by
default); an explicit `Length` on a widget overrides it. For the units
(`vmin` / `orient` / `dp` / …), the clamp discipline and how it all resolves,
see the *Responsive sizing* section of
[`architecture.md`](architecture.md#responsive-sizing) and the `Length`
rustdoc.

## Recommended learning order

If you are new to the library, this order minimizes confusion:

1. Run `examples/showcase.rs`.
2. Read the crate-level docs in `src/lib.rs`, especially `ltk::window`.
3. Build a plain xdg-shell window with `button`, `text`, `column`.
4. Add input handling with `text_edit` or `slider`.
5. Only then look at `ltk::shell` for overlays and layer-shell.
6. Move to `ltk::runtime` only when you need advanced hooks or embedding.

## Performance rules of thumb

`ltk` is designed to sleep when idle and redraw only on real changes, but the
application can still make bad choices. Keep these rules in mind:

- keep `view()` pure and cheap
- do not do filesystem I/O, parsing or image decoding inside `view()`
- cache expensive derived data on your app struct
- leave `poll_interval()` as `None` unless you genuinely need periodic wakeups
- only return `true` from `is_animating()` while something is actually moving

On mobile targets, the last two matter directly for battery life.

## When to use `core::UiSurface`

Most apps should ignore `core` at first.

Use `core::UiSurface` when you want `ltk`'s layout/drawing/hit-testing without
`ltk::run()`. Typical cases:

- compositor-side decorations
- embedding `ltk` widgets in another render loop
- offscreen rendering or previews

There is coverage for that path in `tests/core_surface.rs`.

## Current assumptions and rough edges

This repo is usable, but a few current behaviours are worth knowing up front:

- examples and docs assume Wayland, not X11
- theming is process-global
- theme discovery currently expects a `default` theme on disk (a B/W
  fallback document kicks in when missing, with a red banner on every
  frame so the gap is impossible to miss)
- the architecture docs mention downstream consumer repos that are not part of
  this repository

None of that blocks learning the toolkit, but it matters when you evaluate
`ltk` as a third-party dependency.

## What to read next

In the README's recommended order — onboarding, then the widget catalogue,
then the cookbook, then architecture:

- [`docs/widgets.md`](./widgets.md) — per-widget catalogue: what each one
  is, when to use it, minimal example
- [`docs/cookbook.md`](./cookbook.md) — concrete recipes: slide-in panels,
  password fields, runtime theme toggle, channel-driven state
- [`docs/architecture.md`](./architecture.md) — multi-surface patterns,
  theming, animation and performance
- [`docs/theming.md`](./theming.md) — JSON theme schema, slot conventions,
  runtime APIs
- [`docs/backends.md`](./backends.md) — software/GLES capability matrix
- [`examples/showcase.rs`](../examples/showcase.rs) — smallest visual tour
- [`examples/widgets.rs`](../examples/widgets.rs) — broader widget coverage
- [`examples/mini_shell.rs`](../examples/mini_shell.rs) — overlays and shell
  patterns
- [`tests/core_surface.rs`](../tests/core_surface.rs) — runtime-free rendering
