/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.utils.ui.color; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; /** * * Canvas that shows color gradients and color positions. * Without READ_ONLY style the canvas allows user to drag color positions. * * @author Marko Luukkainen * */ public class ColorGradientAdjustingCanvas extends ColorGradientCanvas implements ISelectionProvider{ ColorValue[] values; int last; int coords[]; int size = 8; int sized2 = 4; int width; int height; int selectedValueIndex = -1; public ColorGradientAdjustingCanvas(Composite parent, int style) { super(parent,style|SWT.DOUBLE_BUFFERED|SWT.NO_BACKGROUND); addMouseListener(new MouseListener() { @Override public void mouseUp(MouseEvent e) { } @Override public void mouseDown(MouseEvent e) { // store and reset selection int prev = selectedValueIndex; selectedValueIndex = -1; // locate closest ColorValue, and select it. int d = Integer.MAX_VALUE; for (int i = 0; i <= last; i++) { int x = coords[i*2]; int y = coords[i*2+1]; int dx = Math.abs(x - e.x); int dy = Math.abs(y - e.y); if ((dx < size) && (dy < size)) { int dd = dx+dy; if (dd < d) { selectedValueIndex = i; d = dd; } } } // if selection was changed, update it. if (prev != selectedValueIndex) { updateSelection(); redraw(); } } @Override public void mouseDoubleClick(MouseEvent e) { } }); if ((style&SWT.READ_ONLY) == 0) { addMouseMoveListener(new MouseMoveListener() { @Override public void mouseMove(MouseEvent e) { if ((e.stateMask & SWT.BUTTON1)>0) { if (selectedValueIndex > 0 && selectedValueIndex < last) { double d; if ((ColorGradientAdjustingCanvas.this.style | SWT.HORIZONTAL) > 0) { d = (double)e.x/(double)width; } else { d = (double)e.y/(double)height; } double r = max-min; d *= r; d += min; double offset = r*0.015; if (d <= values[selectedValueIndex-1].getValue()+offset) d = values[selectedValueIndex-1].getValue()+offset; else if (d >= values[selectedValueIndex+1].getValue()-offset) d = values[selectedValueIndex+1].getValue()-offset; values[selectedValueIndex]._setValue(d); calculateCoords(width, height); redraw(); } } } }); } } public void setGradient(ColorGradient gradient) { int prevSize = 0; if (values != null) prevSize = values.length; values = gradient.getColorValueArray(); last = values.length-1; coords = new int[values.length*2]; super.setGradient(gradient); if (selectedValueIndex >= 0 && prevSize != values.length) { selectedValueIndex = -1; updateSelection(); } else { updateSelection(); } } double min; double max; private void calculateCoords(int width, int height) { this.width = width; this.height = height; min = values[0].getValue(); max = values[last].getValue(); if ((ColorGradientAdjustingCanvas.this.style & SWT.HORIZONTAL) > 0) { for (int i = 0; i <= last ; i++) { int y = height / 2; double d = values[i].getValue(); int x = (int)(((d-min)/(max-min))*(double)width); coords[i*2] = x; coords[i*2+1] = y; } } else { for (int i = 0; i <= last ; i++) { int x = width / 2; double d = values[i].getValue(); int y = (int)(((d-min)/(max-min))*(double)height); coords[i*2] = x; coords[i*2+1] = y; } } } @Override protected void paintGradient(GC gc, Rectangle clip) { if (values != null && values.length > 0) { Image image = gradient.getGradientImage(clip.width,clip.height,ColorGradientAdjustingCanvas.this.style); gc.drawImage(image, 0, 0); image.dispose(); calculateCoords(clip.width, clip.height); Color white = new Color(gc.getDevice(), 255,255,255); Color yellow = new Color(gc.getDevice(), 255,230,0); Color black = new Color(gc.getDevice(), 0, 0, 0); for (int i = 0; i <= last ; i++) { int x = coords[i*2]; int y = coords[i*2+1]; gc.setForeground(black); if (selectedValueIndex == i) gc.setBackground(yellow); else gc.setBackground(white); if (i == 0 || i == last ) { gc.fillRectangle(x-sized2, y-sized2, size, size); gc.drawRectangle(x-sized2, y-sized2, size, size); } else { gc.fillOval(x-sized2, y-sized2, size, size); gc.drawOval(x-sized2, y-sized2, size, size); } } white.dispose(); black.dispose(); yellow.dispose(); } else { gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); gc.fillRectangle(clip); } } private ISelection selection = new StructuredSelection(); private List listeners = new ArrayList<>(); @Override public void addSelectionChangedListener(ISelectionChangedListener listener) { listeners.add(listener); } @Override public ISelection getSelection() { return selection; } @Override public void removeSelectionChangedListener(ISelectionChangedListener listener) { listeners.remove(listener); } @Override public void setSelection(ISelection selection) { ColorValue value = (ColorValue)((StructuredSelection)selection).getFirstElement(); selectedValueIndex = gradient.getColorValues().indexOf(value); } private void updateSelection() { if (selectedValueIndex < 0) selection = new StructuredSelection(); else selection = new StructuredSelection(values[selectedValueIndex]); for (ISelectionChangedListener l : listeners) { l.selectionChanged(new SelectionChangedEvent(this, selection)); } } public int getPointSize() { return size; } public void setPointSize(int size) { this.size = size; this.sized2 = size/2; } }