/*******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tiny Look and Feel * * (C) Copyright 2003 - 2007 Hans Bickel * * For
* licensing information and credits, please refer to the * comment in file
* de.muntjak.tinylookandfeel.TinyLookAndFeel * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
package de.muntjak.tinylookandfeel;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicGraphicsUtils;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import javax.swing.text.View;
import de.muntjak.tinylookandfeel.controlpanel.ColorRoutines;
import de.muntjak.tinylookandfeel.controlpanel.DrawRoutines;
/**
* TinyTabbedPaneUI
*
* @version 1.3.04
* @author Hans Bickel
*/
@SuppressWarnings (
{ "all" } )
public class TinyTabbedPaneUI extends BasicTabbedPaneUI
{
/**
* Creates the UI delegate for the given component.
*
* @param c The component to create its UI delegate.
* @return The UI delegate for the given component.
*/
public static ComponentUI createUI ( JComponent c )
{
return new TinyTabbedPaneUI ();
}
int rollover = -1;
protected void installListeners ()
{
super.installListeners ();
tabPane.addMouseMotionListener ( ( MouseMotionListener ) mouseListener );
}
protected MouseListener createMouseListener ()
{
return new TinyMouseHandler ();
}
protected void installDefaults ()
{
super.installDefaults ();
}
private boolean scrollableTabLayoutEnabled ()
{
return ( tabPane.getTabLayoutPolicy () == JTabbedPane.SCROLL_TAB_LAYOUT );
}
private void checkRollOver ( int tabIndex )
{
if ( rollover >= tabPane.getTabCount () )
{
rollover = -1;
}
if ( tabIndex == rollover )
return;
if ( rollover != -1 )
{ // Update old rollover
tabPane.repaint ( getTabBounds ( tabPane, rollover ) );
if ( tabIndex == -1 )
rollover = -1;
}
if ( tabIndex >= 0 && tabPane.isEnabledAt ( tabIndex ) )
{
// Paint new rollover
rollover = tabIndex;
tabPane.repaint ( getTabBounds ( tabPane, tabIndex ) );
}
}
/**
* Overridden so we can enable/disable tab rotating using
* TinyTabbedPaneLayout. Invoked by <code>installUI</code> to create a
* layout manager object to manage the <code>JTabbedPane</code>.
*
* @return a layout manager object
* @see TabbedPaneLayout
* @see javax.swing.JTabbedPane#getTabLayoutPolicy
*/
protected LayoutManager createLayoutManager ()
{
if ( tabPane.getTabLayoutPolicy () == JTabbedPane.SCROLL_TAB_LAYOUT )
{
return super.createLayoutManager ();
}
else
{ /* WRAP_TAB_LAYOUT */
return new TinyTabbedPaneLayout ();
}
}
private int getTabAtLocation ( int x, int y )
{
if ( TinyLookAndFeel.is1dot4 () )
{
ensureCurrentLayout ();
int tabCount = tabPane.getTabCount ();
for ( int i = 0 ; i < tabCount ; i++ )
{
if ( rects [ i ].contains ( x, y ) )
{
return i;
}
}
return -1;
}
else
{ // JRE 1.5 or higher
return tabForCoordinate ( tabPane, x, y );
}
}
private void ensureCurrentLayout ()
{
if ( !tabPane.isValid () )
{
tabPane.validate ();
}
/*
* If tabPane doesn't have a peer yet, the validate() call will silently
* fail. We handle that by forcing a layout if tabPane is still invalid. See
* bug 4237677.
*/
if ( !tabPane.isValid () )
{
TabbedPaneLayout layout = ( TabbedPaneLayout ) tabPane.getLayout ();
layout.calculateLayoutInfo ();
}
}
public class TinyMouseHandler implements MouseListener, MouseMotionListener
{
public void mousePressed ( MouseEvent e )
{
if ( !tabPane.isEnabled () )
return;
// 1.3.04 code - see getTabAtLocation(int, int) for
// JRE 1.5 fix
int tabIndex = getTabAtLocation ( e.getX (), e.getY () );
if ( tabIndex >= 0 && tabPane.isEnabledAt ( tabIndex ) )
{
if ( tabIndex != tabPane.getSelectedIndex () )
{
// Clicking on unselected tab, change selection, do NOT
// request focus.
// This will trigger the focusIndex to change by way
// of stateChanged.
tabPane.setSelectedIndex ( tabIndex );
}
else if ( tabPane.isRequestFocusEnabled () )
{
// Clicking on selected tab, try and give the tabbedpane
// focus. Repaint will occur in focusGained.
tabPane.requestFocus ();
}
}
}
public void mouseEntered ( MouseEvent e )
{
}
public void mouseExited ( MouseEvent e )
{
if ( rollover >= tabPane.getTabCount () )
{
rollover = -1;
}
if ( rollover != -1 )
{
tabPane.repaint ( getTabBounds ( tabPane, rollover ) );
rollover = -1;
}
}
public void mouseClicked ( MouseEvent e )
{
}
public void mouseReleased ( MouseEvent e )
{
}
public void mouseDragged ( MouseEvent e )
{
}
public void mouseMoved ( MouseEvent e )
{
if ( tabPane == null )
return;
if ( !tabPane.isEnabled () )
return;
// Note: When running JRE v1.4 there's no way to do
// tab rollovers with SCROLL_TAB_LAYOUT
if ( TinyLookAndFeel.is1dot4 () && scrollableTabLayoutEnabled () )
return;
checkRollOver ( getTabAtLocation ( e.getX (), e.getY () ) );
}
}
/**
* Paints the backround of a given tab.
*
* @param g The graphics context.
* @param tabPlacement The placement of the tab to paint.
* @param tabIndex The index of the tab to paint.
* @param x The x coordinate of the top left corner.
* @param y The y coordinate of the top left corner.
* @param w The width.
* @param h The height.
* @param isSelected True if the tab to paint is selected otherwise false.
*/
protected void paintTabBackground ( Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h, boolean isSelected )
{
boolean isEnabled = ( tabPane.isEnabledAt ( tabIndex ) );
if ( !tabPane.isEnabled () )
isEnabled = false;
if ( isSelected && !Theme.ignoreSelectedBg [ Theme.style ] )
{
if ( isEnabled )
{
g.setColor ( Theme.tabSelectedColor [ Theme.style ].getColor () );
}
else
{
g
.setColor ( Theme.tabDisabledSelectedColor [ Theme.style ]
.getColor () );
}
}
else
{
if ( isEnabled )
{
// because (Tiny)JTabbedPane now has a defined
// background color, this should work
g.setColor ( tabPane.getBackgroundAt ( tabIndex ) );
}
else
{
g.setColor ( Theme.tabDisabledColor [ Theme.style ].getColor () );
}
}
switch ( tabPlacement )
{
case LEFT :
g.fillRect ( x + 1, y + 1, w - 1, h - 3 );
break;
case RIGHT :
x -= 2;
g.fillRect ( x, y + 1, w - 1, h - 3 );
break;
case BOTTOM :
y -= 2;
g.fillRect ( x + 1, y, w - 3, h - 1 );
break;
case TOP :
default :
g.fillRect ( x + 1, y + 1, w - 3, h - 1 );
}
}
/**
* Paints the border of a given tab.
*
* @param g The graphics context.
* @param tabPlacement The placement of the tab to paint.
* @param selectedIndex The index of the selected tab.
*/
protected void paintContentBorder ( Graphics g, int tabPlacement,
int selectedIndex )
{
}
/**
* @see javax.swing.plaf.basic.BasicTabbedPaneUI#paintFocusIndicator(Graphics,
* int, Rectangle[], int, Rectangle, Rectangle, boolean)
*/
protected void paintFocusIndicator ( Graphics g, int tabPlacement,
Rectangle [] rects, int tabIndex, Rectangle iconRect, Rectangle textRect,
boolean isSelected )
{
if ( !Theme.tabFocus [ Theme.style ] )
return;
Rectangle tabRect = rects [ tabIndex ];
if ( tabPane.hasFocus () && isSelected )
{
int x, y, w, h;
g.setColor ( Theme.tabFontColor [ Theme.style ].getColor () );
switch ( tabPlacement )
{
case LEFT :
x = tabRect.x + 3;
y = tabRect.y + 3;
w = tabRect.width - 5;
h = tabRect.height - 7;
break;
case RIGHT :
x = tabRect.x;
y = tabRect.y + 3;
w = tabRect.width - 5;
h = tabRect.height - 7;
break;
case BOTTOM :
x = tabRect.x + 3;
y = tabRect.y;
w = tabRect.width - 7;
h = tabRect.height - 5;
break;
case TOP :
default :
x = tabRect.x + 3;
y = tabRect.y + 3;
w = tabRect.width - 7;
h = tabRect.height - 5;
}
BasicGraphicsUtils.drawDashedRect ( g, x, y, w, h );
}
}
/**
* Draws the border around each tab.
*
* @param g The graphics context.
* @param tabPlacement The placement of the tabs.
* @param tabIndex The index of the tab to paint.
* @param x The x coordinate of the top left corner.
* @param y The y coordinate of the top left corner.
* @param w The width.
* @param h The height.
* @param isSelected True if the tab to paint is selected otherwise false.
*/
protected void paintTabBorder ( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected )
{
boolean isEnabled = ( tabPane.isEnabledAt ( tabIndex ) );
if ( !tabPane.isEnabled () )
isEnabled = false;
boolean isRollover = ( rollover == tabIndex );
switch ( Theme.derivedStyle [ Theme.style ] )
{
case Theme.TINY_STYLE :
drawTinyTabBorder ( g, tabPlacement, x, y, w, h, isSelected, isEnabled,
isRollover );
break;
case Theme.W99_STYLE :
drawWinTabBorder ( g, tabPlacement, x, y, w, h, isSelected, isEnabled,
isRollover );
break;
case Theme.YQ_STYLE :
drawXpTabBorder ( g, tabPlacement, x, y, w, h, isSelected, isEnabled,
isRollover );
break;
}
}
private void drawTinyTabBorder ( Graphics g, int tabPlacement, int x, int y,
int w, int h, boolean isSelected, boolean isEnabled, boolean isRollover )
{
}
private void drawWinTabBorder ( Graphics g, int tabPlacement, int x, int y,
int w, int h, boolean isSelected, boolean isEnabled, boolean isRollover )
{
g.setColor ( Theme.tabLightColor [ Theme.style ].getColor () );
switch ( tabPlacement )
{
case SwingConstants.LEFT :
g.drawLine ( x + 2, y, x + w - 1, y );
g.drawLine ( x + 1, y + 1, x + 1, y + 1 );
g.drawLine ( x, y + 2, x, y + h - 3 );
g.setColor ( Theme.tabDarkColor [ Theme.style ].getColor () );
g.drawLine ( x + 2, y + h - 2, x + w - 1, y + h - 2 );
g.setColor ( Theme.tabBorderColor [ Theme.style ].getColor () );
g.drawLine ( x + 2, y + h - 1, x + w - 1, y + h - 1 );
g.drawLine ( x + 1, y + h - 2, x + 1, y + h - 2 );
break;
case SwingConstants.RIGHT :
g.drawLine ( x + w - 3, y, x, y );
g.drawLine ( x + w - 2, y + 1, x + w - 2, y + 1 );
g.drawLine ( x + w - 1, y + 2, x + w - 1, y + h - 3 );
g.setColor ( Theme.tabDarkColor [ Theme.style ].getColor () );
g.drawLine ( x + w - 3, y + h - 2, x, y + h - 2 );
g.setColor ( Theme.tabBorderColor [ Theme.style ].getColor () );
g.drawLine ( x + w - 3, y + h - 1, x, y + h - 1 );
g.drawLine ( x + w - 2, y + h - 2, x + w - 2, y + h - 2 );
break;
case SwingConstants.BOTTOM :
g.drawLine ( x + 2, y + h - 1, x + w - 3, y + h - 1 );
g.drawLine ( x, y + h - 3, x, y );
g.drawLine ( x + 1, y + h - 2, x + 1, y + h - 2 );
g.setColor ( Theme.tabDarkColor [ Theme.style ].getColor () );
g.drawLine ( x + w - 2, y + h - 3, x + w - 2, y );
g.setColor ( Theme.tabBorderColor [ Theme.style ].getColor () );
g.drawLine ( x + w - 1, y + h - 3, x + w - 1, y );
g.drawLine ( x + w - 2, y + h - 2, x + w - 2, y + h - 2 );
break;
case SwingConstants.TOP :
default :
g.drawLine ( x + 2, y, x + w - 3, y );
g.drawLine ( x, y + 2, x, y + h - 1 );
g.drawLine ( x + 1, y + 1, x + 1, y + 1 );
g.setColor ( Theme.tabDarkColor [ Theme.style ].getColor () );
g.drawLine ( x + w - 2, y + 2, x + w - 2, y + h - 1 );
g.setColor ( Theme.tabBorderColor [ Theme.style ].getColor () );
g.drawLine ( x + w - 1, y + 2, x + w - 1, y + h - 1 );
g.drawLine ( x + w - 2, y + 1, x + w - 2, y + 1 );
}
}
private void drawXpTabBorder ( Graphics g, int tabPlacement, int x, int y,
int w, int h, boolean isSelected, boolean isEnabled, boolean isRollover )
{
if ( !isEnabled )
{
DrawRoutines.drawXpTabBorder ( g, Theme.tabBorderColor [ Theme.style ]
.getColor (), x, y, w, h, tabPlacement );
}
else if ( isSelected )
{
DrawRoutines.drawSelectedXpTabBorder ( g,
Theme.tabBorderColor [ Theme.style ].getColor (), x, y, w, h,
tabPlacement );
}
else if ( isRollover && Theme.tabRollover [ Theme.style ] )
{
DrawRoutines.drawSelectedXpTabBorder ( g,
Theme.tabBorderColor [ Theme.style ].getColor (), x, y, w, h,
tabPlacement );
}
else
{
DrawRoutines.drawXpTabBorder ( g, Theme.tabBorderColor [ Theme.style ]
.getColor (), x, y, w, h, tabPlacement );
}
}
/**
* Paint the border and then call paint().
*/
public void update ( Graphics g, JComponent c )
{
Insets insets = tabPane.getInsets ();
int x = insets.left;
int y = insets.top;
int w = tabPane.getWidth () - insets.right - insets.left;
int h = tabPane.getHeight () - insets.top - insets.bottom;
if ( c.isOpaque () )
{
g.setColor ( Theme.backColor [ Theme.style ].getColor () );
g.fillRect ( 0, 0, c.getWidth (), c.getHeight () );
}
int tabPlacement = tabPane.getTabPlacement ();
switch ( tabPlacement )
{
case LEFT :
x += calculateTabAreaWidth ( tabPlacement, runCount, maxTabWidth );
w -= ( x - insets.left );
break;
case RIGHT :
w -= calculateTabAreaWidth ( tabPlacement, runCount, maxTabWidth );
break;
case BOTTOM :
h -= calculateTabAreaHeight ( tabPlacement, runCount, maxTabHeight );
break;
case TOP :
default :
y += calculateTabAreaHeight ( tabPlacement, runCount, maxTabHeight );
h -= ( y - insets.top );
}
switch ( Theme.derivedStyle [ Theme.style ] )
{
case Theme.TINY_STYLE :
drawTinyContentBorder ( g, x, y, w, h );
break;
case Theme.W99_STYLE :
drawWinContentBorder ( g, x, y, w, h );
break;
case Theme.YQ_STYLE :
drawXpContentBorder ( g, x, y, w, h );
break;
}
super.paint ( g, c );
}
private void drawTinyContentBorder ( Graphics g, int x, int y, int w, int h )
{
}
private void drawWinContentBorder ( Graphics g, int x, int y, int w, int h )
{
g.setColor ( Theme.tabPaneLightColor [ Theme.style ].getColor () );
g.drawLine ( x + 1, y, x + w - 2, y ); // top
g.drawLine ( x, y, x, y + h - 2 ); // left
g.setColor ( Theme.tabPaneDarkColor [ Theme.style ].getColor () );
g.drawLine ( x + 1, y + h - 2, x + w - 2, y + h - 2 ); // bottom
g.drawLine ( x + w - 2, y + 1, x + w - 2, y + h - 2 ); // right
g.setColor ( Theme.tabPaneBorderColor [ Theme.style ].getColor () );
g.drawLine ( x, y + h - 1, x + w - 2, y + h - 1 ); // bottom
g.drawLine ( x + w - 1, y, x + w - 1, y + h - 1 ); // right
}
private void drawXpContentBorder ( Graphics g, int x, int y, int w, int h )
{
g.setColor ( Theme.tabPaneBorderColor [ Theme.style ].getColor () );
g.drawRect ( x, y, w - 3, h - 3 );
// Shadow
g.setColor ( ColorRoutines.darken ( Theme.backColor [ Theme.style ]
.getColor (), 15 ) );
g.drawLine ( x + w - 2, y + 1, x + w - 2, y + h - 2 ); // right
g.drawLine ( x + 1, y + h - 2, x + w - 3, y + h - 2 ); // bottom
}
protected int getTabLabelShiftX ( int tabPlacement, int tabIndex,
boolean isSelected )
{
Rectangle tabRect = rects [ tabIndex ];
int nudge = 0;
switch ( tabPlacement )
{
case LEFT :
nudge = isSelected ? -1 : 1;
break;
case RIGHT :
nudge = isSelected ? 1 : -1;
break;
case BOTTOM :
case TOP :
default :
nudge = 0;
}
return nudge;
}
protected int getTabLabelShiftY ( int tabPlacement, int tabIndex,
boolean isSelected )
{
Rectangle tabRect = rects [ tabIndex ];
int nudge = 0;
switch ( tabPlacement )
{
case BOTTOM :
nudge = isSelected ? 1 : -1;
break;
case LEFT :
case RIGHT :
nudge = tabRect.height % 2;
break;
case TOP :
default :
nudge = isSelected ? -1 : 1;
}
return nudge;
}
protected void paintText ( Graphics g, int tabPlacement, Font font,
FontMetrics metrics, int tabIndex, String title, Rectangle textRect,
boolean isSelected )
{
if ( Theme.derivedStyle [ Theme.style ] == Theme.W99_STYLE )
{
super.paintText ( g, tabPlacement, font, metrics, tabIndex, title,
textRect, isSelected );
return;
}
g.setFont ( font );
View v = getTextViewForTab ( tabIndex );
if ( v != null )
{
// html
v.paint ( g, textRect );
}
else
{
// plain text
int mnemIndex = tabPane.getDisplayedMnemonicIndexAt ( tabIndex );
if ( tabPane.isEnabled () && tabPane.isEnabledAt ( tabIndex ) )
{
g.setColor ( tabPane.getForegroundAt ( tabIndex ) );
}
else
{ // tab disabled
g.setColor ( Theme.tabDisabledTextColor [ Theme.style ].getColor () );
}
BasicGraphicsUtils.drawStringUnderlineCharAt ( g, title, mnemIndex,
textRect.x, textRect.y + metrics.getAscent () );
}
}
protected class TinyTabbedPaneLayout extends TabbedPaneLayout
{
protected void rotateTabRuns ( int tabPlacement, int selectedRun )
{
if ( !Theme.fixedTabs [ Theme.style ] )
{
super.rotateTabRuns ( tabPlacement, selectedRun );
}
}
}
}