// 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 ) ]

//! # 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
//! [fontdue](https://crates.io/crates/fontdue).
//!
//! 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 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()`].
//! - **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( 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 mod theme;
pub mod wallpaper;
pub mod chassis;

pub( crate ) mod tree;
pub( crate ) mod draw;
pub( crate ) mod input;
pub( crate ) mod event_loop;
pub( crate ) mod secure_mem;
pub mod gles_render;
pub mod egl_context;
pub mod core;

pub use app::
{
	Anchor, App, ChannelSender, ShellMode, Layer, OverlayId, OverlaySpec,
	SubsurfaceId, SubsurfaceSpec, SubsurfaceParent,
	InvalidationScope, 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 wallpaper::{ WallpaperBundle, ImageData };
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, 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 widget::{ Element, button, icon_button, text_edit, image as img_widget, text, container };
pub use text_shaping::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::text::TextAlign;
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::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 };
pub use app::run;
pub use app::{ try_run, RunError };
pub use smithay_client_toolkit::seat::keyboard::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,
		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,
		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,
		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;
	pub use crate::event_loop::diff_overlay_ids;
}
