mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Migrate remaining node graph data types from Vec to Table (#4067)
* Move Vec<String> to Table<String> * Remove old VecDVec2 * Move Vec<u8> to Table<u8> * Move Vec<f64> to Table<f64> * Move [f64; 4] to Table<f64> * Move Vec<NodeId> to Table<NodeId> * Tidy up the TaggedValue variants * Move Vec<BrushStroke> to Table<BrushStroke> * Add missing type implementations * Fix tests ---------
This commit is contained in:
@@ -18,22 +18,37 @@ impl CornerRadius for f64 {
|
||||
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_rounded_rectangle(size / -2., size / 2., [clamped_radius; 4])))
|
||||
}
|
||||
}
|
||||
impl CornerRadius for [f64; 4] {
|
||||
impl CornerRadius for Table<f64> {
|
||||
fn generate(self, size: DVec2, clamped: bool) -> Table<Vector> {
|
||||
// Expand to four corners using the CSS `border-radius` shorthand rules.
|
||||
// - `[a]` → `[a, a, a, a]`
|
||||
// - `[a, b]` → `[a, b, a, b]`
|
||||
// - `[a, b, c]` → `[a, b, c, b]`
|
||||
// - `[a, b, c, d, …]` → `[a, b, c, d]`
|
||||
// - `[]` → `[0, 0, 0, 0]`
|
||||
let values: Vec<f64> = self.iter_element_values().copied().collect();
|
||||
let radii: [f64; 4] = match values.as_slice() {
|
||||
[] => [0., 0., 0., 0.],
|
||||
&[a] => [a, a, a, a],
|
||||
&[a, b] => [a, b, a, b],
|
||||
&[a, b, c] => [a, b, c, b],
|
||||
&[a, b, c, d, ..] => [a, b, c, d],
|
||||
};
|
||||
|
||||
let clamped_radius = if clamped {
|
||||
// Algorithm follows the CSS spec: <https://drafts.csswg.org/css-backgrounds/#corner-overlap>
|
||||
|
||||
let mut scale_factor: f64 = 1.;
|
||||
for i in 0..4 {
|
||||
let side_length = if i % 2 == 0 { size.x } else { size.y };
|
||||
let adjacent_corner_radius_sum = self[i] + self[(i + 1) % 4];
|
||||
let adjacent_corner_radius_sum = radii[i] + radii[(i + 1) % 4];
|
||||
if side_length < adjacent_corner_radius_sum {
|
||||
scale_factor = scale_factor.min(side_length / adjacent_corner_radius_sum);
|
||||
}
|
||||
}
|
||||
self.map(|x| x * scale_factor)
|
||||
radii.map(|x| x * scale_factor)
|
||||
} else {
|
||||
self
|
||||
radii
|
||||
};
|
||||
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_rounded_rectangle(size / -2., size / 2., clamped_radius)))
|
||||
}
|
||||
@@ -140,7 +155,7 @@ fn rectangle<T: CornerRadius>(
|
||||
#[default(100)]
|
||||
height: f64,
|
||||
_individual_corner_radii: bool, // TODO: Move this to the bottom once we have a migration capability
|
||||
#[implementations(f64, [f64; 4])] corner_radius: T,
|
||||
#[implementations(f64, Table<f64>)] corner_radius: T,
|
||||
#[default(true)] clamped: bool,
|
||||
) -> Table<Vector> {
|
||||
corner_radius.generate(DVec2::new(width, height), clamped)
|
||||
|
||||
@@ -7,7 +7,7 @@ use vector_types::vector::VectorModification;
|
||||
|
||||
/// Applies a differential modification to a vector path, associating changes made by the Pen and Path tools to indices of edited points and segments.
|
||||
#[node_macro::node(category(""))]
|
||||
async fn path_modify(_ctx: impl Ctx, mut vector: Table<Vector>, modification: Box<VectorModification>, node_path: Vec<NodeId>) -> Table<Vector> {
|
||||
async fn path_modify(_ctx: impl Ctx, mut vector: Table<Vector>, modification: Box<VectorModification>, node_path: Table<NodeId>) -> Table<Vector> {
|
||||
use core_types::table::TableRow;
|
||||
|
||||
if vector.is_empty() {
|
||||
@@ -15,8 +15,11 @@ async fn path_modify(_ctx: impl Ctx, mut vector: Table<Vector>, modification: Bo
|
||||
}
|
||||
modification.apply(vector.element_mut(0).expect("push should give one item"));
|
||||
|
||||
// Update the source node id
|
||||
let this_node_path = node_path.iter().rev().nth(1).copied();
|
||||
// Update the source node id (penultimate element in the path, identifying the user-facing layer node)
|
||||
let this_node_path = {
|
||||
let index = node_path.len().wrapping_sub(2);
|
||||
node_path.element(index).copied()
|
||||
};
|
||||
let existing: Option<NodeId> = vector.attribute_cloned_or_default("editor:layer", 0);
|
||||
vector.set_attribute("editor:layer", 0, existing.or(this_node_path));
|
||||
|
||||
|
||||
@@ -179,9 +179,9 @@ impl IntoF64Vec for f64 {
|
||||
vec![self]
|
||||
}
|
||||
}
|
||||
impl IntoF64Vec for Vec<f64> {
|
||||
impl IntoF64Vec for Table<f64> {
|
||||
fn into_vec(self) -> Vec<f64> {
|
||||
self
|
||||
self.into_iter().map(|row| row.into_element()).collect()
|
||||
}
|
||||
}
|
||||
impl IntoF64Vec for String {
|
||||
@@ -217,7 +217,7 @@ async fn stroke<V, L: IntoF64Vec>(
|
||||
/// The order to paint the stroke on top of the fill, or the fill on top of the stroke.
|
||||
paint_order: PaintOrder,
|
||||
/// The stroke dash lengths. Each length forms a distance in a pattern where the first length is a dash, the second is a gap, and so on. If the list is an odd length, the pattern repeats with solid-gap roles reversed.
|
||||
#[implementations(Vec<f64>, f64, String, Vec<f64>, f64, String)]
|
||||
#[implementations(Table<f64>, f64, String, Table<f64>, f64, String)]
|
||||
dash_lengths: L,
|
||||
/// The phase offset distance from the starting point of the dash pattern.
|
||||
#[unit(" px")]
|
||||
@@ -2850,11 +2850,6 @@ impl<T> Count for Table<T> {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
impl<T> Count for Vec<T> {
|
||||
fn count(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Return u32, u64, or usize instead of f64 after #1621 is resolved and has allowed us to implement automatic type conversion in the node graph for nodes with generic type inputs.
|
||||
// TODO: (Currently automatic type conversion only works for concrete types, via the Graphene preprocessor and not the full Graphene type system.)
|
||||
@@ -2868,9 +2863,10 @@ async fn count_elements<I: Count>(
|
||||
Table<Raster<GPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
Vec<String>,
|
||||
Vec<f64>,
|
||||
Vec<DVec2>,
|
||||
Table<String>,
|
||||
Table<f64>,
|
||||
Table<u8>,
|
||||
Table<NodeId>,
|
||||
)]
|
||||
content: I,
|
||||
) -> f64 {
|
||||
|
||||
Reference in New Issue
Block a user