mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 05:18:19 +00:00
Improve previewing node data (#1446)
* Improve preview * Improve contrast * Restructure in order to duplicate code * Code review nits --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
c823016316
commit
e0ac073805
18 changed files with 326 additions and 202 deletions
|
@ -204,6 +204,18 @@ impl<'a, T> AsRef<EditorApi<'a, T>> for EditorApi<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Required for the EndLetNode
|
||||
impl<'a, IO> From<EditorApi<'a, IO>> for Footprint {
|
||||
fn from(value: EditorApi<'a, IO>) -> Self {
|
||||
value.render_config.viewport
|
||||
}
|
||||
}
|
||||
|
||||
// Required for the EndLetNode
|
||||
impl<'a, IO> From<EditorApi<'a, IO>> for () {
|
||||
fn from(_value: EditorApi<'a, IO>) -> Self {}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ExtractImageFrame;
|
||||
|
||||
|
|
|
@ -88,6 +88,15 @@ impl SvgRender {
|
|||
self.svg.push("</svg>");
|
||||
}
|
||||
|
||||
/// Wraps the SVG with `<svg><g transform="...">`, which allows for rotation
|
||||
pub fn wrap_with_transform(&mut self, transform: DAffine2) {
|
||||
let defs = &self.svg_defs;
|
||||
|
||||
let svg_header = format!(r#"<svg xmlns="http://www.w3.org/2000/svg"><defs>{defs}</defs><g transform="{}">"#, format_transform_matrix(transform));
|
||||
self.svg.insert(0, svg_header.into());
|
||||
self.svg.push("</g></svg>");
|
||||
}
|
||||
|
||||
pub fn leaf_tag(&mut self, name: impl Into<SvgSegment>, attributes: impl FnOnce(&mut SvgRenderAttrs)) {
|
||||
self.indent();
|
||||
self.svg.push("<");
|
||||
|
@ -97,6 +106,11 @@ impl SvgRender {
|
|||
self.svg.push("/>");
|
||||
}
|
||||
|
||||
pub fn leaf_node(&mut self, content: impl Into<SvgSegment>) {
|
||||
self.indent();
|
||||
self.svg.push(content);
|
||||
}
|
||||
|
||||
pub fn parent_tag(&mut self, name: impl Into<SvgSegment>, attributes: impl FnOnce(&mut SvgRenderAttrs), inner: impl FnOnce(&mut Self)) {
|
||||
let name = name.into();
|
||||
self.indent();
|
||||
|
@ -359,6 +373,55 @@ impl GraphicElementRendered for GraphicElementData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Used to stop rust complaining about upstream traits adding display implementations to `Option<Color>`. This would not be an issue as we control that crate.
|
||||
trait Primitive: core::fmt::Display {}
|
||||
impl Primitive for String {}
|
||||
impl Primitive for bool {}
|
||||
impl Primitive for f32 {}
|
||||
impl Primitive for f64 {}
|
||||
|
||||
fn text_attributes(attributes: &mut SvgRenderAttrs) {
|
||||
attributes.push("fill", "white");
|
||||
attributes.push("y", "30");
|
||||
attributes.push("font-size", "30");
|
||||
}
|
||||
|
||||
impl<T: Primitive> GraphicElementRendered for T {
|
||||
fn render_svg(&self, render: &mut SvgRender, _render_params: &RenderParams) {
|
||||
render.parent_tag("text", text_attributes, |render| render.leaf_node(format!("{self}")));
|
||||
}
|
||||
|
||||
fn bounding_box(&self, _transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||
None
|
||||
}
|
||||
|
||||
fn add_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
||||
}
|
||||
|
||||
impl GraphicElementRendered for Option<Color> {
|
||||
fn render_svg(&self, render: &mut SvgRender, _render_params: &RenderParams) {
|
||||
let Some(color) = self else {
|
||||
render.parent_tag("text", |_| {}, |render| render.leaf_node("Empty color"));
|
||||
return;
|
||||
};
|
||||
|
||||
render.leaf_tag("rect", |attributes| {
|
||||
attributes.push("width", "100");
|
||||
attributes.push("height", "100");
|
||||
attributes.push("y", "40");
|
||||
attributes.push("fill", format!("#{}", color.rgba_hex()));
|
||||
});
|
||||
let color_info = format!("{:?} #{} {:?}", color, color.rgba_hex(), color.to_rgba8_srgb());
|
||||
render.parent_tag("text", text_attributes, |render| render.leaf_node(color_info))
|
||||
}
|
||||
|
||||
fn bounding_box(&self, _transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||
None
|
||||
}
|
||||
|
||||
fn add_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
||||
}
|
||||
|
||||
/// A segment of an svg string to allow for embedding blob urls
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SvgSegment {
|
||||
|
|
|
@ -111,23 +111,24 @@ impl<T> LetNode<T> {
|
|||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct EndLetNode<Input> {
|
||||
pub struct EndLetNode<Input, Parameter> {
|
||||
input: Input,
|
||||
paramenter: PhantomData<Parameter>,
|
||||
}
|
||||
impl<'i, T: 'i, Input> Node<'i, T> for EndLetNode<Input>
|
||||
impl<'i, T: 'i, Parameter: 'i + From<T>, Input> Node<'i, T> for EndLetNode<Input, Parameter>
|
||||
where
|
||||
Input: Node<'i, ()>,
|
||||
Input: Node<'i, Parameter>,
|
||||
{
|
||||
type Output = <Input>::Output;
|
||||
fn eval(&'i self, _: T) -> Self::Output {
|
||||
let result = self.input.eval(());
|
||||
fn eval(&'i self, t: T) -> Self::Output {
|
||||
let result = self.input.eval(Parameter::from(t));
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<Input> EndLetNode<Input> {
|
||||
pub const fn new(input: Input) -> EndLetNode<Input> {
|
||||
EndLetNode { input }
|
||||
impl<Input, Parameter> EndLetNode<Input, Parameter> {
|
||||
pub const fn new(input: Input) -> EndLetNode<Input, Parameter> {
|
||||
EndLetNode { input, paramenter: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ pub struct GenerateBrightnessContrastMapperNode<Brightness, Contrast> {
|
|||
contrast: Contrast,
|
||||
}
|
||||
|
||||
// TODO: Replace this node implementation with one that reuses the more generalized Curves adjustment node.
|
||||
// TODO: It will be necessary to ensure the tests below are faithfully translated in a way that ensures identical results.
|
||||
#[node_macro::node_fn(GenerateBrightnessContrastMapperNode)]
|
||||
fn brightness_contrast_node(_primary: (), brightness: f32, contrast: f32) -> BrightnessContrastMapperNode {
|
||||
// Brightness LUT
|
||||
|
|
|
@ -127,12 +127,12 @@ impl Gradient {
|
|||
|
||||
// Compute the color of the inserted stop
|
||||
let get_color = |index: usize, time: f64| match (self.positions[index].1, self.positions.get(index + 1).and_then(|x| x.1)) {
|
||||
// Lerp between the nearest colours if applicable
|
||||
// Lerp between the nearest colors if applicable
|
||||
(Some(a), Some(b)) => a.lerp(
|
||||
b,
|
||||
((time - self.positions[index].0) / self.positions.get(index + 1).map(|end| end.0 - self.positions[index].0).unwrap_or_default()) as f32,
|
||||
),
|
||||
// Use the start or the end colour if applicable
|
||||
// Use the start or the end color if applicable
|
||||
(Some(v), _) | (_, Some(v)) => v,
|
||||
_ => Color::WHITE,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue