mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
WIP conversion to messages
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use std::f64::consts::PI;
|
||||
use std::{collections::HashMap, f64::consts::PI};
|
||||
|
||||
use super::DocumentMessageHandler;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene::{
|
||||
layers::style::{self, Stroke},
|
||||
@@ -11,41 +12,40 @@ use crate::{
|
||||
message_prelude::*,
|
||||
};
|
||||
|
||||
use super::DocumentMessageHandler;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SnapHandler {
|
||||
enabled: bool,
|
||||
document: DocumentMessageHandler,
|
||||
snap_targets: Option<(Vec<f64>, Vec<f64>)>,
|
||||
snappables: HashMap<Vec<LayerId>, Vec<Vec<LayerId>>>,
|
||||
overlay_messages: Vec<Message>,
|
||||
|
||||
overlay_paths: Vec<Vec<LayerId>>,
|
||||
}
|
||||
|
||||
impl SnapHandler {
|
||||
fn add_overlays(&mut self, responses: &mut VecDeque<Message>, viewport_bounds: DVec2) {
|
||||
fn add_overlay_line(responses: &mut VecDeque<Message>, transform: DAffine2) -> Vec<LayerId> {
|
||||
let layer_path = vec![generate_uuid()];
|
||||
fn add_overlay_line(&mut self, transform: DAffine2) -> Vec<LayerId> {
|
||||
let layer_path = vec![generate_uuid()];
|
||||
|
||||
let operation = Operation::AddOverlayLine {
|
||||
path: layer_path.clone(),
|
||||
transform: transform.to_cols_array(),
|
||||
style: style::PathStyle::new(Some(Stroke::new(COLOR_ACCENT, 1.0)), None),
|
||||
};
|
||||
responses.push_back(DocumentMessage::Overlay(operation.into()).into());
|
||||
let operation = Operation::AddOverlayLine {
|
||||
path: layer_path.clone(),
|
||||
transform: transform.to_cols_array(),
|
||||
style: style::PathStyle::new(Some(Stroke::new(COLOR_ACCENT, 1.0)), None),
|
||||
};
|
||||
self.overlay_messages.push(DocumentMessage::Overlay(operation.into()).into());
|
||||
|
||||
layer_path
|
||||
}
|
||||
layer_path
|
||||
}
|
||||
|
||||
fn add_overlays(&mut self, viewport_bounds: DVec2) {
|
||||
if let Some((x_targets, y_targets)) = &self.snap_targets {
|
||||
for x_target in x_targets {
|
||||
self.overlay_paths.push(add_overlay_line(
|
||||
responses,
|
||||
DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.y, 1.), PI / 2., DVec2::new(x_target.round(), 0.)),
|
||||
));
|
||||
self.overlay_paths
|
||||
.push(self.add_overlay_line(DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.y, 1.), PI / 2., DVec2::new(x_target.round(), 0.))));
|
||||
}
|
||||
for y_target in y_targets {
|
||||
self.overlay_paths.push(add_overlay_line(
|
||||
responses,
|
||||
DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.x, 1.), 0., DVec2::new(0., y_target.round())),
|
||||
));
|
||||
self.overlay_paths
|
||||
.push(self.add_overlay_line(DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.x, 1.), 0., DVec2::new(0., y_target.round()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,29 +58,30 @@ impl SnapHandler {
|
||||
|
||||
/// Gets a list of snap targets for the X and Y axes in Viewport coords for the target layers (usually all layers or all non-selected layers.)
|
||||
/// This should be called at the start of a drag.
|
||||
pub fn start_snap(&mut self, responses: &mut VecDeque<Message>, viewport_bounds: DVec2, document_message_handler: &DocumentMessageHandler, target_layers: Vec<Vec<LayerId>>) {
|
||||
if document_message_handler.snapping_enabled {
|
||||
pub fn start_snap(&mut self, viewport_bounds: DVec2, target_layers: Vec<Vec<LayerId>>) {
|
||||
if self.document.snapping_enabled {
|
||||
// Could be made into sorted Vec or a HashSet for more performant lookups.
|
||||
self.snap_targets = Some(
|
||||
target_layers
|
||||
.iter()
|
||||
.filter_map(|path| document_message_handler.graphene_document.viewport_bounding_box(path).ok()?)
|
||||
.filter_map(|path| self.document.graphene_document.viewport_bounding_box(path).ok()?)
|
||||
.flat_map(|[bound1, bound2]| [bound1, bound2, ((bound1 + bound2) / 2.)])
|
||||
.map(|vec| vec.into())
|
||||
.unzip(),
|
||||
);
|
||||
self.add_overlays(responses, viewport_bounds);
|
||||
self.add_overlays(viewport_bounds);
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the closest snap from an array of layers to the specified snap targets in viewport coords.
|
||||
/// Returns 0 for each axis that there is no snap less than the snap tolerance.
|
||||
pub fn snap_layers(&self, document_message_handler: &DocumentMessageHandler, selected_layers: &[Vec<LayerId>], mouse_delta: DVec2) -> DVec2 {
|
||||
if document_message_handler.snapping_enabled {
|
||||
pub fn snap_layers(&self, mouse_delta: DVec2) -> DVec2 {
|
||||
if self.enabled {
|
||||
if let Some((targets_x, targets_y)) = &self.snap_targets {
|
||||
let (snap_x, snap_y): (Vec<f64>, Vec<f64>) = selected_layers
|
||||
let (snap_x, snap_y): (Vec<f64>, Vec<f64>) = self
|
||||
.snappables
|
||||
.iter()
|
||||
.filter_map(|path| document_message_handler.graphene_document.viewport_bounding_box(path).ok()?)
|
||||
.filter_map(|(path, _)| self.document.graphene_document.viewport_bounding_box(path).ok()?)
|
||||
.flat_map(|[bound1, bound2]| [bound1, bound2, (bound1 + bound2) / 2.])
|
||||
.map(|vec| vec.into())
|
||||
.unzip();
|
||||
@@ -112,8 +113,8 @@ impl SnapHandler {
|
||||
}
|
||||
|
||||
/// Handles snapping of a viewport position, returning another viewport position.
|
||||
pub fn snap_position(&self, document_message_handler: &DocumentMessageHandler, position_viewport: DVec2) -> DVec2 {
|
||||
if document_message_handler.snapping_enabled {
|
||||
pub fn snap_position(&self, position_viewport: DVec2) -> DVec2 {
|
||||
if self.document.snapping_enabled {
|
||||
if let Some((targets_x, targets_y)) = &self.snap_targets {
|
||||
// For each list of snap targets, find the shortest distance to move the point to that target.
|
||||
let closest_move = DVec2::new(
|
||||
@@ -148,4 +149,18 @@ impl SnapHandler {
|
||||
self.remove_overlays(responses);
|
||||
self.snap_targets = None;
|
||||
}
|
||||
|
||||
// ---
|
||||
pub fn add_snappable(&mut self, layer: Vec<LayerId>) {
|
||||
self.snappables.insert(layer, vec![]);
|
||||
}
|
||||
|
||||
pub fn remove_snappable(&mut self, layer: Vec<LayerId>) {
|
||||
self.snappables.remove(&layer);
|
||||
}
|
||||
|
||||
pub fn process_overlays(&mut self, responses: &mut VecDeque<Message>) {
|
||||
responses.extend(self.overlay_messages.into_iter());
|
||||
self.overlay_messages.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::message_prelude::*;
|
||||
use glam::DVec2;
|
||||
use graphene::color::Color;
|
||||
|
||||
use crate::input::InputPreprocessor;
|
||||
@@ -21,6 +22,10 @@ pub enum ToolMessage {
|
||||
DocumentIsDirty,
|
||||
UpdateHints,
|
||||
SetToolOptions(ToolType, ToolOptions),
|
||||
SetSnapping(bool),
|
||||
AddSnappable(Vec<LayerId>),
|
||||
RemoveSnappable(Vec<LayerId>),
|
||||
SnapLayer(Vec<LayerId>),
|
||||
#[child]
|
||||
Fill(FillMessage),
|
||||
#[child]
|
||||
|
||||
Reference in New Issue
Block a user