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