feat: add local pan offset to eliminate one-frame panning latency in shader canvas
This commit is contained in:
@@ -893,6 +893,8 @@ pub struct CanvasShaderState {
|
|||||||
pub middle_pressed: bool,
|
pub middle_pressed: bool,
|
||||||
/// Distinguishes Space+left temporary pan from a physical middle-button pan.
|
/// Distinguishes Space+left temporary pan from a physical middle-button pan.
|
||||||
pub space_left_pan: bool,
|
pub space_left_pan: bool,
|
||||||
|
/// Immediate local pan offset maintained during active panning to eliminate 1-frame Elm update latency.
|
||||||
|
pub local_pan_offset: Option<Vector>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Canvas shader program — implements `iced::widget::shader::Program`.
|
/// Canvas shader program — implements `iced::widget::shader::Program`.
|
||||||
@@ -988,6 +990,10 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
_shell: &mut Shell<'_, Message>,
|
_shell: &mut Shell<'_, Message>,
|
||||||
) -> (iced::event::Status, Option<Message>) {
|
) -> (iced::event::Status, Option<Message>) {
|
||||||
|
if !state.middle_pressed {
|
||||||
|
state.local_pan_offset = None;
|
||||||
|
}
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
shader::Event::Mouse(mouse_event) => {
|
shader::Event::Mouse(mouse_event) => {
|
||||||
match mouse_event {
|
match mouse_event {
|
||||||
@@ -1005,7 +1011,7 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
self.engine_w as f32,
|
self.engine_w as f32,
|
||||||
self.engine_h as f32,
|
self.engine_h as f32,
|
||||||
self.zoom,
|
self.zoom,
|
||||||
self.pan_offset,
|
state.local_pan_offset.unwrap_or(self.pan_offset),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Left mouse drag (drawing)
|
// Left mouse drag (drawing)
|
||||||
@@ -1024,7 +1030,8 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
let start = state.pan_start.unwrap();
|
let start = state.pan_start.unwrap();
|
||||||
let delta = position - start;
|
let delta = position - start;
|
||||||
state.pan_start = Some(position);
|
state.pan_start = Some(position);
|
||||||
let mut new_pan = self.pan_offset;
|
let current_pan = state.local_pan_offset.unwrap_or(self.pan_offset);
|
||||||
|
let mut new_pan = current_pan;
|
||||||
new_pan.x += delta.x;
|
new_pan.x += delta.x;
|
||||||
new_pan.y += delta.y;
|
new_pan.y += delta.y;
|
||||||
|
|
||||||
@@ -1048,6 +1055,8 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
(bounds.height - min_vis_h).max(0.0),
|
(bounds.height - min_vis_h).max(0.0),
|
||||||
) - default_oy;
|
) - default_oy;
|
||||||
|
|
||||||
|
state.local_pan_offset = Some(new_pan);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
iced::event::Status::Captured,
|
iced::event::Status::Captured,
|
||||||
Some(Message::CanvasPanZoom {
|
Some(Message::CanvasPanZoom {
|
||||||
@@ -1079,6 +1088,7 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
state.middle_pressed = true;
|
state.middle_pressed = true;
|
||||||
state.space_left_pan = true;
|
state.space_left_pan = true;
|
||||||
state.pan_start = cursor.position();
|
state.pan_start = cursor.position();
|
||||||
|
state.local_pan_offset = Some(self.pan_offset);
|
||||||
return (iced::event::Status::Captured, None);
|
return (iced::event::Status::Captured, None);
|
||||||
}
|
}
|
||||||
let local_pos = {
|
let local_pos = {
|
||||||
@@ -1105,6 +1115,7 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
if let Some(pos) = cursor.position() {
|
if let Some(pos) = cursor.position() {
|
||||||
state.middle_pressed = true;
|
state.middle_pressed = true;
|
||||||
state.pan_start = Some(pos);
|
state.pan_start = Some(pos);
|
||||||
|
state.local_pan_offset = Some(self.pan_offset);
|
||||||
return (iced::event::Status::Captured, None);
|
return (iced::event::Status::Captured, None);
|
||||||
}
|
}
|
||||||
} else if button == mouse::Button::Right {
|
} else if button == mouse::Button::Right {
|
||||||
@@ -1142,6 +1153,7 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
state.middle_pressed = false;
|
state.middle_pressed = false;
|
||||||
state.space_left_pan = false;
|
state.space_left_pan = false;
|
||||||
state.pan_start = None;
|
state.pan_start = None;
|
||||||
|
state.local_pan_offset = None;
|
||||||
return (iced::event::Status::Captured, None);
|
return (iced::event::Status::Captured, None);
|
||||||
}
|
}
|
||||||
state.left_pressed = false;
|
state.left_pressed = false;
|
||||||
@@ -1152,6 +1164,7 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
} else if button == mouse::Button::Middle {
|
} else if button == mouse::Button::Middle {
|
||||||
state.middle_pressed = false;
|
state.middle_pressed = false;
|
||||||
state.pan_start = None;
|
state.pan_start = None;
|
||||||
|
state.local_pan_offset = None;
|
||||||
return (iced::event::Status::Captured, None);
|
return (iced::event::Status::Captured, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1240,7 +1253,7 @@ impl shader::Program<Message> for CanvasShaderProgram {
|
|||||||
/// and pixel data so `prepare()` can upload only the changed sub-region.
|
/// and pixel data so `prepare()` can upload only the changed sub-region.
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
_state: &Self::State,
|
state: &Self::State,
|
||||||
_cursor: mouse::Cursor,
|
_cursor: mouse::Cursor,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
) -> Self::Primitive {
|
) -> Self::Primitive {
|
||||||
|
|||||||
Reference in New Issue
Block a user