From 0c912fcca7afb9e837d0e8949b776288e8a585a2 Mon Sep 17 00:00:00 2001 From: Victor Date: Sat, 16 Sep 2017 13:48:34 +0300 Subject: [PATCH] Add image node --- .../annimon/hotarufx/bundles/NodesBundle.java | 12 +++ .../hotarufx/visual/objects/ImageNode.java | 89 +++++++++++++++++++ .../hotarufx/visual/visitors/NodeVisitor.java | 1 + .../visual/visitors/RenderVisitor.java | 5 ++ 4 files changed, 107 insertions(+) create mode 100644 app/src/main/java/com/annimon/hotarufx/visual/objects/ImageNode.java diff --git a/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java b/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java index 324ed13..7b171c5 100644 --- a/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java +++ b/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java @@ -25,6 +25,7 @@ public class NodesBundle implements Bundle { FUNCTIONS.put("circle", of(NODE, node(CircleNode::new))); FUNCTIONS.put("ellipse", of(NODE, node(EllipseNode::new))); FUNCTIONS.put("group", of(NODE, group())); + FUNCTIONS.put("image", of(NODE, image())); FUNCTIONS.put("line", of(NODE, node(LineNode::new))); FUNCTIONS.put("polygon", of(NODE, poly(PolygonNode::new))); FUNCTIONS.put("polyline", of(NODE, poly(PolylineNode::new))); @@ -60,6 +61,17 @@ public class NodesBundle implements Bundle { }; } + private static Function image() { + return args -> { + val validator = Validator.with(args); + val map = validator.requireMapAt(1); + val url = args[0].asString(); + val node = new NodeValue(new ImageNode(url)); + node.fill(map); + return node; + }; + } + private static Function group() { return args -> { val nodes = Arrays.stream(args) diff --git a/app/src/main/java/com/annimon/hotarufx/visual/objects/ImageNode.java b/app/src/main/java/com/annimon/hotarufx/visual/objects/ImageNode.java new file mode 100644 index 0000000..a78614d --- /dev/null +++ b/app/src/main/java/com/annimon/hotarufx/visual/objects/ImageNode.java @@ -0,0 +1,89 @@ +package com.annimon.hotarufx.visual.objects; + +import com.annimon.hotarufx.visual.PropertyBindings; +import com.annimon.hotarufx.visual.PropertyTimeline; +import com.annimon.hotarufx.visual.PropertyTimelineHolder; +import com.annimon.hotarufx.visual.TimeLine; +import com.annimon.hotarufx.visual.visitors.NodeVisitor; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import static com.annimon.hotarufx.visual.PropertyType.BOOLEAN; +import static com.annimon.hotarufx.visual.PropertyType.NUMBER; + +public class ImageNode extends ObjectNode { + + public final ImageView imageView; + + private PropertyTimelineHolder x, y, fitWidth, fitHeight; + private PropertyTimelineHolder preserveRatio, smooth; + + public ImageNode(String url) { + this(url, new ImageView()); + } + + private ImageNode(String url, ImageView imageView) { + super(imageView); + this.imageView = imageView; + imageView.imageProperty().setValue(new Image(url)); + x = PropertyTimelineHolder.empty(); + y = PropertyTimelineHolder.empty(); + fitWidth = PropertyTimelineHolder.empty(); + fitHeight = PropertyTimelineHolder.empty(); + preserveRatio = PropertyTimelineHolder.empty(); + smooth = PropertyTimelineHolder.empty(); + } + + public PropertyTimeline xProperty() { + return x.setIfEmptyThenGet(imageView::xProperty); + } + + public PropertyTimeline yProperty() { + return y.setIfEmptyThenGet(imageView::yProperty); + } + + public PropertyTimeline fitWidthProperty() { + return fitWidth.setIfEmptyThenGet(imageView::fitWidthProperty); + } + + public PropertyTimeline fitHeightProperty() { + return fitHeight.setIfEmptyThenGet(imageView::fitHeightProperty); + } + + public PropertyTimeline preserveRatioProperty() { + return preserveRatio.setIfEmptyThenGet(imageView::preserveRatioProperty); + } + + public PropertyTimeline smoothProperty() { + return smooth.setIfEmptyThenGet(imageView::smoothProperty); + } + + @Override + public void buildTimeline(TimeLine timeline) { + super.buildTimeline(timeline); + x.applyIfPresent(timeline); + y.applyIfPresent(timeline); + fitWidth.applyIfPresent(timeline); + fitHeight.applyIfPresent(timeline); + preserveRatio.applyIfPresent(timeline); + smooth.applyIfPresent(timeline); + } + + @Override + public PropertyBindings propertyBindings(PropertyBindings bindings) { + return super.propertyBindings(bindings) + .add("x", NUMBER, this::xProperty) + .add("y", NUMBER, this::yProperty) + .add("width", NUMBER, this::fitWidthProperty) + .add("fitWidth", NUMBER, this::fitWidthProperty) + .add("height", NUMBER, this::fitHeightProperty) + .add("fitHeight", NUMBER, this::fitHeightProperty) + .add("ratio", BOOLEAN, this::preserveRatioProperty) + .add("preserveRatio", BOOLEAN, this::preserveRatioProperty) + .add("smooth", BOOLEAN, this::smoothProperty); + } + + @Override + public R accept(NodeVisitor visitor, T input) { + return visitor.visit(this, input); + } +} diff --git a/app/src/main/java/com/annimon/hotarufx/visual/visitors/NodeVisitor.java b/app/src/main/java/com/annimon/hotarufx/visual/visitors/NodeVisitor.java index 107922b..f6f3bab 100644 --- a/app/src/main/java/com/annimon/hotarufx/visual/visitors/NodeVisitor.java +++ b/app/src/main/java/com/annimon/hotarufx/visual/visitors/NodeVisitor.java @@ -8,6 +8,7 @@ public interface NodeVisitor { R visit(CircleNode node, T input); R visit(EllipseNode node, T input); R visit(GroupNode node, T input); + R visit(ImageNode node, T input); R visit(LineNode node, T input); R visit(PolygonNode node, T input); R visit(PolylineNode node, T input); diff --git a/app/src/main/java/com/annimon/hotarufx/visual/visitors/RenderVisitor.java b/app/src/main/java/com/annimon/hotarufx/visual/visitors/RenderVisitor.java index 6483453..dae153a 100644 --- a/app/src/main/java/com/annimon/hotarufx/visual/visitors/RenderVisitor.java +++ b/app/src/main/java/com/annimon/hotarufx/visual/visitors/RenderVisitor.java @@ -35,6 +35,11 @@ public class RenderVisitor implements NodeVisitor { return null; } + @Override + public Void visit(ImageNode node, VirtualScene scene) { + return render(node, scene); + } + @Override public Void visit(LineNode node, VirtualScene scene) { return render(node, scene);