khora_core/ui/app/context.rs
1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8
9//! `AppContext` — per-frame handle handed to [`super::App::update`].
10//!
11//! Wraps the backend's per-tick context (egui's `Context`, in
12//! practice) behind a neutral surface. Apps use it to:
13//!
14//! - install / swap the [`UiTheme`] and [`FontPack`] at startup;
15//! - request a repaint from a background thread or async event;
16//! - query the screen size for responsive layouts;
17//! - hand a callback the central paint region (which receives a
18//! `&mut dyn UiBuilder` — same trait the editor's panels use).
19
20use crate::ui::editor::UiBuilder;
21use crate::ui::{FontPack, UiTheme};
22
23/// Top-level app context — one per frame.
24pub trait AppContext {
25 /// Open the central drawing region. The closure receives a
26 /// `&mut dyn UiBuilder` and lays out the frame's content.
27 ///
28 /// Equivalent to "the whole window minus any panels installed at
29 /// the backend level". For tools without OS-level panels (the
30 /// hub) this is the only call needed per frame.
31 fn central(&mut self, f: &mut dyn FnMut(&mut dyn UiBuilder));
32
33 /// Apply a [`UiTheme`] to the underlying backend's visual
34 /// configuration. Idempotent — call again to swap palettes at
35 /// runtime.
36 fn set_theme(&mut self, theme: &UiTheme);
37
38 /// Install the fonts described by `pack`. Called once at startup
39 /// (or whenever fonts change).
40 fn set_fonts(&mut self, pack: &FontPack);
41
42 /// Logical screen size in pixels — `[width, height]`.
43 fn screen_size(&self) -> [f32; 2];
44
45 /// Pixels-per-point ratio (DPI scale). 1.0 on standard displays,
46 /// 2.0 on Retina, etc.
47 fn pixels_per_point(&self) -> f32 {
48 1.0
49 }
50
51 /// Ask the backend for another paint pass on the next available
52 /// frame, even if no input event would normally trigger one. Use
53 /// when an off-thread async task completes and the visible UI
54 /// must update.
55 fn request_repaint(&mut self);
56
57 /// Request the application window to close. The shutdown happens
58 /// at the end of the current frame (or whenever the backend gets
59 /// to it).
60 fn request_close(&mut self) {
61 // Default no-op — backends that support it override.
62 }
63}