mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Add reference point input to the Mirror node
This commit is contained in:
@@ -276,13 +276,13 @@ impl LayoutMessageHandler {
|
||||
|
||||
responses.add(callback_message);
|
||||
}
|
||||
Widget::PivotInput(pivot_input) => {
|
||||
Widget::ReferencePointInput(reference_point_input) => {
|
||||
let callback_message = match action {
|
||||
WidgetValueAction::Commit => (pivot_input.on_commit.callback)(&()),
|
||||
WidgetValueAction::Commit => (reference_point_input.on_commit.callback)(&()),
|
||||
WidgetValueAction::Update => {
|
||||
let update_value = value.as_str().expect("PivotInput update was not of type: u64");
|
||||
pivot_input.position = update_value.into();
|
||||
(pivot_input.on_update.callback)(pivot_input)
|
||||
let update_value = value.as_str().expect("ReferencePointInput update was not of type: u64");
|
||||
reference_point_input.value = update_value.into();
|
||||
(reference_point_input.on_update.callback)(reference_point_input)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ impl LayoutGroup {
|
||||
Widget::TextInput(x) => &mut x.tooltip,
|
||||
Widget::TextLabel(x) => &mut x.tooltip,
|
||||
Widget::BreadcrumbTrailButtons(x) => &mut x.tooltip,
|
||||
Widget::InvisibleStandinInput(_) | Widget::PivotInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::WorkingColorsInput(_) | Widget::NodeCatalog(_) => continue,
|
||||
Widget::InvisibleStandinInput(_) | Widget::ReferencePointInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::WorkingColorsInput(_) | Widget::NodeCatalog(_) => continue,
|
||||
};
|
||||
if val.is_empty() {
|
||||
val.clone_from(&tooltip);
|
||||
@@ -546,7 +546,7 @@ pub enum Widget {
|
||||
NodeCatalog(NodeCatalog),
|
||||
NumberInput(NumberInput),
|
||||
ParameterExposeButton(ParameterExposeButton),
|
||||
PivotInput(PivotInput),
|
||||
ReferencePointInput(ReferencePointInput),
|
||||
PopoverButton(PopoverButton),
|
||||
RadioInput(RadioInput),
|
||||
Separator(Separator),
|
||||
@@ -621,7 +621,7 @@ impl DiffUpdate {
|
||||
| Widget::CurveInput(_)
|
||||
| Widget::InvisibleStandinInput(_)
|
||||
| Widget::NodeCatalog(_)
|
||||
| Widget::PivotInput(_)
|
||||
| Widget::ReferencePointInput(_)
|
||||
| Widget::RadioInput(_)
|
||||
| Widget::Separator(_)
|
||||
| Widget::TextAreaInput(_)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use derivative::*;
|
||||
use glam::DVec2;
|
||||
use graphene_core::Color;
|
||||
use graphene_core::raster::curve::Curve;
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use graphite_proc_macros::WidgetBuilder;
|
||||
|
||||
#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)]
|
||||
@@ -411,100 +411,18 @@ pub struct CurveInput {
|
||||
|
||||
#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)]
|
||||
#[derivative(Debug, PartialEq)]
|
||||
pub struct PivotInput {
|
||||
pub struct ReferencePointInput {
|
||||
#[widget_builder(constructor)]
|
||||
pub position: PivotPosition,
|
||||
pub value: ReferencePoint,
|
||||
|
||||
pub disabled: bool,
|
||||
|
||||
// Callbacks
|
||||
#[serde(skip)]
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
pub on_update: WidgetCallback<PivotInput>,
|
||||
pub on_update: WidgetCallback<ReferencePointInput>,
|
||||
|
||||
#[serde(skip)]
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
pub on_commit: WidgetCallback<()>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, Debug, Default, PartialEq, Eq, specta::Type)]
|
||||
pub enum PivotPosition {
|
||||
#[default]
|
||||
None,
|
||||
TopLeft,
|
||||
TopCenter,
|
||||
TopRight,
|
||||
CenterLeft,
|
||||
Center,
|
||||
CenterRight,
|
||||
BottomLeft,
|
||||
BottomCenter,
|
||||
BottomRight,
|
||||
}
|
||||
|
||||
impl From<&str> for PivotPosition {
|
||||
fn from(input: &str) -> Self {
|
||||
match input {
|
||||
"None" => PivotPosition::None,
|
||||
"TopLeft" => PivotPosition::TopLeft,
|
||||
"TopCenter" => PivotPosition::TopCenter,
|
||||
"TopRight" => PivotPosition::TopRight,
|
||||
"CenterLeft" => PivotPosition::CenterLeft,
|
||||
"Center" => PivotPosition::Center,
|
||||
"CenterRight" => PivotPosition::CenterRight,
|
||||
"BottomLeft" => PivotPosition::BottomLeft,
|
||||
"BottomCenter" => PivotPosition::BottomCenter,
|
||||
"BottomRight" => PivotPosition::BottomRight,
|
||||
_ => panic!("Failed parsing unrecognized PivotPosition enum value '{input}'"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PivotPosition> for Option<DVec2> {
|
||||
fn from(input: PivotPosition) -> Self {
|
||||
match input {
|
||||
PivotPosition::None => None,
|
||||
PivotPosition::TopLeft => Some(DVec2::new(0., 0.)),
|
||||
PivotPosition::TopCenter => Some(DVec2::new(0.5, 0.)),
|
||||
PivotPosition::TopRight => Some(DVec2::new(1., 0.)),
|
||||
PivotPosition::CenterLeft => Some(DVec2::new(0., 0.5)),
|
||||
PivotPosition::Center => Some(DVec2::new(0.5, 0.5)),
|
||||
PivotPosition::CenterRight => Some(DVec2::new(1., 0.5)),
|
||||
PivotPosition::BottomLeft => Some(DVec2::new(0., 1.)),
|
||||
PivotPosition::BottomCenter => Some(DVec2::new(0.5, 1.)),
|
||||
PivotPosition::BottomRight => Some(DVec2::new(1., 1.)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DVec2> for PivotPosition {
|
||||
fn from(input: DVec2) -> Self {
|
||||
const TOLERANCE: f64 = 1e-5_f64;
|
||||
if input.y.abs() < TOLERANCE {
|
||||
if input.x.abs() < TOLERANCE {
|
||||
return PivotPosition::TopLeft;
|
||||
} else if (input.x - 0.5).abs() < TOLERANCE {
|
||||
return PivotPosition::TopCenter;
|
||||
} else if (input.x - 1.).abs() < TOLERANCE {
|
||||
return PivotPosition::TopRight;
|
||||
}
|
||||
} else if (input.y - 0.5).abs() < TOLERANCE {
|
||||
if input.x.abs() < TOLERANCE {
|
||||
return PivotPosition::CenterLeft;
|
||||
} else if (input.x - 0.5).abs() < TOLERANCE {
|
||||
return PivotPosition::Center;
|
||||
} else if (input.x - 1.).abs() < TOLERANCE {
|
||||
return PivotPosition::CenterRight;
|
||||
}
|
||||
} else if (input.y - 1.).abs() < TOLERANCE {
|
||||
if input.x.abs() < TOLERANCE {
|
||||
return PivotPosition::BottomLeft;
|
||||
} else if (input.x - 0.5).abs() < TOLERANCE {
|
||||
return PivotPosition::BottomCenter;
|
||||
} else if (input.x - 1.).abs() < TOLERANCE {
|
||||
return PivotPosition::BottomRight;
|
||||
}
|
||||
}
|
||||
PivotPosition::None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use graphene_core::vector::style::{GradientType, LineCap, LineJoin};
|
||||
use graphene_std::animation::RealTimeMode;
|
||||
use graphene_std::application_io::TextureFrameTable;
|
||||
use graphene_std::ops::XY;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::transform::{Footprint, ReferencePoint};
|
||||
use graphene_std::vector::VectorDataTable;
|
||||
use graphene_std::vector::misc::ArcType;
|
||||
use graphene_std::vector::misc::{BooleanOperation, GridType};
|
||||
@@ -178,6 +178,7 @@ pub(crate) fn property_from_type(
|
||||
Some(x) if x == TypeId::of::<VectorDataTable>() => vector_data_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<RasterFrame>() || x == TypeId::of::<ImageFrameTable<Color>>() || x == TypeId::of::<TextureFrameTable>() => raster_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<GraphicGroupTable>() => group_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<ReferencePoint>() => reference_point_widget(default_info, false).into(),
|
||||
Some(x) if x == TypeId::of::<Footprint>() => footprint_widget(default_info, &mut extra_widgets),
|
||||
Some(x) if x == TypeId::of::<BlendMode>() => blend_mode_widget(default_info),
|
||||
Some(x) if x == TypeId::of::<RealTimeMode>() => real_time_mode_widget(default_info),
|
||||
@@ -291,6 +292,27 @@ pub fn bool_widget(parameter_widgets_info: ParameterWidgetsInfo, checkbox_input:
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn reference_point_widget(parameter_widgets_info: ParameterWidgetsInfo, disabled: bool) -> Vec<WidgetHolder> {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
let mut widgets = start_widgets(parameter_widgets_info, FrontendGraphDataType::General);
|
||||
|
||||
let Some(input) = document_node.inputs.get(index) else {
|
||||
log::warn!("A widget failed to be built because its node's input index is invalid.");
|
||||
return vec![];
|
||||
};
|
||||
if let Some(&TaggedValue::ReferencePoint(reference_point)) = input.as_non_exposed_value() {
|
||||
widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
ReferencePointInput::new(reference_point)
|
||||
.on_update(update_value(move |x: &ReferencePointInput| TaggedValue::ReferencePoint(x.value), node_id, index))
|
||||
.disabled(disabled)
|
||||
.widget_holder(),
|
||||
])
|
||||
}
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn footprint_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widgets: &mut Vec<LayoutGroup>) -> LayoutGroup {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
|
||||
@@ -828,6 +828,34 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||
.set_input(&InputConnector::node(*node_id, 3), NodeInput::value(TaggedValue::Bool(true), false), network_path);
|
||||
}
|
||||
|
||||
// Upgrade the Mirror node to add the `reference_point` input and change `offset` from `DVec2` to `f64`
|
||||
if reference == "Mirror" && inputs_count == 4 {
|
||||
let node_definition = resolve_document_node_type(reference).unwrap();
|
||||
let new_node_template = node_definition.default_node_template();
|
||||
let document_node = new_node_template.document_node;
|
||||
document.network_interface.replace_implementation(node_id, network_path, document_node.implementation.clone());
|
||||
document
|
||||
.network_interface
|
||||
.replace_implementation_metadata(node_id, network_path, new_node_template.persistent_node_metadata);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, document_node.inputs.clone(), network_path);
|
||||
|
||||
let Some(&TaggedValue::DVec2(old_offset)) = old_inputs[1].as_value() else { return };
|
||||
let old_offset = if old_offset.x.abs() > old_offset.y.abs() { old_offset.x } else { old_offset.y };
|
||||
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
|
||||
document.network_interface.set_input(
|
||||
&InputConnector::node(*node_id, 1),
|
||||
NodeInput::value(TaggedValue::ReferencePoint(graphene_std::transform::ReferencePoint::Center), false),
|
||||
network_path,
|
||||
);
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::F64(old_offset), false), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[2].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[3].clone(), network_path);
|
||||
}
|
||||
|
||||
// Upgrade artboard name being passed as hidden value input to "To Artboard"
|
||||
if reference == "Artboard" && upgrade_from_before_returning_nested_click_targets {
|
||||
let label = document.network_interface.display_name(node_id, network_path);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
use super::graph_modification_utils;
|
||||
use crate::consts::PIVOT_DIAMETER;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::prelude::*;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -18,7 +18,7 @@ pub struct Pivot {
|
||||
/// The viewspace pivot position (if applicable)
|
||||
pivot: Option<DVec2>,
|
||||
/// The old pivot position in the GUI, used to reduce refreshes of the document bar
|
||||
old_pivot_position: PivotPosition,
|
||||
old_pivot_position: ReferencePoint,
|
||||
}
|
||||
|
||||
impl Default for Pivot {
|
||||
@@ -27,7 +27,7 @@ impl Default for Pivot {
|
||||
normalized_pivot: DVec2::splat(0.5),
|
||||
transform_from_normalized: Default::default(),
|
||||
pivot: Default::default(),
|
||||
old_pivot_position: PivotPosition::Center,
|
||||
old_pivot_position: ReferencePoint::Center,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ impl Pivot {
|
||||
should_refresh
|
||||
}
|
||||
|
||||
pub fn to_pivot_position(&self) -> PivotPosition {
|
||||
pub fn to_pivot_position(&self) -> ReferencePoint {
|
||||
self.normalized_pivot.into()
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ use glam::DMat2;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_core::renderer::Quad;
|
||||
use graphene_std::renderer::Rect;
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use graphene_std::vector::misc::BooleanOperation;
|
||||
use std::fmt;
|
||||
|
||||
@@ -96,7 +97,7 @@ pub enum SelectToolMessage {
|
||||
PointerOutsideViewport(SelectToolPointerKeys),
|
||||
SelectOptions(SelectOptionsUpdate),
|
||||
SetPivot {
|
||||
position: PivotPosition,
|
||||
position: ReferencePoint,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -129,9 +130,9 @@ impl SelectTool {
|
||||
.widget_holder()
|
||||
}
|
||||
|
||||
fn pivot_widget(&self, disabled: bool) -> WidgetHolder {
|
||||
PivotInput::new(self.tool_data.pivot.to_pivot_position())
|
||||
.on_update(|pivot_input: &PivotInput| SelectToolMessage::SetPivot { position: pivot_input.position }.into())
|
||||
fn pivot_reference_point_widget(&self, disabled: bool) -> WidgetHolder {
|
||||
ReferencePointInput::new(self.tool_data.pivot.to_pivot_position())
|
||||
.on_update(|pivot_input: &ReferencePointInput| SelectToolMessage::SetPivot { position: pivot_input.value }.into())
|
||||
.disabled(disabled)
|
||||
.widget_holder()
|
||||
}
|
||||
@@ -204,7 +205,7 @@ impl LayoutHolder for SelectTool {
|
||||
|
||||
// Pivot
|
||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
widgets.push(self.pivot_widget(self.tool_data.selected_layers_count == 0));
|
||||
widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0));
|
||||
|
||||
// Align
|
||||
let disabled = self.tool_data.selected_layers_count < 2;
|
||||
|
||||
@@ -315,7 +315,7 @@ impl NodeRuntime {
|
||||
return;
|
||||
}
|
||||
|
||||
let bounds = graphic_element.bounding_box(DAffine2::IDENTITY);
|
||||
let bounds = graphic_element.bounding_box(DAffine2::IDENTITY, true);
|
||||
|
||||
// Render the thumbnail from a `GraphicElement` into an SVG string
|
||||
let render_params = RenderParams::new(ViewMode::Normal, bounds, true, false, false);
|
||||
|
||||
Reference in New Issue
Block a user