diff --git a/README.md b/README.md index 7cfd3a9..158b34d 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,23 @@ ---

- fastwave_screenshot_firefox + Fastwave - Browser (Firefox) + Browser (Firefox)

- fastwave_video_desktop + Fastwave - Desktop, miller columns and tree + Desktop, miller columns and tree +

+ +

+ Fastwave - Zoom, pan and basic number formats + Zoom, pan and basic number formats +

+ +

+ Fastwave - Zoom and all formats + Zoom and all formats

--- diff --git a/docs/video_simple_vcd.gif b/docs/video_desktop.gif similarity index 100% rename from docs/video_simple_vcd.gif rename to docs/video_desktop.gif diff --git a/docs/video_zoom_formatting.gif b/docs/video_zoom_formatting.gif new file mode 100644 index 0000000..0ade85f Binary files /dev/null and b/docs/video_zoom_formatting.gif differ diff --git a/docs/video_zoom_formatting_simple.gif b/docs/video_zoom_formatting_simple.gif new file mode 100644 index 0000000..6df92e1 Binary files /dev/null and b/docs/video_zoom_formatting_simple.gif differ diff --git a/frontend/src/platform.rs b/frontend/src/platform.rs index 58903f9..73c7f73 100644 --- a/frontend/src/platform.rs +++ b/frontend/src/platform.rs @@ -38,13 +38,14 @@ pub async fn load_signal_and_get_timeline( var_format: shared::VarFormat, ) -> shared::Timeline { platform::load_signal_and_get_timeline( - signal_ref, + signal_ref, timeline_zoom, timeline_viewport_width, - timeline_viewport_x, - block_height, + timeline_viewport_x, + block_height, var_format, - ).await + ) + .await } pub async fn unload_signal(signal_ref: wellen::SignalRef) { diff --git a/frontend/src/platform/browser.rs b/frontend/src/platform/browser.rs index 796f007..09f94fb 100644 --- a/frontend/src/platform/browser.rs +++ b/frontend/src/platform/browser.rs @@ -87,16 +87,15 @@ pub(super) async fn load_signal_and_get_timeline( waveform.load_signals_multi_threaded(&[signal_ref]); let signal = waveform.get_signal(signal_ref).unwrap(); let time_table = waveform.time_table(); - let timeline = - shared::signal_to_timeline( - signal, - time_table, - timeline_zoom, - timeline_viewport_width, - timeline_viewport_x, - block_height, - var_format, - ); + let timeline = shared::signal_to_timeline( + signal, + time_table, + timeline_zoom, + timeline_viewport_width, + timeline_viewport_x, + block_height, + var_format, + ); timeline } diff --git a/frontend/src/waveform_panel/pixi_canvas.rs b/frontend/src/waveform_panel/pixi_canvas.rs index 69e5960..532eded 100644 --- a/frontend/src/waveform_panel/pixi_canvas.rs +++ b/frontend/src/waveform_panel/pixi_canvas.rs @@ -53,7 +53,12 @@ impl PixiCanvas { let task_with_controller = Mutable::new(None); // -- FastWave-specific -- let timeline_getter = Rc::new(Closure::new( - |signal_ref_index, timeline_zoom, timeline_viewport_width, timeline_viewport_x, row_height, var_format| { + |signal_ref_index, + timeline_zoom, + timeline_viewport_width, + timeline_viewport_x, + row_height, + var_format| { future_to_promise(async move { let signal_ref = wellen::SignalRef::from_index(signal_ref_index).unwrap_throw(); let timeline = platform::load_signal_and_get_timeline( @@ -84,15 +89,17 @@ impl PixiCanvas { })) .update_raw_el(|raw_el| { // @TODO rewrite to a native Zoon API - raw_el.event_handler(clone!((controller) move |event: events_extra::WheelEvent| { - if let Some(controller) = controller.lock_ref().as_ref() { - controller.zoom_or_pan( - event.delta_y(), - event.shift_key(), - event.offset_x() as u32, - ); - } - })) + raw_el.event_handler( + clone!((controller) move |event: events_extra::WheelEvent| { + if let Some(controller) = controller.lock_ref().as_ref() { + controller.zoom_or_pan( + event.delta_y(), + event.shift_key(), + event.offset_x() as u32, + ); + } + }), + ) }) .after_insert(clone!((controller, timeline_getter) move |element| { Task::start(async move { @@ -100,8 +107,8 @@ impl PixiCanvas { 1., width.get(), 0, - row_height, - row_gap, + row_height, + row_gap, &timeline_getter ); pixi_controller.init(&element).await; @@ -140,8 +147,16 @@ mod js_bridge { type TimelineViewportX = i32; type RowHeight = u32; type VarFormatJs = JsValue; - type TimelineGetter = - Closure TimelinePromise>; + type TimelineGetter = Closure< + dyn FnMut( + SignalRefIndex, + TimelineZoom, + TimelineViewportWidth, + TimelineViewportX, + RowHeight, + VarFormatJs, + ) -> TimelinePromise, + >; // Note: Add all corresponding methods to `frontend/typescript/pixi_canvas/pixi_canvas.ts` #[wasm_bindgen(module = "/typescript/bundles/pixi_canvas.js")] @@ -184,7 +199,12 @@ mod js_bridge { pub fn set_var_format(this: &PixiController, index: usize, var_format: JsValue); #[wasm_bindgen(method)] - pub fn zoom_or_pan(this: &PixiController, wheel_delta_y: f64, shift_key: bool, offset_x: u32); + pub fn zoom_or_pan( + this: &PixiController, + wheel_delta_y: f64, + shift_key: bool, + offset_x: u32, + ); #[wasm_bindgen(method)] pub fn remove_var(this: &PixiController, index: usize); diff --git a/frontend/typescript/bundles/pixi_canvas.js b/frontend/typescript/bundles/pixi_canvas.js index 27976c4..d542b5e 100644 --- a/frontend/typescript/bundles/pixi_canvas.js +++ b/frontend/typescript/bundles/pixi_canvas.js @@ -35223,10 +35223,22 @@ var PixiController = class { } else { const offset_x_ratio = offset_x / this.timeline_viewport_width; const old_timeline_width = this.timeline_viewport_width * this.timeline_zoom; - this.timeline_zoom -= Math.sign(wheel_delta_y) * this.timeline_zoom * 0.5; - const new_timeline_width = this.timeline_viewport_width * this.timeline_zoom; - const timeline_width_difference = new_timeline_width - old_timeline_width; - this.timeline_viewport_x += timeline_width_difference * offset_x_ratio; + const new_zoom = this.timeline_zoom - Math.sign(wheel_delta_y) * this.timeline_zoom * 0.5; + const new_timeline_width = this.timeline_viewport_width * new_zoom; + if (new_timeline_width < this.timeline_viewport_width) { + this.timeline_zoom = 1; + this.timeline_viewport_x = 0; + } else { + const timeline_width_difference = new_timeline_width - old_timeline_width; + this.timeline_viewport_x += timeline_width_difference * offset_x_ratio; + this.timeline_zoom = new_zoom; + } + } + const timeline_width = this.timeline_viewport_width * this.timeline_zoom; + if (this.timeline_viewport_x < 0) { + this.timeline_viewport_x = 0; + } else if (this.timeline_viewport_x + this.timeline_viewport_width > timeline_width) { + this.timeline_viewport_x = timeline_width - this.timeline_viewport_width; } this.redraw_all_rows(); } diff --git a/frontend/typescript/pixi_canvas/pixi_canvas.ts b/frontend/typescript/pixi_canvas/pixi_canvas.ts index f3c60b9..04e0935 100644 --- a/frontend/typescript/pixi_canvas/pixi_canvas.ts +++ b/frontend/typescript/pixi_canvas/pixi_canvas.ts @@ -151,13 +151,24 @@ export class PixiController { if (shift_key) { this.timeline_viewport_x += Math.sign(wheel_delta_y) * 20; } else { - // @TODO bounds const offset_x_ratio = offset_x / this.timeline_viewport_width; const old_timeline_width = this.timeline_viewport_width * this.timeline_zoom; - this.timeline_zoom -= Math.sign(wheel_delta_y) * this.timeline_zoom * 0.5; - const new_timeline_width = this.timeline_viewport_width * this.timeline_zoom; - const timeline_width_difference = new_timeline_width - old_timeline_width; - this.timeline_viewport_x += timeline_width_difference * offset_x_ratio; + const new_zoom = this.timeline_zoom - Math.sign(wheel_delta_y) * this.timeline_zoom * 0.5; + const new_timeline_width = this.timeline_viewport_width * new_zoom; + if (new_timeline_width < this.timeline_viewport_width) { + this.timeline_zoom = 1; + this.timeline_viewport_x = 0; + } else { + const timeline_width_difference = new_timeline_width - old_timeline_width; + this.timeline_viewport_x += timeline_width_difference * offset_x_ratio; + this.timeline_zoom = new_zoom; + } + } + const timeline_width = this.timeline_viewport_width * this.timeline_zoom; + if (this.timeline_viewport_x < 0) { + this.timeline_viewport_x = 0; + } else if (this.timeline_viewport_x + this.timeline_viewport_width > timeline_width) { + this.timeline_viewport_x = timeline_width - this.timeline_viewport_width; } this.redraw_all_rows(); } diff --git a/shared/src/signal_to_timeline.rs b/shared/src/signal_to_timeline.rs index e9fc24f..f2d05b6 100644 --- a/shared/src/signal_to_timeline.rs +++ b/shared/src/signal_to_timeline.rs @@ -38,7 +38,7 @@ pub fn signal_to_timeline( while let Some((block_x, value)) = x_value_pairs.next() { if block_x >= (timeline_viewport_width as f64) { break; - } + } let next_block_x = if let Some((next_block_x, _)) = x_value_pairs.peek() { *next_block_x @@ -52,7 +52,7 @@ pub fn signal_to_timeline( } if block_x + (block_width as f64) <= 0. { continue; - } + } // @TODO cache? let value = var_format.format(value); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 3b45d05..d985c1c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -56,16 +56,15 @@ async fn load_signal_and_get_timeline( waveform.load_signals_multi_threaded(&[signal_ref]); let signal = waveform.get_signal(signal_ref).unwrap(); let time_table = waveform.time_table(); - let timeline = - shared::signal_to_timeline( - signal, - time_table, - timeline_zoom, - timeline_viewport_width, - timeline_viewport_x, - block_height, - var_format, - ); + let timeline = shared::signal_to_timeline( + signal, + time_table, + timeline_zoom, + timeline_viewport_width, + timeline_viewport_x, + block_height, + var_format, + ); Ok(serde_json::to_value(timeline).unwrap()) }