mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 11:28:30 +08:00
Replace the Artboard struct with a Table<Table<Graphic>> shape (#4077)
* Replace the Artboard struct with a Table<Table<Graphic>> shape * Remove the never-functional, seemingly unneeded migrate_type_descriptor_names due to typo * Allow negative artboard sizes
This commit is contained in:
+5
-2
@@ -1,7 +1,7 @@
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::prelude::*;
|
||||
use glam::{IVec2, UVec2};
|
||||
use glam::UVec2;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Color;
|
||||
|
||||
@@ -47,7 +47,10 @@ impl MessageHandler<NewDocumentDialogMessage, ()> for NewDocumentDialogMessageHa
|
||||
// Finite canvas: create an artboard with the specified dimensions
|
||||
responses.add(GraphOperationMessage::NewArtboard {
|
||||
id: NodeId::new(),
|
||||
artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()),
|
||||
location: glam::DVec2::ZERO,
|
||||
dimensions: self.dimensions.as_dvec2(),
|
||||
background: Color::WHITE,
|
||||
clip: true,
|
||||
});
|
||||
responses.add(NavigationMessage::CanvasPan { delta: self.dimensions.as_dvec2() });
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::{Affine2, DAffine2, Vec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Context;
|
||||
use graphene_std::Graphic;
|
||||
use graphene_std::gradient::GradientStops;
|
||||
use graphene_std::memo::IORecord;
|
||||
use graphene_std::raster_types::{CPU, GPU, Raster};
|
||||
@@ -14,7 +15,6 @@ use graphene_std::table::Table;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::{Fill, FillChoice};
|
||||
use graphene_std::{AlphaBlending, Color};
|
||||
use graphene_std::{Artboard, Graphic};
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -182,7 +182,7 @@ fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'st
|
||||
return Some(table_node_id_path_layout_with_breadcrumb(&io.output, data));
|
||||
}
|
||||
generate_layout_downcast!(introspected_data, data, [
|
||||
Table<Artboard>,
|
||||
Table<Table<Graphic>>,
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
Table<Raster<CPU>>,
|
||||
@@ -300,18 +300,6 @@ impl<T: TableRowLayout> TableRowLayout for Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl TableRowLayout for Artboard {
|
||||
fn type_name() -> &'static str {
|
||||
"Artboard"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
self.label.clone()
|
||||
}
|
||||
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
self.content.value_page(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl TableRowLayout for Graphic {
|
||||
fn type_name() -> &'static str {
|
||||
"Graphic"
|
||||
@@ -652,7 +640,7 @@ impl TableRowLayout for bool {
|
||||
"Bool".to_string()
|
||||
}
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextLabel::new(self.to_string()).narrow(true).widget_instance()
|
||||
CheckboxInput::new(*self).disabled(true).widget_instance()
|
||||
}
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
@@ -897,7 +885,7 @@ impl TableRowLayout for NodeId {
|
||||
macro_rules! known_table_row_types {
|
||||
($apply:ident) => {
|
||||
$apply!(
|
||||
Table<Artboard>,
|
||||
Table<Table<Graphic>>,
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
Table<Raster<CPU>>,
|
||||
@@ -926,7 +914,6 @@ macro_rules! known_table_row_types {
|
||||
Vector,
|
||||
Raster<CPU>,
|
||||
Raster<GPU>,
|
||||
Artboard,
|
||||
Graphic,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::Key;
|
||||
use crate::messages::tool::utility_types::ToolType;
|
||||
use crate::node_graph_executor::NodeGraphExecutor;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||
use graphene_std::math::quad::Quad;
|
||||
@@ -1396,11 +1396,11 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
// When artboard_canvas is provided (SVG file-open flow), use the declared canvas origin and dimensions;
|
||||
// no content-shift Transform node needed since the SVG was already placed at its natural coordinates.
|
||||
let (artboard_location, artboard_dimensions, content_shift) = if let Some((origin, dimensions)) = artboard_canvas {
|
||||
(origin, dimensions, DVec2::ZERO)
|
||||
(origin.as_dvec2(), dimensions.as_dvec2(), DVec2::ZERO)
|
||||
} else {
|
||||
// No declared canvas (image or clipboard paste): derive location and dimensions from the content bounding box.
|
||||
let location = if place_artboard_at_origin { IVec2::ZERO } else { bounds[0].round().as_ivec2() };
|
||||
(location, (bounds[1] - bounds[0]).round().as_ivec2(), -bounds[0].round())
|
||||
let location = if place_artboard_at_origin { DVec2::ZERO } else { bounds[0].round() };
|
||||
(location, (bounds[1] - bounds[0]).round(), -bounds[0].round())
|
||||
};
|
||||
|
||||
// Create an artboard and set its dimensions to the bounding box size and location
|
||||
|
||||
@@ -2,9 +2,8 @@ use super::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
|
||||
use crate::messages::prelude::*;
|
||||
use glam::{DAffine2, IVec2};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::color::Color;
|
||||
use graphene_std::raster::BlendMode;
|
||||
@@ -66,7 +65,10 @@ pub enum GraphOperationMessage {
|
||||
},
|
||||
NewArtboard {
|
||||
id: NodeId,
|
||||
artboard: Artboard,
|
||||
location: DVec2,
|
||||
dimensions: DVec2,
|
||||
background: Color,
|
||||
clip: bool,
|
||||
},
|
||||
NewBitmapLayer {
|
||||
id: NodeId,
|
||||
@@ -119,8 +121,8 @@ pub enum GraphOperationMessage {
|
||||
},
|
||||
ResizeArtboard {
|
||||
layer: LayerNodeIdentifier,
|
||||
location: IVec2,
|
||||
dimensions: IVec2,
|
||||
location: DVec2,
|
||||
dimensions: DVec2,
|
||||
},
|
||||
RemoveArtboards,
|
||||
NewSvg {
|
||||
|
||||
+9
-4
@@ -108,11 +108,16 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
|
||||
|
||||
network_interface.force_set_upstream_to_chain(&first_chain_node, &[]);
|
||||
}
|
||||
GraphOperationMessage::NewArtboard { id, artboard } => {
|
||||
GraphOperationMessage::NewArtboard {
|
||||
id,
|
||||
location,
|
||||
dimensions,
|
||||
background,
|
||||
clip,
|
||||
} => {
|
||||
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
|
||||
|
||||
let artboard_location = artboard.location;
|
||||
let artboard_layer = modify_inputs.create_artboard(id, artboard);
|
||||
let artboard_layer = modify_inputs.create_artboard(id, location, dimensions, background, clip);
|
||||
network_interface.move_layer_to_stack(artboard_layer, LayerNodeIdentifier::ROOT_PARENT, 0, &[]);
|
||||
|
||||
// If there is a non artboard feeding into the primary input of the artboard, move it to the secondary input
|
||||
@@ -138,7 +143,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
|
||||
// Apply a translation to prevent the content from shifting
|
||||
responses.add(GraphOperationMessage::TransformChange {
|
||||
layer,
|
||||
transform: DAffine2::from_translation(-artboard_location.as_dvec2()),
|
||||
transform: DAffine2::from_translation(-location),
|
||||
transform_in: TransformIn::Local,
|
||||
skip_rerender: true,
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions:
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, OutputConnector};
|
||||
use crate::messages::prelude::*;
|
||||
use glam::{DAffine2, IVec2};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete};
|
||||
@@ -16,7 +16,7 @@ use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::{Fill, Stroke};
|
||||
use graphene_std::vector::{PointId, VectorModification, VectorModificationType};
|
||||
use graphene_std::{Artboard, Color, Graphic, NodeInputDecleration};
|
||||
use graphene_std::{Color, Graphic, NodeInputDecleration};
|
||||
|
||||
#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum TransformIn {
|
||||
@@ -130,15 +130,15 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
LayerNodeIdentifier::new(new_id, self.network_interface)
|
||||
}
|
||||
|
||||
/// Creates an artboard as the primary export for the document network
|
||||
pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier {
|
||||
/// Creates an artboard as the primary export for the document network.
|
||||
pub fn create_artboard(&mut self, new_id: NodeId, location: DVec2, dimensions: DVec2, background: Color, clip: bool) -> LayerNodeIdentifier {
|
||||
let artboard_node_template = resolve_network_node_type("Artboard").expect("Node").node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::Artboard(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(artboard.location.into()), false)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(artboard.dimensions.into()), false)),
|
||||
Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(artboard.background)), false)),
|
||||
Some(NodeInput::value(TaggedValue::Bool(artboard.clip), false)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(location), false)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(dimensions), false)),
|
||||
Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(background)), false)),
|
||||
Some(NodeInput::value(TaggedValue::Bool(clip), false)),
|
||||
]);
|
||||
self.network_interface.insert_node(new_id, artboard_node_template, &[]);
|
||||
LayerNodeIdentifier::new(new_id, self.network_interface)
|
||||
@@ -584,7 +584,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokeTable(strokes_table), false), false);
|
||||
}
|
||||
|
||||
pub fn resize_artboard(&mut self, location: IVec2, dimensions: IVec2) {
|
||||
pub fn resize_artboard(&mut self, location: DVec2, dimensions: DVec2) {
|
||||
let Some(artboard_node_id) = self.existing_network_node_id("Artboard", true) else {
|
||||
return;
|
||||
};
|
||||
@@ -592,16 +592,16 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let mut dimensions = dimensions;
|
||||
let mut location = location;
|
||||
|
||||
if dimensions.x < 0 {
|
||||
dimensions.x *= -1;
|
||||
if dimensions.x < 0. {
|
||||
dimensions.x = -dimensions.x;
|
||||
location.x -= dimensions.x;
|
||||
}
|
||||
if dimensions.y < 0 {
|
||||
dimensions.y *= -1;
|
||||
if dimensions.y < 0. {
|
||||
dimensions.y = -dimensions.y;
|
||||
location.y -= dimensions.y;
|
||||
}
|
||||
self.set_input_with_refresh(InputConnector::node(artboard_node_id, 2), NodeInput::value(TaggedValue::DVec2(location.into()), false), false);
|
||||
self.set_input_with_refresh(InputConnector::node(artboard_node_id, 3), NodeInput::value(TaggedValue::DVec2(dimensions.into()), false), false);
|
||||
self.set_input_with_refresh(InputConnector::node(artboard_node_id, 2), NodeInput::value(TaggedValue::DVec2(location), false), false);
|
||||
self.set_input_with_refresh(InputConnector::node(artboard_node_id, 3), NodeInput::value(TaggedValue::DVec2(dimensions), false), false);
|
||||
}
|
||||
|
||||
/// Set the input, refresh the Properties panel, and run the document graph if skip_rerender is false
|
||||
|
||||
@@ -354,13 +354,11 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(4), 0)],
|
||||
nodes: [
|
||||
// Ensure this ID is kept in sync with the ID in set_alias so that the name input is kept in sync with the alias
|
||||
DocumentNode {
|
||||
call_argument: generic!(T),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(artboard::create_artboard::IDENTIFIER),
|
||||
inputs: vec![
|
||||
NodeInput::import(concrete!(TaggedValue), 1),
|
||||
NodeInput::value(TaggedValue::String(String::from("Artboard")), false),
|
||||
NodeInput::import(concrete!(TaggedValue), 2),
|
||||
NodeInput::import(concrete!(TaggedValue), 3),
|
||||
NodeInput::import(concrete!(TaggedValue), 4),
|
||||
@@ -396,7 +394,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
NodeInput::import(graphene_std::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(Table<Artboard>))), 0),
|
||||
NodeInput::import(graphene_std::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(Table<Table<Graphic>>))), 0),
|
||||
NodeInput::node(NodeId(3), 0),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::extend::IDENTIFIER),
|
||||
|
||||
@@ -4571,32 +4571,7 @@ impl NodeNetworkInterface {
|
||||
return;
|
||||
}
|
||||
|
||||
node_metadata.persistent_metadata.display_name.clone_from(&display_name);
|
||||
|
||||
// Keep the alias in sync with the `ToArtboard` name input
|
||||
if self
|
||||
.reference(node_id, network_path)
|
||||
.is_some_and(|reference| reference == DefinitionIdentifier::Network("Artboard".into()))
|
||||
{
|
||||
let Some(nested_network) = self.network_mut(network_path) else {
|
||||
return;
|
||||
};
|
||||
let Some(artboard_node) = nested_network.nodes.get_mut(node_id) else {
|
||||
return;
|
||||
};
|
||||
let DocumentNodeImplementation::Network(network) = &mut artboard_node.implementation else {
|
||||
return;
|
||||
};
|
||||
// Keep this in sync with the definition
|
||||
let Some(to_artboard) = network.nodes.get_mut(&NodeId(0)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let label_index = 1;
|
||||
let label = if !display_name.is_empty() { display_name } else { "Artboard".to_string() };
|
||||
let label_input = NodeInput::value(TaggedValue::String(label), false);
|
||||
to_artboard.inputs[label_index] = label_input;
|
||||
}
|
||||
node_metadata.persistent_metadata.display_name = display_name;
|
||||
|
||||
self.transaction_modified();
|
||||
self.try_unload_layer_width(node_id, network_path);
|
||||
|
||||
@@ -1313,14 +1313,6 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
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 "Create Artboard"
|
||||
if reference == DefinitionIdentifier::Network("Artboard".into()) && reset_node_definitions_on_open {
|
||||
let label = document.network_interface.display_name(node_id, network_path);
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(NodeId(0), 1), NodeInput::value(TaggedValue::String(label), false), &[*node_id]);
|
||||
}
|
||||
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER) && inputs_count == 1 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
@@ -1125,8 +1125,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
layer: item_id,
|
||||
location: new_artboard_origin_doc.round().as_ivec2(),
|
||||
dimensions: dimensions_doc.round().as_ivec2(),
|
||||
location: new_artboard_origin_doc.round(),
|
||||
dimensions: dimensions_doc.round(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -11,9 +11,7 @@ use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapData;
|
||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::renderer::{Quad, Rect};
|
||||
use graphene_std::table::Table;
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
pub struct ArtboardTool {
|
||||
@@ -113,7 +111,7 @@ struct ArtboardToolData {
|
||||
drag_current: DVec2,
|
||||
auto_panning: AutoPanning,
|
||||
snap_candidates: Vec<SnapCandidatePoint>,
|
||||
dragging_current_artboard_location: glam::IVec2,
|
||||
dragging_current_artboard_location: glam::DVec2,
|
||||
draw: Resize,
|
||||
}
|
||||
|
||||
@@ -142,7 +140,7 @@ impl ArtboardToolData {
|
||||
fn start_resizing(&mut self, _selected_edges: (bool, bool, bool, bool), _document: &DocumentMessageHandler, _input: &InputPreprocessorMessageHandler) {
|
||||
if let Some(bounds) = &mut self.bounding_box_manager {
|
||||
bounds.center_of_transformation = bounds.transform.transform_point2((bounds.bounds[0] + bounds.bounds[1]) / 2.);
|
||||
self.dragging_current_artboard_location = bounds.bounds[0].round().as_ivec2();
|
||||
self.dragging_current_artboard_location = bounds.bounds[0].round();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,14 +209,14 @@ impl ArtboardToolData {
|
||||
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
layer: selected_artboard,
|
||||
location: position.round().as_ivec2(),
|
||||
dimensions: size.round().as_ivec2(),
|
||||
location: position.round(),
|
||||
dimensions: size.round(),
|
||||
});
|
||||
|
||||
let translation = position.round().as_ivec2() - self.dragging_current_artboard_location;
|
||||
self.dragging_current_artboard_location = position.round().as_ivec2();
|
||||
let translation = position.round() - self.dragging_current_artboard_location;
|
||||
self.dragging_current_artboard_location = position.round();
|
||||
for child in selected_artboard.children(document.metadata()) {
|
||||
let local_translation = document.metadata().downstream_transform_to_document(child).inverse().transform_vector2(-translation.as_dvec2());
|
||||
let local_translation = document.metadata().downstream_transform_to_document(child).inverse().transform_vector2(-translation);
|
||||
responses.add(GraphOperationMessage::TransformChange {
|
||||
layer: child,
|
||||
transform: DAffine2::from_translation(local_translation),
|
||||
@@ -348,8 +346,8 @@ impl Fsm for ArtboardToolFsmState {
|
||||
}
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
layer: tool_data.selected_artboard.unwrap(),
|
||||
location: position.round().as_ivec2(),
|
||||
dimensions: size.round().as_ivec2(),
|
||||
location: position.round(),
|
||||
dimensions: size.round(),
|
||||
});
|
||||
|
||||
// The second term is added to prevent the slow change in position due to rounding errors.
|
||||
@@ -379,8 +377,8 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
layer: artboard,
|
||||
location: start.min(end).round().as_ivec2(),
|
||||
dimensions: (start.round() - end.round()).abs().as_ivec2(),
|
||||
location: start.min(end).round(),
|
||||
dimensions: (start.round() - end.round()).abs(),
|
||||
});
|
||||
} else {
|
||||
let id = NodeId::new();
|
||||
@@ -389,14 +387,10 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
responses.add(GraphOperationMessage::NewArtboard {
|
||||
id,
|
||||
artboard: Artboard {
|
||||
content: Table::new(),
|
||||
label: String::from("Artboard"),
|
||||
location: start.min(end).round().as_ivec2(),
|
||||
dimensions: (start.round() - end.round()).abs().as_ivec2(),
|
||||
background: graphene_std::Color::WHITE,
|
||||
clip: true,
|
||||
},
|
||||
location: start.min(end).round(),
|
||||
dimensions: (start.round() - end.round()).abs(),
|
||||
background: graphene_std::Color::WHITE,
|
||||
clip: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -516,8 +510,8 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
layer: selected_artboard,
|
||||
location: DVec2::new(existing_top_left.x + delta.x, existing_top_left.y + delta.y).round().as_ivec2(),
|
||||
dimensions: (existing_bottom_right - existing_top_left).round().as_ivec2(),
|
||||
location: DVec2::new(existing_top_left.x + delta.x, existing_top_left.y + delta.y).round(),
|
||||
dimensions: (existing_bottom_right - existing_top_left).round(),
|
||||
});
|
||||
|
||||
return ArtboardToolFsmState::Ready { hovered };
|
||||
@@ -563,8 +557,8 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
layer: selected_artboard,
|
||||
location: position.round().as_ivec2(),
|
||||
dimensions: new.transform_vector2(existing_bottom_right - existing_top_left).round().as_ivec2(),
|
||||
location: position.round(),
|
||||
dimensions: new.transform_vector2(existing_bottom_right - existing_top_left).round(),
|
||||
});
|
||||
|
||||
ArtboardToolFsmState::Ready { hovered }
|
||||
@@ -617,26 +611,27 @@ impl Fsm for ArtboardToolFsmState {
|
||||
#[cfg(test)]
|
||||
mod test_artboard {
|
||||
pub use crate::test_utils::test_prelude::*;
|
||||
use graphene_std::Graphic;
|
||||
use graphene_std::table::Table;
|
||||
|
||||
async fn get_artboards(editor: &mut EditorTestUtils) -> Table<graphene_std::Artboard> {
|
||||
async fn get_artboards(editor: &mut EditorTestUtils) -> Table<Table<Graphic>> {
|
||||
let instrumented = match editor.eval_graph().await {
|
||||
Ok(instrumented) => instrumented,
|
||||
Err(e) => panic!("Failed to evaluate graph: {e}"),
|
||||
};
|
||||
instrumented
|
||||
.grab_all_input::<graphene_std::graphic::extend::NewInput<graphene_std::Artboard>>(&editor.runtime)
|
||||
.grab_all_input::<graphene_std::graphic::extend::NewInput<Table<graphene_std::Graphic>>>(&editor.runtime)
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct ArtboardLayoutDocument {
|
||||
position: IVec2,
|
||||
dimensions: IVec2,
|
||||
position: DVec2,
|
||||
dimensions: DVec2,
|
||||
}
|
||||
impl ArtboardLayoutDocument {
|
||||
pub fn new(position: impl Into<IVec2>, dimensions: impl Into<IVec2>) -> Self {
|
||||
pub fn new(position: impl Into<DVec2>, dimensions: impl Into<DVec2>) -> Self {
|
||||
Self {
|
||||
position: position.into(),
|
||||
dimensions: dimensions.into(),
|
||||
@@ -649,8 +644,9 @@ mod test_artboard {
|
||||
let artboards = get_artboards(editor).await;
|
||||
let artboards = (0..artboards.len())
|
||||
.map(|index| {
|
||||
let element = artboards.element(index).unwrap();
|
||||
ArtboardLayoutDocument::new(element.location, element.dimensions)
|
||||
let location: DVec2 = artboards.attribute_cloned_or_default(graphene_std::ATTR_LOCATION, index);
|
||||
let dimensions: DVec2 = artboards.attribute_cloned_or_default(graphene_std::ATTR_DIMENSIONS, index);
|
||||
ArtboardLayoutDocument::new(location, dimensions)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(artboards.len(), expected.len(), "incorrect len: actual {:?}, expected {:?}", artboards, expected);
|
||||
@@ -668,7 +664,7 @@ mod test_artboard {
|
||||
let mut editor = EditorTestUtils::create();
|
||||
editor.new_document().await;
|
||||
editor.drag_tool(ToolType::Artboard, 10.1, 10.8, 19.9, 0.2, ModifierKeys::empty()).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((10, 0), (10, 11))]).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((10., 0.), (10., 11.))]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -678,7 +674,11 @@ mod test_artboard {
|
||||
editor.set_viewport_size(DVec2::splat(-1000.), DVec2::splat(1000.)).await; // Necessary for doing snapping since snaps outside of the viewport are discarded
|
||||
editor.drag_tool(ToolType::Artboard, 10., 10., 20., 20., ModifierKeys::empty()).await;
|
||||
editor.drag_tool(ToolType::Artboard, 11., 50., 19., 60., ModifierKeys::empty()).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((10, 10), (10, 10)), ArtboardLayoutDocument::new((10, 50), (10, 10))]).await;
|
||||
has_artboards(
|
||||
&mut editor,
|
||||
vec![ArtboardLayoutDocument::new((10., 10.), (10., 10.)), ArtboardLayoutDocument::new((10., 50.), (10., 10.))],
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -686,7 +686,7 @@ mod test_artboard {
|
||||
let mut editor = EditorTestUtils::create();
|
||||
editor.new_document().await;
|
||||
editor.drag_tool(ToolType::Artboard, 10., 10., -10., 11., ModifierKeys::SHIFT).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((-10, 10), (20, 20))]).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((-10., 10.), (20., 20.))]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -703,7 +703,7 @@ mod test_artboard {
|
||||
editor.drag_tool(ToolType::Artboard, 0., 0., 0., 10., ModifierKeys::SHIFT).await;
|
||||
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 10.);
|
||||
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new(IVec2::new(0, 0), desired_size.round().as_ivec2())]).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new(DVec2::new(0., 0.), desired_size.round())]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -719,8 +719,8 @@ mod test_artboard {
|
||||
.await;
|
||||
// Viewport coordinates
|
||||
editor.drag_tool(ToolType::Artboard, 0., 0., 0., 10., ModifierKeys::SHIFT | ModifierKeys::ALT).await;
|
||||
let desired_location = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * -10.).as_ivec2();
|
||||
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 20.).as_ivec2();
|
||||
let desired_location = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * -10.).round();
|
||||
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 20.).round();
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new(desired_location, desired_size)]).await;
|
||||
}
|
||||
|
||||
@@ -752,7 +752,7 @@ mod test_artboard {
|
||||
editor.drag_tool(ToolType::Artboard, 10., 10., 20., 22., ModifierKeys::empty()).await; // Artboard to drag
|
||||
editor.drag_tool(ToolType::Artboard, 15., 15., 65., 65., ModifierKeys::empty()).await; // Drag from the middle by (50,50)
|
||||
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((60, 60), (10, 12))]).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((60., 60.), (10., 12.))]).await;
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn artboard_move_snapping() {
|
||||
@@ -763,7 +763,11 @@ mod test_artboard {
|
||||
editor.drag_tool(ToolType::Artboard, 70., 0., 80., 100., ModifierKeys::empty()).await; // Artboard to snap to
|
||||
editor.drag_tool(ToolType::Artboard, 15., 15., 15. + 49., 15., ModifierKeys::empty()).await; // Drag the artboard so it should snap to the edge
|
||||
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((60, 10), (10, 12)), ArtboardLayoutDocument::new((70, 0), (10, 100))]).await;
|
||||
has_artboards(
|
||||
&mut editor,
|
||||
vec![ArtboardLayoutDocument::new((60., 10.), (10., 12.)), ArtboardLayoutDocument::new((70., 0.), (10., 100.))],
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -777,7 +781,7 @@ mod test_artboard {
|
||||
|
||||
// Put the artboard in
|
||||
editor.drag_tool(ToolType::Artboard, 5., 5., 30., 10., ModifierKeys::empty()).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((5, 5), (25, 5))]).await;
|
||||
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((5., 5.), (25., 5.))]).await;
|
||||
let document = editor.active_document();
|
||||
|
||||
// artboard
|
||||
|
||||
@@ -20,7 +20,7 @@ use graphene_std::text::FontCache;
|
||||
use graphene_std::transform::RenderQuality;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::RenderMode;
|
||||
use graphene_std::{Artboard, Context, Graphic};
|
||||
use graphene_std::{Context, Graphic};
|
||||
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
|
||||
use interpreted_executor::util::wrap_network_in_scope;
|
||||
use spin::Mutex;
|
||||
@@ -439,7 +439,7 @@ impl NodeRuntime {
|
||||
}
|
||||
}
|
||||
// Artboard table: thumbnail
|
||||
else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<Artboard>>>() {
|
||||
else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<Table<Graphic>>>>() {
|
||||
if update_thumbnails {
|
||||
Self::render_thumbnail(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user