Desktop: Support input from drawing tablets (#4354)

This commit is contained in:
Timon
2026-09-15 23:22:00 +02:00
committed by Dennis Kobert
parent 9e32a788ca
commit 83d17f34ab
43 changed files with 498 additions and 243 deletions

58
Cargo.lock generated
View File

@@ -1375,7 +1375,8 @@ dependencies = [
[[package]]
name = "dpi"
version = "0.1.2"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
dependencies = [
"serde",
]
@@ -7669,8 +7670,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winit"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2879d2854d1a43e48f67322d4bd097afcb6eb8f8f775c8de0260a71aea1df1aa"
dependencies = [
"bitflags 2.11.0",
"cfg_aliases",
@@ -7696,8 +7698,9 @@ dependencies = [
[[package]]
name = "winit-android"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d9c0d2cd93efec3a9f9ad819cfaf0834782403af7c0d248c784ec0c61761df"
dependencies = [
"android-activity",
"bitflags 2.11.0",
@@ -7711,8 +7714,9 @@ dependencies = [
[[package]]
name = "winit-appkit"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21310ca07851a49c348e0c2cc768e36b52ca65afda2c2354d78ed4b90074d8aa"
dependencies = [
"bitflags 2.11.0",
"block2 0.6.2",
@@ -7733,8 +7737,9 @@ dependencies = [
[[package]]
name = "winit-common"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45375fbac4cbb77260d83a30b1f9d8105880dbac99a9ae97f56656694680ff69"
dependencies = [
"memmap2 0.9.10",
"objc2 0.6.3",
@@ -7748,8 +7753,9 @@ dependencies = [
[[package]]
name = "winit-core"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4f0ccd7abb43740e2c6124ac7cae7d865ecec74eec63783e8922577ac232583"
dependencies = [
"bitflags 2.11.0",
"cursor-icon",
@@ -7763,8 +7769,9 @@ dependencies = [
[[package]]
name = "winit-orbital"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51ea1fb262e7209f265f12bd0cc792c399b14355675e65531e9c8a87db287d46"
dependencies = [
"bitflags 2.11.0",
"dpi",
@@ -7778,8 +7785,9 @@ dependencies = [
[[package]]
name = "winit-uikit"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "680a356e798837d8eb274d4556e83bceaf81698194e31aafc5cfb8a9f2fab643"
dependencies = [
"bitflags 2.11.0",
"block2 0.6.2",
@@ -7799,8 +7807,9 @@ dependencies = [
[[package]]
name = "winit-wayland"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce5afb2ba07da603f84b722c95f9f9396d2cedae3944fb6c0cda4a6f88de545"
dependencies = [
"ahash",
"bitflags 2.11.0",
@@ -7825,8 +7834,9 @@ dependencies = [
[[package]]
name = "winit-web"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c2490a953fb776fbbd5e295d54f1c3847f4f15b6c3929ec53c09acda6487a92"
dependencies = [
"atomic-waker",
"bitflags 2.11.0",
@@ -7847,8 +7857,9 @@ dependencies = [
[[package]]
name = "winit-win32"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644ea78af0e858aa3b092e5d1c67c41995a98220c81813f1353b28bc8bb91eaa"
dependencies = [
"bitflags 2.11.0",
"cursor-icon",
@@ -7863,8 +7874,9 @@ dependencies = [
[[package]]
name = "winit-x11"
version = "0.30.12"
source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b"
version = "0.31.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa5b600756534c7041aa93cd0d244d44b09fca1b89e202bd1cd80dd9f3636c46"
dependencies = [
"bitflags 2.11.0",
"bytemuck",

View File

@@ -160,7 +160,7 @@ web-sys = { version = "=0.3.98", features = [
"HtmlImageElement",
"ImageBitmapRenderingContext",
] }
winit = { git = "https://github.com/rust-windowing/winit.git" }
winit = "0.31.0-beta.2"
keyboard-types = "0.8"
url = "2.5"
tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt", "rt-multi-thread"] }
@@ -260,8 +260,6 @@ lto = "thin"
debug = true
[patch.crates-io]
# Force cargo to use only one version of the dpi crate (vendoring breaks without this)
dpi = { git = "https://github.com/rust-windowing/winit.git" }
rfd = { git = "https://github.com/timon-schelling/rfd.git", branch = "graphite" } # TODO: Remove this once https://github.com/PolyMeilex/rfd/pull/317 is merged and released
cef = { git = "https://github.com/timon-schelling/cef-rs.git", branch = "graphite-149" }
cef-dll-sys = { git = "https://github.com/timon-schelling/cef-rs.git", branch = "graphite-149" }

View File

@@ -9,19 +9,21 @@ use std::sync::mpsc::{Receiver, SyncSender};
use std::thread;
use std::time::{Duration, Instant};
use winit::application::ApplicationHandler;
use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::event::{ButtonSource, ElementState, MouseButton, StartCause, WindowEvent};
use winit::dpi::PhysicalSize;
use winit::event::{ElementState, MouseButton, StartCause, WindowEvent};
use winit::event_loop::run_on_demand::EventLoopExtRunOnDemand;
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
use winit::window::WindowId;
use crate::dirs;
use crate::event::{AppEvent, AppEventScheduler};
use crate::input::{InputAction, InputState};
use crate::persist;
use crate::preferences;
use crate::render::{RenderError, RenderState};
use crate::ui::{UiCommand, UiInstance};
use crate::window::Window;
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, InputMessage, MouseKeys, MouseState, Preferences};
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, Preferences};
use crate::wrapper::{DesktopWrapper, MmapResourceStorage, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};
pub(crate) struct App {
@@ -33,8 +35,7 @@ pub(crate) struct App {
window_maximized: bool,
window_fullscreen: bool,
window_pending_drag: bool,
pointer_position: PhysicalPosition<f64>,
pointer_lock_position: Option<PhysicalPosition<f64>>,
input_state: InputState,
ui_scale: f64,
app_event_receiver: Receiver<AppEvent>,
app_event_scheduler: AppEventScheduler,
@@ -111,8 +112,7 @@ impl App {
window_maximized: false,
window_fullscreen: false,
window_pending_drag: false,
pointer_position: Default::default(),
pointer_lock_position: Default::default(),
input_state: InputState::new(),
ui_scale: 1.,
app_event_receiver,
app_event_scheduler,
@@ -130,8 +130,8 @@ impl App {
}
}
pub(crate) fn run(mut self, event_loop: EventLoop) -> ExitReason {
event_loop.run_app(&mut self).unwrap();
pub(crate) fn run(mut self, mut event_loop: EventLoop) -> ExitReason {
event_loop.run_app_on_demand(&mut self).unwrap();
self.exit_reason
}
@@ -269,6 +269,8 @@ impl App {
});
}
DesktopFrontendMessage::UpdateViewportPhysicalBounds { x, y, width, height } => {
self.input_state.set_viewport_info(x, y, width, height, self.window_scale);
if let Some(render_state) = &mut self.render_state
&& let Some(window) = &self.window
{
@@ -347,7 +349,7 @@ impl App {
}
}
DesktopFrontendMessage::PointerLock => {
self.pointer_lock_position = Some(self.pointer_position);
self.input_state.lock_pointer();
if let Some(window) = &self.window {
window.start_pointer_lock();
}
@@ -540,14 +542,13 @@ impl ApplicationHandler for App {
fn window_event(&mut self, _event_loop: &dyn ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {
// Handle pointer lock release
if let Some(pointer_lock_position) = self.pointer_lock_position
&& let WindowEvent::PointerButton {
state: ElementState::Released,
button: ButtonSource::Mouse(MouseButton::Left),
..
} = event
if let WindowEvent::PointerButton {
state: ElementState::Released,
button,
..
} = &event && button.clone().mouse_button() == Some(MouseButton::Left)
&& let Some(pointer_lock_position) = self.input_state.unlock_pointer()
{
self.pointer_lock_position = None;
if let Some(window) = &self.window {
window.end_pointer_lock();
}
@@ -559,7 +560,12 @@ impl ApplicationHandler for App {
}));
}
self.ui.send(UiCommand::Input(event.clone()));
for action in self.input_state.process(&event) {
match action {
InputAction::Ui(event) => self.ui.send(UiCommand::Input(event)),
InputAction::Editor(message) => self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message)),
}
}
match event {
WindowEvent::CloseRequested => {
@@ -616,50 +622,20 @@ impl ApplicationHandler for App {
}
}
// Forward and Back buttons are not supported by CEF and thus need to be directly forwarded the editor
WindowEvent::PointerButton {
button: ButtonSource::Mouse(button),
state: ElementState::Pressed,
..
} => {
let mouse_keys = match button {
MouseButton::Back => Some(MouseKeys::BACK),
MouseButton::Forward => Some(MouseKeys::FORWARD),
_ => None,
};
if let Some(mouse_keys) = mouse_keys {
let message = DesktopWrapperMessage::Input(InputMessage::PointerDown {
editor_mouse_state: MouseState { mouse_keys, ..Default::default() },
modifier_keys: Default::default(),
});
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
let message = DesktopWrapperMessage::Input(InputMessage::PointerUp {
editor_mouse_state: Default::default(),
modifier_keys: Default::default(),
});
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
}
}
WindowEvent::PointerMoved { position, .. } | WindowEvent::PointerLeft { position: Some(position), .. } | WindowEvent::PointerEntered { position, .. }
if self.pointer_lock_position.is_none() =>
WindowEvent::PointerMoved { .. } | WindowEvent::PointerLeft { position: Some(_), .. } | WindowEvent::PointerEntered { .. }
if !self.input_state.pointer_locked() && self.window_pending_drag =>
{
self.pointer_position = position;
if self.window_pending_drag {
self.window_pending_drag = false;
if let Some(window) = &self.window {
window.start_drag();
}
self.window_pending_drag = false;
if let Some(window) = &self.window {
window.start_drag();
}
}
WindowEvent::PointerButton {
button: ButtonSource::Mouse(MouseButton::Left),
button,
state: ElementState::Released,
..
} => {
} if button.clone().mouse_button() == Some(MouseButton::Left) => {
self.window_pending_drag = false;
}
@@ -668,7 +644,7 @@ impl ApplicationHandler for App {
}
fn device_event(&mut self, _event_loop: &dyn ActiveEventLoop, _device_id: Option<winit::event::DeviceId>, event: winit::event::DeviceEvent) {
if self.pointer_lock_position.is_some()
if self.input_state.pointer_locked()
&& let winit::event::DeviceEvent::PointerMotion { delta: (x, y) } = event
{
let message = DesktopWrapperMessage::PointerLockMove { x, y };

242
desktop/src/input.rs Normal file
View File

@@ -0,0 +1,242 @@
use std::time::Instant;
use winit::dpi::PhysicalPosition;
use winit::event::{ButtonSource, ElementState, MouseButton, MouseScrollDelta, PointerSource, TabletToolData, TabletToolKind, WindowEvent};
use crate::ui::{MULTICLICK_ALLOWED_TRAVEL, MULTICLICK_TIMEOUT, PINCH_ZOOM_SPEED, SCROLL_LINE_HEIGHT, SCROLL_LINE_WIDTH, SCROLL_SPEED_X, SCROLL_SPEED_Y};
use crate::wrapper::messages::{DesktopWrapperMessage, InputMessage, ModifierKeys, MouseKeys, PointerState, ScrollDelta};
pub(crate) struct InputState {
viewport_info: Option<ViewportInfo>,
pointer_lock_position: Option<PhysicalPosition<f64>>,
modifier_keys: ModifierKeys,
pointer_position: PhysicalPosition<f64>,
pointer_keys: MouseKeys,
ui_capture: bool,
multiclick: Option<Multiclick>,
}
pub(crate) enum InputAction {
Ui(WindowEvent),
Editor(DesktopWrapperMessage),
}
impl InputAction {
fn editor(message: InputMessage) -> Self {
Self::Editor(DesktopWrapperMessage::Input(message))
}
}
impl InputState {
pub(crate) fn new() -> Self {
Self {
viewport_info: None,
pointer_lock_position: None,
modifier_keys: ModifierKeys::empty(),
pointer_position: PhysicalPosition::default(),
pointer_keys: MouseKeys::empty(),
ui_capture: true,
multiclick: None,
}
}
pub(crate) fn set_viewport_info(&mut self, x: f64, y: f64, width: f64, height: f64, scale: f64) {
self.viewport_info = Some(ViewportInfo { x, y, width, height, scale });
}
pub(crate) fn lock_pointer(&mut self) {
self.pointer_lock_position = Some(self.pointer_position);
}
pub(crate) fn unlock_pointer(&mut self) -> Option<PhysicalPosition<f64>> {
let position = self.pointer_lock_position.take();
if let Some(position) = position {
self.pointer_position = position;
}
position
}
pub(crate) fn pointer_locked(&self) -> bool {
self.pointer_lock_position.is_some()
}
pub(crate) fn process(&mut self, event: &WindowEvent) -> Vec<InputAction> {
match event {
WindowEvent::PointerMoved { position, source, .. } => {
self.pointer_position = *position;
let PointerSource::TabletTool { kind, data } = source else {
return vec![InputAction::Ui(event.clone())];
};
let ui_capture = if self.pointer_keys.is_empty() {
self.pointer_locked() || !self.in_viewport(*position)
} else {
self.ui_capture
};
if ui_capture {
return vec![InputAction::Ui(event.clone())];
}
vec![InputAction::editor(InputMessage::PointerMove {
editor_mouse_state: self.tablet_pointer_state(kind, data),
modifier_keys: self.modifier_keys,
})]
}
WindowEvent::PointerEntered { position, .. } | WindowEvent::PointerLeft { position: Some(position), .. } => {
self.pointer_position = *position;
vec![InputAction::Ui(event.clone())]
}
WindowEvent::PointerButton { state, button, position, .. } => {
self.pointer_position = *position;
let tablet = matches!(button, ButtonSource::TabletTool { .. });
// Stroke keeps capture decided from first button press until all buttons are released.
if state.is_pressed() && self.pointer_keys.is_empty() {
self.ui_capture = self.pointer_locked() || !tablet || !self.in_viewport(*position);
}
let mouse_button = button.clone().mouse_button();
let keys = match mouse_button {
Some(MouseButton::Left) => MouseKeys::LEFT,
Some(MouseButton::Right) => MouseKeys::RIGHT,
Some(MouseButton::Middle) => MouseKeys::MIDDLE,
Some(MouseButton::Back) => MouseKeys::BACK,
Some(MouseButton::Forward) => MouseKeys::FORWARD,
_ => MouseKeys::NONE,
};
match state {
ElementState::Pressed => self.pointer_keys.insert(keys),
ElementState::Released => self.pointer_keys.remove(keys),
}
let back_or_forward = matches!(mouse_button, Some(MouseButton::Back | MouseButton::Forward));
if self.pointer_locked() || !(back_or_forward || (tablet && !self.ui_capture)) {
return vec![InputAction::Ui(event.clone())];
}
let editor_mouse_state = match button {
ButtonSource::TabletTool { kind, data, .. } => self.tablet_pointer_state(kind, data),
_ => self.pointer_state(),
};
let modifier_keys = self.modifier_keys;
match state {
ElementState::Pressed => vec![InputAction::editor(InputMessage::PointerDown { editor_mouse_state, modifier_keys })],
ElementState::Released => {
let mut actions = vec![InputAction::editor(InputMessage::PointerUp { editor_mouse_state, modifier_keys })];
if let Some(mouse_button) = mouse_button
&& self.track_multiclick(mouse_button, *position)
{
actions.push(InputAction::editor(InputMessage::DoubleClick {
editor_mouse_state: PointerState {
mouse_keys: keys,
..editor_mouse_state
},
modifier_keys,
}));
}
actions
}
}
}
WindowEvent::MouseWheel { delta, .. } => {
if self.pointer_locked() || !self.in_viewport(self.pointer_position) {
return vec![InputAction::Ui(event.clone())];
}
let (x, y) = match delta {
MouseScrollDelta::LineDelta(x, y) => (f64::from(*x) * SCROLL_LINE_WIDTH, f64::from(*y) * SCROLL_LINE_HEIGHT),
MouseScrollDelta::PixelDelta(position) => (position.x, position.y),
};
let scroll_delta = ScrollDelta::new(-x * SCROLL_SPEED_X, -y * SCROLL_SPEED_Y, 0.);
vec![InputAction::editor(InputMessage::WheelScroll {
editor_mouse_state: PointerState { scroll_delta, ..self.pointer_state() },
modifier_keys: self.modifier_keys,
})]
}
WindowEvent::PinchGesture { delta, .. } => {
if self.pointer_locked() || !self.in_viewport(self.pointer_position) || !delta.is_normal() {
return vec![InputAction::Ui(event.clone())];
}
// TODO: This is a temporary solution to handle pinch gestures, we should handle pinch gestures editor-side instead.
let scroll_delta = ScrollDelta::new(0., -delta * PINCH_ZOOM_SPEED, 0.);
vec![InputAction::editor(InputMessage::WheelScroll {
editor_mouse_state: PointerState { scroll_delta, ..self.pointer_state() },
modifier_keys: self.modifier_keys | ModifierKeys::CONTROL,
})]
}
WindowEvent::ModifiersChanged(modifiers) => {
let modifiers = modifiers.state();
self.modifier_keys = ModifierKeys::empty();
self.modifier_keys.set(ModifierKeys::SHIFT, modifiers.shift_key());
self.modifier_keys.set(ModifierKeys::CONTROL, modifiers.control_key());
self.modifier_keys.set(ModifierKeys::ALT, modifiers.alt_key());
self.modifier_keys.set(ModifierKeys::META_OR_COMMAND, modifiers.meta_key());
vec![InputAction::Ui(event.clone())]
}
_ => vec![InputAction::Ui(event.clone())],
}
}
fn scale(&self) -> f64 {
self.viewport_info.as_ref().map_or(1., |info| info.scale)
}
fn in_viewport(&self, position: PhysicalPosition<f64>) -> bool {
self.viewport_info.as_ref().is_some_and(|info| info.contains(position))
}
fn pointer_state(&self) -> PointerState {
PointerState {
editor_position: (self.pointer_position.x / self.scale(), self.pointer_position.y / self.scale()).into(),
mouse_keys: self.pointer_keys,
..Default::default()
}
}
fn tablet_pointer_state(&self, kind: &TabletToolKind, data: &TabletToolData) -> PointerState {
PointerState {
pressure: data.force.map(|force| force.normalized(None)),
tilt: data.clone().tilt().map(|tilt| (f64::from(tilt.x), f64::from(tilt.y)).into()),
twist: data.twist.map(f64::from),
wheel: data.tangential_force.map(f64::from),
eraser: matches!(kind, TabletToolKind::Eraser),
..self.pointer_state()
}
}
fn track_multiclick(&mut self, button: MouseButton, position: PhysicalPosition<f64>) -> bool {
let now = Instant::now();
let travel = MULTICLICK_ALLOWED_TRAVEL as f64;
let double = self.multiclick.take().is_some_and(|click| {
click.button == button && now.duration_since(click.time) <= MULTICLICK_TIMEOUT && (position.x - click.position.x).abs() <= travel && (position.y - click.position.y).abs() <= travel
});
if !double {
self.multiclick = Some(Multiclick { button, time: now, position });
}
double
}
}
struct ViewportInfo {
x: f64,
y: f64,
width: f64,
height: f64,
scale: f64,
}
impl ViewportInfo {
fn contains(&self, position: PhysicalPosition<f64>) -> bool {
position.x >= self.x && position.y >= self.y && position.x <= self.x + self.width && position.y <= self.y + self.height
}
}
struct Multiclick {
button: MouseButton,
time: Instant,
position: PhysicalPosition<f64>,
}

View File

@@ -17,6 +17,7 @@ mod cli;
mod dirs;
mod event;
mod gpu_context;
mod input;
mod persist;
mod preferences;
mod render;

View File

@@ -344,6 +344,14 @@ unsafe fn position_helper(main: HWND, helper: HWND) {
let h = (r.bottom - r.top) + RESIZE_BAND_THICKNESS * 2;
let _ = unsafe { SetWindowPos(helper, Some(main), x, y, w, h, SWP_NOACTIVATE | SWP_NOSENDCHANGING) };
let outer = unsafe { CreateRectRgn(0, 0, w, h) };
let inner = unsafe { CreateRectRgn(RESIZE_BAND_THICKNESS, RESIZE_BAND_THICKNESS, w - RESIZE_BAND_THICKNESS, h - RESIZE_BAND_THICKNESS) };
let _ = unsafe { CombineRgn(Some(outer), Some(outer), Some(inner), RGN_DIFF) };
let _ = unsafe { DeleteObject(inner.into()) };
if unsafe { SetWindowRgn(helper, Some(outer), false) } == 0 {
let _ = unsafe { DeleteObject(outer.into()) };
}
}
unsafe fn calculate_hit(helper: HWND, lparam: LPARAM) -> u32 {

View File

@@ -1,5 +1,23 @@
use std::time::Duration;
pub const MULTICLICK_TIMEOUT: Duration = Duration::from_millis(500);
pub const MULTICLICK_ALLOWED_TRAVEL: usize = 4;
pub const SCROLL_LINE_HEIGHT: f64 = 40.;
pub const SCROLL_LINE_WIDTH: f64 = 40.;
#[cfg(target_os = "linux")]
pub const SCROLL_SPEED_X: f64 = 3.;
#[cfg(target_os = "linux")]
pub const SCROLL_SPEED_Y: f64 = 3.;
#[cfg(not(target_os = "linux"))]
pub const SCROLL_SPEED_X: f64 = 1.;
#[cfg(not(target_os = "linux"))]
pub const SCROLL_SPEED_Y: f64 = 1.;
pub const PINCH_ZOOM_SPEED: f64 = 300.;
pub(crate) const RESOURCE_SCHEME: &str = "resources";
pub(crate) const RESOURCE_DOMAIN: &str = "resources";
@@ -17,21 +35,3 @@ pub(crate) const HOST_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
#[cfg(target_os = "macos")]
pub(crate) const IPC_BOOTSTRAP_PREFIX: &str = "art.graphite.Graphite.ipc.";
pub(crate) const SCROLL_LINE_HEIGHT: usize = 40;
pub(crate) const SCROLL_LINE_WIDTH: usize = 40;
#[cfg(target_os = "linux")]
pub(crate) const SCROLL_SPEED_X: f32 = 3.;
#[cfg(target_os = "linux")]
pub(crate) const SCROLL_SPEED_Y: f32 = 3.;
#[cfg(not(target_os = "linux"))]
pub(crate) const SCROLL_SPEED_X: f32 = 1.;
#[cfg(not(target_os = "linux"))]
pub(crate) const SCROLL_SPEED_Y: f32 = 1.;
pub(crate) const PINCH_ZOOM_SPEED: f64 = 300.;
pub(crate) const MULTICLICK_TIMEOUT: Duration = Duration::from_millis(500);
pub(crate) const MULTICLICK_ALLOWED_TRAVEL: usize = 4;

View File

@@ -82,14 +82,16 @@ pub(crate) fn translate(input_state: &mut InputState, event: &WindowEvent) -> Ve
}
WindowEvent::PointerButton { state, button, position, .. } => {
let mouse_button = match button {
ButtonSource::Mouse(mouse_button) => mouse_button,
_ => {
return Vec::new(); // TODO: Handle touch input
}
ButtonSource::Mouse(mouse_button) => Some(*mouse_button),
ButtonSource::TabletTool { button, .. } => (*button).into(),
_ => None, // TODO: Handle touch input
};
let Some(mouse_button) = mouse_button else {
return Vec::new();
};
let _ = input_state.cursor_move(position);
let click_count = input_state.mouse_input(mouse_button, state).into();
let click_count = input_state.mouse_input(&mouse_button, state).into();
let up = matches!(state, ElementState::Released);
let button = match mouse_button {
MouseButton::Left => MouseButtonKind::Left,
@@ -110,8 +112,8 @@ pub(crate) fn translate(input_state: &mut InputState, event: &WindowEvent) -> Ve
MouseScrollDelta::LineDelta(x, y) => (x * SCROLL_LINE_WIDTH as f32, y * SCROLL_LINE_HEIGHT as f32),
MouseScrollDelta::PixelDelta(physical_position) => (physical_position.x as f32, physical_position.y as f32),
};
delta_x *= SCROLL_SPEED_X;
delta_y *= SCROLL_SPEED_Y;
delta_x *= SCROLL_SPEED_X as f32;
delta_y *= SCROLL_SPEED_Y as f32;
vec![InputEvent::MouseWheel {
data: input_state.mouse_data(),

View File

@@ -22,6 +22,8 @@ mod resources;
mod utility;
mod view;
pub use consts::{MULTICLICK_ALLOWED_TRAVEL, MULTICLICK_TIMEOUT, PINCH_ZOOM_SPEED, SCROLL_LINE_HEIGHT, SCROLL_LINE_WIDTH, SCROLL_SPEED_X, SCROLL_SPEED_Y};
pub struct UiContext<S: Stage = Started> {
inner: S::ContextData,
}

View File

@@ -4,8 +4,8 @@ use std::path::PathBuf;
pub(crate) use graphite_editor::messages::prelude::Message as EditorMessage;
pub use graphite_editor::messages::frontend::utility_types::{DocumentInfo, PersistedState};
pub use graphite_editor::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
pub use graphite_editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState as MouseState, EditorPosition as Position, MouseKeys};
pub use graphite_editor::messages::input_mapper::utility_types::keyboard::{Key, ModifierKeys};
pub use graphite_editor::messages::input_mapper::utility_types::pointer::{EditorPointerState as PointerState, EditorPosition as Position, MouseKeys, ScrollDelta};
pub use graphite_editor::messages::prelude::DocumentId;
pub use graphite_editor::messages::prelude::InputPreprocessorMessage as InputMessage;
pub use graphite_editor::messages::prelude::PreferencesMessageHandler as Preferences;

View File

@@ -3,7 +3,7 @@ pub(crate) mod menu {
use base64::engine::Engine;
use base64::engine::general_purpose::STANDARD as BASE64;
use graphite_editor::messages::input_mapper::utility_types::input_keyboard::{Key, LabeledKeyOrMouseMotion, LabeledShortcut};
use graphite_editor::messages::input_mapper::utility_types::keyboard::{Key, LabeledKeyOrMouseMotion, LabeledShortcut};
use graphite_editor::messages::input_mapper::utility_types::misc::ActionShortcut;
use graphite_editor::messages::layout::LayoutMessage;
use graphite_editor::messages::tool::tool_messages::tool_prelude::{Layout, LayoutGroup, LayoutTarget, MenuListEntry, Widget, WidgetId, WidgetRow};

View File

@@ -1,5 +1,5 @@
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::input_mouse::MouseButton;
use crate::messages::input_mapper::utility_types::keyboard::Key;
use crate::messages::input_mapper::utility_types::pointer::MouseButton;
use crate::messages::prelude::*;
#[impl_message(Message, KeyMappingMessage, Lookup)]

View File

@@ -1,7 +1,7 @@
use super::utility_types::input_keyboard::KeysGroup;
use super::utility_types::keyboard::KeysGroup;
use super::utility_types::misc::Mapping;
use crate::application::Editor;
use crate::messages::input_mapper::utility_types::input_keyboard::{self, Key};
use crate::messages::input_mapper::utility_types::keyboard::{self, Key};
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
use crate::messages::prelude::*;
@@ -58,7 +58,7 @@ impl InputMapperMessageHandler {
.map(|i| {
// TODO: Use a safe solution eventually
assert!(
i < input_keyboard::NUMBER_OF_KEYS,
i < keyboard::NUMBER_OF_KEYS,
"Attempting to convert a Key with enum index {i}, which is larger than the number of Key enums",
);
(i as u8).try_into().unwrap()

View File

@@ -1,11 +1,11 @@
use crate::application::Editor;
use crate::consts::{BIG_NUDGE_AMOUNT, BRUSH_SIZE_CHANGE_KEYBOARD, NUDGE_AMOUNT};
use crate::messages::input_mapper::key_mapping::MappingVariant;
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates};
use crate::messages::input_mapper::utility_types::input_mouse::MouseButton;
use crate::messages::input_mapper::utility_types::keyboard::{Key, KeyStates};
use crate::messages::input_mapper::utility_types::macros::*;
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping};
use crate::messages::input_mapper::utility_types::pointer::MouseButton;
use crate::messages::portfolio::document::node_graph::utility_types::Direction;
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
use crate::messages::prelude::*;

View File

@@ -1,5 +1,5 @@
use crate::messages::input_mapper::input_mapper_message_handler::InputMapperMessageContext;
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
use crate::messages::input_mapper::utility_types::keyboard::KeysGroup;
use crate::messages::prelude::*;
#[derive(ExtractField)]

View File

@@ -162,7 +162,7 @@ macro_rules! action_shortcut {
macro_rules! action_shortcut_manual {
($($keys:expr),*) => {
Some(crate::messages::input_mapper::utility_types::misc::ActionShortcut::Shortcut(
crate::messages::input_mapper::utility_types::input_keyboard::LabeledShortcut(vec![$($keys.into()),*]).into(),
crate::messages::input_mapper::utility_types::keyboard::LabeledShortcut(vec![$($keys.into()),*]).into(),
))
};
}

View File

@@ -1,7 +1,7 @@
use super::input_keyboard::{KeysGroup, LabeledShortcut, all_required_modifiers_pressed};
use super::keyboard::{KeysGroup, LabeledShortcut, all_required_modifiers_pressed};
use crate::messages::input_mapper::key_mapping::MappingVariant;
use crate::messages::input_mapper::utility_types::input_keyboard::{KeyStates, NUMBER_OF_KEYS};
use crate::messages::input_mapper::utility_types::input_mouse::NUMBER_OF_MOUSE_BUTTONS;
use crate::messages::input_mapper::utility_types::keyboard::{KeyStates, NUMBER_OF_KEYS};
use crate::messages::input_mapper::utility_types::pointer::NUMBER_OF_MOUSE_BUTTONS;
use crate::messages::prelude::*;
use core::time::Duration;

View File

@@ -1,4 +1,5 @@
pub mod input_keyboard;
pub mod input_mouse;
pub mod keyboard;
pub mod pointer;
pub mod macros;
pub mod misc;

View File

@@ -50,15 +50,20 @@ impl ScrollDelta {
}
}
// TODO: Document the difference between this and EditorMouseState
// TODO: Document the difference between this and EditorPointerState
#[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct MouseState {
pub struct PointerState {
pub position: ViewportPosition,
pub mouse_keys: MouseKeys,
pub scroll_delta: ScrollDelta,
pub pressure: Option<f64>,
pub tilt: Option<DVec2>,
pub twist: Option<f64>,
pub wheel: Option<f64>,
pub eraser: bool,
}
impl MouseState {
impl PointerState {
pub fn finish_transaction(&self, drag_start: DVec2, responses: &mut VecDeque<Message>) {
let drag_too_small = drag_start.distance(self.position) <= DRAG_THRESHOLD;
let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction };
@@ -66,15 +71,20 @@ impl MouseState {
}
}
// TODO: Document the difference between this and MouseState
// TODO: Document the difference between this and PointerState
#[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct EditorMouseState {
pub struct EditorPointerState {
pub editor_position: EditorPosition,
pub mouse_keys: MouseKeys,
pub scroll_delta: ScrollDelta,
pub pressure: Option<f64>,
pub tilt: Option<DVec2>,
pub twist: Option<f64>,
pub wheel: Option<f64>,
pub eraser: bool,
}
impl EditorMouseState {
impl EditorPointerState {
pub fn from_keys_and_editor_position(keys: u8, editor_position: EditorPosition) -> Self {
// TODO: Some graphic tablets send key codes not mentioned in the spec. In the future we would like to support these as well.
let mouse_keys = MouseKeys::from_bits_truncate(keys);
@@ -82,15 +92,20 @@ impl EditorMouseState {
Self {
editor_position,
mouse_keys,
scroll_delta: ScrollDelta::default(),
..Default::default()
}
}
pub fn to_mouse_state(&self, viewport: &ViewportMessageHandler) -> MouseState {
MouseState {
pub fn to_pointer_state(&self, viewport: &ViewportMessageHandler) -> PointerState {
PointerState {
position: (viewport.logical(self.editor_position) - viewport.offset()).into(),
mouse_keys: self.mouse_keys,
scroll_delta: self.scroll_delta,
pressure: self.pressure,
tilt: self.tilt,
twist: self.twist,
wheel: self.wheel,
eraser: self.eraser,
}
}
}

View File

@@ -1,17 +1,17 @@
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
use crate::messages::input_mapper::utility_types::input_mouse::EditorMouseState;
use crate::messages::input_mapper::utility_types::keyboard::{Key, ModifierKeys};
use crate::messages::input_mapper::utility_types::pointer::EditorPointerState;
use crate::messages::prelude::*;
#[impl_message(Message, InputPreprocessor)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum InputPreprocessorMessage {
DoubleClick { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
DoubleClick { editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys },
KeyDown { key: Key, key_repeat: bool, modifier_keys: ModifierKeys },
KeyUp { key: Key, key_repeat: bool, modifier_keys: ModifierKeys },
PointerDown { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
PointerMove { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
PointerUp { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
PointerShake { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
PointerDown { editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys },
PointerMove { editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys },
PointerUp { editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys },
PointerShake { editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys },
CurrentTime { timestamp: u64 },
WheelScroll { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
WheelScroll { editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys },
}

View File

@@ -1,7 +1,7 @@
use crate::application::Editor;
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates, ModifierKeys};
use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, MouseKeys, MouseState};
use crate::messages::input_mapper::utility_types::keyboard::{Key, KeyStates, ModifierKeys};
use crate::messages::input_mapper::utility_types::misc::FrameTimeInfo;
use crate::messages::input_mapper::utility_types::pointer::{MouseButton, MouseKeys, PointerState};
use crate::messages::prelude::*;
use std::time::Duration;
@@ -15,7 +15,7 @@ pub struct InputPreprocessorMessageHandler {
pub frame_time: FrameTimeInfo,
pub time: u64,
pub keyboard: KeyStates,
pub mouse: MouseState,
pub mouse: PointerState,
}
#[message_handler_data]
@@ -27,10 +27,10 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => {
self.update_states_of_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
self.mouse.position = mouse_state.position;
let pointer_state = editor_mouse_state.to_pointer_state(viewport);
self.mouse.position = pointer_state.position;
for key in mouse_state.mouse_keys {
for key in pointer_state.mouse_keys {
responses.add(InputMapperMessage::DoubleClick(match key {
MouseKeys::LEFT => MouseButton::Left,
MouseKeys::RIGHT => MouseButton::Right,
@@ -60,35 +60,35 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys } => {
self.update_states_of_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
self.mouse.position = mouse_state.position;
let pointer_state = editor_mouse_state.to_pointer_state(viewport);
self.mouse.position = pointer_state.position;
self.translate_mouse_event(mouse_state, true, responses);
self.translate_mouse_event(pointer_state, true, responses);
}
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => {
self.update_states_of_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
self.mouse.position = mouse_state.position;
let pointer_state = editor_mouse_state.to_pointer_state(viewport);
self.mouse.position = pointer_state.position;
responses.add(InputMapperMessage::PointerMove);
// While any pointer button is already down, additional button down events are not reported, but they are sent as `pointermove` events
self.translate_mouse_event(mouse_state, false, responses);
self.translate_mouse_event(pointer_state, false, responses);
}
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => {
self.update_states_of_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
self.mouse.position = mouse_state.position;
let pointer_state = editor_mouse_state.to_pointer_state(viewport);
self.mouse.position = pointer_state.position;
self.translate_mouse_event(mouse_state, false, responses);
self.translate_mouse_event(pointer_state, false, responses);
}
InputPreprocessorMessage::PointerShake { editor_mouse_state, modifier_keys } => {
self.update_states_of_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
self.mouse.position = mouse_state.position;
let pointer_state = editor_mouse_state.to_pointer_state(viewport);
self.mouse.position = pointer_state.position;
responses.add(InputMapperMessage::PointerShake);
}
@@ -100,9 +100,9 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => {
self.update_states_of_modifier_keys(modifier_keys, responses);
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
self.mouse.position = mouse_state.position;
self.mouse.scroll_delta = mouse_state.scroll_delta;
let pointer_state = editor_mouse_state.to_pointer_state(viewport);
self.mouse.position = pointer_state.position;
self.mouse.scroll_delta = pointer_state.scroll_delta;
responses.add(InputMapperMessage::WheelScroll);
}
@@ -116,7 +116,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
}
impl InputPreprocessorMessageHandler {
fn translate_mouse_event(&mut self, mut new_state: MouseState, allow_first_button_down: bool, responses: &mut VecDeque<Message>) {
fn translate_mouse_event(&mut self, mut new_state: PointerState, allow_first_button_down: bool, responses: &mut VecDeque<Message>) {
let click_mappings = [
(MouseKeys::LEFT, Key::MouseLeft),
(MouseKeys::RIGHT, Key::MouseRight),
@@ -185,18 +185,17 @@ impl InputPreprocessorMessageHandler {
#[cfg(test)]
mod test {
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta};
use crate::messages::input_mapper::utility_types::keyboard::{Key, ModifierKeys};
use crate::messages::input_mapper::utility_types::pointer::EditorPointerState;
use crate::messages::prelude::*;
#[test]
fn process_action_mouse_move_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let editor_mouse_state = EditorMouseState {
let editor_mouse_state = EditorPointerState {
editor_position: (4., 809.).into(),
mouse_keys: MouseKeys::default(),
scroll_delta: ScrollDelta::default(),
..Default::default()
};
let modifier_keys = ModifierKeys::ALT;
let message = InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys };
@@ -216,7 +215,7 @@ mod test {
fn process_action_mouse_down_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let editor_mouse_state = EditorMouseState::default();
let editor_mouse_state = EditorPointerState::default();
let modifier_keys = ModifierKeys::CONTROL;
let message = InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys };
@@ -235,7 +234,7 @@ mod test {
fn process_action_mouse_up_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let editor_mouse_state = EditorMouseState::default();
let editor_mouse_state = EditorPointerState::default();
let modifier_keys = ModifierKeys::SHIFT;
let message = InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys };

View File

@@ -1,4 +1,4 @@
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
use crate::messages::input_mapper::utility_types::keyboard::KeysGroup;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
use crate::messages::prelude::*;

View File

@@ -2,7 +2,7 @@ use super::widgets::button_widgets::*;
use super::widgets::input_widgets::*;
use super::widgets::label_widgets::*;
use crate::application::generate_uuid;
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
use crate::messages::input_mapper::utility_types::keyboard::KeysGroup;
use crate::messages::prelude::*;
use std::collections::HashMap;
use std::collections::hash_map::DefaultHasher;

View File

@@ -2,7 +2,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use super::utility_types::misc::{GroupFolderType, SnappingState};
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::keyboard::Key;
use crate::messages::portfolio::document::data_panel::DataPanelMessage;
use crate::messages::portfolio::document::overlays::utility_types::{OverlayContext, OverlaysType};
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;

View File

@@ -1,4 +1,4 @@
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::keyboard::Key;
use crate::messages::prelude::*;
use glam::DVec2;

View File

@@ -4,8 +4,8 @@ use crate::consts::{
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR,
};
use crate::messages::frontend::utility_types::MouseCursorIcon;
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
use crate::messages::input_mapper::utility_types::keyboard::{Key, MouseMotion};
use crate::messages::input_mapper::utility_types::pointer::ViewportPosition;
use crate::messages::portfolio::document::navigation::utility_types::NavigationOperation;
use crate::messages::portfolio::document::utility_types::misc::PTZ;
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;

View File

@@ -1,5 +1,5 @@
use super::utility_types::Direction;
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::keyboard::Key;
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::network_interface::{ImportOrExport, InputConnector, NodeTemplate, OutputConnector};

View File

@@ -392,7 +392,7 @@ impl TransformOperation {
}
pub fn hints(&self, responses: &mut VecDeque<Message>, local: bool) {
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
use crate::messages::input_mapper::utility_types::keyboard::{Key, MouseMotion};
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
let mut input_hints = Vec::new();

View File

@@ -6,7 +6,7 @@ use crate::consts::{DEFAULT_DOCUMENT_NAME, FILE_EXTENSION, GDD_FILE_EXTENSION};
use crate::messages::animation::TimingInformation;
use crate::messages::dialog::simple_dialogs;
use crate::messages::frontend::utility_types::{DocumentInfo, PersistedState};
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::keyboard::Key;
use crate::messages::input_mapper::utility_types::macros::{action_shortcut, action_shortcut_manual};
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::DocumentMessageContext;

View File

@@ -1,4 +1,4 @@
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::keyboard::Key;
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;

View File

@@ -420,7 +420,7 @@ fn extend_path_with_next_segment(tool_data: &mut FreehandToolData, position: DVe
#[cfg(test)]
mod test_freehand {
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta};
use crate::messages::input_mapper::utility_types::pointer::{EditorPointerState, MouseKeys};
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
use crate::messages::tool::common_functionality::graph_modification_utils::{NodeGraphLayer, get_stroke_width};
use crate::messages::tool::common_functionality::stroke_options::StrokeOptionsUpdate;
@@ -528,10 +528,10 @@ mod test_freehand {
let last_initial_point = initial_points[initial_points.len() - 1];
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: last_initial_point,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -587,10 +587,10 @@ mod test_freehand {
let last_extension_point = extension_points[extension_points.len() - 1];
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: last_extension_point,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -641,10 +641,10 @@ mod test_freehand {
let last_initial_point = initial_points[initial_points.len() - 1];
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: last_initial_point,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -676,10 +676,10 @@ mod test_freehand {
editor
.mousedown(
EditorMouseState {
EditorPointerState {
editor_position: first_second_point,
mouse_keys: MouseKeys::LEFT,
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::SHIFT,
)
@@ -692,10 +692,10 @@ mod test_freehand {
let last_second_point = second_path_points[second_path_points.len() - 1];
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: last_second_point,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::SHIFT,
)
@@ -765,10 +765,10 @@ mod test_freehand {
let last_point = points[points.len() - 1];
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: last_point,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)

View File

@@ -2051,8 +2051,7 @@ enum GradientDragHintState {
mod test_gradient {
use super::{gradient_to_viewport_transform, midpoint_diamonds, midpoint_ratio_at};
use crate::consts::{GRADIENT_MIDPOINT_MAX, GRADIENT_MIDPOINT_MIN};
use crate::messages::input_mapper::utility_types::input_mouse::EditorMouseState;
use crate::messages::input_mapper::utility_types::input_mouse::ScrollDelta;
use crate::messages::input_mapper::utility_types::pointer::EditorPointerState;
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, OutputConnector};
@@ -2523,10 +2522,10 @@ mod test_gradient {
editor.move_mouse(end_pos.x, end_pos.y, ModifierKeys::empty(), MouseKeys::LEFT).await;
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: end_pos,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -2577,10 +2576,10 @@ mod test_gradient {
let click_position = DVec2::new(25., 0.);
editor
.mousedown(
EditorMouseState {
EditorPointerState {
editor_position: click_position,
mouse_keys: MouseKeys::LEFT,
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -2591,10 +2590,10 @@ mod test_gradient {
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: drag_position,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -2656,10 +2655,10 @@ mod test_gradient {
editor.left_mousedown(position2.x, position2.y, ModifierKeys::empty()).await;
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: position2,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -2905,10 +2904,10 @@ mod test_gradient {
editor.move_mouse(new_viewport_end.x, new_viewport_end.y, ModifierKeys::empty(), MouseKeys::LEFT).await;
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: new_viewport_end,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)
@@ -2982,10 +2981,10 @@ mod test_gradient {
editor.move_mouse(new_viewport_end.x, new_viewport_end.y, ModifierKeys::empty(), MouseKeys::LEFT).await;
editor
.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: new_viewport_end,
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::empty(),
)

View File

@@ -14,7 +14,7 @@ pub mod text_tool;
pub mod tool_prelude {
pub use crate::messages::frontend::utility_types::MouseCursorIcon;
pub use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
pub use crate::messages::input_mapper::utility_types::keyboard::{Key, MouseMotion};
pub use crate::messages::layout::utility_types::widget_prelude::*;
pub use crate::messages::prelude::*;
pub use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionMessageContext, ToolMetadata, ToolTransition, ToolType};

View File

@@ -1,6 +1,6 @@
use super::tool_prelude::*;
use crate::consts::{COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_05, HIDE_HANDLE_DISTANCE, LINE_ROTATE_SNAP_ANGLE, SEGMENT_OVERLAY_SIZE};
use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys;
use crate::messages::input_mapper::utility_types::pointer::MouseKeys;
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_network_node_type;
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
use crate::messages::portfolio::document::overlays::utility_types::{DrawHandles, OverlayContext};

View File

@@ -2,7 +2,7 @@
use super::tool_prelude::*;
use crate::consts::*;
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
use crate::messages::input_mapper::utility_types::pointer::ViewportPosition;
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};

View File

@@ -1,6 +1,6 @@
use super::tool_prelude::*;
use crate::consts::{DRAG_THRESHOLD, PATH_JOIN_THRESHOLD, SNAP_POINT_TOLERANCE};
use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys;
use crate::messages::input_mapper::utility_types::pointer::MouseKeys;
use crate::messages::portfolio::document::node_graph::document_node_definitions::{resolve_network_node_type, resolve_proto_node_type};
use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;

View File

@@ -1,4 +1,4 @@
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::keyboard::Key;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::transformation::TransformType;
use crate::messages::prelude::*;

View File

@@ -1,5 +1,5 @@
use crate::consts::{ANGLE_MEASURE_RADIUS_FACTOR, ARC_MEASURE_RADIUS_FACTOR_RANGE, COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GRAY, SLOWING_DIVISOR};
use crate::messages::input_mapper::utility_types::input_mouse::{DocumentPosition, ViewportPosition};
use crate::messages::input_mapper::utility_types::pointer::{DocumentPosition, ViewportPosition};
use crate::messages::portfolio::document::overlays::utility_functions::text_width;
use crate::messages::portfolio::document::overlays::utility_types::{OverlayProvider, Pivot};
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;

View File

@@ -4,7 +4,7 @@ use super::common_functionality::shape_editor::ShapeState;
use super::tool_messages::*;
use crate::messages::broadcast::BroadcastMessage;
use crate::messages::broadcast::event::EventMessage;
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, LabeledKeyOrMouseMotion, LabeledShortcut, MouseMotion};
use crate::messages::input_mapper::utility_types::keyboard::{Key, KeysGroup, LabeledKeyOrMouseMotion, LabeledShortcut, MouseMotion};
use crate::messages::input_mapper::utility_types::macros::action_shortcut;
use crate::messages::input_mapper::utility_types::misc::ActionShortcut;
use crate::messages::layout::utility_types::widget_prelude::*;

View File

@@ -1,6 +1,6 @@
use crate::application::Editor;
use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition};
use crate::messages::input_mapper::utility_types::keyboard::ModifierKeys;
use crate::messages::input_mapper::utility_types::pointer::{EditorPointerState, MouseKeys, ViewportPosition};
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
use crate::messages::prelude::*;
use crate::messages::tool::tool_messages::tool_prelude::Key;
@@ -126,7 +126,7 @@ impl EditorTestUtils {
self.move_mouse(position.x, position.y, modifier_keys, MouseKeys::empty()).await;
self.mousedown(
EditorMouseState {
EditorPointerState {
editor_position: position,
mouse_keys: button,
..Default::default()
@@ -136,7 +136,7 @@ impl EditorTestUtils {
.await;
self.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: position,
..Default::default()
},
@@ -155,10 +155,10 @@ impl EditorTestUtils {
self.move_mouse(x2, y2, modifier_keys, MouseKeys::LEFT).await;
self.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: (x2, y2).into(),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
modifier_keys,
)
@@ -175,10 +175,10 @@ impl EditorTestUtils {
self.move_mouse(100., 100., ModifierKeys::default(), MouseKeys::LEFT).await;
self.mousedown(
EditorMouseState {
EditorPointerState {
editor_position: (100., 100.).into(),
mouse_keys: MouseKeys::LEFT | MouseKeys::RIGHT,
scroll_delta: ScrollDelta::default(),
..Default::default()
},
ModifierKeys::default(),
)
@@ -194,7 +194,7 @@ impl EditorTestUtils {
}
pub async fn move_mouse(&mut self, x: f64, y: f64, modifier_keys: ModifierKeys, mouse_keys: MouseKeys) {
let editor_mouse_state = EditorMouseState {
let editor_mouse_state = EditorPointerState {
editor_position: ViewportPosition::new(x, y),
mouse_keys,
..Default::default()
@@ -202,11 +202,11 @@ impl EditorTestUtils {
self.input(InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }).await;
}
pub async fn mousedown(&mut self, editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys) {
pub async fn mousedown(&mut self, editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys) {
self.input(InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys }).await;
}
pub async fn mouseup(&mut self, editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys) {
pub async fn mouseup(&mut self, editor_mouse_state: EditorPointerState, modifier_keys: ModifierKeys) {
self.handle_message(InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys }).await;
}
@@ -219,10 +219,10 @@ impl EditorTestUtils {
pub async fn left_mousedown(&mut self, x: f64, y: f64, modifier_keys: ModifierKeys) {
self.mousedown(
EditorMouseState {
EditorPointerState {
editor_position: (x, y).into(),
mouse_keys: MouseKeys::LEFT,
scroll_delta: ScrollDelta::default(),
..Default::default()
},
modifier_keys,
)
@@ -231,10 +231,10 @@ impl EditorTestUtils {
pub async fn left_mouseup(&mut self, x: f64, y: f64, modifier_keys: ModifierKeys) {
self.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: (x, y).into(),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
modifier_keys,
)
@@ -287,10 +287,10 @@ impl EditorTestUtils {
pub async fn double_click(&mut self, position: DVec2) {
self.handle_message(InputPreprocessorMessage::DoubleClick {
editor_mouse_state: EditorMouseState {
editor_mouse_state: EditorPointerState {
editor_position: position,
mouse_keys: MouseKeys::LEFT,
scroll_delta: ScrollDelta::default(),
..Default::default()
},
modifier_keys: ModifierKeys::empty(),
})
@@ -311,10 +311,10 @@ impl EditorTestUtils {
}
self.mouseup(
EditorMouseState {
EditorPointerState {
editor_position: points[points.len() - 1],
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
..Default::default()
},
modifier_keys,
)
@@ -373,8 +373,8 @@ pub mod test_prelude {
pub use crate::application::Editor;
pub use crate::float_eq;
pub use crate::messages::clipboard::utility_types::ClipboardContentRaw;
pub use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
pub use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys;
pub use crate::messages::input_mapper::utility_types::keyboard::{Key, ModifierKeys};
pub use crate::messages::input_mapper::utility_types::pointer::MouseKeys;
pub use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
pub use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
pub use crate::messages::prelude::*;

View File

@@ -15,8 +15,8 @@ use wasm_bindgen::prelude::*;
mod editor_commands {
use crate::helpers::translate_key;
use editor::messages::clipboard::utility_types::ClipboardContentRaw;
use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta};
use editor::messages::input_mapper::utility_types::keyboard::ModifierKeys;
use editor::messages::input_mapper::utility_types::pointer::{EditorPointerState, ScrollDelta};
use editor::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use editor::messages::portfolio::document::utility_types::network_interface::ImportOrExport;
use editor::messages::portfolio::utility_types::PanelGroupId;
@@ -299,14 +299,14 @@ mod editor_commands {
/// Mouse movement within the screenspace bounds of the viewport
fn on_mouse_move(x: f64, y: f64, mouse_keys: u8, modifiers: u8) -> Message {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let editor_mouse_state = EditorPointerState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }.into()
}
/// Mouse scrolling within the screenspace bounds of the viewport
fn on_wheel_scroll(x: f64, y: f64, mouse_keys: u8, wheel_delta_x: f64, wheel_delta_y: f64, wheel_delta_z: f64, modifiers: u8) -> Message {
let mut editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let mut editor_mouse_state = EditorPointerState::from_keys_and_editor_position(mouse_keys, (x, y).into());
editor_mouse_state.scroll_delta = ScrollDelta::new(wheel_delta_x, wheel_delta_y, wheel_delta_z);
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys }.into()
@@ -314,28 +314,28 @@ mod editor_commands {
/// A mouse button depressed within screenspace the bounds of the viewport
fn on_mouse_down(x: f64, y: f64, mouse_keys: u8, modifiers: u8) -> Message {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let editor_mouse_state = EditorPointerState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys }.into()
}
/// A mouse button released
fn on_mouse_up(x: f64, y: f64, mouse_keys: u8, modifiers: u8) -> Message {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let editor_mouse_state = EditorPointerState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys }.into()
}
/// Mouse shaken
fn on_mouse_shake(x: f64, y: f64, mouse_keys: u8, modifiers: u8) -> Message {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let editor_mouse_state = EditorPointerState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
InputPreprocessorMessage::PointerShake { editor_mouse_state, modifier_keys }.into()
}
/// Mouse double clicked
fn on_double_click(x: f64, y: f64, mouse_keys: u8, modifiers: u8) -> Message {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let editor_mouse_state = EditorPointerState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys }.into()
}

View File

@@ -8,7 +8,7 @@ use crate::native_communication::RasterizedImage;
#[cfg(not(feature = "native"))]
use editor::application::Editor;
#[cfg(feature = "editor")]
use editor::messages::input_mapper::utility_types::input_keyboard::Key;
use editor::messages::input_mapper::utility_types::keyboard::Key;
#[cfg(not(feature = "native"))]
use editor::messages::prelude::*;
use js_sys::{Object, Reflect};