Skip to main content

TeksiloAppBuilder

Struct TeksiloAppBuilder 

Source
pub struct TeksiloAppBuilder { /* private fields */ }
Expand description

Builder for a Teksilo application.

Implementations§

Source§

impl TeksiloAppBuilder

Source

pub fn new() -> Self

Source

pub fn application( self, qualifier: &str, organization: &str, application: &str, ) -> Self

Identify the application for OS-correct path resolution. The (qualifier, organization, application) triple follows the directories convention (e.g. ("eu", "FernTech", "Skribisto")). Required when settings is used.

§Panics

Panics if the OS does not expose a usable home directory (typically a sandboxed environment with HOME unset). Use app_paths to supply an explicit path in that situation.

Source

pub fn app_paths(self, paths: AppPaths) -> Self

Provide an explicit AppPaths. Used for portable-mode apps and tests.

Source

pub fn configured_app_paths(&self) -> Option<&AppPaths>

Read the currently-configured AppPaths, if any. Used by builder-extension traits (e.g. install_toast in teksilo) that need to open persistent files at install time before run fires.

Source

pub fn settings(self, bundle: SettingsBundle) -> Self

Configure the persistence bundle. When run/build_headless fires, the bundle is opened against the configured AppPaths and every active service is registered in app_state, where it becomes reachable via the SettingsExt trait.

§Panics

Panics during run / build_headless if no AppPaths was configured first via application or app_paths.

Source

pub fn settings_watch(self, enabled: bool) -> Self

Enable or disable the live cross-process settings-reload watcher started in run (windowed apps only — build_headless never starts one, since there is no event loop to post the reload event through).

On by default whenever settings is configured: this is what makes a peer process’s write to a shared settings file (Skribisto’s one-process-per-project model shares general.toml / recents.toml / window_state.toml across every open project) show up in this process’s UI with no restart and no polling. Pass false to opt out — e.g. a sandboxed test environment with no usable filesystem watcher, or an app that wants to poll Reloadable::reload_from_disk on its own schedule instead.

Source

pub fn telemetry(self, bundle: TelemetryBundle) -> Self

Configure the telemetry stack (teksilo-telemetry). Mirrors settings: the bundle is opened during run / build_headless against the configured AppPaths and the live SettingsStore, and the resulting handles (OpenedTelemetry, TelemetryContext, DynamicReporter) are registered into app_state. Apps reach them via teksilo_telemetry::TelemetryExt (use teksilo_telemetry::TelemetryExt;).

§Panics

Panics during run / build_headless if no AppPaths was configured first via application or app_paths, or if no settings bundle was registered (the telemetry consent file is opened via the same AppPaths and the endpoint-override key is read from the SettingsStore).

Source

pub fn register_tooltips(self, contents: Vec<TooltipContent>) -> Self

Register the application’s tooltip string catalog.

Each TooltipContent in the list maps a short stable key (referenced from inline markup as [label](:key)) to a translatable body, an optional long-form “more” body revealed by the Accordion disclosure inside a sticky rich tooltip, and an optional keyboard shortcut (literal label — registry-backed auto-lookup is a follow-up).

This is a single-call registration: the list is the application’s complete tooltip catalog. Call once at app boot, before run(). Calling multiple times panics in debug builds.

use teksilo_widgets::tooltip::TooltipContent;

TeksiloAppBuilder::new()
    .register_tooltips(vec![
        TooltipContent::new("save-as", tr!(save_as_tooltip))
            .for_shortcut("app.save_as"),
        TooltipContent::new("autosave", tr!(autosave_tooltip))
            .with_more(tr!(autosave_tooltip_more)),
    ])
    // …

Multiple calls accumulate, like Self::register_fonts and I18nConfig::compile_in, so an application can compose its own catalogue with catalogues shipped by plugins, extensions or sibling crates. Assigning here instead would mean a contributor registering one tooltip silently deleted every tooltip the application had — the failure has no error and no warning, it just makes rich tooltips stop resolving their [label](:key) links.

On a duplicate key the first registration wins; see install_tooltip_registry.

Source

pub fn event_source<S: EventSource>(self, source: S) -> Self

Register a backend event source. Widgets can then call BuildContext::subscribe_event(origin, callback) from inside their build() method to receive events on the UI thread.

Only one source per application is supported. Subsequent calls replace the previously registered source.

Source

pub fn app_state<T: 'static>(self, value: T) -> Self

Register an application-defined value of type T that any widget can retrieve via BuildContext::app_state::<T>().

Each type T may be registered at most once; a subsequent call with the same type replaces the previous value. To share multiple values of the same logical kind, wrap each in a distinct newtype.

Source

pub fn register_post_root(self, hook: DefaultPostRoot) -> Self

Register an app-wide DefaultPostRoot hook that wraps every window’s root after its root_builder runs.

Unlike app_state(DefaultPostRoot::new(..)) — which stores a single type-keyed value and so silently replaces any previously-registered hook — this composes: each registered hook runs in call order, each wrapping the previous one’s result. So an app that installs the debug inspector AND the toast host (or any other post-root chrome) gets both wrappers, not just whichever was installed last. The earlier-registered hook is the innermost wrapper (it sees the raw user root); the latest is outermost.

All framework installers that splice window-level chrome (install_inspector_in_debug, install_toast*) route through this, so their order of installation no longer matters for correctness.

Source

pub fn register_app_event_observer( self, observer: impl Fn(&AppEvent) + 'static, ) -> Self

Register a composable observer that runs on every AppEvent, in addition to (never instead of) the single on_app_event handler.

Unlike on_app_event — which stores a single Option<Box<dyn FnMut(&AppEvent)>> and so silently replaces any previously registered handler — this composes: each registered observer runs, in call order, on every AppEvent delivered to the UI thread. So a framework extension that needs to react to AppEvents (e.g. teksilo::install_toast turning AppEvent::SettingsWriteFailed into a toast) can register its own observer without clobbering the application’s own on_app_event handler, or being clobbered by it, regardless of install order. Mirrors register_post_root’s type-keyed app_state composition pattern exactly, but for event observation instead of post-root window chrome.

See TeksiloAppHandler::user_event for the dispatch order: the on_app_event handler runs first, then every composed observer.

Source

pub fn install_file_dialog(self) -> Self

Install the rfd-backed native file-dialog service. Registers a FileDialogHandle wrapping an RfdAsyncBackend into the app-state registry. Reachable from any handler via ctx.app_state::<FileDialogHandle>(), or — with use teksilo_platform::file_dialog::EventContextFileDialogExt; — directly via ctx.pick_file(req, |result, ctx| ...).

Apps that ship a custom or mock backend bypass this and call .app_state(FileDialogHandle::new(my_backend)) directly.

Source

pub fn install_external_dnd(self) -> Self

Install the external (OS) drag-and-drop service. Registers an ExternalDndHandle wrapping the platform’s default backend (default_backend — raw NSDraggingDestination on macOS, OLE on Windows, wl_data_device on Wayland, a no-op on X11) into the app-state registry.

Once installed, every window is registered as an OS drop target on creation (and detached on close) by the window manager. Drops surface to widgets through the normal drag handlers (on_drag_hover / on_drag_leave / on_drop) with payload.is_external() true — the ready-made DropZone widget consumes them.

Apps that ship a custom backend bypass this and call .app_state(ExternalDndHandle::new(my_backend)) directly.

Source

pub fn install_native_menu(self) -> Self

Install the native (OS) menu service. Registers a NativeMenuHandle wrapping the platform’s default backend (a real NSMenu on macOS, a no-op elsewhere) into the app-state registry.

Once installed, a MenuBar built with from_model(..).native_on_macos(..) mirrors its MenuModel into the global menu bar on macOS, and item activations route back through the usual Intent/Action pipeline. The global menu follows window focus automatically (see the WindowEvent::Focused arm).

Apps that ship a custom backend bypass this and call .app_state(NativeMenuHandle::new(my_backend)) directly.

Source

pub fn i18n(self, config: I18nConfig) -> Self

Register an I18nConfig. Constructs an I18nManager at startup, installs it on the thread-local, and seeds the widget tree with the resolved initial locale and layout direction. Without this call, tr!-expanded code falls back to returning the literal key as a placeholder.

Source

pub fn theme(self, theme: Theme) -> Self

Set a fixed theme (implies ThemeMode::Manual).

Source

pub fn theme_mode(self, mode: ThemeMode) -> Self

Set how the application resolves its theme.

  • ThemeMode::Manual — use the theme set via .theme() (default).
  • ThemeMode::FollowSystem — auto-switch between light/dark built-in themes.
  • ThemeMode::Native — read colors from OS desktop environment config.
Source

pub fn typesetter(self, typesetter: SharedTypesetter) -> Self

Source

pub fn register_fonts(self, registrar: impl FontRegistrar + 'static) -> Self

Register additional fonts (e.g. a theme’s font family) into the shared typesetter at startup, before any text is shaped — so a theme that sets typography.body.family = "Roboto" resolves correctly instead of silently falling back to the bundled Inter.

A theme preset typically exposes a FontRegistrar the app passes here:

TeksiloAppBuilder::new()
    .theme(material3::light())
    .register_fonts(material3::font_registrar())
    .run();
Source

pub fn on_app_event(self, handler: impl FnMut(&AppEvent) + 'static) -> Self

Register a handler for AppEvents received from background threads.

Source

pub fn on_external_with_ctx( self, handler: impl FnMut(&(dyn Any + Send), &mut EventContext<'_>) -> bool + 'static, ) -> Self

Register a router for AppEvent::External payloads that needs to open, find or focus windows — see ExternalCtxHandler.

on_app_event is the hook for reacting to an event; this is the hook for acting on the window set because of one. The difference is not stylistic: on_app_event receives &AppEvent and nothing else, and EventContext::open_window panics on a standalone context, so there is no way to open a window from there at all.

The handler runs against the focused window’s tree (or the primary window’s) with a real WindowOps sink, and is consulted only for payloads that no framework router and no built-in downcast arm claimed — so it never has to defend against CloseWindowRequest and friends. Return true when the payload was yours.

Unlike register_app_event_observer, this is a single slot: calling it twice replaces the first router, the same way on_app_event does.

// A single-instance app: a second launch forwards its argv over a socket,
// the listener posts it with `AppEventProxy::send_external`, and this
// opens (or raises) the document window — the "document window" recipe in
// docs/multi-window.md, driven from off the UI thread.
.on_external_with_ctx(move |payload, ctx| {
    let Some(req) = payload.downcast_ref::<OpenDocument>() else {
        return false;
    };
    let wid = window_id_for(&req.path);
    match ctx.find_window(&wid) {
        Some(id) => ctx.focus_window(id),
        None => { ctx.open_window(document_window_config(&req.path)); }
    }
    true
})
Source

pub fn on_ready(self, handler: impl FnOnce(AppEventProxy) + 'static) -> Self

Register a callback that receives an AppEventProxy once the event loop is ready. Use this to hand the proxy to background threads that need to post commands. May be called more than once; all registered callbacks fire in order (e.g. install_async registers one to wire the executor’s waker).

Source

pub fn on_loop_tick( self, poll_source: Rc<Cell<bool>>, tick: impl FnMut() -> bool + 'static, ) -> Self

Register a closure run once per event-loop turn (at the top of about_to_wait) plus a shared poll flag. Returning true from the closure means it advanced work that may have mutated UI state, which triggers a repaint of all windows. While poll_source is set the loop stays in ControlFlow::Poll so the closure keeps running; when it clears, the loop sleeps until the next event (off-thread wakes arrive via AppEventProxy).

General-purpose and async-agnostic — teksilo-app only ever sees FnMut. The optional teksilo-async crate uses this to drive a main-thread executor; nothing in the core loop depends on a runtime.

Source

pub fn initial_window(self, config: WindowConfig) -> Self

Configure the initial window. Required — every app must open at least one window at startup. The single canonical entry point: build a WindowConfig and pass it here.

TeksiloAppBuilder::new()
    .theme(teksilo_core::presets::intui::light())
    .initial_window(
        WindowConfig::new()
            .title("My App")
            .size(800, 600)
            .root(|tree, _state| tree.add(MyRoot::new())),
    )
    .run();
Source

pub fn build_headless(self) -> HeadlessApp

Build a headless app for testing (no window, no GPU).

Source

pub fn run(self)

Build and run the application with windowed rendering.

Trait Implementations§

Source§

impl Default for TeksiloAppBuilder

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl TeksiloAppBuilderAutomationExt for TeksiloAppBuilder

Available on debug-assertions enabled only.
Source§

fn install_automation_bridge_in_debug(self) -> Self

In a debug build: generate a per-process token, then on on_ready bind a private 0600 Unix socket, print its path + TEKSILO_AUTOMATION_TOKEN=<uuid> to stderr, and spawn the bridge thread. The announcement follows the bind, so the printed path is connectable the instant it appears. In a release build (or on a non-Unix target): a no-op returning self.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more