Files
ltk/src/lib.rs
T
admin af4009374d
CI / build + test (push) Canceled after 0s
CI / cargo audit (push) Canceled after 0s
A browser app takes part in the desktop as a Wayland client does: fullscreen, the desktop's windows, activation and the shell protocol through forge/web, its own files through ltk::vfs, and images its caller names
On a page with forge/web an ltk app had a main surface, overlays and subsurfaces, but none of what a shell such as crustace needs from the compositor: fullscreen did nothing, the app heard nothing of the other windows, an activation token it asked for never came, forge/web was never told when a launched window had shown, the shell could not speak its protocol, and the app had no way to read its own files in a browser. Each now goes through the app's connection to forge/web, in the shape of the Wayland protocol it stands for.
Fullscreen. On a page with forge/web, `App::fullscreen` and `App::start_fullscreen` send a `set_fullscreen` request for the main window, as `xdg_toplevel.set_fullscreen` does, instead of doing nothing; alone on a page the canvas still takes the browser's fullscreen. `examples/web_hello.rs` gains a button that toggles it.
The desktop's windows. On connecting, the backend asks for the list of toplevels, and forge/web's `toplevel_opened` and `toplevel_closed` events become `ToplevelEvent`s for `App::on_toplevel_event`, as `ext-foreign-toplevel-list-v1` does on Wayland, so a shell's dock knows which applications have windows open.
Activation. The tokens an app asks for with `App::take_activation_requests` are issued before it draws: forge/web's, through its `activation_token` request, or empty without a desktop, as on Wayland without xdg-activation, and handed to `App::on_activation_token` with their messages processed. A browser app that launched others through tokens waited for one that never came. Each surface's first presented frame is reported with a `presented` request (`WebSurfaceState::presented`), so forge/web knows when a window it launched has shown and can report it activated, which dismisses crustace's splash.
The shell protocol. `platform/web/shell.rs` carries the JSON a shell speaks to forge over its socket over the app's connection to forge/web: `ltk::web::shell_send( json )` sends it as a `shell` request, and each `shell` event's message reaches the listener `ltk::web::set_shell_listener` gives, as JSON. What is sent before the app has connected is kept and sent once it has, so a shell can tell forge/web its theme while it starts. An overlay's role now carries its `App::overlay_namespace`, as its layer-shell namespace does on Wayland, so forge/web can tell a shell's overlays apart.
The cursor over every surface. The CSS `cursor` was set on the main surface's element only, so over an overlay the pointer kept the page's arrow. `WebSurfaceState` keeps the element that takes its input, the shape moves to that of the surface the pointer enters, and `WebPlatform::cursor` keeps the last one asked for.
An app's own files. `ltk::vfs`, through which ltk reads its themes, fonts and keyboard layouts, is public: `read`, `read_to_string`, `read_dir`, `is_file` and `is_dir` read the file system natively and, in a browser, the files the page loaded into memory. `ltk::web::load_tree( base, root ).await` loads any tree served with a `MANIFEST` under `root`, and `load_resources` is that into `/ltk` with the directory made the resource directory. `ltk::time::Instant` is public too, `std`'s natively and `web_time`'s on wasm32, where `std::time::Instant::now` panics, so an app that builds for both measures time with ltk's clock.
wasm-bindgen-cli. `scripts/wasm-bindgen-cli.sh TOOLS_DIR` builds wasm-bindgen-cli into `TOOLS_DIR/bin` at the version of the `wasm-bindgen` crate ltk pins in its `Cargo.toml`, from its sources with a lock resolved for Debian's rustc, which is what `make web-deps` did inline and now runs. Since `make install` copies `scripts/` into the registry, a project that builds for the browser against the installed ltk, such as forge/web or crustace, gets the same CLI without a checkout of ltk. The README and docs/architecture.md say so.
Images named by their caller. Every draw through `draw_image_data` fingerprints its pixels to find them in the image caches, which for a terminal means hashing every glyph of every frame. `Canvas::draw_image_keyed( key, rgba, w, h, dest, opacity )` is `draw_image_data` with `key` naming the pixels in place of their fingerprint: every draw with the same key must pass the same pixels, which are read only when the image is not cached. Both backends' caches are keyed by `ImageId`, `Content` for a fingerprint and `Keyed` for a caller's key, so a key never names an image drawn by content even when it equals its fingerprint. `GlesCanvas` and `SoftwareCanvas` gain `draw_image_keyed`, and their `draw_image_data` and it share one private `draw_image`. Tests check that a keyed image draws as its pixels do and that a key equal to a fingerprint is another image.
A held button is not also tapped. A button with `on_long_press` and no `on_drag_start` stayed a tap after its hold fired, so releasing it sent its `on_press` as well. `GestureState::long_press_msg_fired` is set when the hold fires `long_press_msg` and suppresses the press message on release; a test covers it.
`CHANGELOG.md` describes these changes.
2026-10-21 10:21:11 +02:00

627 lines
26 KiB
Rust
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
// Inside `unsafe fn` bodies, every unsafe op must still be wrapped in
// its own `unsafe { ... }` block. Without this lint the compiler treats
// the whole body as one implicit `unsafe` scope and a SAFETY: comment
// per call site becomes impossible to enforce — the kind of drift that
// hides UB in renderer code where every glow::* call is `unsafe fn`.
#![ deny( unsafe_op_in_unsafe_fn ) ]
// Without a backend there is no runtime to use the helpers it shares with the core.
#![ cfg_attr( not( backend ), allow( dead_code, unused_imports ) ) ]
// Wayland drives the whole runtime, so its build is where dead code shows; a backend that drives part of it would warn about the rest.
#![ cfg_attr( all( backend, not( feature = "wayland" ) ), allow( dead_code ) ) ]
// Drawing and damage passes take the geometry and state of a surface as plain arguments, and caches are keyed by tuples; splitting either up for the lint would only add types. The quick start keeps its `fn main` to show how an app starts.
#![ allow( clippy::too_many_arguments, clippy::type_complexity, clippy::needless_doctest_main ) ]
//! # ltk — Liberux ToolKit
//!
//! A lightweight Wayland UI toolkit built on top of
//! [smithay-client-toolkit](https://crates.io/crates/smithay-client-toolkit),
//! [tiny-skia](https://crates.io/crates/tiny-skia) and
//! [rustybuzz](https://crates.io/crates/rustybuzz).
//!
//! ltk is the UI toolkit for the Liberux desktop. The Liberux compositor (Forge)
//! handles window management, decorations, and positioning — ltk focuses on
//! rendering the content of each Wayland surface.
//!
//! `ltk` is also a public library for third-party developers building native
//! Wayland applications. If you are approaching the crate through `cargo doc`,
//! the API is grouped conceptually into three navigation modules:
//!
//! - [`window`] — the basic application window path most apps should start with
//! - [`shell`] — layer-shell and overlay APIs for shell-like surfaces
//! - [`runtime`] — advanced runtime hooks, invalidation, channels, and
//! runtime-free embedding via [`core::UiSurface`]
//!
//! ## Quick start
//!
//! ```rust,no_run
//! use ltk::{App, Element, column, text, button, spacer, Color, ButtonVariant};
//!
//! #[ derive( Clone ) ]
//! enum Msg { Quit }
//!
//! struct MyApp;
//!
//! impl App for MyApp
//! {
//! type Message = Msg;
//!
//! fn app_id( &self ) -> &str { "net.example.Hello" }
//!
//! // Nothing worth restoring in a one-button app.
//! fn save_state( &self ) -> Option<Vec<u8>> { None }
//! fn restore_state( &mut self, _state: Vec<u8> ) {}
//!
//! fn view( &self ) -> Element<Msg>
//! {
//! column()
//! .push( text( "Hello, ltk!" ).size( 32.0 ).color( Color::WHITE ) )
//! .push( spacer() )
//! .push( button( "Quit" ).on_press( Msg::Quit ) )
//! .into()
//! }
//!
//! fn update( &mut self, msg: Msg )
//! {
//! match msg { Msg::Quit => std::process::exit( 0 ) }
//! }
//! }
//!
//! fn main() { ltk::run( MyApp ); }
//! ```
//!
//! ## Architecture
//!
//! - **[`App`]** trait — implement this to define your application.
//! - **[`Element`]** enum — the widget tree returned by [`App::view`].
//! - Widgets, layouts and primitive types are listed below in their own
//! sidebar sections; the [`widgets`], [`layouts`] and [`types`] modules
//! are concept-oriented landing pages that `cargo doc` exposes for the
//! same set, grouped by category.
//!
//! ## Rendering backends
//!
//! All drawing goes through a single [`Canvas`], which is one of two interchangeable backends exposing the same API. The GLES backend (`GlesCanvas`) is the default when an EGL/OpenGL ES context is available and renders on the GPU; the software backend (`SoftwareCanvas`) rasterises on the CPU with tiny-skia and is the fallback when there is no GL context (and what offscreen/preview rendering uses). The two are kept at visual parity for the common primitives, with a few backend-specific traits documented per method (e.g. multi-rect [`Canvas::set_clip_rects`] is an exact mask on software but a bounding-box scissor on GLES, and [`Canvas::is_software`] lets a caller branch on a real path clip vs a bounding rect). [`run()`] selects the backend automatically; [`core::UiSurface`] lets an embedder force one.
//!
//! ## Widgets
//!
//! The interactive and decorative leaves of the [`Element`] tree:
//!
//! - **Buttons / activations** — [`button()`], [`icon_button`],
//! [`pressable`], [`window_button`], [`list_item()`].
//! - **Stateful binary controls** — [`toggle()`], [`checkbox()`],
//! [`radio()`].
//! - **Continuous controls** — [`slider()`], [`vslider()`],
//! [`progress_bar()`], [`pattern_grid()`].
//! - **Text** — [`text()`], [`text_edit()`].
//! - **Decoration** — [`container()`], [`separator()`], [`img_widget()`].
//! - **Clipping wrappers** — [`scroll()`], [`viewport()`], [`flex()`].
//! - **Modal overlays** — [`dialog()`] (centered confirmation card with
//! optional title, subtitle, custom body and action row; built-in
//! scrim, ESC-to-cancel, and tap-outside-to-dismiss for the
//! non-modal variant).
//!
//! See [`widgets`] for the grouped landing page and
//! `docs/widgets.md` for the per-widget catalogue.
//!
//! ## Layouts
//!
//! Composable arrangers for [`Element`] trees:
//!
//! - [`column()`] — vertical flow.
//! - [`row()`] — horizontal flow.
//! - [`stack()`] — z-order overlay with per-child alignment.
//! - [`grid()`] — fixed-column-count wrapping grid; [`grid_min_cell()`]
//! derives the column count from the width instead.
//! - [`spacer()`] — invisible flexible filler.
//!
//! See [`layouts`] for the grouped landing page.
//!
//! ## Types
//!
//! Geometry and primitive values that flow through every builder:
//!
//! - [`Color`], [`Rect`], [`Point`], [`Size`], [`Corners`], [`WidgetId`].
//! - [`Length`] — a size/distance that may be absolute pixels
//! ([`LengthBase::Px`]), relative to the surface viewport
//! ([`LengthBase::Vw`] / [`LengthBase::Vh`] / [`LengthBase::Vmin`] /
//! [`LengthBase::Vmax`] / [`LengthBase::Orient`]), to the root font
//! size ([`LengthBase::Em`]) or to the pixel density
//! ([`LengthBase::Dp`]). Every setter that takes a size, padding,
//! spacing or font height now accepts `impl Into<Length>`, so legacy
//! `.size( 24.0 )` keeps working while new code can write
//! `.size( Length::vmin( 4.0 ).clamp( 16.0, 32.0 ) )` for a typeface
//! that scales with the screen. See **Responsive design** below.
//!
//! See [`types`] for the full module with `//!` description.
//!
//! ## Responsive design: one UI from phone to desktop
//!
//! A core goal of ltk is that a **single view** reads coherently across
//! a portrait phone, a tablet and a landscape desktop window — no
//! per-target forks, no media-query soup. The mechanism is **fluid
//! sizing**: express sizes as a fraction of the surface so the whole
//! design breathes with the screen, instead of freezing at one pixel
//! size that only looks right on one device.
//!
//! ### The core rule — fluid, but clamped
//!
//! Default to `Length::vmin( pct ).clamp( lo, hi )` for every font size,
//! padding, spacing and spacer:
//!
//! - the percentage tracks the surface's **smaller** side, so portrait
//! and landscape stay coherent — an element keeps the same fraction of
//! the narrow axis whichever way the device is held;
//! - the px `clamp` bounds the fluid range so the design never collapses
//! on a watch-sized surface nor balloons on a 4K monitor.
//!
//! The clamp is not optional polish: it is what turns *pure* proportional
//! sizing (fragile at the extremes) into *bounded* proportional sizing
//! (robust everywhere). Treat "always clamp a fluid value" as the rule,
//! not the exception.
//!
//! ### Orientation-dependent proportion — [`Length::orient`]
//!
//! Sometimes the right *proportion* differs by orientation, not merely
//! the reference axis. A logo may want 40 % of the width in portrait —
//! there is vertical room to spare — but only 5 % of the height in
//! landscape, where vertical room is scarce.
//! [`Length::orient`]`( portrait, landscape )` expresses exactly that:
//! `portrait` % of the **width** when the surface is portrait,
//! `landscape` % of the **height** when it is landscape (the short side
//! of each orientation, but with its own proportion).
//!
//! When the *structure* of the layout should change with the
//! orientation — a row of panels in landscape, the same panels stacked
//! in portrait — branch the view on [`orientation()`] (backed by
//! [`viewport_size()`], recorded by the runtime on every configure and
//! sharing `orient`'s square-counts-as-portrait rule). See
//! `examples/clip_path.rs`.
//!
//! For images, pair it with
//! [`Image::short_side`](widget::image::Image::short_side), which sizes
//! the image along the screen's short side and lets the other axis follow
//! the source aspect ratio:
//!
//! ```rust,no_run
//! # use std::sync::Arc;
//! # use ltk::{ img_widget, Length, Element };
//! # #[ derive( Clone ) ] enum Msg {}
//! # fn _ex( rgba: Arc<Vec<u8>>, w: u32, h: u32 ) -> Element<Msg> {
//! // 40 % of the width in portrait, 5 % of the height in landscape.
//! img_widget( rgba, w, h ).short_side( Length::orient( 40.0, 5.0 ) ).into()
//! # }
//! ```
//!
//! ### When constant *physical* size matters instead
//!
//! Fluid units scale with the screen's pixels, not with real-world
//! millimetres — and legibility is a function of physical (angular) size,
//! not of what fraction of the screen a glyph fills. When a size must stay
//! a **constant physical size** across very different displays, use the
//! other mode: [`Length::dp`] (a density-independent pixel — `n ×` the
//! pixel density, applied when the value is resolved — the mainstream
//! HiDPI unit), or [`LengthBase::Em`] for text
//! relative to the root font size. The pre-calibrated
//! [`theme::typography`] scale
//! ([`theme::typography::h0`]…[`theme::typography::body_xs`]) is built on
//! clamped `vmin`, so it stays fluid while respecting a readable px floor
//! and ceiling — a good default for running text.
//!
//! ### The two modes, and choosing per app
//!
//! ltk offers both strategies as first-class citizens and lets the app
//! pick — per value, or process-wide for every stock widget:
//!
//! - **Fluid** — [`Length::fluid`] and the raw `vmin` / `vmax` / `vw` /
//! `vh` / `orient` units. Surface-proportional; tracks the short side
//! (width in portrait, height in landscape). Best for full-screen system
//! surfaces on known hardware (lock screen, greeter, splash, kiosk,
//! launcher).
//! - **Physical** — [`Length::dp`] plus [`set_density`] / [`density`].
//! Constant real-world size, HiDPI-aware. Best for conventional windowed
//! apps across an open-ended device set.
//!
//! Stock widgets carry one design pixel per dimension and resolve it
//! through the process-wide [`WidgetScaling`] mode
//! ([`set_widget_scaling`]): [`WidgetScaling::Fluid`] (the default) reads
//! it as [`Length::fluid`], [`WidgetScaling::Physical`] as [`Length::dp`].
//! An explicit [`Length`] on a widget always overrides the mode.
//!
//! ### Structural changes — branch in `view()`
//!
//! When the layout *structure* must change (sidebar → bottom tabs, two
//! columns → one) rather than merely resize, branch in `view()` on
//! `surface_width` / `surface_height`. Keep this for genuine
//! restructuring; [`Length`] covers all pure sizing.
//!
//! ## Runtime-free embedding
//!
//! Use [`core::UiSurface`] when you need ltk's layout, drawing and
//! hit-testing without [`run()`] — typically for compositor-side
//! decorations, embedding ltk widgets in another render loop, or
//! offscreen rendering / previews.
//!
//! ## Licence and third-party assets
//!
//! `ltk` itself is distributed under `LGPL-2.1-only`. The default
//! theme bundles two third-party asset sets that travel under their
//! own licences and must be credited when the toolkit (or a binary
//! that embeds the default theme) is redistributed:
//!
//! - **Symbolic icons** under `themes/default/icons/catalogue/` —
//! Streamline's *Core Line Free* set, [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/),
//! © Streamline. Some files modified for the symbolic-tinting
//! pipeline; details in `themes/default/icons/catalogue/LICENSE.md`.
//! Upstream: <https://www.streamlinehq.com/icons/core-line-free>.
//! - **Sora Regular** (`src/theme/fallback/Sora-Regular.otf`) — the
//! embedded font fallback, [SIL OFL 1.1](https://scripts.sil.org/OFL),
//! © The Sora Project Authors, Jonathan Barnbrook, Julián Moncada.
//! - **Pointer cursors** under `themes/default/cursors/` — GNOME's
//! *Adwaita* cursor theme (the cursors GNOME Shell ships), bundled
//! verbatim, © the GNOME Project. Offered upstream under
//! [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/) *or*
//! [LGPL 3](https://www.gnu.org/licenses/lgpl-3.0.html), and
//! [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) for
//! the newer assets; any one option satisfies the licence. See
//! `themes/default/cursors/README.md` (what the set is and how it is
//! used) and `themes/default/cursors/LICENSE.md` (attribution).
//! Upstream: <https://gitlab.gnome.org/GNOME/adwaita-icon-theme>.
//!
//! The remaining artwork in the default theme (wallpapers, lockscreens,
//! launcher logo, brand-mark variants, per-application icons) is
//! original to Liberux Labs and travels under the toolkit's own
//! `LGPL-2.1-only` licence. The full Debian-style declaration lives in
//! `debian/copyright` of the source tree.
// Load YAML locale files from `ltk/locales/*.yaml`. The `t!()` macro is
// re-exported (see below) so consuming applications can also use it; their
// own `i18n!()` invocations merge into the same runtime registry. The
// fallback locale is English — built-in widget strings always have an
// English entry.
rust_i18n::i18n!( "locales", fallback = "en" );
/// Serialises tests across modules that read or mutate the process-wide
/// density / [`WidgetScaling`] globals, so parallel test threads never
/// observe each other's transient state.
#[ cfg( test ) ]
pub( crate ) static TEST_GLOBALS_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new( () );
pub mod types;
pub mod font_face;
pub mod osk;
pub( crate ) mod render;
pub( crate ) mod system_fonts;
pub( crate ) mod text_shaping;
pub( crate ) mod a11y;
pub( crate ) mod widget;
pub( crate ) mod layout;
pub( crate ) mod app;
pub( crate ) mod channel;
pub mod theme;
pub mod wallpaper;
pub mod chassis;
pub mod nav_stack;
pub( crate ) mod tree;
pub( crate ) mod draw;
#[ cfg( backend ) ]
pub( crate ) mod input;
#[ cfg( backend ) ]
pub( crate ) mod event_loop;
#[ cfg( backend ) ]
pub( crate ) mod platform;
#[ cfg( feature = "wayland" ) ]
pub( crate ) mod protocol;
#[ cfg( feature = "wayland" ) ]
pub( crate ) mod session_state;
pub( crate ) mod secure_mem;
pub( crate ) mod resources;
pub mod time;
pub mod vfs;
pub mod gles_render;
#[ cfg( not( target_arch = "wasm32" ) ) ]
pub mod egl_context;
pub mod core;
pub use app::
{
Anchor, App, BackAtRoot, BackResponse, ChannelSender, ShellMode, Layer, OverlayId, OverlaySpec,
SubsurfaceId, SubsurfaceSpec, SubsurfaceParent,
InvalidationScope, MouseButton, MouseButtonEvent, RawKey, SelectionKind, SurfaceTarget, ToplevelEvent,
};
pub use theme::
{
Palette, ThemeMode, ThemePreference, ThemeError,
ThemeDocument, Mode, SlotStore,
WallpaperSpec, WallpaperFit, LauncherSpec, WindowControlsSpec,
active_document, active_mode, active_theme_id,
is_fallback_active,
set_active_document, set_active_mode,
tint_symbolic,
};
pub use theme::{ color as theme_color, color_or as theme_color_or };
pub use theme::{ paint as theme_paint, shadows as theme_shadows };
pub use theme::{ surface as theme_surface, text_style as theme_text_style };
pub use theme::resolve_surface as theme_resolve_surface;
pub use theme::palette as theme_palette;
pub use theme::window_controls as theme_window_controls;
pub use theme::wallpaper as theme_wallpaper;
pub use theme::lockscreen as theme_lockscreen;
pub use theme::app_icon as theme_app_icon;
pub use theme::app_default_icon as theme_app_default_icon;
pub use theme::launcher_icon as theme_launcher_icon;
pub use theme::logo as theme_logo;
pub use theme::logo_square as theme_logo_square;
pub use theme::logo_horizontal as theme_logo_horizontal;
pub use theme::branding_asset as theme_branding_asset;
pub use theme::branding_raster as theme_branding_raster;
pub use theme::branding_image as theme_branding_image;
pub use theme::{ decode_svg_bytes, icon_path as theme_icon_path, icon_rgba as theme_icon_rgba };
pub use gles_render::{ BorrowedGlesTexture, GlesVersion };
pub use render::is_software_render;
pub use render::Canvas;
pub use font_face::{ ColorGlyph, FontFace, LineMetrics, Metrics, OutlineBounds };
pub use osk::Purpose as InputPurpose;
pub use wallpaper::{ WallpaperBundle, ImageData };
pub use nav_stack::NavStack;
pub use chassis::{ set_default_theme, theme_logo_rgba, theme_icon_tinted, branding_bundle_or_solid, wallpaper_bundle_or_solid, backdrop };
pub use types::{ Color, CompositeMode, Corners, CursorShape, Length, LengthBase, PathCmd, Point, Rect, Size, WidgetId };
pub use types::{ WidgetScaling, FLUID_MIN, FLUID_MAX };
pub use types::{ fluid_reference, set_fluid_reference };
pub use types::{ density, set_density };
pub use types::{ set_text_scale, text_scale };
pub use types::{ widget_scaling, set_widget_scaling };
pub use types::{ Orientation, orientation, viewport_size, set_viewport_size };
pub use types::{ output_logical_size, set_output_logical_size };
pub use widget::{ Element, button, icon_button, text_edit, image as img_widget, text, container };
pub use text_shaping::{ caret_offsets, caret_offsets_with_font, line_metrics, measure_text };
pub use widget::rich_text::{ rich_text, RichText, LinkSpan };
pub use widget::button::ButtonVariant;
pub use widget::slider::{ Slider, slider, SliderAxis };
pub use widget::vslider::{ VSlider, vslider };
pub use widget::pattern_grid::{ PatternGrid, pattern_grid };
pub use widget::text::{ TextAlign, WRAP_PAD as TEXT_WRAP_PAD };
pub use widget::toggle::{ Toggle, toggle };
pub use widget::separator::{ Separator, separator };
pub use widget::progress_bar::{ ProgressBar, progress_bar };
pub use widget::checkbox::{ Checkbox, checkbox };
pub use widget::radio::{ Radio, radio };
pub use widget::list_item::{ ListItem, list_item };
pub use widget::window_button::{ WindowButton, WindowButtonKind, window_button, window_controls };
pub use widget::pressable::{ Pressable, pressable };
pub use widget::flex::{ Flex, flex };
pub use widget::combo::{ Combo, ComboState, combo };
pub use widget::spinner::{ Spinner, spinner };
pub use widget::tab_bar::{ TabBar, tabs };
pub use widget::anchored_overlay::{ anchored, AnchoredOverlay };
pub use widget::tab_strip::{ TabItem, TabLayout, TabMotion, TabOverview, TabStrip, TabStripColors, tab, tab_overview, tab_strip };
pub use widget::toast::{ Toast, toast };
pub use widget::tooltip::{ Tooltip, tooltip };
pub use widget::notebook::{ Notebook, NotebookPage, notebook };
pub use widget::external::{ External, ExternalSource };
pub use widget::external as widget_external;
pub use widget::date_picker::
{
Date, DatePicker, Locale as DateLocale, date_picker,
is_leap_year, days_in_month, day_of_week, add_months,
};
pub use widget::time_picker::{ Time, TimePicker, time_picker };
pub use widget::color_picker::
{
ColorPicker, color_picker, color_to_hex, parse_hex,
};
pub use widget::dialog::{ Dialog, dialog };
pub use layout::spacer::{ Spacer, spacer };
pub use layout::column::{ Column, column };
pub use layout::row::{ Row, row };
pub use layout::stack::{ Stack, stack, HAlign, VAlign };
// push_aligned_margin is available as a method on Stack — no separate re-export needed.
pub use layout::wrap_grid::{ WrapGrid, grid, grid_min_cell };
pub use widget::scroll::{ scroll, ScrollAxis };
pub use widget::viewport::{ Viewport, viewport };
pub use widget::carousel::{ Carousel, carousel };
#[ cfg( backend ) ]
pub use app::{ run, try_run, RunError };
#[ cfg( feature = "android" ) ]
pub use platform::android::{ keep_running, set_android_app, AndroidApp };
/// What only the browser backend offers.
#[ cfg( feature = "web" ) ]
pub mod web
{
pub use crate::platform::web::{ load_resources, load_tree, set_canvas, set_shell_listener, shell_send };
}
pub use resources::{ resource_dir, set_resource_dir };
pub use xkeysym::Keysym;
/// Widgets — the interactive and decorative leaves of the [`Element`]
/// tree.
///
/// Concept-oriented sidebar entry: every widget the toolkit ships is also
/// available at the crate root (`ltk::button`, `ltk::toggle`, …); this
/// module groups them so `cargo doc` shows a single landing page when you
/// are looking for "what controls can I draw".
///
/// See [`docs/widgets.md`](https://github.com/liberux/ltk/blob/master/docs/widgets.md)
/// for the per-widget catalogue with usage notes and minimal examples.
pub mod widgets
{
pub use crate::
{
// Buttons / activations
button, icon_button,
Pressable, pressable,
WindowButton, WindowButtonKind, window_button, window_controls,
ListItem, list_item,
// Stateful binary controls
Toggle, toggle,
Checkbox, checkbox,
Radio, radio,
// Continuous controls
Slider, slider, SliderAxis,
VSlider, vslider,
PatternGrid, pattern_grid,
ProgressBar, progress_bar,
// Composite picker
Combo, ComboState, combo,
// Activity / hint indicators
Spinner, spinner,
// Segmented selector + paginated tabs
TabBar, tabs,
Notebook, NotebookPage, notebook,
// Date / time / color pickers
Date, DatePicker, DateLocale, date_picker,
Time, TimePicker, time_picker,
ColorPicker, color_picker, color_to_hex, parse_hex,
// Transient overlays (return OverlaySpec)
Toast, toast,
Tooltip, tooltip,
// Modal / non-modal centered overlays
Dialog, dialog,
// Text input and display
text, text_edit, TextAlign,
// Decoration and chrome
container, Separator, separator,
img_widget,
// Clipping wrappers
scroll,
Viewport, viewport,
Flex, flex,
// Button styling token
ButtonVariant,
};
}
/// Layouts — composable arrangers for [`Element`] trees.
///
/// Concept-oriented sidebar entry. Each layout has a free constructor
/// (`column()`, `row()`, …) and a builder-style API for spacing, padding
/// and alignment. Layouts and [widgets] share the same `Element<Msg>`
/// tree.
pub mod layouts
{
pub use crate::
{
Column, column,
Row, row,
Stack, stack, HAlign, VAlign,
WrapGrid, grid, grid_min_cell,
Spacer, spacer,
};
}
/// Basic application-window API.
///
/// Start here if you are building a normal Wayland client window.
///
/// This module is documentation-first: it re-exports the common entry points
/// that most applications need so `cargo doc` presents a smaller and more
/// approachable surface before the user gets into overlays, gestures, and
/// shell-specific features.
///
/// The default path is:
///
/// 1. implement [`App`]
/// 2. return an [`Element`] tree from [`App::view`]
/// 3. mutate state in [`App::update`]
/// 4. start the event loop with [`run`]
///
/// If you are looking for layer-shell, overlays, or advanced runtime hooks,
/// move on to [`crate::shell`] or [`crate::runtime`].
pub mod window
{
pub use crate::
{
App, ButtonVariant, Color, Element, Keysym, Point, Rect, Size,
BackAtRoot, BackResponse, NavStack,
Column, Row, Stack, WrapGrid, Spacer,
button, icon_button, text, text_edit, img_widget,
container, checkbox, radio, toggle, separator,
progress_bar, list_item, slider, vslider, scroll, viewport,
column, row, stack, grid, grid_min_cell, spacer,
TextAlign, SliderAxis,
};
#[ cfg( backend ) ]
pub use crate::run;
}
/// Shell and layer-surface API.
///
/// Use this module when you are building shell-like surfaces rather than a
/// plain application window:
///
/// - panels
/// - docks
/// - homescreens
/// - greeters
/// - lock screens
/// - transient overlays
///
/// These items are also available at the crate root; this module exists so
/// `cargo doc` exposes a concept-oriented entry point for layer-shell users.
pub mod shell
{
pub use crate::
{
Anchor, App, Layer, OverlayId, OverlaySpec, ShellMode,
SurfaceTarget, InvalidationScope,
WindowButton, WindowButtonKind, window_button, window_controls,
};
}
/// Advanced runtime and embedding API.
///
/// This module groups the hooks that are useful once the basic app-window flow
/// is no longer enough:
///
/// - external wakeups via [`ChannelSender`]
/// - redraw narrowing via [`InvalidationScope`]
/// - surface-level invalidation targets via [`SurfaceTarget`]
/// - runtime-free embedding with [`crate::core::UiSurface`]
/// - direct theme/runtime state access
///
/// Most applications do not need to start here.
pub mod runtime
{
pub use crate::
{
ChannelSender, InvalidationScope, SurfaceTarget,
Palette, ThemeDocument, ThemeError, ThemeMode, ThemePreference,
WallpaperBundle, ImageData,
active_document, active_mode, active_theme_id,
is_fallback_active,
set_active_document, set_active_mode,
theme_color, theme_color_or, theme_paint, theme_palette,
theme_resolve_surface, theme_shadows, theme_surface, theme_text_style,
theme_wallpaper, theme_lockscreen, theme_window_controls,
theme_branding_asset, theme_branding_raster, theme_branding_image,
tint_symbolic,
};
pub use crate::core::{ RenderOptions, RenderOutput, UiSurface };
}
/// Internal helpers re-exported for the integration tests under `tests/` and
/// the criterion benches under `benches/`. The items themselves are `pub` but
/// live inside `pub(crate)` modules, so the only path that reaches them from
/// outside the crate is `ltk::test_support::*` — which is exactly what test
/// crates (and benches, which are also external) need.
///
/// **Not part of the stable public API.** Anything in here may change between
/// patch releases without notice. Hidden from generated docs via
/// `#[doc(hidden)]`, and gated behind the `test-support` feature so it is
/// absent from third-party builds entirely (ltk's own `make test` enables it).
#[ cfg( feature = "test-support" ) ]
#[ doc( hidden ) ]
pub mod test_support
{
pub use crate::tree::{ find_widget_at, find_widget, find_handlers, next_focusable_index };
pub use crate::widget::{ LaidOutWidget, WidgetHandlers };
pub use crate::widget::slider::{ value_from_x_in_rect, value_from_pos_in_rect, thumb_design_px, SliderAxis };
pub use crate::widget::vslider::value_from_y_in_rect;
#[ cfg( backend ) ]
pub use crate::event_loop::diff_overlay_ids;
}