/*
This file is part of leafdigital leafChat.
leafChat is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
leafChat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with leafChat. If not, see <http://www.gnu.org/licenses/>.
Copyright 2011 Samuel Marshall.
*/
package com.leafdigital.ui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import util.PlatformUtils;
/**
* Dialog for selecting a colour.
*/
public class ColourSelectDialog extends JDialog
{
private final static int GRIDSIZE=16,SUBGRIDSIZE=GRIDSIZE/2,SELECTORSIZE=16;
private Color chosen=null;
private HueSelector[] hues;
private HueSelector selectedHue;
private SBSelector[] others;
private SBSelector selectedOther;
private ColourPreview colourPreview;
private class HueSelector extends ColourSelector
{
float hue;
HueSelector(float hue)
{
this.hue=hue;
}
@Override
void clicked()
{
HueSelector oldSelectedHue=selectedHue;
selectedHue=this;
oldSelectedHue.repaint();
repaint();
for(int i=0;i<others.length;i++)
{
others[i].repaint();
}
colourPreview.repaint();
}
@Override
Color getColour()
{
return Color.getHSBColor(hue,1.0f,1.0f);
}
@Override
boolean isSelected()
{
return selectedHue==this;
}
}
private class SBSelector extends ColourSelector
{
float saturation,brightness;
SBSelector(float saturation,float brightness)
{
this.saturation=saturation;
this.brightness=brightness;
}
@Override
void clicked()
{
SBSelector oldSelectedOther=selectedOther;
selectedOther=this;
oldSelectedOther.repaint();
repaint();
colourPreview.repaint();
}
@Override
Color getColour()
{
return Color.getHSBColor(selectedHue.hue,saturation,brightness);
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(SELECTORSIZE*2+4,SELECTORSIZE*2+4);
}
@Override
boolean isSelected()
{
return selectedOther==this;
}
}
private abstract class ColourSelector extends JComponent
{
public ColourSelector()
{
addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
clicked();
}
});
addKeyListener(new KeyAdapter()
{
@Override
public void keyTyped(KeyEvent e)
{
if(e.getKeyChar()==' ')
clicked();
}
});
addFocusListener(new FocusListener()
{
@Override
public void focusGained(FocusEvent e)
{
repaint();
}
@Override
public void focusLost(FocusEvent e)
{
repaint();
}
});
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(SELECTORSIZE,SELECTORSIZE);
}
@Override
public boolean isFocusable()
{
return true;
}
abstract Color getColour();
abstract void clicked();
abstract boolean isSelected();
@Override
public boolean isOpaque()
{
return true;
}
@Override
protected void paintComponent(Graphics g)
{
g.setColor(getColour());
g.fillRect(1,1,getWidth()-2,getHeight()-2);
if(isSelected())
{
g.setColor(Color.black);
g.drawRect(0,0,getWidth()-1,getHeight()-1);
g.drawRect(2,2,getWidth()-5,getHeight()-5);
g.setColor(Color.white);
g.drawRect(1,1,getWidth()-3,getHeight()-3);
}
else
{
g.setColor(Color.black);
g.drawRect(0,0,getWidth()-1,getHeight()-1);
}
if(hasFocus())
{
g.setColor(Color.white);
g.drawRect(0,0,getWidth()-1,getHeight()-1);
}
}
}
private class ColourPreview extends JComponent
{
@Override
protected void paintComponent(Graphics g)
{
Color c=Color.getHSBColor(
selectedHue.hue,selectedOther.saturation,selectedOther.brightness);
int divider=getHeight()/3;
g.setColor(c);
g.fillRect(0,0,getWidth(),divider);
g.setColor(Color.white);
g.fillRect(0,divider,getWidth(),divider);
g.setColor(c);
Shape previousClip=g.getClip();
g.clipRect(0,divider,getWidth(),divider);
int lineHeight=g.getFontMetrics().getHeight();
int lines=divider/lineHeight + 1;
for(int i=0;i<lines;i++)
{
g.drawString("TextTextTextTextTextTextTextTextText",-8*i,divider+(i+1)*lineHeight-5);
}
g.setClip(previousClip);
g.setColor(c);
g.fillRect(0,2*divider,getWidth(),getHeight()-2*divider);
g.setColor(Color.black);
previousClip=g.getClip();
g.clipRect(0,2*divider,getWidth(),getHeight()-2*divider);
for(int i=0;i<lines;i++)
{
g.drawString("BackgroundBackgroundBackgroundBackground",-8*i,2*divider+(i+1)*lineHeight-5);
}
g.setClip(previousClip);
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(96,96);
}
@Override
public boolean isOpaque()
{
return true;
}
}
ColourSelectDialog(Component parent,String title,Color original)
{
super((Frame)null,title,true);
JPanel main=new JPanel(new BorderLayout(8,8));
main.setBorder(BorderFactory.createEmptyBorder(8,8,8,8));
getContentPane().add(main);
JPanel selectors=new JPanel(new BorderLayout(8,8));
main.add(selectors,BorderLayout.CENTER);
JPanel hueControls=new JPanel(new BorderLayout(4,4));
selectors.add(hueControls,BorderLayout.NORTH);
JPanel otherControls=new JPanel(new BorderLayout(4,4));
selectors.add(otherControls,BorderLayout.SOUTH);
JLabel hueLabel=new JLabel("Hue");
hueControls.add(hueLabel,BorderLayout.NORTH);
JLabel otherLabel=new JLabel("Saturation and brightness");
otherControls.add(otherLabel,BorderLayout.NORTH);
JPanel hueSelectors=new JPanel(new GridLayout(1,GRIDSIZE,4,4));
hueControls.add(hueSelectors,BorderLayout.SOUTH);
JPanel otherSelectors=new JPanel(new GridLayout(SUBGRIDSIZE,SUBGRIDSIZE,4,4));
otherControls.add(otherSelectors,BorderLayout.SOUTH);
JPanel buttons1=new JPanel(new BorderLayout(8,8));
main.add(buttons1,BorderLayout.SOUTH);
JPanel buttons2=new JPanel(new BorderLayout());
buttons1.add(buttons2,BorderLayout.CENTER);
JButton select=new JButton("Select");
select.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent ae)
{
chosen=Color.getHSBColor(
selectedHue.hue,selectedOther.saturation,selectedOther.brightness);
dispose();
}
});
JButton cancel=new JButton("Cancel");
cancel.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent ae)
{
chosen=null;
dispose();
}
});
getRootPane().setDefaultButton(select);
if(PlatformUtils.isWindows())
{
buttons2.add(select,BorderLayout.EAST);
buttons1.add(cancel,BorderLayout.EAST);
}
else
{
buttons1.add(select,BorderLayout.EAST);
buttons2.add(cancel,BorderLayout.EAST);
}
colourPreview=new ColourPreview();
main.add(colourPreview,BorderLayout.EAST);
hues=new HueSelector[GRIDSIZE];
for(int hue=0;hue<GRIDSIZE;hue++)
{
float hueValue=((float)hue/(float)GRIDSIZE);
hues[hue]=new HueSelector(hueValue);
hueSelectors.add(hues[hue]);
}
others=new SBSelector[SUBGRIDSIZE*SUBGRIDSIZE];
for(int saturation=0;saturation<SUBGRIDSIZE;saturation++)
{
for(int brightness=0;brightness<SUBGRIDSIZE;brightness++)
{
int index=saturation*SUBGRIDSIZE+brightness;
others[index]=new SBSelector(
((float)saturation/(float)(SUBGRIDSIZE-1)),((float)brightness/(float)(SUBGRIDSIZE-1)));
otherSelectors.add(others[index]);
}
}
float[] hsbSpecified=Color.RGBtoHSB(original.getRed(),original.getGreen(),original.getBlue(),null);
selectedHue=hues[Math.min(GRIDSIZE-1,Math.round(hsbSpecified[0]*GRIDSIZE))];
selectedOther=others[
Math.min(SUBGRIDSIZE-1,Math.round(hsbSpecified[1]*(SUBGRIDSIZE-1)))*SUBGRIDSIZE+
Math.min(SUBGRIDSIZE-1,Math.round(hsbSpecified[2]*(SUBGRIDSIZE-1)))];
pack();
setResizable(false);
setLocationRelativeTo(parent);
setVisible(true);
}
Color getChosenColour()
{
return chosen;
}
}