//----------------------------------------------------------------------------//
// //
// S h a p e C o l o r C h o o s e r //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.glyph.ui;
import omr.glyph.Shape;
import omr.glyph.ShapeSet;
import omr.ui.MainGui;
import org.jdesktop.application.Application;
import org.jdesktop.application.ResourceMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Class {@code ShapeColorChooser} offers a convenient user interface
* to choose proper color for each glyph shape.
* It is derived from the Sun Java tutorial ColorChooserDemo.
*
* <p>The right part of the panel is used by a classic color chooser
*
* <p>The left part of the panel is used by the shape at hand, with a way to
* browse through the various defined shapes.
*
* <p>The strategy is the following: First the predefined shape ranges (such as
* "Physicals", "Bars", "Clefs", ...) have their own color defined. Then, each
* individual shape within these shape ranges has its color assigned by default
* to the color of the containing range, unless a color is specifically assigned
* to this individual shape.
*
* @author Hervé Bitteur
*/
public class ShapeColorChooser
implements ChangeListener
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(
ShapeColorChooser.class);
private static JFrame frame;
//~ Instance fields --------------------------------------------------------
/** The classic color chooser utility */
private JColorChooser colorChooser;
/** Color chosen in the JColorChooser utility */
private Color chosenColor;
/** UI component */
private JPanel component;
/** To select shape range */
private RangesPane ranges;
/** To select shape (within selected range) */
private ShapesPane shapes;
//~ Constructors -----------------------------------------------------------
//-------------------//
// ShapeColorChooser //
//-------------------//
/**
* Create an instance of ShapeColorChooser (should be improved to always
* reuse the same instance. TODO)
*/
private ShapeColorChooser ()
{
component = new JPanel(new BorderLayout());
// Range Panel
ranges = new RangesPane();
shapes = new ShapesPane();
// Global Panel
JPanel globalPanel = new JPanel(new BorderLayout());
globalPanel.add(ranges, BorderLayout.NORTH);
globalPanel.add(shapes, BorderLayout.SOUTH);
globalPanel.setPreferredSize(new Dimension(400, 400));
// Color chooser
colorChooser = new JColorChooser();
colorChooser.getSelectionModel()
.addChangeListener(this);
colorChooser.setBorder(
BorderFactory.createTitledBorder("Choose Shape Color"));
component.add(globalPanel, BorderLayout.CENTER);
component.add(colorChooser, BorderLayout.EAST);
}
//~ Methods ----------------------------------------------------------------
//-----------//
// showFrame //
//-----------//
/**
* Display the UI frame.
*/
public static void showFrame ()
{
if (frame == null) {
frame = new JFrame();
frame.setName("shapeColorChooserFrame");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.add(new ShapeColorChooser().component);
// Resources injection
ResourceMap resource = Application.getInstance()
.getContext()
.getResourceMap(
ShapeColorChooser.class);
resource.injectComponents(frame);
}
MainGui.getInstance()
.show(frame);
}
//--------------//
// stateChanged //
//--------------//
/**
* Triggered when color selection in the color chooser has changed.
*
* @param e not used
*/
@Override
public void stateChanged (ChangeEvent e)
{
chosenColor = colorChooser.getColor();
///logger.info("chosenColor: " + chosenColor);
ranges.colorChanged();
shapes.colorChanged();
}
//~ Inner Classes ----------------------------------------------------------
//------//
// Pane //
//------//
private abstract class Pane
extends JPanel
{
//~ Instance fields ----------------------------------------------------
public JLabel banner = new JLabel("", JLabel.CENTER);
public JPopupMenu menu = new JPopupMenu();
//~ Constructors -------------------------------------------------------
public Pane (String title)
{
setLayout(new BorderLayout());
setBorder(BorderFactory.createTitledBorder(title));
banner.setForeground(Color.black);
banner.setBackground(Color.white);
banner.setOpaque(true);
banner.setFont(new Font("SansSerif", Font.BOLD, 18));
add(banner, BorderLayout.CENTER);
}
//~ Methods ------------------------------------------------------------
public abstract void colorChanged ();
protected abstract void refreshBanner ();
}
//------------//
// RangesPane //
//------------//
private class RangesPane
extends Pane
{
//~ Instance fields ----------------------------------------------------
public ShapeSet current;
private SelectAction select = new SelectAction();
private JButton selectButton = new JButton(select);
private PasteAction paste = new PasteAction();
private ActionListener selectionListener = new ActionListener()
{
// Called when a range has been selected
@Override
public void actionPerformed (ActionEvent e)
{
JMenuItem source = (JMenuItem) e.getSource();
current = ShapeSet.valueOf(source.getText());
if (current != null) {
banner.setText(current.getName());
Color color = current.getColor();
if (color != null) {
//colorChooser.setColor(color);
refreshBanner();
} else {
banner.setForeground(Color.black);
}
paste.setEnabled(false);
shapes.setRange();
} else {
banner.setText("");
}
}
};
private JButton pasteButton = new JButton(paste);
//~ Constructors -------------------------------------------------------
public RangesPane ()
{
super("Shape Range");
add(selectButton, BorderLayout.NORTH);
add(pasteButton, BorderLayout.SOUTH);
paste.setEnabled(false);
buildRangesMenu();
}
//~ Methods ------------------------------------------------------------
// When color chooser selection has been made
@Override
public void colorChanged ()
{
if (current != null) {
paste.setEnabled(true);
}
}
@Override
protected void refreshBanner ()
{
if (current != null) {
banner.setForeground(current.getColor());
}
}
private void buildRangesMenu ()
{
menu.removeAll();
ShapeSet.addAllShapeSets(menu, selectionListener);
}
//~ Inner Classes ------------------------------------------------------
private class PasteAction
extends AbstractAction
{
//~ Constructors ---------------------------------------------------
public PasteAction ()
{
super("Paste");
}
//~ Methods --------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
current.setConstantColor(chosenColor);
setEnabled(false);
refreshBanner();
buildRangesMenu();
// Forward to contained shapes ?
shapes.setRange();
}
}
private class SelectAction
extends AbstractAction
{
//~ Constructors ---------------------------------------------------
public SelectAction ()
{
super("Select");
}
//~ Methods --------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
JButton button = (JButton) e.getSource();
menu.show(RangesPane.this, button.getX(), button.getY());
}
}
}
//------------//
// ShapesPane //
//------------//
private class ShapesPane
extends Pane
{
//~ Instance fields ----------------------------------------------------
public Shape current;
private ActionListener selectionListener = new ActionListener()
{
// Called when a shape has been selected
@Override
public void actionPerformed (ActionEvent e)
{
JMenuItem source = (JMenuItem) e.getSource();
current = Shape.valueOf(source.getText());
banner.setText(current.toString());
// Check if a specific color is assigned
Color color = current.getColor();
if (color == ranges.current.getColor()) {
prepareDefaultOption();
refreshBanner();
} else {
prepareSpecificOption();
banner.setForeground(ranges.current.getColor());
}
}
};
private CopyAction copy = new CopyAction();
private CutAction cut = new CutAction();
private PasteAction paste = new PasteAction();
private SelectAction select = new SelectAction();
private JButton selectButton = new JButton(select);
private boolean isSpecific;
//~ Constructors -------------------------------------------------------
public ShapesPane ()
{
super("Individual Shape");
selectButton.setText("-- Select Shape --");
// No range has been selected yet, so no shape can be selected
select.setEnabled(false);
add(selectButton, BorderLayout.NORTH);
// A series of 3 buttons at the bottom
JPanel buttons = new JPanel(new GridLayout(1, 3));
buttons.add(new JButton(cut));
buttons.add(new JButton(copy));
buttons.add(new JButton(paste));
add(buttons, BorderLayout.SOUTH);
cut.setEnabled(false);
copy.setEnabled(false);
paste.setEnabled(false);
}
//~ Methods ------------------------------------------------------------
// When color chooser selection has been made
@Override
public void colorChanged ()
{
updateActions();
}
// When a new range has been selected
public void setRange ()
{
buildShapesMenu();
select.setEnabled(true);
selectButton.setText(
"-- Select Shape from " + ranges.current.getName() + " --");
current = null;
banner.setText("");
cut.setEnabled(false);
copy.setEnabled(false);
paste.setEnabled(false);
}
@Override
protected void refreshBanner ()
{
if (current != null) {
banner.setForeground(current.getColor());
}
}
private void buildShapesMenu ()
{
menu.removeAll();
// Add all shapes within current range
ShapeSet.addSetShapes(ranges.current, menu, selectionListener);
}
private void prepareDefaultOption ()
{
isSpecific = true;
updateActions();
}
private void prepareSpecificOption ()
{
isSpecific = false;
updateActions();
if (chosenColor != null) {
paste.setEnabled(chosenColor != ranges.current.getColor());
} else {
paste.setEnabled(false);
}
}
private void updateActions ()
{
if (current != null) {
cut.setEnabled(isSpecific);
copy.setEnabled(isSpecific);
paste.setEnabled(!isSpecific);
} else {
cut.setEnabled(false);
copy.setEnabled(false);
paste.setEnabled(false);
}
}
//~ Inner Classes ------------------------------------------------------
private class CopyAction
extends AbstractAction
{
//~ Constructors ---------------------------------------------------
public CopyAction ()
{
super("Copy");
}
//~ Methods --------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
colorChooser.setColor(current.getColor());
}
}
private class CutAction
extends AbstractAction
{
//~ Constructors ---------------------------------------------------
public CutAction ()
{
super("Cut");
}
//~ Methods --------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
// Drop specific for default
current.setColor(ranges.current.getColor());
prepareSpecificOption();
refreshBanner();
buildShapesMenu();
}
}
private class PasteAction
extends AbstractAction
{
//~ Constructors ---------------------------------------------------
public PasteAction ()
{
super("Paste");
}
//~ Methods --------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
// Set a specific color
current.setConstantColor(chosenColor);
prepareDefaultOption();
refreshBanner();
buildShapesMenu();
}
}
private class SelectAction
extends AbstractAction
{
//~ Constructors ---------------------------------------------------
public SelectAction ()
{
super("Select");
}
//~ Methods --------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
JButton button = (JButton) e.getSource();
menu.show(ShapesPane.this, button.getX(), button.getY());
}
}
}
}