package com.kartoflane.common.swt.ui;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Color;
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.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.kartoflane.common.swt.graphics.HSV;
import com.kartoflane.common.swt.ui.widgets.HuePicker;
import com.kartoflane.common.swt.ui.widgets.ShadePicker;
/**
* This dialog allows the user to select a color of their liking.
*
* @author kartoFlane
*
*/
public class SquareColorPickerDialog extends Dialog {
private static final int shadeWidth = 270;
private static final int shadeHeight = 270;
private static final int hueWidth = 25;
private RGB result = null;
private RGB current = null;
private Shell shell;
private ShadePicker shadePicker;
private HuePicker huePicker;
private Composite coButtons;
private Button btnConfirm;
private Button btnCancel;
private Composite coControls;
private Composite coColors;
private Label lblNew;
private Label lblCurrent;
private Label lblColorNew;
private Label lblColorCurrent;
private Composite coColorsCompare;
private Text txtR;
private Text txtG;
private Text txtB;
private Text txtH;
private Text txtS;
private Text txtV;
private Label lblHex;
private Text txtHex;
private Label lblSeparator;
private Text[] txtFields = new Text[7];
private VerifyListener vl;
private ModifyListener ml;
public SquareColorPickerDialog( Shell parent ) {
super( parent );
setText( "Color Picker" );
}
/**
* Opens the color picker dialog using the specified color as the "current" color.
* Returns the selected color, or null if the user canceled selection.
*
* When this method returns, the dialog is already disposed.
*/
public RGB open( RGB current ) {
Shell parent = getParent();
if ( current == null )
this.current = new RGB( 0, 0, 0 );
else
this.current = current;
result = this.current;
shell = new Shell( parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL );
shell.setText( getText() );
shell.setLayout( new GridLayout( 3, false ) );
createWidgets();
shell.pack();
Point size = shell.getSize();
Point parSize = parent.getSize();
Point parLoc = parent.getLocation();
shell.setLocation( parLoc.x + parSize.x / 2 - size.x / 2, parLoc.y + parSize.y / 3 - size.y / 2 );
shell.open();
Display display = parent.getDisplay();
while ( !shell.isDisposed() ) {
if ( !display.readAndDispatch() )
display.sleep();
}
return result;
}
private void createWidgets() {
shadePicker = new ShadePicker( shell, SWT.NONE );
GridData gd_spShade = new GridData( SWT.LEFT, SWT.TOP, false, false, 1, 1 );
gd_spShade.heightHint = shadeHeight;
gd_spShade.widthHint = shadeWidth;
shadePicker.setLayoutData( gd_spShade );
shadePicker.setHue( current );
shadePicker.setSelection( current );
shadePicker.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
updateColorSelection();
}
} );
huePicker = new HuePicker( shell, SWT.NONE );
GridData gd_hpHue = new GridData( SWT.FILL, SWT.TOP, false, false, 1, 1 );
gd_hpHue.heightHint = shadeHeight;
gd_hpHue.widthHint = hueWidth;
huePicker.setLayoutData( gd_hpHue );
huePicker.setSelection( current );
huePicker.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
shadePicker.setHue( huePicker.getSelectedColor() );
updateColorSelection();
}
} );
coControls = new Composite( shell, SWT.NONE );
coControls.setLayout( new GridLayout( 5, false ) );
coControls.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, false, 1, 1 ) );
coColors = new Composite( coControls, SWT.NONE );
coColors.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 5, 1 ) );
GridLayout gl_coColors = new GridLayout( 3, false );
gl_coColors.marginWidth = 0;
gl_coColors.marginHeight = 0;
coColors.setLayout( gl_coColors );
lblNew = new Label( coColors, SWT.NONE );
lblNew.setText( "new" );
coColorsCompare = new Composite( coColors, SWT.BORDER );
coColorsCompare.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 1, 1 ) );
coColorsCompare.setBounds( 0, 0, 64, 64 );
GridLayout gl_coColorsCompare = new GridLayout( 2, false );
gl_coColorsCompare.horizontalSpacing = 0;
gl_coColorsCompare.verticalSpacing = 0;
gl_coColorsCompare.marginWidth = 0;
gl_coColorsCompare.marginHeight = 0;
coColorsCompare.setLayout( gl_coColorsCompare );
lblColorNew = new Label( coColorsCompare, SWT.NONE );
GridData gd_lblColorNew = new GridData( SWT.FILL, SWT.CENTER, true, false, 1, 1 );
gd_lblColorNew.heightHint = 25;
gd_lblColorNew.widthHint = 50;
lblColorNew.setLayoutData( gd_lblColorNew );
lblColorNew.setSize( 50, 20 );
lblColorCurrent = new Label( coColorsCompare, SWT.NONE );
GridData gd_lblColorCurrent = new GridData( SWT.FILL, SWT.CENTER, true, false, 1, 1 );
gd_lblColorCurrent.heightHint = 25;
gd_lblColorCurrent.widthHint = 50;
lblColorCurrent.setLayoutData( gd_lblColorCurrent );
lblColorCurrent.setSize( 50, 20 );
lblColorCurrent.setBackground( new Color( getParent().getDisplay(), current ) );
lblCurrent = new Label( coColors, SWT.NONE );
lblCurrent.setText( "current" );
lblCurrent.setBounds( 0, 0, 22, 15 );
lblSeparator = new Label( coControls, SWT.NONE );
lblSeparator.setLayoutData( new GridData( SWT.LEFT, SWT.CENTER, false, false, 5, 1 ) );
Label lblR = new Label( coControls, SWT.NONE );
lblR.setLayoutData( new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 ) );
lblR.setText( "R:" );
txtR = new Text( coControls, SWT.BORDER );
txtR.setText( "0" );
GridData gd_txtR = new GridData( SWT.LEFT, SWT.CENTER, false, false, 1, 1 );
gd_txtR.widthHint = 40;
txtR.setLayoutData( gd_txtR );
Label lblH = new Label( coControls, SWT.NONE );
lblH.setLayoutData( new GridData( SWT.RIGHT, SWT.CENTER, true, false, 1, 1 ) );
lblH.setText( "H:" );
txtH = new Text( coControls, SWT.BORDER );
txtH.setText( "0" );
GridData gd_txtH = new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 );
gd_txtH.widthHint = 40;
txtH.setLayoutData( gd_txtH );
Label lblUnitH = new Label( coControls, SWT.NONE );
lblUnitH.setText( "\u00b0" );
Label lblG = new Label( coControls, SWT.NONE );
lblG.setLayoutData( new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 ) );
lblG.setText( "G:" );
txtG = new Text( coControls, SWT.BORDER );
txtG.setText( "0" );
GridData gd_txtG = new GridData( SWT.LEFT, SWT.CENTER, false, false, 1, 1 );
gd_txtG.widthHint = 40;
txtG.setLayoutData( gd_txtG );
Label lblS = new Label( coControls, SWT.NONE );
lblS.setLayoutData( new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 ) );
lblS.setText( "S:" );
txtS = new Text( coControls, SWT.BORDER );
txtS.setText( "0" );
GridData gd_txtS = new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 );
gd_txtS.widthHint = 40;
txtS.setLayoutData( gd_txtS );
Label lblUnitS = new Label( coControls, SWT.NONE );
lblUnitS.setText( "%" );
Label lblB = new Label( coControls, SWT.NONE );
lblB.setLayoutData( new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 ) );
lblB.setText( "B:" );
txtB = new Text( coControls, SWT.BORDER );
txtB.setText( "0" );
GridData gd_txtB = new GridData( SWT.LEFT, SWT.CENTER, false, false, 1, 1 );
gd_txtB.widthHint = 40;
txtB.setLayoutData( gd_txtB );
Label lblV = new Label( coControls, SWT.NONE );
lblV.setLayoutData( new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 ) );
lblV.setText( "B:" );
txtV = new Text( coControls, SWT.BORDER );
txtV.setText( "0" );
GridData gd_txtV = new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 );
gd_txtV.widthHint = 40;
txtV.setLayoutData( gd_txtV );
Label lblUnitV = new Label( coControls, SWT.NONE );
lblUnitV.setText( "%" );
lblHex = new Label( coControls, SWT.NONE );
lblHex.setLayoutData( new GridData( SWT.RIGHT, SWT.BOTTOM, false, false, 1, 1 ) );
lblHex.setText( "#" );
txtHex = new Text( coControls, SWT.BORDER );
txtHex.setText( "000000" );
txtHex.setLayoutData( new GridData( SWT.FILL, SWT.BOTTOM, true, true, 4, 1 ) );
txtFields[0] = txtHex;
txtFields[1] = txtR;
txtFields[2] = txtG;
txtFields[3] = txtB;
txtFields[4] = txtH;
txtFields[5] = txtS;
txtFields[6] = txtV;
coButtons = new Composite( shell, SWT.NONE );
GridLayout gl_coButtons = new GridLayout( 2, false );
gl_coButtons.marginWidth = 0;
gl_coButtons.marginHeight = 0;
coButtons.setLayout( gl_coButtons );
coButtons.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 3, 1 ) );
btnConfirm = new Button( coButtons, SWT.NONE );
GridData gd_btnConfirm = new GridData( SWT.RIGHT, SWT.CENTER, true, false, 1, 1 );
gd_btnConfirm.widthHint = 80;
btnConfirm.setLayoutData( gd_btnConfirm );
btnConfirm.setText( "Confirm" );
btnCancel = new Button( coButtons, SWT.NONE );
GridData gd_btnCancel = new GridData( SWT.RIGHT, SWT.CENTER, false, false, 1, 1 );
gd_btnCancel.widthHint = 80;
btnCancel.setLayoutData( gd_btnCancel );
btnCancel.setText( "Cancel" );
coControls.setTabList( new Control[] { txtR, txtG, txtB, txtH, txtS, txtV, txtHex } );
shell.setTabList( new Control[] { coControls, coButtons } );
lblColorCurrent.addMouseListener( new MouseAdapter() {
@Override
public void mouseDown( MouseEvent e ) {
if ( e.button == 1 ) {
huePicker.setSelection( current );
shadePicker.setSelection( current );
updateColorSelection();
}
}
} );
btnConfirm.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
dispose();
}
} );
btnCancel.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent e ) {
result = null;
dispose();
}
} );
shell.addListener( SWT.Close, new Listener() {
@Override
public void handleEvent( Event e ) {
e.doit = false;
result = null;
dispose();
}
} );
vl = new VerifyListener() {
@Override
public void verifyText( VerifyEvent e ) {
e.doit = verifyInput( e.getSource(), e.character );
}
};
ml = new ModifyListener() {
@Override
public void modifyText( ModifyEvent e ) {
setInput( e.getSource() );
}
};
FocusListener fl = new FocusAdapter() {
@Override
public void focusGained( FocusEvent e ) {
if ( e.getSource() == txtHex ) {
String t = txtHex.getText();
if ( t.length() % 2 == 1 )
txtHex.setText( t + "0" );
}
updateColorSelection();
}
};
txtHex.addFocusListener( fl );
txtR.addFocusListener( fl );
txtG.addFocusListener( fl );
txtB.addFocusListener( fl );
txtH.addFocusListener( fl );
txtS.addFocusListener( fl );
txtV.addFocusListener( fl );
updateColorSelection();
}
private void updateColorSelection() {
// Updating the txt fields while listeners are registered results in a
// huge amount of lag. Remove the listeners temporarily, and re-register
// them when we're done.
removeListeners();
HSV hsv = shadePicker.getSelection();
result = hsv.toRGB();
lblColorNew.getBackground().dispose();
lblColorNew.setBackground( new Color( getParent().getDisplay(), result ) );
if ( !txtR.isFocusControl() )
txtR.setText( "" + result.red );
if ( !txtG.isFocusControl() )
txtG.setText( "" + result.green );
if ( !txtB.isFocusControl() )
txtB.setText( "" + result.blue );
DecimalFormatSymbols symbols = new DecimalFormatSymbols( Locale.ENGLISH );
NumberFormat formatter = new DecimalFormat( "#0.00", symbols );
hsv.h = huePicker.getSelection();
if ( !txtH.isFocusControl() )
txtH.setText( formatter.format( hsv.h * 360 ) );
if ( !txtS.isFocusControl() )
txtS.setText( formatter.format( hsv.s * 100 ) );
if ( !txtV.isFocusControl() )
txtV.setText( formatter.format( hsv.v * 100 ) );
if ( !txtHex.isFocusControl() ) {
String hr = Integer.toHexString( result.red );
hr = hr.length() == 0 ? "00" : ( hr.length() == 1 ? "0" + hr : hr );
String hg = Integer.toHexString( result.green );
hg = hg.length() == 0 ? "00" : ( hg.length() == 1 ? "0" + hg : hg );
String hb = Integer.toHexString( result.blue );
hb = hb.length() == 0 ? "00" : ( hb.length() == 1 ? "0" + hb : hb );
txtHex.setText( hr + hg + hb );
}
addListeners();
}
private void removeListeners() {
for ( Text t : txtFields ) {
t.removeVerifyListener( vl );
t.removeModifyListener( ml );
}
}
private void addListeners() {
for ( Text t : txtFields ) {
t.addVerifyListener( vl );
t.addModifyListener( ml );
}
}
private boolean verifyInput( Object src, char ch ) {
if ( ch == '\b' || ch == 127 ) // Backspace and delete keys
return true;
Text t = (Text)src;
if ( src == txtHex ) {
return ( t.getText().length() < 6 || t.getSelectionCount() > 0 ) &&
( ( ch >= '0' && ch <= '9' ) || ( ch >= 'a' && ch <= 'f' ) ||
( ch >= 'A' && ch <= 'F' ) );
}
else if ( src == txtR || src == txtG || src == txtB ) {
return ( t.getText().length() < 3 || t.getSelectionCount() > 0 ) && ( ch >= '0' && ch <= '9' );
}
else if ( src == txtH || src == txtS || src == txtV ) {
if ( ch == '.' && ( !t.getText().contains( "." ) || t.getSelectionText().contains( "." ) ) )
return true;
return ( t.getText().length() < 6 || t.getSelectionCount() > 0 ) && ( ch >= '0' && ch <= '9' );
}
return false;
}
private void setInput( Object src ) {
if ( src == txtHex ) {
String text = ( (Text)src ).getText();
RGB rgb = new RGB( 0, 0, 0 );
try {
rgb.red = Integer.parseInt( text.substring( 0, 2 ), 16 );
rgb.green = Integer.parseInt( text.substring( 2, 4 ), 16 );
rgb.blue = Integer.parseInt( text.substring( 4, 6 ), 16 );
}
catch ( StringIndexOutOfBoundsException e ) {
}
float[] hsv = rgb.getHSB();
huePicker.setSelection( hsv[0] );
shadePicker.setSelection( hsv[1], hsv[2] );
}
else if ( src == txtR || src == txtG || src == txtB ) {
RGB rgb = new RGB( 0, 0, 0 );
try {
rgb.red = Math.min( 255, Integer.parseInt( txtR.getText() ) );
}
catch ( NumberFormatException e ) {
}
try {
rgb.green = Math.min( 255, Integer.parseInt( txtG.getText() ) );
}
catch ( NumberFormatException e ) {
}
try {
rgb.blue = Math.min( 255, Integer.parseInt( txtB.getText() ) );
}
catch ( NumberFormatException e ) {
}
float[] hsv = rgb.getHSB();
huePicker.setSelection( hsv[0] );
shadePicker.setSelection( hsv[1], hsv[2] );
}
else if ( src == txtH || src == txtS || src == txtV ) {
HSV hsv = new HSV( 0, 0, 0 );
try {
hsv.h = Math.min( 360, Float.parseFloat( txtH.getText() ) ) / 360f;
}
catch ( NumberFormatException e ) {
}
try {
hsv.s = Math.min( 100, Float.parseFloat( txtS.getText() ) ) / 100f;
}
catch ( NumberFormatException e ) {
}
try {
hsv.v = Math.min( 100, Float.parseFloat( txtV.getText() ) ) / 100f;
}
catch ( NumberFormatException e ) {
}
if ( src == txtH ) {
huePicker.setSelection( hsv.h );
shadePicker.setSelection( hsv.s, hsv.v );
}
else if ( src == txtS ) {
shadePicker.setSelection( hsv.s, shadePicker.getSelection().v );
}
else if ( src == txtV ) {
shadePicker.setSelection( shadePicker.getSelection().s, hsv.v );
}
}
}
public void dispose() {
lblColorCurrent.getBackground().dispose();
shell.dispose();
}
}