+/*******************************************************************************\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