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