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.RGB;
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 shade of a specified hue.
*
* @author kartoFlane
*
*/
public class ShadePicker extends Composite {
int selHalfSize;
float currentHue;
Color selectionBorderColor;
Canvas canvas;
float selectedSaturation = 0.0f;
float selectedBrightness = 1.0f;
public ShadePicker( Composite parent, int style ) {
super( parent, style );
selHalfSize = 5;
currentHue = 1.0f;
selectionBorderColor = new Color( getDisplay(), 128, 128, 128 );
canvas = new Canvas( this, SWT.BORDER | SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED );
canvas.addPaintListener( new PaintListener() {
@Override
public void paintControl( PaintEvent e ) {
paintShades( e );
paintSelectionIndicator( e );
}
} );
final MouseMoveListener mml = new MouseMoveListener() {
@Override
public void mouseMove( MouseEvent e ) {
if ( ( e.stateMask & SWT.BUTTON1 ) != 0 ) {
canvas.forceFocus();
final float width = canvas.getClientArea().width;
final float height = canvas.getClientArea().height;
e.x = (int)Math.max( 0, Math.min( width, e.x ) );
e.y = (int)Math.max( 0, Math.min( height, e.y ) );
setSelection( e.x / width, 1 - ( e.y / height ) );
}
}
};
canvas.addMouseMoveListener( mml );
canvas.addMouseListener( new MouseAdapter() {
@Override
public void mouseDown( MouseEvent e ) {
if ( e.button == 1 ) {
e.stateMask = SWT.BUTTON1;
mml.mouseMove( e );
}
}
} );
}
@Override
public void setSize( int w, int h ) {
super.setSize( w, h );
canvas.setSize( w, h );
}
@Override
public void setBounds( int x, int y, int w, int h ) {
super.setBounds( x, y, w, h );
canvas.setBounds( x, y, w - selHalfSize, h - selHalfSize );
}
public void setHue( float hue ) {
if ( hue < 0 || hue > 1.0f )
throw new IllegalArgumentException( "0 < " + hue + " < 1.0" );
currentHue = hue;
canvas.redraw();
}
public void setHue( RGB rgb ) {
if ( rgb == null )
throw new IllegalArgumentException( "Argument must not be null." );
HSV hsv = new HSV( rgb );
setHue( hsv.h );
}
public void setHue( Color color ) {
if ( color == null )
throw new IllegalArgumentException( "Argument must not be null." );
HSV hsv = new HSV( color.getRGB() );
setHue( hsv.h );
}
public void setSelection( float saturation, float brightness ) {
if ( saturation < 0 || saturation > 1.0f )
throw new IllegalArgumentException( "Saturation: 0 < " + saturation + " < 1.0" );
if ( brightness < 0 || brightness > 1.0f )
throw new IllegalArgumentException( "Brightness: 0 < " + brightness + " < 1.0" );
selectedSaturation = saturation;
selectedBrightness = brightness;
canvas.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.s, hsv.v );
}
public void setSelection( Color color ) {
if ( color == null )
throw new IllegalArgumentException( "Argument must not be null." );
HSV hsv = new HSV( color.getRGB() );
setSelection( hsv.s, hsv.v );
}
public HSV getSelection() {
return new HSV( currentHue, selectedSaturation, selectedBrightness );
}
public void addSelectionListener( SelectionListener listener ) {
addListener( SWT.Selection, new TypedListener( listener ) );
}
public void removeListener( SelectionListener listener ) {
removeListener( SWT.Selection, listener );
}
void paintShades( PaintEvent e ) {
final Display d = getDisplay();
final int width = canvas.getClientArea().width;
final int height = canvas.getClientArea().height;
final float stepY = 1f / height;
final HSV white = new HSV( 0, 0, 1 );
final HSV shade = new HSV( currentHue, 1.0f, 1.0f );
try {
for ( int y = 0; y < height; ++y ) {
Color c1 = white.toColor( d );
Color c2 = shade.toColor( d );
e.gc.setForeground( c1 );
e.gc.setBackground( c2 );
e.gc.fillGradientRectangle( 0, y, width, 1, false );
c1.dispose();
c2.dispose();
white.v -= stepY;
shade.v -= stepY;
}
}
catch ( Exception ex ) {
System.err.printf( "%s, %s%n", white, shade );
}
}
void paintSelectionIndicator( PaintEvent e ) {
final int width = canvas.getClientArea().width;
final int height = canvas.getClientArea().height;
final int s = (int)( selectedSaturation * width );
final int b = (int)( ( 1 - selectedBrightness ) * height );
float d = (float)( Math.sqrt( Math.pow( 1 - selectedBrightness, 2 ) + Math.pow( selectedSaturation, 2 ) ) );
d = d > 0.4 ? 1 : 0;
HSV hsv = new HSV( 0, 0, d );
if ( selectionBorderColor != null )
selectionBorderColor.dispose();
selectionBorderColor = hsv.toColor( getDisplay() );
e.gc.setForeground( selectionBorderColor );
e.gc.drawOval( s - selHalfSize, b - selHalfSize, selHalfSize * 2, selHalfSize * 2 );
}
public void dispose() {
selectionBorderColor.dispose();
canvas.dispose();
super.dispose();
}
}