mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
New node: Pointer Position (#3535)
* New node: Pointer Position * Fix test
This commit is contained in:
@@ -57,7 +57,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc<WasmEdito
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::create_context::IDENTIFIER),
|
||||
context_features: graphene_std::ContextDependencies {
|
||||
extract: ContextFeatures::empty(),
|
||||
inject: ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME | ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
||||
inject: ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME | ContextFeatures::POINTER | ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
@@ -239,6 +239,7 @@ pub struct RenderConfig {
|
||||
pub scale: f64,
|
||||
pub export_format: ExportFormat,
|
||||
pub time: TimingInformation,
|
||||
pub pointer: DVec2,
|
||||
#[serde(alias = "view_mode")]
|
||||
pub render_mode: RenderMode,
|
||||
pub hide_artboards: bool,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::transform::Footprint;
|
||||
use glam::DVec2;
|
||||
pub use no_std_types::context::{ArcCtx, Ctx};
|
||||
use std::any::Any;
|
||||
use std::borrow::Borrow;
|
||||
@@ -26,6 +27,10 @@ pub trait ExtractAnimationTime {
|
||||
fn try_animation_time(&self) -> Option<f64>;
|
||||
}
|
||||
|
||||
pub trait ExtractPointer {
|
||||
fn try_pointer(&self) -> Option<DVec2>;
|
||||
}
|
||||
|
||||
pub trait ExtractIndex {
|
||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>>;
|
||||
}
|
||||
@@ -47,6 +52,7 @@ pub trait CloneVarArgs: ExtractVarArgs {
|
||||
pub trait InjectFootprint {}
|
||||
pub trait InjectRealTime {}
|
||||
pub trait InjectAnimationTime {}
|
||||
pub trait InjectPointer {}
|
||||
pub trait InjectIndex {}
|
||||
pub trait InjectVarArgs {}
|
||||
|
||||
@@ -54,23 +60,26 @@ pub trait InjectVarArgs {}
|
||||
pub trait ModifyFootprint: ExtractFootprint + InjectFootprint {}
|
||||
pub trait ModifyRealTime: ExtractRealTime + InjectRealTime {}
|
||||
pub trait ModifyAnimationTime: ExtractAnimationTime + InjectAnimationTime {}
|
||||
pub trait ModifyPointer: ExtractPointer + InjectPointer {}
|
||||
pub trait ModifyIndex: ExtractIndex + InjectIndex {}
|
||||
pub trait ModifyVarArgs: ExtractVarArgs + InjectVarArgs {}
|
||||
|
||||
pub trait ExtractAll: ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractVarArgs {}
|
||||
pub trait ExtractAll: ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractPointer + ExtractVarArgs {}
|
||||
|
||||
impl<T: ?Sized + ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractVarArgs> ExtractAll for T {}
|
||||
impl<T: ?Sized + ExtractFootprint + ExtractIndex + ExtractRealTime + ExtractAnimationTime + ExtractPointer + ExtractVarArgs> ExtractAll for T {}
|
||||
|
||||
impl<T: Ctx> InjectFootprint for T {}
|
||||
impl<T: Ctx> InjectRealTime for T {}
|
||||
impl<T: Ctx> InjectIndex for T {}
|
||||
impl<T: Ctx> InjectAnimationTime for T {}
|
||||
impl<T: Ctx> InjectPointer for T {}
|
||||
impl<T: Ctx> InjectVarArgs for T {}
|
||||
|
||||
impl<T: Ctx + InjectFootprint + ExtractFootprint> ModifyFootprint for T {}
|
||||
impl<T: Ctx + InjectRealTime + ExtractRealTime> ModifyRealTime for T {}
|
||||
impl<T: Ctx + InjectIndex + ExtractIndex> ModifyIndex for T {}
|
||||
impl<T: Ctx + InjectAnimationTime + ExtractAnimationTime> ModifyAnimationTime for T {}
|
||||
impl<T: Ctx + InjectPointer + ExtractPointer> ModifyPointer for T {}
|
||||
impl<T: Ctx + InjectVarArgs + ExtractVarArgs> ModifyVarArgs for T {}
|
||||
|
||||
// Public enum for flexible node macro codegen
|
||||
@@ -79,11 +88,13 @@ pub enum ContextFeature {
|
||||
ExtractFootprint,
|
||||
ExtractRealTime,
|
||||
ExtractAnimationTime,
|
||||
ExtractPointer,
|
||||
ExtractIndex,
|
||||
ExtractVarArgs,
|
||||
InjectFootprint,
|
||||
InjectRealTime,
|
||||
InjectAnimationTime,
|
||||
InjectPointer,
|
||||
InjectIndex,
|
||||
InjectVarArgs,
|
||||
}
|
||||
@@ -96,8 +107,9 @@ bitflags! {
|
||||
const FOOTPRINT = 1 << 0;
|
||||
const REAL_TIME = 1 << 1;
|
||||
const ANIMATION_TIME = 1 << 2;
|
||||
const INDEX = 1 << 3;
|
||||
const VARARGS = 1 << 4;
|
||||
const POINTER = 1 << 3;
|
||||
const INDEX = 1 << 4;
|
||||
const VARARGS = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +128,7 @@ impl From<&[ContextFeature]> for ContextDependencies {
|
||||
ContextFeature::ExtractFootprint => ContextFeatures::FOOTPRINT,
|
||||
ContextFeature::ExtractRealTime => ContextFeatures::REAL_TIME,
|
||||
ContextFeature::ExtractAnimationTime => ContextFeatures::ANIMATION_TIME,
|
||||
ContextFeature::ExtractPointer => ContextFeatures::POINTER,
|
||||
ContextFeature::ExtractIndex => ContextFeatures::INDEX,
|
||||
ContextFeature::ExtractVarArgs => ContextFeatures::VARARGS,
|
||||
_ => ContextFeatures::empty(),
|
||||
@@ -124,6 +137,7 @@ impl From<&[ContextFeature]> for ContextDependencies {
|
||||
ContextFeature::InjectFootprint => ContextFeatures::FOOTPRINT,
|
||||
ContextFeature::InjectRealTime => ContextFeatures::REAL_TIME,
|
||||
ContextFeature::InjectAnimationTime => ContextFeatures::ANIMATION_TIME,
|
||||
ContextFeature::InjectPointer => ContextFeatures::POINTER,
|
||||
ContextFeature::InjectIndex => ContextFeatures::INDEX,
|
||||
ContextFeature::InjectVarArgs => ContextFeatures::VARARGS,
|
||||
_ => ContextFeatures::empty(),
|
||||
@@ -174,6 +188,11 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Option<T> {
|
||||
self.as_ref().and_then(|x| x.try_animation_time())
|
||||
}
|
||||
}
|
||||
impl<T: ExtractPointer + Sync> ExtractPointer for Option<T> {
|
||||
fn try_pointer(&self) -> Option<DVec2> {
|
||||
self.as_ref().and_then(|x| x.try_pointer())
|
||||
}
|
||||
}
|
||||
impl<T: ExtractIndex> ExtractIndex for Option<T> {
|
||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
||||
self.as_ref().and_then(|x| x.try_index())
|
||||
@@ -211,6 +230,11 @@ impl<T: ExtractAnimationTime + Sync> ExtractAnimationTime for Arc<T> {
|
||||
(**self).try_animation_time()
|
||||
}
|
||||
}
|
||||
impl<T: ExtractPointer + Sync> ExtractPointer for Arc<T> {
|
||||
fn try_pointer(&self) -> Option<DVec2> {
|
||||
(**self).try_pointer()
|
||||
}
|
||||
}
|
||||
impl<T: ExtractIndex> ExtractIndex for Arc<T> {
|
||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
||||
(**self).try_index()
|
||||
@@ -303,6 +327,11 @@ impl ExtractAnimationTime for OwnedContextImpl {
|
||||
self.animation_time
|
||||
}
|
||||
}
|
||||
impl ExtractPointer for OwnedContextImpl {
|
||||
fn try_pointer(&self) -> Option<DVec2> {
|
||||
self.pointer
|
||||
}
|
||||
}
|
||||
impl ExtractIndex for OwnedContextImpl {
|
||||
fn try_index(&self) -> Option<impl Iterator<Item = usize>> {
|
||||
self.index.clone().map(|x| x.into_iter().rev())
|
||||
@@ -363,6 +392,7 @@ pub struct OwnedContextImpl {
|
||||
index: Option<Vec<usize>>,
|
||||
real_time: Option<f64>,
|
||||
animation_time: Option<f64>,
|
||||
pointer: Option<DVec2>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for OwnedContextImpl {
|
||||
@@ -374,6 +404,7 @@ impl std::fmt::Debug for OwnedContextImpl {
|
||||
.field("index", &self.index)
|
||||
.field("real_time", &self.real_time)
|
||||
.field("animation_time", &self.animation_time)
|
||||
.field("pointer", &self.pointer)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -392,6 +423,7 @@ impl Hash for OwnedContextImpl {
|
||||
self.index.hash(state);
|
||||
self.real_time.map(|x| x.to_bits()).hash(state);
|
||||
self.animation_time.map(|x| x.to_bits()).hash(state);
|
||||
self.pointer.map(|v| (v.x.to_bits(), v.y.to_bits())).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,12 +432,14 @@ impl OwnedContextImpl {
|
||||
pub fn from<T: ExtractAll + CloneVarArgs>(value: T) -> Self {
|
||||
OwnedContextImpl::from_flags(value, ContextFeatures::all())
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn from_flags<T: ExtractAll + CloneVarArgs>(value: T, bitflags: ContextFeatures) -> Self {
|
||||
let footprint = bitflags.contains(ContextFeatures::FOOTPRINT).then(|| value.try_footprint().copied()).flatten();
|
||||
let index = bitflags.contains(ContextFeatures::INDEX).then(|| value.try_index()).flatten();
|
||||
let real_time = bitflags.contains(ContextFeatures::REAL_TIME).then(|| value.try_real_time()).flatten();
|
||||
let animation_time = bitflags.contains(ContextFeatures::ANIMATION_TIME).then(|| value.try_animation_time()).flatten();
|
||||
let pointer = bitflags.contains(ContextFeatures::POINTER).then(|| value.try_pointer()).flatten();
|
||||
let parent = bitflags
|
||||
.contains(ContextFeatures::VARARGS)
|
||||
.then(|| match value.varargs_len() {
|
||||
@@ -421,8 +455,10 @@ impl OwnedContextImpl {
|
||||
index: index.map(|x| x.collect()),
|
||||
real_time,
|
||||
animation_time,
|
||||
pointer,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn empty() -> Self {
|
||||
OwnedContextImpl {
|
||||
footprint: None,
|
||||
@@ -431,6 +467,7 @@ impl OwnedContextImpl {
|
||||
index: None,
|
||||
real_time: None,
|
||||
animation_time: None,
|
||||
pointer: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -475,6 +512,10 @@ impl OwnedContextImpl {
|
||||
self.animation_time = Some(animation_time);
|
||||
self
|
||||
}
|
||||
pub fn with_pointer(mut self, pointer: DVec2) -> Self {
|
||||
self.pointer = Some(pointer);
|
||||
self
|
||||
}
|
||||
pub fn with_vararg(mut self, value: Box<dyn AnyHash + Send + Sync>) -> Self {
|
||||
assert!(self.varargs.is_none_or(|value| value.is_empty()));
|
||||
self.varargs = Some(Arc::new([value]));
|
||||
|
||||
@@ -1112,11 +1112,11 @@ impl<Upstream> Vector<Upstream> {
|
||||
for neighbors in &mut adjacency {
|
||||
neighbors.sort_by(|a, b| {
|
||||
let angle = [a, b].map(|side| {
|
||||
let curve = PathSeg::from(self.path_segment_from_index(
|
||||
let curve = self.path_segment_from_index(
|
||||
self.segment_domain.start_point[side.segment_index],
|
||||
self.segment_domain.end_point[side.segment_index],
|
||||
self.segment_domain.handles[side.segment_index],
|
||||
));
|
||||
);
|
||||
let curve = if side.reversed { curve.reverse() } else { curve };
|
||||
let tangent = curve.tangent_at_start();
|
||||
tangent.y.atan2(tangent.x)
|
||||
@@ -1140,20 +1140,19 @@ impl<Upstream> Vector<Upstream> {
|
||||
}
|
||||
}
|
||||
|
||||
return FaceIterator::new(faces, self);
|
||||
FaceIterator::new(faces, self)
|
||||
}
|
||||
|
||||
fn construct_face(&self, adjacency: &Vec<Vec<FaceSide>>, first: FaceSide, faces: &mut Faces, seen: &mut FaceSideSet) -> Option<()> {
|
||||
fn construct_face(&self, adjacency: &[Vec<FaceSide>], first: FaceSide, faces: &mut Faces, seen: &mut FaceSideSet) -> Option<()> {
|
||||
faces.start_new_face();
|
||||
let max_iterations = self.segment_domain.id.len() * 2;
|
||||
let mut side = first;
|
||||
for _iteration in 1..max_iterations {
|
||||
if seen.contains(side) {
|
||||
log::debug!("Encountered seen side {:?}, aborting face construction", side);
|
||||
return None;
|
||||
}
|
||||
seen.insert(side);
|
||||
faces.add_side(side.clone());
|
||||
faces.add_side(side);
|
||||
let next_vertex = if side.reversed {
|
||||
self.segment_domain.start_point[side.segment_index]
|
||||
} else {
|
||||
|
||||
@@ -414,11 +414,13 @@ fn parse_context_feature_idents(ty: &Type) -> Vec<Ident> {
|
||||
"ExtractFootprint"
|
||||
| "ExtractRealTime"
|
||||
| "ExtractAnimationTime"
|
||||
| "ExtractPointer"
|
||||
| "ExtractIndex"
|
||||
| "ExtractVarArgs"
|
||||
| "InjectFootprint"
|
||||
| "InjectRealTime"
|
||||
| "InjectAnimationTime"
|
||||
| "InjectPointer"
|
||||
| "InjectIndex"
|
||||
| "InjectVarArgs" => {
|
||||
features.push(segment.ident.clone());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use core_types::{Ctx, ExtractAnimationTime, ExtractRealTime};
|
||||
use core_types::{Ctx, ExtractAnimationTime, ExtractPointer, ExtractRealTime};
|
||||
use glam::DVec2;
|
||||
|
||||
const DAY: f64 = 1000. * 3600. * 24.;
|
||||
|
||||
@@ -47,6 +48,12 @@ fn animation_time(ctx: impl Ctx + ExtractAnimationTime) -> f64 {
|
||||
ctx.try_animation_time().unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Produces the current position of the user's pointer within the document canvas.
|
||||
#[node_macro::node(category("Animation"))]
|
||||
fn pointer_position(ctx: impl Ctx + ExtractPointer) -> DVec2 {
|
||||
ctx.try_pointer().unwrap_or_default()
|
||||
}
|
||||
|
||||
// TODO: These nodes require more sophisticated algorithms for giving the correct result
|
||||
// #[node_macro::node(category("Animation"))]
|
||||
// fn month(ctx: impl Ctx + ExtractRealTime) -> f64 {
|
||||
|
||||
@@ -113,6 +113,7 @@ async fn create_context<'a: 'n>(
|
||||
.with_footprint(footprint)
|
||||
.with_real_time(render_config.time.time)
|
||||
.with_animation_time(render_config.time.animation_time.as_secs_f64())
|
||||
.with_pointer(render_config.pointer)
|
||||
.with_vararg(Box::new(render_params))
|
||||
.into_context();
|
||||
|
||||
|
||||
@@ -471,12 +471,41 @@ fn ceiling<T: num_traits::float::Float>(
|
||||
value.ceil()
|
||||
}
|
||||
|
||||
trait AbsoluteValue {
|
||||
fn abs(self) -> Self;
|
||||
}
|
||||
impl AbsoluteValue for DVec2 {
|
||||
fn abs(self) -> Self {
|
||||
DVec2::new(self.x.abs(), self.y.abs())
|
||||
}
|
||||
}
|
||||
impl AbsoluteValue for f32 {
|
||||
fn abs(self) -> Self {
|
||||
self.abs()
|
||||
}
|
||||
}
|
||||
impl AbsoluteValue for f64 {
|
||||
fn abs(self) -> Self {
|
||||
self.abs()
|
||||
}
|
||||
}
|
||||
impl AbsoluteValue for i32 {
|
||||
fn abs(self) -> Self {
|
||||
self.abs()
|
||||
}
|
||||
}
|
||||
impl AbsoluteValue for i64 {
|
||||
fn abs(self) -> Self {
|
||||
self.abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// The absolute value function (`abs`) removes the negative sign from an input value, if present.
|
||||
#[node_macro::node(category("Math: Numeric"))]
|
||||
fn absolute_value<T: num_traits::sign::Signed>(
|
||||
fn absolute_value<T: AbsoluteValue>(
|
||||
_: impl Ctx,
|
||||
/// The number to be made positive.
|
||||
#[implementations(f64, f32, i32, i64)]
|
||||
#[implementations(f64, f32, i32, i64, DVec2)]
|
||||
value: T,
|
||||
) -> T {
|
||||
value.abs()
|
||||
|
||||
Reference in New Issue
Block a user