/* * (C) Copyright 2005 Nilo J. Gonzalez * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser Gereral Public Licence as published by the Free * Software Foundation; either version 2 of the Licence, or (at your opinion) any * later version. * * This library is distributed in the hope that it will be usefull, but WITHOUT ANY * WARRANTY; without even the implied warranty of merchantability or fitness for a * particular purpose. See the GNU Lesser General Public Licence for more details. * * You should have received a copy of the GNU Lesser General Public Licence along * with this library; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, Ma 02111-1307 USA. * * http://www.gnu.org/licenses/lgpl.html (English) * http://gugs.sindominio.net/gnu-gpl/lgpl-es.html (Espa�ol) * * * Original author: Nilo J. Gonzalez */ package com.nilo.plaf.nimrod; import java.awt.*; import java.awt.event.*; import java.awt.geom.RoundRectangle2D; import javax.swing.*; import javax.swing.border.Border; import javax.swing.plaf.*; import javax.swing.plaf.metal.*; /** * * @author Nilo J. Gonzalez 2007 */ public class NimRODComboBoxUI extends MetalComboBoxUI { private boolean rollover = false; private boolean focus = false; private MiML miML; protected boolean oldOpaque; public static ComponentUI createUI( JComponent c) { return new NimRODComboBoxUI(); } protected void installDefaults() { super.installDefaults(); oldOpaque = comboBox.isOpaque(); comboBox.setOpaque( false); } protected void uninstallDefaults() { super.uninstallDefaults(); comboBox.setOpaque( oldOpaque); } protected void installListeners() { super.installListeners(); miML = new MiML(); comboBox.addMouseListener( miML); comboBox.addFocusListener( miML); } protected void uninstallListeners() { super.uninstallListeners(); comboBox.removeMouseListener( miML); comboBox.removeFocusListener( miML); } public Dimension getMinimumSize( JComponent c) { Dimension dim = super.getMinimumSize( c); if ( comboBox.isEditable() ) { dim.height = editor.getPreferredSize().height - 2; } dim.width += 20; return dim; } protected ComboBoxEditor createEditor() { return new NimRODComboBoxEditor(); } protected JButton createArrowButton() { return new NimRODComboBoxButton( comboBox, UIManager.getIcon( "ComboBox.buttonDownIcon"), (comboBox.isEditable() ? true : false), currentValuePane, listBox); } public class NimRODComboBoxEditor extends MetalComboBoxEditor { public NimRODComboBoxEditor() { super(); editor.setBorder( NimRODBorders.getComboEditorBorder()); } } private final class NimRODComboBoxButton extends MetalComboBoxButton { private static final long serialVersionUID = 1L; public NimRODComboBoxButton( JComboBox cb, Icon icon, boolean editable, CellRendererPane pane, JList list) { super( cb, icon, editable, pane, list); miML = new MiML(); addMouseListener( miML); addFocusListener( miML); } /* * Este metodo se a�ade para limitar la espuesta de los eventos de raton a la zona del boton en los * combos no editables. * en los combos no editables, TOOOOODO el combo es un boton, y como los botones capturan los eventos * de raton, por defecto no deja pasar ninguno a los posibles mouselisteners que se hayan registrado en * el JComboBox. Estos no se llegan a lanzar nunca porque los captura este boton. * Para evitarlo, se sobreescribe el metodo contains, que es invocado cada vez que se genera un evento * de raton y devuelve true si el evento debe ser tratado y false en caso contrario, para que la nueva * implementacion solo responda true en caso de que el raton se encuentre en el area del boton y no * cuando se encuentra sobre la parte que tiene texto. */ public boolean contains( int x, int y) { boolean res = super.contains( x, y); if ( res && !iconOnly ) { if ( x < (getWidth() - comboIcon.getIconWidth() - getInsets().right - 5) ) { res = false; } } return res; } /* * Esto es triky. * - Primero, le ponemos el borde que le viene bien segun sea * un boton o un cuadro de texto. No se puede hacer en el constructor porque cuando se construye el * objeto aun no se sabe si es editable (se muestra un simple boton con bordes de boton) o no * editable (todo es un boton, con bordes de textfield). Si es editable, pues borde de boton y a * correr, y si no, borde de editor y se ajustan algunas cosillas. Pero sobre todo, si es peque�o * se pone un borde que ocupa menos espacio. Es principalmente para que se pinten bien dentro de las * tablas * * - Segundo, si es editable se pinta tal cual, pero si no lo es, hay que hacer transparente el * renderer de cada fila porque si no cada vez que se pulsa se rellena del color del foco y * queda feisimo. Ademas, como super.paintComponent pinta el foco *SIEMPRE* y a mi no me gusta * como pinta el foco, hay que copiar el metodo padre y comentar la parte del foco para que no lo * pinte, que es por lo que esta ahi el metodo paintLeches. * * - Tercero, una vez pintado, hacemos un ajuste fino de lo que han pintado los JButton, que en * el caso de los cuadros editables consiste en borrar el sobrante de boton con el color del fondo * y tanto si es editable como si no, pintar el foco por el exterior del boton. */ public void paintComponent( Graphics g) { boolean canijo = false; if ( iconOnly ) { Border bb = NimRODBorders.getComboButtonBorder(); Insets ins = bb.getBorderInsets( comboBox); // Si cabe todo, le ponemos un borde guay. Si no, pues le dejamos un borde cutrecillo if ( ( getSize().height < (comboIcon.getIconHeight() + ins.top + ins.bottom) ) || ( getSize().width < (comboIcon.getIconWidth() + ins.left + ins.right) ) ) { canijo = true; bb = NimRODBorders.getThinGenBorder(); } setBorder( bb); setMargin( new Insets( 0,5,0,7)); } else { Border bb = NimRODBorders.getComboEditorBorder(); Insets ins = bb.getBorderInsets( comboBox); // Si cabe todo, le ponemos un borde guay. Si no, pues le dejamos un borde cutrecillo if ( getSize().height < (getFont().getSize() + ins.top + ins.bottom) ) { canijo = true; bb = NimRODBorders.getThinGenBorder(); } setBorder( bb); setOpaque( false); } if ( !iconOnly && comboBox != null) { try { // Le pintamos el fondo g.setColor( getBackground()); if ( !canijo ) { g.fillRect( 2,3, getWidth()-4, getHeight()-6); } else { g.fillRect( 0,0, getWidth(), getHeight()); } g.drawLine( 3,2, getWidth()-4, 2); g.drawLine( 3,getHeight()-3, getWidth()-4, getHeight()-3); paintLeches( g); } catch ( Exception ex) {} } if ( iconOnly ) { RoundRectangle2D.Float boton = new RoundRectangle2D.Float(); if ( canijo ) { boton.x = 0; boton.y = 0; boton.width = getWidth(); boton.height = getHeight(); boton.arcwidth = 1; boton.archeight = 1; } else { boton.x = 2; boton.y = 2; boton.width = getWidth() - 4; boton.height = getHeight() - 4; boton.arcwidth = 8; boton.archeight = 8; } setOpaque( false); paintLeches( g); ButtonModel mod = getModel(); Graphics2D g2D = (Graphics2D)g; g2D.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); GradientPaint grad = null; if ( mod.isPressed() || mod.isSelected() ) { grad = new GradientPaint( 0,0, NimRODUtils.getSombra(), 0,getHeight(), NimRODUtils.getBrillo()); g2D.setPaint( grad); g2D.fill( boton); } else { grad = new GradientPaint( 0,0, NimRODUtils.getBrillo(), 0,getHeight(), NimRODUtils.getSombra()); g2D.setPaint( grad); g2D.fill( boton); } g2D.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); } // Esto es para arreglar lo que deja el pintado por defecto if ( this.isEnabled() && !canijo ) { if ( focus ) { NimRODUtils.paintFocus( g, 1, 1, getWidth()-2, getHeight()-2, 4,4, 3, NimRODLookAndFeel.getFocusColor()); } else if ( rollover ) { NimRODUtils.paintFocus( g, 1, 1, getWidth()-2, getHeight()-2, 4,4, 3, NimRODUtils.getColorAlfa( NimRODLookAndFeel.getFocusColor(), 150)); } } } /* * Todo esto es porque la clase padre no pregunta si el focus se debe pintar cuando va a pintar el puto focus */ protected void paintLeches( Graphics g ) { boolean leftToRight = comboBox.getComponentOrientation().isLeftToRight(); if (ui != null) { Graphics scratchGraphics = (g == null) ? null : g.create(); try { ui.update( scratchGraphics, this); } finally { scratchGraphics.dispose(); } } Insets insets = getInsets(); int width = getWidth() - (insets.left + insets.right); int height = getHeight() - (insets.top + insets.bottom); if ( height <= 0 || width <= 0 ) { return; } int left = insets.left; int top = insets.top; int right = left + (width - 1); int bottom = top + (height - 1); int iconWidth = 0; int iconLeft = (leftToRight) ? right : left; // Paint the icon if ( comboIcon != null ) { iconWidth = comboIcon.getIconWidth(); int iconHeight = comboIcon.getIconHeight(); int iconTop = 0; if ( iconOnly ) { iconLeft = (getWidth() / 2) - (iconWidth / 2); iconTop = (getHeight() / 2) - (iconHeight / 2); } else { if (leftToRight) { iconLeft = (left + (width - 1)) - iconWidth; } else { iconLeft = left; } iconTop = (top + ((bottom - top) / 2)) - (iconHeight / 2); } comboIcon.paintIcon( this, g, iconLeft, iconTop ); // Se a�ade esto para pintar un limite al boton de despliegue if ( !iconOnly ) { g.setColor( NimRODUtils.getSombra()); g.drawLine( iconLeft-5,6, iconLeft-5,getHeight()-6); g.setColor( NimRODUtils.getBrillo()); g.drawLine( iconLeft-4,6, iconLeft-4,getHeight()-6); } // Paint the focus /* Esto queda comentado porque pinta el focus SIEMPRE, aunque yo no quiera... if ( comboBox.hasFocus()) { g.setColor( MetalLookAndFeel.getFocusColor() ); g.drawRect( left - 1, top - 1, width + 3, height + 1 ); } */ } // Let the renderer paint if ( !iconOnly && comboBox != null ) { ListCellRenderer renderer = comboBox.getRenderer(); Component c; boolean renderPressed = getModel().isPressed(); c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, renderPressed, false); c.setFont(rendererPane.getFont()); if ( model.isArmed() && model.isPressed() ) { /* if ( isOpaque() ) { c.setBackground( UIManager.getColor( "Button.select")); } */ c.setForeground( comboBox.getForeground()); // Esto se pone para que el combo no se ponga amarillo al pulsarse c.setBackground( getBackground()); } else if ( !comboBox.isEnabled() ) { if ( isOpaque() ) { c.setBackground(UIManager.getColor("ComboBox.disabledBackground")); } c.setForeground(UIManager.getColor("ComboBox.disabledForeground")); } else { c.setForeground( comboBox.getForeground()); c.setBackground( comboBox.getBackground()); } int cWidth = width - (insets.right + iconWidth); // Fix for 4238829: should lay out the JPanel. boolean shouldValidate = false; if (c instanceof JPanel) { shouldValidate = true; } if (leftToRight) { rendererPane.paintComponent( g, c, this, left, top, cWidth, height, shouldValidate ); } else { rendererPane.paintComponent( g, c, this, left + iconWidth, top, cWidth, height, shouldValidate ); } } } } ////////////////////////// public class MiML extends MouseAdapter implements FocusListener { protected void refresh() { if ( comboBox != null && comboBox.getParent() != null ) { comboBox.getParent().repaint( comboBox.getX()-5, comboBox.getY()-5, comboBox.getWidth()+10, comboBox.getHeight()+10); } } public void mouseExited( MouseEvent e) { rollover = false; refresh(); } public void mouseEntered( MouseEvent e) { rollover = true; refresh(); } public void focusGained( FocusEvent e) { focus = true; refresh(); } public void focusLost( FocusEvent e) { focus = false; refresh(); } } }