Skip to main content

libsurfer/
message.rs

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