diff --git a/Makefile.toml b/Makefile.toml index 6f1c212..236fb15 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -38,6 +38,15 @@ run_task = { fork = true, parallel = true, name = [ "watch_tauri_glue", ]} +[tasks.start_browser_release] +description = "Run without Tauri in the browser & watch Typescript and Rust in the release mode" +dependencies = ["store_current_process_id"] +run_task = { fork = true, parallel = true, name = [ + "mzoon_start_release_with_cleanup", + "watch_pixi_canvas", + "watch_tauri_glue", +]} + [tasks.bundle] description = "Compile in the release mode and create installation packages" dependencies = ["tauri_build", "show_release_paths"] @@ -100,6 +109,11 @@ description = "Run `mzoon start`" extend = "mzoon" args = ["start"] +[tasks.mzoon_start_release] +description = "Run `mzoon start --release`" +extend = "mzoon" +args = ["start", "--release"] + [tasks.tauri_dev_with_cleanup] description = "Run forked `tauri dev` with cleanup" run_task = { fork = true, cleanup_task = "kill_watchers", name = ["tauri_dev"] } @@ -108,6 +122,10 @@ run_task = { fork = true, cleanup_task = "kill_watchers", name = ["tauri_dev"] } description = "Run forked `mzoon start` with cleanup" run_task = { fork = true, cleanup_task = "kill_watchers", name = ["mzoon_start"] } +[tasks.mzoon_start_release_with_cleanup] +description = "Run forked `mzoon start` with cleanup" +run_task = { fork = true, cleanup_task = "kill_watchers", name = ["mzoon_start_release"] } + [tasks.kill_watchers] description = "Kill the cargo-make/makers process and all its children / forked processes" script_runner = "@duckscript" diff --git a/README.md b/README.md index 0b2c352..7cfd3a9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ___ -### Start: +### Start the desktop version: 1. `makers start` @@ -39,26 +39,33 @@ Troubleshooting: --- -### Start in the browser: +### Production build of the desktop version: + +1. `makers bundle` +2. Runnable executable is in `target/release` +3. Installable bundles specific for the platform are in `target/release/bundle` + +--- + +### Start in a browser: 1. `makers start_browser` 2. Ctrl + Click the server URL mentioned in the terminal log --- +### Start in a browser in the release mode: + +1. `makers start_browser_release` +2. Ctrl + Click the server URL mentioned in the terminal log + +--- + ### Steps before pushing: 1. `makers format` ---- -### Production build: - -1. `makers bundle` -2. Runnable executable is in `target/release` -3. Installable bundles specific for the platform are in `target/release/bundle` - ---- ### Test files diff --git a/frontend/src/controls_panel.rs b/frontend/src/controls_panel.rs index 2c8ec0e..942df2e 100644 --- a/frontend/src/controls_panel.rs +++ b/frontend/src/controls_panel.rs @@ -219,10 +219,7 @@ impl ControlsPanel { Task::start(async move { if let Some(filename) = platform::pick_and_load_waveform(Some(file)).await { loaded_filename.set_neq(Some(filename)); - let (hierarchy, time_table) = - join!(platform::get_hierarchy(), platform::get_time_table()); - hierarchy - .set(Some((Rc::new(hierarchy), Rc::new(time_table)))) + hierarchy.set(Some(Rc::new(platform::get_hierarchy().await))) } }) }) diff --git a/frontend/src/platform/browser.rs b/frontend/src/platform/browser.rs index 94f5f35..ff18cfc 100644 --- a/frontend/src/platform/browser.rs +++ b/frontend/src/platform/browser.rs @@ -79,8 +79,13 @@ pub(super) async fn load_signal_and_get_timeline( screen_width: u32, block_height: u32, ) -> shared::Timeline { - // @TODO implement, copy from tauri platform - shared::Timeline { blocks: Vec::new() } + let mut waveform_lock = STORE.waveform.lock().unwrap(); + let waveform = waveform_lock.as_mut().unwrap(); + waveform.load_signals_multi_threaded(&[signal_ref]); + let signal = waveform.get_signal(signal_ref).unwrap(); + let time_table = waveform.time_table(); + let timeline = signal_to_timeline(signal, time_table, screen_width, block_height); + timeline } pub(super) async fn unload_signal(signal_ref: wellen::SignalRef) { @@ -88,3 +93,77 @@ pub(super) async fn unload_signal(signal_ref: wellen::SignalRef) { let waveform = waveform_lock.as_mut().unwrap_throw(); waveform.unload_signals(&[signal_ref]); } + +// @TODO keep in sync with the same method in `src-tauri/src/lib.rs` +fn signal_to_timeline( + signal: &wellen::Signal, + time_table: &[wellen::Time], + screen_width: u32, + block_height: u32, +) -> shared::Timeline { + const MIN_BLOCK_WIDTH: u32 = 3; + const LETTER_WIDTH: u32 = 15; + const LETTER_HEIGHT: u32 = 21; + const LABEL_X_PADDING: u32 = 10; + + let Some(last_time) = time_table.last().copied() else { + return shared::Timeline::default(); + }; + + let last_time = last_time as f64; + let screen_width = screen_width as f64; + + let mut x_value_pairs = signal + .iter_changes() + .map(|(index, value)| { + let index = index as usize; + let time = time_table[index] as f64; + let x = time / last_time * screen_width; + (x, value) + }) + .peekable(); + + // @TODO parallelize? + let mut blocks = Vec::new(); + while let Some((block_x, value)) = x_value_pairs.next() { + let next_block_x = if let Some((next_block_x, _)) = x_value_pairs.peek() { + *next_block_x + } else { + screen_width + }; + + let block_width = (next_block_x - block_x) as u32; + if block_width < MIN_BLOCK_WIDTH { + continue; + } + + // @TODO dynamic formatter + // @TODO optimize it by not using `.to_string` if possible + let value = value.to_string(); + let ones_and_zeros = value.chars().rev().map(|char| char.to_digit(2).unwrap()).collect::>(); + let mut base = convert_base::Convert::new(2, 16); + let output = base.convert::(&ones_and_zeros); + let value: String = output.into_iter().map(|number| char::from_digit(number, 16).unwrap()).collect(); + + let value_width = value.chars().count() as u32 * LETTER_WIDTH; + let label = if (value_width + (2 * LABEL_X_PADDING)) <= block_width { + Some(shared::TimeLineBlockLabel { + text: value, + x: (block_width - value_width) / 2, + y: (block_height - LETTER_HEIGHT) / 2, + }) + } else { + None + }; + + let block = shared::TimelineBlock { + x: block_x as u32, + width: block_width, + height: block_height, + label, + }; + blocks.push(block); + } + + shared::Timeline { blocks } +} diff --git a/frontend/src/waveform_panel.rs b/frontend/src/waveform_panel.rs index 8f3b7ae..f9a4c3d 100644 --- a/frontend/src/waveform_panel.rs +++ b/frontend/src/waveform_panel.rs @@ -62,6 +62,7 @@ impl WaveformPanel { selected_var_refs.signal_vec().delay_remove(clone!((hierarchy) move |var_ref| { clone!((var_ref, hierarchy) async move { if let Some(hierarchy) = hierarchy.get_cloned() { + // @TODO unload only when no other selected variable use it? platform::unload_signal(hierarchy.get(var_ref).signal_ref()).await; } }) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 7ea748d..9b98a0c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -88,6 +88,7 @@ pub fn run() { .expect("error while running tauri application"); } +// @TODO keep in sync with the same method in `frontend/src/platform/browser.rs` fn signal_to_timeline( signal: &wellen::Signal, time_table: &[wellen::Time],