Skip to main content

fret_runtime/
window_command_availability.rs

1use std::collections::HashMap;
2
3use fret_core::AppWindowId;
4
5/// Window-scoped command availability snapshots published by the app layer.
6///
7/// This is a data-only integration seam used by cross-surface command gating (menus, command
8/// palette, shortcuts) without depending on UI-kit or app-specific model types.
9#[derive(Debug, Default)]
10pub struct WindowCommandAvailabilityService {
11    by_window: HashMap<AppWindowId, WindowCommandAvailability>,
12}
13
14impl WindowCommandAvailabilityService {
15    pub fn snapshot(&self, window: AppWindowId) -> Option<&WindowCommandAvailability> {
16        self.by_window.get(&window)
17    }
18
19    pub fn set_snapshot(&mut self, window: AppWindowId, availability: WindowCommandAvailability) {
20        self.by_window.insert(window, availability);
21    }
22
23    pub fn update_snapshot(
24        &mut self,
25        window: AppWindowId,
26        f: impl FnOnce(&mut WindowCommandAvailability),
27    ) {
28        let availability = self.by_window.entry(window).or_default();
29        f(availability);
30    }
31
32    pub fn set_edit_availability(&mut self, window: AppWindowId, can_undo: bool, can_redo: bool) {
33        self.update_snapshot(window, |availability| {
34            availability.edit_can_undo = can_undo;
35            availability.edit_can_redo = can_redo;
36        });
37    }
38
39    pub fn set_router_availability(
40        &mut self,
41        window: AppWindowId,
42        can_back: bool,
43        can_forward: bool,
44    ) {
45        self.update_snapshot(window, |availability| {
46            availability.router_can_back = can_back;
47            availability.router_can_forward = can_forward;
48        });
49    }
50
51    pub fn remove_window(&mut self, window: AppWindowId) {
52        self.by_window.remove(&window);
53    }
54}
55
56/// Minimal command availability surface (v1).
57///
58/// This is intentionally conservative: it only captures state that is hard to infer at the runner
59/// boundary and is needed for native OS menus to present correct enable/disable states.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct WindowCommandAvailability {
62    pub edit_can_undo: bool,
63    pub edit_can_redo: bool,
64    pub router_can_back: bool,
65    pub router_can_forward: bool,
66}
67
68impl Default for WindowCommandAvailability {
69    fn default() -> Self {
70        Self {
71            edit_can_undo: true,
72            edit_can_redo: true,
73            router_can_back: false,
74            router_can_forward: false,
75        }
76    }
77}