package bibliothek.notes.view.actions.icon; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseEvent; import javax.swing.Icon; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.event.MouseInputAdapter; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import bibliothek.notes.model.Note; import bibliothek.notes.util.ResourceSet; import bibliothek.notes.view.actions.IconAction; /** * A panel showing a set of icons in a grid. The icons are read listed * in {@link ResourceSet#NOTE_ICONS}.<br> * Clients might use {@link #changeIcon(Note, Component, int, int)} to change * the image of a {@link Note}. * * @author Benjamin Sigg * @see IconAction * */ public class IconGrid extends JPanel{ /** An instance of IconGrid which can be used everywhere */ public static IconGrid GRID = new IconGrid(); /** the width and height of one icon */ private static final int ICON_SIZE = 16; /** the width and height of the grid */ private static final int GRID_SIZE = 24; /** the popup on which this panel lies */ private JPopupMenu popup; /** the Note whose image will be exchanged by this IconGrid */ private Note note; /** the index of the currently selected icon */ private int selection = -1; /** An observer of the mouse and the {@link #popup} */ private Listener listener = new Listener(); /** * Creates a new grid. */ public IconGrid(){ setBackground( Color.WHITE ); setForeground( new Color( 150, 150, 255 ) ); setFocusable( true ); addMouseListener( listener ); addMouseMotionListener( listener ); popup = new JPopupMenu(); popup.add( this ); popup.addPopupMenuListener( listener ); } @Override protected void paintComponent( Graphics g ){ super.paintComponent( g ); int size = ResourceSet.NOTE_ICONS.size(); int sqrt = (int)Math.sqrt( size ); if( sqrt*sqrt < size ) sqrt++; int index = 0; loop: for( int y = 0; y < sqrt; y++ ){ for( int x = 0; x < sqrt; x++ ){ if( index >= ResourceSet.NOTE_ICONS.size() ) break loop; if( selection == index ){ g.setColor( getForeground() ); g.fillRect( x*GRID_SIZE, y*GRID_SIZE, GRID_SIZE, GRID_SIZE ); } Icon icon = ResourceSet.NOTE_ICONS.get( index ); icon.paintIcon( this, g, x*GRID_SIZE + (GRID_SIZE-ICON_SIZE)/2, y*GRID_SIZE + (GRID_SIZE-ICON_SIZE)/2 ); index++; } } } /** * Gets the index of the icon which covers the coordinate <code>x/y</code>. * @param x the x-coordinate * @param y the y-coordinate * @return the icon or <code>null</code> */ private int iconAt( int x, int y ){ int size = ResourceSet.NOTE_ICONS.size(); int sqrt = (int)Math.sqrt( size ); if( sqrt*sqrt < size ) sqrt++; x /= GRID_SIZE; y /= GRID_SIZE; int index = x + y * sqrt; if( index < 0 || index > ResourceSet.NOTE_ICONS.size() ) return -1; return index; } @Override public Dimension getPreferredSize(){ int size = ResourceSet.NOTE_ICONS.size(); int sqrt = (int)Math.sqrt( size ); if( sqrt*sqrt < size ) sqrt++; int leftover = sqrt*sqrt - size; return new Dimension( GRID_SIZE*sqrt, GRID_SIZE*(sqrt - leftover/sqrt) ); } /** * Exchanges the image of <code>note</code>. A popup-panel is opened * above <code>owner</code> at the location <code>x/y</code>. * @param note the Note whose image will be changed * @param owner the parent of the popup-panel * @param x the x-coordinate of the popup, measured in the coordinate space of <code>owner</code> * @param y the y-coordinate of the popup, measured in the coordinate space of <code>owner</code> */ public void changeIcon( Note note, Component owner, int x, int y ){ selection = -1; repaint(); this.note = note; popup.show( owner, x, y ); } /** * A listener to the mouse over the grid, and to the visibility of the * popup. * @author Benjamin Sigg */ private class Listener extends MouseInputAdapter implements PopupMenuListener{ @Override public void mouseMoved( MouseEvent e ){ selection = iconAt( e.getX(), e.getY() ); repaint(); } @Override public void mouseReleased( MouseEvent e ){ if( note != null ){ int check = iconAt( e.getX(), e.getY() ); if( check == selection && selection >= 0 ){ note.setIcon( ResourceSet.NOTE_ICONS.get( check ) ); note = null; popup.setVisible( false ); } } } public void popupMenuCanceled( PopupMenuEvent e ){ note = null; } public void popupMenuWillBecomeInvisible( PopupMenuEvent e ){ // ignore } public void popupMenuWillBecomeVisible( PopupMenuEvent e ){ // ignore } } }