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 a5de63b..186eceb 100644 --- a/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java +++ b/app/src/main/java/com/annimon/hotarufx/bundles/NodesBundle.java @@ -8,6 +8,7 @@ import com.annimon.hotarufx.lib.Validator; import com.annimon.hotarufx.lib.Value; import com.annimon.hotarufx.visual.objects.CircleNode; import com.annimon.hotarufx.visual.objects.GroupNode; +import com.annimon.hotarufx.visual.objects.LineNode; import com.annimon.hotarufx.visual.objects.ObjectNode; import com.annimon.hotarufx.visual.objects.PolygonNode; import com.annimon.hotarufx.visual.objects.PolylineNode; @@ -26,6 +27,7 @@ public class NodesBundle implements Bundle { public void load(Context context) { context.functions().put("circle", node(CircleNode::new)); context.functions().put("group", group()); + context.functions().put("line", node(LineNode::new)); context.functions().put("polygon", poly(PolygonNode::new)); context.functions().put("polyline", poly(PolylineNode::new)); context.functions().put("rectangle", node(RectangleNode::new)); diff --git a/app/src/main/java/com/annimon/hotarufx/visual/objects/LineNode.java b/app/src/main/java/com/annimon/hotarufx/visual/objects/LineNode.java new file mode 100644 index 0000000..7daf81b --- /dev/null +++ b/app/src/main/java/com/annimon/hotarufx/visual/objects/LineNode.java @@ -0,0 +1,68 @@ +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.shape.Line; +import static com.annimon.hotarufx.visual.PropertyType.NUMBER; + +public class LineNode extends ShapeNode { + + public final Line line; + + private PropertyTimelineHolder startX, startY, endX, endY; + + public LineNode() { + this(new Line()); + } + + private LineNode(Line line) { + super(line); + this.line = line; + startX = PropertyTimelineHolder.empty(); + startY = PropertyTimelineHolder.empty(); + endX = PropertyTimelineHolder.empty(); + endY = PropertyTimelineHolder.empty(); + } + + public PropertyTimeline startXProperty() { + return startX.setIfEmptyThenGet(line::startXProperty); + } + + public PropertyTimeline startYProperty() { + return startY.setIfEmptyThenGet(line::startYProperty); + } + + public PropertyTimeline endXProperty() { + return endX.setIfEmptyThenGet(line::endXProperty); + } + + public PropertyTimeline endYProperty() { + return endY.setIfEmptyThenGet(line::endYProperty); + } + + @Override + public void buildTimeline(TimeLine timeline) { + super.buildTimeline(timeline); + startX.applyIfPresent(timeline); + startY.applyIfPresent(timeline); + endX.applyIfPresent(timeline); + endY.applyIfPresent(timeline); + } + + @Override + public PropertyBindings propertyBindings(PropertyBindings bindings) { + return super.propertyBindings(bindings) + .add("startX", NUMBER, this::startXProperty) + .add("startY", NUMBER, this::startYProperty) + .add("endX", NUMBER, this::endXProperty) + .add("endY", NUMBER, this::endYProperty); + } + + @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 aa92298..010b743 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 @@ -2,6 +2,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.LineNode; import com.annimon.hotarufx.visual.objects.PolygonNode; import com.annimon.hotarufx.visual.objects.PolylineNode; import com.annimon.hotarufx.visual.objects.RectangleNode; @@ -12,6 +13,7 @@ public interface NodeVisitor { R visit(CircleNode node, T input); R visit(GroupNode node, T input); + R visit(LineNode node, T input); R visit(PolygonNode node, T input); R visit(PolylineNode node, T input); R visit(RectangleNode 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 c23aff3..cf789e9 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 @@ -4,6 +4,7 @@ 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.LineNode; import com.annimon.hotarufx.visual.objects.ObjectNode; import com.annimon.hotarufx.visual.objects.PolygonNode; import com.annimon.hotarufx.visual.objects.PolylineNode; @@ -32,6 +33,11 @@ public class RenderVisitor implements NodeVisitor { return null; } + @Override + public Void visit(LineNode node, VirtualScene scene) { + return render(node, scene); + } + @Override public Void visit(PolygonNode node, VirtualScene scene) { return render(node, scene); diff --git a/app/src/main/resources/main.hfx b/app/src/main/resources/main.hfx index 235def3..4ebf79d 100644 --- a/app/src/main/resources/main.hfx +++ b/app/src/main/resources/main.hfx @@ -86,5 +86,17 @@ POLYLINE = polyline(points, { stroke: "purple" }) -render(B, A, C, CLIP, HEART, POLYGON, POLYLINE) +LINE = line({ + visible: 0, + startX: -600 + startY: 300 + endX: 600 + endY: 300, + stroke: "#777", + strokeDashOffset: 45 +}) +LINE@visible.add(100, 1) +LINE@strokeWidth.add(100, 0).add(140, 10) + +render(B, A, C, CLIP, HEART, POLYGON, POLYLINE, LINE)