Make auto-panning speed uniform (#1690)

* Make auto-panning speed uniform

* Abstract time-delta calculation to `TimeInfo`

* Update docs and add additional check

* Apply code review changes
This commit is contained in:
Elbert Ronnie 2024-03-16 12:06:22 +05:30 committed by GitHub
parent 56f8ecacc9
commit 42c822020e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 140 additions and 113 deletions

View File

@ -19,7 +19,7 @@ pub const VIEWPORT_ROTATE_SNAP_INTERVAL: f64 = 15.;
pub const VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR: f64 = 0.95;
pub const DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS: f64 = 50.;
pub const DRAG_BEYOND_VIEWPORT_SPEED_FACTOR: f64 = 0.5;
pub const DRAG_BEYOND_VIEWPORT_SPEED_FACTOR: f64 = 20.;
// Snapping point
pub const SNAP_POINT_TOLERANCE: f64 = 5.;

View File

@ -40,7 +40,7 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerStructure),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
];
const DEBUG_MESSAGE_BLOCK_LIST: &[&str] = &["AnimationFrame", "PointerMove", "PointerOutsideViewport"];
const DEBUG_MESSAGE_BLOCK_LIST: &[&str] = &["AnimationFrame", "PointerMove", "PointerOutsideViewport", "FrameTimeAdvance"];
impl Dispatcher {
pub fn new() -> Self {

View File

@ -4,6 +4,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::{KeyStates, NU
use crate::messages::input_mapper::utility_types::input_mouse::NUMBER_OF_MOUSE_BUTTONS;
use crate::messages::prelude::*;
use core::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
@ -146,3 +147,22 @@ impl ActionKeys {
}
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct FrameTimeInfo {
timestamp: Duration,
prev_timestamp: Option<Duration>,
}
impl FrameTimeInfo {
pub fn frame_duration(&self) -> Option<Duration> {
self.prev_timestamp.map(|prev| self.timestamp - prev)
}
pub fn advance_timestamp(&mut self, next_timestamp: Duration) {
debug_assert!(next_timestamp >= self.timestamp);
self.prev_timestamp = Some(self.timestamp);
self.timestamp = next_timestamp;
}
}

View File

@ -2,6 +2,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::{Key, Modifier
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ViewportBounds};
use crate::messages::prelude::*;
use core::time::Duration;
use serde::{Deserialize, Serialize};
#[impl_message(Message, InputPreprocessor)]
@ -14,5 +15,6 @@ pub enum InputPreprocessorMessage {
PointerDown { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
PointerMove { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
PointerUp { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
FrameTimeAdvance { timestamp: Duration },
WheelScroll { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
}

View File

@ -1,5 +1,6 @@
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates, ModifierKeys};
use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, MouseKeys, MouseState, ViewportBounds};
use crate::messages::input_mapper::utility_types::misc::FrameTimeInfo;
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
use crate::messages::prelude::*;
@ -7,6 +8,7 @@ use glam::DVec2;
#[derive(Debug, Default)]
pub struct InputPreprocessorMessageHandler {
pub frame_time: FrameTimeInfo,
pub keyboard: KeyStates,
pub mouse: MouseState,
pub viewport_bounds: ViewportBounds,
@ -84,6 +86,9 @@ impl MessageHandler<InputPreprocessorMessage, KeyboardPlatformLayout> for InputP
self.translate_mouse_event(mouse_state, false, responses);
}
InputPreprocessorMessage::FrameTimeAdvance { timestamp } => {
self.frame_time.advance_timestamp(timestamp);
}
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => {
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);

View File

@ -34,7 +34,9 @@ impl AutoPanning {
}
}
pub fn setup_by_mouse_position(&mut self, mouse_position: DVec2, viewport_size: DVec2, messages: &[Message], responses: &mut VecDeque<Message>) {
pub fn setup_by_mouse_position(&mut self, input: &InputPreprocessorMessageHandler, messages: &[Message], responses: &mut VecDeque<Message>) {
let mouse_position = input.mouse.position;
let viewport_size = input.viewport_bounds.size();
let is_pointer_outside_edge = mouse_position.x < 0. || mouse_position.x > viewport_size.x || mouse_position.y < 0. || mouse_position.y > viewport_size.y;
match is_pointer_outside_edge {
@ -46,9 +48,15 @@ impl AutoPanning {
/// Shifts the viewport when the mouse reaches the edge of the viewport.
///
/// If the mouse was beyond any edge, it returns the amount shifted. Otherwise it returns None.
/// The shift is proportional to the distance between edge and mouse. It is also guaranteed to be integral.
pub fn shift_viewport(mouse_position: DVec2, viewport_size: DVec2, responses: &mut VecDeque<Message>) -> Option<DVec2> {
let mouse_position = mouse_position.clamp(
/// The shift is proportional to the distance between edge and mouse, and to the duration of the frame.
/// It is also guaranteed to be integral.
pub fn shift_viewport(&self, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> Option<DVec2> {
if !self.subscribed_to_animation_frame {
return None;
}
let viewport_size = input.viewport_bounds.size();
let mouse_position = input.mouse.position.clamp(
DVec2::ZERO - DVec2::splat(DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS),
viewport_size + DVec2::splat(DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS),
);
@ -72,7 +80,8 @@ impl AutoPanning {
return None;
}
let delta = (shift_percent * DRAG_BEYOND_VIEWPORT_SPEED_FACTOR * viewport_size).round();
let time_delta = input.frame_time.frame_duration()?.as_secs_f64();
let delta = (shift_percent * DRAG_BEYOND_VIEWPORT_SPEED_FACTOR * viewport_size * time_delta).round();
responses.add(NavigationMessage::TranslateCanvas { delta });
Some(delta)
}

View File

@ -213,15 +213,12 @@ impl Fsm for ArtboardToolFsmState {
let mouse_position = input.mouse.position;
tool_data.resize_artboard(responses, document, mouse_position, from_center, constrain_square);
tool_data.auto_panning.setup_by_mouse_position(
mouse_position,
input.viewport_bounds.size(),
&[
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
],
responses,
);
// AutoPanning
let messages = [
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
ArtboardToolFsmState::ResizingBounds
}
@ -245,15 +242,12 @@ impl Fsm for ArtboardToolFsmState {
bounds.bounds[0] = position.round();
bounds.bounds[1] = position.round() + size.round();
tool_data.auto_panning.setup_by_mouse_position(
mouse_position,
input.viewport_bounds.size(),
&[
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
],
responses,
);
// AutoPanning
let messages = [
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
}
ArtboardToolFsmState::Dragging
}
@ -303,15 +297,12 @@ impl Fsm for ArtboardToolFsmState {
})
}
tool_data.auto_panning.setup_by_mouse_position(
mouse_position,
input.viewport_bounds.size(),
&[
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
],
responses,
);
// AutoPanning
let messages = [
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
ArtboardToolFsmState::Drawing
}
@ -326,12 +317,14 @@ impl Fsm for ArtboardToolFsmState {
ArtboardToolFsmState::Ready
}
(ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
// AutoPanning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
ArtboardToolFsmState::ResizingBounds
}
(ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
// AutoPanning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
tool_data.drag_current += shift;
tool_data.drag_start += shift;
}
@ -339,20 +332,20 @@ impl Fsm for ArtboardToolFsmState {
ArtboardToolFsmState::Dragging
}
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
// AutoPanning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
tool_data.drag_start += shift;
}
ArtboardToolFsmState::Drawing
}
(state, ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }) => {
tool_data.auto_panning.stop(
&[
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
],
responses,
);
// AutoPanning
let messages = [
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
];
tool_data.auto_panning.stop(&messages, responses);
state
}

View File

@ -231,7 +231,7 @@ impl Fsm for EllipseToolFsmState {
EllipseToolMessage::PointerOutsideViewport { center, lock_ratio }.into(),
EllipseToolMessage::PointerMove { center, lock_ratio }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
self
}
@ -242,7 +242,7 @@ impl Fsm for EllipseToolFsmState {
}
(EllipseToolFsmState::Drawing, EllipseToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
let _ = tool_data.auto_panning.shift_viewport(input, responses);
EllipseToolFsmState::Drawing
}

View File

@ -440,13 +440,13 @@ impl Fsm for GradientToolFsmState {
GradientToolMessage::PointerOutsideViewport { constrain_axis }.into(),
GradientToolMessage::PointerMove { constrain_axis }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
GradientToolFsmState::Drawing
}
(GradientToolFsmState::Drawing, GradientToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(selected_gradient) = &mut tool_data.selected_gradient {
selected_gradient.transform.translation += shift;
}

View File

@ -204,7 +204,7 @@ impl Fsm for LineToolFsmState {
LineToolMessage::PointerOutsideViewport { center, snap_angle, lock_angle }.into(),
LineToolMessage::PointerMove { center, snap_angle, lock_angle }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
LineToolFsmState::Drawing
}
@ -215,7 +215,7 @@ impl Fsm for LineToolFsmState {
}
(LineToolFsmState::Drawing, LineToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
let _ = tool_data.auto_panning.shift_viewport(input, responses);
LineToolFsmState::Drawing
}

View File

@ -496,7 +496,7 @@ impl Fsm for PathToolFsmState {
// Auto-panning
let messages = [PathToolMessage::PointerOutsideViewport { alt, shift }.into(), PathToolMessage::PointerMove { alt, shift }.into()];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
PathToolFsmState::DrawingBox
}
@ -507,13 +507,13 @@ impl Fsm for PathToolFsmState {
// Auto-panning
let messages = [PathToolMessage::PointerOutsideViewport { alt, shift }.into(), PathToolMessage::PointerMove { alt, shift }.into()];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
PathToolFsmState::Dragging
}
(PathToolFsmState::DrawingBox, PathToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
tool_data.drag_start_pos += shift;
}
@ -521,7 +521,7 @@ impl Fsm for PathToolFsmState {
}
(PathToolFsmState::Dragging, PathToolMessage::PointerOutsideViewport { shift, .. }) => {
// Auto-panning
if let Some(delta) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
if let Some(delta) = tool_data.auto_panning.shift_viewport(input, responses) {
let shift_state = input.keyboard.get(shift as usize);
shape_editor.move_selected_points(&document.network, &document.metadata, -delta, shift_state, responses);
}

View File

@ -685,7 +685,7 @@ impl Fsm for PenToolFsmState {
PenToolMessage::PointerOutsideViewport { snap_angle, break_handle, lock_angle }.into(),
PenToolMessage::PointerMove { snap_angle, break_handle, lock_angle }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
state
}
@ -704,7 +704,7 @@ impl Fsm for PenToolFsmState {
PenToolMessage::PointerOutsideViewport { snap_angle, break_handle, lock_angle }.into(),
PenToolMessage::PointerMove { snap_angle, break_handle, lock_angle }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
state
}
@ -715,13 +715,13 @@ impl Fsm for PenToolFsmState {
}
(PenToolFsmState::DraggingHandle, PenToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
let _ = tool_data.auto_panning.shift_viewport(input, responses);
PenToolFsmState::DraggingHandle
}
(PenToolFsmState::PlacingAnchor, PenToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
let _ = tool_data.auto_panning.shift_viewport(input, responses);
PenToolFsmState::PlacingAnchor
}

View File

@ -275,7 +275,7 @@ impl Fsm for PolygonToolFsmState {
PolygonToolMessage::PointerOutsideViewport { center, lock_ratio }.into(),
PolygonToolMessage::PointerMove { center, lock_ratio }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
self
}
@ -286,7 +286,7 @@ impl Fsm for PolygonToolFsmState {
}
(PolygonToolFsmState::Drawing, PolygonToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
let _ = tool_data.auto_panning.shift_viewport(input, responses);
PolygonToolFsmState::Drawing
}

View File

@ -237,7 +237,7 @@ impl Fsm for RectangleToolFsmState {
RectangleToolMessage::PointerOutsideViewport { center, lock_ratio }.into(),
RectangleToolMessage::PointerMove { center, lock_ratio }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
self
}
@ -248,7 +248,7 @@ impl Fsm for RectangleToolFsmState {
}
(RectangleToolFsmState::Drawing, RectangleToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
let _ = tool_data.auto_panning.shift_viewport(input, responses);
RectangleToolFsmState::Drawing
}

View File

@ -654,15 +654,12 @@ impl Fsm for SelectToolFsmState {
}
tool_data.drag_current += mouse_delta;
tool_data.auto_panning.setup_by_mouse_position(
input.mouse.position,
input.viewport_bounds.size(),
&[
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
],
responses,
);
// AutoPanning
let messages = [
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
SelectToolFsmState::Dragging
}
@ -698,15 +695,12 @@ impl Fsm for SelectToolFsmState {
selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse());
tool_data.auto_panning.setup_by_mouse_position(
input.mouse.position,
input.viewport_bounds.size(),
&[
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
],
responses,
);
// AutoPanning
let messages = [
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
}
}
SelectToolFsmState::ResizingBounds
@ -751,15 +745,12 @@ impl Fsm for SelectToolFsmState {
let snapped_mouse_position = mouse_position; //tool_data.snap_manager.snap_position(responses, document, mouse_position);
tool_data.pivot.set_viewport_position(snapped_mouse_position, document, responses);
tool_data.auto_panning.setup_by_mouse_position(
input.mouse.position,
input.viewport_bounds.size(),
&[
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
],
responses,
);
// AutoPanning
let messages = [
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
SelectToolFsmState::DraggingPivot
}
@ -767,15 +758,12 @@ impl Fsm for SelectToolFsmState {
tool_data.drag_current = input.mouse.position;
responses.add(OverlaysMessage::Draw);
tool_data.auto_panning.setup_by_mouse_position(
input.mouse.position,
input.viewport_bounds.size(),
&[
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
],
responses,
);
// AutoPanning
let messages = [
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
let selection = tool_data.nested_selection_behavior;
SelectToolFsmState::DrawingBox { selection }
@ -800,7 +788,8 @@ impl Fsm for SelectToolFsmState {
SelectToolFsmState::Ready { selection }
}
(SelectToolFsmState::Dragging, SelectToolMessage::PointerOutsideViewport(_)) => {
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
// AutoPanning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
tool_data.drag_current += shift;
tool_data.drag_start += shift;
}
@ -808,7 +797,8 @@ impl Fsm for SelectToolFsmState {
SelectToolFsmState::Dragging
}
(SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerOutsideViewport(_)) => {
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
// AutoPanning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(ref mut bounds) = &mut tool_data.bounding_box_manager {
bounds.center_of_transformation += shift;
bounds.original_bound_transform.translation += shift;
@ -818,25 +808,26 @@ impl Fsm for SelectToolFsmState {
self
}
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport(_)) => {
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
// AutoPanning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
self
}
(SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::PointerOutsideViewport(_)) => {
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
// AutoPanning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
tool_data.drag_start += shift;
}
self
}
(state, SelectToolMessage::PointerOutsideViewport(modifier_keys)) => {
tool_data.auto_panning.stop(
&[
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
],
responses,
);
// AutoPanning
let messages = [
SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(),
SelectToolMessage::PointerMove(modifier_keys).into(),
];
tool_data.auto_panning.stop(&messages, responses);
state
}

View File

@ -271,13 +271,13 @@ impl Fsm for SplineToolFsmState {
// Auto-panning
let messages = [SplineToolMessage::PointerOutsideViewport.into(), SplineToolMessage::PointerMove.into()];
tool_data.auto_panning.setup_by_mouse_position(input.mouse.position, input.viewport_bounds.size(), &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
SplineToolFsmState::Drawing
}
(SplineToolFsmState::Drawing, SplineToolMessage::PointerOutsideViewport) => {
// Auto-panning
let _ = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses);
let _ = tool_data.auto_panning.shift_viewport(input, responses);
SplineToolFsmState::Drawing
}

View File

@ -48,7 +48,7 @@ pub fn wasm_memory() -> JsValue {
}
/// Helper function for calling JS's `requestAnimationFrame` with the given closure
fn request_animation_frame(f: &Closure<dyn FnMut()>) {
fn request_animation_frame(f: &Closure<dyn FnMut(f64)>) {
web_sys::window()
.expect("No global `window` exists")
.request_animation_frame(f.as_ref().unchecked_ref())
@ -235,10 +235,17 @@ impl JsEditorHandle {
let f = std::rc::Rc::new(RefCell::new(None));
let g = f.clone();
*g.borrow_mut() = Some(Closure::new(move || {
*g.borrow_mut() = Some(Closure::new(move |timestamp| {
wasm_bindgen_futures::spawn_local(poll_node_graph_evaluation());
call_closure_with_editor_and_handle(|editor, handle| {
let micros: f64 = timestamp * 1000.;
let timestamp = Duration::from_micros(micros.round() as u64);
for message in editor.handle_message(InputPreprocessorMessage::FrameTimeAdvance { timestamp }) {
handle.send_frontend_message_to_js(message);
}
for message in editor.handle_message(BroadcastMessage::TriggerEvent(BroadcastEvent::AnimationFrame)) {
handle.send_frontend_message_to_js(message);
}