Skip to main content

libsurfer/
system_state.rs

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