import java.util.Collections;\r
import java.util.List;\r
\r
-import org.simantics.Simantics;\r
import org.simantics.charts.editor.ChartData;\r
import org.simantics.charts.editor.ChartKeys;\r
import org.simantics.databoard.binding.error.BindingException;\r
import org.simantics.db.Resource;\r
import org.simantics.db.common.request.PossibleIndexRoot;\r
import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.variable.Variable;\r
import org.simantics.history.HistoryException;\r
import org.simantics.history.HistorySamplerItem;\r
import org.simantics.history.ItemManager;\r
import org.simantics.modeling.subscription.SubscriptionItem;\r
import org.simantics.modeling.subscription.SubscriptionItemQuery;\r
import org.simantics.project.IProject;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+import org.simantics.simulation.experiment.IExperiment;\r
\r
/**\r
* Main facade for externally dealing with the trending system.\r
}\r
}\r
\r
- public static HistorySamplerItem createHistorySamplerItem(ReadGraph graph, Resource subscriptionItem) throws DatabaseException {\r
- \r
- try {\r
-\r
- Resource model = graph.syncRequest(new PossibleIndexRoot(subscriptionItem));\r
- if ( model == null ) {\r
- throw new DatabaseException("There is no model for " + subscriptionItem);\r
- }\r
-\r
- Key chartDataKey = ChartKeys.chartSourceKey(model);\r
+ public static HistorySamplerItem createHistorySamplerItem(ReadGraph graph, Variable run, Resource subscriptionItem) throws DatabaseException {\r
+ IExperiment exp = (IExperiment) run.getPropertyValue(graph, "iExperiment");\r
+ ITrendSupport support = exp.getService(ITrendSupport.class);\r
+ ChartData data = support.getChartData();\r
+ return createHistorySamplerItem(graph, subscriptionItem, data);\r
+ }\r
\r
- final ChartData data = Simantics.getProject().getHint(chartDataKey);\r
- if ( data == null ) {\r
- throw new DatabaseException("There is no chart data for " + model);\r
- }\r
+ public static HistorySamplerItem createHistorySamplerItem(ReadGraph graph, Resource subscriptionItem, ChartData data) throws DatabaseException {\r
\r
- ItemManager im = new ItemManager( data.history.getItems() );\r
+ try {\r
+ Resource model = graph.syncRequest(new PossibleIndexRoot(subscriptionItem));\r
+ if (model == null) {\r
+ throw new DatabaseException("There is no model for " + subscriptionItem);\r
+ }\r
\r
- SubscriptionItem i = graph.syncRequest(new SubscriptionItemQuery(subscriptionItem));\r
+ ItemManager im = new ItemManager(data.history.getItems());\r
\r
- List<Bean> items = im.search("variableId", i.variableId);\r
- Collections.sort(items, SamplingFormat.INTERVAL_COMPARATOR);\r
- if (items.isEmpty()) new DatabaseException("There is history item for " + i.variableId);\r
- Bean config = items.get(0);\r
- String historyId = (String) config.getFieldUnchecked("id");\r
+ SubscriptionItem i = graph.syncRequest(new SubscriptionItemQuery(subscriptionItem));\r
\r
- return new HistorySamplerItem(data.collector, data.history, historyId, System.identityHashCode(data));\r
+ List<Bean> items = im.search("variableId", i.variableId);\r
+ Collections.sort(items, SamplingFormat.INTERVAL_COMPARATOR);\r
+ if (items.isEmpty())\r
+ new DatabaseException("There is history item for " + i.variableId);\r
+ Bean config = items.get(0);\r
+ String historyId = (String) config.getFieldUnchecked("id");\r
\r
- } catch (HistoryException e) {\r
- throw new DatabaseException(e);\r
- } catch (BindingException e) {\r
- throw new DatabaseException(e);\r
- }\r
- \r
- }\r
+ return new HistorySamplerItem(data.collector, data.history, historyId, System.identityHashCode(data));\r
+ } catch (HistoryException e) {\r
+ throw new DatabaseException(e);\r
+ } catch (BindingException e) {\r
+ throw new DatabaseException(e);\r
+ }\r
+ }\r
\r
}\r
package org.simantics.charts;\r
\r
+import org.simantics.charts.editor.ChartData;\r
import org.simantics.db.ReadGraph;\r
import org.simantics.db.exception.DatabaseException;\r
\r
\r
void setChartData(ReadGraph graph) throws DatabaseException;\r
\r
+ ChartData getChartData();\r
+ \r
}\r
*******************************************************************************/\r
package org.simantics.diagram.elements;\r
\r
-import gnu.trove.list.array.TIntArrayList;\r
-\r
import java.awt.AlphaComposite;\r
import java.awt.BasicStroke;\r
import java.awt.Color;\r
import java.util.ArrayList;\r
import java.util.Arrays;\r
import java.util.Hashtable;\r
+import java.util.List;\r
\r
import org.simantics.datatypes.literal.RGB;\r
import org.simantics.db.layer0.variable.RVI;\r
import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent;\r
import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
+import org.simantics.scenegraph.g2d.events.NodeEventHandler;\r
import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
import org.simantics.scenegraph.g2d.events.command.Commands;\r
-import org.simantics.scenegraph.g2d.events.NodeEventHandler;\r
import org.simantics.scenegraph.utils.GeometryUtils;\r
import org.simantics.scenegraph.utils.NodeUtil;\r
import org.simantics.scl.runtime.function.Function1;\r
import org.simantics.scl.runtime.function.Function2;\r
import org.simantics.ui.colors.Colors;\r
import org.simantics.ui.dnd.LocalObjectTransferable;\r
+import org.simantics.ui.dnd.MultiTransferable;\r
+import org.simantics.ui.dnd.PlaintextTransfer;\r
import org.simantics.ui.fonts.Fonts;\r
import org.simantics.utils.threads.AWTThread;\r
\r
import com.lowagie.text.pdf.PdfWriter;\r
import com.lowagie.text.pdf.TextField;\r
\r
+import gnu.trove.list.array.TIntArrayList;\r
+\r
\r
/**\r
* TextNode which supports in-line editing.\r
if (isHovering()\r
&& (isControlDown(e) || isShiftDown(e))\r
&& e.context instanceof NodeEventHandler\r
- && dataRVI != null)\r
+ && (dataRVI != null || text != null))\r
{\r
- e.transferable = new LocalObjectTransferable(dataRVI);\r
+ List<Transferable> trs = new ArrayList<>(2);\r
+ if (dataRVI != null) {\r
+ trs.add(new LocalObjectTransferable(dataRVI));\r
+ trs.add(new PlaintextTransfer(dataRVI.toString()));\r
+ } else if (text != null && !text.isEmpty()) {\r
+ trs.add(new PlaintextTransfer(text));\r
+ }\r
+ if (!trs.isEmpty()) {\r
+ e.transferable = new MultiTransferable(trs);\r
+ return true;\r
+ }\r
}\r
return false;\r
}\r
@Override\r
public int getEventMask() {\r
return EventTypes.KeyPressedMask | EventTypes.MouseMovedMask | EventTypes.MouseButtonPressedMask\r
- | EventTypes.MouseClickMask | EventTypes.CommandMask;\r
+ | EventTypes.MouseClickMask | EventTypes.MouseDragBeginMask | EventTypes.CommandMask;\r
}\r
\r
private MouseEvent lastMouseEvent = null;\r
\r
import java.util.ArrayList;\r
import java.util.Collections;\r
+import java.util.Optional;\r
import java.util.concurrent.CopyOnWriteArrayList;\r
import java.util.concurrent.TimeUnit;\r
\r
import org.eclipse.jface.viewers.SelectionChangedEvent;\r
import org.eclipse.jface.viewers.StructuredSelection;\r
import org.eclipse.ui.IWorkbenchPartSite;\r
+import org.simantics.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
import org.simantics.diagram.elements.AdaptableImmutableProxyElement;\r
import org.simantics.g2d.canvas.ICanvasContext;\r
import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;\r
import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
import org.simantics.g2d.canvas.impl.HintReflection.HintListener;\r
+import org.simantics.g2d.diagram.participant.ElementJSON;\r
import org.simantics.g2d.diagram.participant.Selection;\r
import org.simantics.g2d.element.ElementHints;\r
import org.simantics.g2d.element.IElement;\r
+import org.simantics.ui.selection.WorkbenchSelectionUtils;\r
import org.simantics.utils.datastructures.hints.IHintObservable;\r
import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
import org.simantics.utils.threads.IThreadWorkQueue;\r
* \r
* @author Tuukka Lehtonen\r
*/\r
-public class WorkbenchSelectionProvider extends AbstractCanvasParticipant implements IPostSelectionProvider {\r
+public class WorkbenchSelectionProvider extends AbstractCanvasParticipant implements IPostSelectionProvider, ElementJSON {\r
\r
private static final long POST_SELECTION_DELAY = 300;\r
\r
System.out.println("WorkbenchSelectionProvider: TODO: set selection: " + selection);\r
}\r
\r
+ @Override\r
+ public Optional<String> getJSON(IElement element) {\r
+ ISelection sel = constructAdaptableSelection(Collections.singleton(element));\r
+ try {\r
+ return Optional.ofNullable( WorkbenchSelectionUtils.getPossibleJSON(sel) );\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ return Optional.empty();\r
+ }\r
+ }\r
+\r
}\r
void createSession(String sessionGUID, IConsole console);\r
void deleteSession(String sessionGUID);\r
void setInputURI(String sessionGUID, String inputURI);\r
+ void setSessionParameter(String sessionGUID, String parameterName, Object value);\r
public IJSONResult requestDocument(String document, int sequenceNumber, int pollingHint, String sessionGUID);\r
public String requestDocumentURI(String alias);\r
String requestCSS(String documentURI);\r
public static boolean selected(IJSONObject object) {\r
return getValueOrDefault(object, "selected", false);\r
}\r
- \r
+\r
+ public static boolean followEditMode(IJSONObject object) {\r
+ return getValueOrDefault(object, "followEditMode", true);\r
+ }\r
+\r
public static String getType(IJSONObject object) {\r
String result = (String)object.getValue("type");\r
if(result == null) throw new IllegalStateException("No type for object " + object);\r
import "Simantics/DB"\r
import "Simantics/Variables"\r
+import "JavaBuiltin" as Java\r
\r
importJava "org.simantics.document.server.io.IConsole" where\r
data IConsole\r
addMessage :: IConsole -> String -> <Proc> ()\r
+ sendEvent :: IConsole -> String -> String -> Vector Dynamic -> <Proc> ()\r
\r
importJava "org.simantics.document.server.io.IDocument" where\r
data IDocument\r
\r
putValue :: CommandContextMutable -> String -> a -> <Proc> CommandContextMutable\r
\r
+ merge :: CommandContextMutable -> CommandContext -> <Proc> CommandContextMutable \r
+\r
importJava "org.simantics.document.server.io.CommandContextImpl" where\r
\r
@JavaName create\r
commandContext :: () -> CommandContextMutable\r
\r
+instance Coercible CommandContextMutable CommandContext where\r
+ coerce = Java.unsafeCoerce\r
+\r
+cloneCommandContext :: CommandContext -> <Proc> CommandContextMutable\r
+cloneCommandContext context = merge (commandContext ()) context\r
+\r
importJava "org.simantics.document.server.io.CommandResult" where\r
data CommandResult\r
\r
package org.simantics.document.server.request;\r
\r
+import java.util.HashMap;\r
import java.util.List;\r
import java.util.Map;\r
\r
import org.simantics.db.Resource;\r
import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
import org.simantics.db.common.request.IndexRoot;\r
-import org.simantics.db.common.request.UnaryRead;\r
import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.request.VariableRead;\r
import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext;\r
import org.simantics.db.layer0.scl.AbstractExpressionCompilationRequest;\r
import org.simantics.db.layer0.util.RuntimeEnvironmentRequest;\r
import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.document.server.Functions;\r
+import org.simantics.document.server.bean.DataDefinition;\r
import org.simantics.document.server.request.ServerSCLHandlerValueRequest.CompilationContext;\r
import org.simantics.layer0.Layer0;\r
+import org.simantics.scl.compiler.constants.StringConstant;\r
import org.simantics.scl.compiler.elaboration.expressions.EApply;\r
import org.simantics.scl.compiler.elaboration.expressions.EConstant;\r
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;\r
+import org.simantics.scl.compiler.elaboration.expressions.EVar;\r
import org.simantics.scl.compiler.elaboration.expressions.EVariable;\r
import org.simantics.scl.compiler.elaboration.expressions.Expression;\r
import org.simantics.scl.compiler.elaboration.modules.SCLValue;\r
\r
public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationRequest<CompilationContext, Variable> {\r
\r
+ private final Variable context;\r
private final Pair<Resource,Resource> componentTypeAndRoot;\r
private final Resource literal;\r
\r
}\r
}\r
\r
- private ServerSCLHandlerValueRequest(Pair<Resource,Resource> componentTypeAndRoot, Resource literal) {\r
+ private ServerSCLHandlerValueRequest(Variable context, Pair<Resource,Resource> componentTypeAndRoot, Resource literal) {\r
assert(literal != null);\r
+ this.context = context;\r
this.literal = literal;\r
this.componentTypeAndRoot = componentTypeAndRoot;\r
}\r
\r
public ServerSCLHandlerValueRequest(ReadGraph graph, Variable context) throws DatabaseException {\r
- this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph));\r
+ this(context, getComponentTypeAndRoot(graph, context), context.getRepresents(graph));\r
}\r
\r
private static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Variable property) throws DatabaseException {\r
}\r
\r
@Override\r
- protected CompilationContext getCompilationContext(ReadGraph graph)\r
- throws DatabaseException {\r
- return graph.syncRequest(new UnaryRead<Pair<Resource,Resource>,CompilationContext>(componentTypeAndRoot) {\r
+ protected CompilationContext getCompilationContext(ReadGraph graph) throws DatabaseException {\r
+ \r
+ return graph.syncRequest(new VariableRead<CompilationContext>(context) {\r
+ \r
@Override\r
- public CompilationContext perform(ReadGraph graph)\r
- throws DatabaseException {\r
+ public CompilationContext perform(ReadGraph graph) throws DatabaseException {\r
+ \r
+ Pair<Resource,Resource> parameter = getComponentTypeAndRoot(graph, variable);\r
RuntimeEnvironment runtimeEnvironment = graph.syncRequest(getRuntimeEnvironmentRequest(parameter.second));\r
+ \r
Map<String, ComponentTypeProperty> propertyMap =\r
graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()),\r
TransientCacheListener.<Map<String, ComponentTypeProperty>>instance());\r
+\r
+// Map<String, ComponentTypeProperty> result = new HashMap<String,ComponentTypeProperty>(propertyMap); \r
+// for(DataDefinition dd : Functions.dataDefinitions(graph, variable)) {\r
+// result.put(dd.target, null);\r
+// }\r
+ \r
return new CompilationContext(runtimeEnvironment, propertyMap);\r
+ \r
}\r
+ \r
});\r
+ \r
}\r
\r
@Override\r
return getPropertyFlexible(environment, accessInputVariable(environment, contextVariable), name, type);\r
}\r
\r
-\r
@Override\r
protected Expression getVariableAccessExpression(\r
ReadGraph graph,\r
contextVariable,\r
name,\r
property.type == null ? Types.metaVar(Kinds.STAR) : property.type);\r
- else\r
+ else {\r
+ \r
+// if(context.propertyMap.containsKey(name)) {\r
+// \r
+// org.simantics.scl.compiler.elaboration.expressions.Variable parametersVariable = new org.simantics.scl.compiler.elaboration.expressions.Variable("context", COMMAND_CONTEXT);\r
+// \r
+// Environment environment = context.runtimeEnvironment.getEnvironment();\r
+// \r
+//// return new EApply(\r
+//// new EConstant(environment.getValue(FROM_DYNAMIC), Types.STRING),\r
+// return new EApply(\r
+// new EConstant(environment.getValue(CONTEXT_VARIABLE), Types.DYNAMIC),\r
+// new EVariable(parametersVariable),\r
+// new ELiteral(new StringConstant(name)));\r
+// \r
+// }\r
+ \r
return getSpecialVariableAccessExpression(graph, context, contextVariable, name);\r
+ \r
+ }\r
}\r
\r
protected Expression getSpecialVariableAccessExpression(ReadGraph graph,\r
\r
@Override\r
public int hashCode() {\r
- return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode();\r
+ final int prime = 31;\r
+ int result = 1;\r
+ result = prime * result + ((context == null) ? 0 : context.hashCode());\r
+ return result;\r
}\r
\r
@Override\r
public boolean equals(Object obj) {\r
- if(this == obj)\r
+ if (this == obj)\r
return true;\r
- if(obj == null || obj.getClass() != getClass())\r
+ if (obj == null)\r
+ return false;\r
+ if (getClass() != obj.getClass())\r
return false;\r
- ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest)obj;\r
- return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot);\r
+ ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest) obj;\r
+ if (context == null) {\r
+ if (other.context != null)\r
+ return false;\r
+ } else if (!context.equals(other.context))\r
+ return false;\r
+ return true;\r
}\r
+\r
+// @Override\r
+// public int hashCode() {\r
+// return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode();\r
+// }\r
+//\r
+// @Override\r
+// public boolean equals(Object obj) {\r
+// if(this == obj)\r
+// return true;\r
+// if(obj == null || obj.getClass() != getClass())\r
+// return false;\r
+// ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest)obj;\r
+// return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot);\r
+// }\r
+ \r
}\r
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2016 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * Semantum Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g2d.diagram.participant;\r
+\r
+import java.util.Optional;\r
+\r
+import org.simantics.g2d.canvas.ICanvasParticipant;\r
+import org.simantics.g2d.element.IElement;\r
+\r
+/**\r
+ * @author Antti Villberg\r
+ */\r
+public interface ElementJSON extends ICanvasParticipant {\r
+ \r
+ /**\r
+ * @param element\r
+ * @return JSON that describes the provided diagram element\r
+ */\r
+ public Optional<String> getJSON(IElement element);\r
+\r
+}\r
ConnectionNode holder = e.getHint(sgKey);\r
if (holder == null) {\r
holder = parentNode.addNode(ElementUtils.generateNodeId(e), ConnectionNode.class);\r
+ holder.setTransferableProvider(new ElementTransferableProvider(getContext(), e));\r
e.setHint(sgKey, holder);\r
holder.setZIndex(parentNode.getNodeCount() + 1);\r
}\r
SingleElementNode holder = e.getHint(sgKey);\r
if (holder == null) {\r
holder = parentNode.addNode(ElementUtils.generateNodeId(e), SingleElementNode.class);\r
+ holder.setTransferableProvider(new ElementTransferableProvider(getContext(), e));\r
e.setHint(sgKey, holder);\r
holder.setZIndex(parentNode.getNodeCount() + 1);\r
}\r
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2016 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * Semantum Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g2d.diagram.participant;\r
+\r
+import java.awt.datatransfer.Transferable;\r
+\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.scenegraph.g2d.nodes.TransferableProvider;\r
+import org.simantics.ui.dnd.PlaintextTransfer;\r
+\r
+/**\r
+ * @author Antti Villberg, Tuukka Lehtonen\r
+ */\r
+public class ElementTransferableProvider implements TransferableProvider {\r
+\r
+ final private ICanvasContext context;\r
+ final private IElement element;\r
+ \r
+ public ElementTransferableProvider(ICanvasContext context, IElement element) {\r
+ this.context = context;\r
+ this.element = element;\r
+ }\r
+ \r
+ @Override\r
+ public Transferable create() {\r
+ ElementJSON converter = context.getAtMostOneItemOfClass(ElementJSON.class);\r
+ if (converter == null)\r
+ return null;\r
+ return converter.getJSON(element).map(PlaintextTransfer::new).orElse(null);\r
+ }\r
+\r
+}\r
import org.simantics.databoard.type.Datatype;\r
import org.simantics.db.exception.DatabaseException;\r
import org.simantics.db.layer0.variable.NodeSupport;\r
+import org.simantics.modeling.ModelingResources;\r
import org.simantics.scl.compiler.types.Type;\r
import org.simantics.simulator.variable.Realm;\r
import org.simantics.simulator.variable.exceptions.NodeManagerException;\r
\r
@Override\r
public String getPropertyURI(String parent, String property) {\r
- return "http://www.simantics.org/Modeling-1.2/CommandSession/hasValue";\r
+ return ModelingResources.URIs.SCLCommandSession_hasValue;\r
}\r
}\r
import java.awt.dnd.DragSourceDropEvent;\r
import java.awt.dnd.DragSourceEvent;\r
import java.awt.dnd.DragSourceListener;\r
+import java.awt.event.InputEvent;\r
import java.awt.geom.Point2D;\r
import java.util.ArrayList;\r
import java.util.Arrays;\r
import java.util.Comparator;\r
+import java.util.List;\r
\r
import org.simantics.scenegraph.INode;\r
import org.simantics.scenegraph.g2d.G2DFocusManager;\r
import org.simantics.scenegraph.g2d.IG2DNode;\r
import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
+import org.simantics.scenegraph.g2d.events.adapter.AWTMouseEventAdapter;\r
import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
/**\r
private static final boolean DEBUG_EVENTS = false;\r
private static final boolean DEBUG_HANDLER_SORT = false;\r
\r
+ private static final IEventHandler[] NONE = {};\r
+\r
public static class TreePreOrderComparator implements Comparator<IEventHandler> {\r
\r
static enum Order {\r
TreePreOrderComparator COMPARATOR = new TreePreOrderComparator(TreePreOrderComparator.Order.DESCENDING);\r
\r
/**\r
- * FocusEvents are propagated to event handlers in undefined order.\r
+ * {@link FocusEvent} are propagated first to the scene graph focus node,\r
+ * then to event handler nodes in scene graph tree pre-order.\r
*/\r
- protected ListenerList<IEventHandler> focusListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
+ protected List<IEventHandler> focusListeners = new ArrayList<IEventHandler>();\r
+ protected IEventHandler[] sortedFocusListeners = null;\r
\r
/**\r
- * TimeEvents are propagated to events handlers in an undefined order.\r
+ * {@link TimeEvent} are propagated first to the scene graph focus node,\r
+ * then to event handler nodes in scene graph tree pre-order.\r
*/\r
- protected ListenerList<IEventHandler> timeListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
+ protected List<IEventHandler> timeListeners = new ArrayList<IEventHandler>();\r
+ protected IEventHandler[] sortedTimeListeners = null;\r
\r
/**\r
- * CommandEvents are propagated first to the scene graph focus node, then to\r
- * event handler nodes in scene graph tree pre-order.\r
+ * {@link CommandEvent} are propagated first to the scene graph focus node,\r
+ * then to event handler nodes in scene graph tree pre-order.\r
*/\r
- protected ListenerList<IEventHandler> commandListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
+ protected List<IEventHandler> commandListeners = new ArrayList<IEventHandler>();\r
protected IEventHandler[] sortedCommandListeners = null;\r
\r
/**\r
- * KeyEvents are propagated first to the scene graph focus node, then to\r
- * event handler nodes in scene graph tree pre-order.\r
+ * {@link KeyEvent} are propagated first to the scene graph focus node, then\r
+ * to event handler nodes in scene graph tree pre-order.\r
*/\r
- protected ListenerList<IEventHandler> keyListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
+ protected List<IEventHandler> keyListeners = new ArrayList<IEventHandler>();\r
protected IEventHandler[] sortedKeyListeners = null;\r
\r
/**\r
- * MouseEvents are propagated first to the scene graph focus node, then to\r
- * event handler nodes in scene graph tree pre-order.\r
+ * {@link MouseEvent} are propagated first to the scene graph focus node,\r
+ * then to event handler nodes in scene graph tree pre-order.\r
*/\r
- protected ListenerList<IEventHandler> mouseListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
+ protected List<IEventHandler> mouseListeners = new ArrayList<IEventHandler>();\r
protected IEventHandler[] sortedMouseListeners = null;\r
+\r
+ /**\r
+ * {@link MouseDragBegin} events are propagated first to the scene graph focus node, then\r
+ * to event handler nodes in scene graph tree pre-order.\r
+ */\r
+ protected List<IEventHandler> mouseDragBeginListeners = new ArrayList<IEventHandler>();\r
+ protected IEventHandler[] sortedMouseDragBeginListeners = null;\r
/**\r
* The scene graph this instance handles event propagation for.\r
*/\r
protected G2DSceneGraph sg;\r
- \r
- protected DragSource ds = new DragSource();\r
+\r
+ /**\r
+ * For proper initiation of native DnD operations within this AWT-based\r
+ * scenegraph system.\r
+ */\r
+ protected DragSource ds = new DragSource();\r
public NodeEventHandler(G2DSceneGraph sg) {\r
this.sg = sg;
}
\r
+ @SuppressWarnings("unused")\r
private IEventHandler[] sort(IEventHandler[] sort) {\r
if (DEBUG_HANDLER_SORT)\r
- debug("sort " + sort.length + " handlers");\r
- IEventHandler[] copy = Arrays.copyOf(sort, sort.length);\r
- Arrays.sort(copy, COMPARATOR);\r
- return copy;\r
+ debug("copy sort " + sort.length + " handlers");\r
+ return sortInplace(Arrays.copyOf(sort, sort.length));\r
}\r
- \r
- public void setRootPane(Component rootPane) {\r
- \r
- final DragSourceListener dsl = new DragSourceListener() {\r
- \r
- @Override\r
- public void dropActionChanged(DragSourceDragEvent dsde) {\r
- }\r
- \r
- @Override\r
- public void dragOver(DragSourceDragEvent dsde) {\r
- }\r
- \r
- @Override\r
- public void dragExit(DragSourceEvent dse) {\r
- }\r
- \r
- @Override\r
- public void dragEnter(DragSourceDragEvent dsde) {\r
- }\r
- \r
- @Override\r
- public void dragDropEnd(DragSourceDropEvent dsde) {\r
- }\r
- };\r
- ds.createDefaultDragGestureRecognizer(rootPane, DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK, new DragGestureListener() {\r
- \r
- @Override\r
- public void dragGestureRecognized(DragGestureEvent dge) {\r
- MouseDragBegin event = new MouseDragBegin(NodeEventHandler.this,\r
- 0, 0, 0, 0, 0,\r
- new Point2D.Double(),new Point2D.Double(),\r
- new Point2D.Double(),new Point2D.Double());\r
- handleMouseEvent(event, EventTypes.MouseDragBegin);\r
- if(event.transferable != null) {\r
- ds.startDrag(dge, null, event.transferable, dsl);\r
- if (DEBUG_EVENTS)\r
- debug("dragGestureRecognized: startDrag " + event.transferable);\r
- }\r
- }\r
- });\r
- ds.addDragSourceListener(dsl);\r
- \r
+\r
+ private IEventHandler[] sortInplace(IEventHandler[] sort) {\r
+ if (DEBUG_HANDLER_SORT)\r
+ debug("in-place sort " + sort.length + " handlers");\r
+ Arrays.sort(sort, COMPARATOR);\r
+ return sort;\r
}\r
\r
-// @Override
-// public void mouseReleased(MouseEvent event) {
-// Point op = event.getPoint();
-// for (MouseListener l : mouseListeners.getListeners()) {
-// MouseEvent e = (MouseEvent) NodeUtil.transformEvent(event,(IG2DNode) l);
-// l.mouseReleased(e);
-// event.translatePoint((int)(op.getX()-event.getX()), (int)(op.getY()-event.getY()));
-// if (e.isConsumed())
-// break;
-// }
-// }
-//
-// @Override
-// public void mouseMoved(MouseEvent event) {
-// for (MouseMotionListener l : mouseMotionListeners.getListeners()) {
-// MouseEvent e = (MouseEvent) NodeUtil.transformEvent(event,(IG2DNode) l);
-// l.mouseMoved(e);
-// if (e.isConsumed())
-// break;
-// }
-// }
+ public void setRootPane(Component rootPane) {\r
+ final DragSourceListener dsl = new DragSourceListener() {\r
+ @Override\r
+ public void dropActionChanged(DragSourceDragEvent dsde) {\r
+ }\r
+ @Override\r
+ public void dragOver(DragSourceDragEvent dsde) {\r
+ }\r
+ @Override\r
+ public void dragExit(DragSourceEvent dse) {\r
+ }\r
+ @Override\r
+ public void dragEnter(DragSourceDragEvent dsde) {\r
+ }\r
+ @Override\r
+ public void dragDropEnd(DragSourceDropEvent dsde) {\r
+ }\r
+ };\r
+ DragGestureListener dgl = new DragGestureListener() {\r
+ @Override\r
+ public void dragGestureRecognized(DragGestureEvent dge) {\r
+ InputEvent ie = dge.getTriggerEvent();\r
+ if (ie instanceof java.awt.event.MouseEvent) {\r
+ java.awt.event.MouseEvent e = (java.awt.event.MouseEvent) ie;\r
+ Point2D controlPos = AWTMouseEventAdapter.getControlPosition(e);\r
+ MouseDragBegin event = new MouseDragBegin(NodeEventHandler.this,\r
+ e.getWhen(), 0,\r
+ AWTMouseEventAdapter.getButtonStatus(e),\r
+ AWTMouseEventAdapter.getStateMask(e),\r
+ AWTMouseEventAdapter.getMouseButton(e),\r
+ // TODO: fix canvas position if necessary\r
+ new Point2D.Double(),\r
+ controlPos,\r
+ controlPos,\r
+ AWTMouseEventAdapter.getScreenPosition(e));\r
+\r
+ // Send MouseDragBegin to the scenegraph and see\r
+ // if anyone sets event.transferable to start DnD.\r
+ handleMouseDragBeginEvent(event, EventTypes.MouseDragBegin);\r
+ if (event.transferable != null) {\r
+ ds.startDrag(dge, null, event.transferable, dsl);\r
+ if (DEBUG_EVENTS)\r
+ debug("dragGestureRecognized: startDrag " + event.transferable);\r
+ }\r
+ }\r
+ }\r
+ };\r
+ ds.createDefaultDragGestureRecognizer(\r
+ rootPane,\r
+ DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK,\r
+ dgl);\r
+ ds.addDragSourceListener(dsl);\r
+ }\r
public boolean mousePressed(MouseButtonPressedEvent event) {\r
G2DFocusManager.INSTANCE.clearFocus();\r
}\r
}\r
\r
- private boolean handleMouseEvent(MouseEvent e, int eventType) {\r
- IEventHandler[] sorted = sortedMouseListeners;\r
- if (sorted == null)\r
- sortedMouseListeners = sorted = sort(mouseListeners.getListeners());\r
- return handleEvent(e, sg.getFocusNode(), sorted);\r
- }\r
-\r
private boolean handleEvent(Event e, IG2DNode focusNode, IEventHandler[] handlers) {\r
+ int typeMask = EventTypes.toTypeMask(e);\r
if (focusNode instanceof IEventHandler) {\r
IEventHandler h = (IEventHandler) focusNode;\r
- if (eats(h.getEventMask(), EventTypes.toTypeMask(e))) {\r
+ if (eats(h.getEventMask(), typeMask)) {\r
if (h.handleEvent(e))\r
return true;\r
}\r
}\r
for (IEventHandler l : handlers) {\r
- if (l.handleEvent(e))\r
- return true;\r
+ if (eats(l.getEventMask(), typeMask)) {\r
+ if (l.handleEvent(e))\r
+ return true;\r
+ }\r
}\r
return false;\r
}\r
\r
+ private boolean handleMouseEvent(MouseEvent e, int eventType) {\r
+ IEventHandler[] sorted = sortedMouseListeners;\r
+ if (sorted == null)\r
+ sortedMouseListeners = sorted = sortInplace(mouseListeners.toArray(NONE));\r
+ return handleEvent(e, sg.getFocusNode(), sorted);\r
+ }\r
+\r
+ private boolean handleMouseDragBeginEvent(MouseEvent e, int eventType) {\r
+ IEventHandler[] sorted = sortedMouseDragBeginListeners;\r
+ if (sorted == null)\r
+ sortedMouseDragBeginListeners = sorted = sortInplace(mouseDragBeginListeners.toArray(NONE));\r
+ // Give null for focusNode because we want to propagate\r
+ // this event in scene tree pre-order only.\r
+ return handleEvent(e, null, sorted);\r
+ }\r
+\r
private boolean handleFocusEvent(FocusEvent e) {\r
- return handleEvent(e, null, focusListeners.getListeners());\r
+ IEventHandler[] sorted = sortedFocusListeners;\r
+ if (sorted == null)\r
+ sortedFocusListeners = sorted = sortInplace(focusListeners.toArray(NONE));\r
+ return handleEvent(e, null, sorted);\r
}\r
\r
private boolean handleTimeEvent(TimeEvent e) {\r
- return handleEvent(e, null, timeListeners.getListeners());\r
+ IEventHandler[] sorted = sortedTimeListeners;\r
+ if (sorted == null)\r
+ sortedTimeListeners = sorted = sortInplace(timeListeners.toArray(NONE));\r
+ return handleEvent(e, null, sorted);\r
}\r
\r
private boolean handleCommandEvent(CommandEvent e) {\r
IEventHandler[] sorted = sortedCommandListeners;\r
if (sorted == null)\r
- sortedCommandListeners = sorted = sort(commandListeners.getListeners());\r
+ sortedCommandListeners = sorted = sortInplace(commandListeners.toArray(NONE));\r
return handleEvent(e, sg.getFocusNode(), sorted);\r
}\r
\r
private boolean handleKeyEvent(KeyEvent e) {\r
IEventHandler[] sorted = sortedKeyListeners;\r
if (sorted == null)\r
- sortedKeyListeners = sorted = sort(keyListeners.getListeners());\r
+ sortedKeyListeners = sorted = sortInplace(keyListeners.toArray(NONE));\r
return handleEvent(e, sg.getFocusNode(), sorted);\r
}\r
case EventTypes.KeyReleased:\r
return handleKeyEvent((KeyEvent) e);\r
\r
+ case EventTypes.MouseDragBegin:\r
+ return handleMouseDragBeginEvent((MouseEvent) e, eventType);\r
+\r
case EventTypes.MouseButtonPressed:\r
case EventTypes.MouseButtonReleased:\r
case EventTypes.MouseClick:\r
case EventTypes.MouseDoubleClick:\r
- case EventTypes.MouseDragBegin:\r
case EventTypes.MouseEnter:\r
case EventTypes.MouseExit:\r
case EventTypes.MouseMoved:\r
}\r
if (eats(mask, EventTypes.FocusMask)) {\r
focusListeners.add(item);\r
+ sortedFocusListeners = null;\r
}\r
if (eats(mask, EventTypes.KeyMask)) {\r
keyListeners.add(item);\r
sortedKeyListeners = null;\r
}\r
- if (eats(mask, EventTypes.MouseMask)) {\r
+ if (eats(mask, EventTypes.MouseDragBeginMask)) {\r
+ mouseDragBeginListeners.add(item);\r
+ sortedMouseDragBeginListeners = null;\r
+ }\r
+ if (eats(mask, EventTypes.MouseMask & ~EventTypes.MouseDragBeginMask)) {\r
mouseListeners.add(item);\r
sortedMouseListeners = null;\r
}\r
if (eats(mask, EventTypes.TimeMask)) {\r
timeListeners.add(item);\r
+ sortedTimeListeners = null;\r
}\r
}\r
\r
}\r
if (eats(mask, EventTypes.FocusMask)) {\r
removed |= focusListeners.remove(item);\r
+ sortedFocusListeners = null;\r
}\r
if (eats(mask, EventTypes.KeyMask)) {\r
removed |= keyListeners.remove(item);\r
sortedKeyListeners = null;\r
}\r
- if (eats(mask, EventTypes.MouseMask)) {\r
+ if (eats(mask, EventTypes.MouseDragBeginMask)) {\r
+ removed |= mouseDragBeginListeners.remove(item);\r
+ sortedMouseDragBeginListeners = null;\r
+ }\r
+ if (eats(mask, EventTypes.MouseMask & ~EventTypes.MouseDragBeginMask)) {\r
removed |= mouseListeners.remove(item);\r
sortedMouseListeners = null;\r
}\r
if (eats(mask, EventTypes.TimeMask)) {\r
removed |= timeListeners.remove(item);\r
+ sortedTimeListeners = null;\r
}\r
return removed;\r
}\r
super(sender, queue);\r
}\r
\r
- private Point2D getControlPosition(MouseEvent e)\r
+ public static Point2D getControlPosition(MouseEvent e)\r
{\r
return new Point2D.Double(e.getX(), e.getY());\r
}\r
\r
- private Point2D getScreenPosition(MouseEvent e)\r
+ public static Point2D getScreenPosition(MouseEvent e)\r
{\r
return e.getLocationOnScreen();\r
}\r
\r
- private static int getStateMask(MouseEvent e) {\r
+ public static int getStateMask(MouseEvent e) {\r
int modifiers = e.getModifiersEx();\r
int stateMask = 0;\r
if((modifiers & InputEvent.CTRL_DOWN_MASK) != 0)\r
return stateMask;\r
}\r
\r
- private int getMouseButton(MouseEvent e)\r
+ public static int getMouseButton(MouseEvent e)\r
{\r
int awtMouseButton = e.getButton();\r
if (awtMouseButton == MouseEvent.BUTTON1)\r
* @param e\r
* @return\r
*/\r
- private int getButtonStatus(MouseEvent e) {\r
+ public static int getButtonStatus(MouseEvent e) {\r
int modex = e.getModifiersEx();\r
int status = 0;\r
status |= (modex & MouseEvent.BUTTON1_DOWN_MASK) != 0 ? org.simantics.scenegraph.g2d.events.MouseEvent.LEFT_MASK : 0;\r
import java.awt.Color;\r
import java.awt.Composite;\r
import java.awt.Stroke;\r
+import java.awt.geom.Point2D;\r
\r
+import org.simantics.diagram.connection.RouteGraph;\r
import org.simantics.scenegraph.INode;\r
import org.simantics.scenegraph.g2d.IG2DNode;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent;\r
import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode;\r
import org.simantics.scenegraph.utils.InitValueSupport;\r
import org.simantics.scenegraph.utils.NodeUtil;\r
}\r
}\r
\r
+ @Override\r
+ protected boolean hitTest(MouseEvent event) {\r
+ if (!super.hitTest(event))\r
+ return false;\r
+\r
+ Point2D pos = NodeUtil.worldToLocal(this, event.controlPosition, new Point2D.Double());\r
+ double tolerance = 0.5;\r
+ // TODO: change tolerance based on zoom level\r
+\r
+ for (IG2DNode child : getSortedNodes()) {\r
+ if (child instanceof RouteGraphNode) {\r
+ RouteGraphNode rgn = (RouteGraphNode) child;\r
+ RouteGraph rg = rgn.getRouteGraph();\r
+ Object pick = rg.pickLine(pos.getX(), pos.getY(), tolerance);\r
+ if (pick != null)\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
}\r
import java.awt.AlphaComposite;\r
import java.awt.Composite;\r
import java.awt.Graphics2D;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
\r
import org.simantics.scenegraph.g2d.IG2DNode;\r
+import org.simantics.scenegraph.g2d.events.EventTypes;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
import org.simantics.scenegraph.utils.InitValueSupport;\r
+import org.simantics.scenegraph.utils.NodeUtil;\r
\r
public class SingleElementNode extends TransformNode implements InitValueSupport {\r
- /**\r
- * \r
- */\r
+\r
private static final long serialVersionUID = -4982578347433716440L;\r
\r
+ private TransferableProvider transferableProvider;\r
protected Composite composite;\r
protected Boolean visible = Boolean.TRUE;\r
protected Boolean hidden = Boolean.FALSE;\r
\r
+ public void setTransferableProvider(TransferableProvider transferableProvider) {\r
+ if (transferableProvider != this.transferableProvider) {\r
+ if (this.transferableProvider != null)\r
+ removeEventHandler(this);\r
+ if (transferableProvider != null)\r
+ addEventHandler(this);\r
+ this.transferableProvider = transferableProvider;\r
+ }\r
+ }\r
+\r
@Override\r
public boolean validate() {\r
return visible && !hidden;\r
return sb.toString();\r
}\r
\r
-// private INode findChild(String key) {\r
-//\r
-// INode result = getNode(key);\r
-// if(result != null) return result;\r
-//\r
-// for(Map.Entry<String, IG2DNode> entry : children.entrySet()) {\r
-//\r
-// if(!(entry.getValue() instanceof SingleElementNode)) {\r
-// if(entry.getKey().startsWith(key)) return entry.getValue();\r
-// }\r
-//\r
-// }\r
-//\r
-// for(IG2DNode node : getNodes()) {\r
-//\r
-// if(node instanceof SingleElementNode) {\r
-//\r
-// result = ((SingleElementNode)node).findChild(key);\r
-// if(result != null) return result;\r
-//\r
-// }\r
-//\r
-// }\r
-//\r
-// return null;\r
-//\r
-// }\r
-\r
protected Composite alphaComposite = null;\r
\r
@PropertySetter("alpha")\r
this.alphaComposite = alphaComposite;\r
}\r
\r
-// public void setValue(String key, Object value) {\r
-//\r
-// if ("alpha".equals(key)) {\r
-// Float val = Float.parseFloat((String)value);\r
-// alphaComposite = AlphaComposite.getInstance(AlphaComposite. SRC_OVER, val);\r
-// } else {\r
-//\r
-// String[] parts = key.split("\\.");\r
-// if(parts.length != 2) return;\r
-//\r
-// INode child = findChild(parts[0]);\r
-//\r
-// if(child == null) return;\r
-//\r
-//// child.setValue(parts[1], value);\r
-//\r
-// }\r
-//\r
-// }\r
-\r
@Override\r
public void initValues() {\r
alphaComposite = null;\r
}\r
}\r
\r
+ @Override\r
+ public void cleanup() {\r
+ if (transferableProvider != null) {\r
+ removeEventHandler(this);\r
+ transferableProvider = null;\r
+ }\r
+ super.cleanup();\r
+ }\r
+\r
+ protected boolean isDragStartEvent(MouseEvent e) {\r
+ return e.isControlDown();\r
+ }\r
+\r
+ protected boolean hitTest(MouseEvent event) {\r
+ Rectangle2D bounds = super.getBoundsInLocal(false);\r
+ if (bounds == null)\r
+ return false;\r
+ Point2D localPos = NodeUtil.worldToLocal(this, event.controlPosition, new Point2D.Double());\r
+ double x = localPos.getX();\r
+ double y = localPos.getY();\r
+ boolean hit = bounds.contains(x, y);\r
+ return hit;\r
+ }\r
+\r
+ @Override\r
+ protected boolean mouseDragged(MouseDragBegin e) {\r
+ if (transferableProvider == null\r
+ || !isDragStartEvent(e)\r
+ || !hitTest(e))\r
+ return false;\r
+ e.transferable = transferableProvider.create();\r
+ return e.transferable != null;\r
+ }\r
+\r
+ @Override\r
+ public int getEventMask() {\r
+ return EventTypes.MouseDragBeginMask;\r
+ }\r
+\r
}\r
--- /dev/null
+package org.simantics.scenegraph.g2d.nodes;\r
+\r
+import java.awt.datatransfer.Transferable;\r
+\r
+public interface TransferableProvider {\r
+\r
+ public Transferable create();\r
+ \r
+}\r
import java.awt.datatransfer.Transferable;\r
import java.awt.datatransfer.UnsupportedFlavorException;\r
import java.io.IOException;\r
+import java.util.Collection;\r
import java.util.HashMap;\r
import java.util.Map;\r
\r
}\r
}\r
\r
+ public MultiTransferable(Collection<Transferable> tr) {\r
+ for(Transferable t : tr) {\r
+ for(DataFlavor f : t.getTransferDataFlavors()) {\r
+ transferables.put(f, t);\r
+ }\r
+ }\r
+ }\r
+\r
@Override\r
public void lostOwnership(Clipboard arg0, Transferable arg1) {\r
for(Transferable t : transferables.values())\r
return transferables.containsKey(arg0);\r
}\r
\r
+ @Override\r
+ public String toString() {\r
+ return "MultiTransferable " + transferables.toString();\r
+ }\r
+\r
}\r
import java.awt.datatransfer.DataFlavor;\r
import java.awt.datatransfer.Transferable;\r
import java.awt.datatransfer.UnsupportedFlavorException;\r
+import java.io.ByteArrayInputStream;\r
import java.io.IOException;\r
\r
public class PlaintextTransfer implements Transferable {\r
\r
final String content;\r
\r
+ final DataFlavor flavor = DataFlavor.getTextPlainUnicodeFlavor();\r
+ final DataFlavor[] flavors = new DataFlavor[] { flavor };\r
+ final String flavorCharset = flavor.getParameter("charset");\r
+ \r
public PlaintextTransfer(String content) {\r
this.content = content;\r
}\r
\r
@Override\r
public Object getTransferData(DataFlavor arg0) throws UnsupportedFlavorException, IOException {\r
- if(DataFlavor.getTextPlainUnicodeFlavor().equals(arg0)) {\r
- return content;\r
+ if(flavor.equals(arg0)) {\r
+ byte[] bytes = content.getBytes(flavorCharset);\r
+ return new ByteArrayInputStream(bytes);\r
}\r
return null;\r
}\r
\r
@Override\r
public DataFlavor[] getTransferDataFlavors() {\r
- return new DataFlavor[] { DataFlavor.getTextPlainUnicodeFlavor() };\r
+ return flavors;\r
}\r
\r
@Override\r
public boolean isDataFlavorSupported(DataFlavor arg0) {\r
- return(DataFlavor.getTextPlainUnicodeFlavor().equals(arg0));\r
+ return flavor.equals(arg0);\r
}\r
\r
}\r
--- /dev/null
+package org.simantics.utils.ui.workbench.dialogs;\r
+\r
+import java.io.IOException;\r
+import java.util.Deque;\r
+import java.util.LinkedList;\r
+\r
+import org.eclipse.core.runtime.preferences.InstanceScope;\r
+import org.eclipse.jface.layout.GridLayoutFactory;\r
+import org.eclipse.jface.preference.IPersistentPreferenceStore;\r
+import org.eclipse.jface.preference.IPreferenceStore;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Group;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.ui.IMemento;\r
+import org.eclipse.ui.preferences.ScopedPreferenceStore;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+import org.simantics.utils.ui.color.Color;\r
+import org.simantics.utils.ui.workbench.StringMemento;\r
+\r
+/**\r
+ * ColorDialog that keeps track used colors.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class ColorDialog extends org.simantics.utils.ui.color.ColorDialog{\r
+ \r
+ public ColorDialog(Shell parentShell) {\r
+ super(parentShell);\r
+ }\r
+\r
+ \r
+ protected Control createDialogArea(Composite parent) {\r
+ initRecent();\r
+ Composite composite = (Composite)super.createDialogArea(parent);\r
+ Group recentGroup = new Group(composite, SWT.NONE);\r
+ recentGroup.setText("Recent colors");\r
+ GridLayoutFactory.fillDefaults().numColumns(8).spacing(2, 2).margins(4, 4).applyTo(recentGroup);\r
+ int i = 0;\r
+ for (Color c : recentColors) {\r
+ i++;\r
+ createColorButton(recentGroup, c);\r
+ }\r
+ org.eclipse.swt.graphics.Color c = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);\r
+ Color color = new Color(c.getRGB());\r
+ for ( ; i < MAX_RECENT_COLORS; i++) {\r
+ Button button = createColorButton(recentGroup, color);\r
+ button.setEnabled(false);\r
+ }\r
+ return composite;\r
+ }\r
+ \r
+ @Override\r
+ protected Point getInitialSize() {\r
+ return new Point(400, 450);\r
+ }\r
+ \r
+ private static final int MAX_RECENT_COLORS = 8;\r
+ \r
+ public static final String RECENT_COLORS = "RECENT_COLORS";\r
+\r
+ private static final String TAG_COLORS = "color";\r
+ private static final String R_ATTR_NAME = "r";\r
+ private static final String G_ATTR_NAME = "g";\r
+ private static final String B_ATTR_NAME = "b";\r
+ \r
+ private static final String PLUGIN_ID = "org.simantics.utils.ui.workbench";\r
+ \r
+ protected Deque<Color> recentColors;\r
+ \r
+ private void initRecent() {\r
+ IPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID);\r
+ String recentString = store.getString(RECENT_COLORS);\r
+ recentColors = decodeColors(recentString);\r
+ }\r
+ \r
+ private void storeRecent() {\r
+ Color color = getColor();\r
+ recentColors.remove(color);\r
+ recentColors.addFirst(color);\r
+ while(recentColors.size() > MAX_RECENT_COLORS)\r
+ recentColors.removeLast();\r
+ \r
+ IPersistentPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID);\r
+ store.putValue(RECENT_COLORS, encodeColors(recentColors));\r
+ \r
+ if (store.needsSaving())\r
+ try { \r
+ store.save();\r
+ } catch (IOException e) {\r
+ ExceptionUtils.logError(e);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ protected void okPressed() {\r
+ storeRecent();\r
+ super.okPressed();\r
+ }\r
+ \r
+ public static Deque<Color> decodeColors(String recentColorsPref) {\r
+ Deque<Color> result = new LinkedList<Color>();\r
+ try {\r
+ StringMemento sm = new StringMemento(recentColorsPref);\r
+ for (IMemento m : sm.getChildren(TAG_COLORS)) {\r
+ try {\r
+ int r = m.getInteger(R_ATTR_NAME);\r
+ int g = m.getInteger(G_ATTR_NAME);\r
+ int b = m.getInteger(B_ATTR_NAME);\r
+ Color c = new Color(r, g, b);\r
+ result.add(c);\r
+ } catch (Exception e) {\r
+ \r
+ }\r
+ \r
+ }\r
+ } catch (IllegalArgumentException e) {\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ public static String encodeColors(Deque<Color> recentColors) {\r
+ StringMemento sm = new StringMemento();\r
+ for (Color c : recentColors) {\r
+ IMemento m = sm.createChild(TAG_COLORS);\r
+ m.putInteger(R_ATTR_NAME, c.getR());\r
+ m.putInteger(G_ATTR_NAME, c.getG());\r
+ m.putInteger(B_ATTR_NAME, c.getB());\r
+ }\r
+ return sm.toString();\r
+ }\r
+}\r
this.h = h;\r
this.s = s;\r
this.v = v;\r
- updateRGB(); \r
+ updateRGB(); \r
}\r
\r
public Color(double h, double s, double v) {\r
this.h = (float)h;\r
this.s = (float)s;\r
this.v = (float)v;\r
- updateRGB(); \r
+ updateRGB(); \r
}\r
\r
public Color(RGB rgb) {\r
}\r
\r
if (s == 0.f) {\r
- h = Float.NaN; // saturation is 0 -> achromatic color\r
+ //h = Float.NaN; // saturation is 0 -> achromatic color\r
+ h = 0.f;\r
} else {\r
if (tr == v) {\r
h = 60.f * (tg - tb);\r
*/\r
private void updateRGB() {\r
if (s == 0.f) {\r
- //if (Float.isNaN(h)) {\r
- h = Float.NaN;\r
- r = floatToInt(v);\r
- g = floatToInt(v);\r
- b = floatToInt(v);\r
- //} else {\r
- // throw new RuntimeException("Saturation is 0 -> Hue must be undefined");\r
- //}\r
+ r = floatToInt(v);\r
+ g = floatToInt(v);\r
+ b = floatToInt(v);\r
} else {\r
while (h < 0.f)\r
h+= 360.f;\r
*******************************************************************************/\r
package org.simantics.utils.ui.color;\r
\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.layout.GridLayoutFactory;\r
import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
import org.eclipse.swt.events.MouseEvent;\r
import org.eclipse.swt.events.MouseListener;\r
+import org.eclipse.swt.events.MouseMoveListener;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.graphics.GC;\r
import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.layout.GridData;\r
import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Canvas;\r
+import org.eclipse.swt.widgets.Button;\r
import org.eclipse.swt.widgets.Composite;\r
import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.TabFolder;\r
+import org.eclipse.swt.widgets.TabItem;\r
import org.eclipse.swt.widgets.Text;\r
\r
/**\r
public class ColorComposite extends Composite{\r
\r
\r
- private Color color = new Color(255,255,255);\r
+ private Color color;\r
private ColorGradient rGradient;\r
private ColorGradient gGradient;\r
private ColorGradient bGradient;\r
+ private ColorGradient hGradient;\r
+ private ColorGradient sGradient;\r
+ private ColorGradient vGradient;\r
private ColorGradient colorGradient;\r
\r
+ TabFolder tabFolder;\r
+ \r
Text rText;\r
Text gText;\r
Text bText;\r
- ColorGradientCanvas rCanvas;\r
- ColorGradientCanvas gCanvas;\r
- ColorGradientCanvas bCanvas;\r
+ IntGradientWidget rCanvas;\r
+ IntGradientWidget gCanvas;\r
+ IntGradientWidget bCanvas;\r
ColorGradientCanvas colorCanvas;\r
\r
+ Text hText;\r
+ Text sText;\r
+ Text vText;\r
+ GradientWidget hCanvas;\r
+ GradientWidget sCanvas;\r
+ GradientWidget vCanvas;\r
+ \r
+ Button dynamicButton;\r
+ \r
+ boolean dynamic = true;\r
+ \r
\r
public ColorComposite(Composite parent, int style) {\r
super(parent,style);\r
- updateGradients();\r
\r
GridLayout layout = new GridLayout();\r
- layout.makeColumnsEqualWidth = false;\r
- layout.numColumns = 3;\r
+ layout.makeColumnsEqualWidth = true;\r
+ layout.numColumns = 1;\r
this.setLayout(layout);\r
\r
colorCanvas = new ColorGradientCanvas(this,SWT.BORDER|SWT.HORIZONTAL);\r
- GridData colorCanvasData = new GridData();\r
- colorCanvasData.horizontalSpan = 3;\r
- colorCanvasData.heightHint = 32;\r
- colorCanvasData.widthHint = 600;\r
- colorCanvasData.grabExcessHorizontalSpace = true;\r
- colorCanvas.setLayoutData(colorCanvasData);\r
- \r
- //layout data used with labels\r
- GridData labelData = new GridData();\r
- labelData.widthHint = 30;\r
- //layout data used with gradients\r
- GridData gradientData = new GridData();\r
- gradientData.grabExcessHorizontalSpace = true;\r
- gradientData.heightHint = 16;\r
- gradientData.widthHint = 500;\r
- //layout data used with texts\r
- GridData textData = new GridData();\r
- textData.widthHint = 30;\r
- \r
- \r
- //Composite rComposite = new Composite(this,SWT.NONE);\r
- //Layout rLayout = new FillLayout(SWT.HORIZONTAL);\r
- //rComposite.setLayout(rLayout);\r
- Label rLabel = new Label(this,SWT.NONE);\r
+ \r
+ tabFolder = new TabFolder(this, SWT.NONE);\r
+ \r
+ TabItem rgbTab = new TabItem(tabFolder, SWT.NONE);\r
+ rgbTab.setText("RGB");\r
+ Composite rgbComposite = new Composite(tabFolder, SWT.NONE);\r
+ \r
+ rgbTab.setControl(rgbComposite);\r
+ \r
+ Label rLabel = new Label(rgbComposite,SWT.NONE);\r
rLabel.setText("Red");\r
- rLabel.setLayoutData(labelData);\r
- rCanvas = new ColorGradientCanvas(this,SWT.BORDER|SWT.HORIZONTAL);\r
- rCanvas.setLayoutData(gradientData);\r
- rText = new Text(this,SWT.BORDER);\r
- rText.setLayoutData(textData);\r
- rCanvas.addMouseListener(new ColorSelectListener(rCanvas) {\r
+ rCanvas = new IntGradientWidget(rgbComposite,SWT.BORDER|SWT.HORIZONTAL){\r
+ @Override\r
+ protected void updatePosition(int value) {\r
+ Color newColor = new Color(value,color.getG(),color.getB());\r
+ setColor(newColor);\r
+ }\r
+ };\r
+ rText = new Text(rgbComposite,SWT.BORDER);\r
+ rText.addModifyListener(new IntColorModifyListener() {\r
+ \r
+ @Override\r
void setValue(int value) {\r
Color newColor = new Color(value,color.getG(),color.getB());\r
- updateColor(newColor);\r
- };\r
+ setColor(newColor);\r
+ }\r
});\r
\r
- //Composite gComposite = new Composite(this,SWT.NONE);\r
- //Layout gLayout = new FillLayout(SWT.HORIZONTAL);\r
- //gComposite.setLayout(gLayout);\r
- Label gLabel = new Label(this,SWT.NONE);\r
+ Label gLabel = new Label(rgbComposite,SWT.NONE);\r
gLabel.setText("Green");\r
- gLabel.setLayoutData(labelData);\r
- gCanvas = new ColorGradientCanvas(this,SWT.BORDER|SWT.HORIZONTAL);\r
- gCanvas.setLayoutData(gradientData);\r
- gText = new Text(this,SWT.BORDER);\r
- gText.setLayoutData(textData);\r
- gCanvas.addMouseListener(new ColorSelectListener(gCanvas) {\r
+ gCanvas = new IntGradientWidget(rgbComposite,SWT.BORDER|SWT.HORIZONTAL) {\r
+ @Override\r
+ protected void updatePosition(int value) {\r
+ Color newColor = new Color(color.getR(),value,color.getB());\r
+ setColor(newColor);\r
+ }\r
+ };\r
+ gText = new Text(rgbComposite,SWT.BORDER);\r
+ gText.addModifyListener(new IntColorModifyListener() {\r
+ \r
+ @Override\r
void setValue(int value) {\r
Color newColor = new Color(color.getR(),value,color.getB());\r
- updateColor(newColor);\r
- };\r
+ setColor(newColor);\r
+ }\r
});\r
\r
- //Composite bComposite = new Composite(this,SWT.NONE);\r
- //Layout bLayout = new FillLayout(SWT.HORIZONTAL);\r
- //bComposite.setLayout(bLayout);\r
- Label bLabel = new Label(this,SWT.NONE);\r
+ Label bLabel = new Label(rgbComposite,SWT.NONE);\r
bLabel.setText("Blue");\r
- bLabel.setLayoutData(labelData);\r
- bCanvas = new ColorGradientCanvas(this,SWT.BORDER|SWT.HORIZONTAL);\r
- bCanvas.setLayoutData(gradientData);\r
- bText = new Text(this,SWT.BORDER);\r
- bText.setLayoutData(textData);\r
- bCanvas.addMouseListener(new ColorSelectListener(bCanvas) {\r
+ bCanvas = new IntGradientWidget(rgbComposite,SWT.BORDER|SWT.HORIZONTAL) {\r
+ @Override\r
+ protected void updatePosition(int value) {\r
+ Color newColor = new Color(color.getR(),color.getG(),value);\r
+ setColor(newColor);\r
+ }\r
+ };\r
+ bText = new Text(rgbComposite,SWT.BORDER);\r
+ bText.addModifyListener(new IntColorModifyListener() {\r
+ \r
+ @Override\r
void setValue(int value) {\r
Color newColor = new Color(color.getR(),color.getG(),value);\r
- updateColor(newColor);\r
- };\r
+ setColor(newColor);\r
+ }\r
});\r
- updateWidgets();\r
\r
- }\r
- \r
- private abstract class ColorSelectListener implements MouseListener {\r
- private Canvas canvas;\r
+ TabItem hsvTab = new TabItem(tabFolder, SWT.NONE);\r
+ hsvTab.setText("HSV");\r
+ Composite hsvComposite = new Composite(tabFolder, SWT.NONE);\r
\r
- public ColorSelectListener(Canvas canvas) {\r
- this.canvas = canvas;\r
- }\r
- public void mouseDoubleClick(MouseEvent e) {\r
- \r
- }\r
- public void mouseDown(MouseEvent e) {\r
- Rectangle r = this.canvas.getBounds();\r
- double d = (double)e.x / (double)r.width;\r
- int value = (int)(d * 255);\r
- if (value < 0)\r
- value = 0;\r
- if (value > 255)\r
- value = 255;\r
- setValue(value);\r
+ hsvTab.setControl(hsvComposite);\r
+ \r
+ Label hLabel = new Label(hsvComposite,SWT.NONE);\r
+ hLabel.setText("Hue");\r
+ hCanvas = new GradientWidget(hsvComposite,SWT.BORDER|SWT.HORIZONTAL) {\r
+ @Override\r
+ protected boolean updatePosition(double d) {\r
+ Color newColor = new Color(d*360.0,color.getS(),color.getV());\r
+ setColor(newColor);\r
+ return true;\r
+ }\r
\r
- }\r
- public void mouseUp(MouseEvent e) {\r
+ @Override\r
+ protected void setPosition(double d) {\r
+ super.setPosition(d/360.0);\r
+ }\r
+ };\r
+ hText = new Text(hsvComposite,SWT.BORDER);\r
+ hText.addModifyListener(new DoubleColorModifyListener(0.,360.) {\r
+ \r
+ @Override\r
+ void setValue(double value) {\r
+ Color newColor = new Color(value,color.getS(),color.getV());\r
+ setColor(newColor);\r
+ }\r
+ });\r
+ \r
+ Label sLabel = new Label(hsvComposite,SWT.NONE);\r
+ sLabel.setText("Saturation");\r
+ sCanvas = new GradientWidget(hsvComposite,SWT.BORDER|SWT.HORIZONTAL) {\r
+ @Override\r
+ protected boolean updatePosition(double d) {\r
+ Color newColor = new Color(color.getH(),d,color.getV());\r
+ setColor(newColor);\r
+ return true;\r
+ }\r
+ };\r
+ sText = new Text(hsvComposite,SWT.BORDER);\r
+ sText.addModifyListener(new DoubleColorModifyListener(0.,1.) {\r
+ \r
+ @Override\r
+ void setValue(double value) {\r
+ Color newColor = new Color(color.getH(),value,color.getV());\r
+ setColor(newColor);\r
+ }\r
+ });\r
+ \r
+ Label vLabel = new Label(hsvComposite,SWT.NONE);\r
+ vLabel.setText("Value");\r
+ vCanvas = new GradientWidget(hsvComposite,SWT.BORDER|SWT.HORIZONTAL) {\r
+ @Override\r
+ protected boolean updatePosition(double d) {\r
+ Color newColor = new Color(color.getH(),color.getS(),d);\r
+ setColor(newColor);\r
+ return true;\r
+ }\r
+ };\r
+ vText = new Text(hsvComposite,SWT.BORDER);\r
+ vText.addModifyListener(new DoubleColorModifyListener(0.,1.) {\r
+ \r
+ @Override\r
+ void setValue(double value) {\r
+ Color newColor = new Color(color.getH(),color.getS(),value);\r
+ setColor(newColor);\r
+ }\r
+ });\r
+ \r
+ TabItem settingsTab = new TabItem(tabFolder, SWT.NONE);\r
+ settingsTab.setText("Settings");\r
+ Composite settingsComposite = new Composite(tabFolder, SWT.NONE);\r
+ \r
+ settingsTab.setControl(settingsComposite);\r
+ \r
+ dynamicButton = new Button(settingsComposite, SWT.CHECK);\r
+ dynamicButton.setText("Dynamic widgets");\r
+ dynamicButton.setSelection(dynamic);\r
+ dynamicButton.addSelectionListener(new SelectionAdapter() {\r
+ @Override\r
+ public void widgetSelected(SelectionEvent e) {\r
+ dynamic = dynamicButton.getSelection();\r
+ updateWidgets();\r
+ }\r
+ });\r
+\r
+ GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).applyTo(rgbComposite);\r
+ GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).applyTo(hsvComposite);\r
+ GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).applyTo(settingsComposite);\r
+ GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(rgbComposite);\r
+ GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(hsvComposite);\r
+ GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(settingsComposite);\r
+ GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(tabFolder);\r
+ \r
+ GridDataFactory.fillDefaults().hint(-1, 32).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(colorCanvas);\r
+ GridDataFactory.fillDefaults().hint(-1, 16).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(rCanvas);\r
+ GridDataFactory.fillDefaults().hint(-1, 16).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(gCanvas);\r
+ GridDataFactory.fillDefaults().hint(-1, 16).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(bCanvas);\r
+ GridDataFactory.fillDefaults().hint(-1, 16).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(hCanvas);\r
+ GridDataFactory.fillDefaults().hint(-1, 16).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(sCanvas);\r
+ GridDataFactory.fillDefaults().hint(-1, 16).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(vCanvas);\r
+ GridDataFactory.fillDefaults().hint(20, 15).grab(false, false).applyTo(rText);\r
+ GridDataFactory.fillDefaults().hint(20, 15).grab(false, false).applyTo(gText);\r
+ GridDataFactory.fillDefaults().hint(20, 15).grab(false, false).applyTo(bText);\r
+ GridDataFactory.fillDefaults().hint(20, 15).grab(false, false).applyTo(hText);\r
+ GridDataFactory.fillDefaults().hint(20, 15).grab(false, false).applyTo(sText);\r
+ GridDataFactory.fillDefaults().hint(20, 15).grab(false, false).applyTo(vText);\r
+ \r
+ if (color == null)\r
+ setColor(new Color(255,255,255));\r
+ else\r
+ setColor(color);\r
+ }\r
+ \r
+ private abstract class IntColorModifyListener implements ModifyListener {\r
+ boolean modify = false;\r
+ @Override\r
+ public void modifyText(ModifyEvent e) {\r
+ if (internalUpdate)\r
+ return;\r
+ if (modify)\r
+ return;\r
+ modify = true;\r
+ Text text = (Text)e.widget;\r
+ try {\r
+ int value = Integer.parseInt(text.getText());\r
+ if (value < 0)\r
+ value = 0;\r
+ if (value > 255)\r
+ value = 255;\r
+ setValue(value);\r
+ } catch (NumberFormatException err) {\r
+ \r
+ }\r
+ modify = false;\r
\r
}\r
\r
abstract void setValue(int value);\r
}\r
+\r
+ private abstract class DoubleColorModifyListener implements ModifyListener {\r
+ boolean modify = false;\r
+ double min;\r
+ double max;\r
+ \r
+ public DoubleColorModifyListener( double min, double max) {\r
+ this.min = min;\r
+ this.max = max;\r
+ }\r
+ \r
+ @Override\r
+ public void modifyText(ModifyEvent e) {\r
+ if (internalUpdate)\r
+ return;\r
+ if (modify)\r
+ return;\r
+ modify = true;\r
+ Text text = (Text)e.widget;\r
+ try {\r
+ double value = Integer.parseInt(text.getText());\r
+ if (value < min) {\r
+ value = min;\r
+ } else if (value > max)\r
+ value = max;\r
+ setValue(value);\r
+ } catch (NumberFormatException err) {\r
+ \r
+ }\r
+ modify = false; \r
+ }\r
+\r
+ \r
+ abstract void setValue(double value);\r
+ }\r
\r
- private void updateColor(Color color) {\r
+ public void setColor(Color color) {\r
this.color = color;\r
updateWidgets();\r
}\r
\r
+ public Color getColor() {\r
+ return color;\r
+ }\r
+ \r
private void updateGradients() {\r
- rGradient = new ColorGradient(new ColorValue[]{\r
- new ColorValue(new Color(0,color.getG(),color.getB()),0.0),\r
- new ColorValue(new Color(255,color.getG(),color.getB()),1.0)});\r
- gGradient = new ColorGradient(new ColorValue[]{\r
- new ColorValue(new Color(color.getR(),0,color.getB()),0.0),\r
- new ColorValue(new Color(color.getR(),255,color.getB()),1.0)});\r
- bGradient = new ColorGradient(new ColorValue[]{\r
- new ColorValue(new Color(color.getR(),color.getG(),0),0.0),\r
- new ColorValue(new Color(color.getR(),color.getG(),255),1.0)});\r
+ if (dynamic) {\r
+ rGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(0,color.getG(),color.getB()),0.0),\r
+ new ColorValue(new Color(255,color.getG(),color.getB()),1.0)});\r
+ gGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(color.getR(),0,color.getB()),0.0),\r
+ new ColorValue(new Color(color.getR(),255,color.getB()),1.0)});\r
+ bGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(color.getR(),color.getG(),0),0.0),\r
+ new ColorValue(new Color(color.getR(),color.getG(),255),1.0)});\r
+ // hue is interpolated along the shortest route, using just 0 and 360 would result in constant color. \r
+ hGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(0.0,color.getS(),color.getV()),0.0),\r
+ new ColorValue(new Color(90.0,color.getS(),color.getV()),0.25),\r
+ new ColorValue(new Color(180.0,color.getS(),color.getV()),0.5),\r
+ new ColorValue(new Color(270.0,color.getS(),color.getV()),0.75),\r
+ new ColorValue(new Color(360.0,color.getS(),color.getV()),1.0)}, ColorGradient.HSV);\r
+ sGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(color.getH(),0.0,color.getV()),0.0),\r
+ new ColorValue(new Color(color.getH(),1.0,color.getV()),1.0)}, ColorGradient.HSV);\r
+ vGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(color.getH(),color.getS(),0.0),0.0),\r
+ new ColorValue(new Color(color.getH(),color.getS(),1.0),1.0)}, ColorGradient.HSV);\r
+ } else {\r
+ rGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(0,0,0),0.0),\r
+ new ColorValue(new Color(255,0,0),1.0)});\r
+ gGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(0,0,0),0.0),\r
+ new ColorValue(new Color(0,255,0),1.0)});\r
+ bGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(0,0,0),0.0),\r
+ new ColorValue(new Color(0,0,255),1.0)});\r
+ // hue is interpolated along the shortest route, using just 0 and 360 would result in constant color. \r
+ hGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(0.0,1.0,1.0),0.0),\r
+ new ColorValue(new Color(90.0,1.0,1.0),0.25),\r
+ new ColorValue(new Color(180.0,1.0,1.0),0.5),\r
+ new ColorValue(new Color(270.0,1.0,1.0),0.75),\r
+ new ColorValue(new Color(360.0,1.0,1.0),1.0)}, ColorGradient.HSV);\r
+ sGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(color.getH(),0.0,1.0),0.0),\r
+ new ColorValue(new Color(color.getH(),1.0,1.0),1.0)}, ColorGradient.HSV);\r
+ vGradient = new ColorGradient(new ColorValue[]{\r
+ new ColorValue(new Color(color.getH(),1.0,0.0),0.0),\r
+ new ColorValue(new Color(color.getH(),1.0,1.0),1.0)}, ColorGradient.HSV);\r
+ }\r
+ \r
colorGradient = new ColorGradient(new ColorValue[]{\r
new ColorValue(new Color(color.getR(),color.getG(),color.getB()),0.0)});\r
\r
}\r
\r
+ private boolean internalUpdate = false;\r
+ \r
private void updateWidgets() {\r
+ if (internalUpdate)\r
+ return;\r
+ internalUpdate = true;\r
updateGradients();\r
rCanvas.setGradient(rGradient);\r
gCanvas.setGradient(gGradient);\r
bCanvas.setGradient(bGradient);\r
+ hCanvas.setGradient(hGradient);\r
+ sCanvas.setGradient(sGradient);\r
+ vCanvas.setGradient(vGradient);\r
colorCanvas.setGradient(colorGradient);\r
- rText.setText(Integer.toString(color.getR()));\r
- gText.setText(Integer.toString(color.getG()));\r
- bText.setText(Integer.toString(color.getB())); \r
+ \r
+ rCanvas.setPosition(color.getR());\r
+ gCanvas.setPosition(color.getG());\r
+ bCanvas.setPosition(color.getB());\r
+ hCanvas.setPosition(color.getH());\r
+ sCanvas.setPosition(color.getS());\r
+ vCanvas.setPosition(color.getV());\r
+ \r
+ if(!rText.isFocusControl())\r
+ rText.setText(Integer.toString(color.getR()));\r
+ if(!gText.isFocusControl())\r
+ gText.setText(Integer.toString(color.getG()));\r
+ if(!bText.isFocusControl())\r
+ bText.setText(Integer.toString(color.getB()));\r
+ if(!hText.isFocusControl())\r
+ hText.setText(Double.toString(color.getH()));\r
+ if(!sText.isFocusControl())\r
+ sText.setText(Double.toString(color.getS()));\r
+ if(!vText.isFocusControl())\r
+ vText.setText(Double.toString(color.getV())); \r
+ internalUpdate = false;\r
+ }\r
+ \r
+ private abstract static class IntGradientWidget extends GradientWidget {\r
+\r
+ public IntGradientWidget(Composite parent, int style) {\r
+ super(parent, style);\r
+ }\r
+ \r
+ @Override\r
+ protected boolean updatePosition(double d) {\r
+ int value = (int)(d * 255);\r
+ if (value < 0)\r
+ value = 0;\r
+ if (value > 255)\r
+ value = 255;\r
+ updatePosition(value);\r
+ return true;\r
+ }\r
+ protected abstract void updatePosition(int value);\r
+ \r
+ protected void setPosition(int value) {\r
+ double d = ((double)value)/255.0;\r
+ setPosition(d);\r
+ }\r
+ \r
+ }\r
+ \r
+ private abstract static class GradientWidget extends ColorGradientCanvas {\r
+\r
+ int pos = -1;\r
+ double posD = -1.0;\r
+ \r
+ int size = 8;\r
+ int sized2 = 4;\r
+ \r
+ \r
+ \r
+ public GradientWidget(Composite parent, int style) {\r
+ super(parent, style);\r
+ this.addMouseListener(new MouseListener() { \r
+ @Override\r
+ public void mouseDown(MouseEvent e) {\r
+ if (e.button == 1) {\r
+ update(e);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void mouseUp(MouseEvent e) {}\r
+ @Override\r
+ public void mouseDoubleClick(MouseEvent e) {}\r
+ });\r
+ this.addMouseMoveListener(new MouseMoveListener() {\r
+ \r
+ @Override\r
+ public void mouseMove(MouseEvent e) {\r
+ if ((e.stateMask & SWT.BUTTON1)>0) {\r
+ update(e);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ \r
+ protected void update(MouseEvent e) {\r
+ Rectangle r = getClientArea();\r
+ double d;\r
+ if ((style & SWT.HORIZONTAL) > 0) {\r
+ d = (double)e.x / (double)r.width;\r
+ } else {\r
+ d = (double)e.y / (double)r.height;\r
+ }\r
+ if (d < 0.0)\r
+ d = 0.0;\r
+ else if (d > 1.0)\r
+ d = 1.0;\r
+ if (updatePosition(d)) {\r
+ if ((style & SWT.HORIZONTAL) > 0) {\r
+ pos = (int)(d*((double)r.width));\r
+ } else {\r
+ pos = (int)(d*((double)r.height));\r
+ }\r
+ posD = d;\r
+ }\r
+ }\r
+ \r
+ protected abstract boolean updatePosition(double d);\r
+ \r
+ protected void setPosition(double d) {\r
+ if (d == posD)\r
+ return;\r
+ _setPosition(d); \r
+ }\r
+ \r
+ private void _setPosition(double d) {\r
+ Rectangle r = getClientArea();\r
+ posD = d;\r
+ if (posD >= 0.0) {\r
+ if ((style & SWT.HORIZONTAL) > 0) {\r
+ pos = (int)(d * (double)r.width);\r
+ } else {\r
+ pos = (int)(d * (double)r.height);\r
+ }\r
+ } else {\r
+ pos = -1;\r
+ }\r
+ }\r
+ \r
+ Rectangle prevClip;\r
+ @Override\r
+ protected void paintGradient(GC gc, Rectangle clip) {\r
+ super.paintGradient(gc, clip);\r
+ if (!clip.equals(prevClip)) {\r
+ prevClip = clip;\r
+ _setPosition(posD);\r
+ }\r
+ \r
+ if (pos >= 0) {\r
+ org.eclipse.swt.graphics.Color white = new org.eclipse.swt.graphics.Color(gc.getDevice(), 255,255,255);\r
+ org.eclipse.swt.graphics.Color black = new org.eclipse.swt.graphics.Color(gc.getDevice(), 0, 0, 0);\r
+ gc.setForeground(black);\r
+ gc.setBackground(white);\r
+ int x;\r
+ int y;\r
+ if ((style & SWT.HORIZONTAL) > 0) {\r
+ x = pos;\r
+ y = clip.height / 2;\r
+ } else {\r
+ x = clip.width / 2;\r
+ y = pos;\r
+ }\r
+ gc.fillOval(x-sized2, y-sized2, size, size);\r
+ gc.drawOval(x-sized2, y-sized2, size, size);\r
+ \r
+ white.dispose();\r
+ black.dispose();\r
+ }\r
+ }\r
+ \r
}\r
}\r
--- /dev/null
+package org.simantics.utils.ui.color;\r
+\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.layout.GridLayoutFactory;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Group;\r
+import org.eclipse.swt.widgets.Shell;\r
+\r
+public class ColorDialog extends Dialog{\r
+ protected ColorComposite colorComposite;\r
+ protected Color value;\r
+ \r
+ public ColorDialog(Shell parentShell) {\r
+ super(parentShell); \r
+ }\r
+ \r
+ @Override\r
+ protected void configureShell(Shell newShell) {\r
+ super.configureShell(newShell);\r
+ newShell.setText("Color");\r
+ }\r
+\r
+ \r
+ public void setInitialValue(Color initialValue) {\r
+ this.value = new Color(initialValue);\r
+ }\r
+ \r
+ @Override\r
+ protected Point getInitialSize() {\r
+ return new Point(400, 400);\r
+ }\r
+ \r
+ @Override\r
+ protected Control createDialogArea(Composite parent) {\r
+ Composite composite = new Composite(parent, SWT.NONE);\r
+ GridLayoutFactory.fillDefaults().numColumns(1).margins(6, 0).applyTo(composite);\r
+ GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(composite);\r
+ colorComposite = new ColorComposite(composite, 0);\r
+ GridData childData = new GridData(GridData.FILL_BOTH);\r
+ colorComposite.setLayoutData(childData); \r
+ if (value != null)\r
+ colorComposite.setColor(value);\r
+ Group builtinGroup = new Group(composite, SWT.NONE);\r
+ builtinGroup.setText("System colors");\r
+ GridLayoutFactory.fillDefaults().numColumns(8).spacing(2, 2).margins(4, 4).applyTo(builtinGroup);\r
+ for (int i = SWT.COLOR_WHITE; i <= SWT.COLOR_DARK_GRAY; i++) {\r
+ org.eclipse.swt.graphics.Color c = Display.getCurrent().getSystemColor(i);\r
+ Color color = new Color(c.getRGB());\r
+ createColorButton(builtinGroup, color);\r
+ }\r
+ \r
+\r
+ return composite;\r
+ }\r
+ \r
+ protected Button createColorButton(Composite parent, Color color) {\r
+ Button button = new Button(parent, SWT.PUSH);\r
+ button.setImage(ColorIconCreator.createImage(color, 32, SWT.BORDER));\r
+ button.setData(color);\r
+ button.addSelectionListener(new SelectionAdapter() {\r
+ @Override\r
+ public void widgetSelected(SelectionEvent e) {\r
+ colorComposite.setColor(color);\r
+ }\r
+ });\r
+ return button;\r
+ }\r
+\r
+ \r
+ public Color getColor() {\r
+ return colorComposite.getColor();\r
+ }\r
+ \r
+\r
+}\r
import java.util.ArrayList;\r
import java.util.Collection;\r
import java.util.Collections;\r
+import java.util.List;\r
\r
import org.eclipse.swt.SWT;\r
import org.eclipse.swt.graphics.Color;\r
return type;\r
}\r
\r
- public Collection<ColorValue> getColorValues() {\r
+ public List<ColorValue> getColorValues() {\r
return values;\r
}\r
\r
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.utils.ui.color;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.ISelectionProvider;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.MouseEvent;\r
+import org.eclipse.swt.events.MouseListener;\r
+import org.eclipse.swt.events.MouseMoveListener;\r
+import org.eclipse.swt.graphics.Color;\r
+import org.eclipse.swt.graphics.GC;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Rectangle;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+\r
+/**\r
+ * \r
+ * Canvas that shows color gradients and color positions.\r
+ * Without READ_ONLY style the canvas allows user to drag color positions.\r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+public class ColorGradientAdjustingCanvas extends ColorGradientCanvas implements ISelectionProvider{\r
+ \r
+ ColorValue[] values;\r
+ int last;\r
+ int coords[];\r
+ int size = 8;\r
+ int sized2 = 4;\r
+ int width;\r
+ int height;\r
+ \r
+ int selectedValueIndex = -1;\r
+ \r
+ public ColorGradientAdjustingCanvas(Composite parent, int style) {\r
+ super(parent,style|SWT.DOUBLE_BUFFERED|SWT.NO_BACKGROUND);\r
+ addMouseListener(new MouseListener() {\r
+ \r
+ @Override\r
+ public void mouseUp(MouseEvent e) {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void mouseDown(MouseEvent e) {\r
+ // store and reset selection\r
+ int prev = selectedValueIndex;\r
+ selectedValueIndex = -1;\r
+ \r
+ // locate closest ColorValue, and select it.\r
+ int d = Integer.MAX_VALUE;\r
+ for (int i = 0; i <= last; i++) {\r
+ int x = coords[i*2];\r
+ int y = coords[i*2+1];\r
+ int dx = Math.abs(x - e.x);\r
+ int dy = Math.abs(y - e.y);\r
+ if ((dx < size) &&\r
+ (dy < size)) {\r
+ int dd = dx+dy;\r
+ if (dd < d) {\r
+ selectedValueIndex = i;\r
+ d = dd;\r
+ }\r
+ }\r
+ }\r
+ // if selection was changed, update it.\r
+ if (prev != selectedValueIndex) {\r
+ updateSelection();\r
+ redraw();\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void mouseDoubleClick(MouseEvent e) {\r
+ \r
+ }\r
+ });\r
+ if ((style&SWT.READ_ONLY) == 0) {\r
+ addMouseMoveListener(new MouseMoveListener() {\r
+ \r
+ @Override\r
+ public void mouseMove(MouseEvent e) {\r
+ if ((e.stateMask & SWT.BUTTON1)>0) {\r
+ if (selectedValueIndex > 0 && selectedValueIndex < last) {\r
+ double d;\r
+ if ((ColorGradientAdjustingCanvas.this.style | SWT.HORIZONTAL) > 0) {\r
+ d = (double)e.x/(double)width;\r
+ } else {\r
+ d = (double)e.y/(double)height;\r
+ }\r
+ double r = max-min;\r
+ d *= r;\r
+ d += min;\r
+ double offset = r*0.015;\r
+ if (d <= values[selectedValueIndex-1].getValue()+offset)\r
+ d = values[selectedValueIndex-1].getValue()+offset;\r
+ else if (d >= values[selectedValueIndex+1].getValue()-offset)\r
+ d = values[selectedValueIndex+1].getValue()-offset;\r
+ values[selectedValueIndex]._setValue(d);\r
+ calculateCoords(width, height);\r
+ redraw();\r
+ }\r
+ }\r
+ \r
+ }\r
+ });\r
+ }\r
+\r
+ }\r
+ \r
+ public void setGradient(ColorGradient gradient) {\r
+ int prevSize = 0;\r
+ if (values != null)\r
+ prevSize = values.length;\r
+ \r
+ values = gradient.getColorValueArray();\r
+ last = values.length-1;\r
+ coords = new int[values.length*2];\r
+ super.setGradient(gradient);\r
+ if (selectedValueIndex >= 0 && prevSize != values.length) {\r
+ selectedValueIndex = -1;\r
+ updateSelection();\r
+ } else {\r
+ updateSelection();\r
+ }\r
+ }\r
+ \r
+ double min;\r
+ double max;\r
+ \r
+ private void calculateCoords(int width, int height) {\r
+ this.width = width;\r
+ this.height = height;\r
+ \r
+ min = values[0].getValue();\r
+ max = values[last].getValue();\r
+ \r
+ if ((ColorGradientAdjustingCanvas.this.style & SWT.HORIZONTAL) > 0) {\r
+ for (int i = 0; i <= last ; i++) {\r
+ int y = height / 2;\r
+ double d = values[i].getValue();\r
+ int x = (int)(((d-min)/(max-min))*(double)width);\r
+ coords[i*2] = x;\r
+ coords[i*2+1] = y;\r
+ }\r
+ } else {\r
+ for (int i = 0; i <= last ; i++) {\r
+ int x = width / 2;\r
+ double d = values[i].getValue();\r
+ int y = (int)(((d-min)/(max-min))*(double)height);\r
+ coords[i*2] = x;\r
+ coords[i*2+1] = y;\r
+ }\r
+ }\r
+ }\r
+\r
+ \r
+ @Override\r
+ protected void paintGradient(GC gc, Rectangle clip) {\r
+ if (values != null && values.length > 0) {\r
+ Image image = gradient.getGradientImage(clip.width,clip.height,ColorGradientAdjustingCanvas.this.style);\r
+ gc.drawImage(image, 0, 0);\r
+ image.dispose(); \r
+ calculateCoords(clip.width, clip.height);\r
+\r
+ Color white = new Color(gc.getDevice(), 255,255,255);\r
+ Color yellow = new Color(gc.getDevice(), 255,230,0);\r
+ Color black = new Color(gc.getDevice(), 0, 0, 0);\r
+ for (int i = 0; i <= last ; i++) {\r
+ int x = coords[i*2];\r
+ int y = coords[i*2+1];\r
+ gc.setForeground(black);\r
+ if (selectedValueIndex == i)\r
+ gc.setBackground(yellow);\r
+ else\r
+ gc.setBackground(white);\r
+ if (i == 0 || i == last ) {\r
+ gc.fillRectangle(x-sized2, y-sized2, size, size);\r
+ gc.drawRectangle(x-sized2, y-sized2, size, size);\r
+ } else {\r
+ gc.fillOval(x-sized2, y-sized2, size, size);\r
+ gc.drawOval(x-sized2, y-sized2, size, size);\r
+ }\r
+ }\r
+ \r
+ white.dispose();\r
+ black.dispose();\r
+ yellow.dispose();\r
+ } else {\r
+ gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));\r
+ gc.fillRectangle(clip);\r
+ }\r
+ }\r
+ \r
+ private ISelection selection = new StructuredSelection();\r
+ private List<ISelectionChangedListener> listeners = new ArrayList<>();\r
+\r
+ @Override\r
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {\r
+ listeners.add(listener);\r
+ }\r
+\r
+ @Override\r
+ public ISelection getSelection() {\r
+ return selection;\r
+ }\r
+\r
+ @Override\r
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {\r
+ listeners.remove(listener);\r
+ }\r
+\r
+ @Override\r
+ public void setSelection(ISelection selection) {\r
+ ColorValue value = (ColorValue)((StructuredSelection)selection).getFirstElement();\r
+ selectedValueIndex = gradient.getColorValues().indexOf(value);\r
+ }\r
+ \r
+ private void updateSelection() {\r
+ if (selectedValueIndex < 0)\r
+ selection = new StructuredSelection();\r
+ else\r
+ selection = new StructuredSelection(values[selectedValueIndex]);\r
+ \r
+ for (ISelectionChangedListener l : listeners) {\r
+ l.selectionChanged(new SelectionChangedEvent(this, selection));\r
+ }\r
+ }\r
+ \r
+ public int getPointSize() {\r
+ return size;\r
+ }\r
+ \r
+ public void setPointSize(int size) {\r
+ this.size = size;\r
+ this.sized2 = size/2;\r
+ }\r
+ \r
+\r
+}\r
int style;\r
\r
public ColorGradientCanvas(Composite parent, int style) {\r
- // FIXME : use xor operation to get SWT.HORIZONTAL and SWT.VERTICAL\r
- // out of style when it's passed to parent\r
- super(parent,SWT.BORDER);\r
+ super(parent,(style|SWT.BORDER)&(~(SWT.VERTICAL|SWT.HORIZONTAL)));\r
this.style = style & (SWT.VERTICAL | SWT.HORIZONTAL) ;\r
- addPaintListener(new PaintListener() {\r
+ addPaintListener(createPaintListener());\r
+ }\r
+ \r
+ public void setGradient(ColorGradient gradient) {\r
+ this.gradient = gradient;\r
+ this.redraw();\r
+ } \r
+ \r
+ protected PaintListener createPaintListener() {\r
+ return new PaintListener() {\r
public void paintControl(PaintEvent e) {\r
GC gc = e.gc;\r
Rectangle clip = gc.getClipping();\r
- if (gradient != null) {\r
- Image image = gradient.getGradientImage(clip.width,clip.height,ColorGradientCanvas.this.style);\r
- gc.drawImage(image, 0, 0);\r
- image.dispose(); \r
- } else {\r
- gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));\r
- gc.fillRectangle(clip);\r
- }\r
+ paintGradient(gc, clip);\r
}\r
- });\r
+ };\r
}\r
\r
- public void setGradient(ColorGradient gradient) {\r
- this.gradient = gradient;\r
- this.redraw();\r
- } \r
+ protected void paintGradient(GC gc, Rectangle clip) {\r
+ if (gradient != null) {\r
+ Image image = gradient.getGradientImage(clip.width,clip.height,ColorGradientCanvas.this.style);\r
+ gc.drawImage(image, 0, 0);\r
+ image.dispose(); \r
+ } else {\r
+ gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));\r
+ gc.fillRectangle(clip);\r
+ }\r
+ }\r
\r
}\r
import org.eclipse.swt.widgets.Button;\r
import org.eclipse.swt.widgets.ColorDialog;\r
import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Group;\r
import org.eclipse.swt.widgets.Table;\r
import org.eclipse.swt.widgets.TableColumn;\r
import org.eclipse.swt.widgets.TableItem;\r
public void dispose() {\r
for (Image i : images.values())\r
i.dispose();\r
- \r
+ super.dispose();\r
}\r
\r
public void setGradient(ColorGradient gradient) {\r
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.utils.ui.color;\r
+\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.graphics.RGB;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+\r
+/**\r
+ * Widget to create and edit color gradients\r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+public class ColorGradientComposite2 extends Composite implements ISelectionChangedListener{ \r
+ \r
+ private ColorGradientAdjustingCanvas gradientComposite;\r
+ private Button addButton;\r
+ private Button editButton;\r
+ private Button removeButton;\r
+ private Button rgbButton;\r
+ private Button hsvButton;\r
+ private int type = ColorGradient.RGB;\r
+ \r
+ private ArrayList<ColorValue> values = new ArrayList<ColorValue>();\r
+ \r
+ public ColorGradientComposite2(Composite parent, int style) {\r
+ super(parent,style);\r
+ GridLayout layout = new GridLayout(2,false);\r
+ this.setLayout(layout);\r
+ gradientComposite = new ColorGradientAdjustingCanvas(this,SWT.HORIZONTAL);\r
+ \r
+ gradientComposite.addSelectionChangedListener(this);\r
+ \r
+ Composite typeComposite = new Composite(this, SWT.NONE);\r
+ \r
+ typeComposite.setLayout(new GridLayout(1,false));\r
+ rgbButton = new Button(typeComposite,SWT.RADIO);\r
+ rgbButton.setSelection(true);\r
+ rgbButton.addSelectionListener(new SelectionListener() {\r
+ public void widgetDefaultSelected(SelectionEvent e) {\r
+ widgetSelected(e);\r
+ }\r
+ public void widgetSelected(SelectionEvent e) {\r
+ rgbButton.setSelection(true);\r
+ hsvButton.setSelection(false);\r
+ type = ColorGradient.RGB;\r
+ gradientComposite.setGradient(new ColorGradient(values,type));\r
+ }\r
+ });\r
+ rgbButton.setText("RGB");\r
+ hsvButton = new Button(typeComposite,SWT.RADIO);\r
+ hsvButton.addSelectionListener(new SelectionListener() {\r
+ public void widgetDefaultSelected(SelectionEvent e) {\r
+ widgetSelected(e);\r
+ }\r
+ public void widgetSelected(SelectionEvent e) {\r
+ hsvButton.setSelection(true);\r
+ rgbButton.setSelection(false);\r
+ type = ColorGradient.HSV;\r
+ gradientComposite.setGradient(new ColorGradient(values,type));\r
+ }\r
+ });\r
+ hsvButton.setText("HSV"); \r
+ \r
+ Composite buttonComposite = new Composite(this,SWT.NONE);\r
+\r
+ buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+ \r
+ addButton = new Button(buttonComposite,SWT.PUSH);\r
+ addButton.setText("Add new color");\r
+ addButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { \r
+ public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { \r
+ RGB rgb = openDialog(null);\r
+ if (rgb != null) {\r
+ Color c = new Color(rgb.red,rgb.green,rgb.blue);\r
+ Double value;\r
+ if (values.size() == 0) {\r
+ value = 0.0;\r
+ } else if (values.size() == 1) {\r
+ value = 100.0;\r
+ } else {\r
+ StructuredSelection selection = (StructuredSelection)gradientComposite.getSelection();\r
+ if (selection.size() == 1) {\r
+ // add new color next to the selection\r
+ ColorValue v = (ColorValue)selection.getFirstElement();\r
+ int index = values.indexOf(v);\r
+ if (index == values.size() -1) {\r
+ index--;\r
+ }\r
+ value = (values.get(index+1).getValue()-values.get(index).getValue())*0.5;\r
+ value += values.get(index).getValue();\r
+ } else {\r
+ // add new color to largest gap\r
+ int index = 0;\r
+ double r = 0.0;\r
+ for (int i = 0; i < values.size() -1; i++) {\r
+ double v1 = values.get(i).getValue();\r
+ double v2 = values.get(i+1).getValue();\r
+ double vr = v2 -v1;\r
+ if (vr > r) {\r
+ r=vr;\r
+ index = i;\r
+ }\r
+ }\r
+ value = values.get(index).getValue() + r *0.5;\r
+ }\r
+ }\r
+ addColor(c,value);\r
+ }\r
+ }\r
+ });\r
+ editButton = new Button(buttonComposite,SWT.PUSH);\r
+ editButton.setText("Edit color");\r
+ editButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { \r
+ public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { \r
+ \r
+ Object obj = ((StructuredSelection)gradientComposite.getSelection()).getFirstElement();\r
+ if (obj == null)\r
+ return;\r
+ if (obj instanceof ColorValue) {\r
+ RGB rgb = openDialog(((ColorValue)obj).getColor().getRgb());\r
+ if (rgb != null) {\r
+ modifyColorValueColor((ColorValue)obj,rgb);\r
+ }\r
+ } \r
+ \r
+ }\r
+ });\r
+ editButton.setEnabled(false);\r
+ removeButton = new Button(buttonComposite,SWT.PUSH);\r
+ removeButton.setText("Remove color");\r
+ removeButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { \r
+ public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { \r
+ Object o = ((StructuredSelection)gradientComposite.getSelection()).getFirstElement();\r
+ if (o == null)\r
+ return;\r
+ if (o instanceof ColorValue) {\r
+ values.remove(o);\r
+ updateWidgets();\r
+ } \r
+ \r
+ }\r
+ });\r
+ removeButton.setEnabled(false);\r
+ \r
+ GridDataFactory.fillDefaults().span(1, 1).grab(true, false).align(SWT.FILL, SWT.CENTER).hint(SWT.DEFAULT, 32).applyTo(gradientComposite);\r
+ GridDataFactory.fillDefaults().grab(false, true).align(SWT.LEFT, SWT.FILL).applyTo(typeComposite);\r
+ GridDataFactory.fillDefaults().span(1, 1).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(buttonComposite); \r
+ }\r
+ \r
+ protected RGB openDialog(RGB selection) {\r
+// ColorDialog dialog = new ColorDialog(ColorGradientComposite2.this.getShell(), SWT.NONE);\r
+// if (selection != null)\r
+// dialog.setRGB(selection);\r
+// RGB rgb = dialog.open();\r
+// return rgb;\r
+ org.simantics.utils.ui.color.ColorDialog dialog = new org.simantics.utils.ui.color.ColorDialog(getShell());\r
+ if (selection != null) {\r
+ Color color = new Color(selection);\r
+ dialog.setInitialValue(color);\r
+ }\r
+ if (dialog.open() == org.simantics.utils.ui.color.ColorDialog.OK) {\r
+ Color color = dialog.getColor();\r
+ return color.getRgb();\r
+ }\r
+ return null;\r
+ }\r
+\r
+ public void addColor(Color color, double value) {\r
+ addColor(new ColorValue(color,value));\r
+ }\r
+ \r
+ public void addColor(ColorValue value) {\r
+ values.add(value);\r
+ updateWidgets();\r
+ }\r
+ \r
+ private void updateWidgets() {\r
+ Collections.sort(values,new ColorValueComparator()); \r
+ gradientComposite.setGradient(new ColorGradient(values,type));\r
+ }\r
+\r
+ public ColorGradient getGradient() {\r
+ return new ColorGradient(values,type);\r
+ }\r
+\r
+ public void dispose() {\r
+ super.dispose();\r
+ }\r
+ \r
+ public void setGradient(ColorGradient gradient) {\r
+ values.clear();\r
+ type = gradient.getType();\r
+ for (ColorValue value : gradient.getColorValues())\r
+ addColor(value);\r
+ if (type == ColorGradient.HSV) {\r
+ rgbButton.setSelection(false);\r
+ hsvButton.setSelection(true);\r
+ } else if (type == ColorGradient.RGB) {\r
+ hsvButton.setSelection(false);\r
+ rgbButton.setSelection(true);\r
+ }\r
+ \r
+ }\r
+ \r
+ private void modifyColorValueColor(ColorValue cValue, RGB rgb) {\r
+ values.remove(cValue);;\r
+ Color newColor = new Color(rgb.red,rgb.green,rgb.blue);\r
+ ColorValue newCValue = new ColorValue(newColor,cValue.getValue());\r
+ values.add(newCValue);\r
+ updateWidgets();\r
+ }\r
+ \r
+ /**\r
+ * Enables and disables "Edit color" and "Remove color" buttons depending on selected item\r
+ */\r
+ public void selectionChanged(SelectionChangedEvent event) {\r
+ Object obj = ((IStructuredSelection)event.getSelection()).getFirstElement();\r
+ if (obj == null) {\r
+ editButton.setEnabled(false);\r
+ removeButton.setEnabled(false);\r
+ } else {\r
+ editButton.setEnabled(true);\r
+ int index = values.indexOf(obj);\r
+ if (index > 0 && index < values.size() -1)\r
+ removeButton.setEnabled(true);\r
+ else\r
+ removeButton.setEnabled(false);\r
+ }\r
+ }\r
+ \r
+}\r
+\r
+ \r
return value;\r
}\r
\r
+ public void _setValue(double value) {\r
+ this.value = value;\r
+ }\r
+ \r
@Override\r
public int hashCode() { \r
return color.hashCode() ^ new Double(value).hashCode();\r