mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
New node: Rasterize (#1755)
* Add RasterizeVector node * Add document node definition for RasterizeVectorNode * Add dummy node properties * Add prototype of footprint widget * Fix types * Fix footprint widget to use document space * Fix aspect ratio issues by making resolution a multiplier * Fix rebase errors * Fix rasterization bounds and node definition * UI and bug fixes but still issues with scaling in the frame * Rename node to Raster * Fix RasterizeNode * Reenable resolution multiplier * Remove unused variable * UI fixes * Fix Footprint default and resolution updates --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
cf496668fb
commit
c9a33e44bd
7 changed files with 330 additions and 44 deletions
|
|
@ -483,6 +483,70 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
}],
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Rasterize",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(2), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
name: "Create Canvas".to_string(),
|
||||
inputs: vec![NodeInput::network(concrete!(WasmEditorApi), 2)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
|
||||
skip_deduplication: true,
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Rasterize".to_string(),
|
||||
inputs: vec![NodeInput::network(generic!(T), 0), NodeInput::network(concrete!(Footprint), 1), NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RasterizeNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
DocumentInputType {
|
||||
name: "Artwork",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
default: NodeInput::value(TaggedValue::VectorData(VectorData::default()), true),
|
||||
},
|
||||
DocumentInputType {
|
||||
name: "Footprint",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::value(
|
||||
TaggedValue::Footprint(Footprint {
|
||||
transform: DAffine2::from_scale_angle_translation(DVec2::new(100., 100.), 0., DVec2::new(0., 0.)),
|
||||
resolution: UVec2::new(100, 100),
|
||||
..Default::default()
|
||||
}),
|
||||
false,
|
||||
),
|
||||
},
|
||||
DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::network(concrete!(WasmEditorApi), 0),
|
||||
},
|
||||
],
|
||||
properties: node_properties::rasterize_properties,
|
||||
outputs: vec![DocumentOutputType {
|
||||
name: "Canvas",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
}],
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
// This essentially builds the concept of a closure where we store variables (`let` bindings) so they can be accessed within this scope.
|
||||
name: "Begin Scope",
|
||||
|
|
@ -720,7 +784,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||
DocumentNodeDefinition {
|
||||
name: "Mask",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::MaskImageNode<_, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -733,7 +797,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||
DocumentNodeDefinition {
|
||||
name: "Insert Channel",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::InsertChannelNode<_, _, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -747,7 +811,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||
DocumentNodeDefinition {
|
||||
name: "Combine Channels",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::CombineChannelsNode"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("None", TaggedValue::None, false),
|
||||
|
|
@ -765,7 +829,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||
DocumentNodeDefinition {
|
||||
name: "Blend",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::BlendNode<_, _, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -779,7 +843,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Levels",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::LevelsNode<_, _, _, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType {
|
||||
|
|
@ -819,7 +883,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Black & White",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::BlackAndWhiteNode<_, _, _, _, _, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType {
|
||||
|
|
@ -869,7 +933,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Color Channel",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::ops::IdentityNode"),
|
||||
inputs: vec![DocumentInputType::value("Channel", TaggedValue::RedGreenBlue(RedGreenBlue::Red), false)],
|
||||
outputs: vec![DocumentOutputType::new("Out", FrontendGraphDataType::General)],
|
||||
|
|
@ -887,7 +951,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Luminance",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::LuminanceNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -899,7 +963,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Extract Channel",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::ExtractChannelNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -911,7 +975,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Extract Opaque",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::ExtractOpaqueNode<>"),
|
||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
|
|
@ -919,7 +983,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Split Channels",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![
|
||||
NodeInput::node(NodeId(0), 0),
|
||||
|
|
@ -1584,7 +1648,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
#[cfg(feature = "gpu")]
|
||||
DocumentNodeDefinition {
|
||||
name: "GpuImage",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1605,7 +1669,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
#[cfg(feature = "gpu")]
|
||||
DocumentNodeDefinition {
|
||||
name: "Blend (GPU)",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::executor::BlendGpuImageNode<_, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1699,7 +1763,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Invert RGB",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::InvertRGBNode"),
|
||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
|
|
@ -1707,7 +1771,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Hue/Saturation",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::HueSaturationNode<_, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1721,7 +1785,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Brightness/Contrast",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::BrightnessContrastNode<_, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1735,7 +1799,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Curves",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::CurvesNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1747,7 +1811,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Threshold",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::ThresholdNode<_, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1761,7 +1825,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Vibrance",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::VibranceNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1773,7 +1837,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Channel Mixer",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::ChannelMixerNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1808,7 +1872,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Selective Color",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto(
|
||||
"graphene_core::raster::SelectiveColorNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>",
|
||||
),
|
||||
|
|
@ -1870,7 +1934,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Opacity",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::OpacityNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1882,7 +1946,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Blend Mode",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::BlendModeNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1894,7 +1958,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Posterize",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::PosterizeNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -1906,7 +1970,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Exposure",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::ExposureNode<_, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -2645,7 +2709,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||
DocumentNodeDefinition {
|
||||
name: "Image Segmentation",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::image_segmentation::ImageSegmentationNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -2656,7 +2720,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Index",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::IndexNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Segmentation", TaggedValue::Segments(vec![ImageFrame::empty()]), true),
|
||||
|
|
@ -2669,7 +2733,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
// Applies the given color to each pixel of an image but maintains the alpha value
|
||||
DocumentNodeDefinition {
|
||||
name: "Color Fill",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::adjustments::ColorFillNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -2681,7 +2745,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Color Overlay",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::raster::adjustments::ColorOverlayNode<_, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
@ -2695,7 +2759,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Image Color Palette",
|
||||
category: "Image Adjustments",
|
||||
category: "Raster",
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::image_color_palette::ImageColorPaletteNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ use graphene_core::vector::misc::CentroidType;
|
|||
use graphene_core::vector::style::{GradientType, LineCap, LineJoin};
|
||||
use graphene_std::vector::style::{Fill, FillChoice};
|
||||
|
||||
use glam::{DVec2, IVec2, UVec2};
|
||||
use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::misc::BooleanOperation;
|
||||
|
||||
pub fn string_properties(text: impl Into<String>) -> Vec<LayoutGroup> {
|
||||
|
|
@ -137,6 +138,148 @@ fn bool_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||
widgets
|
||||
}
|
||||
|
||||
fn footprint_widget(document_node: &DocumentNode, node_id: NodeId, index: usize) -> Vec<LayoutGroup> {
|
||||
let mut location_widgets = start_widgets(document_node, node_id, index, "Footprint", FrontendGraphDataType::General, true);
|
||||
location_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
|
||||
let mut scale_widgets = vec![TextLabel::new("").widget_holder()];
|
||||
add_blank_assist(&mut scale_widgets);
|
||||
scale_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
|
||||
let mut resolution_widgets = vec![TextLabel::new("").widget_holder()];
|
||||
add_blank_assist(&mut resolution_widgets);
|
||||
resolution_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
|
||||
if let NodeInput::Value {
|
||||
tagged_value: TaggedValue::Footprint(footprint),
|
||||
exposed: false,
|
||||
} = &document_node.inputs[index]
|
||||
{
|
||||
let footprint = *footprint;
|
||||
let top_left = footprint.transform.transform_point2(DVec2::ZERO);
|
||||
let bounds = footprint.scale();
|
||||
let oversample = footprint.resolution.as_dvec2() / bounds;
|
||||
|
||||
location_widgets.extend_from_slice(&[
|
||||
NumberInput::new(Some(top_left.x))
|
||||
.label("X")
|
||||
.unit(" px")
|
||||
.on_update(update_value(
|
||||
move |x: &NumberInput| {
|
||||
let (offset, scale) = (move |x: f64| -> (DVec2, DVec2) {
|
||||
let diff = DVec2::new(top_left.x - x, 0.);
|
||||
(top_left - diff, bounds)
|
||||
})(x.value.unwrap_or_default());
|
||||
|
||||
let footprint = Footprint {
|
||||
transform: DAffine2::from_scale_angle_translation(scale.into(), 0., offset.into()),
|
||||
resolution: (oversample * scale).as_uvec2(),
|
||||
..footprint
|
||||
};
|
||||
|
||||
TaggedValue::Footprint(footprint)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(top_left.y))
|
||||
.label("Y")
|
||||
.unit(" px")
|
||||
.on_update(update_value(
|
||||
move |x: &NumberInput| {
|
||||
let (offset, scale) = (move |y: f64| -> (DVec2, DVec2) {
|
||||
let diff = DVec2::new(0., top_left.y - y);
|
||||
(top_left - diff, bounds)
|
||||
})(x.value.unwrap_or_default());
|
||||
|
||||
let footprint = Footprint {
|
||||
transform: DAffine2::from_scale_angle_translation(scale.into(), 0., offset.into()),
|
||||
resolution: (oversample * scale).as_uvec2(),
|
||||
..footprint
|
||||
};
|
||||
|
||||
TaggedValue::Footprint(footprint)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
]);
|
||||
|
||||
scale_widgets.extend_from_slice(&[
|
||||
NumberInput::new(Some(bounds.x))
|
||||
.label("W")
|
||||
.unit(" px")
|
||||
.on_update(update_value(
|
||||
move |x: &NumberInput| {
|
||||
let (offset, scale) = (move |x: f64| -> (DVec2, DVec2) { (top_left, DVec2::new(x, bounds.y)) })(x.value.unwrap_or_default());
|
||||
|
||||
let footprint = Footprint {
|
||||
transform: DAffine2::from_scale_angle_translation(scale.into(), 0., offset.into()),
|
||||
resolution: (oversample * scale).as_uvec2(),
|
||||
..footprint
|
||||
};
|
||||
|
||||
TaggedValue::Footprint(footprint)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(bounds.y))
|
||||
.label("H")
|
||||
.unit(" px")
|
||||
.on_update(update_value(
|
||||
move |x: &NumberInput| {
|
||||
let (offset, scale) = (move |y: f64| -> (DVec2, DVec2) { (top_left, DVec2::new(bounds.x, y)) })(x.value.unwrap_or_default());
|
||||
|
||||
let footprint = Footprint {
|
||||
transform: DAffine2::from_scale_angle_translation(scale.into(), 0., offset.into()),
|
||||
resolution: (oversample * scale).as_uvec2(),
|
||||
..footprint
|
||||
};
|
||||
|
||||
TaggedValue::Footprint(footprint)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
]);
|
||||
|
||||
resolution_widgets.push(
|
||||
NumberInput::new(Some((footprint.resolution.as_dvec2() / bounds).x as f64 * 100.))
|
||||
.label("Resolution")
|
||||
.unit("%")
|
||||
.on_update(update_value(
|
||||
move |x: &NumberInput| {
|
||||
let resolution = (bounds * x.value.unwrap_or(100.) / 100.).as_uvec2().max((1, 1).into()).min((4000, 4000).into());
|
||||
|
||||
let footprint = Footprint { resolution, ..footprint };
|
||||
TaggedValue::Footprint(footprint)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
);
|
||||
}
|
||||
|
||||
vec![
|
||||
LayoutGroup::Row { widgets: location_widgets },
|
||||
LayoutGroup::Row { widgets: scale_widgets },
|
||||
LayoutGroup::Row { widgets: resolution_widgets },
|
||||
]
|
||||
}
|
||||
|
||||
fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, x: &str, y: &str, unit: &str, min: Option<f64>, mut assist: impl FnMut(&mut Vec<WidgetHolder>)) -> LayoutGroup {
|
||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Number, false);
|
||||
|
||||
|
|
@ -1640,6 +1783,9 @@ pub fn transform_properties(document_node: &DocumentNode, node_id: NodeId, _cont
|
|||
|
||||
vec![translation, rotation, scale]
|
||||
}
|
||||
pub fn rasterize_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
footprint_widget(document_node, node_id, 1)
|
||||
}
|
||||
|
||||
pub fn node_section_font(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let text = text_area_widget(document_node, node_id, 1, "Text", true);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue