libsurfer/
system_state.rs

1use eyre::{Context, Result};
2use std::{
3    cell::RefCell,
4    collections::{HashMap, HashSet, VecDeque},
5    sync::{atomic::AtomicBool, Arc},
6};
7use tokio::task::JoinHandle;
8
9use egui::{Pos2, Rect};
10use surfer_translation_types::translator::VariableNameInfo;
11
12use crate::{
13    command_prompt,
14    config::SurferConfig,
15    displayed_item::DisplayedItemRef,
16    message::Message,
17    state::UserState,
18    time::TimeUnit,
19    translation::{all_translators, TranslatorList},
20    variable_filter::VariableFilter,
21    wave_container::{ScopeRef, VariableRef},
22    wave_source::LoadProgress,
23    CachedDrawData, CanvasState, Channels, WcpClientCapabilities,
24};
25
26#[cfg(feature = "performance_plot")]
27use crate::benchmark::Timing;
28
29pub struct SystemState {
30    pub user: UserState,
31
32    /// Which translator to use for each variable
33    pub(crate) translators: TranslatorList,
34    /// Channels for messages generated by other threads
35    pub channels: Channels,
36
37    /// Tracks progress of file/variable loading operations.
38    pub(crate) progress_tracker: Option<LoadProgress>,
39
40    /// Buffer for the command input
41    pub(crate) command_prompt: command_prompt::CommandPrompt,
42
43    /// The context to egui, we need this to change the visual settings when the config is reloaded
44    pub(crate) context: Option<Arc<egui::Context>>,
45
46    /// List of batch messages which will executed as soon as possible
47    pub(crate) batch_messages: VecDeque<Message>,
48    pub(crate) batch_messages_completed: bool,
49
50    /// The WCP server
51    #[allow(unused)]
52    pub(crate) wcp_server_thread: Option<JoinHandle<()>>,
53    #[allow(unused)]
54    pub(crate) wcp_server_address: Option<String>,
55    #[allow(unused)]
56    pub(crate) wcp_stop_signal: Arc<AtomicBool>,
57    #[allow(unused)]
58    pub(crate) wcp_running_signal: Arc<AtomicBool>,
59    pub(crate) wcp_greeted_signal: Arc<AtomicBool>,
60    pub(crate) wcp_client_capabilities: WcpClientCapabilities,
61
62    /// The draw commands for every variable currently selected
63    // For performance reasons, these need caching so we have them in a RefCell for interior
64    // mutability
65    pub(crate) draw_data: RefCell<Vec<Option<CachedDrawData>>>,
66
67    pub(crate) variable_name_info_cache: RefCell<HashMap<VariableRef, Option<VariableNameInfo>>>,
68
69    pub(crate) gesture_start_location: Option<Pos2>,
70
71    pub(crate) measure_start_location: Option<Pos2>,
72
73    // Egui requires a place to store text field content between frames
74    pub(crate) url: RefCell<String>,
75    pub(crate) command_prompt_text: RefCell<String>,
76    pub(crate) last_canvas_rect: RefCell<Option<Rect>>,
77    pub(crate) item_renaming_string: RefCell<String>,
78
79    /// These items should be expanded into subfields in the next frame. Cleared after each
80    /// frame
81    pub(crate) items_to_expand: RefCell<Vec<(DisplayedItemRef, usize)>>,
82    /// Character to add to the command prompt if it is visible. This is only needed for
83    /// presentations at them moment.
84    pub(crate) char_to_add_to_prompt: RefCell<Option<char>>,
85    // This item works with the expand scope feature to determine what hierarchys to open
86    pub scope_ref_to_expand: RefCell<Option<ScopeRef>>,
87
88    // Benchmarking stuff
89    /// Invalidate draw commands every frame to make performance comparison easier
90    pub(crate) continuous_redraw: bool,
91    #[cfg(feature = "performance_plot")]
92    pub(crate) rendering_cpu_times: VecDeque<f32>,
93    #[cfg(feature = "performance_plot")]
94    pub(crate) timing: RefCell<Timing>,
95
96    // Undo and Redo stacks
97    pub(crate) undo_stack: Vec<CanvasState>,
98    pub(crate) redo_stack: Vec<CanvasState>,
99
100    pub(crate) url_callback: Option<Box<dyn Fn(String) -> Message + Send + 'static>>,
101
102    // Only used for testing
103    pub(crate) expand_parameter_section: bool,
104}
105
106impl SystemState {
107    pub fn new() -> Result<SystemState> {
108        Self::new_inner(false)
109    }
110
111    #[cfg(test)]
112    pub(crate) fn new_default_config() -> Result<SystemState> {
113        Self::new_inner(true)
114    }
115
116    fn new_inner(force_default_config: bool) -> Result<SystemState> {
117        let config = SurferConfig::new(force_default_config)
118            .with_context(|| "Failed to load config file")?;
119        let channels = Channels::new();
120
121        // Basic translators that we can load quickly
122        let translators = all_translators();
123
124        let result = SystemState {
125            user: UserState {
126                config,
127                waves: None,
128                previous_waves: None,
129                count: None,
130                blacklisted_translators: HashSet::new(),
131                show_about: false,
132                show_keys: false,
133                show_gestures: false,
134                show_performance: false,
135                show_license: false,
136                show_logs: false,
137                show_cursor_window: false,
138                wanted_timeunit: TimeUnit::None,
139                time_string_format: None,
140                show_url_entry: false,
141                show_quick_start: false,
142                rename_target: None,
143                show_reload_suggestion: None,
144                variable_name_filter_focused: false,
145                variable_filter: VariableFilter::new(),
146                ui_zoom_factor: None,
147                state_file: None,
148                show_hierarchy: None,
149                show_menu: None,
150                show_ticks: None,
151                show_toolbar: None,
152                show_tooltip: None,
153                show_scope_tooltip: None,
154                show_default_timeline: None,
155                show_overview: None,
156                show_statusbar: None,
157                show_variable_direction: None,
158                show_open_sibling_state_file_suggestion: None,
159                align_names_right: None,
160                show_variable_indices: None,
161                show_empty_scopes: None,
162                show_parameters_in_scopes: None,
163                highlight_focused: None,
164                fill_high_values: None,
165                drag_started: false,
166                drag_source_idx: None,
167                drag_target_idx: None,
168                sidepanel_width: None,
169                primary_button_drag_behavior: None,
170                arrow_key_bindings: None,
171                clock_highlight_type: None,
172                hierarchy_style: None,
173                autoload_sibling_state_files: None,
174                autoreload_files: None,
175            },
176            translators,
177            channels,
178            progress_tracker: None,
179            command_prompt: command_prompt::CommandPrompt {
180                visible: false,
181                suggestions: vec![],
182                selected: 0,
183                new_selection: None,
184                new_cursor_pos: None,
185                previous_commands: vec![],
186            },
187            context: None,
188            wcp_server_thread: None,
189            wcp_server_address: None,
190            wcp_stop_signal: Arc::new(AtomicBool::new(false)),
191            wcp_running_signal: Arc::new(AtomicBool::new(false)),
192            wcp_greeted_signal: Arc::new(AtomicBool::new(false)),
193            wcp_client_capabilities: WcpClientCapabilities::new(),
194            gesture_start_location: None,
195            measure_start_location: None,
196            batch_messages: VecDeque::new(),
197            batch_messages_completed: false,
198            url: RefCell::new(String::new()),
199            command_prompt_text: RefCell::new(String::new()),
200            draw_data: RefCell::new(vec![None]),
201            variable_name_info_cache: RefCell::new(HashMap::new()),
202            last_canvas_rect: RefCell::new(None),
203            item_renaming_string: RefCell::new(String::new()),
204
205            items_to_expand: RefCell::new(vec![]),
206            char_to_add_to_prompt: RefCell::new(None),
207            scope_ref_to_expand: RefCell::new(None),
208            expand_parameter_section: false,
209
210            url_callback: None,
211            continuous_redraw: false,
212            #[cfg(feature = "performance_plot")]
213            rendering_cpu_times: VecDeque::new(),
214            #[cfg(feature = "performance_plot")]
215            timing: RefCell::new(Timing::new()),
216            undo_stack: vec![],
217            redo_stack: vec![],
218        };
219
220        Ok(result)
221    }
222}
223
224impl From<UserState> for SystemState {
225    fn from(serializable_state: UserState) -> SystemState {
226        let mut state = SystemState::new().unwrap();
227        state.user = serializable_state;
228        state
229    }
230}