mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 07:38:11 +08:00
Fix gradient tool
This commit is contained in:
committed by
Keavon Chambers
parent
6173662a40
commit
9a39c4a0cc
@@ -41,6 +41,14 @@ impl DocumentMetadata {
|
|||||||
self.all_layers()
|
self.all_layers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn selected_layers_contains(&self, layer: LayerNodeIdentifier) -> bool {
|
||||||
|
self.selected_layers().any(|selected| selected == layer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn selected_visible_layers(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||||
|
self.all_layers()
|
||||||
|
}
|
||||||
|
|
||||||
/// Access the [`NodeRelations`] of a layer
|
/// Access the [`NodeRelations`] of a layer
|
||||||
fn get_relations(&self, node_identifier: LayerNodeIdentifier) -> Option<&NodeRelations> {
|
fn get_relations(&self, node_identifier: LayerNodeIdentifier) -> Option<&NodeRelations> {
|
||||||
self.structure.get(&node_identifier)
|
self.structure.get(&node_identifier)
|
||||||
@@ -90,12 +98,27 @@ impl DocumentMetadata {
|
|||||||
.filter_map(|layer| self.click_targets.get(&layer).map(|targets| (layer, targets)))
|
.filter_map(|layer| self.click_targets.get(&layer).map(|targets| (layer, targets)))
|
||||||
.find(|(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.transform_from_document(*layer))))
|
.find(|(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.transform_from_document(*layer))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the bounding box of the click target of the specified layer in the specified transform space
|
||||||
|
pub fn bounding_box(&self, layer: LayerNodeIdentifier, transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||||
|
self.click_targets
|
||||||
|
.get(&layer)?
|
||||||
|
.iter()
|
||||||
|
.filter_map(|click_target| click_target.subpath.bounding_box_with_transform(transform))
|
||||||
|
.reduce(Quad::combine_bounds)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Id of a layer node
|
/// Id of a layer node
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct LayerNodeIdentifier(NonZeroU64);
|
pub struct LayerNodeIdentifier(NonZeroU64);
|
||||||
|
|
||||||
|
impl Default for LayerNodeIdentifier {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::ROOT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LayerNodeIdentifier {
|
impl LayerNodeIdentifier {
|
||||||
const ROOT: Self = LayerNodeIdentifier::new_unchecked(0);
|
const ROOT: Self = LayerNodeIdentifier::new_unchecked(0);
|
||||||
|
|
||||||
@@ -283,6 +306,10 @@ impl LayerNodeIdentifier {
|
|||||||
document_metadata.structure.remove(&node);
|
document_metadata.structure.remove(&node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exists(&self, document_metadata: &DocumentMetadata) -> bool {
|
||||||
|
document_metadata.get_relations(*self).is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodeId> for LayerNodeIdentifier {
|
impl From<NodeId> for LayerNodeIdentifier {
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
|||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use bezier_rs::{ManipulatorGroup, Subpath};
|
use bezier_rs::{ManipulatorGroup, Subpath};
|
||||||
use document_legacy::{document_metadata::LayerNodeIdentifier, LayerId, Operation};
|
use document_legacy::{document::Document, document_metadata::LayerNodeIdentifier, LayerId, Operation};
|
||||||
use graph_craft::document::{value::TaggedValue, DocumentNode, NodeId, NodeInput, NodeNetwork};
|
use graph_craft::document::{value::TaggedValue, DocumentNode, NodeId, NodeInput, NodeNetwork};
|
||||||
use graphene_core::uuid::ManipulatorGroupId;
|
use graphene_core::uuid::ManipulatorGroupId;
|
||||||
|
use graphene_core::vector::style::{FillType, Gradient};
|
||||||
|
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
@@ -17,6 +18,7 @@ pub fn new_vector_layer(subpaths: Vec<Subpath<ManipulatorGroupId>>, layer_path:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a legacy node graph frame TODO: remove
|
||||||
pub fn new_custom_layer(network: NodeNetwork, layer_path: Vec<LayerId>, responses: &mut VecDeque<Message>) {
|
pub fn new_custom_layer(network: NodeNetwork, layer_path: Vec<LayerId>, responses: &mut VecDeque<Message>) {
|
||||||
responses.add(DocumentMessage::DeselectAllLayers);
|
responses.add(DocumentMessage::DeselectAllLayers);
|
||||||
responses.add(Operation::AddFrame {
|
responses.add(Operation::AddFrame {
|
||||||
@@ -28,6 +30,7 @@ pub fn new_custom_layer(network: NodeNetwork, layer_path: Vec<LayerId>, response
|
|||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Batch set all of the manipulator groups to mirror on a specific layer
|
||||||
pub fn set_manipulator_mirror_angle(manipulator_groups: &[ManipulatorGroup<ManipulatorGroupId>], layer_path: &[u64], mirror_angle: bool, responses: &mut VecDeque<Message>) {
|
pub fn set_manipulator_mirror_angle(manipulator_groups: &[ManipulatorGroup<ManipulatorGroupId>], layer_path: &[u64], mirror_angle: bool, responses: &mut VecDeque<Message>) {
|
||||||
for manipulator_group in manipulator_groups {
|
for manipulator_group in manipulator_groups {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
@@ -40,6 +43,64 @@ pub fn set_manipulator_mirror_angle(manipulator_groups: &[ManipulatorGroup<Manip
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Locate the subpaths from the shape nodes of a particular layer
|
||||||
|
pub fn get_subpaths(layer: LayerNodeIdentifier, document: &Document) -> Option<&Vec<Subpath<ManipulatorGroupId>>> {
|
||||||
|
if let TaggedValue::Subpaths(subpaths) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 0)? {
|
||||||
|
Some(subpaths)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the currently mirrored handles for a particular layer from the shape node
|
||||||
|
pub fn get_mirror_handles(layer: LayerNodeIdentifier, document: &Document) -> Option<&Vec<ManipulatorGroupId>> {
|
||||||
|
if let TaggedValue::ManipulatorGroupIds(mirror_handles) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 1)? {
|
||||||
|
Some(mirror_handles)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current gradient of a layer from the closest fill node
|
||||||
|
pub fn get_gradient(layer: LayerNodeIdentifier, document: &Document) -> Option<Gradient> {
|
||||||
|
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Fill")?;
|
||||||
|
let TaggedValue::FillType(FillType::Gradient) = inputs.get(1)?.as_value()? else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let TaggedValue::GradientType(gradient_type) = inputs.get(3)?.as_value()? else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let TaggedValue::DVec2(start) = inputs.get(4)?.as_value()? else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let TaggedValue::DVec2(end) = inputs.get(5)?.as_value()? else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let TaggedValue::DAffine2(transform) = inputs.get(6)?.as_value()? else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let TaggedValue::GradientPositions(positions) = inputs.get(7)?.as_value()? else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(Gradient {
|
||||||
|
start: start.clone(),
|
||||||
|
end: end.clone(),
|
||||||
|
transform: transform.clone(),
|
||||||
|
positions: positions.clone(),
|
||||||
|
gradient_type: gradient_type.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert subpaths to an iterator of manipulator groups
|
||||||
|
pub fn get_manipulator_groups(subpaths: &[Subpath<ManipulatorGroupId>]) -> impl Iterator<Item = &bezier_rs::ManipulatorGroup<ManipulatorGroupId>> + DoubleEndedIterator {
|
||||||
|
subpaths.iter().flat_map(|subpath| subpath.manipulator_groups())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find a manipulator group with a specific id from several subpaths
|
||||||
|
pub fn get_manipulator_from_id(subpaths: &[Subpath<ManipulatorGroupId>], id: ManipulatorGroupId) -> Option<&bezier_rs::ManipulatorGroup<ManipulatorGroupId>> {
|
||||||
|
subpaths.iter().find_map(|subpath| subpath.manipulator_from_id(id))
|
||||||
|
}
|
||||||
|
|
||||||
/// An immutable reference to a layer within the document node graph for easy access.
|
/// An immutable reference to a layer within the document node graph for easy access.
|
||||||
pub struct NodeGraphLayer<'a> {
|
pub struct NodeGraphLayer<'a> {
|
||||||
node_graph: &'a NodeNetwork,
|
node_graph: &'a NodeNetwork,
|
||||||
@@ -84,18 +145,18 @@ impl<'a> NodeGraphLayer<'a> {
|
|||||||
self.node_graph.primary_flow_from_opt(Some(self.layer_node))
|
self.node_graph.primary_flow_from_opt(Some(self.layer_node))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a specific input of a node within the layer's primary flow
|
/// Find all of the inputs of a specific node within the layer's primary flow
|
||||||
pub fn find_input(&self, node_name: &str, index: usize) -> Option<&'a TaggedValue> {
|
pub fn find_node_inputs(&self, node_name: &str) -> Option<&'a Vec<NodeInput>> {
|
||||||
for (node, _id) in self.primary_layer_flow() {
|
for (node, _id) in self.primary_layer_flow() {
|
||||||
if node.name == node_name {
|
if node.name == node_name {
|
||||||
let subpaths_input = node.inputs.get(index)?;
|
return Some(&node.inputs);
|
||||||
let NodeInput::Value { tagged_value, .. } = subpaths_input else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
return Some(tagged_value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find a specific input of a node within the layer's primary flow
|
||||||
|
pub fn find_input(&self, node_name: &str, index: usize) -> Option<&'a TaggedValue> {
|
||||||
|
self.find_node_inputs(node_name)?.get(index)?.as_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::application::generate_uuid;
|
|||||||
use crate::consts::VIEWPORT_GRID_ROUNDING_BIAS;
|
use crate::consts::VIEWPORT_GRID_ROUNDING_BIAS;
|
||||||
use crate::consts::{COLOR_ACCENT, HIDE_HANDLE_DISTANCE, MANIPULATOR_GROUP_MARKER_SIZE, PATH_OUTLINE_WEIGHT};
|
use crate::consts::{COLOR_ACCENT, HIDE_HANDLE_DISTANCE, MANIPULATOR_GROUP_MARKER_SIZE, PATH_OUTLINE_WEIGHT};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::tool_messages::pen_tool::{get_manipulator_groups, get_subpaths};
|
use crate::messages::tool::common_functionality::graph_modification_utils::{get_manipulator_groups, get_subpaths};
|
||||||
|
|
||||||
use bezier_rs::ManipulatorGroup;
|
use bezier_rs::ManipulatorGroup;
|
||||||
use document_legacy::document::Document;
|
use document_legacy::document::Document;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::consts::DRAG_THRESHOLD;
|
use crate::consts::DRAG_THRESHOLD;
|
||||||
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::tool_messages::pen_tool::{get_manipulator_from_id, get_manipulator_groups, get_mirror_handles, get_subpaths};
|
use crate::messages::tool::common_functionality::graph_modification_utils::{get_manipulator_from_id, get_manipulator_groups, get_mirror_handles, get_subpaths};
|
||||||
|
|
||||||
use bezier_rs::{Bezier, ManipulatorGroup, TValue};
|
use bezier_rs::{Bezier, ManipulatorGroup, TValue};
|
||||||
use document_legacy::document::Document;
|
use document_legacy::document::Document;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::application::generate_uuid;
|
use crate::application::generate_uuid;
|
||||||
use crate::consts::{COLOR_ACCENT, LINE_ROTATE_SNAP_ANGLE, MANIPULATOR_GROUP_MARKER_SIZE, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
|
use crate::consts::{COLOR_ACCENT, LINE_ROTATE_SNAP_ANGLE, MANIPULATOR_GROUP_MARKER_SIZE, SELECTION_THRESHOLD};
|
||||||
|
use crate::messages::tool::common_functionality::graph_modification_utils::get_gradient;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::intersection::Quad;
|
use document_legacy::document_metadata::LayerNodeIdentifier;
|
||||||
use document_legacy::layers::layer_info::Layer;
|
|
||||||
use document_legacy::layers::layer_layer::CachedOutputData;
|
|
||||||
use document_legacy::layers::style::{Fill, Gradient, GradientType, PathStyle, RenderData, Stroke};
|
use document_legacy::layers::style::{Fill, Gradient, GradientType, PathStyle, RenderData, Stroke};
|
||||||
use document_legacy::LayerId;
|
use document_legacy::LayerId;
|
||||||
use document_legacy::Operation;
|
use document_legacy::Operation;
|
||||||
@@ -115,12 +114,12 @@ enum GradientToolFsmState {
|
|||||||
Drawing,
|
Drawing,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the transform from gradient space to layer space (where gradient space is 0..1 in layer space)
|
/// Computes the transform from gradient space to viewport space (where gradient space is 0..1)
|
||||||
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, render_data: &RenderData) -> DAffine2 {
|
fn gradient_space_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 {
|
||||||
let bounds = layer.aabb_for_transform(DAffine2::IDENTITY, render_data).unwrap();
|
let bounds = document.document_legacy.metadata.bounding_box(layer, DAffine2::IDENTITY).unwrap();
|
||||||
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
|
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
|
||||||
|
|
||||||
let multiplied = document.document_legacy.multiply_transforms(path).unwrap();
|
let multiplied = document.document_legacy.metadata.transform_from_viewport(layer);
|
||||||
|
|
||||||
multiplied * bound_transform
|
multiplied * bound_transform
|
||||||
}
|
}
|
||||||
@@ -131,7 +130,7 @@ pub struct GradientOverlay {
|
|||||||
pub handles: [Vec<LayerId>; 2],
|
pub handles: [Vec<LayerId>; 2],
|
||||||
pub line: Vec<LayerId>,
|
pub line: Vec<LayerId>,
|
||||||
pub steps: Vec<Vec<LayerId>>,
|
pub steps: Vec<Vec<LayerId>>,
|
||||||
path: Vec<LayerId>,
|
layer: LayerNodeIdentifier,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
gradient: Gradient,
|
gradient: Gradient,
|
||||||
}
|
}
|
||||||
@@ -174,17 +173,9 @@ impl GradientOverlay {
|
|||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(gradient: Gradient, dragging: Option<GradientDragTarget>, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Self {
|
||||||
fill: &Gradient,
|
let transform = gradient_space_transform(layer, document);
|
||||||
dragging: Option<GradientDragTarget>,
|
let Gradient { start, end, positions, .. } = &gradient;
|
||||||
path: &[LayerId],
|
|
||||||
layer: &Layer,
|
|
||||||
document: &DocumentMessageHandler,
|
|
||||||
responses: &mut VecDeque<Message>,
|
|
||||||
render_data: &RenderData,
|
|
||||||
) -> Self {
|
|
||||||
let transform = gradient_space_transform(path, layer, document, render_data);
|
|
||||||
let Gradient { start, end, positions, .. } = fill;
|
|
||||||
let [start, end] = [transform.transform_point2(*start), transform.transform_point2(*end)];
|
let [start, end] = [transform.transform_point2(*start), transform.transform_point2(*end)];
|
||||||
|
|
||||||
let line = Self::generate_overlay_line(start, end, responses);
|
let line = Self::generate_overlay_line(start, end, responses);
|
||||||
@@ -197,14 +188,11 @@ impl GradientOverlay {
|
|||||||
let create_step = |(index, pos)| Self::generate_overlay_handle(start.lerp(end, pos), responses, dragging == Some(GradientDragTarget::Step(index)));
|
let create_step = |(index, pos)| Self::generate_overlay_handle(start.lerp(end, pos), responses, dragging == Some(GradientDragTarget::Step(index)));
|
||||||
let steps = positions.iter().map(|(pos, _)| *pos).enumerate().filter(not_at_end).map(create_step).collect();
|
let steps = positions.iter().map(|(pos, _)| *pos).enumerate().filter(not_at_end).map(create_step).collect();
|
||||||
|
|
||||||
let path = path.to_vec();
|
|
||||||
let gradient = fill.clone();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
handles,
|
handles,
|
||||||
steps,
|
steps,
|
||||||
line,
|
line,
|
||||||
path,
|
layer,
|
||||||
transform,
|
transform,
|
||||||
gradient,
|
gradient,
|
||||||
}
|
}
|
||||||
@@ -240,17 +228,17 @@ pub enum GradientDragTarget {
|
|||||||
/// Contains information about the selected gradient handle
|
/// Contains information about the selected gradient handle
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct SelectedGradient {
|
struct SelectedGradient {
|
||||||
path: Vec<LayerId>,
|
layer: LayerNodeIdentifier,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
gradient: Gradient,
|
gradient: Gradient,
|
||||||
dragging: GradientDragTarget,
|
dragging: GradientDragTarget,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectedGradient {
|
impl SelectedGradient {
|
||||||
pub fn new(gradient: Gradient, path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, render_data: &RenderData) -> Self {
|
pub fn new(gradient: Gradient, layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Self {
|
||||||
let transform = gradient_space_transform(path, layer, document, render_data);
|
let transform = gradient_space_transform(layer, document);
|
||||||
Self {
|
Self {
|
||||||
path: path.to_vec(),
|
layer,
|
||||||
transform,
|
transform,
|
||||||
gradient,
|
gradient,
|
||||||
dragging: GradientDragTarget::End,
|
dragging: GradientDragTarget::End,
|
||||||
@@ -258,23 +246,23 @@ impl SelectedGradient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the selected gradient, checking for removal or change of gradient.
|
/// Update the selected gradient, checking for removal or change of gradient.
|
||||||
pub fn update(gradient: &mut Option<Self>, document: &DocumentMessageHandler, render_data: &RenderData, responses: &mut VecDeque<Message>) {
|
pub fn update(gradient: &mut Option<Self>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||||
let Some(inner_gradient) = gradient else {
|
let Some(inner_gradient) = gradient else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clear the gradient if layer deleted
|
// Clear the gradient if layer deleted
|
||||||
let Ok(layer) = document.document_legacy.layer(&inner_gradient.path) else {
|
if !inner_gradient.layer.exists(&document.document_legacy.metadata) {
|
||||||
responses.add(ToolMessage::RefreshToolOptions);
|
responses.add(ToolMessage::RefreshToolOptions);
|
||||||
*gradient = None;
|
*gradient = None;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update transform
|
// Update transform
|
||||||
inner_gradient.transform = gradient_space_transform(&inner_gradient.path, layer, document, render_data);
|
inner_gradient.transform = gradient_space_transform(inner_gradient.layer, document);
|
||||||
|
|
||||||
// Clear if no longer a gradient
|
// Clear if no longer a gradient
|
||||||
let Some(gradient) = layer.style().ok().and_then(|style| style.fill().as_gradient()) else {
|
let Some(gradient) = get_gradient(inner_gradient.layer, &document.document_legacy) else {
|
||||||
responses.add(ToolMessage::RefreshToolOptions);
|
responses.add(ToolMessage::RefreshToolOptions);
|
||||||
*gradient = None;
|
*gradient = None;
|
||||||
return;
|
return;
|
||||||
@@ -340,7 +328,7 @@ impl SelectedGradient {
|
|||||||
pub fn render_gradient(&mut self, responses: &mut VecDeque<Message>) {
|
pub fn render_gradient(&mut self, responses: &mut VecDeque<Message>) {
|
||||||
self.gradient.transform = self.transform;
|
self.gradient.transform = self.transform;
|
||||||
let fill = Fill::Gradient(self.gradient.clone());
|
let fill = Fill::Gradient(self.gradient.clone());
|
||||||
let layer = self.path.clone();
|
let layer = self.layer.to_path();
|
||||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,20 +388,16 @@ impl Fsm for GradientToolFsmState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self != GradientToolFsmState::Drawing {
|
if self != GradientToolFsmState::Drawing {
|
||||||
SelectedGradient::update(&mut tool_data.selected_gradient, document, render_data, responses);
|
SelectedGradient::update(&mut tool_data.selected_gradient, document, responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
for path in document.selected_visible_layers() {
|
for layer in document.document_legacy.metadata.selected_visible_layers() {
|
||||||
let layer = document.document_legacy.layer(path).unwrap();
|
if let Some(gradient) = get_gradient(layer, &document.document_legacy) {
|
||||||
|
|
||||||
if let Ok(Fill::Gradient(gradient)) = layer.style().map(|style| style.fill()) {
|
|
||||||
let dragging = tool_data
|
let dragging = tool_data
|
||||||
.selected_gradient
|
.selected_gradient
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|selected| if selected.path == path { Some(selected.dragging) } else { None });
|
.and_then(|selected| if selected.layer == layer { Some(selected.dragging) } else { None });
|
||||||
tool_data
|
tool_data.gradient_overlays.push(GradientOverlay::new(gradient, dragging, layer, document, responses))
|
||||||
.gradient_overlays
|
|
||||||
.push(GradientOverlay::new(gradient, dragging, path, layer, document, responses, render_data))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,7 +423,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
// The gradient has only one point and so should become a fill
|
// The gradient has only one point and so should become a fill
|
||||||
if selected_gradient.gradient.positions.len() == 1 {
|
if selected_gradient.gradient.positions.len() == 1 {
|
||||||
let fill = Fill::Solid(selected_gradient.gradient.positions[0].1.unwrap_or(Color::BLACK));
|
let fill = Fill::Solid(selected_gradient.gradient.positions[0].1.unwrap_or(Color::BLACK));
|
||||||
let layer = selected_gradient.path.clone();
|
let layer = selected_gradient.layer.to_path();
|
||||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -481,18 +465,15 @@ impl Fsm for GradientToolFsmState {
|
|||||||
if let Some(index) = gradient.insert_stop(mouse, overlay.transform) {
|
if let Some(index) = gradient.insert_stop(mouse, overlay.transform) {
|
||||||
document.backup_nonmut(responses);
|
document.backup_nonmut(responses);
|
||||||
|
|
||||||
let layer = document.document_legacy.layer(&overlay.path);
|
let mut selected_gradient = SelectedGradient::new(gradient, overlay.layer, document);
|
||||||
if let Ok(layer) = layer {
|
|
||||||
let mut selected_gradient = SelectedGradient::new(gradient, &overlay.path, layer, document, render_data);
|
|
||||||
|
|
||||||
// Select the new point
|
// Select the new point
|
||||||
selected_gradient.dragging = GradientDragTarget::Step(index);
|
selected_gradient.dragging = GradientDragTarget::Step(index);
|
||||||
|
|
||||||
// Update the layer fill
|
// Update the layer fill
|
||||||
selected_gradient.render_gradient(responses);
|
selected_gradient.render_gradient(responses);
|
||||||
|
|
||||||
tool_data.selected_gradient = Some(selected_gradient);
|
tool_data.selected_gradient = Some(selected_gradient);
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -516,7 +497,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
if pos.distance_squared(mouse) < tolerance {
|
if pos.distance_squared(mouse) < tolerance {
|
||||||
dragging = true;
|
dragging = true;
|
||||||
tool_data.selected_gradient = Some(SelectedGradient {
|
tool_data.selected_gradient = Some(SelectedGradient {
|
||||||
path: overlay.path.clone(),
|
layer: overlay.layer.clone(),
|
||||||
transform: overlay.transform,
|
transform: overlay.transform,
|
||||||
gradient: overlay.gradient.clone(),
|
gradient: overlay.gradient.clone(),
|
||||||
dragging: GradientDragTarget::Step(index),
|
dragging: GradientDragTarget::Step(index),
|
||||||
@@ -533,7 +514,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
dragging = true;
|
dragging = true;
|
||||||
start_snap(&mut tool_data.snap_manager, document, input, render_data);
|
start_snap(&mut tool_data.snap_manager, document, input, render_data);
|
||||||
tool_data.selected_gradient = Some(SelectedGradient {
|
tool_data.selected_gradient = Some(SelectedGradient {
|
||||||
path: overlay.path.clone(),
|
layer: overlay.layer.clone(),
|
||||||
transform: overlay.transform,
|
transform: overlay.transform,
|
||||||
gradient: overlay.gradient.clone(),
|
gradient: overlay.gradient.clone(),
|
||||||
dragging: dragging_target,
|
dragging: dragging_target,
|
||||||
@@ -545,34 +526,30 @@ impl Fsm for GradientToolFsmState {
|
|||||||
document.backup_nonmut(responses);
|
document.backup_nonmut(responses);
|
||||||
GradientToolFsmState::Drawing
|
GradientToolFsmState::Drawing
|
||||||
} else {
|
} else {
|
||||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
let selected_layer = document.document_legacy.metadata.click(input.mouse.position);
|
||||||
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
|
|
||||||
let intersection = document.document_legacy.intersects_quad_root(quad, render_data).pop();
|
|
||||||
|
|
||||||
// the intersection is the layer where the gradient is being applied
|
// Apply the gradient to the selected layer
|
||||||
if let Some(intersection) = intersection {
|
if let Some((layer, _)) = selected_layer {
|
||||||
let is_bitmap = document
|
// let is_bitmap = document
|
||||||
.document_legacy
|
// .document_legacy
|
||||||
.layer(&intersection)
|
// .layer(&layer)
|
||||||
.ok()
|
// .ok()
|
||||||
.and_then(|layer| layer.as_layer().ok())
|
// .and_then(|layer| layer.as_layer().ok())
|
||||||
.map_or(false, |layer| matches!(layer.cached_output_data, CachedOutputData::BlobURL(_) | CachedOutputData::SurfaceId(_)));
|
// .map_or(false, |layer| matches!(layer.cached_output_data, CachedOutputData::BlobURL(_) | CachedOutputData::SurfaceId(_)));
|
||||||
if is_bitmap {
|
// if is_bitmap {
|
||||||
return self;
|
// return self;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if !document.selected_layers_contains(&intersection) {
|
if !document.document_legacy.metadata.selected_layers_contains(layer) {
|
||||||
let replacement_selected_layers = vec![intersection.clone()];
|
let replacement_selected_layers = vec![layer.to_path()];
|
||||||
|
|
||||||
responses.add(DocumentMessage::SetSelectedLayers { replacement_selected_layers });
|
responses.add(DocumentMessage::SetSelectedLayers { replacement_selected_layers });
|
||||||
}
|
}
|
||||||
|
|
||||||
let layer = document.document_legacy.layer(&intersection).unwrap();
|
|
||||||
|
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
// Use the already existing gradient if it exists
|
// Use the already existing gradient if it exists
|
||||||
let gradient = if let Some(gradient) = layer.style().ok().map(|style| style.fill()).and_then(|fill| fill.as_gradient()) {
|
let gradient = if let Some(gradient) = get_gradient(layer, &document.document_legacy) {
|
||||||
gradient.clone()
|
gradient.clone()
|
||||||
} else {
|
} else {
|
||||||
// Generate a new gradient
|
// Generate a new gradient
|
||||||
@@ -586,7 +563,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
tool_options.gradient_type,
|
tool_options.gradient_type,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let selected_gradient = SelectedGradient::new(gradient, &intersection, layer, document, render_data).with_gradient_start(input.mouse.position);
|
let selected_gradient = SelectedGradient::new(gradient, layer, document).with_gradient_start(input.mouse.position);
|
||||||
|
|
||||||
tool_data.selected_gradient = Some(selected_gradient);
|
tool_data.selected_gradient = Some(selected_gradient);
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,11 @@ use crate::consts::LINE_ROTATE_SNAP_ANGLE;
|
|||||||
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
||||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
|
use crate::messages::tool::common_functionality::graph_modification_utils::get_subpaths;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
use crate::messages::tool::tool_messages::pen_tool::graph_modification_utils::NodeGraphLayer;
|
|
||||||
|
|
||||||
use bezier_rs::Subpath;
|
|
||||||
use document_legacy::document::Document;
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
use document_legacy::document_metadata::LayerNodeIdentifier;
|
||||||
use document_legacy::LayerId;
|
use document_legacy::LayerId;
|
||||||
use graph_craft::document::value::TaggedValue;
|
|
||||||
use graphene_core::uuid::ManipulatorGroupId;
|
use graphene_core::uuid::ManipulatorGroupId;
|
||||||
use graphene_core::vector::style::{Fill, Stroke};
|
use graphene_core::vector::style::{Fill, Stroke};
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||||
@@ -767,26 +764,3 @@ fn should_extend(document: &DocumentMessageHandler, pos: DVec2, tolerance: f64)
|
|||||||
|
|
||||||
best
|
best
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_subpaths(layer: LayerNodeIdentifier, document: &Document) -> Option<&Vec<Subpath<ManipulatorGroupId>>> {
|
|
||||||
if let TaggedValue::Subpaths(subpaths) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 0)? {
|
|
||||||
Some(subpaths)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mirror_handles(layer: LayerNodeIdentifier, document: &Document) -> Option<&Vec<ManipulatorGroupId>> {
|
|
||||||
if let TaggedValue::ManipulatorGroupIds(mirror_handles) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 1)? {
|
|
||||||
Some(mirror_handles)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_manipulator_groups(subpaths: &[Subpath<ManipulatorGroupId>]) -> impl Iterator<Item = &bezier_rs::ManipulatorGroup<ManipulatorGroupId>> + DoubleEndedIterator {
|
|
||||||
subpaths.iter().flat_map(|subpath| subpath.manipulator_groups())
|
|
||||||
}
|
|
||||||
pub fn get_manipulator_from_id(subpaths: &[Subpath<ManipulatorGroupId>], id: ManipulatorGroupId) -> Option<&bezier_rs::ManipulatorGroup<ManipulatorGroupId>> {
|
|
||||||
subpaths.iter().find_map(|subpath| subpath.manipulator_from_id(id))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::messages::tool::common_functionality::color_selector::{ToolColorOptio
|
|||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::{LayerId, Operation};
|
use document_legacy::LayerId;
|
||||||
use graphene_core::vector::style::{Fill, Stroke};
|
use graphene_core::vector::style::{Fill, Stroke};
|
||||||
use graphene_core::Color;
|
use graphene_core::Color;
|
||||||
|
|
||||||
|
|||||||
@@ -239,6 +239,13 @@ impl NodeInput {
|
|||||||
NodeInput::Inline(_) => panic!("ty() called on NodeInput::Inline"),
|
NodeInput::Inline(_) => panic!("ty() called on NodeInput::Inline"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn as_value(&self) -> Option<&TaggedValue> {
|
||||||
|
if let NodeInput::Value { tagged_value, .. } = self {
|
||||||
|
Some(tagged_value)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Hash, DynAny)]
|
#[derive(Clone, Debug, PartialEq, Hash, DynAny)]
|
||||||
|
|||||||
Reference in New Issue
Block a user