mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-24 07:48:12 +08:00
Replace deprecated row/cell/instance terminology with "item" and "value" terms (#4075)
This commit is contained in:
@@ -102,22 +102,22 @@ impl LayoutMessageHandler {
|
||||
}
|
||||
LayoutGroup::Table(WidgetTable { rows, .. }) => {
|
||||
for (row_index, row) in rows.iter().enumerate() {
|
||||
for (cell_index, cell) in row.iter().enumerate() {
|
||||
for (value_index, value) in row.iter().enumerate() {
|
||||
// Return if this is the correct ID
|
||||
if cell.widget_id == widget_id {
|
||||
if value.widget_id == widget_id {
|
||||
widget_path.push(row_index);
|
||||
widget_path.push(cell_index);
|
||||
return Some((cell, widget_path));
|
||||
widget_path.push(value_index);
|
||||
return Some((value, widget_path));
|
||||
}
|
||||
|
||||
if let Widget::PopoverButton(popover) = &*cell.widget {
|
||||
if let Widget::PopoverButton(popover) = &*value.widget {
|
||||
stack.extend(
|
||||
popover
|
||||
.popover_layout
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(child, val)| ([widget_path.as_slice(), &[row_index, cell_index, child]].concat(), val)),
|
||||
.map(|(child, val)| ([widget_path.as_slice(), &[row_index, value_index, child]].concat(), val)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ macro_rules! define_layout_target {
|
||||
};
|
||||
}
|
||||
define_layout_target!(
|
||||
/// The spreadsheet panel allows for the visualisation of data in the graph.
|
||||
/// The Data panel visualizes the output data flowing through the selected node in the graph.
|
||||
DataPanel,
|
||||
/// Contains the action buttons at the bottom of the dialog. Must be shown with the `FrontendMessage::DisplayDialog` message.
|
||||
DialogButtons,
|
||||
@@ -785,7 +785,7 @@ pub enum Widget {
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct WidgetDiff {
|
||||
/// A path to the change
|
||||
/// e.g. [0, 1, 2] in the properties panel is the first section, second row and third widget.
|
||||
/// e.g. [0, 1, 2] in the Properties panel is the first section, second row and third widget.
|
||||
/// An empty path [] shows that the entire panel has changed and is sent when the UI is first created.
|
||||
#[serde(rename = "widgetPath")]
|
||||
pub widget_path: Vec<usize>,
|
||||
|
||||
@@ -26,8 +26,8 @@ pub enum DataPanelMessage {
|
||||
},
|
||||
}
|
||||
|
||||
/// One hop in the breadcrumb path through nested data the data panel is displaying.
|
||||
/// Drilling into a row's element produces an `Element` step; drilling into one of a row's attributes produces an `Attribute` step.
|
||||
/// One hop in the breadcrumb path through nested data the Data panel is displaying.
|
||||
/// Drilling into an item's element produces an `Element` step; drilling into one of an item's attributes produces an `Attribute` step.
|
||||
#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum PathStep {
|
||||
Element(usize),
|
||||
|
||||
@@ -24,7 +24,7 @@ pub struct DataPanelMessageContext<'a> {
|
||||
pub data_panel_open: bool,
|
||||
}
|
||||
|
||||
/// The data panel allows for graph data to be previewed.
|
||||
/// The Data panel allows for graph data to be previewed.
|
||||
#[derive(Default, Debug, Clone, ExtractField)]
|
||||
pub struct DataPanelMessageHandler {
|
||||
/// Full path from the root network to the introspected node, with the node itself as the last element.
|
||||
@@ -155,7 +155,7 @@ struct LayoutData<'a> {
|
||||
current_depth: usize,
|
||||
desired_path: &'a mut Vec<PathStep>,
|
||||
network_interface: &'a NodeNetworkInterface,
|
||||
/// The `network_path` to use when resolving a `NodeId` cell or leaf page against the network interface.
|
||||
/// 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
|
||||
/// layers (e.g. inside a Ctrl+M-merged custom subgraph) resolve correctly.
|
||||
node_lookup_network_path: Vec<NodeId>,
|
||||
@@ -177,7 +177,7 @@ 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 row's NodeId resolves against the prefix made up of the rows above it.
|
||||
// `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>>>() {
|
||||
return Some(table_node_id_path_layout_with_breadcrumb(&io.output, data));
|
||||
}
|
||||
@@ -218,22 +218,22 @@ trait TableRowLayout {
|
||||
fn identifier(&self) -> String;
|
||||
fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
data.breadcrumbs.push(self.identifier());
|
||||
self.element_page(data)
|
||||
self.value_page(data)
|
||||
}
|
||||
/// Renders this value as a single inline widget inside a row of a Vec/Table.
|
||||
/// `target` is the [`PathStep`] to push when the cell is clicked to drill into the value.
|
||||
/// Renders this value as a single inline widget inside an item of a Table.
|
||||
/// `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).
|
||||
/// The default is a button labeled with `identifier()`. Types whose values are best shown
|
||||
/// inline (colors, transforms, primitives, etc.) override this to ignore `target` and
|
||||
/// return a richer non-navigating widget.
|
||||
fn cell_widget(&self, target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextButton::new(self.identifier())
|
||||
.on_update(move |_| DataPanelMessage::PushToElementPath { step: target.clone() }.into())
|
||||
.narrow(true)
|
||||
.widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
@@ -243,9 +243,9 @@ impl<T: TableRowLayout> TableRowLayout for Table<T> {
|
||||
"Table"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("Table<{}> ({} element{})", T::type_name(), self.len(), if self.len() == 1 { "" } else { "s" })
|
||||
format!("{}[] ({} item{})", T::type_name(), self.len(), if self.len() == 1 { "" } else { "s" })
|
||||
}
|
||||
fn element_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
if let Some(step) = data.desired_path.get(data.current_depth).cloned() {
|
||||
match step {
|
||||
PathStep::Element(index) => {
|
||||
@@ -279,16 +279,16 @@ impl<T: TableRowLayout> TableRowLayout for Table<T> {
|
||||
let mut rows = (0..self.len())
|
||||
.map(|index| {
|
||||
let element = self.element(index).unwrap();
|
||||
let mut cells = vec![TextLabel::new(format!("{index}")).narrow(true).widget_instance(), element.cell_widget(PathStep::Element(index), data)];
|
||||
let mut values = vec![TextLabel::new(format!("{index}")).narrow(true).widget_instance(), element.value_widget(PathStep::Element(index), data)];
|
||||
for key in &attribute_keys {
|
||||
let target = PathStep::Attribute { row: index, key: key.clone() };
|
||||
let widget = self.attribute_any(key, index).and_then(|any| dispatch_cell_widget(any, target, data)).unwrap_or_else(|| {
|
||||
let widget = self.attribute_any(key, index).and_then(|any| dispatch_value_widget(any, target, data)).unwrap_or_else(|| {
|
||||
let text = self.attribute_display_value(key, index, |_| None).unwrap_or_else(|| "-".to_string());
|
||||
TextLabel::new(text).narrow(true).widget_instance()
|
||||
});
|
||||
cells.push(widget);
|
||||
values.push(widget);
|
||||
}
|
||||
cells
|
||||
values
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -307,8 +307,8 @@ impl TableRowLayout for Artboard {
|
||||
fn identifier(&self) -> String {
|
||||
self.label.clone()
|
||||
}
|
||||
fn element_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
self.content.element_page(data)
|
||||
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
self.content.value_page(data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,9 +328,9 @@ impl TableRowLayout for Graphic {
|
||||
}
|
||||
// Don't put a breadcrumb for Graphic
|
||||
fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
self.element_page(data)
|
||||
self.value_page(data)
|
||||
}
|
||||
fn element_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
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),
|
||||
@@ -355,7 +355,7 @@ impl TableRowLayout for Vector {
|
||||
if self.segment_domain.ids().len() == 1 { "" } else { "s" }
|
||||
)
|
||||
}
|
||||
fn element_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let table_tab_entries = [VectorTableTab::Properties, VectorTableTab::Points, VectorTableTab::Segments, VectorTableTab::Regions]
|
||||
.into_iter()
|
||||
.map(|tab| {
|
||||
@@ -508,7 +508,7 @@ impl TableRowLayout for Raster<CPU> {
|
||||
fn identifier(&self) -> String {
|
||||
format!("Raster ({} x {})", self.width, self.height)
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let raster = self.data();
|
||||
|
||||
if raster.width == 0 || raster.height == 0 {
|
||||
@@ -539,7 +539,7 @@ impl TableRowLayout for Raster<GPU> {
|
||||
fn identifier(&self) -> String {
|
||||
format!("Raster ({} x {})", self.data().width(), self.data().height())
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let widgets = vec![TextLabel::new("Raster is a texture on the GPU and cannot currently be displayed here").widget_instance()];
|
||||
vec![LayoutGroup::row(widgets)]
|
||||
}
|
||||
@@ -552,15 +552,15 @@ impl TableRowLayout for Color {
|
||||
fn identifier(&self) -> String {
|
||||
format!("Color (#{})", self.to_gamma_srgb().to_rgba_hex_srgb())
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
ColorInput::new(FillChoice::Solid(*self))
|
||||
.disabled(true)
|
||||
.menu_direction(Some(MenuDirection::Top))
|
||||
.narrow(true)
|
||||
.widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let widgets = vec![self.cell_widget(PathStep::Element(0), _data)];
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let widgets = vec![self.value_widget(PathStep::Element(0), _data)];
|
||||
vec![LayoutGroup::row(widgets)]
|
||||
}
|
||||
}
|
||||
@@ -572,15 +572,15 @@ impl TableRowLayout for GradientStops {
|
||||
fn identifier(&self) -> String {
|
||||
format!("Gradient ({} stops)", self.len())
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
ColorInput::new(FillChoice::Gradient(self.clone()))
|
||||
.menu_direction(Some(MenuDirection::Top))
|
||||
.disabled(true)
|
||||
.narrow(true)
|
||||
.widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let widgets = vec![self.cell_widget(PathStep::Element(0), _data)];
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let widgets = vec![self.value_widget(PathStep::Element(0), _data)];
|
||||
vec![LayoutGroup::row(widgets)]
|
||||
}
|
||||
}
|
||||
@@ -592,8 +592,8 @@ impl TableRowLayout for f64 {
|
||||
fn identifier(&self) -> String {
|
||||
format!("{self}")
|
||||
}
|
||||
// Cells fall back to the default drill-in button (labeled with the value via `identifier`); the leaf page shows the rich `NumberInput`.
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
// Values fall back to the default drill-in button (labeled via `identifier`); the value page shows the rich `NumberInput`.
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![
|
||||
NumberInput::new(Some(*self)).disabled(true).max_width(220).display_decimal_places(20).widget_instance(),
|
||||
])]
|
||||
@@ -607,8 +607,8 @@ impl TableRowLayout for u8 {
|
||||
fn identifier(&self) -> String {
|
||||
format!("{self:02X}")
|
||||
}
|
||||
// Cells fall back to the default drill-in button (labeled with the hex value via `identifier`); the leaf page shows the same hex value as a label.
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
// Values fall back to the default drill-in button (labeled with the hex string via `identifier`); the value page shows the same hex value as a label.
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![TextLabel::new(self.identifier()).widget_instance()])]
|
||||
}
|
||||
}
|
||||
@@ -620,8 +620,8 @@ impl TableRowLayout for u32 {
|
||||
fn identifier(&self) -> String {
|
||||
format!("{self}")
|
||||
}
|
||||
// Cells fall back to the default drill-in button (labeled with the value via `identifier`); the leaf page shows the rich `NumberInput`.
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
// Values fall back to the default drill-in button (labeled via `identifier`); the value page shows the rich `NumberInput`.
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![
|
||||
NumberInput::new(Some(*self as f64)).disabled(true).max_width(220).display_decimal_places(20).widget_instance(),
|
||||
])]
|
||||
@@ -635,9 +635,9 @@ impl TableRowLayout for u64 {
|
||||
fn identifier(&self) -> String {
|
||||
format!("{self}")
|
||||
}
|
||||
// Cells fall back to the default drill-in button (labeled with the value via `identifier`); the leaf page shows the rich `NumberInput`.
|
||||
// Values fall back to the default drill-in button (labeled via `identifier`); the value page shows the rich `NumberInput`.
|
||||
// TODO: Make this robust for large u64 values that don't fit in f64 (above roughly 2^53). Perhaps using a bigint kind of approach through the widget's data flow.
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![
|
||||
NumberInput::new(Some(*self as f64)).disabled(true).max_width(220).display_decimal_places(20).widget_instance(),
|
||||
])]
|
||||
@@ -651,11 +651,11 @@ impl TableRowLayout for bool {
|
||||
fn identifier(&self) -> String {
|
||||
"Bool".to_string()
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextLabel::new(self.to_string()).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0), _data)])]
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,8 +672,8 @@ impl TableRowLayout for String {
|
||||
format!("\"{}\"", first_line)
|
||||
}
|
||||
}
|
||||
// Cells fall back to the default drill-in button (labeled with the truncated quoted preview via `identifier`); the leaf page shows the full multi-line text in a `TextAreaInput`.
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
// Values fall back to the default drill-in button (labeled with the truncated quoted preview via `identifier`); the value page shows the full multi-line text in a `TextAreaInput`.
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![TextAreaInput::new(self.to_string()).monospace(true).disabled(true).widget_instance()])]
|
||||
}
|
||||
}
|
||||
@@ -685,11 +685,11 @@ impl TableRowLayout for Option<f64> {
|
||||
fn identifier(&self) -> String {
|
||||
"Option<f64>".to_string()
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextLabel::new(format!("{self:?}")).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0), _data)])]
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,11 +700,11 @@ impl TableRowLayout for DVec2 {
|
||||
fn identifier(&self) -> String {
|
||||
"Vec2".to_string()
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextLabel::new(format_dvec2(*self)).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0), _data)])]
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,11 +715,11 @@ impl TableRowLayout for Vec2 {
|
||||
fn identifier(&self) -> String {
|
||||
"Vec2".to_string()
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextLabel::new(format_dvec2(DVec2::new(self.x as f64, self.y as f64))).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0), _data)])]
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,11 +730,11 @@ impl TableRowLayout for DAffine2 {
|
||||
fn identifier(&self) -> String {
|
||||
"Transform".to_string()
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextLabel::new(format_transform_matrix(*self)).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0), _data)])]
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,12 +745,12 @@ impl TableRowLayout for Affine2 {
|
||||
fn identifier(&self) -> String {
|
||||
"Transform".to_string()
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
let matrix = DAffine2::from_cols_array(&self.to_cols_array().map(|x| x as f64));
|
||||
TextLabel::new(format_transform_matrix(matrix)).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0), _data)])]
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -761,15 +761,15 @@ impl TableRowLayout for AlphaBlending {
|
||||
fn identifier(&self) -> String {
|
||||
format_alpha_blending(*self)
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, _target: PathStep, _data: &LayoutData) -> WidgetInstance {
|
||||
TextLabel::new(format_alpha_blending(*self)).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0), _data)])]
|
||||
fn value_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.value_widget(PathStep::Element(0), _data)])]
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the cell/breadcrumb label for a `NodeId` against `network_interface` at the given `network_path`,
|
||||
/// Resolves the value/breadcrumb label for a `NodeId` against `network_interface` at the given `network_path`,
|
||||
/// falling back to "Node {id}" if the node isn't present (e.g. an ID that no longer maps to a real node).
|
||||
fn node_id_display_label(node_id: NodeId, network_interface: &NodeNetworkInterface, network_path: &[NodeId]) -> String {
|
||||
if network_interface.node_metadata(&node_id, network_path).is_some() {
|
||||
@@ -786,16 +786,16 @@ impl TableRowLayout for NodeId {
|
||||
fn identifier(&self) -> String {
|
||||
format!("Node {self}")
|
||||
}
|
||||
// Override so the breadcrumb uses the same resolved display name as the cell button, instead of the bare-ID fallback `identifier()` returns.
|
||||
// Override so the breadcrumb uses the same resolved display name as the value button, instead of the bare-ID fallback `identifier()` returns.
|
||||
fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
data.breadcrumbs.push(node_id_display_label(*self, data.network_interface, &data.node_lookup_network_path));
|
||||
self.element_page(data)
|
||||
self.value_page(data)
|
||||
}
|
||||
// Cell label resolves the node's display name via the network interface so the button reads as the name shown
|
||||
// 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
|
||||
// signals layer-vs-node kind. Falls back to "Node {id}" with no icon if the lookup misses.
|
||||
fn cell_widget(&self, target: PathStep, data: &LayoutData) -> WidgetInstance {
|
||||
fn value_widget(&self, target: PathStep, data: &LayoutData) -> WidgetInstance {
|
||||
let label = node_id_display_label(*self, data.network_interface, &data.node_lookup_network_path);
|
||||
let mut button = TextButton::new(label)
|
||||
.on_update(move |_| DataPanelMessage::PushToElementPath { step: target.clone() }.into())
|
||||
@@ -806,8 +806,8 @@ impl TableRowLayout for NodeId {
|
||||
}
|
||||
button.widget_instance()
|
||||
}
|
||||
// The leaf page shows the node's kind, name (editable), lock/visibility toggles, and a "Select Layer/Node" action button.
|
||||
fn element_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
// The value page shows the node's kind, name (editable), lock/visibility toggles, and a "Select Layer/Node" action button.
|
||||
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let node_id = *self;
|
||||
let network_path = data.node_lookup_network_path.clone();
|
||||
let known = data.network_interface.node_metadata(&node_id, &network_path).is_some();
|
||||
@@ -892,7 +892,7 @@ impl TableRowLayout for NodeId {
|
||||
}
|
||||
|
||||
/// Invokes another macro with the full list of `TableRowLayout`-implementing types whose values may appear
|
||||
/// as attribute cell values. Both the cell-rendering and drilldown-navigation dispatchers iterate this list,
|
||||
/// 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 {
|
||||
($apply:ident) => {
|
||||
@@ -932,16 +932,16 @@ macro_rules! known_table_row_types {
|
||||
};
|
||||
}
|
||||
|
||||
/// Type-dispatched widget for displaying an attribute cell in a `Table<T>` row.
|
||||
/// Delegates to [`TableRowLayout::cell_widget`] so the same widget code is shared between
|
||||
/// Type-dispatched widget for displaying an attribute value in a `Table<T>` item.
|
||||
/// Delegates to [`TableRowLayout::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`].
|
||||
fn dispatch_cell_widget(any: &dyn Any, target: PathStep, data: &LayoutData) -> Option<WidgetInstance> {
|
||||
fn dispatch_value_widget(any: &dyn Any, target: PathStep, data: &LayoutData) -> Option<WidgetInstance> {
|
||||
macro_rules! check {
|
||||
( $($ty:ty),* $(,)? ) => {
|
||||
$(
|
||||
if let Some(value) = any.downcast_ref::<$ty>() {
|
||||
return Some(value.cell_widget(target, data));
|
||||
return Some(value.value_widget(target, data));
|
||||
}
|
||||
)*
|
||||
};
|
||||
@@ -950,10 +950,10 @@ fn dispatch_cell_widget(any: &dyn Any, target: PathStep, data: &LayoutData) -> O
|
||||
None
|
||||
}
|
||||
|
||||
/// Renders a `Table<NodeId>` as a path: the standard table view, but each row's `NodeId` cell is resolved
|
||||
/// against the network path made up of all preceding rows. So for a path `[outer, middle, leaf]`, row 0
|
||||
/// resolves at root, row 1 resolves at `[outer]`, and row 2 resolves at `[outer, middle]` — letting deeply
|
||||
/// nested layers display each step's correct name. Drilling into a row drops into that node's leaf page
|
||||
/// Renders a `Table<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> {
|
||||
data.breadcrumbs.push(path.identifier());
|
||||
@@ -979,7 +979,7 @@ fn table_node_id_path_layout_with_breadcrumb(path: &Table<NodeId>, data: &mut La
|
||||
let node_id = path.element(index).unwrap();
|
||||
let prefix: Vec<NodeId> = path.iter_element_values().take(index).copied().collect();
|
||||
let saved = std::mem::replace(&mut data.node_lookup_network_path, prefix);
|
||||
let widget = node_id.cell_widget(PathStep::Element(index), data);
|
||||
let widget = node_id.value_widget(PathStep::Element(index), data);
|
||||
data.node_lookup_network_path = saved;
|
||||
vec![TextLabel::new(format!("{index}")).narrow(true).widget_instance(), widget]
|
||||
})
|
||||
@@ -989,12 +989,12 @@ fn table_node_id_path_layout_with_breadcrumb(path: &Table<NodeId>, data: &mut La
|
||||
vec![LayoutGroup::table(rows, false)]
|
||||
}
|
||||
|
||||
/// Type-dispatched recursion into an attribute value for the data panel breadcrumb navigation.
|
||||
/// Mirrors [`dispatch_cell_widget`] but routes to [`TableRowLayout::layout_with_breadcrumb`].
|
||||
/// Type-dispatched recursion into an attribute value for the Data panel breadcrumb navigation.
|
||||
/// Mirrors [`dispatch_value_widget`] but routes to [`TableRowLayout::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` attribute), so each row's NodeId cell
|
||||
// resolves against the prefix made up of preceding rows. Handled before the generic `Table<T>` blanket impl.
|
||||
// `Table<NodeId>` is interpreted as a path (e.g. the `editor:layer` 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>>() {
|
||||
return Some(table_node_id_path_layout_with_breadcrumb(path, data));
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ pub enum DocumentMessage {
|
||||
undo_count: usize,
|
||||
},
|
||||
ToggleLayerExpansion {
|
||||
instance_path: Vec<NodeId>,
|
||||
tree_path: Vec<NodeId>,
|
||||
recursive: bool,
|
||||
},
|
||||
ToggleSelectedVisibility,
|
||||
|
||||
@@ -84,7 +84,7 @@ pub struct DocumentMessageHandler {
|
||||
//
|
||||
// Contains the NodeNetwork and acts an an interface to manipulate the NodeNetwork with custom setters in order to keep NetworkMetadata in sync
|
||||
pub network_interface: NodeNetworkInterface,
|
||||
/// Tracks which layer instances are collapsed in the Layers panel, keyed by instance path.
|
||||
/// Tracks which layer occurrences are collapsed in the Layers panel, keyed by tree path.
|
||||
#[serde(deserialize_with = "deserialize_collapsed_layers", default)]
|
||||
pub collapsed: CollapsedLayers,
|
||||
/// The full Git commit hash of the Graphite repository that was used to build the editor.
|
||||
@@ -1183,27 +1183,27 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
||||
}
|
||||
DocumentMessage::ToggleLayerExpansion { instance_path, recursive } => {
|
||||
let is_collapsed = self.collapsed.0.contains(&instance_path);
|
||||
DocumentMessage::ToggleLayerExpansion { tree_path, recursive } => {
|
||||
let is_collapsed = self.collapsed.0.contains(&tree_path);
|
||||
|
||||
if is_collapsed {
|
||||
if recursive {
|
||||
// Remove this path and all descendant paths (paths that start with this one)
|
||||
self.collapsed.0.retain(|path| !path.starts_with(&instance_path));
|
||||
self.collapsed.0.retain(|path| !path.starts_with(&tree_path));
|
||||
} else {
|
||||
self.collapsed.0.retain(|path| *path != instance_path);
|
||||
self.collapsed.0.retain(|path| *path != tree_path);
|
||||
}
|
||||
} else {
|
||||
if recursive {
|
||||
// Collapse all expanded descendant instances by collecting their paths from the structure tree
|
||||
let descendant_paths = self.collect_descendant_instance_paths(&instance_path);
|
||||
// Collapse all expanded descendant occurrences by collecting their tree paths from the structure tree
|
||||
let descendant_paths = self.collect_descendant_tree_paths(&tree_path);
|
||||
for path in descendant_paths {
|
||||
if !self.collapsed.0.contains(&path) {
|
||||
self.collapsed.0.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.collapsed.0.push(instance_path);
|
||||
self.collapsed.0.push(tree_path);
|
||||
}
|
||||
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
@@ -1782,11 +1782,11 @@ impl DocumentMessageHandler {
|
||||
let selected_layers: HashSet<NodeId> = network.selected_nodes().selected_layers(self.metadata()).map(LayerNodeIdentifier::to_node).collect();
|
||||
|
||||
let ancestors = HashSet::new();
|
||||
let instance_path = Vec::new();
|
||||
let tree_path = Vec::new();
|
||||
let mut root_entries = Vec::new();
|
||||
|
||||
// The first root layer is the topmost entry
|
||||
root_entries.push(self.build_layer_entry(first_root_layer_id, &ancestors, &selected_layers, &instance_path));
|
||||
root_entries.push(self.build_layer_entry(first_root_layer_id, &ancestors, &selected_layers, &tree_path));
|
||||
|
||||
// Layers in the primary flow (input[0] chain) from the first root layer are root-level siblings
|
||||
let mut root_ancestors = HashSet::new();
|
||||
@@ -1794,7 +1794,7 @@ impl DocumentMessageHandler {
|
||||
|
||||
for sibling_id in network.upstream_flow_back_from_nodes(vec![first_root_layer_id], &[], FlowType::PrimaryFlow).skip(1) {
|
||||
if network.is_layer(&sibling_id, &[]) && !root_ancestors.contains(&sibling_id) {
|
||||
root_entries.push(self.build_layer_entry(sibling_id, &root_ancestors, &selected_layers, &instance_path));
|
||||
root_entries.push(self.build_layer_entry(sibling_id, &root_ancestors, &selected_layers, &tree_path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1803,19 +1803,19 @@ impl DocumentMessageHandler {
|
||||
|
||||
/// Builds a single `LayerStructureEntry` for the given layer, including its `children_present` flag,
|
||||
/// `descendant_selected` flag, and (if expanded) its children collected from the graph.
|
||||
fn build_layer_entry(&self, layer_id: NodeId, ancestors: &HashSet<NodeId>, selected_layers: &HashSet<NodeId>, parent_instance_path: &[NodeId]) -> LayerStructureEntry {
|
||||
let mut instance_path = parent_instance_path.to_vec();
|
||||
instance_path.push(layer_id);
|
||||
fn build_layer_entry(&self, layer_id: NodeId, ancestors: &HashSet<NodeId>, selected_layers: &HashSet<NodeId>, parent_tree_path: &[NodeId]) -> LayerStructureEntry {
|
||||
let mut tree_path = parent_tree_path.to_vec();
|
||||
tree_path.push(layer_id);
|
||||
|
||||
let mut child_ancestors = ancestors.clone();
|
||||
child_ancestors.insert(layer_id);
|
||||
|
||||
let children_present = self.has_layer_children_in_graph(layer_id, &child_ancestors);
|
||||
|
||||
let collapsed = self.collapsed.0.contains(&instance_path);
|
||||
let collapsed = self.collapsed.0.contains(&tree_path);
|
||||
|
||||
let children = if children_present && !collapsed {
|
||||
self.collect_layer_children(layer_id, &child_ancestors, selected_layers, &instance_path)
|
||||
self.collect_layer_children(layer_id, &child_ancestors, selected_layers, &tree_path)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
@@ -1896,7 +1896,7 @@ impl DocumentMessageHandler {
|
||||
/// The horizontal flow (a layer's secondary input chain) finds nested content layers, and the
|
||||
/// primary flow from those (their stack's top output) finds stacked siblings at the same depth.
|
||||
/// `ancestors` contains layer IDs in the current path from root, used for cycle prevention.
|
||||
fn collect_layer_children(&self, layer_id: NodeId, ancestors: &HashSet<NodeId>, selected_layers: &HashSet<NodeId>, instance_path: &[NodeId]) -> Vec<LayerStructureEntry> {
|
||||
fn collect_layer_children(&self, layer_id: NodeId, ancestors: &HashSet<NodeId>, selected_layers: &HashSet<NodeId>, tree_path: &[NodeId]) -> Vec<LayerStructureEntry> {
|
||||
let network = &self.network_interface;
|
||||
|
||||
// Find the first nested layer via horizontal flow (content inside this layer)
|
||||
@@ -1914,22 +1914,22 @@ impl DocumentMessageHandler {
|
||||
}
|
||||
|
||||
// The nested layer is the first child at this depth level
|
||||
let mut children = vec![self.build_layer_entry(nested_id, ancestors, selected_layers, instance_path)];
|
||||
let mut children = vec![self.build_layer_entry(nested_id, ancestors, selected_layers, tree_path)];
|
||||
|
||||
// Primary flow from the nested layer finds stacked siblings (more children of this layer)
|
||||
for sibling_id in network.upstream_flow_back_from_nodes(vec![nested_id], &[], FlowType::PrimaryFlow).skip(1) {
|
||||
if network.is_layer(&sibling_id, &[]) && !ancestors.contains(&sibling_id) {
|
||||
children.push(self.build_layer_entry(sibling_id, ancestors, selected_layers, instance_path));
|
||||
children.push(self.build_layer_entry(sibling_id, ancestors, selected_layers, tree_path));
|
||||
}
|
||||
}
|
||||
|
||||
children
|
||||
}
|
||||
|
||||
/// Collects instance paths for all descendant layers of the given instance path by traversing the graph.
|
||||
/// Collects tree paths for all descendant layers of the given tree path by traversing the graph.
|
||||
/// Used for recursive collapse to find all expandable descendants.
|
||||
fn collect_descendant_instance_paths(&self, instance_path: &[NodeId]) -> Vec<Vec<NodeId>> {
|
||||
let Some(&layer_id) = instance_path.last() else { return Vec::new() };
|
||||
fn collect_descendant_tree_paths(&self, tree_path: &[NodeId]) -> Vec<Vec<NodeId>> {
|
||||
let Some(&layer_id) = tree_path.last() else { return Vec::new() };
|
||||
let network = &self.network_interface;
|
||||
|
||||
let mut paths = Vec::new();
|
||||
@@ -1938,7 +1938,7 @@ impl DocumentMessageHandler {
|
||||
// Seed with child layers via horizontal flow
|
||||
for node_id in network.upstream_flow_back_from_nodes(vec![layer_id], &[], FlowType::HorizontalFlow).skip(1) {
|
||||
if network.is_layer(&node_id, &[]) {
|
||||
let mut child_path = instance_path.to_vec();
|
||||
let mut child_path = tree_path.to_vec();
|
||||
child_path.push(node_id);
|
||||
stack.push((node_id, child_path));
|
||||
}
|
||||
@@ -1946,14 +1946,14 @@ impl DocumentMessageHandler {
|
||||
|
||||
let mut visited = HashSet::new();
|
||||
|
||||
// Depth-first traversal collecting all unique descendant instance paths
|
||||
// Depth-first traversal collecting all unique descendant tree paths
|
||||
while let Some((current_id, current_path)) = stack.pop() {
|
||||
// Skip paths we've already visited to prevent cycles
|
||||
if !visited.insert(current_path.clone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Record this descendant's instance path for collapsing
|
||||
// Record this descendant's tree path for collapsing
|
||||
paths.push(current_path.clone());
|
||||
|
||||
// Add nested content layers found via horizontal flow
|
||||
@@ -2218,18 +2218,18 @@ impl DocumentMessageHandler {
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
|
||||
// The control path layer (Blend Path / Morph Path) should start collapsed.
|
||||
let instance_path = {
|
||||
// Build instance path from root down to the control path layer, which is a sibling of the main layer under `parent`.
|
||||
let mut instance_path: Vec<NodeId> = parent
|
||||
let tree_path = {
|
||||
// Build tree path from root down to the control path layer, which is a sibling of the main layer under `parent`.
|
||||
let mut tree_path: Vec<NodeId> = parent
|
||||
.ancestors(network_interface.document_metadata())
|
||||
.take_while(|&ancestor| ancestor != LayerNodeIdentifier::ROOT_PARENT)
|
||||
.map(LayerNodeIdentifier::to_node)
|
||||
.collect();
|
||||
instance_path.reverse();
|
||||
instance_path.push(control_path_id);
|
||||
instance_path
|
||||
tree_path.reverse();
|
||||
tree_path.push(control_path_id);
|
||||
tree_path
|
||||
};
|
||||
responses.add(DocumentMessage::ToggleLayerExpansion { instance_path, recursive: false });
|
||||
responses.add(DocumentMessage::ToggleLayerExpansion { tree_path, recursive: false });
|
||||
|
||||
return folder_id;
|
||||
}
|
||||
@@ -2375,7 +2375,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 vector table row.
|
||||
// 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: 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();
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ pub struct GraphOperationMessageContext<'a> {
|
||||
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, ExtractField)]
|
||||
pub struct GraphOperationMessageHandler {}
|
||||
|
||||
// GraphOperationMessageHandler always modified the document network. This is so changes to the layers panel will only affect the document network.
|
||||
// GraphOperationMessageHandler always modified the document network. This is so changes to the Layers panel will only affect the document network.
|
||||
// For changes to the selected network, use NodeGraphMessageHandler. No NodeGraphMessage's should be added here, since they will affect the selected nested network.
|
||||
#[message_handler_data]
|
||||
impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for GraphOperationMessageHandler {
|
||||
|
||||
@@ -392,7 +392,7 @@ 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 row.
|
||||
// TODO: Allow the 'Path' node to operate on `Table` 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>)) {
|
||||
@@ -604,7 +604,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
self.set_input_with_refresh(InputConnector::node(artboard_node_id, 3), NodeInput::value(TaggedValue::DVec2(dimensions.into()), false), false);
|
||||
}
|
||||
|
||||
/// Set the input, refresh the properties panel, and run the document graph if skip_rerender is false
|
||||
/// Set the input, refresh the Properties panel, and run the document graph if skip_rerender is false
|
||||
pub fn set_input_with_refresh(&mut self, input_connector: InputConnector, input: NodeInput, skip_rerender: bool) {
|
||||
self.network_interface.set_input(&input_connector, input, &[]);
|
||||
self.responses.add(PropertiesPanelMessage::Refresh);
|
||||
|
||||
@@ -239,7 +239,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::path_of_subgraph::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
// Stamp each row of the content with the parent layer's NodeId via the `editor:layer` attribute,
|
||||
// Stamp each item of the content with the parent layer's NodeId via the `editor:layer` attribute,
|
||||
// so editor tools (e.g. selection, click target routing) can trace data back to its owning layer.
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
@@ -343,7 +343,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed("Merges the provided content as a new element in the graphic table that represents a layer compositing stack."),
|
||||
description: Cow::Borrowed("Merges the provided content as a new item in the layer's compositing stack."),
|
||||
properties: None,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
@@ -374,7 +374,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::path_of_subgraph::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
// Stamp each row of the content with the parent layer's NodeId via the `editor:layer` attribute,
|
||||
// Stamp each item of the content with the parent layer's NodeId via the `editor:layer` attribute,
|
||||
// so editor tools (e.g. selection, click target routing) can trace data back to its owning layer.
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
@@ -697,7 +697,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 4: Multiply (total instances)
|
||||
// 4: Multiply (total items)
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(16, 1)),
|
||||
@@ -1545,7 +1545,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
exports: vec![
|
||||
// Primary output: the whole match (String)
|
||||
NodeInput::node(NodeId(1), 0),
|
||||
// Secondary output: capture groups (Table<String>), each row carries `start`/`end`/`name` attributes from `regex_find`
|
||||
// Secondary output: capture groups (Table<String>), each item carries `start`/`end`/`name` attributes from `regex_find`
|
||||
NodeInput::node(NodeId(2), 0),
|
||||
],
|
||||
nodes: [
|
||||
@@ -1561,13 +1561,13 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
implementation: DocumentNodeImplementation::ProtoNode(text_nodes::regex::regex_find::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
// Node 1: extract_element at index 0, extracts the whole match as a bare String (drops the row's start/end/name attributes since the unwrapped String can't carry them)
|
||||
// Node 1: extract_element at index 0, extracts the whole match as a bare String (drops the item's start/end/name attributes since the unwrapped String can't carry them)
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::F64(0.), false)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::extract_element::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
// Node 2: omit_element at index 0, returns the capture group rows as a Table<String>, preserving each row's start/end/name attributes
|
||||
// Node 2: omit_element at index 0, returns the capture group items as a Table<String>, preserving each item's start/end/name attributes
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::F64(0.), false)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::omit_element::IDENTIFIER),
|
||||
@@ -1880,7 +1880,7 @@ type NodeProperties = HashMap<String, Box<dyn Fn(NodeId, &mut NodePropertiesCont
|
||||
// TODO: Replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) or similar
|
||||
pub static NODE_OVERRIDES: once_cell::sync::Lazy<NodeProperties> = once_cell::sync::Lazy::new(static_node_properties);
|
||||
|
||||
/// Defines the logic for inputs to display a custom properties panel widget.
|
||||
/// Defines the logic for inputs to display a custom Properties panel widget.
|
||||
fn static_node_properties() -> NodeProperties {
|
||||
let mut map: NodeProperties = HashMap::new();
|
||||
map.insert("brightness_contrast_properties".to_string(), Box::new(node_properties::brightness_contrast_properties));
|
||||
@@ -1909,7 +1909,7 @@ type InputProperties = HashMap<String, Box<dyn Fn(NodeId, usize, &mut NodeProper
|
||||
// TODO: Replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) or similar
|
||||
static INPUT_OVERRIDES: once_cell::sync::Lazy<InputProperties> = once_cell::sync::Lazy::new(static_input_properties);
|
||||
|
||||
/// Defines the logic for inputs to display a custom properties panel widget.
|
||||
/// Defines the logic for inputs to display a custom Properties panel widget.
|
||||
fn static_input_properties() -> InputProperties {
|
||||
let mut map: InputProperties = HashMap::new();
|
||||
map.insert("hidden".to_string(), Box::new(|_node_id, _index, _context| Ok(Vec::new())));
|
||||
|
||||
@@ -2402,7 +2402,7 @@ impl NodeGraphMessageHandler {
|
||||
self.widgets[1] = LayoutGroup::row(widgets);
|
||||
}
|
||||
|
||||
/// Collate the properties panel sections for a node graph
|
||||
/// Collate the Properties panel sections for a node graph
|
||||
pub fn collate_properties(context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
// If the selected nodes are in the document network, use the document network. Otherwise, use the nested network
|
||||
let Some(selected_nodes) = context.network_interface.selected_nodes_in_nested_network(context.selection_network_path) else {
|
||||
@@ -2468,7 +2468,7 @@ impl NodeGraphMessageHandler {
|
||||
}
|
||||
|
||||
// TODO: Display properties for encapsulating node when no nodes are selected in a nested network
|
||||
// This may require store a separate path for the properties panel
|
||||
// This may require store a separate path for the Properties panel
|
||||
let mut properties = vec![LayoutGroup::row(vec![
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
IconLabel::new("File").tooltip_description("Name of the current document.").widget_instance(),
|
||||
|
||||
@@ -1531,10 +1531,10 @@ pub(crate) fn spiral_properties(node_id: NodeId, context: &mut NodePropertiesCon
|
||||
}
|
||||
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_SPACING: &str = "Use a point sampling density controlled by a distance between, or specific number of, points.";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_SEPARATION: &str = "Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled).";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_SEPARATION: &str = "Distance between each point (exact if 'Adaptive Spacing' is disabled, approximate if enabled).";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_QUANTITY: &str = "Number of points to place along the path.";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_START_OFFSET: &str = "Exclude some distance from the start of the path before the first instance.";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_STOP_OFFSET: &str = "Exclude some distance from the end of the path after the last instance.";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_START_OFFSET: &str = "Exclude some distance from the start of the path before the first point.";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_STOP_OFFSET: &str = "Exclude some distance from the end of the path after the last point.";
|
||||
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_ADAPTIVE_SPACING: &str = "Round 'Separation' to a nearby value that divides into the path length evenly.";
|
||||
|
||||
pub(crate) fn sample_polyline_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
|
||||
@@ -3284,7 +3284,7 @@ impl NodeNetworkInterface {
|
||||
self.document_metadata.local_transforms = local_transforms;
|
||||
}
|
||||
|
||||
/// Update the cached first instance source id of the layers
|
||||
/// Update the cached first item's source id of the layers
|
||||
pub fn update_first_element_source_id(&mut self, new: HashMap<NodeId, Option<NodeId>>) {
|
||||
self.document_metadata.first_element_source_ids = new;
|
||||
}
|
||||
@@ -6636,11 +6636,11 @@ pub enum NodeTypeTransientMetadata {
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct LayerTransientMetadata {
|
||||
// Stores the width in grid cell units for layer nodes from the left edge of the thumbnail (+12px padding since thumbnail ends between grid spaces) to the left end of the node
|
||||
// Stores the width in grid units for layer nodes from the left edge of the thumbnail (+12px padding since thumbnail ends between grid spaces) to the left end of the node
|
||||
/// This is necessary since calculating the layer width through web_sys is very slow
|
||||
pub layer_width: TransientMetadata<u32>,
|
||||
// Should not be a performance concern to calculate when needed with chain_width.
|
||||
// Stores the width in grid cell units for layer nodes from the left edge of the thumbnail to the end of the chain
|
||||
// Stores the width in grid units for layer nodes from the left edge of the thumbnail to the end of the chain
|
||||
// chain_width: u32,
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ impl SelectedNodes {
|
||||
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||
/// Tracks which layer instances are collapsed in the Layers panel. Each entry is an "instance path":
|
||||
/// Tracks which layer occurrences are collapsed in the Layers panel. Each entry is a "tree path":
|
||||
/// the sequence of ancestor node IDs from the root down to the collapsed layer. This allows the same
|
||||
/// layer appearing under multiple parents to have independent expand/collapse state per instance.
|
||||
/// layer appearing under multiple parents to have independent expand/collapse state per occurrence.
|
||||
pub struct CollapsedLayers(pub Vec<Vec<NodeId>>);
|
||||
|
||||
@@ -1599,10 +1599,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
.set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::U32(0), false), network_path);
|
||||
}
|
||||
|
||||
// Migrate from the old source/target v1 "Morph" node to the new vector table based v2 "Morph" node.
|
||||
// This doesn't produce exactly equivalent results in cases involving input vector tables with multiple rows.
|
||||
// The old version would zip the source and target table rows, interpoleating each pair together.
|
||||
// The migrated version will instead deeply flatten both merged tables and morph sequentially between all source vectors and all target vector elements.
|
||||
// Migrate from the old source/target v1 "Morph" node to the new `Table<Vector>`-based v2 "Morph" node.
|
||||
// This doesn't produce exactly equivalent results in cases involving input `Table<Vector>` values with multiple items.
|
||||
// The old version would zip the source and target items, interpolating each pair together.
|
||||
// The migrated version will instead deeply flatten both merged `Table`s and morph sequentially between all source vectors and all target vector elements.
|
||||
// This migration assumes most usages didn't involve multiple parallel vector elements, and instead morphed from a single source to a single target vector element.
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::morph::IDENTIFIER) && (inputs_count == 3 || inputs_count == 4) {
|
||||
// 3 inputs - old signature (#3405):
|
||||
@@ -1669,7 +1669,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
return None;
|
||||
};
|
||||
|
||||
// Create Count Elements node: counts content table rows → N
|
||||
// Create Count Elements node: counts content `Table` items → N
|
||||
let Some(count_elements_def) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::count_elements::IDENTIFIER)) else {
|
||||
log::error!("Could not get count_elements node from definition when upgrading morph");
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
|
||||
|
||||
@@ -417,7 +417,7 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
|
||||
let Some(&TaggedValue::TextAlign(align)) = inputs[graphene_std::text::text::AlignInput::INDEX].as_value() else {
|
||||
return None;
|
||||
};
|
||||
let Some(&TaggedValue::Bool(per_glyph_instances)) = inputs[graphene_std::text::text::SeparateGlyphElementsInput::INDEX].as_value() else {
|
||||
let Some(&TaggedValue::Bool(per_glyph_items)) = inputs[graphene_std::text::text::SeparateGlyphElementsInput::INDEX].as_value() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -430,7 +430,7 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
|
||||
tilt,
|
||||
align,
|
||||
};
|
||||
Some((text, font, typesetting, per_glyph_instances))
|
||||
Some((text, font, typesetting, per_glyph_items))
|
||||
}
|
||||
|
||||
pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {
|
||||
|
||||
@@ -1281,7 +1281,7 @@ impl ShapeState {
|
||||
};
|
||||
let delta = delta_transform.inverse().transform_vector2(delta);
|
||||
|
||||
// Make a new collection of anchor points which needs to be moved
|
||||
// Make a new set of anchor points which needs to be moved
|
||||
let mut affected_points = state.selected_points.clone();
|
||||
|
||||
for (segment_id, _, start, end) in vector.segment_bezier_iter() {
|
||||
|
||||
@@ -64,15 +64,15 @@ where
|
||||
|
||||
/// Calculates the bounding box of the layer's text, based on the settings for max width and height specified in the typesetting config.
|
||||
pub fn text_bounding_box(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, font_cache: &FontCache) -> Quad {
|
||||
let Some((text, font, typesetting, per_glyph_instances)) = get_text(layer, &document.network_interface) else {
|
||||
let Some((text, font, typesetting, per_glyph_items)) = get_text(layer, &document.network_interface) else {
|
||||
return Quad::from_box([DVec2::ZERO, DVec2::ZERO]);
|
||||
};
|
||||
|
||||
let far = graphene_std::text::bounding_box(text, font, font_cache, typesetting, false);
|
||||
|
||||
// TODO: Once the instance tables refactor is complete and per_glyph_instances can be removed (since it'll be the default),
|
||||
// TODO: Once the `Table` refactor is complete and per_glyph_items can be removed (since it'll be the default),
|
||||
// TODO: remove this because the top of the dashed bounding overlay should no longer be based on the first line's baseline.
|
||||
let vertical_offset = if per_glyph_instances {
|
||||
let vertical_offset = if per_glyph_items {
|
||||
DVec2::NEG_Y * typesetting.font_size * (1. + (typesetting.line_height_ratio - 1.) / 2.)
|
||||
} else {
|
||||
DVec2::ZERO
|
||||
|
||||
@@ -450,7 +450,7 @@ mod test_freehand {
|
||||
}
|
||||
|
||||
fn verify_path_points(vector_and_transform_list: &[(Vector, DAffine2)], expected_captured_points: &[DVec2], tolerance: f64) -> Result<(), String> {
|
||||
assert_eq!(vector_and_transform_list.len(), 1, "There should be one row of Vector geometry");
|
||||
assert_eq!(vector_and_transform_list.len(), 1, "There should be one item of Vector geometry");
|
||||
|
||||
let (vector, transform) = vector_and_transform_list
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user