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    frame_buffer::{FrameBufferArrayCache, FrameBufferContent, FrameBufferPixelCache},
16    hierarchy::ScopeExpandType,
17    message::Message,
18    state::UserState,
19    time::TimeInputState,
20    translation::{TranslatorList, all_translators},
21    wave_container::VariableRef,
22    wave_source::{LoadOptions, LoadProgress},
23};
24
25#[cfg(feature = "performance_plot")]
26use crate::benchmark::Timing;
27
28pub struct SystemState {
29    pub user: UserState,
30
31    /// Which translator to use for each variable
32    pub(crate) translators: TranslatorList,
33    /// Channels for messages generated by other threads
34    pub channels: Channels,
35
36    /// Tracks progress of file/variable loading operations.
37    pub(crate) progress_tracker: Option<LoadProgress>,
38
39    /// Buffer for the command input
40    pub(crate) command_prompt: command_prompt::CommandPrompt,
41
42    /// The context to egui, we need this to change the visual settings when the config is reloaded
43    pub(crate) context: Option<Arc<egui::Context>>,
44
45    /// List of batch messages which will executed as soon as possible
46    pub(crate) batch_messages: VecDeque<Message>,
47    pub(crate) batch_messages_completed: bool,
48
49    /// The WCP server
50    #[allow(unused)]
51    pub(crate) wcp_server_thread: Option<JoinHandle<()>>,
52    #[allow(unused)]
53    pub(crate) wcp_server_address: Option<String>,
54    #[allow(unused)]
55    pub(crate) wcp_stop_signal: Arc<AtomicBool>,
56    #[allow(unused)]
57    pub(crate) wcp_running_signal: Arc<AtomicBool>,
58    pub(crate) wcp_greeted_signal: Arc<AtomicBool>,
59    pub(crate) wcp_client_capabilities: WcpClientCapabilities,
60
61    /// The draw commands for every variable currently selected
62    // For performance reasons, these need caching so we have them in a RefCell for interior
63    // mutability
64    pub(crate) draw_data: RefCell<Vec<Option<CachedDrawData>>>,
65
66    pub(crate) variable_name_info_cache: RefCell<HashMap<VariableRef, Option<VariableNameInfo>>>,
67
68    pub(crate) gesture_start_location: Option<Pos2>,
69
70    pub(crate) measure_start_location: Option<Pos2>,
71
72    // Egui requires a place to store text field content between frames
73    pub(crate) url: RefCell<String>,
74    pub(crate) command_prompt_text: RefCell<String>,
75    pub(crate) last_canvas_rect: RefCell<Option<Rect>>,
76    pub(crate) surver_selected_file: RefCell<Option<usize>>,
77    pub(crate) surver_load_options: RefCell<LoadOptions>,
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<ScopeExpandType>>,
87
88    pub(crate) time_widget: RefCell<TimeInputState>,
89    pub(crate) time_edit_focused: bool,
90    pub(crate) request_time_edit_focus: bool,
91    pub(crate) frame_buffer_content: Option<FrameBufferContent>,
92    pub(crate) frame_buffer_array_cache: Option<FrameBufferArrayCache>,
93    pub(crate) frame_buffer_pixel_cache: Option<FrameBufferPixelCache>,
94
95    // Benchmarking stuff
96    /// Invalidate draw commands every frame to make performance comparison easier
97    pub(crate) continuous_redraw: bool,
98    #[cfg(feature = "performance_plot")]
99    pub(crate) rendering_cpu_times: VecDeque<f32>,
100    #[cfg(feature = "performance_plot")]
101    pub(crate) timing: RefCell<Timing>,
102
103    // Undo and Redo stacks
104    pub(crate) undo_stack: Vec<CanvasState>,
105    pub(crate) redo_stack: Vec<CanvasState>,
106
107    pub(crate) url_callback: Option<Box<dyn Fn(String) -> Message + Send + 'static>>,
108
109    // Only used for testing
110    pub(crate) expand_parameter_section: bool,
111}
112
113impl SystemState {
114    pub fn new() -> Result<SystemState> {
115        Self::new_inner(false)
116    }
117
118    #[cfg(test)]
119    pub(crate) fn new_default_config() -> Result<SystemState> {
120        Self::new_inner(true)
121    }
122
123    fn new_inner(force_default_config: bool) -> Result<SystemState> {
124        let channels = Channels::new();
125
126        // Basic translators that we can load quickly
127        let translators = all_translators();
128
129        let result = SystemState {
130            user: UserState::new(force_default_config)?,
131            translators,
132            channels,
133            progress_tracker: None,
134            command_prompt: Default::default(),
135            context: None,
136            wcp_server_thread: None,
137            wcp_server_address: None,
138            wcp_stop_signal: Arc::new(AtomicBool::new(false)),
139            wcp_running_signal: Arc::new(AtomicBool::new(false)),
140            wcp_greeted_signal: Arc::new(AtomicBool::new(false)),
141            wcp_client_capabilities: WcpClientCapabilities::new(),
142            gesture_start_location: None,
143            measure_start_location: None,
144            batch_messages: VecDeque::new(),
145            batch_messages_completed: false,
146            url: RefCell::new(String::new()),
147            command_prompt_text: RefCell::new(String::new()),
148            draw_data: RefCell::new(vec![None]),
149            variable_name_info_cache: RefCell::new(HashMap::new()),
150            last_canvas_rect: RefCell::new(None),
151
152            items_to_expand: RefCell::new(vec![]),
153            char_to_add_to_prompt: RefCell::new(None),
154            scope_ref_to_expand: RefCell::new(None),
155            surver_selected_file: RefCell::new(None),
156            surver_load_options: RefCell::new(LoadOptions::Clear),
157            expand_parameter_section: false,
158            time_widget: RefCell::new(TimeInputState::default()),
159            time_edit_focused: false,
160            request_time_edit_focus: false,
161            frame_buffer_content: None,
162            frame_buffer_array_cache: None,
163            frame_buffer_pixel_cache: None,
164
165            url_callback: None,
166            continuous_redraw: false,
167            #[cfg(feature = "performance_plot")]
168            rendering_cpu_times: VecDeque::new(),
169            #[cfg(feature = "performance_plot")]
170            timing: RefCell::new(Timing::new()),
171            undo_stack: vec![],
172            redo_stack: vec![],
173        };
174
175        Ok(result)
176    }
177}
178
179impl From<UserState> for SystemState {
180    fn from(serializable_state: UserState) -> SystemState {
181        let mut state = SystemState::new().unwrap();
182        state.user = serializable_state;
183        state
184    }
185}