# Developer Guide
## Goal
`faststep` should behave more like a small UIKit-style framework than a loose widget bundle.
The intended authoring flow is:
1. Keep `main` thin.
2. Provide a root view implementation.
3. Let an OEM adapter construct the board/display/touch side.
4. Start the app with `run_ui_system(...)`.
5. Let the root view configure its children and metadata.
6. Use container views for stack/tab/split/alert behavior.
7. Let controls own their own interaction state.
8. Build scrolling surfaces from `ScrollView`.
9. Use datasource/delegate protocols for data-driven views such as lists.
## Entry Point
The framework entry points are `UiSystem` and `run_ui_system(...)`.
`UiSystem` owns:
- the OEM display port
- the root view instance
- theme and i18n
- the root `ViewRegistration`
`FsTheme` is the global semantic palette for the system. Configure it once at startup and let views consume semantic colors such as:
- neutral surfaces
- primary/accent
- warning
- danger
- text-on-accent
- text-on-danger
`run_ui_system(...)` owns:
- the update/touch/present loop
- tick pacing
- feeding touch into the root view
- calling the OEM presenter when a redraw is pending
The intended startup shape is:
```rust
run_ui_system(display, RootView::new(), theme, i18n, driver, presenter)?;
```
That keeps hardware setup in the OEM adapter and keeps the runtime loop inside `faststep`.
## View Contract
`UiView<'text, ViewId, Message, N>` is the core view trait.
Every view can:
- `configure(...)`: declare title, alpha, hidden state, clipping, and child views
- `update(...)`: produce redraw/message output during tick
- `handle_touch(...)`: react to input and emit messages/redraws
- `draw(...)`: render itself using `embedded-graphics`
`ViewRegistration` is the setup/configuration object passed into `configure(...)`.
Useful registration methods:
- `set_title(...)`
- `set_alpha(...)`
- `set_hidden(...)`
- `set_clips_to_bounds(...)`
- `set_user_interaction_enabled(...)`
- `add_child(...)`
Child views are declared with `ChildView`, which carries:
- a child id
- a `ViewKind`
- a frame
- view properties
This is how a root view states what it contains.
## View Metadata
`ViewProperties` carries UIKit-like view attributes:
- `title`
- `alpha`
- `hidden`
- `clips_to_bounds`
- `user_interaction_enabled`
Those properties are part of the framework contract, not ad hoc app state.
## OEM Abstraction
The framework does not hardcode ESP-IDF display plumbing.
The OEM-facing traits are:
- `DisplayPort`
- `UiRuntimeDriver`
- `UiRuntimePresenter`
This is the seam for turning `faststep` into an OEM-ready solution instead of coupling it to one board implementation.
An OEM project should not need to rewrite the framework to fit a new panel, touch controller, or a future simulator backend. The hardware boundary stays trait-based, and the runtime loop stays in `faststep` rather than in the final app binary.
### Display
Implement `DisplayPort` for the target display backend.
Required pieces:
- `bounds() -> Rectangle`
- `draw_frame(...)`
Optional optimization:
- override `draw_dirty(...)` if the backend supports partial redraw efficiently
This is the place to connect:
- framebuffer ownership
- DMA / flush
- dirty-rect presentation
- double buffering
### Runtime Driver
Implement `UiRuntimeDriver` for the board or simulator runtime side.
This trait owns:
- touch polling in terms of `TouchEvent`
- poll cadence decisions
- sleep or delay
- clock reads
That keeps gesture, list, and container code portable across devices while moving the event loop out of `main`.
### Presenter
Implement `UiRuntimePresenter` for the panel or backend-specific presentation policy.
This is where redraw scheduling belongs:
- full redraw vs dirty redraw
- motion frame throttling
- platform-specific partial-present optimizations
- tracking previous dirty geometry when required
### Expected Main Layout
Typical `main` structure should now be:
1. initialize system patches or logging
2. hand off to an OEM adapter
3. let that adapter call `faststep::run_ui_system(...)`
The important boundary is:
- the board or simulator crate owns hardware construction and backend-specific adapters
- `faststep` owns the UI contracts and the runtime loop
- the app or root view owns only UI structure and behavior
## Container Views
The first foundation layer includes thin container/state wrappers:
- `StackView`
- `TabView`
- `SplitView`
- `AlertHost`
These are not yet a full retained view tree, but they establish the correct direction:
- stack mechanics belong to a stack container
- tab organization belongs to a tab container
- split-pane layout belongs to a split container
- alert presentation belongs to an alert host
## Controls
Leaf controls should keep their own interaction state inside `faststep`.
For example:
- `Button` owns pressed/highlighted/captured touch state
- `ImageView` owns image frame/alignment/inset presentation instead of making each screen hand-place raw images
- `TextView` and `RichTextView` own mono-font layout for single-line and multiline text blocks
- app/root code should keep button actions and layout, not a parallel `ButtonTouchState`
- this keeps application views closer to UIKit view-controller structure instead of pushing control bookkeeping upward
## Lists
`ScrollView` is the base scrolling primitive.
It owns:
- inertial scrolling
- overscroll/snap-back behavior
- transient vertical scroll indicator state
The indicator should behave like a mobile scroll surface:
- stay hidden on touch-down
- reveal only after drag slop is crossed and content is actually moving
- stay visible during drag/fling/snap-back
- fade after motion ends
`ListView` builds on `ScrollView` and adds separate roles:
- `ListDataSource`: count, item id, item size
- `ListDelegate`: row drawing plus highlight/select callbacks
Rows are described with `ListRow` and `ListRowState`.
That means a row renderer can change appearance when:
- the row is highlighted
- the row is selected
This is the current bridge toward UIKit-like reusable row/cell behavior.
That means the list itself owns scrolling and selection mechanics, while application code owns data and row appearance/selection responses.
This is the shape new screens should follow.
## Examples
The crate ships with compile-checked examples for each major API family:
- `examples/buttons.rs`
- `examples/text_and_image.rs`
- `examples/scroll_and_list.rs`
- `examples/containers.rs`
- `examples/alerts.rs`
- `examples/runtime_shell.rs`
- `examples/uikit_root.rs`
- `examples/root_delegate.rs`
These examples are packaged with the crate and are intended to show up cleanly on docs.rs.
## Redraw Model
The new foundation uses `ViewRedraw`:
- `None`
- `Dirty(Rectangle)`
- `Full`
`ViewEvent<Message>` carries:
- redraw request
- capture state
- optional message
This keeps view behavior explicit and testable.
## Compatibility Layer
`UiApp` still exists because current projects use it, but it should be treated as transitional.
Use `UiApp` only when maintaining existing demos.
Use `UiSystem` + `UiView` + container/data-source APIs for new work.