L0.HasLabel "Hide Profile Monitors?"
>-- DIA.Element.upProfileMonitors --> L0.Boolean <R L0.HasProperty : L0.FunctionalRelation : SEL.GenericParameterType
L0.HasLabel "Grow Profile Monitors Upward?"
+
+DIA.symbolFunction <R L0.HasProperty : L0.FunctionalRelation
DIA.DiagramContainer <T L0.Entity
@L0.singleProperty L0.HasName
DIA.Groups.DefinedElementGroup : DIA.TypeGroup
DIA.TypeGroup.HasType DIA.DefinedElement
+DIA.Groups.RouteGraphConnectionElementGroup : DIA.TypeGroup
+ DIA.TypeGroup.HasType DIA.RouteGraphConnection
*******************************************************************************/
package org.simantics.diagram.adapter;
+import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.Collection;
return null;
return ti.getTransform();
}
+
+ @Override
+ public Shape getTerminalShape(IElement e, Terminal t) {
+ if (t instanceof ResourceTerminal) {
+ ResourceTerminal rt = (ResourceTerminal) t;
+ IG2DNode node = e.getHint(DefinedElementHandler.KEY_SG_NODE);
+ if (node != null) {
+ IG2DNode n = findResourceTerminalNode(node, rt);
+ if (n != null) {
+ return n.getBoundsInLocal();
+ }
+ }
+ }
+ return super.getTerminalShape(e, t);
+ }
}
\ No newline at end of file
@L0.orderedSet
_ : DIA.SVGElement
G2D.HasSVGDocument """<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" overflow="visible" version="1.1"><g transform="translate(-0.0,-0.0)"><ellipse cx="0.0" cy="0.0" rx="0.5" ry="0.5" fill="rgb(0,163,204)" stroke="black" stroke-width="0.1"/></g></svg>""" : L0.String
-
+
+TERMINALS.TargetedDynamicTerminal /* @ "Connection point to a child element" */ <T DIA.DefinedElement <T DIA.Terminal
+ STR.IsDefinedBy _ : DIA.Composite
+ @L0.orderedSet
+ _ : DIA.SVGElement
+ G2D.HasSVGDocument """<svg display="none"><g display="none"></g></svg>""" : L0.String
+
TERMINALS.CommandTerminal /* @ "Command termina" */ <T DIA.DefinedElement <T DIA.Terminal
STR.IsDefinedBy _ : DIA.Composite
@L0.orderedSet
L0.HasDescription """Specifies a template for a symbol that is created
by default for the new component type under the model."""
>-- MOD.StructuralModel.HasSymbolDiagramType --> L0.Type <R L0.IsRelatedTo : L0.FunctionalRelation
-
+ >-- MOD.StructuralModel.HasSymbolType --> L0.Type <R L0.IsRelatedTo : L0.FunctionalRelation
>-- MOD.StructuralModel.HasConfigurationType --> L0.Type <R L0.IsRelatedTo : L0.FunctionalRelation
@L0.assert MOD.StructuralModel.HasComponentTypeSupertype STR.Component
data G2DNodeModification
@JavaName "<init>"
createG2DNodeModification :: [SVGNodeAssignment] -> [TransformationAssignment] -> G2DNodeModification
+ @JavaName "<init>"
+ createG2DNodeModification3 :: [SVGNodeAssignment] -> [TargetedSVGNodeAssignment] -> [TransformationAssignment] -> G2DNodeModification
importJava "org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment" where
data SVGNodeAssignment
+ @JavaName "<init>"
+ createSVGNodeAssignment :: String -> String -> String -> SVGNodeAssignment
+importJava "org.simantics.scenegraph.g2d.nodes.TargetedSVGNodeAssignment" where
+ data TargetedSVGNodeAssignment
+ @JavaName "<init>"
+ createTargetedSVGNodeAssignment :: a -> String -> String -> String -> TargetedSVGNodeAssignment
+
importJava "org.simantics.scenegraph.g2d.nodes.TransformationAssignment" where
data TransformationAssignment
@JavaName "<init>"
}
@Deprecated
- public Resource createSymbol2(String name, Resource type) throws DatabaseException {
+ public Resource createSymbol2(String name, Resource diagramType) throws DatabaseException {
+ return createSymbol2(name, diagramType, dr.DefinedElement);
+ }
+ @Deprecated
+ public Resource createSymbol2(String name, Resource diagramType, Resource symbolType) throws DatabaseException {
G2DResource g2d = G2DResource.getInstance(g);
// Resource visibleTag = wg.newResource();
// wg.claim(focusableTag, b.SubrelationOf, null, dr.IsFocusable);
Double boxDimension = 6.0;
- Collection<Statement> grid = g.getAssertedStatements(type, dr.HasGridSize);
+ Collection<Statement> grid = g.getAssertedStatements(diagramType, dr.HasGridSize);
if(grid.size() == 1) {
Double d = g.getPossibleValue(grid.iterator().next().getObject(), Bindings.DOUBLE);
if(d != null) boxDimension = 2*d;
// wg.claim(element, visibleTag, element);
// wg.claim(element, focusableTag, element);
- Resource orderedSet = OrderedSetUtils.create(wg, type, element);
+ Resource orderedSet = OrderedSetUtils.create(wg, diagramType, element);
// wg.claim(orderedSet, dr.HasLayer, GraphUtils.create2(wg, dr.Layer,
// b.HasName, "Default",
AddElement.claimFreshElementName(wg, orderedSet, element);
wg.claim(orderedSet, b.ConsistsOf, element);
- wg.claim(result, b.Inherits, null, dr.DefinedElement);
+ wg.claim(result, b.Inherits, null, symbolType);
return result;
}
Resource symbolDiagramType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasSymbolDiagramType);
if(symbolDiagramType == null) symbolDiagramType = DIA.Composite;
-
+
+ Resource symbolType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasSymbolType);
+ if(symbolType == null) symbolType = DIA.DefinedElement;
+
// Symbol
- Resource symbol = new ModelingUtils(graph).createSymbol2("Symbol", symbolDiagramType);
+ Resource symbol = new ModelingUtils(graph).createSymbol2("Symbol", symbolDiagramType, symbolType);
graph.claim(componentType, MOD.ComponentTypeToSymbol, symbol);
graph.claim(componentType, L0.ConsistsOf, symbol);
import java.util.List;
import java.util.Map;
+import org.simantics.Simantics;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
import org.simantics.db.exception.DatabaseException;
import org.simantics.scenegraph.INode;
import org.simantics.scenegraph.g2d.G2DNodeModification;
import org.simantics.scenegraph.g2d.IG2DNode;
+import org.simantics.scenegraph.g2d.nodes.ConnectionNode;
import org.simantics.scenegraph.g2d.nodes.SVGNode;
import org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment;
import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
+import org.simantics.scenegraph.g2d.nodes.TargetedSVGNodeAssignment;
import org.simantics.scenegraph.g2d.nodes.TransformationAssignment;
+import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode;
import org.simantics.scenegraph.profile.EvaluationContext;
import org.simantics.scenegraph.utils.NodeUtil;
+import org.simantics.scl.runtime.function.Function;
+import org.simantics.structural.stubs.StructuralResource2;
import org.simantics.utils.datastructures.Pair;
/**
if (elementVariable == null)
return null;
Object modi = elementVariable.getPossiblePropertyValue(graph, DIA.symbolCode);
- if (modi == null)
- return null;
+ if (modi == null) {
+ if(graph.isInstanceOf(element, DIA.RouteGraphConnection)) {
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+ Resource connectionType = graph.getPossibleObject(element, STR.HasConnectionType);
+ if(connectionType != null) {
+ Variable connectionTypeVariable = Variables.getPossibleVariable(graph, connectionType);
+ Function fn = connectionTypeVariable.getPossiblePropertyValue(graph, DIA.symbolFunction);
+ modi = Simantics.applySCLRead(graph, fn, elementVariable);
+ }
+ }
+ }
+
+ if(modi == null) return null;
// If element is moved, recalculate style
Object transform = graph.getPossibleRelatedValue(element, DIA.HasTransform);
}
}
+ private Map<Object,SingleElementNode> buildSingleElementMap(INode node) {
+ Map<Object,SingleElementNode> elements = new HashMap<>();
+ NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> {
+ elements.put(n.getKey(), n);
+ return null;
+ });
+ return elements;
+ }
+
@Override
public void applyStyleForNode(EvaluationContext evaluationContext, INode node, Pair<G2DNodeModification, Object> result) {
- if (result == null || result.first == null)
+
+ if (result == null || result.first == null)
return;
+ Map<Object,SingleElementNode> elements = null;
+
G2DNodeModification modification = result.first;
- if (modification.svgAssignments != null && !modification.svgAssignments.isEmpty()) {
- for (SVGNode p : NodeUtil.collectNodes(node, SVGNode.class)) {
- p.setAssignments(modification.svgAssignments);
+
+ if(node instanceof ConnectionNode) {
+
+ if (modification.svgAssignments != null && !modification.svgAssignments.isEmpty()) {
+ INode child = NodeUtil.getFirstChild(node);
+ if(child instanceof RouteGraphNode) {
+ RouteGraphNode rgn = (RouteGraphNode)child;
+ rgn.setAssignments(modification.svgAssignments);
+ }
+ }
+
+ } else if(node instanceof SingleElementNode) {
+
+ Map<SVGNode, List<SVGNodeAssignment>> assignmentMap = new HashMap<>();
+
+ if (modification.svgAssignments != null && !modification.svgAssignments.isEmpty()) {
+ for (SVGNode p : NodeUtil.collectNodes(node, SVGNode.class)) {
+ List<SVGNodeAssignment> list = assignmentMap.get(p);
+ if(list == null) {
+ list = new ArrayList<>();
+ assignmentMap.put(p, list);
+ }
+ list.addAll(modification.svgAssignments);
+ }
+ }
+
+ if(modification.targetedSVGAssignments != null && !modification.targetedSVGAssignments.isEmpty()) {
+ elements = buildSingleElementMap(node);
+ for(TargetedSVGNodeAssignment ass : modification.targetedSVGAssignments) {
+ SingleElementNode sen = elements.get(ass.singleElementKey);
+ for (SVGNode p : NodeUtil.collectNodes(sen, SVGNode.class)) {
+ List<SVGNodeAssignment> list = assignmentMap.get(p);
+ if(list == null) {
+ list = new ArrayList<>();
+ assignmentMap.put(p, list);
+ }
+ list.add(ass);
+ }
+ }
+ }
+
+ for(Map.Entry<SVGNode, List<SVGNodeAssignment>> entry : assignmentMap.entrySet()) {
+ SVGNode p = entry.getKey();
+ p.setAssignments(entry.getValue());
p.cleanDiagramCache();
+ }
+
+ if (modification.transformAssignments != null) {
+ Map<Object,AffineTransform> trs = new HashMap<>();
+ for (TransformationAssignment ass : modification.transformAssignments)
+ trs.put(ass.key, ass.transform);
+ NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> {
+ Object key = n.getKey();
+ AffineTransform tr = trs.get(key);
+ if (tr != null) {
+ IG2DNode[] children = n.getSortedNodes();
+ if (children.length > 0)
+ children[0].setTransform(tr);
+ }
+ return null;
+ });
}
+
}
- if (modification.transformAssignments != null) {
- Map<Object,AffineTransform> trs = new HashMap<>();
- for (TransformationAssignment ass : modification.transformAssignments)
- trs.put(ass.key, ass.transform);
- NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> {
- Object key = n.getKey();
- AffineTransform tr = trs.get(key);
- if (tr != null) {
- IG2DNode[] children = n.getSortedNodes();
- if (children.length > 0)
- children[0].setTransform(tr);
- }
- return null;
- });
- }
+
}
}
ArrayList<Resource> result = new ArrayList<>();
for(Resource contribution : query.find(graph, index)) {
- result.add(graph.getSingleObject(contribution, DIA.ProfileEntryContribution_HasEntry));
+ for(Resource entry : graph.getObjects(contribution, DIA.ProfileEntryContribution_HasEntry)) {
+ result.add(entry);
+ }
+
}
return result;
org.simantics.scl.runtime;bundle-version="0.1.4",
org.simantics.databoard;bundle-version="0.6.3",
com.lowagie.text;bundle-version="2.1.7";resolution:=optional,
- org.simantics.utils;bundle-version="1.1.0"
+ org.simantics.utils;bundle-version="1.1.0",
+ org.slf4j.api
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ClassPath: .,
lib/svgSalamander-tiny.jar,
import java.util.List;
import org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment;
+import org.simantics.scenegraph.g2d.nodes.TargetedSVGNodeAssignment;
import org.simantics.scenegraph.g2d.nodes.TransformationAssignment;
/**
*/
public class G2DNodeModification {
public List<SVGNodeAssignment> svgAssignments;
+ public List<TargetedSVGNodeAssignment> targetedSVGAssignments;
public List<TransformationAssignment> transformAssignments;
public G2DNodeModification(List<SVGNodeAssignment> svgAssignments, List<TransformationAssignment> transformAssignments) {
this.svgAssignments = svgAssignments;
this.transformAssignments = transformAssignments;
}
+ public G2DNodeModification(List<SVGNodeAssignment> svgAssignments, List<TargetedSVGNodeAssignment> targetedSVGAssignments, List<TransformationAssignment> transformAssignments) {
+ this.svgAssignments = svgAssignments;
+ this.targetedSVGAssignments = targetedSVGAssignments;
+ this.transformAssignments = transformAssignments;
+ }
+ public static G2DNodeModification create3(List<SVGNodeAssignment> svgAssignments, List<TargetedSVGNodeAssignment> targetedSVGAssignments, List<TransformationAssignment> transformAssignments) {
+ return new G2DNodeModification(svgAssignments, targetedSVGAssignments, transformAssignments);
+ }
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.WeakHashMap;
import org.simantics.scenegraph.ExportableWidget.RasterOutputWidget;
diagramCache = null;
}
- // NOTE: hard-coded to assume all SVG data is encoded in UTF-8
- byte[] dataBytes = data.getBytes("UTF-8");
+
+ // Lets check for rootAssignment that contributes the whole SVG
+ SVGNodeAssignment rootAssignment = null;
+ if (!assignments.isEmpty()) {
+ for (SVGNodeAssignment ass : assignments) {
+ if (ass.attributeNameOrId.equals("$root")) {
+ rootAssignment = ass;
+ break;
+ }
+ }
+ }
+ byte[] dataBytes;
+ if (rootAssignment != null) {
+ dataBytes = rootAssignment.value.getBytes("UTF-8");
+ } else {
+ // NOTE: hard-coded to assume all SVG data is encoded in UTF-8
+ dataBytes = data.getBytes("UTF-8");
+ }
dataHash = digest(dataBytes, assignments);
URI uri = univ.loadSVG(new ByteArrayInputStream(dataBytes), dataHash);
diagramCache = univ.getDiagram(uri, false);
if (diagramCache != null) {
univ.incRefCount(diagramCache.getXMLBase());
-
- if (diagramCache.getRoot() == null) {
+ SVGRoot root = diagramCache.getRoot();
+ if (root == null) {
univ.decRefCount(diagramCache.getXMLBase());
diagramCache = univ.getDiagram(univ.loadSVG(BROKEN_SVG_DATA), false);
dataHash = "broken";
univ.incRefCount(diagramCache.getXMLBase());
bbox = (Rectangle2D) diagramCache.getRoot().getBoundingBox().clone();
} else {
- bbox = diagramCache.getRoot().getBoundingBox();
+ bbox = root.getBoundingBox();
if (bbox.isEmpty()) {
- univ.decRefCount(diagramCache.getXMLBase());
- diagramCache = univ.getDiagram(univ.loadSVG(EMPTY_SVG_DATA), false);
- dataHash = "empty";
- univ.incRefCount(diagramCache.getXMLBase());
- bbox = (Rectangle2D) diagramCache.getRoot().getBoundingBox().clone();
+ // Lets check if this should be visible or not
+ Set presentationAttributes = root.getPresentationAttributes();
+ if (!presentationAttributes.contains("display")) {
+ // TODO: fix this - How can one read values of attributes in SVG salamander???
+ univ.decRefCount(diagramCache.getXMLBase());
+ diagramCache = univ.getDiagram(univ.loadSVG(EMPTY_SVG_DATA), false);
+ dataHash = "empty";
+ univ.incRefCount(diagramCache.getXMLBase());
+ bbox = (Rectangle2D) root.getBoundingBox().clone();
+ } else {
+ bbox = new Rectangle2D.Double(0, 0, 0, 0);
+ }
} else {
if (applyAssignments(diagramCache, assignments)) {
- bbox = (Rectangle2D) diagramCache.getRoot().getBoundingBox().clone();
+ bbox = (Rectangle2D) root.getBoundingBox().clone();
} else {
bbox = (Rectangle2D) bbox.clone();
}
return false;
boolean changed = false;
for (SVGNodeAssignment ass : assignments) {
+// System.err.println("assign: " + ass.elementId + " " + ass.attributeNameOrId + " " + ass.value);
+// if("opacity".equals(ass.attributeNameOrId))
+// System.err.println("faaf");
SVGElement e = diagram.getElement(ass.elementId);
if (e != null) {
if ("$text".equals(ass.attributeNameOrId)) {
--- /dev/null
+package org.simantics.scenegraph.g2d.nodes;
+
+/**
+ * @author Antti Villberg
+ * @since 1.29.0
+ */
+public class TargetedSVGNodeAssignment extends SVGNodeAssignment {
+ public Object singleElementKey;
+ public TargetedSVGNodeAssignment(Object singleElementKey, String elementId, String attributeNameOrId, String value) {
+ super(elementId, attributeNameOrId, value);
+ this.singleElementKey = singleElementKey;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((singleElementKey == null) ? 0 : singleElementKey.hashCode());
+ result = prime * result + ((attributeNameOrId == null) ? 0 : attributeNameOrId.hashCode());
+ result = prime * result + ((elementId == null) ? 0 : elementId.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TargetedSVGNodeAssignment other = (TargetedSVGNodeAssignment) obj;
+ if (singleElementKey == null) {
+ if (other.singleElementKey != null)
+ return false;
+ } else if (!singleElementKey.equals(other.singleElementKey))
+ return false;
+ if (attributeNameOrId == null) {
+ if (other.attributeNameOrId != null)
+ return false;
+ } else if (!attributeNameOrId.equals(other.attributeNameOrId))
+ return false;
+ if (elementId == null) {
+ if (other.elementId != null)
+ return false;
+ } else if (!elementId.equals(other.elementId))
+ return false;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+
+}
\ No newline at end of file
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Constructor;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import org.simantics.diagram.connection.RouteGraph;
import org.simantics.scenegraph.g2d.events.command.Commands;
import org.simantics.scenegraph.g2d.nodes.GridNode;
import org.simantics.scenegraph.g2d.nodes.LinkNode;
+import org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment;
import org.simantics.scenegraph.g2d.nodes.connection.HighlightActionPointsAction.Action;
import org.simantics.scenegraph.g2d.nodes.connection.HighlightActionPointsAction.Pick;
import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
+import org.simantics.scenegraph.utils.ColorUtil;
import org.simantics.scenegraph.utils.GeometryUtils;
import org.simantics.scenegraph.utils.InitValueSupport;
import org.simantics.scenegraph.utils.NodeUtil;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
import gnu.trove.map.hash.THashMap;
*/
public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, InitValueSupport {
- private static final long serialVersionUID = -917194130412280965L;
+ private static final Logger LOGGER = LoggerFactory.getLogger(RouteGraphNode.class);
+
+ private static final long serialVersionUID = -917194130412280965L;
private static final double TOLERANCE = IAction.TOLERANCE;
private static final Stroke SELECTION_STROKE = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
protected transient Map<Object,ILineEndStyle> dynamicStyles = null;
-
+
private transient boolean ignoreSelection = false;
@Override
wrapRenderer();
}
+ private static float tryParseFloat(String s, float def) {
+ try {
+ return Float.parseFloat(s);
+ } catch (NumberFormatException e) {
+ LOGGER.error("Could not parse '" + s + "' into float.");
+ return def;
+ }
+ }
+
+ /*
+ * 1.0 BUTT MITER 1.0 0.0
+ */
+ private static Stroke parseStroke(String definition) {
+
+ float width = 1.0f;
+ int cap = BasicStroke.CAP_BUTT;
+ int join = BasicStroke.JOIN_MITER;
+ float miterLimit = 1.0f;
+ float[] dash = { 1, 0};
+ float dash_phase = 0;
+
+ String[] parts = definition.split(" ");
+
+ if(parts.length > 0) {
+ width = tryParseFloat(parts[0], width);
+ }
+ if(parts.length > 1) {
+ if("BUTT".equals(parts[1])) cap = BasicStroke.CAP_BUTT;
+ else if("ROUND".equals(parts[1])) cap = BasicStroke.CAP_ROUND;
+ else if("SQUARE".equals(parts[1])) cap = BasicStroke.CAP_SQUARE;
+ }
+ if(parts.length > 2) {
+ if("BEVEL".equals(parts[2])) cap = BasicStroke.JOIN_BEVEL;
+ else if("MITER".equals(parts[2])) cap = BasicStroke.JOIN_MITER;
+ else if("ROUND".equals(parts[2])) cap = BasicStroke.JOIN_ROUND;
+ }
+ if(parts.length > 3) {
+ miterLimit = tryParseFloat(parts[3], miterLimit);
+ }
+ if(parts.length > 4) {
+ dash_phase = tryParseFloat(parts[4], dash_phase);
+ }
+ if(parts.length > 6) {
+ dash = new float[parts.length - 5];
+ for(int i=5;i<parts.length;i++) {
+ dash[i-5] = tryParseFloat(parts[i], 1.0f);
+ }
+ }
+
+
+ try {
+ return new BasicStroke(width, cap, join, miterLimit, dash, dash_phase);
+ } catch (IllegalArgumentException e) {
+ return new BasicStroke();
+ }
+
+ }
+
+ public void setAssignments(List<SVGNodeAssignment> assignments) {
+ for(SVGNodeAssignment ass : assignments) {
+ if("dynamicColor".equals(ass.elementId)) {
+ setDynamicColor(ColorUtil.hexColor(ass.value));
+ } else if("dynamicStroke".equals(ass.elementId)) {
+ setDynamicStroke(parseStroke(ass.value));
+ }
+ }
+ }
+
public void setIgnoreSelection(boolean value) {
ignoreSelection = value;
}
if ( b > 255 ) b = 255;
return new Color(r, g, b, c.getAlpha());
- }
+ }
+
+ public static Color hexColor(String hex) {
+ if(hex.startsWith("#")) {
+ if(hex.length() == 4) {
+ int r = Character.digit(hex.charAt(1), 16);
+ int g = Character.digit(hex.charAt(2), 16);
+ int b = Character.digit(hex.charAt(3), 16);
+ return new Color(r+(r<<4), g+(g<<4), b+(b<<4));
+ } else if(hex.length() == 7) {
+ return new Color(Integer.parseInt(hex.substring(1), 16));
+ }
+ }
+ return Color.BLACK;
+ }
}