From 502ad42fde8639a327df4415daf64636c4d85c30 Mon Sep 17 00:00:00 2001 From: Victor Date: Sat, 2 Sep 2017 12:33:30 +0300 Subject: [PATCH] Add group node --- .../annimon/hotarufx/bundles/NodesBundle.java | 15 +++++ .../annimon/hotarufx/visual/PropertyType.java | 2 +- .../hotarufx/visual/objects/GroupNode.java | 62 +++++++++++++++++++ .../hotarufx/visual/objects/ObjectNode.java | 4 +- .../hotarufx/visual/visitors/NodeVisitor.java | 2 + .../visual/visitors/RenderVisitor.java | 13 +++- app/src/main/resources/main.hfx | 6 +- 7 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/annimon/hotarufx/visual/objects/GroupNode.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 627ba9c..841c0a5 100644 --- a/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java +++ b/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java @@ -3,13 +3,17 @@ package com.annimon.hotarufx.bundles; import com.annimon.hotarufx.lib.Context; import com.annimon.hotarufx.lib.Function; import com.annimon.hotarufx.lib.NodeValue; +import com.annimon.hotarufx.lib.Types; import com.annimon.hotarufx.lib.Validator; import com.annimon.hotarufx.visual.objects.CircleNode; +import com.annimon.hotarufx.visual.objects.GroupNode; import com.annimon.hotarufx.visual.objects.ObjectNode; import com.annimon.hotarufx.visual.objects.RectangleNode; import com.annimon.hotarufx.visual.objects.SVGPathNode; import com.annimon.hotarufx.visual.objects.TextNode; +import java.util.Arrays; import java.util.function.Supplier; +import java.util.stream.Collectors; import lombok.val; public class NodesBundle implements Bundle { @@ -17,6 +21,7 @@ public class NodesBundle implements Bundle { @Override public void load(Context context) { context.functions().put("circle", node(CircleNode::new)); + context.functions().put("group", group()); context.functions().put("rectangle", node(RectangleNode::new)); context.functions().put("svgPath", node(SVGPathNode::new)); context.functions().put("text", node(TextNode::new)); @@ -30,4 +35,14 @@ public class NodesBundle implements Bundle { return node; }; } + + private Function group() { + return args -> { + val nodes = Arrays.stream(args) + .filter(v -> v.type() == Types.NODE) + .map(v -> ((NodeValue) v).getNode()) + .collect(Collectors.toList()); + return new NodeValue(new GroupNode(nodes)); + }; + } } diff --git a/app/src/main/java/com/annimon/hotarufx/visual/PropertyType.java b/app/src/main/java/com/annimon/hotarufx/visual/PropertyType.java index b6fea60..4379b56 100644 --- a/app/src/main/java/com/annimon/hotarufx/visual/PropertyType.java +++ b/app/src/main/java/com/annimon/hotarufx/visual/PropertyType.java @@ -61,7 +61,7 @@ public enum PropertyType { private static Function toClipNode() { return v -> { ObjectNode node = ((NodeValue) v).getNode(); - node.setUsedAsClip(true); + node.setRenderable(false); return node.getFxNode(); }; } diff --git a/app/src/main/java/com/annimon/hotarufx/visual/objects/GroupNode.java b/app/src/main/java/com/annimon/hotarufx/visual/objects/GroupNode.java new file mode 100644 index 0000000..48df55e --- /dev/null +++ b/app/src/main/java/com/annimon/hotarufx/visual/objects/GroupNode.java @@ -0,0 +1,62 @@ +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 java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import javafx.scene.Group; +import lombok.val; +import static com.annimon.hotarufx.visual.PropertyType.BOOLEAN; + +public class GroupNode extends ObjectNode { + + public final Group group; + public final List nodes; + + private PropertyTimelineHolder autoSizeChildren; + + public GroupNode(List nodes) { + this(new Group(), nodes); + } + + private GroupNode(Group group, List nodes) { + super(group); + this.group = group; + this.nodes = new ArrayList<>(nodes); + val fxNodes = nodes.stream() + .map(ObjectNode::getFxNode) + .collect(Collectors.toList()); + group.getChildren().addAll(fxNodes); + autoSizeChildren = PropertyTimelineHolder.empty(); + } + + public PropertyTimeline autoSizeChildrenProperty() { + return autoSizeChildren.setIfEmptyThenGet(group::autoSizeChildrenProperty); + } + + @Override + public void buildTimeline(TimeLine timeline) { + super.buildTimeline(timeline); + autoSizeChildren.applyIfPresent(timeline); + for (ObjectNode node : nodes) { + node.buildTimeline(timeline); + } + + } + + @Override + public PropertyBindings propertyBindings(PropertyBindings bindings) { + return super.propertyBindings(bindings) + .add("autoSize", BOOLEAN, this::autoSizeChildrenProperty) + .add("autoSizeChildren", BOOLEAN, this::autoSizeChildrenProperty); + } + + @Override + public R accept(NodeVisitor visitor, T input) { + return visitor.visit(this, input); + } +} diff --git a/app/src/main/java/com/annimon/hotarufx/visual/objects/ObjectNode.java b/app/src/main/java/com/annimon/hotarufx/visual/objects/ObjectNode.java index 0c36ea6..c0e3c39 100644 --- a/app/src/main/java/com/annimon/hotarufx/visual/objects/ObjectNode.java +++ b/app/src/main/java/com/annimon/hotarufx/visual/objects/ObjectNode.java @@ -22,7 +22,7 @@ public abstract class ObjectNode { private PropertyTimelineHolder scaleX, scaleY, scaleZ; private PropertyTimelineHolder layoutX, layoutY; @Getter @Setter - private boolean isUsedAsClip; + private boolean isRenderable; public ObjectNode(Node node) { this.node = node; @@ -39,7 +39,7 @@ public abstract class ObjectNode { scaleZ = PropertyTimelineHolder.empty(); layoutX = PropertyTimelineHolder.empty(); layoutY = PropertyTimelineHolder.empty(); - isUsedAsClip = false; + isRenderable = true; } public Node getFxNode() { 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 68917f9..ea6c21d 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 @@ -1,6 +1,7 @@ package com.annimon.hotarufx.visual.visitors; import com.annimon.hotarufx.visual.objects.CircleNode; +import com.annimon.hotarufx.visual.objects.GroupNode; import com.annimon.hotarufx.visual.objects.RectangleNode; import com.annimon.hotarufx.visual.objects.SVGPathNode; import com.annimon.hotarufx.visual.objects.TextNode; @@ -8,6 +9,7 @@ import com.annimon.hotarufx.visual.objects.TextNode; public interface NodeVisitor { R visit(CircleNode node, T input); + R visit(GroupNode node, T input); R visit(RectangleNode node, T input); R visit(SVGPathNode node, T input); R visit(TextNode 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 489e46a..6f912f5 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 @@ -3,6 +3,7 @@ package com.annimon.hotarufx.visual.visitors; import com.annimon.hotarufx.visual.TimeLine; import com.annimon.hotarufx.visual.VirtualScene; import com.annimon.hotarufx.visual.objects.CircleNode; +import com.annimon.hotarufx.visual.objects.GroupNode; import com.annimon.hotarufx.visual.objects.ObjectNode; import com.annimon.hotarufx.visual.objects.RectangleNode; import com.annimon.hotarufx.visual.objects.SVGPathNode; @@ -19,6 +20,16 @@ public class RenderVisitor implements NodeVisitor { return render(node, scene); } + @Override + public Void visit(GroupNode group, VirtualScene scene) { + render(group, scene); + for (ObjectNode node : group.nodes) { + node.setRenderable(false); + node.accept(this, scene); + } + return null; + } + @Override public Void visit(RectangleNode node, VirtualScene scene) { return render(node, scene); @@ -36,7 +47,7 @@ public class RenderVisitor implements NodeVisitor { private Void render(ObjectNode node, VirtualScene scene) { node.buildTimeline(timeline); - if (!node.isUsedAsClip()) { + if (node.isRenderable()) { scene.add(node.getFxNode()); } return null; diff --git a/app/src/main/resources/main.hfx b/app/src/main/resources/main.hfx index 33f4c6f..9182114 100644 --- a/app/src/main/resources/main.hfx +++ b/app/src/main/resources/main.hfx @@ -71,4 +71,8 @@ HEART = svgPath({ stroke: "white" }) -render(B, A, C, CLIP, HEART) \ No newline at end of file +#render(B, A, C, CLIP, HEART) + +G1 = group(B, A) +G1@rotate.add(10, 45).add(20, -45) +render(G1)