Skip to main content

libsurfer/
message.rs

1use bytes::Bytes;
2use camino::Utf8PathBuf;
3use derive_more::Debug;
4use egui::{DroppedFileHandle, Id, Rect};
5use emath::{Pos2, RectTransform, Vec2};
6use ftr_parser::types::Transaction;
7use num::BigInt;
8use serde::Deserialize;
9use std::sync::Arc;
10use surver::SurverStatus;
11
12use crate::annotation_list::AnnotationGroup;
13use crate::arrow::{ArrowHeadMode, WavePoint};
14use crate::async_util::AsyncJob;
15use crate::comment::Comment;
16use crate::config::{FocusHighlight, PrimaryMouseDrag, TransitionValue};
17use crate::displayed_item_tree::{ItemIndex, VisibleItemIndex};
18use crate::frame_buffer::FrameBufferColorMode;
19use crate::graphics::{Graphic, GraphicId, GraphicsY};
20use crate::hierarchy::{ParameterDisplayLocation, ScopeExpandType};
21use crate::mousegestures::AnnotationKind;
22use crate::state::UserState;
23use crate::trace_style::TraceStyle;
24use crate::transaction_container::{
25    StreamScopeRef, TransactionContainer, TransactionRef, TransactionStreamRef,
26};
27use crate::translation::DynTranslator;
28use crate::viewport::ViewportStrategy;
29use crate::wave_data::ScopeType;
30use crate::{
31    MoveDir, VariableNameFilterType, WaveSource,
32    clock_highlighting::ClockHighlightType,
33    config::ArrowKeyBindings,
34    dialog::{OpenSiblingStateFileDialog, ReloadWaveformDialog},
35    displayed_item::{DisplayedFieldRef, DisplayedItemRef},
36    file_dialog::OpenMode,
37    hierarchy::HierarchyStyle,
38    time::{TimeStringFormatting, TimeUnit},
39    variable_filter::VariableIOFilterType,
40    variable_name_type::VariableNameType,
41    wave_container::{AnalogCacheKey, ScopeRef, VariableRef, WaveContainer},
42    wave_source::{CxxrtlKind, LoadOptions, WaveFormat},
43    wellen::{BodyResult, HeaderResult, LoadSignalsResult},
44};
45
46type CommandCount = usize;
47
48/// Encapsulates either a specific variable or all selected variables
49#[derive(Debug, Deserialize, Clone)]
50pub enum MessageTarget<T> {
51    Explicit(T),
52    CurrentSelection,
53}
54
55impl<T> From<MessageTarget<T>> for Option<T> {
56    fn from(value: MessageTarget<T>) -> Self {
57        match value {
58            MessageTarget::Explicit(val) => Some(val),
59            MessageTarget::CurrentSelection => None,
60        }
61    }
62}
63
64impl<T> From<Option<T>> for MessageTarget<T> {
65    fn from(value: Option<T>) -> Self {
66        match value {
67            Some(val) => Self::Explicit(val),
68            None => Self::CurrentSelection,
69        }
70    }
71}
72
73impl<T: Copy> Copy for MessageTarget<T> {}
74
75#[derive(Debug, Deserialize)]
76/// The design of Surfer relies on sending messages to trigger actions.
77pub enum Message {
78    /// Set active scope, None corresponds to the top-level scope.
79    SetActiveScope(Option<ScopeType>),
80    ExpandScope(ScopeExpandType),
81    /// Add one or more variables to wave view.
82    AddVariables(Vec<VariableRef>),
83    /// Add scope to wave view.
84    ///
85    /// If second argument is true, add subscopes recursively.
86    AddScope(ScopeRef, bool),
87    /// Add scope to wave view as a group.
88    ///
89    /// If second argument is true, add subscopes recursively.
90    AddScopeAsGroup(ScopeRef, bool),
91    /// Add a character to the repeat command counter.
92    AddCount(char),
93    AddStreamOrGenerator(TransactionStreamRef),
94    AddStreamOrGeneratorFromName(Option<StreamScopeRef>, String),
95    AddAllFromStreamScope(String),
96    /// Reset the repeat command counter.
97    InvalidateCount,
98    RemoveVisibleItems(MessageTarget<VisibleItemIndex>),
99    RemoveItems(Vec<DisplayedItemRef>),
100    /// Focus a wave/item.
101    FocusItem(VisibleItemIndex),
102    ItemSelectRange(VisibleItemIndex),
103    /// Select all waves/items.
104    ItemSelectAll,
105    SetItemSelected(VisibleItemIndex, bool),
106    /// Unfocus a wave/item.
107    UnfocusItem,
108    MoveFocus(MoveDir, CommandCount, bool),
109    MoveFocusedItem(MoveDir, CommandCount),
110    FocusTransaction(Option<TransactionRef>, Option<Transaction>),
111    VerticalScroll(MoveDir, CommandCount),
112    /// Scroll in vertical direction so that the item at a given location in the list is at the top (or visible).
113    ScrollToItem(usize),
114    SetScrollOffset(f32),
115    /// Change format (translator) of a variable.
116    ///
117    /// Passing None as first element means all selected variables.
118    VariableFormatChange(MessageTarget<DisplayedFieldRef>, String),
119    ItemSelectionClear,
120    /// Change color of waves/items.
121    ///
122    /// If first argument is None, change for selected items. If second argument is None, change to default value.
123    ItemColorChange(MessageTarget<VisibleItemIndex>, Option<String>),
124    /// Change background color of waves/items.
125    ///
126    /// If first argument is None, change for selected items. If second argument is None, change to default value.
127    ItemBackgroundColorChange(MessageTarget<VisibleItemIndex>, Option<String>),
128    ItemNameChange(Option<VisibleItemIndex>, Option<String>),
129    ItemNameReset(MessageTarget<VisibleItemIndex>),
130    /// Change scaling factor/height of waves/items.
131    ///
132    /// If first argument is None, change for selected items.
133    ItemHeightScalingFactorChange(MessageTarget<VisibleItemIndex>, f32),
134    /// Change variable name type of waves/items.
135    ///
136    /// If first argument is None, change for selected items.
137    ChangeVariableNameType(MessageTarget<VisibleItemIndex>, VariableNameType),
138    ForceVariableNameTypes(VariableNameType),
139    /// Set or unset right alignment of names
140    SetNameAlignRight(bool),
141    SetClockHighlightType(ClockHighlightType),
142    SetFillHighValues(bool),
143    SetTraceStyle(TraceStyle),
144    /// Reset the translator for this variable back to default.
145    ///
146    /// Sub-variables, i.e., those with the variable idx and a shared path are also reset.
147    ResetVariableFormat(DisplayedFieldRef),
148    CanvasScroll {
149        delta: Vec2,
150        viewport_idx: usize,
151    },
152    CanvasZoom {
153        mouse_ptr: Option<BigInt>,
154        delta: f32,
155        viewport_idx: usize,
156    },
157    ZoomToCursor {
158        delta: f32,
159        viewport_idx: usize,
160    },
161    ZoomToRange {
162        start: BigInt,
163        end: BigInt,
164        viewport_idx: usize,
165    },
166    /// Set cursor at time.
167    CursorSet(BigInt),
168    #[serde(skip)]
169    SetSurverStatus(web_time::Instant, String, SurverStatus),
170    /// Load file from file path.
171    LoadFile(Utf8PathBuf, LoadOptions),
172    /// Load file from URL.
173    LoadWaveformFileFromUrl(String, LoadOptions),
174    /// Load file from data.
175    LoadFromData(Vec<u8>, LoadOptions),
176    #[cfg(feature = "python")]
177    /// Load translator from Python file path.
178    LoadPythonTranslator(Utf8PathBuf),
179    /// Load a web assembly translator from file.
180    ///
181    /// This is loaded in addition to the translators loaded on startup.
182    #[cfg(all(not(target_arch = "wasm32"), feature = "wasm_plugins"))]
183    LoadWasmTranslator(Utf8PathBuf),
184    /// Load command file from file path.
185    LoadCommandFile(Utf8PathBuf),
186    /// Load commands from data.
187    LoadCommandFromData(Vec<u8>),
188    /// Load command file from URL.
189    LoadCommandFileFromUrl(String),
190    #[serde(skip)]
191    ExecuteBatchCommand {
192        line: usize,
193        command: String,
194    },
195    SetupCxxrtl(CxxrtlKind),
196    #[serde(skip)]
197    /// Message sent when waveform file header is loaded.
198    WaveHeaderLoaded(
199        web_time::Instant,
200        WaveSource,
201        LoadOptions,
202        #[debug(skip)] HeaderResult,
203    ),
204    #[serde(skip)]
205    /// Message sent when waveform file body is loaded.
206    WaveBodyLoaded(web_time::Instant, WaveSource, #[debug(skip)] BodyResult),
207    #[serde(skip)]
208    WavesLoaded(
209        WaveSource,
210        WaveFormat,
211        #[debug(skip)] Box<WaveContainer>,
212        LoadOptions,
213    ),
214    #[serde(skip)]
215    SignalsLoaded(web_time::Instant, #[debug(skip)] LoadSignalsResult),
216    #[serde(skip)]
217    TransactionStreamsLoaded(
218        WaveSource,
219        WaveFormat,
220        #[debug(skip)] TransactionContainer,
221        LoadOptions,
222    ),
223    #[serde(skip)]
224    TranslatorLoaded(#[debug(skip)] Arc<DynTranslator>),
225    /// Take note that the specified translator errored on a `translates` call on the
226    /// specified variable
227    BlacklistTranslator(VariableRef, String),
228    HideCommandPrompt,
229    ShowCommandPrompt(String, Option<String>),
230    /// Message sent when file is dropped onto Surfer.
231    #[serde(skip)]
232    FileDropped(DroppedFileHandle),
233    #[serde(skip)]
234    /// Message sent when dropped-file bytes are asynchronously available.
235    DroppedFileBytesLoaded(Option<Utf8PathBuf>, Vec<u8>),
236    #[serde(skip)]
237    /// Message sent when download of a waveform file is complete.
238    FileDownloaded(String, Bytes, LoadOptions),
239    #[serde(skip)]
240    /// Message sent when download of a command file is complete.
241    CommandFileDownloaded(String, Bytes),
242    ReloadConfig,
243    ReloadWaveform(bool),
244    /// Suggest reloading the current waveform as the file on disk has changed.
245    /// This should first take the user's confirmation before reloading the waveform.
246    /// However, there is a configuration setting that the user can overwrite.
247    #[serde(skip)]
248    SuggestReloadWaveform,
249    /// Close the '`reload_waveform`' dialog.
250    /// The `reload_file` boolean is the return value of the dialog.
251    /// If `do_not_show_again` is true, the `reload_file` setting will be persisted.
252    #[serde(skip)]
253    CloseReloadWaveformDialog {
254        reload_file: bool,
255        do_not_show_again: bool,
256    },
257    /// Update the waveform dialog UI with the provided dialog model.
258    #[serde(skip)]
259    UpdateReloadWaveformDialog(ReloadWaveformDialog),
260    // When a file is open, suggest opening state files in the same directory
261    OpenSiblingStateFile(bool),
262    #[serde(skip)]
263    SuggestOpenSiblingStateFile,
264    #[serde(skip)]
265    CloseOpenSiblingStateFileDialog {
266        load_state: bool,
267        do_not_show_again: bool,
268    },
269    #[serde(skip)]
270    UpdateOpenSiblingStateFileDialog(OpenSiblingStateFileDialog),
271    RemovePlaceholders,
272    ZoomToFit {
273        viewport_idx: usize,
274    },
275    GoToStart {
276        viewport_idx: usize,
277    },
278    GoToEnd {
279        viewport_idx: usize,
280    },
281    GoToTime(Option<BigInt>, usize),
282    SetMenuVisible(bool),
283    ToggleMenu,
284    SetToolbarVisible(bool),
285    SetToolbarGroupEnabled(String, bool),
286    SetToolbarGroupRow(String, u8),
287    SetOverviewVisible(bool),
288    SetStatusbarVisible(bool),
289    SetShowIndices(bool),
290    SetShowVariableDirection(bool),
291    SetShowEmptyScopes(bool),
292    SetShowHierarchyIcons(bool),
293    SetParameterDisplayLocation(ParameterDisplayLocation),
294    SetSidePanelVisible(bool),
295    ToggleItemSelected(Option<VisibleItemIndex>),
296    SetDefaultTimeline(bool),
297    SetTickLines(bool),
298    SetVariableTooltip(bool),
299    SetScopeTooltip(bool),
300    SetSurverFileWindowVisible(bool),
301    LoadSurverFileByIndex(Option<usize>, LoadOptions),
302    LoadSurverFileByName(String, LoadOptions),
303    SetTransitionValue(TransitionValue),
304    ToggleFullscreen,
305    StopProgressTracker,
306    /// Set which time unit to use.
307    SetTimeUnit(TimeUnit),
308    /// Set how to format the time strings.
309    ///
310    /// Passing None resets it to default.
311    SetTimeStringFormatting(Option<TimeStringFormatting>),
312    CommandPromptClear,
313    CommandPromptUpdate {
314        suggestions: Vec<(String, Vec<bool>)>,
315    },
316    CommandPromptPushPrevious(String),
317    SelectPrevCommand,
318    SelectNextCommand,
319    OpenFileDialog(OpenMode),
320    OpenCommandFileDialog,
321    #[cfg(feature = "python")]
322    OpenPythonPluginDialog,
323    #[cfg(feature = "python")]
324    ReloadPythonPlugin,
325    SaveStateFile(Option<Utf8PathBuf>),
326    /// Export the currently displayed variables (and only the hierarchy needed for them) to an FST file.
327    #[cfg(not(target_arch = "wasm32"))]
328    ExportSignalsToFst(Option<Utf8PathBuf>),
329    /// Load state from data.
330    /// Note: the internal state is not a stable format and this should not be
331    /// relied on to work across revisions.
332    LoadStateFromData(Vec<u8>),
333    LoadStateFile(Option<Utf8PathBuf>),
334    LoadState(Box<UserState>, Option<Utf8PathBuf>),
335    SetStateFile(Utf8PathBuf),
336    SetAboutVisible(bool),
337    SetKeyHelpVisible(bool),
338    SetGestureHelpVisible(bool),
339    SetQuickStartVisible(bool),
340    #[serde(skip)]
341    SetUrlEntryVisible(
342        bool,
343        #[debug(skip)] Option<Box<dyn Fn(String) -> Message + Send + 'static>>,
344    ),
345    SetLicenseVisible(bool),
346    SetLogsVisible(bool),
347    SetFrameBufferVariable(VariableRef),
348    SetFrameBufferVisibleVariable(Option<VisibleItemIndex>),
349    SetFrameBufferArray(ScopeRef),
350    SetFrameBufferMode(FrameBufferColorMode, u8, u8, u8),
351    SetFrameBufferWidth(usize),
352    SetFrameBufferRange(Vec<(i64, i64)>),
353    SetMouseGestureDragStart(Option<Pos2>, Option<BigInt>),
354    OpenMemoryViewer {
355        scope: ScopeRef,
356        name: Option<String>,
357    },
358    SetMeasureDragStart(Option<Pos2>),
359    /// Set or clear focus state for a widget identified by id string.
360    SetTextEditFocused(String, bool),
361    /// Request focus (one-shot) for a widget identified by id string.
362    SetRequestTextEditFocus(String, bool),
363    /// Clear focus state for all widgets.
364    ClearAllTextEditFocuses,
365    SetVariableNameFilterType(VariableNameFilterType),
366    SetVariableNameFilterCaseInsensitive(bool),
367    SetVariableIOFilter(VariableIOFilterType, bool),
368    SetVariableGroupByDirection(bool),
369    SetUIZoomFactor(f32),
370    SetPerformanceVisible(bool),
371    SetContinuousRedraw(bool),
372    SetCursorWindowVisible(bool),
373    SetDrawVectorUnknownsAsLine(bool),
374    SetFocusHighlight(FocusHighlight),
375    SetHierarchyStyle(HierarchyStyle),
376    SetArrowKeyBindings(ArrowKeyBindings),
377    SetPrimaryMouseDragBehavior(PrimaryMouseDrag),
378    SetTimeOffsetEnabled(bool),
379    // Second argument is position to insert after, None inserts after focused item,
380    // or last if no focused item
381    AddDivider(Option<String>, Option<VisibleItemIndex>),
382    // Argument is position to insert after, None inserts after focused item,
383    // or last if no focused item
384    AddTimeLine(Option<VisibleItemIndex>),
385    AddMarker {
386        time: BigInt,
387        name: Option<String>,
388        move_focus: bool,
389    },
390    /// Resolve a marker name or `#id` at execution time, then set or create the marker.
391    // FIXME Resolving by `#id` does not work as expected; characters after a `#` are
392    // stripped as comments before being parsed.
393    ResolveMarkerSet {
394        name: String,
395        time: BigInt,
396    },
397    /// Set a marker at a specific position.
398    ///
399    /// If it doesn't exist, it will be created
400    SetMarker {
401        id: u8,
402        time: BigInt,
403    },
404    /// Resolve a marker name or `#id` at execution time, then remove the marker if it exists.
405    // FIXME Resolving by `#id` does not work as expected; characters after a `#` are
406    // stripped as comments before being parsed.
407    ResolveMarkerRemove(String),
408    /// Remove marker.
409    RemoveMarker(u8),
410    /// Set or move a marker to the position of the current cursor.
411    MoveMarkerToCursor(u8),
412    /// Scroll in horizontal direction so that the cursor is visible.
413    GoToCursorIfNotInView,
414    GoToMarkerPosition(u8, usize),
415    MoveCursorToTransition {
416        next: bool,
417        variable: Option<VisibleItemIndex>,
418        skip_zero: bool,
419    },
420    MoveTransaction {
421        next: bool,
422    },
423    VariableValueToClipbord(MessageTarget<VisibleItemIndex>),
424    VariableNameToClipboard(MessageTarget<VisibleItemIndex>),
425    VariableFullNameToClipboard(MessageTarget<VisibleItemIndex>),
426    InvalidateDrawCommands,
427    AddGraphic(GraphicId, Graphic),
428    RemoveGraphic(GraphicId),
429
430    /// Variable dragging messages
431    VariableDragStarted(VisibleItemIndex),
432    VariableDragTargetChanged(crate::displayed_item_tree::TargetPosition),
433    VariableDragFinished,
434    AddDraggedVariables(Vec<VariableRef>),
435    /// Unpauses the simulation if the wave source supports this kind of interactivity.
436    ///
437    /// Otherwise does nothing
438    UnpauseSimulation,
439    /// Pause the simulation if the wave source supports this kind of interactivity.
440    ///
441    /// Otherwise does nothing
442    PauseSimulation,
443    /// Expand the displayed item into subfields.
444    ///
445    /// Levels controls how many layers of subfields are expanded. 0 unexpands it completely.
446    ExpandDrawnItem {
447        item: DisplayedItemRef,
448        levels: usize,
449    },
450    /// Toggle whether a compound variable's field (path relative to the variable's root) is
451    /// expanded to show its own subfields.
452    ToggleVariableFieldFold(DisplayedItemRef, Vec<String>),
453    SetAnalogSettings(
454        MessageTarget<VisibleItemIndex>,
455        Option<crate::displayed_item::AnalogSettings>,
456    ),
457    BuildAnalogCache {
458        display_id: DisplayedItemRef,
459        cache_key: AnalogCacheKey,
460    },
461    #[serde(skip)]
462    AnalogCacheBuilt {
463        #[debug(skip)]
464        entry: Arc<crate::analog_signal_cache::AnalogCacheEntry>,
465        #[debug(skip)]
466        result: Result<crate::analog_signal_cache::AnalogSignalCache, String>,
467    },
468
469    SetViewportStrategy(ViewportStrategy),
470    SetConfigFromString(String),
471    AddCharToPrompt(char),
472
473    /// Run more than one message in sequence
474    Batch(Vec<Message>),
475    AddViewport,
476    RemoveViewport,
477    /// Select Theme
478    SelectTheme(Option<String>),
479    /// Enable animations
480    EnableAnimations(bool),
481    /// Show text of the dividers inline with the signals
482    ShowDividerText(bool),
483    /// Undo the last n changes
484    Undo(usize),
485    /// Redo the last n changes
486    Redo(usize),
487    DumpTree,
488    GroupNew {
489        name: Option<String>,
490        before: Option<ItemIndex>,
491        items: Option<Vec<DisplayedItemRef>>,
492    },
493    GroupDissolve(Option<DisplayedItemRef>),
494    GroupFold(Option<DisplayedItemRef>),
495    GroupUnfold(Option<DisplayedItemRef>),
496    GroupFoldRecursive(Option<DisplayedItemRef>),
497    GroupUnfoldRecursive(Option<DisplayedItemRef>),
498    GroupFoldAll,
499    GroupUnfoldAll,
500    /// WCP Server
501    StartWcpServer {
502        address: Option<String>,
503        initiate: bool,
504    },
505    StopWcpServer,
506    /// Configures the WCP system to listen for messages over internal channels.
507    /// This is used to start WCP on wasm
508    SetupChannelWCP,
509    DownloadDefaultConfig,
510    /// Exit the application.
511    ///
512    /// This has no effect on wasm and closes the window
513    /// on other platforms
514    Exit,
515    /// Expands the parameter section so that one can test the rendering.
516    ///
517    /// Should only used for tests.
518    ExpandParameterSection,
519    AsyncDone(AsyncJob),
520    SetMouseGestureAnnotation(Option<AnnotationKind>),
521    RectangleAdded {
522        time_at_start: BigInt,
523        time_at_end: BigInt,
524        wave_from: Option<GraphicsY>,
525        wave_to: Option<GraphicsY>,
526        rect: Rect,
527    },
528    ArrowAdded {
529        wave_point_from: WavePoint,
530        wave_point_to: WavePoint,
531        head_mode: ArrowHeadMode,
532    },
533    RemoveAnnotation(Id),
534    ToggleAnnotationVisiblility(Id),
535    ToggleAnnotationListShowComments(Id),
536    GoToAnnotationPosition(Id, usize),
537    ToggleAnnotationlistVisibility(),
538    CreateAnnotationGroup(String),
539    DeleteAnnotationGroup(String),
540    DeleteAllAnnotationInGroup(String),
541    UpdateAnnotationGroup(Id, Option<String>),
542    SetGroupVisibility(AnnotationGroup, bool),
543    UpdateAnnotationName(Id, String),
544    AnnotationClicked(
545        Option<Id>,
546        Option<Pos2>,
547        Option<usize>,
548        Option<RectTransform>,
549        Option<f32>,
550    ),
551    SetActiveViewport(usize),
552    ClickHandled(),
553    UpdateCommentBox(Vec<(Id, Comment)>),
554    AddCommentMessage(Id, String, String),
555    RemoveCommentMessage(Id, Id),
556    ToggleCommentVisibility(Id),
557}