libsurfer/
message.rs

1use bytes::Bytes;
2use camino::Utf8PathBuf;
3use derive_more::Debug;
4use egui::DroppedFile;
5use emath::{Pos2, Vec2};
6use ftr_parser::types::Transaction;
7use num::BigInt;
8use serde::Deserialize;
9use std::path::PathBuf;
10use surver::Status;
11
12use crate::async_util::AsyncJob;
13use crate::config::PrimaryMouseDrag;
14use crate::displayed_item_tree::{ItemIndex, VisibleItemIndex};
15use crate::graphics::{Graphic, GraphicId};
16use crate::state::UserState;
17use crate::transaction_container::{
18    StreamScopeRef, TransactionContainer, TransactionRef, TransactionStreamRef,
19};
20use crate::translation::DynTranslator;
21use crate::viewport::ViewportStrategy;
22use crate::wave_data::ScopeType;
23use crate::{
24    clock_highlighting::ClockHighlightType,
25    config::ArrowKeyBindings,
26    dialog::{OpenSiblingStateFileDialog, ReloadWaveformDialog},
27    displayed_item::{DisplayedFieldRef, DisplayedItemRef},
28    file_dialog::OpenMode,
29    hierarchy::HierarchyStyle,
30    time::{TimeStringFormatting, TimeUnit},
31    variable_filter::VariableIOFilterType,
32    variable_name_type::VariableNameType,
33    wave_container::{ScopeRef, VariableRef, WaveContainer},
34    wave_source::{CxxrtlKind, LoadOptions, WaveFormat},
35    wellen::{BodyResult, HeaderResult, LoadSignalsResult},
36    MoveDir, VariableNameFilterType, WaveSource,
37};
38
39type CommandCount = usize;
40
41/// Encapsulates either a specific variable or all selected variables
42#[derive(Debug, Deserialize, Clone)]
43pub enum MessageTarget<T> {
44    Explicit(T),
45    CurrentSelection,
46}
47
48impl<T> From<MessageTarget<T>> for Option<T> {
49    fn from(value: MessageTarget<T>) -> Self {
50        match value {
51            MessageTarget::Explicit(val) => Some(val),
52            MessageTarget::CurrentSelection => None,
53        }
54    }
55}
56
57impl<T> From<Option<T>> for MessageTarget<T> {
58    fn from(value: Option<T>) -> Self {
59        match value {
60            Some(val) => Self::Explicit(val),
61            None => Self::CurrentSelection,
62        }
63    }
64}
65
66impl<T: Copy> Copy for MessageTarget<T> {}
67
68#[derive(Debug, Deserialize)]
69/// The design of Surfer relies on sending messages to trigger actions.
70pub enum Message {
71    /// Set active scope
72    SetActiveScope(ScopeType),
73    ExpandScope(ScopeRef),
74    /// Add one or more variables to wave view.
75    AddVariables(Vec<VariableRef>),
76    /// Add scope to wave view. If second argument is true, add subscopes recursively.
77    AddScope(ScopeRef, bool),
78    /// Add scope to wave view as a group. If second argument is true, add subscopes recursively.
79    AddScopeAsGroup(ScopeRef, bool),
80    /// Add a character to the repeat command counter.
81    AddCount(char),
82    AddStreamOrGenerator(TransactionStreamRef),
83    AddStreamOrGeneratorFromName(Option<StreamScopeRef>, String),
84    AddAllFromStreamScope(String),
85    /// Reset the repeat command counter.
86    InvalidateCount,
87    RemoveItemByIndex(VisibleItemIndex),
88    RemoveItems(Vec<DisplayedItemRef>),
89    /// Focus a wave/item.
90    FocusItem(VisibleItemIndex),
91    ItemSelectRange(VisibleItemIndex),
92    /// Select all waves/items.
93    ItemSelectAll,
94    SetItemSelected(VisibleItemIndex, bool),
95    /// Unfocus a wave/item.
96    UnfocusItem,
97    RenameItem(Option<VisibleItemIndex>),
98    MoveFocus(MoveDir, CommandCount, bool),
99    MoveFocusedItem(MoveDir, CommandCount),
100    FocusTransaction(Option<TransactionRef>, Option<Transaction>),
101    VerticalScroll(MoveDir, CommandCount),
102    /// Scroll in vertical direction so that the item at a given location in the list is at the top (or visible).
103    ScrollToItem(usize),
104    SetScrollOffset(f32),
105    /// Change format (translator) of a variable. Passing None as first element means all selected variables.
106    VariableFormatChange(MessageTarget<DisplayedFieldRef>, String),
107    ItemSelectionClear,
108    /// Change color of waves/items. If first argument is None, change for selected items. If second argument is None, change to default value.
109    ItemColorChange(MessageTarget<VisibleItemIndex>, Option<String>),
110    /// Change background color of waves/items. If first argument is None, change for selected items. If second argument is None, change to default value.
111    ItemBackgroundColorChange(MessageTarget<VisibleItemIndex>, Option<String>),
112    ItemNameChange(Option<VisibleItemIndex>, Option<String>),
113    /// Change scaling factor/height of waves/items. If first argument is None, change for selected items.
114    ItemHeightScalingFactorChange(MessageTarget<VisibleItemIndex>, f32),
115    /// Change variable name type of waves/items. If first argument is None, change for selected items.
116    ChangeVariableNameType(MessageTarget<VisibleItemIndex>, VariableNameType),
117    ForceVariableNameTypes(VariableNameType),
118    /// Set or unset right alignment of names
119    SetNameAlignRight(bool),
120    SetClockHighlightType(ClockHighlightType),
121    SetFillHighValues(bool),
122    // Reset the translator for this variable back to default. Sub-variables,
123    // i.e. those with the variable idx and a shared path are also reset
124    ResetVariableFormat(DisplayedFieldRef),
125    CanvasScroll {
126        delta: Vec2,
127        viewport_idx: usize,
128    },
129    CanvasZoom {
130        mouse_ptr: Option<BigInt>,
131        delta: f32,
132        viewport_idx: usize,
133    },
134    ZoomToRange {
135        start: BigInt,
136        end: BigInt,
137        viewport_idx: usize,
138    },
139    /// Set cursor at time.
140    CursorSet(BigInt),
141    #[serde(skip)]
142    SurferServerStatus(web_time::Instant, String, Status),
143    /// Load file from file path.
144    LoadFile(Utf8PathBuf, LoadOptions),
145    /// Load file from URL.
146    LoadWaveformFileFromUrl(String, LoadOptions),
147    /// Load file from data.
148    LoadFromData(Vec<u8>, LoadOptions),
149    #[cfg(feature = "python")]
150    /// Load translator from Python file path.
151    LoadPythonTranslator(Utf8PathBuf),
152    /// Load a web assembly translator from file. This is loaded in addition to the
153    /// translators loaded on startup.
154    #[cfg(all(not(target_arch = "wasm32"), feature = "wasm_plugins"))]
155    LoadWasmTranslator(Utf8PathBuf),
156    /// Load command file from file path.
157    LoadCommandFile(Utf8PathBuf),
158    /// Load commands from data.
159    LoadCommandFromData(Vec<u8>),
160    /// Load command file from URL.
161    LoadCommandFileFromUrl(String),
162    SetupCxxrtl(CxxrtlKind),
163    #[serde(skip)]
164    /// Message sent when waveform file header is loaded.
165    WaveHeaderLoaded(
166        web_time::Instant,
167        WaveSource,
168        LoadOptions,
169        #[debug(skip)] HeaderResult,
170    ),
171    #[serde(skip)]
172    /// Message sent when waveform file body is loaded.
173    WaveBodyLoaded(web_time::Instant, WaveSource, #[debug(skip)] BodyResult),
174    #[serde(skip)]
175    WavesLoaded(
176        WaveSource,
177        WaveFormat,
178        #[debug(skip)] Box<WaveContainer>,
179        LoadOptions,
180    ),
181    #[serde(skip)]
182    SignalsLoaded(web_time::Instant, #[debug(skip)] LoadSignalsResult),
183    #[serde(skip)]
184    TransactionStreamsLoaded(
185        WaveSource,
186        WaveFormat,
187        #[debug(skip)] TransactionContainer,
188        LoadOptions,
189    ),
190    #[serde(skip)]
191    Error(eyre::Error),
192    #[serde(skip)]
193    TranslatorLoaded(#[debug(skip)] Box<DynTranslator>),
194    /// Take note that the specified translator errored on a `translates` call on the
195    /// specified variable
196    BlacklistTranslator(VariableRef, String),
197    ShowCommandPrompt(Option<String>),
198    /// Message sent when file is loadedropped onto Surfer.
199    FileDropped(DroppedFile),
200    #[serde(skip)]
201    /// Message sent when download of a waveform file is complete.
202    FileDownloaded(String, Bytes, LoadOptions),
203    #[serde(skip)]
204    /// Message sent when download of a command file is complete.
205    CommandFileDownloaded(String, Bytes),
206    ReloadConfig,
207    ReloadWaveform(bool),
208    /// Suggest reloading the current waveform as the file on disk has changed.
209    /// This should first take the user's confirmation before reloading the waveform.
210    /// However, there is a configuration setting that the user can overwrite.
211    #[serde(skip)]
212    SuggestReloadWaveform,
213    /// Close the 'reload_waveform' dialog.
214    /// The `reload_file` boolean is the return value of the dialog.
215    /// If `do_not_show_again` is true, the `reload_file` setting will be persisted.
216    #[serde(skip)]
217    CloseReloadWaveformDialog {
218        reload_file: bool,
219        do_not_show_again: bool,
220    },
221    /// Update the waveform dialog UI with the provided dialog model.
222    #[serde(skip)]
223    UpdateReloadWaveformDialog(ReloadWaveformDialog),
224    // When a file is open, suggest opening state files in the same directory
225    OpenSiblingStateFile(bool),
226    #[serde(skip)]
227    SuggestOpenSiblingStateFile,
228    #[serde(skip)]
229    CloseOpenSiblingStateFileDialog {
230        load_state: bool,
231        do_not_show_again: bool,
232    },
233    #[serde(skip)]
234    UpdateOpenSiblingStateFileDialog(OpenSiblingStateFileDialog),
235    RemovePlaceholders,
236    ZoomToFit {
237        viewport_idx: usize,
238    },
239    GoToStart {
240        viewport_idx: usize,
241    },
242    GoToEnd {
243        viewport_idx: usize,
244    },
245    GoToTime(Option<BigInt>, usize),
246    ToggleMenu,
247    ToggleToolbar,
248    ToggleOverview,
249    ToggleStatusbar,
250    ToggleIndices,
251    ToggleDirection,
252    ToggleEmptyScopes,
253    ToggleParametersInScopes,
254    ToggleSidePanel,
255    ToggleItemSelected(Option<VisibleItemIndex>),
256    ToggleDefaultTimeline,
257    ToggleTickLines,
258    ToggleVariableTooltip,
259    ToggleScopeTooltip,
260    ToggleFullscreen,
261    /// Set which time unit to use.
262    SetTimeUnit(TimeUnit),
263    /// Set how to format the time strings. Passing None resets it to default.
264    SetTimeStringFormatting(Option<TimeStringFormatting>),
265    SetHighlightFocused(bool),
266    CommandPromptClear,
267    CommandPromptUpdate {
268        suggestions: Vec<(String, Vec<bool>)>,
269    },
270    CommandPromptPushPrevious(String),
271    SelectPrevCommand,
272    SelectNextCommand,
273    OpenFileDialog(OpenMode),
274    OpenCommandFileDialog,
275    #[cfg(feature = "python")]
276    OpenPythonPluginDialog,
277    #[cfg(feature = "python")]
278    ReloadPythonPlugin,
279    SaveStateFile(Option<PathBuf>),
280    LoadStateFile(Option<PathBuf>),
281    LoadState(Box<UserState>, Option<PathBuf>),
282    SetStateFile(PathBuf),
283    SetAboutVisible(bool),
284    SetKeyHelpVisible(bool),
285    SetGestureHelpVisible(bool),
286    SetQuickStartVisible(bool),
287    #[serde(skip)]
288    SetUrlEntryVisible(
289        bool,
290        #[debug(skip)] Option<Box<dyn Fn(String) -> Message + Send + 'static>>,
291    ),
292    SetLicenseVisible(bool),
293    SetRenameItemVisible(bool),
294    SetLogsVisible(bool),
295    SetMouseGestureDragStart(Option<Pos2>),
296    SetMeasureDragStart(Option<Pos2>),
297    SetFilterFocused(bool),
298    SetVariableNameFilterType(VariableNameFilterType),
299    SetVariableNameFilterCaseInsensitive(bool),
300    SetVariableIOFilter(VariableIOFilterType, bool),
301    SetVariableGroupByDirection(bool),
302    SetUIZoomFactor(f32),
303    SetPerformanceVisible(bool),
304    SetContinuousRedraw(bool),
305    SetCursorWindowVisible(bool),
306    SetHierarchyStyle(HierarchyStyle),
307    SetArrowKeyBindings(ArrowKeyBindings),
308    SetPrimaryMouseDragBehavior(PrimaryMouseDrag),
309    // Second argument is position to insert after, None inserts after focused item,
310    // or last if no focused item
311    AddDivider(Option<String>, Option<VisibleItemIndex>),
312    // Argument is position to insert after, None inserts after focused item,
313    // or last if no focused item
314    AddTimeLine(Option<VisibleItemIndex>),
315    AddMarker {
316        time: BigInt,
317        name: Option<String>,
318        move_focus: bool,
319    },
320    /// Set a marker at a specific position. If it doesn't exist, it will be created
321    SetMarker {
322        id: u8,
323        time: BigInt,
324    },
325    /// Remove marker.
326    RemoveMarker(u8),
327    /// Set or move a marker to the position of the current cursor.
328    MoveMarkerToCursor(u8),
329    /// Scroll in horizontal direction so that the cursor is visible.
330    GoToCursorIfNotInView,
331    GoToMarkerPosition(u8, usize),
332    MoveCursorToTransition {
333        next: bool,
334        variable: Option<VisibleItemIndex>,
335        skip_zero: bool,
336    },
337    MoveTransaction {
338        next: bool,
339    },
340    VariableValueToClipbord(MessageTarget<VisibleItemIndex>),
341    VariableNameToClipboard(MessageTarget<VisibleItemIndex>),
342    VariableFullNameToClipboard(MessageTarget<VisibleItemIndex>),
343    InvalidateDrawCommands,
344    AddGraphic(GraphicId, Graphic),
345    RemoveGraphic(GraphicId),
346
347    /// Variable dragging messages
348    VariableDragStarted(VisibleItemIndex),
349    VariableDragTargetChanged(crate::displayed_item_tree::TargetPosition),
350    VariableDragFinished,
351    AddDraggedVariables(Vec<VariableRef>),
352    /// Unpauses the simulation if the wave source supports this kind of interactivity. Otherwise
353    /// does nothing
354    UnpauseSimulation,
355    /// Pause the simulation if the wave source supports this kind of interactivity. Otherwise
356    /// does nothing
357    PauseSimulation,
358    /// Expand the displayed item into subfields. Levels controls how many layers of subfields
359    /// are expanded. 0 unexpands it completely
360    ExpandDrawnItem {
361        item: DisplayedItemRef,
362        levels: usize,
363    },
364
365    SetViewportStrategy(ViewportStrategy),
366    SetConfigFromString(String),
367    AddCharToPrompt(char),
368
369    /// Run more than one message in sequence
370    Batch(Vec<Message>),
371    AddViewport,
372    RemoveViewport,
373    /// Select Theme
374    SelectTheme(Option<String>),
375    /// Undo the last n changes
376    Undo(usize),
377    /// Redo the last n changes
378    Redo(usize),
379    DumpTree,
380    GroupNew {
381        name: Option<String>,
382        before: Option<ItemIndex>,
383        items: Option<Vec<DisplayedItemRef>>,
384    },
385    GroupDissolve(Option<DisplayedItemRef>),
386    GroupFold(Option<DisplayedItemRef>),
387    GroupUnfold(Option<DisplayedItemRef>),
388    GroupFoldRecursive(Option<DisplayedItemRef>),
389    GroupUnfoldRecursive(Option<DisplayedItemRef>),
390    GroupFoldAll,
391    GroupUnfoldAll,
392    /// WCP Server
393    StartWcpServer {
394        address: Option<String>,
395        initiate: bool,
396    },
397    StopWcpServer,
398    /// Configures the WCP system to listen for messages over internal channels.
399    /// This is used to start WCP on wasm
400    SetupChannelWCP,
401    /// Exit the application. This has no effect on wasm and closes the window
402    /// on other platforms
403    Exit,
404    /// Should only used for tests. Expands the parameter section so that one can test the rendering.
405    ExpandParameterSection,
406    AsyncDone(AsyncJob),
407}