pub struct TeksiloAppBuilder { /* private fields */ }Expand description
Builder for a Teksilo application.
Implementations§
Source§impl TeksiloAppBuilder
impl TeksiloAppBuilder
pub fn new() -> Self
Sourcepub fn application(
self,
qualifier: &str,
organization: &str,
application: &str,
) -> Self
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.
Sourcepub fn app_paths(self, paths: AppPaths) -> Self
pub fn app_paths(self, paths: AppPaths) -> Self
Provide an explicit AppPaths. Used
for portable-mode apps and tests.
Sourcepub fn configured_app_paths(&self) -> Option<&AppPaths>
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.
Sourcepub fn settings(self, bundle: SettingsBundle) -> Self
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.
Sourcepub fn settings_watch(self, enabled: bool) -> Self
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.
Sourcepub fn telemetry(self, bundle: TelemetryBundle) -> Self
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).
Sourcepub fn register_tooltips(self, contents: Vec<TooltipContent>) -> Self
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.
Sourcepub fn event_source<S: EventSource>(self, source: S) -> Self
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.
Sourcepub fn app_state<T: 'static>(self, value: T) -> Self
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.
Sourcepub fn register_post_root(self, hook: DefaultPostRoot) -> Self
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.
Sourcepub fn register_app_event_observer(
self,
observer: impl Fn(&AppEvent) + 'static,
) -> Self
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.
Sourcepub fn install_file_dialog(self) -> Self
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.
Sourcepub fn install_external_dnd(self) -> Self
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.
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.
Sourcepub fn i18n(self, config: I18nConfig) -> Self
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.
Sourcepub fn theme_mode(self, mode: ThemeMode) -> Self
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.
pub fn typesetter(self, typesetter: SharedTypesetter) -> Self
Sourcepub fn register_fonts(self, registrar: impl FontRegistrar + 'static) -> Self
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();Sourcepub fn on_app_event(self, handler: impl FnMut(&AppEvent) + 'static) -> Self
pub fn on_app_event(self, handler: impl FnMut(&AppEvent) + 'static) -> Self
Register a handler for AppEvents received from background threads.
Sourcepub fn on_external_with_ctx(
self,
handler: impl FnMut(&(dyn Any + Send), &mut EventContext<'_>) -> bool + 'static,
) -> Self
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
})Sourcepub fn on_ready(self, handler: impl FnOnce(AppEventProxy) + 'static) -> Self
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).
Sourcepub fn on_loop_tick(
self,
poll_source: Rc<Cell<bool>>,
tick: impl FnMut() -> bool + 'static,
) -> Self
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.
Sourcepub fn initial_window(self, config: WindowConfig) -> Self
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();Sourcepub fn build_headless(self) -> HeadlessApp
pub fn build_headless(self) -> HeadlessApp
Build a headless app for testing (no window, no GPU).
Trait Implementations§
Source§impl Default for TeksiloAppBuilder
impl Default for TeksiloAppBuilder
Source§impl TeksiloAppBuilderAutomationExt for TeksiloAppBuilder
Available on debug-assertions enabled only.
impl TeksiloAppBuilderAutomationExt for TeksiloAppBuilder
Source§fn install_automation_bridge_in_debug(self) -> Self
fn install_automation_bridge_in_debug(self) -> Self
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§
impl !RefUnwindSafe for TeksiloAppBuilder
impl !Send for TeksiloAppBuilder
impl !Sync for TeksiloAppBuilder
impl !UnwindSafe for TeksiloAppBuilder
impl Freeze for TeksiloAppBuilder
impl Unpin for TeksiloAppBuilder
impl UnsafeUnpin for TeksiloAppBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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