Skip to main content

libsurfer/
system_state.rs

1use eyre::Result;
2use std::{
3    cell::RefCell,
4    collections::{HashMap, VecDeque},
5    sync::{Arc, atomic::AtomicBool},
6};
7use tokio::task::JoinHandle;
8
9use egui::{Pos2, Rect};
10use surfer_translation_types::translator::VariableNameInfo;
11
12use crate::{
13    CachedDrawData, CanvasState, Channels, WcpClientCapabilities, command_prompt,
14    displayed_item::DisplayedItemRef,
15    hierarchy::ScopeExpandType,
16    message::Message,
17    state::UserState,
18    translation::{TranslatorList, all_translators},
19    wave_container::VariableRef,
20    wave_source::{LoadOptions, LoadProgress},
21};
22
23#[cfg(feature = "performance_plot")]
24use crate::benchmark::Timing;
25
26pub struct SystemState {
27    pub user: UserState,
28
29    /// Which translator to use for each variable
30    pub(crate) translators: TranslatorList,
31    /// Channels for messages generated by other threads
32    pub channels: Channels,
33
34    /// Tracks progress of file/variable loading operations.
35    pub(crate) progress_tracker: Option<LoadProgress>,
36
37    /// Buffer for the command input
38    pub(crate) command_prompt: command_prompt::CommandPrompt,
39
40    /// The context to egui, we need this to change the visual settings when the config is reloaded
41    pub(crate) context: Option<Arc<egui::Context>>,
42
43    /// List of batch messages which will executed as soon as possible
44    pub(crate) batch_messages: VecDeque<Message>,
45    pub(crate) batch_messages_completed: bool,
46
47    /// The WCP server
48    #[allow(unused)]
49    pub(crate) wcp_server_thread: Option<JoinHandle<()>>,
50    #[allow(unused)]
51    pub(crate) wcp_server_address: Option<String>,
52    #[allow(unused)]
53    pub(crate) wcp_stop_signal: Arc<AtomicBool>,
54    #[allow(unused)]
55    pub(crate) wcp_running_signal: Arc<AtomicBool>,
56    pub(crate) wcp_greeted_signal: Arc<AtomicBool>,
57    pub(crate) wcp_client_capabilities: WcpClientCapabilities,
58
59    /// The draw commands for every variable currently selected
60    // For performance reasons, these need caching so we have them in a RefCell for interior
61    // mutability
62    pub(crate) draw_data: RefCell<Vec<Option<CachedDrawData>>>,
63
64    pub(crate) variable_name_info_cache: RefCell<HashMap<VariableRef, Option<VariableNameInfo>>>,
65
66    pub(crate) gesture_start_location: Option<Pos2>,
67
68    pub(crate) measure_start_location: Option<Pos2>,
69
70    // Egui requires a place to store text field content between frames
71    pub(crate) url: RefCell<String>,
72    pub(crate) command_prompt_text: RefCell<String>,
73    pub(crate) last_canvas_rect: RefCell<Option<Rect>>,
74    pub(crate) surver_selected_file: RefCell<Option<usize>>,
75    pub(crate) surver_load_options: RefCell<LoadOptions>,
76
77    /// These items should be expanded into subfields in the next frame. Cleared after each
78    /// frame
79    pub(crate) items_to_expand: RefCell<Vec<(DisplayedItemRef, usize)>>,
80    /// Character to add to the command prompt if it is visible. This is only needed for
81    /// presentations at them moment.
82    pub(crate) char_to_add_to_prompt: RefCell<Option<char>>,
83    // This item works with the expand scope feature to determine what hierarchys to open
84    pub scope_ref_to_expand: RefCell<Option<ScopeExpandType>>,
85
86    // Benchmarking stuff
87    /// Invalidate draw commands every frame to make performance comparison easier
88    pub(crate) continuous_redraw: bool,
89    #[cfg(feature = "performance_plot")]
90    pub(crate) rendering_cpu_times: VecDeque<f32>,
91    #[cfg(feature = "performance_plot")]
92    pub(crate) timing: RefCell<Timing>,
93
94    // Undo and Redo stacks
95    pub(crate) undo_stack: Vec<CanvasState>,
96    pub(crate) redo_stack: Vec<CanvasState>,
97
98    pub(crate) url_callback: Option<Box<dyn Fn(String) -> Message + Send + 'static>>,
99
100    // Only used for testing
101    pub(crate) expand_parameter_section: bool,
102}
103
104impl SystemState {
105    pub fn new() -> Result<SystemState> {
106        Self::new_inner(false)
107    }
108
109    #[cfg(test)]
110    pub(crate) fn new_default_config() -> Result<SystemState> {
111        Self::new_inner(true)
112    }
113
114    fn new_inner(force_default_config: bool) -> Result<SystemState> {
115        let channels = Channels::new();
116
117        // Basic translators that we can load quickly
118        let translators = all_translators();
119
120        let result = SystemState {
121            user: UserState::new(force_default_config)?,
122            translators,
123            channels,
124            progress_tracker: None,
125            command_prompt: Default::default(),
126            context: None,
127            wcp_server_thread: None,
128            wcp_server_address: None,
129            wcp_stop_signal: Arc::new(AtomicBool::new(false)),
130            wcp_running_signal: Arc::new(AtomicBool::new(false)),
131            wcp_greeted_signal: Arc::new(AtomicBool::new(false)),
132            wcp_client_capabilities: WcpClientCapabilities::new(),
133            gesture_start_location: None,
134            measure_start_location: None,
135            batch_messages: VecDeque::new(),
136            batch_messages_completed: false,
137            url: RefCell::new(String::new()),
138            command_prompt_text: RefCell::new(String::new()),
139            draw_data: RefCell::new(vec![None]),
140            variable_name_info_cache: RefCell::new(HashMap::new()),
141            last_canvas_rect: RefCell::new(None),
142
143            items_to_expand: RefCell::new(vec![]),
144            char_to_add_to_prompt: RefCell::new(None),
145            scope_ref_to_expand: RefCell::new(None),
146            surver_selected_file: RefCell::new(None),
147            surver_load_options: RefCell::new(LoadOptions::Clear),
148            expand_parameter_section: false,
149
150            url_callback: None,
151            continuous_redraw: false,
152            #[cfg(feature = "performance_plot")]
153            rendering_cpu_times: VecDeque::new(),
154            #[cfg(feature = "performance_plot")]
155            timing: RefCell::new(Timing::new()),
156            undo_stack: vec![],
157            redo_stack: vec![],
158        };
159
160        Ok(result)
161    }
162}
163
164impl From<UserState> for SystemState {
165    fn from(serializable_state: UserState) -> SystemState {
166        let mut state = SystemState::new().unwrap();
167        state.user = serializable_state;
168        state
169    }
170}