mirror of
https://github.com/aNNiMON/HotaruFX.git
synced 2024-09-19 14:14:21 +03:00
Add group node
This commit is contained in:
parent
1c5adfe885
commit
502ad42fde
@ -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));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public enum PropertyType {
|
||||
private static Function<Value, Object> toClipNode() {
|
||||
return v -> {
|
||||
ObjectNode node = ((NodeValue) v).getNode();
|
||||
node.setUsedAsClip(true);
|
||||
node.setRenderable(false);
|
||||
return node.getFxNode();
|
||||
};
|
||||
}
|
||||
|
@ -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<ObjectNode> nodes;
|
||||
|
||||
private PropertyTimelineHolder<Boolean> autoSizeChildren;
|
||||
|
||||
public GroupNode(List<ObjectNode> nodes) {
|
||||
this(new Group(), nodes);
|
||||
}
|
||||
|
||||
private GroupNode(Group group, List<ObjectNode> 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<Boolean> 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, T> R accept(NodeVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ public abstract class ObjectNode {
|
||||
private PropertyTimelineHolder<Number> scaleX, scaleY, scaleZ;
|
||||
private PropertyTimelineHolder<Number> 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() {
|
||||
|
@ -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, T> {
|
||||
|
||||
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);
|
||||
|
@ -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<Void, VirtualScene> {
|
||||
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<Void, VirtualScene> {
|
||||
|
||||
private Void render(ObjectNode node, VirtualScene scene) {
|
||||
node.buildTimeline(timeline);
|
||||
if (!node.isUsedAsClip()) {
|
||||
if (node.isRenderable()) {
|
||||
scene.add(node.getFxNode());
|
||||
}
|
||||
return null;
|
||||
|
@ -71,4 +71,8 @@ HEART = svgPath({
|
||||
stroke: "white"
|
||||
})
|
||||
|
||||
render(B, A, C, CLIP, HEART)
|
||||
#render(B, A, C, CLIP, HEART)
|
||||
|
||||
G1 = group(B, A)
|
||||
G1@rotate.add(10, 45).add(20, -45)
|
||||
render(G1)
|
||||
|
Loading…
Reference in New Issue
Block a user