diff --git a/pom.xml b/pom.xml index d591299..ce3f472 100755 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,11 @@ + + com.brunomnsilva + fluentfxcss + 1.2.0 + org.openjfx javafx-base diff --git a/src/main/java/com/brunomnsilva/smartgraph/examples/cities/Main.java b/src/main/java/com/brunomnsilva/smartgraph/examples/cities/Main.java index 7ac4916..61a9bbf 100644 --- a/src/main/java/com/brunomnsilva/smartgraph/examples/cities/Main.java +++ b/src/main/java/com/brunomnsilva/smartgraph/examples/cities/Main.java @@ -24,6 +24,8 @@ package com.brunomnsilva.smartgraph.examples.cities; +import com.brunomnsilva.fluentfxcss.FluentFxCss; +import com.brunomnsilva.fluentfxcss.definitions.ShapeStyleDefinition; import com.brunomnsilva.smartgraph.containers.SmartGraphDemoContainer; import com.brunomnsilva.smartgraph.graph.Graph; import com.brunomnsilva.smartgraph.graph.GraphEdgeList; @@ -103,7 +105,18 @@ public void start(Stage ignored) { * .addStyleClass(class). However, inline styles can be overwritten by using .setStyleInline(css); * also, when you use .setStyleClass(class), all previous styles will be discarded, including inline. */ - graphView.getStylableVertex(tokyo).setStyleInline("-fx-fill: url(\"file:squares.jpg\");"); + + /* The possibility of setting a image pattern as a fill is undocumented on javafx reference. + * But it can be done programmatically with an ImagePattern. We exploit this with a custom property. */ + ShapeStyleDefinition vTokyo = FluentFxCss.shapeStyle() + .customProperty("-fx-fill", "url(\"file:squares.jpg\")") + .build(); + + System.out.println(vTokyo); + + graphView.getStylableVertex(tokyo).setStyleInline(vTokyo.toCssInline()); + + //graphView.getStylableVertex(tokyo).setStyleInline("-fx-fill: url(\"file:squares.jpg\");"); //graphVertex.setStyleInline("-fx-fill: red;"); //this will overwrite the property later on graphView.setVertexDoubleClickAction(graphVertex -> { diff --git a/src/main/java/com/brunomnsilva/smartgraph/examples/digraph/Main.java b/src/main/java/com/brunomnsilva/smartgraph/examples/digraph/Main.java index a803be9..17413e3 100755 --- a/src/main/java/com/brunomnsilva/smartgraph/examples/digraph/Main.java +++ b/src/main/java/com/brunomnsilva/smartgraph/examples/digraph/Main.java @@ -23,6 +23,8 @@ */ package com.brunomnsilva.smartgraph.examples.digraph; +import com.brunomnsilva.fluentfxcss.FluentFxCss; +import com.brunomnsilva.fluentfxcss.definitions.ShapeStyleDefinition; import com.brunomnsilva.smartgraph.containers.SmartGraphDemoContainer; import com.brunomnsilva.smartgraph.graph.Digraph; import com.brunomnsilva.smartgraph.graph.DigraphEdgeList; @@ -30,9 +32,12 @@ import com.brunomnsilva.smartgraph.graphview.*; import javafx.application.Application; import javafx.scene.Scene; +import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.stage.StageStyle; + + /** * Class that provides an example of using the library. * @@ -57,7 +62,13 @@ public void start(Stage ignored) { This can be done at any time afterwards. */ if (g.numVertices() > 0) { - graphView.getStylableVertex("A").setStyleInline("-fx-fill: gold; -fx-stroke: brown;"); + + ShapeStyleDefinition style = FluentFxCss.shapeStyle() + .fill(Color.GOLD) + .stroke(Color.BROWN) + .build(); + + graphView.getStylableVertex("A").setStyleInline(style.toCssInline()); } diff --git a/src/main/java/com/brunomnsilva/smartgraph/examples/flowers/Main.java b/src/main/java/com/brunomnsilva/smartgraph/examples/flowers/Main.java index 27d7021..2a68dcc 100755 --- a/src/main/java/com/brunomnsilva/smartgraph/examples/flowers/Main.java +++ b/src/main/java/com/brunomnsilva/smartgraph/examples/flowers/Main.java @@ -23,15 +23,28 @@ */ package com.brunomnsilva.smartgraph.examples.flowers; +import com.brunomnsilva.fluentfxcss.FluentFxCss; +import com.brunomnsilva.fluentfxcss.definitions.*; +import com.brunomnsilva.fluentfxcss.enums.PseudoClassValue; +import com.brunomnsilva.fluentfxcss.enums.UnitValue; import com.brunomnsilva.smartgraph.containers.SmartGraphDemoContainer; import com.brunomnsilva.smartgraph.graph.Graph; import com.brunomnsilva.smartgraph.graph.GraphEdgeList; import com.brunomnsilva.smartgraph.graphview.*; import javafx.application.Application; import javafx.scene.Scene; +import javafx.scene.effect.BlurType; +import javafx.scene.paint.Color; +import javafx.scene.shape.StrokeLineCap; +import javafx.scene.text.FontWeight; import javafx.stage.Stage; import javafx.stage.StageStyle; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + /** * Class that provides an example of using the library. * @@ -44,13 +57,20 @@ public void start(Stage ignored) { Graph g = build_flower_graph(); System.out.println(g); - + + URI stylesheetURI = createStylesheet(); + + SmartGraphProperties properties = new SmartGraphProperties(); SmartPlacementStrategy initialPlacement = new SmartCircularSortedPlacementStrategy(); ForceDirectedLayoutStrategy automaticPlacementStrategy = new ForceDirectedSpringGravityLayoutStrategy<>(); - SmartGraphPanel graphView = new SmartGraphPanel<>(g, initialPlacement, automaticPlacementStrategy); - graphView.setAutomaticLayout(true); // Set automatic layout from the start + SmartGraphPanel graphView = new SmartGraphPanel<>(g, + properties, + initialPlacement, + stylesheetURI, + automaticPlacementStrategy); + graphView.setAutomaticLayout(true); // Set automatic layout from the start Scene scene = new Scene(new SmartGraphDemoContainer(graphView), 1024, 768); @@ -116,5 +136,116 @@ private Graph build_flower_graph() { return g; } + private static URI createStylesheet() { + + /* .graph */ + PaneStyleDefinition graph = FluentFxCss.paneStyle() + .backgroundColor(Color.BLACK) + .build(); + + /* .vertex and .vertex:hover */ + ShapeStyleDefinition vertex = FluentFxCss.shapeStyle() + .fill(Color.web("#3498db")) + .stroke(Color.web("#2980b9")) + .strokeWidth(2) + .dropShadow(BlurType.GAUSSIAN, Color.web("#00ffff"), 15, 0.8, 0, 0) + .opacity(0.5) + .build(); + + ShapeStyleDefinition vertexHover = FluentFxCss.shapeStyle() + .strokeWidth(4) + .build(); + + /* .vertex-label */ + TextStyleDefinition vertexLabelText = FluentFxCss.textStyle() + .fontWeight(FontWeight.BOLD) + .fontSize(8, UnitValue.PT) + .fontFamily("sans-serif") + .build(); + + RegionStyleDefinition vertexLabelBackground = FluentFxCss.regionStyle() + .padding(UnitValue.PX, 5) + .dropShadow(BlurType.GAUSSIAN, Color.web("#00ffff"), 10, 0.6, 0, 0) + .build(); + + StyleDefinition vertexLabel = vertexLabelText.mergeWith(vertexLabelBackground); + + /* .edge and .edge:hover */ + ShapeStyleDefinition edge = FluentFxCss.shapeStyle() + .stroke(Color.WHITE) + .strokeWidth(2) + .dropShadow(BlurType.GAUSSIAN, Color.web("#00ffff"), 10, 0.6, 0, 0) + .fill(Color.TRANSPARENT) + .strokeLineCap(StrokeLineCap.ROUND) + .opacity(0.8) + .build(); + + ShapeStyleDefinition edgeHover = FluentFxCss.shapeStyle() + .strokeWidth(3) + .build(); + + TextStyleDefinition edgeLabelText = FluentFxCss.textStyle() + .fontWeight(FontWeight.NORMAL) + .fontSize(5, UnitValue.PT) + .fontFamily("sans-serif") + .build(); + + RegionStyleDefinition edgeLabelBackground = FluentFxCss.regionStyle() + .dropShadow(BlurType.GAUSSIAN, Color.web("#00ffff"), 10, 0.6, 0, 0) + .build(); + + StyleDefinition edgeLabel = edgeLabelText.mergeWith(edgeLabelBackground); + + TextStyleDefinition edgeLabelTextHover = FluentFxCss.textStyle() + .fontWeight(FontWeight.BOLD) + .fontSize(5, UnitValue.PT) + .fontFamily("sans-serif") + .build(); + + RegionStyleDefinition edgeLabelBackgroundHover = FluentFxCss.regionStyle() + .backgroundRadius(5) + .borderRadius(5) + .build(); + + StyleDefinition edgeLabelHover = edgeLabelTextHover.mergeWith(edgeLabelBackgroundHover); + + + /* Compose CSS */ + String graphClass = graph.toCssClass("graph"); + String vertexClass = vertex.toCssClass("vertex"); + String vertexHoverClass = vertexHover.toCssPseudoClass("vertex", PseudoClassValue.HOVER); + + String vertexLabelClass = vertexLabel.toCssClass("vertex-label"); + + String edgeClass = edge.toCssClass("edge"); + String edgeHoverClass = edgeHover.toCssPseudoClass("edge", PseudoClassValue.HOVER); + + String edgeLabelClass = edgeLabel.toCssClass("edge-label"); + String edgeLabelHoverClass = edgeLabelHover.toCssPseudoClass("edge-label", PseudoClassValue.HOVER); + + String css = String.join("\n", + graphClass, + vertexClass, + vertexHoverClass, + vertexLabelClass, + edgeClass, + edgeHoverClass, + edgeLabelClass, + edgeLabelHoverClass + ); + + try { + // Create a temporary file (OS will handle cleanup eventually) + Path tempCssFile = Files.createTempFile("dynamic-style", ".css"); + Files.write(tempCssFile, css.getBytes(StandardCharsets.UTF_8)); + + // Convert to URI + return tempCssFile.toUri(); + } catch(Exception e) { + System.err.println("Cannot create temporary file."); + } + + return null; + } } diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 1d0fd63..354683a 100755 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -7,6 +7,8 @@ requires javafx.base; requires java.logging; + requires com.brunomnsilva.fluentfxcss; + exports com.brunomnsilva.smartgraph.containers; exports com.brunomnsilva.smartgraph.graph; exports com.brunomnsilva.smartgraph.graphview;