package com.kartoflane.common.swt.ui.widgets; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.TypedListener; import com.kartoflane.common.swt.graphics.HSV; /** * A widget that allows the user to select a hue. * * @author kartoFlane * */ public class HuePicker extends Composite { int triangleSize; Color selectionFillColor; Color selectionBorderColor; Canvas canvas; float selectedHue = 1.0f; public HuePicker( Composite parent, int style ) { super( parent, style ); triangleSize = 8; selectionFillColor = new Color( getDisplay(), 255, 255, 255 ); selectionBorderColor = new Color( getDisplay(), 128, 128, 128 ); GridLayout gridLayout = new GridLayout( 1, false ); gridLayout.verticalSpacing = 0; gridLayout.marginWidth = triangleSize; gridLayout.marginHeight = triangleSize / 2; gridLayout.horizontalSpacing = 0; setLayout( gridLayout ); canvas = new Canvas( this, SWT.DOUBLE_BUFFERED | SWT.NO_FOCUS | SWT.BORDER ); canvas.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true, 1, 1 ) ); canvas.addPaintListener( new PaintListener() { @Override public void paintControl( PaintEvent e ) { paintHues( e ); } } ); addPaintListener( new PaintListener() { @Override public void paintControl( PaintEvent e ) { paintSelectionIndicator( e ); } } ); final MouseMoveListener mml = new MouseMoveListener() { @Override public void mouseMove( MouseEvent e ) { if ( ( e.stateMask & SWT.BUTTON1 ) != 0 ) { canvas.forceFocus(); final float height = canvas.getClientArea().height; e.y = (int)Math.max( 0, Math.min( height, e.y ) ); setSelection( 1 - ( e.y / height ) ); } } }; canvas.addMouseMoveListener( mml ); canvas.addMouseListener( new MouseAdapter() { @Override public void mouseDown( MouseEvent e ) { e.stateMask = SWT.BUTTON1; mml.mouseMove( e ); } } ); } @Override public Point computeSize( int wHint, int hHint, boolean changed ) { Point p = super.computeSize( wHint, hHint, changed ); p.x += triangleSize * 2; p.y += triangleSize / 2; return p; } public void setSelection( float hue ) { if ( hue < 0 || hue > 1.0f ) throw new IllegalArgumentException( "0 < " + hue + " < 1.0" ); selectedHue = hue; redraw(); notifyListeners( SWT.Selection, new Event() ); } public void setSelection( RGB rgb ) { if ( rgb == null ) throw new IllegalArgumentException( "Argument must not be null." ); HSV hsv = new HSV( rgb ); setSelection( hsv.h ); } public void setSelection( Color color ) { if ( color == null ) throw new IllegalArgumentException( "Argument must not be null." ); HSV hsv = new HSV( color.getRGB() ); setSelection( hsv.h ); } public float getSelection() { return selectedHue; } /** * Returns the current selection in the form of a color, using the display associated with this control as device. * Colors in SWT are a system resource, and as such have to be disposed when no longer used. */ public Color getSelectedColor() { return getSelectedColor( getDisplay() ); } /** * Returns the current selection in the form of a color. * Colors in SWT are a system resource, and as such have to be disposed when no longer used. */ public Color getSelectedColor( Device d ) { return new HSV( selectedHue, 1.0f, 1.0f ).toColor( d ); } public void addSelectionListener( SelectionListener listener ) { addListener( SWT.Selection, new TypedListener( listener ) ); } public void removeListener( SelectionListener listener ) { removeListener( SWT.Selection, listener ); } void paintHues( PaintEvent e ) { final Display d = getDisplay(); final int width = canvas.getSize().x; final int height = canvas.getClientArea().height; final float stepY = 1f / height; HSV hsv = new HSV( 1, 1, 1 ); for ( int y = 0; y < height; ++y ) { Color c = hsv.toColor( d ); e.gc.setBackground( c ); e.gc.fillRectangle( 0, y, width, 1 ); c.dispose(); hsv.h -= stepY; } } void paintSelectionIndicator( PaintEvent e ) { final int width = canvas.getSize().x; final int height = canvas.getClientArea().height; final int hOffset = (int)( ( 1 - selectedHue ) * height ); int[] leftTriangle = new int[] { 0, hOffset - 2 + triangleSize / 2, 0, hOffset + 6 + triangleSize / 2, triangleSize, hOffset + triangleSize / 2 + 2 }; int[] rightTriangle = new int[] { width + triangleSize * 2 - 1, hOffset - 2 + triangleSize / 2, width + triangleSize * 2 - 1, hOffset + 6 + triangleSize / 2, width + triangleSize - 1, hOffset + triangleSize / 2 + 2 }; e.gc.setBackground( selectionFillColor ); e.gc.fillPolygon( leftTriangle ); e.gc.fillPolygon( rightTriangle ); e.gc.setBackground( selectionBorderColor ); e.gc.drawPolygon( leftTriangle ); e.gc.drawPolygon( rightTriangle ); } public void dispose() { canvas.dispose(); selectionFillColor.dispose(); selectionBorderColor.dispose(); super.dispose(); } }