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::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
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 config = SurferConfig::new(force_default_config)
116            .with_context(|| "Failed to load config file")?;
117        let channels = Channels::new();
118
119        // Basic translators that we can load quickly
120        let translators = all_translators();
121
122        let result = SystemState {
123            user: UserState {
124                config,
125                waves: None,
126                previous_waves: None,
127                count: None,
128                blacklisted_translators: HashSet::new(),
129                show_about: false,
130                show_keys: false,
131                show_gestures: false,
132                show_performance: false,
133                show_license: false,
134                show_logs: false,
135                show_cursor_window: false,
136                wanted_timeunit: TimeUnit::None,
137                time_string_format: None,
138                show_url_entry: false,
139                show_quick_start: false,
140                rename_target: None,
141                show_reload_suggestion: None,
142                variable_name_filter_focused: false,
143                variable_filter: VariableFilter::new(),
144                ui_zoom_factor: None,
145                state_file: None,
146                show_hierarchy: None,
147                show_menu: None,
148                show_ticks: None,
149                show_toolbar: None,
150                show_tooltip: None,
151                show_scope_tooltip: None,
152                show_default_timeline: None,
153                show_overview: None,
154                show_statusbar: None,
155                show_variable_direction: None,
156                show_open_sibling_state_file_suggestion: None,
157                align_names_right: None,
158                show_variable_indices: None,
159                show_empty_scopes: None,
160                show_parameters_in_scopes: None,
161                highlight_focused: None,
162                fill_high_values: None,
163                drag_started: false,
164                drag_source_idx: None,
165                drag_target_idx: None,
166                sidepanel_width: None,
167                primary_button_drag_behavior: None,
168                arrow_key_bindings: None,
169                clock_highlight_type: None,
170                hierarchy_style: None,
171                autoload_sibling_state_files: None,
172                autoreload_files: None,
173            },
174            translators,
175            channels,
176            progress_tracker: None,
177            command_prompt: command_prompt::CommandPrompt {
178                visible: false,
179                suggestions: vec![],
180                selected: 0,
181                new_selection: None,
182                new_cursor_pos: None,
183                previous_commands: vec![],
184            },
185            context: None,
186            wcp_server_thread: None,
187            wcp_server_address: None,
188            wcp_stop_signal: Arc::new(AtomicBool::new(false)),
189            wcp_running_signal: Arc::new(AtomicBool::new(false)),
190            wcp_greeted_signal: Arc::new(AtomicBool::new(false)),
191            wcp_client_capabilities: WcpClientCapabilities::new(),
192            gesture_start_location: None,
193            measure_start_location: None,
194            batch_messages: VecDeque::new(),
195            batch_messages_completed: false,
196            url: RefCell::new(String::new()),
197            command_prompt_text: RefCell::new(String::new()),
198            draw_data: RefCell::new(vec![None]),
199            variable_name_info_cache: RefCell::new(HashMap::new()),
200            last_canvas_rect: RefCell::new(None),
201            item_renaming_string: RefCell::new(String::new()),
202
203            items_to_expand: RefCell::new(vec![]),
204            char_to_add_to_prompt: RefCell::new(None),
205            expand_parameter_section: false,
206
207            url_callback: None,
208            continuous_redraw: false,
209            #[cfg(feature = "performance_plot")]
210            rendering_cpu_times: VecDeque::new(),
211            #[cfg(feature = "performance_plot")]
212            timing: RefCell::new(Timing::new()),
213            undo_stack: vec![],
214            redo_stack: vec![],
215        };
216
217        Ok(result)
218    }
219}
220
221impl From<UserState> for SystemState {
222    fn from(serializable_state: UserState) -> SystemState {
223        let mut state = SystemState::new().unwrap();
224        state.user = serializable_state;
225        state
226    }
227}