Skip to main content

libsurfer/
system_state.rs

1use egui::{Pos2, Rect};
2use eyre::Result;
3use num::BigInt;
4use std::{
5    cell::RefCell,
6    collections::{HashMap, VecDeque},
7    sync::{Arc, atomic::AtomicBool},
8};
9use surfer_translation_types::translator::VariableNameInfo;
10use tokio::task::JoinHandle;
11
12use std::rc::Rc;
13
14use crate::{
15    CachedDrawData, CanvasState, Channels, WcpClientCapabilities, command_prompt,
16    displayed_item::DisplayedItemRef,
17    file_history::FileHistory,
18    frame_buffer::{FrameBufferArrayCache, FrameBufferContent, FrameBufferPixelCache},
19    hierarchy::{AllVariableCacheKey, ScopeExpandType, VariableListRow},
20    memory_viewer::{MemoryViewerCache, MemoryViewerState},
21    message::Message,
22    mousegestures::AnnotationKind,
23    state::UserState,
24    time::TimeInputState,
25    translation::{TranslatorList, all_translators},
26    wave_container::VariableRef,
27    wave_source::{LoadOptions, LoadProgress},
28};
29
30#[cfg(feature = "performance_plot")]
31use crate::benchmark::Timing;
32pub struct SystemState {
33    pub user: UserState,
34    pub(crate) file_history: FileHistory,
35    /// Which translator to use for each variable
36    pub(crate) translators: TranslatorList,
37    /// Channels for messages generated by other threads
38    pub channels: Channels,
39
40    /// Tracks progress of file/variable loading operations.
41    pub(crate) progress_tracker: Option<LoadProgress>,
42
43    /// Buffer for the command input
44    pub(crate) command_prompt: command_prompt::CommandPrompt,
45
46    /// The context to egui, we need this to change the visual settings when the config is reloaded
47    pub(crate) context: Option<Arc<egui::Context>>,
48
49    /// List of batch messages which will executed as soon as possible
50    pub(crate) batch_messages: VecDeque<Message>,
51    pub(crate) batch_messages_completed: bool,
52
53    /// The WCP server
54    #[allow(unused)]
55    pub(crate) wcp_server_thread: Option<JoinHandle<()>>,
56    #[allow(unused)]
57    pub(crate) wcp_server_address: Option<String>,
58    #[allow(unused)]
59    pub(crate) wcp_stop_signal: Arc<AtomicBool>,
60    #[allow(unused)]
61    pub(crate) wcp_running_signal: Arc<AtomicBool>,
62    pub(crate) wcp_greeted_signal: Arc<AtomicBool>,
63    pub(crate) wcp_client_capabilities: WcpClientCapabilities,
64
65    /// The draw commands for every variable currently selected
66    // For performance reasons, these need caching so we have them in a RefCell for interior
67    // mutability
68    pub(crate) draw_data: RefCell<Vec<Option<CachedDrawData>>>,
69
70    pub(crate) variable_name_info_cache: RefCell<HashMap<VariableRef, Option<VariableNameInfo>>>,
71
72    /// Monotonically increasing counter incremented when translators reload, to invalidate
73    /// the `all_variable_rows_cache` when name info changes without a waveform reload.
74    pub(crate) translator_generation: u64,
75    /// Cached result of `build_variable_rows` for `draw_all_variables`; rebuilt only when the
76    /// key changes (filter settings, wave data, or translator state).
77    pub(crate) all_variable_rows_cache: Option<(AllVariableCacheKey, Rc<Vec<VariableListRow>>)>,
78
79    pub(crate) gesture_start_location: Option<Pos2>,
80    pub(crate) gesture_start_time: Option<BigInt>,
81
82    pub(crate) measure_start_location: Option<Pos2>,
83
84    pub(crate) annotation_kind: Option<AnnotationKind>,
85
86    // Egui requires a place to store text field content between frames
87    pub(crate) url: RefCell<String>,
88    pub(crate) command_prompt_text: RefCell<String>,
89    pub(crate) last_canvas_rect: RefCell<Option<Rect>>,
90    pub(crate) surver_selected_file: RefCell<Option<usize>>,
91    pub(crate) surver_load_options: RefCell<LoadOptions>,
92
93    /// These items should be expanded into subfields in the next frame.
94    ///
95    /// Cleared after each frame
96    pub(crate) items_to_expand: RefCell<Vec<(DisplayedItemRef, usize)>>,
97    /// Character to add to the command prompt if it is visible.
98    ///
99    /// This is only needed for presentations at them moment.
100    pub(crate) char_to_add_to_prompt: RefCell<Option<char>>,
101    /// This item works with the expand scope feature to determine what hierarchys to open.
102    pub scope_ref_to_expand: RefCell<Option<ScopeExpandType>>,
103
104    pub(crate) time_widgets: RefCell<std::collections::HashMap<String, TimeInputState>>,
105    /// Map of widget id -> focused state.
106    pub(crate) text_edit_focused: std::collections::HashMap<String, bool>,
107    /// Map of widget id -> one-shot request focus flag.
108    pub(crate) text_edit_request_focus: std::collections::HashMap<String, bool>,
109    pub(crate) frame_buffer_content: Option<FrameBufferContent>,
110    pub(crate) frame_buffer_array_cache: Option<FrameBufferArrayCache>,
111    pub(crate) frame_buffer_pixel_cache: Option<FrameBufferPixelCache>,
112    pub(crate) memory_viewer: MemoryViewerState,
113    pub(crate) memory_viewer_cache: Option<MemoryViewerCache>,
114    // Benchmarking stuff
115    /// Invalidate draw commands every frame to make performance comparison easier
116    pub(crate) continuous_redraw: bool,
117    #[cfg(feature = "performance_plot")]
118    pub(crate) rendering_cpu_times: VecDeque<f32>,
119    #[cfg(feature = "performance_plot")]
120    pub(crate) timing: RefCell<Timing>,
121
122    // Undo and Redo stacks
123    pub(crate) undo_stack: Vec<CanvasState>,
124    pub(crate) redo_stack: Vec<CanvasState>,
125
126    // Toolbar group drag state
127    pub(crate) toolbar_dragging_group: Option<String>,
128    pub(crate) toolbar_drop_row: Option<usize>,
129    pub(crate) toolbar_drop_index: Option<usize>,
130    pub(crate) toolbar_drop_new_row: bool,
131
132    pub(crate) url_callback: Option<Box<dyn Fn(String) -> Message + Send + 'static>>,
133
134    // Only used for testing
135    pub(crate) expand_parameter_section: bool,
136
137    pub(crate) annotation_id_source: u64,
138    pub(crate) click_handled: bool,
139}
140
141impl SystemState {
142    pub fn new() -> Result<SystemState> {
143        Self::new_inner(false)
144    }
145
146    #[cfg(test)]
147    pub(crate) fn new_default_config() -> Result<SystemState> {
148        Self::new_inner(true)
149    }
150
151    fn new_inner(force_default_config: bool) -> Result<SystemState> {
152        let channels = Channels::new();
153        let user = UserState::new(force_default_config)?;
154        let file_history = FileHistory::load(user.config.behavior.file_history_size());
155
156        // Basic translators that we can load quickly
157        let translators = all_translators();
158
159        let result = SystemState {
160            user,
161            file_history,
162            translators,
163            channels,
164            progress_tracker: None,
165            command_prompt: Default::default(),
166            context: None,
167            wcp_server_thread: None,
168            wcp_server_address: None,
169            wcp_stop_signal: Arc::new(AtomicBool::new(false)),
170            wcp_running_signal: Arc::new(AtomicBool::new(false)),
171            wcp_greeted_signal: Arc::new(AtomicBool::new(false)),
172            wcp_client_capabilities: WcpClientCapabilities::new(),
173            gesture_start_location: None,
174            gesture_start_time: None,
175
176            measure_start_location: None,
177            batch_messages: VecDeque::new(),
178            batch_messages_completed: false,
179            url: RefCell::new(String::new()),
180            command_prompt_text: RefCell::new(String::new()),
181            draw_data: RefCell::new(vec![None]),
182            variable_name_info_cache: RefCell::new(HashMap::new()),
183            translator_generation: 0,
184            all_variable_rows_cache: None,
185            last_canvas_rect: RefCell::new(None),
186
187            items_to_expand: RefCell::new(vec![]),
188            char_to_add_to_prompt: RefCell::new(None),
189            scope_ref_to_expand: RefCell::new(None),
190            surver_selected_file: RefCell::new(None),
191            surver_load_options: RefCell::new(LoadOptions::Clear),
192            expand_parameter_section: false,
193            time_widgets: RefCell::new(std::collections::HashMap::new()),
194            text_edit_focused: std::collections::HashMap::new(),
195            text_edit_request_focus: std::collections::HashMap::new(),
196            frame_buffer_content: None,
197            frame_buffer_array_cache: None,
198            frame_buffer_pixel_cache: None,
199            memory_viewer: MemoryViewerState::default(),
200            memory_viewer_cache: None,
201            url_callback: None,
202            continuous_redraw: false,
203            #[cfg(feature = "performance_plot")]
204            rendering_cpu_times: VecDeque::new(),
205            #[cfg(feature = "performance_plot")]
206            timing: RefCell::new(Timing::new()),
207            undo_stack: vec![],
208            redo_stack: vec![],
209            annotation_kind: None,
210            annotation_id_source: 0,
211            click_handled: false,
212            toolbar_dragging_group: None,
213            toolbar_drop_row: None,
214            toolbar_drop_index: None,
215            toolbar_drop_new_row: false,
216        };
217
218        Ok(result)
219    }
220}
221
222impl From<UserState> for SystemState {
223    fn from(serializable_state: UserState) -> SystemState {
224        let mut state = SystemState::new().unwrap();
225        state.user = serializable_state;
226        state
227    }
228}