Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo-artwork/changing-seasons.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/isometric-fountain.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/marbled-mandelbrot.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/painted-dreams.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/parametric-dunescape.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/procedural-string-lights.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/red-dress.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/valley-of-spires.graphite

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use glam::{Affine2, DAffine2, Vec2};
use graph_craft::document::NodeId;
use graphene_std::blending::BlendMode;
use graphene_std::gradient::GradientStops;
use graphene_std::list::List;
use graphene_std::memo::IORecord;
use graphene_std::raster_types::{CPU, GPU, Raster};
use graphene_std::table::Table;
use graphene_std::vector::Vector;
use graphene_std::vector::style::{Fill, FillChoice, GradientSpreadMethod, GradientType};
use graphene_std::{Artboard, Color, Context, Graphic};
Expand Down Expand Up @@ -155,7 +155,7 @@ struct LayoutData<'a> {
desired_path: &'a mut Vec<PathStep>,
network_interface: &'a NodeNetworkInterface,
/// The `network_path` to use when resolving a `NodeId` against the network interface.
/// Defaults to root (`&[]`); `Table<NodeId>` rendering temporarily sets it to the path's prefix so nested
/// Defaults to root (`&[]`); `List<NodeId>` rendering temporarily sets it to the path's prefix so nested
/// layers (e.g. inside a Ctrl+M-merged custom subgraph) resolve correctly.
node_lookup_network_path: Vec<NodeId>,
breadcrumbs: Vec<String>,
Expand All @@ -175,27 +175,27 @@ macro_rules! generate_layout_downcast {
}
// TODO: We simply try all these types sequentially. Find a better strategy.
fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'static>, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
// `Table<NodeId>` is interpreted as a path (e.g. the value produced by `path_of_subgraph`), shown as a
// `Table` where each item's NodeId resolves against the prefix made up of the items above it.
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<NodeId>>>() {
// `List<NodeId>` is interpreted as a path (e.g. the value produced by `path_of_subgraph`), shown as a
// `List` where each item's NodeId resolves against the prefix made up of the items above it.
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, List<NodeId>>>() {
return Some(table_node_id_path_layout_with_breadcrumb(&io.output, data));
}
generate_layout_downcast!(introspected_data, data, [
Table<Artboard>,
Table<Graphic>,
Table<Vector>,
Table<Raster<CPU>>,
Table<Raster<GPU>>,
Table<Color>,
Table<GradientStops>,
Table<String>,
Table<f64>,
Table<u8>,
Table<bool>,
Table<DAffine2>,
Table<BlendMode>,
Table<GradientType>,
Table<GradientSpreadMethod>,
List<Artboard>,
List<Graphic>,
List<Vector>,
List<Raster<CPU>>,
List<Raster<GPU>>,
List<Color>,
List<GradientStops>,
List<String>,
List<f64>,
List<u8>,
List<bool>,
List<DAffine2>,
List<BlendMode>,
List<GradientType>,
List<GradientSpreadMethod>,
GradientStops,
f64,
u32,
Expand Down Expand Up @@ -227,7 +227,7 @@ trait TableItemLayout {
data.breadcrumbs.push(self.identifier());
self.value_page(data)
}
/// Renders this value as a single inline widget inside an item of a Table.
/// Renders this value as a single inline widget inside an item of a `List`.
/// `target` is the [`PathStep`] to push when the widget is clicked to drill into the value.
/// `data` provides shared context (notably `network_interface`) for types whose label or content
/// depends on lookup beyond their own value (e.g. `NodeId` resolving a node's display name).
Expand All @@ -245,9 +245,9 @@ trait TableItemLayout {
}
}

impl<T: TableItemLayout> TableItemLayout for Table<T> {
impl<T: TableItemLayout> TableItemLayout for List<T> {
Comment thread
Keavon marked this conversation as resolved.
fn type_name() -> &'static str {
"Table"
"List"
}
fn identifier(&self) -> String {
format!("{}[] ({} item{})", T::type_name(), self.len(), if self.len() == 1 { "" } else { "s" })
Expand Down Expand Up @@ -312,14 +312,14 @@ impl TableItemLayout for Artboard {
"Artboard"
}
fn identifier(&self) -> String {
self.as_graphic_table().identifier()
self.as_graphic_list().identifier()
}
// Don't put a breadcrumb for Artboard
fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
self.value_page(data)
}
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
self.as_graphic_table().layout_with_breadcrumb(data)
self.as_graphic_list().layout_with_breadcrumb(data)
}
}

Expand All @@ -329,12 +329,12 @@ impl TableItemLayout for Graphic {
}
fn identifier(&self) -> String {
match self {
Self::Graphic(table) => table.identifier(),
Self::Vector(table) => table.identifier(),
Self::RasterCPU(table) => table.identifier(),
Self::RasterGPU(table) => table.identifier(),
Self::Color(table) => table.identifier(),
Self::Gradient(table) => table.identifier(),
Self::Graphic(list) => list.identifier(),
Self::Vector(list) => list.identifier(),
Self::RasterCPU(list) => list.identifier(),
Self::RasterGPU(list) => list.identifier(),
Self::Color(list) => list.identifier(),
Self::Gradient(list) => list.identifier(),
}
}
// Don't put a breadcrumb for Graphic
Expand All @@ -343,12 +343,12 @@ impl TableItemLayout for Graphic {
}
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
match self {
Self::Graphic(table) => table.layout_with_breadcrumb(data),
Self::Vector(table) => table.layout_with_breadcrumb(data),
Self::RasterCPU(table) => table.layout_with_breadcrumb(data),
Self::RasterGPU(table) => table.layout_with_breadcrumb(data),
Self::Color(table) => table.layout_with_breadcrumb(data),
Self::Gradient(table) => table.layout_with_breadcrumb(data),
Self::Graphic(list) => list.layout_with_breadcrumb(data),
Self::Vector(list) => list.layout_with_breadcrumb(data),
Self::RasterCPU(list) => list.layout_with_breadcrumb(data),
Self::RasterGPU(list) => list.layout_with_breadcrumb(data),
Self::Color(list) => list.layout_with_breadcrumb(data),
Self::Gradient(list) => list.layout_with_breadcrumb(data),
}
}
}
Expand Down Expand Up @@ -834,7 +834,7 @@ impl TableItemLayout for NodeId {
}
// The value's label resolves the node's display name via the network interface so the button reads as the name shown
// in the Node Graph / Layers panels. The lookup uses `data.node_lookup_network_path` (set by the enclosing
// `Table<NodeId>` if rendering a path) so the resolution succeeds at any nesting depth. The button's icon
// `List<NodeId>` if rendering a path) so the resolution succeeds at any nesting depth. The button's icon
// signals layer-vs-node kind. Falls back to "Node {id}" with no icon if the lookup misses.
fn value_widget(&self, target: PathStep, data: &LayoutData) -> WidgetInstance {
let label = node_id_display_label(*self, data.network_interface, &data.node_lookup_network_path);
Expand Down Expand Up @@ -935,20 +935,20 @@ impl TableItemLayout for NodeId {
/// Invokes another macro with the full list of `TableItemLayout`-implementing types whose values may appear
/// as attribute values. Both the value-rendering and drilldown-navigation dispatchers iterate this list,
/// so adding a new attribute-displayable type is a single edit here.
macro_rules! known_table_row_types {
macro_rules! known_item_types {
($apply:ident) => {
$apply!(
Table<Artboard>,
Table<Graphic>,
Table<Vector>,
Table<Raster<CPU>>,
Table<Raster<GPU>>,
Table<Color>,
Table<GradientStops>,
Table<String>,
Table<NodeId>,
Table<f64>,
Table<u8>,
List<Artboard>,
List<Graphic>,
List<Vector>,
List<Raster<CPU>>,
List<Raster<GPU>>,
List<Color>,
List<GradientStops>,
List<String>,
List<NodeId>,
List<f64>,
List<u8>,
GradientStops,
Color,
NodeId,
Expand Down Expand Up @@ -983,7 +983,7 @@ fn display_value_override(any: &dyn Any) -> Option<String> {
None
}

/// Type-dispatched widget for displaying an attribute value in a `Table<T>` item.
/// Type-dispatched widget for displaying an attribute value in a `List<T>` item.
/// Delegates to [`TableItemLayout::value_widget`] so the same widget code is shared between
/// element-column rendering and attribute-column rendering. Returns `None` for unrecognized
/// types so the caller can fall back to a debug-formatted [`TextLabel`].
Expand All @@ -997,16 +997,16 @@ fn dispatch_value_widget(any: &dyn Any, target: PathStep, data: &LayoutData) ->
)*
};
}
known_table_row_types!(check);
known_item_types!(check);
None
}

/// Renders a `Table<NodeId>` as a path: the standard table view, but each item's `NodeId` value is resolved
/// Renders a `List<NodeId>` as a path: the standard table view, but each item's `NodeId` value is resolved
/// against the network path made up of all preceding items. So for a path `[outer, middle, leaf]`, item 0
/// resolves at root, item 1 resolves at `[outer]`, and item 2 resolves at `[outer, middle]` — letting deeply
/// nested layers display each step's correct name. Drilling into an item drops into that node's value page
/// using the same prefix as `network_path`.
fn table_node_id_path_layout_with_breadcrumb(path: &Table<NodeId>, data: &mut LayoutData) -> Vec<LayoutGroup> {
fn table_node_id_path_layout_with_breadcrumb(path: &List<NodeId>, data: &mut LayoutData) -> Vec<LayoutGroup> {
Comment thread
Keavon marked this conversation as resolved.
Comment thread
Keavon marked this conversation as resolved.
data.breadcrumbs.push(path.identifier());

if let Some(step) = data.desired_path.get(data.current_depth).cloned() {
Expand Down Expand Up @@ -1044,9 +1044,9 @@ fn table_node_id_path_layout_with_breadcrumb(path: &Table<NodeId>, data: &mut La
/// Mirrors [`dispatch_value_widget`] but routes to [`TableItemLayout::layout_with_breadcrumb`].
/// Returns `None` for unrecognized types.
fn drilldown_attribute_layout(any: &dyn Any, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
// `Table<NodeId>` is interpreted as a path (e.g. the `editor:layer_path` attribute), so each item's NodeId value
// resolves against the prefix made up of preceding items. Handled before the generic `Table<T>` blanket impl.
if let Some(path) = any.downcast_ref::<Table<NodeId>>() {
// `List<NodeId>` is interpreted as a path (e.g. the `editor:layer_path` attribute), so each item's NodeId value
// resolves against the prefix made up of preceding items. Handled before the generic `List<T>` blanket impl.
if let Some(path) = any.downcast_ref::<List<NodeId>>() {
return Some(table_node_id_path_layout_with_breadcrumb(path, data));
}
macro_rules! check {
Expand All @@ -1058,7 +1058,7 @@ fn drilldown_attribute_layout(any: &dyn Any, data: &mut LayoutData) -> Option<Ve
)*
};
}
known_table_row_types!(check);
known_item_types!(check);
None
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2427,7 +2427,7 @@ impl DocumentMessageHandler {
});

if layer_to_move.parent(self.metadata()) != Some(parent) {
// TODO: Fix this so it works when dragging a layer into a group parent which has a Transform node, which used to work before #2689 caused this regression by removing the empty `Table<Vector>` item.
// TODO: Fix this so it works when dragging a layer into a group parent which has a Transform node, which used to work before #2689 caused this regression by removing the empty `List<Vector>` item.
// TODO: See #2688 for this issue.
let layer_local_transform = self.network_interface.document_metadata().transform_to_viewport(layer_to_move);
let undo_transform = self.network_interface.document_metadata().transform_to_viewport(parent).inverse();
Expand Down Expand Up @@ -3345,7 +3345,7 @@ impl DocumentMessageHandler {
/// Create a network interface with a single export
fn default_document_network_interface() -> NodeNetworkInterface {
let mut network_interface = NodeNetworkInterface::default();
network_interface.add_export(TaggedValue::TypeDefault(descriptor!(graphene_std::table::Table<graphene_std::Artboard>)), -1, "", &[]);
network_interface.add_export(TaggedValue::TypeDefault(descriptor!(graphene_std::list::List<graphene_std::Artboard>)), -1, "", &[]);
network_interface
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use crate::messages::tool::common_functionality::graph_modification_utils::get_c
use glam::{DAffine2, DVec2, IVec2};
use graph_craft::descriptor;
use graph_craft::document::{NodeId, NodeInput};
use graphene_std::list::List;
use graphene_std::renderer::Quad;
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
use graphene_std::table::Table;
use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::style::{Fill, Gradient, GradientSpreadMethod, GradientStop, GradientStops, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
use graphene_std::{Artboard, Color};
Expand Down Expand Up @@ -170,15 +170,15 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
}

// Set the bottom input of the artboard back to artboard
let bottom_input = NodeInput::type_default(descriptor!(Table<Artboard>), true);
let bottom_input = NodeInput::type_default(descriptor!(List<Artboard>), true);
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
} else {
// We have some non layers (e.g. just a rectangle node). We disconnect the bottom input and connect it to the left input.
network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]);
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 1), primary_input, &[]);

// Set the bottom input of the artboard back to artboard
let bottom_input = NodeInput::type_default(descriptor!(Table<Artboard>), true);
let bottom_input = NodeInput::type_default(descriptor!(List<Artboard>), true);
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
use graph_craft::{ProtoNodeIdentifier, concrete, descriptor};
use graphene_std::brush::brush_stroke::BrushStroke;
use graphene_std::list::List;
use graphene_std::raster::BlendMode;
use graphene_std::raster_types::Image;
use graphene_std::subpath::Subpath;
use graphene_std::table::Table;
use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::style::{Fill, GradientSpreadMethod, GradientType, Stroke};
use graphene_std::vector::{GradientStops, PointId, Vector, VectorModification, VectorModificationType};
Expand Down Expand Up @@ -132,8 +132,8 @@ impl<'a> ModifyInputsContext<'a> {
/// 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::type_default(descriptor!(Table<Artboard>), true)),
Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)),
Some(NodeInput::type_default(descriptor!(List<Artboard>), true)),
Some(NodeInput::type_default(descriptor!(List<Graphic>), true)),
Some(NodeInput::value(TaggedValue::DVec2(location), false)),
Some(NodeInput::value(TaggedValue::DVec2(dimensions), false)),
Some(NodeInput::value(TaggedValue::Color(Some(background)), false)),
Expand All @@ -147,7 +147,7 @@ impl<'a> ModifyInputsContext<'a> {
let boolean = resolve_proto_node_type(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER)
.expect("Boolean node does not exist")
.node_template_input_override([
Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)),
Some(NodeInput::type_default(descriptor!(List<Graphic>), true)),
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
]);

Expand All @@ -159,7 +159,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_blend_data(&mut self, layer: LayerNodeIdentifier, count: f64) -> NodeId {
let blend = resolve_network_node_type("Blend")
.expect("Blend node does not exist")
.node_template_input_override([Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]);
.node_template_input_override([Some(NodeInput::type_default(descriptor!(List<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]);

let blend_id = NodeId::new();
self.network_interface.insert_node(blend_id, blend, &[]);
Expand All @@ -171,7 +171,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_morph_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {
let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)
.expect("Morph node does not exist")
.node_template_input_override([Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);
.node_template_input_override([Some(NodeInput::type_default(descriptor!(List<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);

let morph_id = NodeId::new();
self.network_interface.insert_node(morph_id, morph, &[]);
Expand Down Expand Up @@ -390,10 +390,10 @@ impl<'a> ModifyInputsContext<'a> {
};

// If inserting a 'Path' node, insert a 'Flatten Path' node if the type is `Graphic`.
// TODO: Allow the 'Path' node to operate on `Table` data by utilizing the reference (index or ID?) for each item.
// TODO: Allow the 'Path' node to operate on `List` data by utilizing the reference (index or ID?) for each item.
if node_definition.identifier == "Path" {
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]);
if layer_input_type.compiled_nested_type() == Some(&concrete!(Table<Graphic>)) {
if layer_input_type.compiled_nested_type() == Some(&concrete!(List<Graphic>)) {
let Some(flatten_path_definition) = resolve_proto_node_type(graphene_std::vector_nodes::flatten_path::IDENTIFIER) else {
log::error!("Flatten Path does not exist in ModifyInputsContext::existing_node_id");
return None;
Expand Down Expand Up @@ -489,7 +489,7 @@ impl<'a> ModifyInputsContext<'a> {
);
}

/// Set the stops table on the 'Gradient Value' node, creating it if necessary.
/// Set the GradientStops list on the 'Gradient Value' node, creating it if necessary.
pub fn gradient_stops_set(&mut self, stops: GradientStops) {
let Some(gradient_node_id) = self.existing_proto_node_id(graphene_std::math_nodes::gradient_value::IDENTIFIER, true) else {
return;
Expand Down Expand Up @@ -612,7 +612,7 @@ impl<'a> ModifyInputsContext<'a> {
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.join_miter_limit), false), false);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::PaintOrderInput::INDEX);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(stroke.paint_order), false), false);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashLengthsInput::<graphene_std::table::Table<f64>>::INDEX);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashLengthsInput::<graphene_std::list::List<f64>>::INDEX);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64Array(stroke.dash_lengths), false), true);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashOffsetInput::INDEX);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.dash_offset), false), true);
Expand Down
Loading
Loading