Skip to main content

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