All outline text draws with Slug curves on every platform (SDF/MSDF stays selectable per size); a frame never presents a blank glyph and retained draw lists keep theirs. One coverage model for vector feathering, widget families split out of the core crate, fewer steady-state allocations, video keeps its aspect (Contain/Cover), render and SSAO pass unification. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
181 lines
10 KiB
Markdown
181 lines
10 KiB
Markdown
# Application styles
|
|
|
|
These Splash files are the library's own sheets, one per desktop family the
|
|
window manager lays out: `omarchy`, `black-orange`, `macos`, `macos-dark`,
|
|
`windows`, `windows-dark`, `windows-2000`, `nextstep`, `ios`, `ios-dark`,
|
|
`android` and `android-dark`.
|
|
|
|
## The sheet catalogue
|
|
|
|
Every style is a sheet in one catalogue (`widgets/core/src/desktop_style.rs`):
|
|
a `SheetEntry` holds its id, its label, the desktop family it lays out as
|
|
(`DesktopStyle`: floating or tiled, shelf, title bar, icons, the WM's style
|
|
tween), the id of its dark variant, both Splash halves embedded, the source
|
|
directory a checkout hotloads them from, and the crate its
|
|
`crate_resource("self:...")` resolves against. The sheets above are the
|
|
catalogue's first entries, made with `sheet_entry!`. An app brings its own
|
|
sheets the same way and adds them at startup, before the first style load:
|
|
|
|
```rust
|
|
static SHEETS: [SheetEntry; 1] = [makepad_widgets::sheet_entry!(
|
|
dir: "themes", id: "harbour", label: "Harbour",
|
|
family: DesktopStyle::Omarchy, dark: None, resources: makepad_widgets::widgets_dir,
|
|
)];
|
|
desktop_style::register(&SHEETS);
|
|
```
|
|
|
|
Every list of styles -- the pickers, the WM's style menu, the theme lab and
|
|
store, the storybook's theme list -- reads the catalogue
|
|
(`desktop_style::catalogue`, `picks`, `find`), so a registered sheet turns up
|
|
everywhere without being named anywhere else. Sheets that belong to one app
|
|
live with that app, in a crate of its own, not here. The
|
|
checks every sheet is held to are `sheet_checks` in widgets-core (the
|
|
`sheet-checks` feature for an app's own tests).
|
|
|
|
Each style has two phases:
|
|
|
|
- `theme.splash` installs semantic roles, typography, spacing, radii, and bevels
|
|
before stock widgets are registered.
|
|
- `widgets.splash` applies component geometry and materials after registration.
|
|
It can replace a widget's shader as well as its properties. Windows 2000's
|
|
raised buttons and sunken edit fields are examples.
|
|
|
|
A replaced button face still shows the colour an app paints on it: apps light
|
|
a latch (the page they are on, a mute that is down) by setting `draw_bg.color`.
|
|
Each `Button*` face a sheet draws goes through `self.host_over(face, m)` (`m`
|
|
the room the sheet grew its quad by) or fills with `self.host_face(...)` or
|
|
`self.face_fill()`. At the variant's own `color_default` these return the
|
|
sheet's face unchanged; `sheet_checks::button_faces_take_the_host_colour`
|
|
holds every sheet to it.
|
|
|
|
## The surface material
|
|
|
|
The rounded view, the panel, the button, the check box, the toggle, the
|
|
slider and the knob carry a moulded material behind one uniform, `material`,
|
|
whose default is the theme's `material_level`. Every stock theme leaves it at
|
|
0, so those shaders draw exactly what they always did; a sheet built on it
|
|
raises it in its `theme.splash` before any widget registers (1 relief, 2
|
|
relief with rim, gloss and specular), and the `material_*` tokens beside it
|
|
set the key light, the shoulder, the finish, the cast and inner shadows, the
|
|
glow and the press. The shading is `mod.sdf.Material` in
|
|
`draw/src/shader/surface.rs`, the library `ReliefView` is lit by too.
|
|
|
|
A material control keeps its quad and insets its face by
|
|
`theme.material_margin`: the room its cast shadow falls into, which a sheet
|
|
pays for again in the control's padding. The press is one signed number,
|
|
`material_press_depth`: past `-material_raise` a held face inverts, short of
|
|
it the cap deepens, near zero the glow carries the state (with
|
|
`material_ink_glow` lighting the label). The storybook's Containers >
|
|
Material page shows all three.
|
|
|
|
The loader embeds both files for installed/wasm builds. In a native source
|
|
checkout it reads the sheet's source directory (`widgets/themes/<style>/` for
|
|
these) on each selection. Edit either file
|
|
and choose the same style again from the WM's style picker to hotload it.
|
|
End a generated assignment-only Splash module with `true` so its last
|
|
assignment is evaluated as a statement.
|
|
|
|
The WM keeps its Omarchy top bar. Click the current style name to open the
|
|
dropdown. Modern desktop and mobile styles also have a Light/Dark button. Its Applications
|
|
launcher, Windows Start menus, window chrome, and hosted apps use the selected
|
|
appearance.
|
|
|
|
`desktop_style::StyleSheet` carries both phases to existing process clients
|
|
through `StudioToApp::Custom`. `Window` receives the message and requests an
|
|
application Splash reload with `Apply::ScriptReapply`. Module clients re-evaluate
|
|
their registrations in their existing isolates with the same apply mode.
|
|
Widget identities, editable text, and application Rust state are retained.
|
|
Initialize persistent script models only when `!vm.is_reload()`; read the existing
|
|
`mod.state` from application Splash. See `examples/counter/src/main.rs`. Dynamic
|
|
`View.on_render` children and embedded Splash isolates reapply the style too.
|
|
Embedded `Splash` widgets inherit the stylesheet and reapply their existing
|
|
widget tree in their own isolate.
|
|
|
|
Applications should inherit the stock component styles and read `theme.*` for
|
|
custom drawing. Rust drawing reads `makepad_widgets::theme_tokens::color(vm, role)`
|
|
during registration or through the owning VM with `Cx::with_vm`. Re-read these
|
|
roles after each style reload: appearances can change while an app is open.
|
|
The WM provides `MAKEPAD_WIDGET_STYLE` at spawn and the `makepad_style` sheet
|
|
event for live changes; apps do not read the WM's desk palette file.
|
|
|
|
The framebuffer crossfade lives in `apps/wm/src/scene.rs`. It freezes the old
|
|
GPU render target while the live scene renders the new style; it does not take
|
|
screenshots, rebuild app instances, or put transitions in the widget system.
|
|
Shell geometry interpolates over the same 650 ms interval. Floating desktop
|
|
rectangles are stored separately from the Omarchy tiling tree, so switching back
|
|
restores the tiling arrangement.
|
|
|
|
The macOS dock overlays the desktop; dragging keeps the title bar reachable but
|
|
allows window bodies behind the dock or partly offscreen. Terminals render only
|
|
their background with opacity (`MAKEPAD_WM_TERM_OPACITY`, default `0.78 0.70` for
|
|
focused/unfocused); text and ANSI cell colors remain crisp. Their foreground and
|
|
background follow the active light/dark stylesheet without restarting the PTY.
|
|
`color_terminal_bg` and `color_terminal_text` are separate semantic roles:
|
|
Windows 2000 and Android use opaque black consoles, while NeXTSTEP uses white.
|
|
Rust terminal drawing reads these tokens directly, using `color_bg_app` and
|
|
`color_text` when the terminal-specific roles are absent. Declare both in each
|
|
style so a reload resets the previous console palette.
|
|
The terminal opts into `Window.body.keyboard_resize: true`; this KeyboardView
|
|
mode reflows content above the animated keyboard instead of panning the whole
|
|
terminal out of view. Its grid and PTY resize with the available space.
|
|
|
|
`widgets/core/src/backdrop.rs` supplies ordered compositor checkpoints. Windows are
|
|
composited from back to front, and a glass surface samples a checkpoint below it.
|
|
Disjoint sampling footprints share a Gaussian stack, including the kernel's
|
|
support outside the visible surface. Intervening opaque or translucent content
|
|
that overlaps the footprint starts a new checkpoint. The dock is the final
|
|
consumer. Requested blur levels are combined before drawing the pyramid, so
|
|
unused deeper passes are skipped. Explicit producer/consumer links preserve GPU
|
|
ordering when pass IDs are recycled. `MAKEPAD_WM_TRACE_BLUR=1` logs stack and pass
|
|
counts when they change; normal operation does not log each frame.
|
|
|
|
In a checkout, build with `cargo build --release -p makepad-app-wm`, then launch
|
|
`./target/release/makepad-app-wm --remote` from the checkout root.
|
|
Applications launch on demand with `cargo run --release -p <package>`; there is
|
|
no binary collection to prepare. The app's window shows Cargo's compiling or
|
|
build-wait stage before the process connects, then fades into its first frame.
|
|
Installed distributions without a source checkout use sibling executables.
|
|
|
|
NeXTSTEP uses black focused title bars, gray beveled window controls, square
|
|
widgets, a right-hand vertical application dock, and its own icon family. Its
|
|
launcher opens a draggable Workspace palette with attached submenu columns.
|
|
Hold the secondary mouse button on the desktop or a window title bar, drag
|
|
through the menu and release to choose a command. The popup follows the pointer
|
|
and opens submenus to the left near the screen edge. The Omarchy top bar
|
|
and shared application state remain in place while switching styles.
|
|
|
|
Application icons use `AppIcon{name: "files" width: 32 height: 32}`. The default
|
|
`style: "auto"` follows the application's Splash stylesheet; standalone apps use
|
|
the host OS family. An explicit style ID is available for galleries. `color`
|
|
retints the Omarchy artwork; `opacity` preserves the other families' own colors.
|
|
Window captions derive their icon name from `window.app_id` (or the binary name),
|
|
and the WM's dock/taskbar/launcher use the same `AppIconDraw` renderer.
|
|
|
|
Each family has editable `icons/<app-id>.svg` assets. macOS dark and light share
|
|
app artwork, as on the OS. Unknown IDs use that family's `app.svg`. Add or edit
|
|
an SVG and reselect the style to hotload it; the complete icon sources travel in
|
|
the stylesheet to existing process and module apps. Unchanged sources keep their
|
|
parsed geometry cache. `python3 widgets/themes/build_icons.py` rebuilds the
|
|
bundled artwork families using only Python's standard library.
|
|
|
|
Use original application symbols within each OS's visual style. Files uses a
|
|
folder with documents, and Browser uses a web window with a globe; do not use
|
|
the Finder face or Safari compass artwork.
|
|
|
|
Application surfaces should use the shared `theme` roles (or app-specific aliases
|
|
that resolve to those roles), including `corner_radius` and
|
|
`container_corner_radius`. Keep content colors such as chart series and model
|
|
axes separate. Filled accent actions use `color_text_on_accent`.
|
|
|
|
Mark live fields that contain runtime UI state with `#[apply_state]` alongside
|
|
`#[live]`: stylesheet `ScriptReapply` preserves these values, while explicit
|
|
`Eval` edits and ordinary source reloads still apply. Standard panel visibility,
|
|
checkbox state, and dropdown selection use this path.
|
|
|
|
On macOS, the WM captures the complete window into a GPU texture and warps
|
|
that surface into its application icon in the dock. Minimize and restore share
|
|
the same reversible progress, without resizing or relaying out the application
|
|
during the animation. A style change invalidates minimized snapshots so the
|
|
restored window uses the current theme. `MAKEPAD_WM_TRACE_WARP=1` enables the
|
|
capture diagnostics using ordinary logs. For frame inspection,
|
|
`MAKEPAD_WM_WARP_SECONDS=5` slows the default 0.62-second animation.
|