/* * (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 */ /** * Esta clase implementa los JTabbedPane. * Practicamente todo el esfuerzo se centra en pintar la pesta�a. * @author Nilo J. Gonzalez */ package com.nilo.plaf.nimrod; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; public class NimRODTabbedPaneUI extends BasicTabbedPaneUI { private Color selectColor; private int inclTab = 12; //private int anchoFocoV = inclTab; private int anchoFocoH = 0; private int anchoCarpetas = 18; private int rollover = -1; private int antRollover = -1; private MiML miml; /** * En este poligono se guarda la forma de la pesta�a. Es muy importante. */ private Polygon shape; public static ComponentUI createUI( JComponent c) { return new NimRODTabbedPaneUI(); } protected void installDefaults() { super.installDefaults(); rollover = -1; selectColor = NimRODLookAndFeel.getFocusColor(); tabAreaInsets.right = anchoCarpetas; } protected void installListeners() { super.installListeners(); miml = new MiML(); tabPane.addMouseMotionListener( miml); tabPane.addMouseListener( miml); } protected void uninstallListeners() { super.uninstallListeners(); tabPane.removeMouseMotionListener( miml); tabPane.removeMouseListener( miml); } protected void layoutLabel( int tabPlacement, FontMetrics metrics, int tabIndex, String title, Icon icon, Rectangle tabRect, Rectangle iconRect, Rectangle textRect, boolean isSelected) { Rectangle tabRectPeq = new Rectangle( tabRect); tabRectPeq.width -= inclTab; super.layoutLabel( tabPlacement, metrics, tabIndex, title, icon, tabRectPeq, iconRect, textRect, isSelected); } protected void paintTabArea( Graphics g, int tabPlacement, int selectedIndex) { if ( runCount > 1 ) { int lines[] = new int[runCount]; for ( int i = 0; i < runCount; i++) { lines[i] = rects[ tabRuns[i]].y + ( tabPlacement == TOP ? maxTabHeight : 0); } Arrays.sort( lines); Graphics2D g2D = (Graphics2D)g; g2D.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if ( tabPlacement == TOP ) { int fila = runCount; for ( int i = 0; i < lines.length-1; i++, fila--) { Polygon carp = new Polygon(); carp.addPoint( 0, lines[i]); carp.addPoint( tabPane.getWidth()-2*fila-2, lines[i]); carp.addPoint( tabPane.getWidth()-2*fila, lines[i]+3); if ( i < lines.length-2 ) { carp.addPoint( tabPane.getWidth()-2*fila, lines[i+1]); carp.addPoint( 0, lines[i+1]); } else { carp.addPoint( tabPane.getWidth()-2*fila, lines[i] + rects[selectedIndex].height); carp.addPoint( 0, lines[i] + rects[selectedIndex].height); } carp.addPoint( 0, lines[i]); g2D.setColor( hazAlfa( fila)); g2D.fillPolygon( carp); g2D.setColor( darkShadow.darker()); g2D.drawPolygon( carp); } } else { int fila = 0; for ( int i = 0; i < lines.length-1; i++, fila++) { Polygon carp = new Polygon(); carp.addPoint( 0, lines[i]); carp.addPoint( tabPane.getWidth()-2*fila-1, lines[i]); carp.addPoint( tabPane.getWidth()-2*fila-1, lines[i+1]-3); carp.addPoint( tabPane.getWidth()-2*fila-3, lines[i+1]); carp.addPoint( 0, lines[i+1]); carp.addPoint( 0, lines[i]); g2D.setColor( hazAlfa( fila+2)); g2D.fillPolygon( carp); g2D.setColor( darkShadow.darker()); g2D.drawPolygon( carp); } } g2D.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); } super.paintTabArea( g, tabPlacement, selectedIndex); } protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected ) { // Este es el primer metodo al que se llama, asi que aqui preparamos el shape que dibujara despues todo... Graphics2D g2D = (Graphics2D)g; g2D.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); GradientPaint gradientShadow; int xp[] = null; // Para la forma int yp[] = null; switch( tabPlacement ) { case LEFT: xp = new int[]{ x, x, x+w, x+w, x}; yp = new int[]{ y, y+h-3, y+h-3, y, y}; gradientShadow = new GradientPaint( x, y, NimRODUtils.getBrillo(), x, y+h, NimRODUtils.getSombra()); break; case RIGHT: xp = new int[]{ x, x, x+w-2, x+w-2, x}; yp = new int[]{ y, y+h-3, y+h-3, y, y}; gradientShadow = new GradientPaint( x, y, NimRODUtils.getBrillo(), x, y+h, NimRODUtils.getSombra()); break; case BOTTOM: xp = new int[]{ x, x, x+3, x+w-inclTab-6, x+w-inclTab-2, x+w-inclTab, x+w-3, x}; yp = new int[]{ y, y+h-3, y+h, y+h, y+h-1, y+h-3, y, y}; gradientShadow = new GradientPaint( x, y, NimRODUtils.getBrillo(), x, y+h, NimRODUtils.getSombra()); break; case TOP: default: xp = new int[]{ x, x, x+3, x+w-inclTab-6, x+w-inclTab-2, x+w-inclTab, x+w, x}; yp = new int[]{ y+h, y+3, y, y, y+1, y+3, y+h, y+h}; gradientShadow = new GradientPaint( x, y, NimRODUtils.getBrillo(), x, y+h, NimRODUtils.getSombra()); break; }; shape = new Polygon( xp, yp, xp.length); // Despues ponemos el color que toque if ( isSelected ) { g2D.setColor( selectColor ); } else { g2D.setColor( tabPane.getBackgroundAt( tabIndex)); } // Encima, pintamos la pesta�a con el color que sea g2D.fill( shape); // Encima, pintamos la pesta�a con el color que le corresponde por profundidad if ( runCount > 1 ) { g2D.setColor( hazAlfa( getRunForTab( tabPane.getTabCount(), tabIndex)-1)); g2D.fill( shape); } // Encima, pintamos un colorin si el raton esta por encima if ( tabIndex == rollover ) { g2D.setColor( NimRODUtils.getRolloverColor()); g2D.fill( shape); } // Y despues, le damos un sombreado que hace que parezca curbada (�A que duele ver algunas faltas de ortografia?) g2D.setPaint( gradientShadow); g2D.fill( shape); // Y al final le pintamos un bordecito para definir mejor la pesta�a g2D.setColor( NimRODUtils.getSombra()); g2D.draw( shape); g2D.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); } /** * Este metodo devuelve un tama�o mas grande de lo necesario, haciendoer hueco para * la decoracion. */ protected int calculateTabWidth( int tabPlacement, int tabIndex, FontMetrics metrics) { return 8 + inclTab + super.calculateTabWidth( tabPlacement, tabIndex, metrics); } /** * Este metodo devuelve un tama�o mas grande de lo necesario, haciendo el hueco para * la decoracion. */ protected int calculateTabHeight( int tabPlacement, int tabIndex, int fontHeight) { if ( tabPlacement == LEFT || tabPlacement == RIGHT ) { return super.calculateTabHeight( tabPlacement, tabIndex, fontHeight); } else { return anchoFocoH + super.calculateTabHeight( tabPlacement, tabIndex, fontHeight); } } /** * Este metodo dibuja el borde. */ protected void paintTabBorder( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { } /** * Este metodo dibuja una se�al amarilla en la solapa que tiene el foco */ protected void paintFocusIndicator( Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected) { if ( tabPane.hasFocus() && isSelected) { Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Stroke oldStroke = g2d.getStroke(); g2d.setStroke( new BasicStroke( 2.0f)); g2d.setColor( UIManager.getColor( "ScrollBar.thumbShadow")); g2d.drawPolygon( shape); g2d.setStroke( oldStroke); g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); } } /** * Esta funcion devuelve una sombra mas opaca cuanto mas arriba este la fila. * A partir de valores de fila superiores a 7 siempre devuelve el mismo color * @param fila int la fila a pintar */ protected Color hazAlfa( int fila) { int alfa = 0; if ( fila >= 0 ) { alfa = 50 + (fila > 7 ? 70 : 8*fila); } return new Color( 0,0,0, alfa); } ///////////////////////////////////// public class MiML extends MouseAdapter implements MouseMotionListener { public void mouseExited( MouseEvent e) { rollover = -1; tabPane.repaint(); } public void mouseDragged( MouseEvent e) {} public void mouseMoved( MouseEvent e) { rollover = tabForCoordinate( tabPane, e.getX(), e.getY()); // Esto es para limitar el numero de veces que se redibuja el panel // Un boton se puede pintar muchas veces porque es peque�o y gasta poco, pero esto es un panel que puede tener cienes y cienes de controles, // asi que cada vez que se repinta gasta lo suyo if ( (rollover == -1) && (antRollover == rollover) ) { return; } tabPane.repaint(); antRollover = rollover; } } }