mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Rename the "Table" type to "List" everywhere (#4133)
* Rename the "Table" type to "List" everywhere * Fix a few missed ones * Re-save demo artwork
This commit is contained in:
@@ -15,7 +15,7 @@ pub trait BoundingBox {
|
||||
/// Returns the bounding box to use when sizing this value's thumbnail in the Layers panel.
|
||||
///
|
||||
/// Diverges from `bounding_box` for types where the rendering bounds wouldn't make a useful thumbnail frame.
|
||||
/// For instance, `GradientStops` is `Infinite` for rendering but returns the line's AABB here, so a `Table<Graphic>`
|
||||
/// For instance, `GradientStops` is `Infinite` for rendering but returns the line's AABB here, so a `List<Graphic>`
|
||||
/// group of a gradient and a vector frames around the vector's geometry rather than infinity.
|
||||
/// Types with no meaningful contribution (e.g., `Color`) return `Infinite` from both; the runtime substitutes a
|
||||
/// small fallback rectangle at the end if no finite bounds remain after combining.
|
||||
|
||||
@@ -4,13 +4,13 @@ pub mod bounds;
|
||||
pub mod consts;
|
||||
pub mod context;
|
||||
pub mod generic;
|
||||
pub mod list;
|
||||
pub mod math;
|
||||
pub mod memo;
|
||||
pub mod misc;
|
||||
pub mod ops;
|
||||
pub mod registry;
|
||||
pub mod render_complexity;
|
||||
pub mod table;
|
||||
pub mod transform;
|
||||
pub mod uuid;
|
||||
pub mod value;
|
||||
@@ -23,6 +23,10 @@ pub use ctor;
|
||||
pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync};
|
||||
pub use graphene_hash;
|
||||
pub use graphene_hash::CacheHash;
|
||||
pub use list::{
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_END,
|
||||
ATTR_GRADIENT_TYPE, ATTR_LOCATION, ATTR_NAME, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD, ATTR_START, ATTR_TRANSFORM, ATTR_TYPE,
|
||||
};
|
||||
pub use memo::MemoHash;
|
||||
pub use no_std_types::AsU32;
|
||||
pub use no_std_types::blending;
|
||||
@@ -33,10 +37,6 @@ pub use num_traits;
|
||||
use std::any::TypeId;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
pub use table::{
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_END,
|
||||
ATTR_GRADIENT_TYPE, ATTR_LOCATION, ATTR_NAME, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD, ATTR_START, ATTR_TRANSFORM, ATTR_TYPE,
|
||||
};
|
||||
#[cfg(feature = "wasm")]
|
||||
pub use tsify;
|
||||
pub use types::Cow;
|
||||
|
||||
@@ -27,11 +27,11 @@ pub const ATTR_OPACITY_FILL: &str = "opacity_fill";
|
||||
/// `bool` for whether an item inherits the alpha of the content beneath it (clipping mask).
|
||||
pub const ATTR_CLIPPING_MASK: &str = "clipping_mask";
|
||||
|
||||
/// `Table<NodeId>` path from the root network to the layer node owning this item.
|
||||
/// `List<NodeId>` path from the root network to the layer node owning this item.
|
||||
/// Used by editor tools to route clicks/selection back to the originating layer.
|
||||
pub const ATTR_EDITOR_LAYER_PATH: &str = "editor:layer_path";
|
||||
|
||||
/// `Table<Graphic>` snapshot of the upstream content that fed into a destructive merge
|
||||
/// `List<Graphic>` snapshot of the upstream content that fed into a destructive merge
|
||||
/// (Boolean Operation, Rasterize, etc.), so the editor can still surface click targets for
|
||||
/// the original child layers after their content has been collapsed.
|
||||
pub const ATTR_EDITOR_MERGED_LAYERS: &str = "editor:merged_layers";
|
||||
@@ -147,7 +147,7 @@ impl Clone for Box<dyn AnyAttributeValue> {
|
||||
// TRAIT: AnyAttribute
|
||||
// ===================
|
||||
|
||||
/// Enables type-erased storage for parallel attribute lists in a [`Table`].
|
||||
/// Enables type-erased storage for parallel attribute lists in a [`List`].
|
||||
pub trait AnyAttribute: std::any::Any + Send + Sync {
|
||||
/// Clones this attribute into a new boxed trait object.
|
||||
fn clone_box(&self) -> Box<dyn AnyAttribute>;
|
||||
@@ -224,7 +224,7 @@ impl Clone for Box<dyn AnyAttribute> {
|
||||
// Attribute<T>
|
||||
// ============
|
||||
|
||||
/// Wraps a Vec<T> for attribute storage in a [`Table`].
|
||||
/// Wraps a Vec<T> for attribute storage in a [`List`].
|
||||
pub struct Attribute<T>(pub Vec<T>);
|
||||
|
||||
impl<T: Clone + Send + Sync + Default + Debug + PartialEq + CacheHash + 'static> AnyAttribute for Attribute<T> {
|
||||
@@ -329,7 +329,7 @@ impl<T: Clone + Send + Sync + Default + Debug + PartialEq + CacheHash + 'static>
|
||||
// ============
|
||||
|
||||
/// Type-erased list of attribute values, used as a node graph parameter type.
|
||||
/// Lets a node accept any `Table<U>` source via the auto-inserted `Convert<AttributeDyn, ()>`
|
||||
/// Lets a node accept any `List<U>` source via the auto-inserted `Convert<AttributeDyn, ()>`
|
||||
/// without monomorphizing over `U` (so the cartesian product of `(content T, source U)` collapses to just `T`).
|
||||
pub struct AttributeDyn(pub Box<dyn AnyAttribute>);
|
||||
|
||||
@@ -439,26 +439,26 @@ unsafe impl StaticType for AttributeValueDyn {
|
||||
type Static = Self;
|
||||
}
|
||||
|
||||
// ========
|
||||
// TableDyn
|
||||
// ========
|
||||
// =======
|
||||
// ListDyn
|
||||
// =======
|
||||
|
||||
/// Type-erased view of a `Table<T>` exposing only its attributes and item count, used as a node graph parameter type.
|
||||
/// Lets a node accept any `Table<U>` source via the auto-inserted `Convert<TableDyn, ()>` without monomorphizing over `U`,
|
||||
/// for cases where the element type is irrelevant (such as nodes that read out a named attribute regardless of the carrier table).
|
||||
/// Type-erased view of a `List<T>` exposing only its attributes and item count, used as a node graph parameter type.
|
||||
/// Lets a node accept any `List<U>` source via the auto-inserted `Convert<ListDyn, ()>` without monomorphizing over `U`,
|
||||
/// for cases where the element type is irrelevant (such as nodes that read out a named attribute regardless of the carrier `List`).
|
||||
#[derive(Default)]
|
||||
pub struct TableDyn {
|
||||
pub struct ListDyn {
|
||||
attributes: Vec<(String, Box<dyn AnyAttribute>)>,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl TableDyn {
|
||||
/// Number of items in the underlying table.
|
||||
impl ListDyn {
|
||||
/// Number of items in the underlying `List`.
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Whether the underlying table has zero items.
|
||||
/// Whether the underlying `List` has zero items.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
@@ -471,16 +471,16 @@ impl TableDyn {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Table<T>> for TableDyn {
|
||||
fn from(table: Table<T>) -> Self {
|
||||
impl<T> From<List<T>> for ListDyn {
|
||||
fn from(list: List<T>) -> Self {
|
||||
Self {
|
||||
attributes: table.attributes.attributes,
|
||||
len: table.attributes.len,
|
||||
attributes: list.attributes.attributes,
|
||||
len: list.attributes.len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TableDyn {
|
||||
impl Clone for ListDyn {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
attributes: self.attributes.iter().map(|(key, attribute)| (key.clone(), attribute.clone_box())).collect(),
|
||||
@@ -489,14 +489,14 @@ impl Clone for TableDyn {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for TableDyn {
|
||||
impl Debug for ListDyn {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let keys: Vec<&str> = self.attributes.iter().map(|(k, _)| k.as_str()).collect();
|
||||
f.debug_struct("TableDyn").field("keys", &keys).field("len", &self.len).finish()
|
||||
f.debug_struct("ListDyn").field("keys", &keys).field("len", &self.len).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for TableDyn {
|
||||
impl PartialEq for ListDyn {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.len == other.len
|
||||
&& self.attributes.len() == other.attributes.len()
|
||||
@@ -508,7 +508,7 @@ impl PartialEq for TableDyn {
|
||||
}
|
||||
}
|
||||
|
||||
impl CacheHash for TableDyn {
|
||||
impl CacheHash for ListDyn {
|
||||
fn cache_hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.len.cache_hash(state);
|
||||
for (key, attribute) in &self.attributes {
|
||||
@@ -518,7 +518,7 @@ impl CacheHash for TableDyn {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl StaticType for TableDyn {
|
||||
unsafe impl StaticType for ListDyn {
|
||||
type Static = Self;
|
||||
}
|
||||
|
||||
@@ -631,7 +631,7 @@ impl ItemAttributeValues {
|
||||
/// The storage data structure for attributes.
|
||||
///
|
||||
/// A collection of type-erased parallel attributes, keyed by string name.
|
||||
/// All access goes through [`Table`] and [`Item`] since internals are private.
|
||||
/// All access goes through [`List`] and [`Item`] since internals are private.
|
||||
/// Invariant: every attribute in `attributes` has exactly `len` elements.
|
||||
#[derive(Clone, Default)]
|
||||
struct Attributes {
|
||||
@@ -842,9 +842,9 @@ impl Attributes {
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// Table<T>
|
||||
// ========
|
||||
// =======
|
||||
// List<T>
|
||||
// =======
|
||||
|
||||
/// A struct-of-arrays collection where each item holds an element of type `T` alongside
|
||||
/// a set of type-erased, dynamically-typed attributes stored in parallel attributes.
|
||||
@@ -853,18 +853,18 @@ impl Attributes {
|
||||
/// [`Attributes`] store that keeps one attribute per attribute key. Items are accessed by
|
||||
/// index through element/attribute accessor methods, or consumed as owned [`Item`]s via iteration.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Table<T> {
|
||||
pub struct List<T> {
|
||||
element: Vec<T>,
|
||||
attributes: Attributes,
|
||||
}
|
||||
|
||||
impl<T> Table<T> {
|
||||
/// Creates an empty table with no items.
|
||||
impl<T> List<T> {
|
||||
/// Creates an empty list with no items.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Creates an empty table with pre-allocated capacity for the given number of items.
|
||||
/// Creates an empty list with pre-allocated capacity for the given number of items.
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
element: Vec::with_capacity(capacity),
|
||||
@@ -872,7 +872,7 @@ impl<T> Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a table containing a single item with the given element and no attributes.
|
||||
/// Creates a list containing a single item with the given element and no attributes.
|
||||
pub fn new_from_element(element: T) -> Self {
|
||||
Self {
|
||||
element: vec![element],
|
||||
@@ -880,7 +880,7 @@ impl<T> Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a table containing a single item from the given [`Item`], preserving its attributes.
|
||||
/// Creates a list containing a single item from the given [`Item`], preserving its attributes.
|
||||
pub fn new_from_item(item: Item<T>) -> Self {
|
||||
let mut attributes = Attributes::new();
|
||||
attributes.push_item(item.attributes);
|
||||
@@ -890,29 +890,29 @@ impl<T> Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends an item to the end of this table.
|
||||
/// Appends an item to the end of this list.
|
||||
pub fn push(&mut self, item: Item<T>) {
|
||||
self.element.push(item.element);
|
||||
self.attributes.push_item(item.attributes);
|
||||
}
|
||||
|
||||
/// Appends all items from another table into this one.
|
||||
pub fn extend(&mut self, table: Table<T>) {
|
||||
self.element.extend(table.element);
|
||||
self.attributes.extend(table.attributes);
|
||||
/// Appends all items from another list into this one.
|
||||
pub fn extend(&mut self, list: List<T>) {
|
||||
self.element.extend(list.element);
|
||||
self.attributes.extend(list.attributes);
|
||||
}
|
||||
|
||||
/// Returns the number of items in this table.
|
||||
/// Returns the number of items in this list.
|
||||
pub fn len(&self) -> usize {
|
||||
self.element.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if this table contains no items.
|
||||
/// Returns `true` if this list contains no items.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.element.is_empty()
|
||||
}
|
||||
|
||||
/// Returns an iterator over all attribute keys in this table, in insertion order.
|
||||
/// Returns an iterator over all attribute keys in this list, in insertion order.
|
||||
pub fn attribute_keys(&self) -> impl Iterator<Item = &str> {
|
||||
self.attributes.keys()
|
||||
}
|
||||
@@ -991,7 +991,7 @@ impl<T> Table<T> {
|
||||
self.attributes.set_value(key, index, value);
|
||||
}
|
||||
|
||||
/// Replaces (or adds) an attribute from a type-erased source. The source is wrapped or truncated to match this table's item count.
|
||||
/// Replaces (or adds) an attribute from a type-erased source. The source is wrapped or truncated to match this list's item count.
|
||||
pub fn set_attribute_dyn(&mut self, key: impl Into<String>, source: AttributeDyn) {
|
||||
let key = key.into();
|
||||
self.attributes.attributes.retain(|(k, _)| k != &key);
|
||||
@@ -999,7 +999,7 @@ impl<T> Table<T> {
|
||||
self.attributes.attributes.push((key, new_attribute));
|
||||
}
|
||||
|
||||
/// Sets a single type-erased attribute value at the given index, creating the attribute from the value's underlying type if it doesn't exist (padded with defaults to match the table's length).
|
||||
/// Sets a single type-erased attribute value at the given index, creating the attribute from the value's underlying type if it doesn't exist (padded with defaults to match the list's length).
|
||||
/// Falls back to default if the value's type doesn't match an existing attribute.
|
||||
pub fn set_attribute_value_dyn(&mut self, key: impl Into<String>, index: usize, value: AttributeValueDyn) {
|
||||
let key = key.into();
|
||||
@@ -1069,7 +1069,7 @@ impl<T> Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BoundingBox> BoundingBox for Table<T> {
|
||||
impl<T: BoundingBox> BoundingBox for List<T> {
|
||||
/// Computes the combined bounding box of all items, composing each item's transform attribute with the given transform.
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||
let mut combined_bounds = None;
|
||||
@@ -1115,11 +1115,11 @@ impl<T: BoundingBox> BoundingBox for Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for Table<T> {
|
||||
impl<T> IntoIterator for List<T> {
|
||||
type Item = Item<T>;
|
||||
type IntoIter = ItemIter<T>;
|
||||
|
||||
/// Consumes a [`Table`] and returns an iterator of [`Item`]s, each containing the owned data of the respective item from the original table.
|
||||
/// Consumes a [`List`] and returns an iterator of [`Item`]s, each containing the owned data of the respective item from the original list.
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let attributes = self.attributes.into_item_vec();
|
||||
ItemIter {
|
||||
@@ -1129,7 +1129,7 @@ impl<T> IntoIterator for Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Table<T> {
|
||||
impl<T> Default for List<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
element: Vec::new(),
|
||||
@@ -1138,7 +1138,7 @@ impl<T> Default for Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CacheHash> CacheHash for Table<T> {
|
||||
impl<T: CacheHash> CacheHash for List<T> {
|
||||
fn cache_hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.element.cache_hash(state);
|
||||
|
||||
@@ -1151,7 +1151,7 @@ impl<T: CacheHash> CacheHash for Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for Table<T> {
|
||||
impl<T: PartialEq> PartialEq for List<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// Attributes participate in equality so the `a == b` ⇒ `hash(a) == hash(b)` contract holds with `cache_hash`
|
||||
self.element == other.element
|
||||
@@ -1165,7 +1165,7 @@ impl<T: PartialEq> PartialEq for Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ApplyTransform for Table<T> {
|
||||
impl<T> ApplyTransform for List<T> {
|
||||
/// Right-multiplies the modification into each item's transform attribute.
|
||||
fn apply_transform(&mut self, modification: &DAffine2) {
|
||||
for transform in self.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
|
||||
@@ -1181,22 +1181,22 @@ impl<T> ApplyTransform for Table<T> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: StaticTypeSized> StaticType for Table<T> {
|
||||
type Static = Table<T::Static>;
|
||||
unsafe impl<T: StaticTypeSized> StaticType for List<T> {
|
||||
type Static = List<T::Static>;
|
||||
}
|
||||
|
||||
impl<T> FromIterator<Item<T>> for Table<T> {
|
||||
/// Collects an iterator of [`Item`]s into a [`Table`], pre-allocating based on the iterator's size hint.
|
||||
impl<T> FromIterator<Item<T>> for List<T> {
|
||||
/// Collects an iterator of [`Item`]s into a [`List`], pre-allocating based on the iterator's size hint.
|
||||
fn from_iter<I: IntoIterator<Item = Item<T>>>(iter: I) -> Self {
|
||||
let iter = iter.into_iter();
|
||||
let (lower_bound, _) = iter.size_hint();
|
||||
let mut table = Self::with_capacity(lower_bound);
|
||||
let mut list = Self::with_capacity(lower_bound);
|
||||
|
||||
for item in iter {
|
||||
table.push(item);
|
||||
list.push(item);
|
||||
}
|
||||
|
||||
table
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1206,7 +1206,7 @@ impl<T> FromIterator<Item<T>> for Table<T> {
|
||||
|
||||
/// An owned item containing an element of type `T` and a set of type-erased scalar attributes.
|
||||
///
|
||||
/// Used to build individual items before pushing them into a [`Table`], or when consuming items out of a table via [`IntoIterator`].
|
||||
/// Used to build individual items before pushing them into a [`List`], or when consuming items out of a list via [`IntoIterator`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Item<T> {
|
||||
element: T,
|
||||
@@ -1317,9 +1317,9 @@ impl<T> Item<T> {
|
||||
// ItemIter<T>
|
||||
// ===========
|
||||
|
||||
/// Owning iterator over the items of a consumed [`Table`], yielding [`Item`]s.
|
||||
/// Owning iterator over the items of a consumed [`List`], yielding [`Item`]s.
|
||||
///
|
||||
/// Created by [`Table::into_iter`]. The table's attributes are converted into per-item
|
||||
/// Created by [`List::into_iter`]. The list's attributes are converted into per-item
|
||||
/// scalar [`ItemAttributeValues`] during construction so each yielded item is self-contained.
|
||||
pub struct ItemIter<T> {
|
||||
element: std::vec::IntoIter<T>,
|
||||
@@ -77,12 +77,12 @@ pub fn migrate_to_optional_color<'de, D: serde::Deserializer<'de>>(deserializer:
|
||||
#[cfg_attr(feature = "serde", serde(untagged))]
|
||||
enum ColorFormat {
|
||||
OptionalColor(Option<Color>),
|
||||
Table(LegacyTable<Color>),
|
||||
List(LegacyTable<Color>),
|
||||
}
|
||||
|
||||
Ok(match ColorFormat::deserialize(deserializer)? {
|
||||
ColorFormat::OptionalColor(color) => color,
|
||||
ColorFormat::Table(table) => table.element.into_iter().next(),
|
||||
ColorFormat::List(list) => list.element.into_iter().next(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -94,11 +94,11 @@ pub fn migrate_to_f64_array<'de, D: serde::Deserializer<'de>>(deserializer: D) -
|
||||
#[cfg_attr(feature = "serde", serde(untagged))]
|
||||
enum F64ArrayFormat {
|
||||
Array(Vec<f64>),
|
||||
Table(LegacyTable<f64>),
|
||||
List(LegacyTable<f64>),
|
||||
}
|
||||
|
||||
Ok(match F64ArrayFormat::deserialize(deserializer)? {
|
||||
F64ArrayFormat::Array(values) => values,
|
||||
F64ArrayFormat::Table(table) => table.element,
|
||||
F64ArrayFormat::List(list) => list.element,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::Node;
|
||||
use crate::table::{Attribute, AttributeDyn, AttributeValueDyn, Item, Table, TableDyn};
|
||||
use crate::list::{Attribute, AttributeDyn, AttributeValueDyn, Item, List, ListDyn};
|
||||
use crate::transform::Footprint;
|
||||
use glam::DVec2;
|
||||
use graphene_hash::CacheHash;
|
||||
@@ -55,27 +55,27 @@ impl<T: ToString + Send> Convert<String, ()> for T {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TableConvert<U> {
|
||||
pub trait ListConvert<U> {
|
||||
fn convert_row(self) -> U;
|
||||
}
|
||||
|
||||
impl<U, T: TableConvert<U> + Send> Convert<Table<U>, ()> for Table<T> {
|
||||
async fn convert(self, _: Footprint, _: ()) -> Table<U> {
|
||||
let table: Table<U> = self
|
||||
impl<U, T: ListConvert<U> + Send> Convert<List<U>, ()> for List<T> {
|
||||
async fn convert(self, _: Footprint, _: ()) -> List<U> {
|
||||
let list: List<U> = self
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
let (element, attributes) = row.into_parts();
|
||||
Item::from_parts(element.convert_row(), attributes)
|
||||
})
|
||||
.collect();
|
||||
table
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps each row's element into a type-erased column. Lets nodes that accept a source attribute
|
||||
/// from any `Table<U>` express their signature as `AttributeColumnDyn` and avoid monomorphizing
|
||||
/// Wraps each row's element into a type-erased attribute. Lets nodes that accept a source attribute
|
||||
/// from any `List<U>` express their signature as `AttributeDyn` and avoid monomorphizing
|
||||
/// over `U`; the compiler inserts this convert to bridge concrete-typed graph wires to the dyn input.
|
||||
impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash + 'static> Convert<AttributeDyn, ()> for Table<T> {
|
||||
impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash + 'static> Convert<AttributeDyn, ()> for List<T> {
|
||||
async fn convert(self, _: Footprint, _: ()) -> AttributeDyn {
|
||||
let values: Vec<T> = self.into_iter().map(|row| row.into_element()).collect();
|
||||
AttributeDyn(Box::new(Attribute(values)))
|
||||
@@ -83,7 +83,7 @@ impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash
|
||||
}
|
||||
|
||||
/// Wraps a value into a type-erased attribute value. Lets nodes that take a per-item value source
|
||||
/// (such as `write_attribute`'s value-producing input) be generic over the destination table type
|
||||
/// (such as `write_attribute`'s value-producing input) be generic over the destination list type
|
||||
/// alone, with the compiler-inserted convert handling each concrete value type at the wire level.
|
||||
impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash + 'static> Convert<AttributeValueDyn, ()> for T {
|
||||
async fn convert(self, _: Footprint, _: ()) -> AttributeValueDyn {
|
||||
@@ -91,11 +91,11 @@ impl<T: Clone + Send + Sync + Default + std::fmt::Debug + PartialEq + CacheHash
|
||||
}
|
||||
}
|
||||
|
||||
/// Erases a `Table<T>`'s element type, exposing only its attributes and row count. Lets nodes that
|
||||
/// only need attribute access (such as the `read_attribute_*` family) take a single `TableDyn` input
|
||||
/// instead of monomorphizing over every possible carrier table type.
|
||||
impl<T: Send> Convert<TableDyn, ()> for Table<T> {
|
||||
async fn convert(self, _: Footprint, _: ()) -> TableDyn {
|
||||
/// Erases a `List<T>`'s element type, exposing only its attributes and row count. Lets nodes that
|
||||
/// only need attribute access (such as the `read_attribute_*` family) take a single `ListDyn` input
|
||||
/// instead of monomorphizing over every possible carrier list type.
|
||||
impl<T: Send> Convert<ListDyn, ()> for List<T> {
|
||||
async fn convert(self, _: Footprint, _: ()) -> ListDyn {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ impl Convert<DVec2, ()> for DVec2 {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add a DVec2 to Table<Vector> anchor point conversion implementation to replace the 'Vec2 to Point' node
|
||||
// TODO: Add a DVec2 to List<Vector> anchor point conversion implementation to replace the 'Vec2 to Point' node
|
||||
|
||||
/// Implements the [`Convert`] trait for conversion between the cartesian product of Rust's primitive numeric types.
|
||||
macro_rules! impl_convert {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Raster types moved to raster-types crate
|
||||
use crate::Color;
|
||||
use crate::table::Table;
|
||||
use crate::list::List;
|
||||
|
||||
pub trait RenderComplexity {
|
||||
fn render_complexity(&self) -> usize {
|
||||
@@ -8,7 +8,7 @@ pub trait RenderComplexity {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RenderComplexity> RenderComplexity for Table<T> {
|
||||
impl<T: RenderComplexity> RenderComplexity for List<T> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
self.iter_element_values().map(|element| element.render_complexity()).fold(0, usize::saturating_add)
|
||||
}
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
use crate::graphic::Graphic;
|
||||
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use core_types::graphene_hash::CacheHash;
|
||||
use core_types::list::List;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::table::Table;
|
||||
use dyn_any::DynAny;
|
||||
use glam::DAffine2;
|
||||
|
||||
/// Nominal wrapper around `Table<Graphic>` representing a single artboard's content.
|
||||
/// Nominal wrapper around `List<Graphic>` representing a single artboard's content.
|
||||
///
|
||||
/// Per-artboard metadata (location, dimensions, background, clip) lives as row attributes on the
|
||||
/// enclosing `Table<Artboard>`, not as fields here. This keeps `Artboard` a pure type-system boundary
|
||||
/// that prevents arbitrary `Table<Table<...<Graphic>>>` nesting.
|
||||
/// enclosing `List<Artboard>`, not as fields here. This keeps `Artboard` a pure type-system boundary
|
||||
/// that prevents arbitrary `List<List<...<Graphic>>>` nesting.
|
||||
#[derive(Clone, Debug, Default, CacheHash, PartialEq, DynAny)]
|
||||
pub struct Artboard(Table<Graphic>);
|
||||
pub struct Artboard(List<Graphic>);
|
||||
|
||||
impl Artboard {
|
||||
pub fn new(content: Table<Graphic>) -> Self {
|
||||
pub fn new(content: List<Graphic>) -> Self {
|
||||
Self(content)
|
||||
}
|
||||
|
||||
pub fn as_graphic_table(&self) -> &Table<Graphic> {
|
||||
pub fn as_graphic_list(&self) -> &List<Graphic> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn as_graphic_table_mut(&mut self) -> &mut Table<Graphic> {
|
||||
pub fn as_graphic_list_mut(&mut self) -> &mut List<Graphic> {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
pub fn into_graphic_table(self) -> Table<Graphic> {
|
||||
pub fn into_graphic_list(self) -> List<Graphic> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Table<Graphic>> for Artboard {
|
||||
fn from(content: Table<Graphic>) -> Self {
|
||||
impl From<List<Graphic>> for Artboard {
|
||||
fn from(content: List<Graphic>) -> Self {
|
||||
Self(content)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Artboard> for Table<Graphic> {
|
||||
impl From<Artboard> for List<Graphic> {
|
||||
fn from(artboard: Artboard) -> Self {
|
||||
artboard.0
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use core_types::graphene_hash::CacheHash;
|
||||
use core_types::ops::TableConvert;
|
||||
use core_types::list::List;
|
||||
use core_types::ops::ListConvert;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::table::Table;
|
||||
use core_types::uuid::NodeId;
|
||||
use core_types::{ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, Color};
|
||||
use dyn_any::DynAny;
|
||||
@@ -16,45 +16,23 @@ pub use vector_types::Vector;
|
||||
/// The possible forms of graphical content that can be rendered by the Render node into either an image or SVG syntax.
|
||||
#[derive(Clone, Debug, CacheHash, PartialEq, DynAny)]
|
||||
pub enum Graphic {
|
||||
Graphic(Table<Graphic>),
|
||||
Vector(Table<Vector>),
|
||||
RasterCPU(Table<Raster<CPU>>),
|
||||
RasterGPU(Table<Raster<GPU>>),
|
||||
Color(Table<Color>),
|
||||
Gradient(Table<GradientStops>),
|
||||
Graphic(List<Graphic>),
|
||||
Vector(List<Vector>),
|
||||
RasterCPU(List<Raster<CPU>>),
|
||||
RasterGPU(List<Raster<GPU>>),
|
||||
Color(List<Color>),
|
||||
Gradient(List<GradientStops>),
|
||||
}
|
||||
|
||||
impl Default for Graphic {
|
||||
fn default() -> Self {
|
||||
Self::Graphic(Table::new())
|
||||
Self::Graphic(List::new())
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit `Send`/`Sync` impls. All fields are themselves `Send`/`Sync`, so these would normally
|
||||
// be inferred, but the type participates in two mutually recursive cycles through `Table<Graphic>`
|
||||
// and `Table<Vector>` (where `Vector = vector_types::Vector<Option<Table<Graphic>>>`). The second
|
||||
// path, wrapped in `Option<_>` and a generic type parameter, produces a distinct auto-trait
|
||||
// obligation that the solver cannot recognize as the same cycle node, causing
|
||||
// `overflow evaluating the requirement` errors at the workspace's `once_cell::sync::Lazy` statics.
|
||||
// Providing these impls explicitly anchors the proof and lets the coinductive cache close both cycles.
|
||||
//
|
||||
// These can be removed (reverting to auto-derived `Send`/`Sync`) once any of the following holds:
|
||||
// - We remove the TaggedValue or its variants that contain tables.
|
||||
// - The `Vector` alias no longer references `Graphic` through a generic type parameter, breaking
|
||||
// the second cycle so only the direct `Table<Graphic>` self-cycle remains (which the solver
|
||||
// already handles on its own).
|
||||
// - `Graphic` stops containing `Table<Graphic>` directly, e.g. by boxing children through a trait
|
||||
// object or opaque handle so the recursion is no longer structural.
|
||||
// - A future rustc release improves the auto-trait solver to recognize cycles across generic-
|
||||
// parameter substitutions. Try deleting these impls and running:
|
||||
// `cargo check --tests -p graphite-editor`
|
||||
// If no `overflow evaluating the requirement` errors appear, they're no longer needed).
|
||||
unsafe impl Send for Graphic {}
|
||||
unsafe impl Sync for Graphic {}
|
||||
|
||||
// Graphic
|
||||
impl From<Table<Graphic>> for Graphic {
|
||||
fn from(graphic: Table<Graphic>) -> Self {
|
||||
impl From<List<Graphic>> for Graphic {
|
||||
fn from(graphic: List<Graphic>) -> Self {
|
||||
Graphic::Graphic(graphic)
|
||||
}
|
||||
}
|
||||
@@ -62,113 +40,113 @@ impl From<Table<Graphic>> for Graphic {
|
||||
// Vector
|
||||
impl From<Vector> for Graphic {
|
||||
fn from(vector: Vector) -> Self {
|
||||
Graphic::Vector(Table::new_from_element(vector))
|
||||
Graphic::Vector(List::new_from_element(vector))
|
||||
}
|
||||
}
|
||||
impl From<Table<Vector>> for Graphic {
|
||||
fn from(vector: Table<Vector>) -> Self {
|
||||
impl From<List<Vector>> for Graphic {
|
||||
fn from(vector: List<Vector>) -> Self {
|
||||
Graphic::Vector(vector)
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Table<Vector> -> Table<Graphic> conversion handled by blanket impl in gcore
|
||||
// Note: List<Vector> -> List<Graphic> conversion handled by blanket impl in gcore
|
||||
|
||||
// Raster<CPU>
|
||||
impl From<Raster<CPU>> for Graphic {
|
||||
fn from(raster: Raster<CPU>) -> Self {
|
||||
Graphic::RasterCPU(Table::new_from_element(raster))
|
||||
Graphic::RasterCPU(List::new_from_element(raster))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<CPU>>> for Graphic {
|
||||
fn from(raster: Table<Raster<CPU>>) -> Self {
|
||||
impl From<List<Raster<CPU>>> for Graphic {
|
||||
fn from(raster: List<Raster<CPU>>) -> Self {
|
||||
Graphic::RasterCPU(raster)
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
// Note: List conversions handled by blanket impl in gcore
|
||||
|
||||
// Raster<GPU>
|
||||
impl From<Raster<GPU>> for Graphic {
|
||||
fn from(raster: Raster<GPU>) -> Self {
|
||||
Graphic::RasterGPU(Table::new_from_element(raster))
|
||||
Graphic::RasterGPU(List::new_from_element(raster))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<GPU>>> for Graphic {
|
||||
fn from(raster: Table<Raster<GPU>>) -> Self {
|
||||
impl From<List<Raster<GPU>>> for Graphic {
|
||||
fn from(raster: List<Raster<GPU>>) -> Self {
|
||||
Graphic::RasterGPU(raster)
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
// Note: List conversions handled by blanket impl in gcore
|
||||
|
||||
// Color
|
||||
impl From<Color> for Graphic {
|
||||
fn from(color: Color) -> Self {
|
||||
Graphic::Color(Table::new_from_element(color))
|
||||
Graphic::Color(List::new_from_element(color))
|
||||
}
|
||||
}
|
||||
impl From<Table<Color>> for Graphic {
|
||||
fn from(color: Table<Color>) -> Self {
|
||||
impl From<List<Color>> for Graphic {
|
||||
fn from(color: List<Color>) -> Self {
|
||||
Graphic::Color(color)
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
// Note: Table<Color> -> Option<Color> is in gcore (Color is defined there)
|
||||
// Note: List conversions handled by blanket impl in gcore
|
||||
// Note: List<Color> -> Option<Color> is in gcore (Color is defined there)
|
||||
|
||||
// GradientStops
|
||||
impl From<GradientStops> for Graphic {
|
||||
fn from(gradient: GradientStops) -> Self {
|
||||
Graphic::Gradient(Table::new_from_element(gradient))
|
||||
Graphic::Gradient(List::new_from_element(gradient))
|
||||
}
|
||||
}
|
||||
impl From<Table<GradientStops>> for Graphic {
|
||||
fn from(gradient: Table<GradientStops>) -> Self {
|
||||
impl From<List<GradientStops>> for Graphic {
|
||||
fn from(gradient: List<GradientStops>) -> Self {
|
||||
Graphic::Gradient(gradient)
|
||||
}
|
||||
}
|
||||
|
||||
/// Deeply flattens a `Table<Graphic>`, collecting only elements matching a specific variant (extracted by `extract_variant`)
|
||||
/// and discarding all other non-matching content. Recursion through `Graphic::Graphic` sub-`Table`s composes transforms and opacity.
|
||||
fn flatten_graphic_table<T>(content: Table<Graphic>, extract_variant: fn(Graphic) -> Option<Table<T>>) -> Table<T> {
|
||||
fn flatten_recursive<T>(output: &mut Table<T>, current_graphic_table: Table<Graphic>, extract_variant: fn(Graphic) -> Option<Table<T>>) {
|
||||
for current_graphic_row in current_graphic_table.into_iter() {
|
||||
let layer_path: Table<NodeId> = current_graphic_row.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH);
|
||||
/// Deeply flattens a `List<Graphic>`, collecting only elements matching a specific variant (extracted by `extract_variant`)
|
||||
/// and discarding all other non-matching content. Recursion through `Graphic::Graphic` sub-`List`s composes transforms and opacity.
|
||||
fn flatten_graphic_list<T>(content: List<Graphic>, extract_variant: fn(Graphic) -> Option<List<T>>) -> List<T> {
|
||||
fn flatten_recursive<T>(output: &mut List<T>, current_graphic_list: List<Graphic>, extract_variant: fn(Graphic) -> Option<List<T>>) {
|
||||
for current_graphic_row in current_graphic_list.into_iter() {
|
||||
let layer_path: List<NodeId> = current_graphic_row.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH);
|
||||
let current_transform: DAffine2 = current_graphic_row.attribute_cloned_or_default(ATTR_TRANSFORM);
|
||||
let current_opacity: f64 = current_graphic_row.attribute_cloned_or(ATTR_OPACITY, 1.);
|
||||
let current_fill: f64 = current_graphic_row.attribute_cloned_or(ATTR_OPACITY_FILL, 1.);
|
||||
|
||||
match current_graphic_row.into_element() {
|
||||
// Compose the parent's transform, opacity, and fill onto each child row
|
||||
Graphic::Graphic(mut sub_table) => {
|
||||
// Identity default means a missing column still composes correctly
|
||||
for v in sub_table.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
|
||||
Graphic::Graphic(mut sub_list) => {
|
||||
// Identity default means a missing attribute still composes correctly
|
||||
for v in sub_list.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
|
||||
*v = current_transform * *v;
|
||||
}
|
||||
|
||||
// f64 defaults to 0, but opacity/fill default to 1, so missing columns must be set rather than multiplied
|
||||
if let Some(values) = sub_table.iter_attribute_values_mut::<f64>(ATTR_OPACITY) {
|
||||
// f64 defaults to 0, but opacity/fill default to 1, so missing attributes must be set rather than multiplied
|
||||
if let Some(values) = sub_list.iter_attribute_values_mut::<f64>(ATTR_OPACITY) {
|
||||
for v in values {
|
||||
*v *= current_opacity;
|
||||
}
|
||||
} else {
|
||||
for v in sub_table.iter_attribute_values_mut_or_default::<f64>(ATTR_OPACITY) {
|
||||
for v in sub_list.iter_attribute_values_mut_or_default::<f64>(ATTR_OPACITY) {
|
||||
*v = current_opacity;
|
||||
}
|
||||
}
|
||||
if let Some(values) = sub_table.iter_attribute_values_mut::<f64>(ATTR_OPACITY_FILL) {
|
||||
if let Some(values) = sub_list.iter_attribute_values_mut::<f64>(ATTR_OPACITY_FILL) {
|
||||
for v in values {
|
||||
*v *= current_fill;
|
||||
}
|
||||
} else {
|
||||
for v in sub_table.iter_attribute_values_mut_or_default::<f64>(ATTR_OPACITY_FILL) {
|
||||
for v in sub_list.iter_attribute_values_mut_or_default::<f64>(ATTR_OPACITY_FILL) {
|
||||
*v = current_fill;
|
||||
}
|
||||
}
|
||||
|
||||
flatten_recursive(output, sub_table, extract_variant);
|
||||
flatten_recursive(output, sub_list, extract_variant);
|
||||
}
|
||||
// Extract the target variant and push its items with composed transform, opacity, and fill
|
||||
other => {
|
||||
if let Some(typed_table) = extract_variant(other) {
|
||||
for mut item in typed_table.into_iter() {
|
||||
if let Some(typed_list) = extract_variant(other) {
|
||||
for mut item in typed_list.into_iter() {
|
||||
let row_transform: DAffine2 = item.attribute_cloned_or_default(ATTR_TRANSFORM);
|
||||
let row_opacity: f64 = item.attribute_cloned_or(ATTR_OPACITY, 1.);
|
||||
let row_fill: f64 = item.attribute_cloned_or(ATTR_OPACITY_FILL, 1.);
|
||||
@@ -186,100 +164,100 @@ fn flatten_graphic_table<T>(content: Table<Graphic>, extract_variant: fn(Graphic
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = Table::new();
|
||||
let mut output = List::new();
|
||||
flatten_recursive(&mut output, content, extract_variant);
|
||||
output
|
||||
}
|
||||
|
||||
/// Maps from a concrete element type to its corresponding `Graphic` enum variant,
|
||||
/// enabling type-directed casting of typed `Table`s from a `Graphic` value.
|
||||
/// enabling type-directed casting of typed `List`s from a `Graphic` value.
|
||||
pub trait TryFromGraphic: Clone + Sized {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<Table<Self>>;
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>>;
|
||||
}
|
||||
|
||||
impl TryFromGraphic for Vector {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<Table<Self>> {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||
if let Graphic::Vector(t) = graphic { Some(t) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromGraphic for Raster<CPU> {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<Table<Self>> {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||
if let Graphic::RasterCPU(t) = graphic { Some(t) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromGraphic for Color {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<Table<Self>> {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||
if let Graphic::Color(t) = graphic { Some(t) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromGraphic for GradientStops {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<Table<Self>> {
|
||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||
if let Graphic::Gradient(t) = graphic { Some(t) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
// Local trait to convert types to Table<Graphic> (avoids orphan rule issues)
|
||||
pub trait IntoGraphicTable {
|
||||
fn into_graphic_table(self) -> Table<Graphic>;
|
||||
// Local trait to convert types to List<Graphic> (avoids orphan rule issues)
|
||||
pub trait IntoGraphicList {
|
||||
fn into_graphic_list(self) -> List<Graphic>;
|
||||
|
||||
/// Deeply flattens any content of type `T` within a `Table<Graphic>`, discarding all other content, and returning a flat `Table<T>`.
|
||||
fn into_flattened_table<T: TryFromGraphic>(self) -> Table<T>
|
||||
/// Deeply flattens any content of type `T` within a `List<Graphic>`, discarding all other content, and returning a flat `List<T>`.
|
||||
fn into_flattened_list<T: TryFromGraphic>(self) -> List<T>
|
||||
where
|
||||
Self: std::marker::Sized,
|
||||
{
|
||||
flatten_graphic_table(self.into_graphic_table(), T::try_from_graphic)
|
||||
flatten_graphic_list(self.into_graphic_list(), T::try_from_graphic)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Graphic> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
impl IntoGraphicList for List<Graphic> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Vector> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
impl IntoGraphicList for List<Vector> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
// Propagate `editor:layer_path` from item 0 onto the wrapper Graphic row so a subsequent
|
||||
// `flatten_graphic_table` doesn't overwrite the inner Vector's stamp with an empty value
|
||||
let layer_path: Table<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let mut graphic_table = Table::new_from_element(Graphic::Vector(self));
|
||||
// `flatten_graphic_list` doesn't overwrite the inner Vector's stamp with an empty value
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let mut graphic_list = List::new_from_element(Graphic::Vector(self));
|
||||
if !layer_path.is_empty() {
|
||||
graphic_table.set_attribute(ATTR_EDITOR_LAYER_PATH, 0, layer_path);
|
||||
graphic_list.set_attribute(ATTR_EDITOR_LAYER_PATH, 0, layer_path);
|
||||
}
|
||||
graphic_table
|
||||
graphic_list
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Raster<CPU>> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::RasterCPU(self))
|
||||
impl IntoGraphicList for List<Raster<CPU>> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
List::new_from_element(Graphic::RasterCPU(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Raster<GPU>> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::RasterGPU(self))
|
||||
impl IntoGraphicList for List<Raster<GPU>> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
List::new_from_element(Graphic::RasterGPU(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Color> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::Color(self))
|
||||
impl IntoGraphicList for List<Color> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
List::new_from_element(Graphic::Color(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<GradientStops> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::Gradient(self))
|
||||
impl IntoGraphicList for List<GradientStops> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
List::new_from_element(Graphic::Gradient(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for DAffine2 {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::default())
|
||||
impl IntoGraphicList for DAffine2 {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
List::new_from_element(Graphic::default())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,45 +267,45 @@ impl From<DAffine2> for Graphic {
|
||||
Graphic::default()
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
// Note: List conversions handled by blanket impl in gcore
|
||||
|
||||
impl Graphic {
|
||||
pub fn as_graphic(&self) -> Option<&Table<Graphic>> {
|
||||
pub fn as_graphic(&self) -> Option<&List<Graphic>> {
|
||||
match self {
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_graphic_mut(&mut self) -> Option<&mut Table<Graphic>> {
|
||||
pub fn as_graphic_mut(&mut self) -> Option<&mut List<Graphic>> {
|
||||
match self {
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector(&self) -> Option<&Table<Vector>> {
|
||||
pub fn as_vector(&self) -> Option<&List<Vector>> {
|
||||
match self {
|
||||
Graphic::Vector(vector) => Some(vector),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector_mut(&mut self) -> Option<&mut Table<Vector>> {
|
||||
pub fn as_vector_mut(&mut self) -> Option<&mut List<Vector>> {
|
||||
match self {
|
||||
Graphic::Vector(vector) => Some(vector),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster(&self) -> Option<&Table<Raster<CPU>>> {
|
||||
pub fn as_raster(&self) -> Option<&List<Raster<CPU>>> {
|
||||
match self {
|
||||
Graphic::RasterCPU(raster) => Some(raster),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster_mut(&mut self) -> Option<&mut Table<Raster<CPU>>> {
|
||||
pub fn as_raster_mut(&mut self) -> Option<&mut List<Raster<CPU>>> {
|
||||
match self {
|
||||
Graphic::RasterCPU(raster) => Some(raster),
|
||||
_ => None,
|
||||
@@ -335,17 +313,17 @@ impl Graphic {
|
||||
}
|
||||
|
||||
pub fn had_clip_enabled(&self) -> bool {
|
||||
fn all_clipped<T>(table: &Table<T>) -> bool {
|
||||
table.iter_attribute_values_or_default::<bool>(ATTR_CLIPPING_MASK).all(|clip| clip)
|
||||
fn all_clipped<T>(list: &List<T>) -> bool {
|
||||
list.iter_attribute_values_or_default::<bool>(ATTR_CLIPPING_MASK).all(|clip| clip)
|
||||
}
|
||||
|
||||
match self {
|
||||
Graphic::Vector(table) => all_clipped(table),
|
||||
Graphic::Graphic(table) => all_clipped(table),
|
||||
Graphic::RasterCPU(table) => all_clipped(table),
|
||||
Graphic::RasterGPU(table) => all_clipped(table),
|
||||
Graphic::Color(table) => all_clipped(table),
|
||||
Graphic::Gradient(table) => all_clipped(table),
|
||||
Graphic::Vector(list) => all_clipped(list),
|
||||
Graphic::Graphic(list) => all_clipped(list),
|
||||
Graphic::RasterCPU(list) => all_clipped(list),
|
||||
Graphic::RasterGPU(list) => all_clipped(list),
|
||||
Graphic::Color(list) => all_clipped(list),
|
||||
Graphic::Gradient(list) => all_clipped(list),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,12 +342,12 @@ impl Graphic {
|
||||
impl BoundingBox for Graphic {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||
match self {
|
||||
Graphic::Vector(table) => table.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterCPU(table) => table.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterGPU(table) => table.bounding_box(transform, include_stroke),
|
||||
Graphic::Graphic(table) => table.bounding_box(transform, include_stroke),
|
||||
Graphic::Color(table) => table.bounding_box(transform, include_stroke),
|
||||
Graphic::Gradient(table) => table.bounding_box(transform, include_stroke),
|
||||
Graphic::Vector(list) => list.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterCPU(list) => list.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterGPU(list) => list.bounding_box(transform, include_stroke),
|
||||
Graphic::Graphic(list) => list.bounding_box(transform, include_stroke),
|
||||
Graphic::Color(list) => list.bounding_box(transform, include_stroke),
|
||||
Graphic::Gradient(list) => list.bounding_box(transform, include_stroke),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,31 +363,31 @@ impl BoundingBox for Graphic {
|
||||
}
|
||||
}
|
||||
|
||||
impl TableConvert<Graphic> for Vector {
|
||||
impl ListConvert<Graphic> for Vector {
|
||||
fn convert_row(self) -> Graphic {
|
||||
Graphic::Vector(Table::new_from_element(self))
|
||||
Graphic::Vector(List::new_from_element(self))
|
||||
}
|
||||
}
|
||||
impl TableConvert<Graphic> for Raster<CPU> {
|
||||
impl ListConvert<Graphic> for Raster<CPU> {
|
||||
fn convert_row(self) -> Graphic {
|
||||
Graphic::RasterCPU(Table::new_from_element(self))
|
||||
Graphic::RasterCPU(List::new_from_element(self))
|
||||
}
|
||||
}
|
||||
impl TableConvert<Graphic> for Raster<GPU> {
|
||||
impl ListConvert<Graphic> for Raster<GPU> {
|
||||
fn convert_row(self) -> Graphic {
|
||||
Graphic::RasterGPU(Table::new_from_element(self))
|
||||
Graphic::RasterGPU(List::new_from_element(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Graphic {
|
||||
fn render_complexity(&self) -> usize {
|
||||
match self {
|
||||
Self::Graphic(table) => table.render_complexity(),
|
||||
Self::Vector(table) => table.render_complexity(),
|
||||
Self::RasterCPU(table) => table.render_complexity(),
|
||||
Self::RasterGPU(table) => table.render_complexity(),
|
||||
Self::Color(table) => table.render_complexity(),
|
||||
Self::Gradient(table) => table.render_complexity(),
|
||||
Self::Graphic(list) => list.render_complexity(),
|
||||
Self::Vector(list) => list.render_complexity(),
|
||||
Self::RasterCPU(list) => list.render_complexity(),
|
||||
Self::RasterGPU(list) => list.render_complexity(),
|
||||
Self::Color(list) => list.render_complexity(),
|
||||
Self::Gradient(list) => list.render_complexity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,14 +410,14 @@ impl<T: Clone> AtIndex for Vec<T> {
|
||||
if index == 0 || index > self.len() { None } else { self.get(self.len() - index).cloned() }
|
||||
}
|
||||
}
|
||||
impl<T: Clone> AtIndex for Table<T> {
|
||||
type Output = Table<T>;
|
||||
impl<T: Clone> AtIndex for List<T> {
|
||||
type Output = List<T>;
|
||||
|
||||
fn at_index(&self, index: usize) -> Option<Self::Output> {
|
||||
self.clone_item(index).map(|row| {
|
||||
let mut result_table = Self::default();
|
||||
result_table.push(row);
|
||||
result_table
|
||||
let mut result_list = Self::default();
|
||||
result_list.push(row);
|
||||
result_list
|
||||
})
|
||||
}
|
||||
|
||||
@@ -464,7 +442,7 @@ impl<T: Clone> OmitIndex for Vec<T> {
|
||||
self.omit_index(self.len() - index)
|
||||
}
|
||||
}
|
||||
impl<T: Clone> OmitIndex for Table<T> {
|
||||
impl<T: Clone> OmitIndex for List<T> {
|
||||
fn omit_index(&self, index: usize) -> Self {
|
||||
let mut result = Self::default();
|
||||
for i in 0..self.len() {
|
||||
|
||||
@@ -8,7 +8,7 @@ pub use vector_types;
|
||||
|
||||
// Re-export commonly used types at the crate root
|
||||
pub use artboard::Artboard;
|
||||
pub use graphic::{Graphic, IntoGraphicTable, TryFromGraphic, Vector};
|
||||
pub use graphic::{Graphic, IntoGraphicList, TryFromGraphic, Vector};
|
||||
|
||||
pub mod migrations {
|
||||
use vector_types::vector::{PathStyle, PointDomain, RegionDomain, SegmentDomain, misc::HandleId};
|
||||
@@ -16,11 +16,11 @@ pub mod migrations {
|
||||
use crate::Vector;
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
/// Returns the first `Vector` recovered from any of the legacy on-disk shapes (a single `Vector`, the old `OldVectorData` flat struct, or any of the historical `Table<Vector>` variants).
|
||||
/// Returns the first `Vector` recovered from any of the legacy on-disk shapes (a single `Vector`, the old `OldVectorData` flat struct, or any of the historical `List<Vector>` variants).
|
||||
pub fn migrate_to_optional_vector<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Option<Vector>, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Old documents stored a `Vector` flattened with table attributes (`transform`, `alpha_blending`, `upstream_graphic_group`); only the geometry fields are recovered.
|
||||
/// Old documents stored a `Vector` flattened with list attributes (`transform`, `alpha_blending`, `upstream_graphic_group`); only the geometry fields are recovered.
|
||||
#[derive(serde::Deserialize)]
|
||||
struct OldVectorData {
|
||||
style: PathStyle,
|
||||
@@ -42,7 +42,7 @@ pub mod migrations {
|
||||
enum VectorFormat {
|
||||
Vector(Vector),
|
||||
OldVectorData(OldVectorData),
|
||||
Table(LegacyTable),
|
||||
List(LegacyTable),
|
||||
}
|
||||
|
||||
Ok(match VectorFormat::deserialize(deserializer)? {
|
||||
@@ -54,7 +54,7 @@ pub mod migrations {
|
||||
segment_domain: old.segment_domain,
|
||||
region_domain: old.region_domain,
|
||||
}),
|
||||
VectorFormat::Table(table) => table.element.into_iter().next(),
|
||||
VectorFormat::List(list) => list.element.into_iter().next(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ use core_types::blending::BlendMode;
|
||||
use core_types::bounds::BoundingBox;
|
||||
use core_types::bounds::RenderBoundingBox;
|
||||
use core_types::color::Color;
|
||||
use core_types::list::{Item, List};
|
||||
use core_types::math::quad::Quad;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::table::{Item, Table};
|
||||
use core_types::transform::Footprint;
|
||||
use core_types::uuid::{NodeId, generate_uuid};
|
||||
use core_types::{
|
||||
@@ -402,7 +402,7 @@ pub trait Render: BoundingBox + RenderComplexity {
|
||||
/// The upstream click targets for each layer are collected during the render so that they do not have to be calculated for each click detection.
|
||||
fn add_upstream_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
||||
|
||||
/// Like `add_upstream_click_targets` but for visual outlines. `Table<Vector>` overrides this to ignore `editor:click_target` so outlines reflect the actual geometry.
|
||||
/// Like `add_upstream_click_targets` but for visual outlines. `List<Vector>` overrides this to ignore `editor:click_target` so outlines reflect the actual geometry.
|
||||
fn add_upstream_outline_targets(&self, outlines: &mut Vec<ClickTarget>) {
|
||||
self.add_upstream_click_targets(outlines);
|
||||
}
|
||||
@@ -423,23 +423,23 @@ pub trait Render: BoundingBox + RenderComplexity {
|
||||
impl Render for Graphic {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.render_svg(render, render_params),
|
||||
Graphic::Vector(table) => table.render_svg(render, render_params),
|
||||
Graphic::RasterCPU(table) => table.render_svg(render, render_params),
|
||||
Graphic::Graphic(list) => list.render_svg(render, render_params),
|
||||
Graphic::Vector(list) => list.render_svg(render, render_params),
|
||||
Graphic::RasterCPU(list) => list.render_svg(render, render_params),
|
||||
Graphic::RasterGPU(_) => (),
|
||||
Graphic::Color(table) => table.render_svg(render, render_params),
|
||||
Graphic::Gradient(table) => table.render_svg(render, render_params),
|
||||
Graphic::Color(list) => list.render_svg(render, render_params),
|
||||
Graphic::Gradient(list) => list.render_svg(render, render_params),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Vector(table) => table.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::RasterCPU(table) => table.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::RasterGPU(table) => table.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Color(table) => table.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Gradient(table) => table.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Graphic(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Vector(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::RasterCPU(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::RasterGPU(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Color(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Gradient(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,100 +449,100 @@ impl Render for Graphic {
|
||||
Graphic::Graphic(_) => {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
}
|
||||
Graphic::Vector(table) => {
|
||||
Graphic::Vector(list) => {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
// TODO: Find a way to handle more than the first item
|
||||
if !table.is_empty() {
|
||||
let layer_path: Table<NodeId> = table.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
if !list.is_empty() {
|
||||
let layer_path: List<NodeId> = list.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let layer = layer_path.iter_element_values().next_back().copied();
|
||||
let transform: DAffine2 = table.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||
let transform: DAffine2 = list.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||
|
||||
metadata.first_element_source_id.insert(element_id, layer);
|
||||
metadata.local_transforms.insert(element_id, transform);
|
||||
}
|
||||
}
|
||||
Graphic::RasterCPU(table) => {
|
||||
Graphic::RasterCPU(list) => {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
|
||||
// TODO: Find a way to handle more than the first item
|
||||
if !table.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, table.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
if !list.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
}
|
||||
}
|
||||
Graphic::RasterGPU(table) => {
|
||||
Graphic::RasterGPU(list) => {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
|
||||
// TODO: Find a way to handle more than the first item
|
||||
if !table.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, table.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
if !list.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
}
|
||||
}
|
||||
Graphic::Color(table) => {
|
||||
Graphic::Color(list) => {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
|
||||
// TODO: Find a way to handle more than the first item
|
||||
if !table.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, table.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
if !list.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
}
|
||||
}
|
||||
Graphic::Gradient(table) => {
|
||||
Graphic::Gradient(list) => {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
|
||||
// TODO: Find a way to handle more than the first item
|
||||
if !table.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, table.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
if !list.is_empty() {
|
||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::Vector(table) => table.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::RasterCPU(table) => table.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::RasterGPU(table) => table.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::Color(table) => table.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::Gradient(table) => table.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::Graphic(list) => list.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::Vector(list) => list.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::RasterCPU(list) => list.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::RasterGPU(list) => list.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::Color(list) => list.collect_metadata(metadata, footprint, element_id),
|
||||
Graphic::Gradient(list) => list.collect_metadata(metadata, footprint, element_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.add_upstream_click_targets(click_targets),
|
||||
Graphic::Vector(table) => table.add_upstream_click_targets(click_targets),
|
||||
Graphic::RasterCPU(table) => table.add_upstream_click_targets(click_targets),
|
||||
Graphic::RasterGPU(table) => table.add_upstream_click_targets(click_targets),
|
||||
Graphic::Color(table) => table.add_upstream_click_targets(click_targets),
|
||||
Graphic::Gradient(table) => table.add_upstream_click_targets(click_targets),
|
||||
Graphic::Graphic(list) => list.add_upstream_click_targets(click_targets),
|
||||
Graphic::Vector(list) => list.add_upstream_click_targets(click_targets),
|
||||
Graphic::RasterCPU(list) => list.add_upstream_click_targets(click_targets),
|
||||
Graphic::RasterGPU(list) => list.add_upstream_click_targets(click_targets),
|
||||
Graphic::Color(list) => list.add_upstream_click_targets(click_targets),
|
||||
Graphic::Gradient(list) => list.add_upstream_click_targets(click_targets),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_upstream_outline_targets(&self, outlines: &mut Vec<ClickTarget>) {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.add_upstream_outline_targets(outlines),
|
||||
Graphic::Vector(table) => table.add_upstream_outline_targets(outlines),
|
||||
Graphic::RasterCPU(table) => table.add_upstream_outline_targets(outlines),
|
||||
Graphic::RasterGPU(table) => table.add_upstream_outline_targets(outlines),
|
||||
Graphic::Color(table) => table.add_upstream_outline_targets(outlines),
|
||||
Graphic::Gradient(table) => table.add_upstream_outline_targets(outlines),
|
||||
Graphic::Graphic(list) => list.add_upstream_outline_targets(outlines),
|
||||
Graphic::Vector(list) => list.add_upstream_outline_targets(outlines),
|
||||
Graphic::RasterCPU(list) => list.add_upstream_outline_targets(outlines),
|
||||
Graphic::RasterGPU(list) => list.add_upstream_outline_targets(outlines),
|
||||
Graphic::Color(list) => list.add_upstream_outline_targets(outlines),
|
||||
Graphic::Gradient(list) => list.add_upstream_outline_targets(outlines),
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_artboard(&self) -> bool {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.contains_artboard(),
|
||||
Graphic::Vector(table) => table.contains_artboard(),
|
||||
Graphic::RasterCPU(table) => table.contains_artboard(),
|
||||
Graphic::RasterGPU(table) => table.contains_artboard(),
|
||||
Graphic::Color(table) => table.contains_artboard(),
|
||||
Graphic::Gradient(table) => table.contains_artboard(),
|
||||
Graphic::Graphic(list) => list.contains_artboard(),
|
||||
Graphic::Vector(list) => list.contains_artboard(),
|
||||
Graphic::RasterCPU(list) => list.contains_artboard(),
|
||||
Graphic::RasterGPU(list) => list.contains_artboard(),
|
||||
Graphic::Color(list) => list.contains_artboard(),
|
||||
Graphic::Gradient(list) => list.contains_artboard(),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_ids_from_hash(&mut self, reference: Option<NodeId>) {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.new_ids_from_hash(reference),
|
||||
Graphic::Vector(table) => table.new_ids_from_hash(reference),
|
||||
Graphic::Graphic(list) => list.new_ids_from_hash(reference),
|
||||
Graphic::Vector(list) => list.new_ids_from_hash(reference),
|
||||
Graphic::RasterCPU(_) => (),
|
||||
Graphic::RasterGPU(_) => (),
|
||||
Graphic::Color(_) => (),
|
||||
@@ -551,19 +551,19 @@ impl Render for Graphic {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the artboard metadata for the item at `index` from a `Table<Artboard>`.
|
||||
fn read_artboard_attributes(table: &Table<Artboard>, index: usize) -> (DVec2, DVec2, Color, bool) {
|
||||
let location: DVec2 = table.attribute_cloned_or_default(ATTR_LOCATION, index);
|
||||
let dimensions: DVec2 = table.attribute_cloned_or_default(ATTR_DIMENSIONS, index);
|
||||
let background: Color = table.attribute_cloned_or_default(ATTR_BACKGROUND, index);
|
||||
let clip: bool = table.attribute_cloned_or_default(ATTR_CLIP, index);
|
||||
/// Reads the artboard metadata for the item at `index` from a `List<Artboard>`.
|
||||
fn read_artboard_attributes(list: &List<Artboard>, index: usize) -> (DVec2, DVec2, Color, bool) {
|
||||
let location: DVec2 = list.attribute_cloned_or_default(ATTR_LOCATION, index);
|
||||
let dimensions: DVec2 = list.attribute_cloned_or_default(ATTR_DIMENSIONS, index);
|
||||
let background: Color = list.attribute_cloned_or_default(ATTR_BACKGROUND, index);
|
||||
let clip: bool = list.attribute_cloned_or_default(ATTR_CLIP, index);
|
||||
(location, dimensions, background, clip)
|
||||
}
|
||||
|
||||
impl Render for Table<Artboard> {
|
||||
impl Render for List<Artboard> {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
for index in 0..self.len() {
|
||||
let Some(content) = self.element(index).map(Artboard::as_graphic_table) else { continue };
|
||||
let Some(content) = self.element(index).map(Artboard::as_graphic_list) else { continue };
|
||||
let (location, dimensions, background, clip) = read_artboard_attributes(self, index);
|
||||
|
||||
let x = location.x.min(location.x + dimensions.x);
|
||||
@@ -621,7 +621,7 @@ impl Render for Table<Artboard> {
|
||||
use vello::peniko;
|
||||
|
||||
for index in 0..self.len() {
|
||||
let Some(content) = self.element(index).map(Artboard::as_graphic_table) else { continue };
|
||||
let Some(content) = self.element(index).map(Artboard::as_graphic_list) else { continue };
|
||||
let (location, dimensions, background, clip) = read_artboard_attributes(self, index);
|
||||
|
||||
let [a, b] = [location, location + dimensions];
|
||||
@@ -651,10 +651,10 @@ impl Render for Table<Artboard> {
|
||||
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option<NodeId>) {
|
||||
for index in 0..self.len() {
|
||||
let Some(content) = self.element(index).map(Artboard::as_graphic_table) else { continue };
|
||||
let Some(content) = self.element(index).map(Artboard::as_graphic_list) else { continue };
|
||||
let (location, dimensions, _background, clip) = read_artboard_attributes(self, index);
|
||||
|
||||
let layer_path: Table<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let element_id = layer_path.iter_element_values().next_back().copied();
|
||||
|
||||
if let Some(element_id) = element_id {
|
||||
@@ -688,7 +688,7 @@ impl Render for Table<Artboard> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Table<Graphic> {
|
||||
impl Render for List<Graphic> {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
let mut mask_state = None;
|
||||
|
||||
@@ -826,7 +826,7 @@ impl Render for Table<Graphic> {
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) {
|
||||
for index in 0..self.len() {
|
||||
let item_transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, index);
|
||||
let layer_path: Table<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.iter_element_values().next_back().copied();
|
||||
let element = self.element(index).unwrap();
|
||||
|
||||
@@ -908,14 +908,14 @@ impl Render for Table<Graphic> {
|
||||
}
|
||||
|
||||
fn new_ids_from_hash(&mut self, _reference: Option<NodeId>) {
|
||||
let (elements, layers) = self.element_and_attribute_slices_mut::<Table<NodeId>>(ATTR_EDITOR_LAYER_PATH);
|
||||
let (elements, layers) = self.element_and_attribute_slices_mut::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH);
|
||||
for (element, layer) in elements.iter_mut().zip(layers.iter()) {
|
||||
element.new_ids_from_hash(layer.iter_element_values().next_back().copied());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Table<Vector> {
|
||||
impl Render for List<Vector> {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
for index in 0..self.len() {
|
||||
let Some(vector) = self.element(index) else { continue };
|
||||
@@ -987,7 +987,7 @@ impl Render for Table<Vector> {
|
||||
|
||||
// The mask must draw at full alpha so the SVG `<mask>`/`<clipPath>` fully zeroes the path interior.
|
||||
// The wrapping SVG group (above) handles the user-set opacity.
|
||||
let vector_item = Table::new_from_item(Item::new_from_element(cloned_vector).with_attribute(ATTR_TRANSFORM, multiplied_transform));
|
||||
let vector_item = List::new_from_item(Item::new_from_element(cloned_vector).with_attribute(ATTR_TRANSFORM, multiplied_transform));
|
||||
|
||||
(id, mask_type, vector_item)
|
||||
});
|
||||
@@ -1312,7 +1312,7 @@ impl Render for Table<Vector> {
|
||||
|
||||
// The mask must draw at full alpha so `SrcOut` fully zeroes the path interior.
|
||||
// The outer opacity/blend layer (above) handles the user-set opacity.
|
||||
let vector_table = Table::new_from_item(Item::new_from_element(cloned_element).with_attribute(ATTR_TRANSFORM, item_transform));
|
||||
let vector_list = List::new_from_item(Item::new_from_element(cloned_element).with_attribute(ATTR_TRANSFORM, item_transform));
|
||||
|
||||
let bounds = element.bounding_box_with_transform(multiplied_transform).unwrap_or(layer_bounds);
|
||||
// This branch is gated on `can_draw_aligned_stroke`, which already requires every subpath is closed
|
||||
@@ -1330,7 +1330,7 @@ impl Render for Table<Vector> {
|
||||
|
||||
if wants_stroke_below {
|
||||
scene.push_layer(peniko::Fill::NonZero, peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect);
|
||||
vector_table.render_to_vello(scene, parent_transform, _context, &render_params.for_alignment(applied_stroke_transform));
|
||||
vector_list.render_to_vello(scene, parent_transform, _context, &render_params.for_alignment(applied_stroke_transform));
|
||||
scene.push_layer(peniko::Fill::NonZero, peniko::BlendMode::new(peniko::Mix::Normal, compose), 1., kurbo::Affine::IDENTITY, &rect);
|
||||
|
||||
do_stroke(scene, 2.);
|
||||
@@ -1344,7 +1344,7 @@ impl Render for Table<Vector> {
|
||||
do_fill(scene);
|
||||
|
||||
scene.push_layer(peniko::Fill::NonZero, peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect);
|
||||
vector_table.render_to_vello(scene, parent_transform, _context, &render_params.for_alignment(applied_stroke_transform));
|
||||
vector_list.render_to_vello(scene, parent_transform, _context, &render_params.for_alignment(applied_stroke_transform));
|
||||
scene.push_layer(peniko::Fill::NonZero, peniko::BlendMode::new(peniko::Mix::Normal, compose), 1., kurbo::Affine::IDENTITY, &rect);
|
||||
|
||||
do_stroke(scene, 2.);
|
||||
@@ -1382,7 +1382,7 @@ impl Render for Table<Vector> {
|
||||
}
|
||||
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, caller_element_id: Option<NodeId>) {
|
||||
// Aggregate all items' targets per element_id so multi-item tables (e.g. 'Text' node with "Separate Glyphs" active) produce hit areas for every glyph.
|
||||
// Aggregate all items' targets per element_id so multi-item lists (e.g. 'Text' node with "Separate Glyphs" active) produce hit areas for every glyph.
|
||||
// Targets are baked relative to item 0's transform since `Graphic::collect_metadata` records that as `local_transforms[element_id]`.
|
||||
let item_zero_transform: DAffine2 = if !self.is_empty() {
|
||||
self.attribute_cloned_or_default(ATTR_TRANSFORM, 0)
|
||||
@@ -1401,7 +1401,7 @@ impl Render for Table<Vector> {
|
||||
for index in 0..self.len() {
|
||||
let Some(source) = self.element(index) else { continue };
|
||||
let transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, index);
|
||||
let layer_path: Table<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.iter_element_values().next_back().copied();
|
||||
|
||||
if let Some(element_id) = caller_element_id.or(layer) {
|
||||
@@ -1440,7 +1440,7 @@ impl Render for Table<Vector> {
|
||||
// If this item carries a snapshot of upstream graphic content (e.g. it was produced by Boolean Operation,
|
||||
// Flatten Path, Morph, or any other destructive merge), recurse into that snapshot so the editor can
|
||||
// surface the original child layers' click targets.
|
||||
let upstream_nested_layers = self.attribute_cloned_or_default::<Table<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, index);
|
||||
let upstream_nested_layers = self.attribute_cloned_or_default::<List<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, index);
|
||||
if !upstream_nested_layers.is_empty() {
|
||||
let mut upstream_footprint = footprint;
|
||||
upstream_footprint.transform *= transform;
|
||||
@@ -1524,7 +1524,7 @@ fn extend_free_point_targets(vector: &Vector, transform: DAffine2) -> impl Itera
|
||||
})
|
||||
}
|
||||
|
||||
impl Render for Table<Raster<CPU>> {
|
||||
impl Render for List<Raster<CPU>> {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
for index in 0..self.len() {
|
||||
let Some(image) = self.element(index) else { continue };
|
||||
@@ -1673,7 +1673,7 @@ impl Render for Table<Raster<CPU>> {
|
||||
|
||||
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.).into()]);
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
// TODO: Find a way to handle more than one item of the `Table<Raster<...>>`
|
||||
// TODO: Find a way to handle more than one item of the `List<Raster<...>>`
|
||||
if !self.is_empty() {
|
||||
let transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||
metadata.local_transforms.insert(element_id, transform);
|
||||
@@ -1684,7 +1684,7 @@ impl Render for Table<Raster<CPU>> {
|
||||
// The snapshot was captured before Rasterize shifted its input transforms to align with the rasterization
|
||||
// area, so the children are already in the coordinate space matching `footprint` here — we must NOT
|
||||
// multiply in `transform` (which is the rasterization area, not a layer-stack transform).
|
||||
let upstream_nested_layers = self.attribute_cloned_or_default::<Table<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, 0);
|
||||
let upstream_nested_layers = self.attribute_cloned_or_default::<List<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, 0);
|
||||
if !upstream_nested_layers.is_empty() {
|
||||
upstream_nested_layers.collect_metadata(metadata, footprint, None);
|
||||
}
|
||||
@@ -1699,7 +1699,7 @@ impl Render for Table<Raster<CPU>> {
|
||||
|
||||
static LAZY_ARC_VEC_ZERO_U8: LazyLock<Arc<Vec<u8>>> = LazyLock::new(|| Arc::new(Vec::new()));
|
||||
|
||||
impl Render for Table<Raster<GPU>> {
|
||||
impl Render for List<Raster<GPU>> {
|
||||
fn render_svg(&self, _render: &mut SvgRender, _render_params: &RenderParams) {
|
||||
log::warn!("tried to render texture as an svg");
|
||||
}
|
||||
@@ -1768,7 +1768,7 @@ impl Render for Table<Raster<GPU>> {
|
||||
|
||||
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.).into()]);
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
// TODO: Find a way to handle more than one item of the `Table<Raster<...>>`
|
||||
// TODO: Find a way to handle more than one item of the `List<Raster<...>>`
|
||||
if !self.is_empty() {
|
||||
let transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||
metadata.local_transforms.insert(element_id, transform);
|
||||
@@ -1779,7 +1779,7 @@ impl Render for Table<Raster<GPU>> {
|
||||
// The snapshot was captured before Rasterize shifted its input transforms to align with the rasterization
|
||||
// area, so the children are already in the coordinate space matching `footprint` here — we must NOT
|
||||
// multiply in `transform` (which is the rasterization area, not a layer-stack transform).
|
||||
let upstream_nested_layers = self.attribute_cloned_or_default::<Table<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, 0);
|
||||
let upstream_nested_layers = self.attribute_cloned_or_default::<List<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, 0);
|
||||
if !upstream_nested_layers.is_empty() {
|
||||
upstream_nested_layers.collect_metadata(metadata, footprint, None);
|
||||
}
|
||||
@@ -1798,7 +1798,7 @@ impl Render for Table<Raster<GPU>> {
|
||||
// For SVG, this is is achived by creating a truly giant rectangle.
|
||||
// For Vello, we create a layer with a placeholder transform which we
|
||||
// later replace with the current viewport transform before each render.
|
||||
impl Render for Table<Color> {
|
||||
impl Render for List<Color> {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
for (index, color) in self.iter_element_values().enumerate() {
|
||||
let blend_mode: BlendMode = self.attribute_cloned_or_default(ATTR_BLEND_MODE, index);
|
||||
@@ -1858,7 +1858,7 @@ impl Render for Table<Color> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Table<GradientStops> {
|
||||
impl Render for List<GradientStops> {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
// For thumbnails the gradient fills a finite rect at the footprint's document space bounds, with a 1-unit margin to cover the `as u32` truncation of `Footprint::resolution`.
|
||||
// The viewBox crops the overshoot. Canvas rendering keeps the polyline path since Chrome rejects rects larger than ~20 million.
|
||||
@@ -2017,7 +2017,7 @@ impl Render for Table<GradientStops> {
|
||||
let mut layer = false;
|
||||
if opacity < 1. || blend_mode_attr != BlendMode::default() {
|
||||
let blending = peniko::BlendMode::new(blend_mode, peniko::Compose::SrcOver);
|
||||
// See implementation in `Table<Color>` for more detail
|
||||
// See implementation in `List<Color>` for more detail
|
||||
scene.push_layer(peniko::Fill::NonZero, blending, opacity, kurbo::Affine::scale(f64::INFINITY), &rect);
|
||||
layer = true;
|
||||
}
|
||||
|
||||
@@ -539,12 +539,12 @@ pub fn migrate_to_gradient_stops<'de, D: serde::Deserializer<'de>>(deserializer:
|
||||
#[cfg_attr(feature = "serde", serde(untagged))]
|
||||
enum GradientStopsFormat {
|
||||
Stops(GradientStops),
|
||||
Table(LegacyTable),
|
||||
List(LegacyTable),
|
||||
}
|
||||
|
||||
Ok(match GradientStopsFormat::deserialize(deserializer)? {
|
||||
GradientStopsFormat::Stops(stops) => stops,
|
||||
GradientStopsFormat::Table(table) => table.element.into_iter().next().unwrap_or_default(),
|
||||
GradientStopsFormat::List(list) => list.element.into_iter().next().unwrap_or_default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ pub use crate::gradient::*;
|
||||
use core_types::ATTR_OPACITY;
|
||||
use core_types::Color;
|
||||
use core_types::color::Alpha;
|
||||
use core_types::table::Table;
|
||||
use core_types::list::List;
|
||||
use core_types::transform::Transform;
|
||||
use dyn_any::DynAny;
|
||||
use glam::DAffine2;
|
||||
@@ -133,16 +133,16 @@ impl From<Option<Color>> for Fill {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Table<Color>> for Fill {
|
||||
fn from(color: Table<Color>) -> Fill {
|
||||
impl From<List<Color>> for Fill {
|
||||
fn from(color: List<Color>) -> Fill {
|
||||
let alpha: f64 = color.attribute_cloned_or(ATTR_OPACITY, 0, 1.);
|
||||
let color = color.element(0).copied();
|
||||
Fill::solid_or_none(color.map(|c| c.with_alpha(c.alpha() * alpha as f32)))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Table<GradientStops>> for Fill {
|
||||
fn from(gradient: Table<GradientStops>) -> Fill {
|
||||
impl From<List<GradientStops>> for Fill {
|
||||
fn from(gradient: List<GradientStops>) -> Fill {
|
||||
Fill::Gradient(Gradient {
|
||||
stops: gradient.element(0).cloned().unwrap_or_default(),
|
||||
..Default::default()
|
||||
|
||||
@@ -556,7 +556,7 @@ impl RenderComplexity for Vector {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: BoundingBox for Table<Vector> is handled by blanket impl in gcore
|
||||
// Note: BoundingBox for List<Vector> is handled by blanket impl in gcore
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::WgpuContext;
|
||||
use crate::shader_runtime::{FULLSCREEN_VERTEX_SHADER_NAME, ShaderRuntime};
|
||||
use core_types::list::{Item, List};
|
||||
use core_types::shaders::buffer_struct::BufferStruct;
|
||||
use core_types::table::{Item, Table};
|
||||
use futures::lock::Mutex;
|
||||
use raster_types::{GPU, Raster};
|
||||
use std::borrow::Cow;
|
||||
@@ -33,7 +33,7 @@ impl PerPixelAdjustShaderRuntime {
|
||||
}
|
||||
|
||||
impl ShaderRuntime {
|
||||
pub async fn run_per_pixel_adjust<T: BufferStruct>(&self, shaders: &Shaders<'_>, textures: Table<Raster<GPU>>, args: Option<&T>) -> Table<Raster<GPU>> {
|
||||
pub async fn run_per_pixel_adjust<T: BufferStruct>(&self, shaders: &Shaders<'_>, textures: List<Raster<GPU>>, args: Option<&T>) -> List<Raster<GPU>> {
|
||||
let mut cache = self.per_pixel_adjust.pipeline_cache.lock().await;
|
||||
let pipeline = cache
|
||||
.entry(shaders.fragment_shader_name.to_owned())
|
||||
@@ -160,7 +160,7 @@ impl PerPixelAdjustGraphicsPipeline {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dispatch(&self, context: &WgpuContext, textures: Table<Raster<GPU>>, arg_buffer: Option<Buffer>) -> Table<Raster<GPU>> {
|
||||
pub fn dispatch(&self, context: &WgpuContext, textures: List<Raster<GPU>>, arg_buffer: Option<Buffer>) -> List<Raster<GPU>> {
|
||||
assert_eq!(self.has_uniform, arg_buffer.is_some());
|
||||
let device = &context.device;
|
||||
let name = self.name.as_str();
|
||||
@@ -236,7 +236,7 @@ impl PerPixelAdjustGraphicsPipeline {
|
||||
let attributes = textures.clone_item_attributes(index);
|
||||
Item::from_parts(Raster::new(GPU { texture: tex_out }), attributes)
|
||||
})
|
||||
.collect::<Table<_>>();
|
||||
.collect::<List<_>>();
|
||||
context.queue.submit([cmd.finish()]);
|
||||
out
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ use crate::WgpuExecutor;
|
||||
use core_types::Color;
|
||||
use core_types::Ctx;
|
||||
use core_types::color::SRGBA8;
|
||||
use core_types::list::{Item, List};
|
||||
use core_types::ops::Convert;
|
||||
use core_types::table::{Item, Table};
|
||||
use core_types::transform::Footprint;
|
||||
use raster_types::Image;
|
||||
use raster_types::{CPU, GPU, Raster};
|
||||
@@ -137,19 +137,19 @@ impl RasterGpuToRasterCpuConverter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Passthrough conversion for GPU `Table`s - no conversion needed
|
||||
impl<'i> Convert<Table<Raster<GPU>>, &'i WgpuExecutor> for Table<Raster<GPU>> {
|
||||
async fn convert(self, _: Footprint, _converter: &'i WgpuExecutor) -> Table<Raster<GPU>> {
|
||||
/// Passthrough conversion for GPU `List`s - no conversion needed
|
||||
impl<'i> Convert<List<Raster<GPU>>, &'i WgpuExecutor> for List<Raster<GPU>> {
|
||||
async fn convert(self, _: Footprint, _converter: &'i WgpuExecutor) -> List<Raster<GPU>> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `Table<Raster<CPU>>` to `Table<Raster<GPU>>` by uploading each image to a texture
|
||||
impl<'i> Convert<Table<Raster<GPU>>, &'i WgpuExecutor> for Table<Raster<CPU>> {
|
||||
async fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> Table<Raster<GPU>> {
|
||||
/// Converts a `List<Raster<CPU>>` to `List<Raster<GPU>>` by uploading each image to a texture
|
||||
impl<'i> Convert<List<Raster<GPU>>, &'i WgpuExecutor> for List<Raster<CPU>> {
|
||||
async fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> List<Raster<GPU>> {
|
||||
let device = &executor.context.device;
|
||||
let queue = &executor.context.queue;
|
||||
let table = self
|
||||
let list = self
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
let (image, attributes) = row.into_parts();
|
||||
@@ -160,7 +160,7 @@ impl<'i> Convert<Table<Raster<GPU>>, &'i WgpuExecutor> for Table<Raster<CPU>> {
|
||||
.collect();
|
||||
|
||||
queue.submit([]);
|
||||
table
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,16 +176,16 @@ impl<'i> Convert<Raster<GPU>, &'i WgpuExecutor> for Raster<CPU> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Passthrough conversion for CPU `Table`s - no conversion needed
|
||||
impl<'i> Convert<Table<Raster<CPU>>, &'i WgpuExecutor> for Table<Raster<CPU>> {
|
||||
async fn convert(self, _: Footprint, _converter: &'i WgpuExecutor) -> Table<Raster<CPU>> {
|
||||
/// Passthrough conversion for CPU `List`s - no conversion needed
|
||||
impl<'i> Convert<List<Raster<CPU>>, &'i WgpuExecutor> for List<Raster<CPU>> {
|
||||
async fn convert(self, _: Footprint, _converter: &'i WgpuExecutor) -> List<Raster<CPU>> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `Table<Raster<GPU>>` to `Table<Raster<CPU>>` by downloading texture data in one go then asynchronously maps all buffers and processes the results.
|
||||
impl<'i> Convert<Table<Raster<CPU>>, &'i WgpuExecutor> for Table<Raster<GPU>> {
|
||||
async fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> Table<Raster<CPU>> {
|
||||
/// Converts a `List<Raster<GPU>>` to `List<Raster<CPU>>` by downloading texture data in one go then asynchronously maps all buffers and processes the results.
|
||||
impl<'i> Convert<List<Raster<CPU>>, &'i WgpuExecutor> for List<Raster<GPU>> {
|
||||
async fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> List<Raster<CPU>> {
|
||||
let device = &executor.context.device;
|
||||
let queue = &executor.context.queue;
|
||||
|
||||
@@ -245,12 +245,12 @@ impl<'i> Convert<Raster<CPU>, &'i WgpuExecutor> for Raster<GPU> {
|
||||
|
||||
/// Uploads an raster texture from the CPU to the GPU. This is now deprecated and the Convert node should be used in the future.
|
||||
///
|
||||
/// Accepts either individual raster data or a `Table` of raster elements and converts it to the GPU format using the WgpuExecutor's device and queue.
|
||||
/// Accepts either individual raster data or a `List` of raster elements and converts it to the GPU format using the WgpuExecutor's device and queue.
|
||||
#[node_macro::node(category(""))]
|
||||
pub async fn upload_texture<'a: 'n, T: Convert<Table<Raster<GPU>>, &'a WgpuExecutor>>(
|
||||
pub async fn upload_texture<'a: 'n, T: Convert<List<Raster<GPU>>, &'a WgpuExecutor>>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Table<Raster<CPU>>, Table<Raster<GPU>>)] input: T,
|
||||
#[implementations(List<Raster<CPU>>, List<Raster<GPU>>)] input: T,
|
||||
executor: &'a WgpuExecutor,
|
||||
) -> Table<Raster<GPU>> {
|
||||
) -> List<Raster<GPU>> {
|
||||
input.convert(Footprint::DEFAULT, executor).await
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user