mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-27 20:26:48 -06:00
refactor(ui-egui): move SheetApp methods and UI types out of lib.rs
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
/// Wall-clock milliseconds since the Unix epoch, for user-visible timestamps (Backstage's "last
|
||||
/// changed", toasts). It can jump when the system clock is adjusted, so it must not drive
|
||||
/// deadlines or pacing; use [`monotonic_ms`] for those.
|
||||
pub fn now_ms() -> f64 {
|
||||
gridcraft_engine::core::date::unix_now_ms().unwrap_or(0.0)
|
||||
}
|
||||
|
||||
/// Monotonic milliseconds since the first call, for screenshot deadlines and AutoSave pacing.
|
||||
///
|
||||
/// Deliberately separate from [`now_ms`]: a wall-clock adjustment must not extend (or expire) a
|
||||
/// screenshot deadline or save a workbook twice. Native uses [`std::time::Instant`]; wasm uses the
|
||||
/// browser's `performance.now()`, which is monotonic too.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[allow(clippy::disallowed_methods)] // the std clock is read only off wasm
|
||||
pub fn monotonic_ms() -> f64 {
|
||||
use std::sync::OnceLock;
|
||||
static START: OnceLock<std::time::Instant> = OnceLock::new();
|
||||
START.get_or_init(std::time::Instant::now).elapsed().as_secs_f64() * 1000.0
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
/// Web monotonic clock: the browser's `performance.now()`, or 0 when it is unavailable.
|
||||
pub fn monotonic_ms() -> f64 {
|
||||
web_sys::window().and_then(|window| window.performance()).map_or(0.0, |performance| performance.now())
|
||||
}
|
||||
+9
-1877
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
use super::*;
|
||||
|
||||
/// Host services the platform shell provides (file pickers, opening URLs).
|
||||
#[derive(Default)]
|
||||
pub struct Services {
|
||||
/// Desktop: discover configured printers on a worker.
|
||||
pub printers: Option<printing::Discover>,
|
||||
/// Desktop: submit the PDF with the chosen settings on a worker.
|
||||
pub print_native: Option<printing::Submit>,
|
||||
pub pick_open: Option<Box<dyn Fn() -> Option<String>>>,
|
||||
pub pick_save: Option<Box<dyn Fn(&str) -> Option<String>>>,
|
||||
/// Native picture picker (PNG/JPEG), separate from workbook opening.
|
||||
pub pick_picture: Option<Box<dyn Fn() -> Option<String>>>,
|
||||
/// Browser picture picker. Each dialog owns its inbox, so canceled picks cannot
|
||||
/// insert into a subsequent dialog or open the image as a workbook.
|
||||
pub pick_picture_async: Option<Box<dyn Fn(Inbox)>>,
|
||||
pub open_url: Option<Box<dyn Fn(&str)>>,
|
||||
/// Publish HTML and its plain-text alternative together. `Ok` means the host owns the
|
||||
/// write (including any asynchronous fallback); an immediate error uses egui's text path.
|
||||
pub copy_html: Option<Box<dyn FnMut(&str, &str) -> Result<(), String>>>,
|
||||
/// Read the HTML flavour of the system clipboard when the user pastes text, so cells the
|
||||
/// source spreadsheet recorded as numbers stay numbers ("Rp10,000.00" → 10000). `None` from
|
||||
/// the host pastes the plain text alone.
|
||||
pub paste_html: Option<Box<dyn FnMut() -> Option<String>>>,
|
||||
/// Read the system clipboard's plain text for the ribbon and menu Paste commands (Cmd/Ctrl+V
|
||||
/// gets it from egui's `Event::Paste`). `None` from the host, or no service (web), pastes
|
||||
/// GridCraft's own clipboard.
|
||||
pub paste_text: Option<Box<dyn FnMut() -> Option<String>>>,
|
||||
/// Web: deliver a file to the user (name, bytes).
|
||||
pub download: Option<Box<dyn Fn(&str, &[u8])>>,
|
||||
/// Web: start an asynchronous file pick; the bytes arrive later in `inbox`.
|
||||
pub open_async: Option<Box<dyn Fn()>>,
|
||||
/// Files delivered asynchronously (name, bytes), opened on the next frame.
|
||||
pub inbox: Option<Inbox>,
|
||||
/// Web: hand PDF bytes to the browser's print flow directly (no download,
|
||||
/// no intermediate file) — opens the system print dialog on that PDF.
|
||||
pub print: Option<Box<dyn Fn(&[u8])>>,
|
||||
}
|
||||
|
||||
/// Shared queue of files read asynchronously (browser file picker, drag and drop).
|
||||
pub type Inbox = std::sync::Arc<std::sync::Mutex<Vec<(String, Vec<u8>)>>>;
|
||||
|
||||
/// Which parts of the app's own window chrome are drawn. Everything is on by default; a host
|
||||
/// that embeds the sheet in its own window (and owns files itself) can turn off the title bar
|
||||
/// and the File tab, whose Backstage view then never opens. Not persisted: it describes the
|
||||
/// host, not a user preference.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Chrome {
|
||||
/// The title bar: AutoSave, Home, Save, Undo/Redo, the file name, Comments, Share, Search and
|
||||
/// the theme switch.
|
||||
pub title_bar: bool,
|
||||
/// The ribbon's File tab and the Backstage view it opens (also reached by keyboard and
|
||||
/// commands such as `ui.backstage`).
|
||||
pub file_tab: bool,
|
||||
}
|
||||
|
||||
impl Default for Chrome {
|
||||
fn default() -> Self {
|
||||
Chrome { title_bar: true, file_tab: true }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/// Per-sheet view state (scroll position in sheet points).
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct SheetView {
|
||||
pub scroll: egui::Vec2,
|
||||
}
|
||||
|
||||
/// Severity of a notice shown in the info bar under the ribbon.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum NoticeKind {
|
||||
Info,
|
||||
Warning,
|
||||
}
|
||||
|
||||
/// An answer to the Save Changes question.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum SaveAnswer {
|
||||
Save,
|
||||
DontSave,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
/// One open window, as View › Switch Windows and the macOS Window menu list it.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct OpenWindow {
|
||||
/// The window's id, the `window` param of `view.switchWindows`.
|
||||
pub window: u64,
|
||||
/// Its workbook's `DocState::uid`.
|
||||
pub doc: u64,
|
||||
pub title: String,
|
||||
pub dirty: bool,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
impl OpenWindow {
|
||||
/// The title ("Book1", or "Book1:2" for a workbook's second window), with a bullet after it
|
||||
/// while the workbook has unsaved changes.
|
||||
pub fn label(&self) -> String {
|
||||
if self.dirty { format!("{} •", self.title) } else { self.title.clone() }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user