/*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.plaf.metal;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.plaf.*;
import java.io.Serializable;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
The Metal subclass of BasicTabbedPaneUI.
Warning:
Serialized objects of this class will not be compatible with
future Swing releases. The current serialization support is
appropriate for short term storage or RMI between applications running
the same version of Swing. As of 1.4, support for long term storage
of all JavaBeans™
has been added to the java.beans
package. Please see XMLEncoder
.
Author: Tom Santos
/**
* The Metal subclass of BasicTabbedPaneUI.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans™
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Tom Santos
*/
@SuppressWarnings("serial") // Same-version serialization only
public class MetalTabbedPaneUI extends BasicTabbedPaneUI {
The minimum width of a pane.
/**
* The minimum width of a pane.
*/
protected int minTabWidth = 40;
// Background color for unselected tabs that don't have an explicitly
// set color.
private Color unselectedBackground;
The color of tab's background.
/**
* The color of tab's background.
*/
protected Color tabAreaBackground;
The color of the selected pane.
/**
* The color of the selected pane.
*/
protected Color selectColor;
The color of the highlight.
/**
* The color of the highlight.
*/
protected Color selectHighlight;
private boolean tabsOpaque = true;
// Whether or not we're using ocean. This is cached as it is used
// extensively during painting.
private boolean ocean;
// Selected border color for ocean.
private Color oceanSelectedBorderColor;
Constructs MetalTabbedPaneUI
. Params: - x – a component
Returns: an instance of MetalTabbedPaneUI
/**
* Constructs {@code MetalTabbedPaneUI}.
*
* @param x a component
* @return an instance of {@code MetalTabbedPaneUI}
*/
public static ComponentUI createUI( JComponent x ) {
return new MetalTabbedPaneUI();
}
protected LayoutManager createLayoutManager() {
if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
return super.createLayoutManager();
}
return new TabbedPaneLayout();
}
protected void installDefaults() {
super.installDefaults();
tabAreaBackground = UIManager.getColor("TabbedPane.tabAreaBackground");
selectColor = UIManager.getColor("TabbedPane.selected");
selectHighlight = UIManager.getColor("TabbedPane.selectHighlight");
tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
unselectedBackground = UIManager.getColor(
"TabbedPane.unselectedBackground");
ocean = MetalLookAndFeel.usingOcean();
if (ocean) {
oceanSelectedBorderColor = UIManager.getColor(
"TabbedPane.borderHightlightColor");
}
}
protected void paintTabBorder( Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h,
boolean isSelected) {
int bottom = y + (h-1);
int right = x + (w-1);
switch ( tabPlacement ) {
case LEFT:
paintLeftTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
break;
case BOTTOM:
paintBottomTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
break;
case RIGHT:
paintRightTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
break;
case TOP:
default:
paintTopTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
}
}
Paints the top tab border.
Params: - tabIndex – a tab index
- g – an instance of
Graphics
- x – an X coordinate
- y – an Y coordinate
- w – a width
- h – a height
- btm – bottom
- rght – right
- isSelected – a selection
/**
* Paints the top tab border.
*
* @param tabIndex a tab index
* @param g an instance of {@code Graphics}
* @param x an X coordinate
* @param y an Y coordinate
* @param w a width
* @param h a height
* @param btm bottom
* @param rght right
* @param isSelected a selection
*/
protected void paintTopTabBorder( int tabIndex, Graphics g,
int x, int y, int w, int h,
int btm, int rght,
boolean isSelected ) {
int currentRun = getRunForTab( tabPane.getTabCount(), tabIndex );
int lastIndex = lastTabInRun( tabPane.getTabCount(), currentRun );
int firstIndex = tabRuns[ currentRun ];
boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
int selectedIndex = tabPane.getSelectedIndex();
int bottom = h - 1;
int right = w - 1;
//
// Paint Gap
//
if (shouldFillGap( currentRun, tabIndex, x, y ) ) {
g.translate( x, y );
if ( leftToRight ) {
g.setColor( getColorForGap( currentRun, x, y + 1 ) );
g.fillRect( 1, 0, 5, 3 );
g.fillRect( 1, 3, 2, 2 );
} else {
g.setColor( getColorForGap( currentRun, x + w - 1, y + 1 ) );
g.fillRect( right - 5, 0, 5, 3 );
g.fillRect( right - 2, 3, 2, 2 );
}
g.translate( -x, -y );
}
g.translate( x, y );
//
// Paint Border
//
if (ocean && isSelected) {
g.setColor(oceanSelectedBorderColor);
}
else {
g.setColor( darkShadow );
}
if ( leftToRight ) {
// Paint slant
g.drawLine( 1, 5, 6, 0 );
// Paint top
g.drawLine( 6, 0, right, 0 );
// Paint right
if ( tabIndex==lastIndex ) {
// last tab in run
g.drawLine( right, 1, right, bottom );
}
if (ocean && tabIndex - 1 == selectedIndex &&
currentRun == getRunForTab(
tabPane.getTabCount(), selectedIndex)) {
g.setColor(oceanSelectedBorderColor);
}
// Paint left
if ( tabIndex != tabRuns[ runCount - 1 ] ) {
// not the first tab in the last run
if (ocean && isSelected) {
g.drawLine(0, 6, 0, bottom);
g.setColor(darkShadow);
g.drawLine(0, 0, 0, 5);
}
else {
g.drawLine( 0, 0, 0, bottom );
}
} else {
// the first tab in the last run
g.drawLine( 0, 6, 0, bottom );
}
} else {
// Paint slant
g.drawLine( right - 1, 5, right - 6, 0 );
// Paint top
g.drawLine( right - 6, 0, 0, 0 );
// Paint left
if ( tabIndex==lastIndex ) {
// last tab in run
g.drawLine( 0, 1, 0, bottom );
}
// Paint right
if (ocean && tabIndex - 1 == selectedIndex &&
currentRun == getRunForTab(
tabPane.getTabCount(), selectedIndex)) {
g.setColor(oceanSelectedBorderColor);
g.drawLine(right, 0, right, bottom);
}
else if (ocean && isSelected) {
g.drawLine(right, 6, right, bottom);
if (tabIndex != 0) {
g.setColor(darkShadow);
g.drawLine(right, 0, right, 5);
}
}
else {
if ( tabIndex != tabRuns[ runCount - 1 ] ) {
// not the first tab in the last run
g.drawLine( right, 0, right, bottom );
} else {
// the first tab in the last run
g.drawLine( right, 6, right, bottom );
}
}
}
//
// Paint Highlight
//
g.setColor( isSelected ? selectHighlight : highlight );
if ( leftToRight ) {
// Paint slant
g.drawLine( 1, 6, 6, 1 );
// Paint top
g.drawLine( 6, 1, (tabIndex == lastIndex) ? right - 1 : right, 1 );
// Paint left
g.drawLine( 1, 6, 1, bottom );
// paint highlight in the gap on tab behind this one
// on the left end (where they all line up)
if ( tabIndex==firstIndex && tabIndex!=tabRuns[runCount - 1] ) {
// first tab in run but not first tab in last run
if (tabPane.getSelectedIndex()==tabRuns[currentRun+1]) {
// tab in front of selected tab
g.setColor( selectHighlight );
}
else {
// tab in front of normal tab
g.setColor( highlight );
}
g.drawLine( 1, 0, 1, 4 );
}
} else {
// Paint slant
g.drawLine( right - 1, 6, right - 6, 1 );
// Paint top
g.drawLine( right - 6, 1, 1, 1 );
// Paint left
if ( tabIndex==lastIndex ) {
// last tab in run
g.drawLine( 1, 1, 1, bottom );
} else {
g.drawLine( 0, 1, 0, bottom );
}
}
g.translate( -x, -y );
}
Returns true
if the gap should be filled. Params: - currentRun – the current run
- tabIndex – the tab index
- x – an X coordinate
- y – an Y coordinate
Returns: true
if the gap should be filled
/**
* Returns {@code true} if the gap should be filled.
*
* @param currentRun the current run
* @param tabIndex the tab index
* @param x an X coordinate
* @param y an Y coordinate
* @return {@code true} if the gap should be filled
*/
protected boolean shouldFillGap( int currentRun, int tabIndex, int x, int y ) {
boolean result = false;
if (!tabsOpaque) {
return false;
}
if ( currentRun == runCount - 2 ) { // If it's the second to last row.
Rectangle lastTabBounds = getTabBounds( tabPane, tabPane.getTabCount() - 1 );
Rectangle tabBounds = getTabBounds( tabPane, tabIndex );
if (MetalUtils.isLeftToRight(tabPane)) {
int lastTabRight = lastTabBounds.x + lastTabBounds.width - 1;
// is the right edge of the last tab to the right
// of the left edge of the current tab?
if ( lastTabRight > tabBounds.x + 2 ) {
return true;
}
} else {
int lastTabLeft = lastTabBounds.x;
int currentTabRight = tabBounds.x + tabBounds.width - 1;
// is the left edge of the last tab to the left
// of the right edge of the current tab?
if ( lastTabLeft < currentTabRight - 2 ) {
return true;
}
}
} else {
// fill in gap for all other rows except last row
result = currentRun != runCount - 1;
}
return result;
}
Returns the color of the gap.
Params: - currentRun – the current run
- x – an X coordinate
- y – an Y coordinate
Returns: the color of the gap
/**
* Returns the color of the gap.
*
* @param currentRun the current run
* @param x an X coordinate
* @param y an Y coordinate
* @return the color of the gap
*/
protected Color getColorForGap( int currentRun, int x, int y ) {
final int shadowWidth = 4;
int selectedIndex = tabPane.getSelectedIndex();
int startIndex = tabRuns[ currentRun + 1 ];
int endIndex = lastTabInRun( tabPane.getTabCount(), currentRun + 1 );
int tabOverGap = -1;
// Check each tab in the row that is 'on top' of this row
for ( int i = startIndex; i <= endIndex; ++i ) {
Rectangle tabBounds = getTabBounds( tabPane, i );
int tabLeft = tabBounds.x;
int tabRight = (tabBounds.x + tabBounds.width) - 1;
// Check to see if this tab is over the gap
if ( MetalUtils.isLeftToRight(tabPane) ) {
if ( tabLeft <= x && tabRight - shadowWidth > x ) {
return selectedIndex == i ? selectColor : getUnselectedBackgroundAt( i );
}
}
else {
if ( tabLeft + shadowWidth < x && tabRight >= x ) {
return selectedIndex == i ? selectColor : getUnselectedBackgroundAt( i );
}
}
}
return tabPane.getBackground();
}
Paints the left tab border.
Params: - tabIndex – a tab index
- g – an instance of
Graphics
- x – an X coordinate
- y – an Y coordinate
- w – a width
- h – a height
- btm – bottom
- rght – right
- isSelected – a selection
/**
* Paints the left tab border.
*
* @param tabIndex a tab index
* @param g an instance of {@code Graphics}
* @param x an X coordinate
* @param y an Y coordinate
* @param w a width
* @param h a height
* @param btm bottom
* @param rght right
* @param isSelected a selection
*/
protected void paintLeftTabBorder( int tabIndex, Graphics g,
int x, int y, int w, int h,
int btm, int rght,
boolean isSelected ) {
int tabCount = tabPane.getTabCount();
int currentRun = getRunForTab( tabCount, tabIndex );
int lastIndex = lastTabInRun( tabCount, currentRun );
int firstIndex = tabRuns[ currentRun ];
g.translate( x, y );
int bottom = h - 1;
int right = w - 1;
//
// Paint part of the tab above
//
if ( tabIndex != firstIndex && tabsOpaque ) {
g.setColor( tabPane.getSelectedIndex() == tabIndex - 1 ?
selectColor :
getUnselectedBackgroundAt( tabIndex - 1 ) );
g.fillRect( 2, 0, 4, 3 );
g.drawLine( 2, 3, 2, 3 );
}
//
// Paint Highlight
//
if (ocean) {
g.setColor(isSelected ? selectHighlight :
MetalLookAndFeel.getWhite());
}
else {
g.setColor( isSelected ? selectHighlight : highlight );
}
// Paint slant
g.drawLine( 1, 6, 6, 1 );
// Paint left
g.drawLine( 1, 6, 1, bottom );
// Paint top
g.drawLine( 6, 1, right, 1 );
if ( tabIndex != firstIndex ) {
if (tabPane.getSelectedIndex() == tabIndex - 1) {
g.setColor(selectHighlight);
} else {
g.setColor(ocean ? MetalLookAndFeel.getWhite() : highlight);
}
g.drawLine( 1, 0, 1, 4 );
}
//
// Paint Border
//
if (ocean) {
if (isSelected) {
g.setColor(oceanSelectedBorderColor);
}
else {
g.setColor( darkShadow );
}
}
else {
g.setColor( darkShadow );
}
// Paint slant
g.drawLine( 1, 5, 6, 0 );
// Paint top
g.drawLine( 6, 0, right, 0 );
// Paint bottom
if ( tabIndex == lastIndex ) {
g.drawLine( 0, bottom, right, bottom );
}
// Paint left
if (ocean) {
if (tabPane.getSelectedIndex() == tabIndex - 1) {
g.drawLine(0, 5, 0, bottom);
g.setColor(oceanSelectedBorderColor);
g.drawLine(0, 0, 0, 5);
}
else if (isSelected) {
g.drawLine( 0, 6, 0, bottom );
if (tabIndex != 0) {
g.setColor(darkShadow);
g.drawLine(0, 0, 0, 5);
}
}
else if ( tabIndex != firstIndex ) {
g.drawLine( 0, 0, 0, bottom );
} else {
g.drawLine( 0, 6, 0, bottom );
}
}
else { // metal
if ( tabIndex != firstIndex ) {
g.drawLine( 0, 0, 0, bottom );
} else {
g.drawLine( 0, 6, 0, bottom );
}
}
g.translate( -x, -y );
}
Paints the bottom tab border.
Params: - tabIndex – a tab index
- g – an instance of
Graphics
- x – an X coordinate
- y – an Y coordinate
- w – a width
- h – a height
- btm – bottom
- rght – right
- isSelected – a selection
/**
* Paints the bottom tab border.
*
* @param tabIndex a tab index
* @param g an instance of {@code Graphics}
* @param x an X coordinate
* @param y an Y coordinate
* @param w a width
* @param h a height
* @param btm bottom
* @param rght right
* @param isSelected a selection
*/
protected void paintBottomTabBorder( int tabIndex, Graphics g,
int x, int y, int w, int h,
int btm, int rght,
boolean isSelected ) {
int tabCount = tabPane.getTabCount();
int currentRun = getRunForTab( tabCount, tabIndex );
int lastIndex = lastTabInRun( tabCount, currentRun );
int firstIndex = tabRuns[ currentRun ];
boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
int bottom = h - 1;
int right = w - 1;
//
// Paint Gap
//
if ( shouldFillGap( currentRun, tabIndex, x, y ) ) {
g.translate( x, y );
if ( leftToRight ) {
g.setColor( getColorForGap( currentRun, x, y ) );
g.fillRect( 1, bottom - 4, 3, 5 );
g.fillRect( 4, bottom - 1, 2, 2 );
} else {
g.setColor( getColorForGap( currentRun, x + w - 1, y ) );
g.fillRect( right - 3, bottom - 3, 3, 4 );
g.fillRect( right - 5, bottom - 1, 2, 2 );
g.drawLine( right - 1, bottom - 4, right - 1, bottom - 4 );
}
g.translate( -x, -y );
}
g.translate( x, y );
//
// Paint Border
//
if (ocean && isSelected) {
g.setColor(oceanSelectedBorderColor);
}
else {
g.setColor( darkShadow );
}
if ( leftToRight ) {
// Paint slant
g.drawLine( 1, bottom - 5, 6, bottom );
// Paint bottom
g.drawLine( 6, bottom, right, bottom );
// Paint right
if ( tabIndex == lastIndex ) {
g.drawLine( right, 0, right, bottom );
}
// Paint left
if (ocean && isSelected) {
g.drawLine(0, 0, 0, bottom - 6);
if ((currentRun == 0 && tabIndex != 0) ||
(currentRun > 0 && tabIndex != tabRuns[currentRun - 1])) {
g.setColor(darkShadow);
g.drawLine(0, bottom - 5, 0, bottom);
}
}
else {
if (ocean && tabIndex == tabPane.getSelectedIndex() + 1) {
g.setColor(oceanSelectedBorderColor);
}
if ( tabIndex != tabRuns[ runCount - 1 ] ) {
g.drawLine( 0, 0, 0, bottom );
} else {
g.drawLine( 0, 0, 0, bottom - 6 );
}
}
} else {
// Paint slant
g.drawLine( right - 1, bottom - 5, right - 6, bottom );
// Paint bottom
g.drawLine( right - 6, bottom, 0, bottom );
// Paint left
if ( tabIndex==lastIndex ) {
// last tab in run
g.drawLine( 0, 0, 0, bottom );
}
// Paint right
if (ocean && tabIndex == tabPane.getSelectedIndex() + 1) {
g.setColor(oceanSelectedBorderColor);
g.drawLine(right, 0, right, bottom);
}
else if (ocean && isSelected) {
g.drawLine(right, 0, right, bottom - 6);
if (tabIndex != firstIndex) {
g.setColor(darkShadow);
g.drawLine(right, bottom - 5, right, bottom);
}
}
else if ( tabIndex != tabRuns[ runCount - 1 ] ) {
// not the first tab in the last run
g.drawLine( right, 0, right, bottom );
} else {
// the first tab in the last run
g.drawLine( right, 0, right, bottom - 6 );
}
}
//
// Paint Highlight
//
g.setColor( isSelected ? selectHighlight : highlight );
if ( leftToRight ) {
// Paint slant
g.drawLine( 1, bottom - 6, 6, bottom - 1 );
// Paint left
g.drawLine( 1, 0, 1, bottom - 6 );
// paint highlight in the gap on tab behind this one
// on the left end (where they all line up)
if ( tabIndex==firstIndex && tabIndex!=tabRuns[runCount - 1] ) {
// first tab in run but not first tab in last run
if (tabPane.getSelectedIndex()==tabRuns[currentRun+1]) {
// tab in front of selected tab
g.setColor( selectHighlight );
}
else {
// tab in front of normal tab
g.setColor( highlight );
}
g.drawLine( 1, bottom - 4, 1, bottom );
}
} else {
// Paint left
if ( tabIndex==lastIndex ) {
// last tab in run
g.drawLine( 1, 0, 1, bottom - 1 );
} else {
g.drawLine( 0, 0, 0, bottom - 1 );
}
}
g.translate( -x, -y );
}
Paints the right tab border.
Params: - tabIndex – a tab index
- g – an instance of
Graphics
- x – an X coordinate
- y – an Y coordinate
- w – a width
- h – a height
- btm – bottom
- rght – right
- isSelected – a selection
/**
* Paints the right tab border.
*
* @param tabIndex a tab index
* @param g an instance of {@code Graphics}
* @param x an X coordinate
* @param y an Y coordinate
* @param w a width
* @param h a height
* @param btm bottom
* @param rght right
* @param isSelected a selection
*/
protected void paintRightTabBorder( int tabIndex, Graphics g,
int x, int y, int w, int h,
int btm, int rght,
boolean isSelected ) {
int tabCount = tabPane.getTabCount();
int currentRun = getRunForTab( tabCount, tabIndex );
int lastIndex = lastTabInRun( tabCount, currentRun );
int firstIndex = tabRuns[ currentRun ];
g.translate( x, y );
int bottom = h - 1;
int right = w - 1;
//
// Paint part of the tab above
//
if ( tabIndex != firstIndex && tabsOpaque ) {
g.setColor( tabPane.getSelectedIndex() == tabIndex - 1 ?
selectColor :
getUnselectedBackgroundAt( tabIndex - 1 ) );
g.fillRect( right - 5, 0, 5, 3 );
g.fillRect( right - 2, 3, 2, 2 );
}
//
// Paint Highlight
//
g.setColor( isSelected ? selectHighlight : highlight );
// Paint slant
g.drawLine( right - 6, 1, right - 1, 6 );
// Paint top
g.drawLine( 0, 1, right - 6, 1 );
// Paint left
if ( !isSelected ) {
g.drawLine( 0, 1, 0, bottom );
}
//
// Paint Border
//
if (ocean && isSelected) {
g.setColor(oceanSelectedBorderColor);
}
else {
g.setColor( darkShadow );
}
// Paint bottom
if ( tabIndex == lastIndex ) {
g.drawLine( 0, bottom, right, bottom );
}
// Paint slant
if (ocean && tabPane.getSelectedIndex() == tabIndex - 1) {
g.setColor(oceanSelectedBorderColor);
}
g.drawLine( right - 6, 0, right, 6 );
// Paint top
g.drawLine( 0, 0, right - 6, 0 );
// Paint right
if (ocean && isSelected) {
g.drawLine(right, 6, right, bottom);
if (tabIndex != firstIndex) {
g.setColor(darkShadow);
g.drawLine(right, 0, right, 5);
}
}
else if (ocean && tabPane.getSelectedIndex() == tabIndex - 1) {
g.setColor(oceanSelectedBorderColor);
g.drawLine(right, 0, right, 6);
g.setColor(darkShadow);
g.drawLine(right, 6, right, bottom);
}
else if ( tabIndex != firstIndex ) {
g.drawLine( right, 0, right, bottom );
} else {
g.drawLine( right, 6, right, bottom );
}
g.translate( -x, -y );
}
public void update( Graphics g, JComponent c ) {
if ( c.isOpaque() ) {
g.setColor( tabAreaBackground );
g.fillRect( 0, 0, c.getWidth(),c.getHeight() );
}
paint( g, c );
}
protected void paintTabBackground( Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h, boolean isSelected ) {
int slantWidth = h / 2;
if ( isSelected ) {
g.setColor( selectColor );
} else {
g.setColor( getUnselectedBackgroundAt( tabIndex ) );
}
if (MetalUtils.isLeftToRight(tabPane)) {
switch ( tabPlacement ) {
case LEFT:
g.fillRect( x + 5, y + 1, w - 5, h - 1);
g.fillRect( x + 2, y + 4, 3, h - 4 );
break;
case BOTTOM:
g.fillRect( x + 2, y, w - 2, h - 4 );
g.fillRect( x + 5, y + (h - 1) - 3, w - 5, 3 );
break;
case RIGHT:
g.fillRect( x, y + 2, w - 4, h - 2);
g.fillRect( x + (w - 1) - 3, y + 5, 3, h - 5 );
break;
case TOP:
default:
g.fillRect( x + 4, y + 2, (w - 1) - 3, (h - 1) - 1 );
g.fillRect( x + 2, y + 5, 2, h - 5 );
}
} else {
switch ( tabPlacement ) {
case LEFT:
g.fillRect( x + 5, y + 1, w - 5, h - 1);
g.fillRect( x + 2, y + 4, 3, h - 4 );
break;
case BOTTOM:
g.fillRect( x, y, w - 5, h - 1 );
g.fillRect( x + (w - 1) - 4, y, 4, h - 5);
g.fillRect( x + (w - 1) - 4, y + (h - 1) - 4, 2, 2);
break;
case RIGHT:
g.fillRect( x + 1, y + 1, w - 5, h - 1);
g.fillRect( x + (w - 1) - 3, y + 5, 3, h - 5 );
break;
case TOP:
default:
g.fillRect( x, y + 2, (w - 1) - 3, (h - 1) - 1 );
g.fillRect( x + (w - 1) - 3, y + 5, 3, h - 3 );
}
}
}
Overridden to do nothing for the Java L&F.
/**
* Overridden to do nothing for the Java L&F.
*/
protected int getTabLabelShiftX( int tabPlacement, int tabIndex, boolean isSelected ) {
return 0;
}
Overridden to do nothing for the Java L&F.
/**
* Overridden to do nothing for the Java L&F.
*/
protected int getTabLabelShiftY( int tabPlacement, int tabIndex, boolean isSelected ) {
return 0;
}
{@inheritDoc}
Since: 1.6
/**
* {@inheritDoc}
*
* @since 1.6
*/
protected int getBaselineOffset() {
return 0;
}
public void paint( Graphics g, JComponent c ) {
int tabPlacement = tabPane.getTabPlacement();
Insets insets = c.getInsets(); Dimension size = c.getSize();
// Paint the background for the tab area
if ( tabPane.isOpaque() ) {
Color background = c.getBackground();
if (background instanceof UIResource && tabAreaBackground != null) {
g.setColor(tabAreaBackground);
}
else {
g.setColor(background);
}
switch ( tabPlacement ) {
case LEFT:
g.fillRect( insets.left, insets.top,
calculateTabAreaWidth( tabPlacement, runCount, maxTabWidth ),
size.height - insets.bottom - insets.top );
break;
case BOTTOM:
int totalTabHeight = calculateTabAreaHeight( tabPlacement, runCount, maxTabHeight );
g.fillRect( insets.left, size.height - insets.bottom - totalTabHeight,
size.width - insets.left - insets.right,
totalTabHeight );
break;
case RIGHT:
int totalTabWidth = calculateTabAreaWidth( tabPlacement, runCount, maxTabWidth );
g.fillRect( size.width - insets.right - totalTabWidth,
insets.top, totalTabWidth,
size.height - insets.top - insets.bottom );
break;
case TOP:
default:
g.fillRect( insets.left, insets.top,
size.width - insets.right - insets.left,
calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight) );
paintHighlightBelowTab();
}
}
super.paint( g, c );
}
Paints highlights below tab.
/**
* Paints highlights below tab.
*/
protected void paintHighlightBelowTab( ) {
}
protected void paintFocusIndicator(Graphics g, int tabPlacement,
Rectangle[] rects, int tabIndex,
Rectangle iconRect, Rectangle textRect,
boolean isSelected) {
if ( tabPane.hasFocus() && isSelected ) {
Rectangle tabRect = rects[tabIndex];
boolean lastInRun = isLastInRun( tabIndex );
g.setColor( focus );
g.translate( tabRect.x, tabRect.y );
int right = tabRect.width - 1;
int bottom = tabRect.height - 1;
boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
switch ( tabPlacement ) {
case RIGHT:
g.drawLine( right - 6,2 , right - 2,6 ); // slant
g.drawLine( 1,2 , right - 6,2 ); // top
g.drawLine( right - 2,6 , right - 2,bottom ); // right
g.drawLine( 1,2 , 1,bottom ); // left
g.drawLine( 1,bottom , right - 2,bottom ); // bottom
break;
case BOTTOM:
if ( leftToRight ) {
g.drawLine( 2, bottom - 6, 6, bottom - 2 ); // slant
g.drawLine( 6, bottom - 2,
right, bottom - 2 ); // bottom
g.drawLine( 2, 0, 2, bottom - 6 ); // left
g.drawLine( 2, 0, right, 0 ); // top
g.drawLine( right, 0, right, bottom - 2 ); // right
} else {
g.drawLine( right - 2, bottom - 6,
right - 6, bottom - 2 ); // slant
g.drawLine( right - 2, 0,
right - 2, bottom - 6 ); // right
if ( lastInRun ) {
// last tab in run
g.drawLine( 2, bottom - 2,
right - 6, bottom - 2 ); // bottom
g.drawLine( 2, 0, right - 2, 0 ); // top
g.drawLine( 2, 0, 2, bottom - 2 ); // left
} else {
g.drawLine( 1, bottom - 2,
right - 6, bottom - 2 ); // bottom
g.drawLine( 1, 0, right - 2, 0 ); // top
g.drawLine( 1, 0, 1, bottom - 2 ); // left
}
}
break;
case LEFT:
g.drawLine( 2, 6, 6, 2 ); // slant
g.drawLine( 2, 6, 2, bottom - 1); // left
g.drawLine( 6, 2, right, 2 ); // top
g.drawLine( right, 2, right, bottom - 1 ); // right
g.drawLine( 2, bottom - 1,
right, bottom - 1 ); // bottom
break;
case TOP:
default:
if ( leftToRight ) {
g.drawLine( 2, 6, 6, 2 ); // slant
g.drawLine( 2, 6, 2, bottom - 1); // left
g.drawLine( 6, 2, right, 2 ); // top
g.drawLine( right, 2, right, bottom - 1 ); // right
g.drawLine( 2, bottom - 1,
right, bottom - 1 ); // bottom
}
else {
g.drawLine( right - 2, 6, right - 6, 2 ); // slant
g.drawLine( right - 2, 6,
right - 2, bottom - 1); // right
if ( lastInRun ) {
// last tab in run
g.drawLine( right - 6, 2, 2, 2 ); // top
g.drawLine( 2, 2, 2, bottom - 1 ); // left
g.drawLine( right - 2, bottom - 1,
2, bottom - 1 ); // bottom
}
else {
g.drawLine( right - 6, 2, 1, 2 ); // top
g.drawLine( 1, 2, 1, bottom - 1 ); // left
g.drawLine( right - 2, bottom - 1,
1, bottom - 1 ); // bottom
}
}
}
g.translate( -tabRect.x, -tabRect.y );
}
}
protected void paintContentBorderTopEdge( Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h ) {
boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
int right = x + w - 1;
Rectangle selRect = selectedIndex < 0? null :
getTabBounds(selectedIndex, calcRect);
if (ocean) {
g.setColor(oceanSelectedBorderColor);
}
else {
g.setColor(selectHighlight);
}
// Draw unbroken line if tabs are not on TOP, OR
// selected tab is not in run adjacent to content, OR
// selected tab is not visible (SCROLL_TAB_LAYOUT)
//
if (tabPlacement != TOP || selectedIndex < 0 ||
(selRect.y + selRect.height + 1 < y) ||
(selRect.x < x || selRect.x > x + w)) {
g.drawLine(x, y, x+w-2, y);
if (ocean && tabPlacement == TOP) {
g.setColor(MetalLookAndFeel.getWhite());
g.drawLine(x, y + 1, x+w-2, y + 1);
}
} else {
// Break line to show visual connection to selected tab
boolean lastInRun = isLastInRun(selectedIndex);
if ( leftToRight || lastInRun ) {
g.drawLine(x, y, selRect.x + 1, y);
} else {
g.drawLine(x, y, selRect.x, y);
}
if (selRect.x + selRect.width < right - 1) {
if ( leftToRight && !lastInRun ) {
g.drawLine(selRect.x + selRect.width, y, right - 1, y);
} else {
g.drawLine(selRect.x + selRect.width - 1, y, right - 1, y);
}
} else {
g.setColor(shadow);
g.drawLine(x+w-2, y, x+w-2, y);
}
if (ocean) {
g.setColor(MetalLookAndFeel.getWhite());
if ( leftToRight || lastInRun ) {
g.drawLine(x, y + 1, selRect.x + 1, y + 1);
} else {
g.drawLine(x, y + 1, selRect.x, y + 1);
}
if (selRect.x + selRect.width < right - 1) {
if ( leftToRight && !lastInRun ) {
g.drawLine(selRect.x + selRect.width, y + 1,
right - 1, y + 1);
} else {
g.drawLine(selRect.x + selRect.width - 1, y + 1,
right - 1, y + 1);
}
} else {
g.setColor(shadow);
g.drawLine(x+w-2, y + 1, x+w-2, y + 1);
}
}
}
}
protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h) {
boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
int bottom = y + h - 1;
int right = x + w - 1;
Rectangle selRect = selectedIndex < 0? null :
getTabBounds(selectedIndex, calcRect);
g.setColor(darkShadow);
// Draw unbroken line if tabs are not on BOTTOM, OR
// selected tab is not in run adjacent to content, OR
// selected tab is not visible (SCROLL_TAB_LAYOUT)
//
if (tabPlacement != BOTTOM || selectedIndex < 0 ||
(selRect.y - 1 > h) ||
(selRect.x < x || selRect.x > x + w)) {
if (ocean && tabPlacement == BOTTOM) {
g.setColor(oceanSelectedBorderColor);
}
g.drawLine(x, y+h-1, x+w-1, y+h-1);
} else {
// Break line to show visual connection to selected tab
boolean lastInRun = isLastInRun(selectedIndex);
if (ocean) {
g.setColor(oceanSelectedBorderColor);
}
if ( leftToRight || lastInRun ) {
g.drawLine(x, bottom, selRect.x, bottom);
} else {
g.drawLine(x, bottom, selRect.x - 1, bottom);
}
if (selRect.x + selRect.width < x + w - 2) {
if ( leftToRight && !lastInRun ) {
g.drawLine(selRect.x + selRect.width, bottom,
right, bottom);
} else {
g.drawLine(selRect.x + selRect.width - 1, bottom,
right, bottom);
}
}
}
}
protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h) {
Rectangle selRect = selectedIndex < 0? null :
getTabBounds(selectedIndex, calcRect);
if (ocean) {
g.setColor(oceanSelectedBorderColor);
}
else {
g.setColor(selectHighlight);
}
// Draw unbroken line if tabs are not on LEFT, OR
// selected tab is not in run adjacent to content, OR
// selected tab is not visible (SCROLL_TAB_LAYOUT)
//
if (tabPlacement != LEFT || selectedIndex < 0 ||
(selRect.x + selRect.width + 1 < x) ||
(selRect.y < y || selRect.y > y + h)) {
g.drawLine(x, y + 1, x, y+h-2);
if (ocean && tabPlacement == LEFT) {
g.setColor(MetalLookAndFeel.getWhite());
g.drawLine(x + 1, y, x + 1, y + h - 2);
}
} else {
// Break line to show visual connection to selected tab
g.drawLine(x, y, x, selRect.y + 1);
if (selRect.y + selRect.height < y + h - 2) {
g.drawLine(x, selRect.y + selRect.height + 1,
x, y+h+2);
}
if (ocean) {
g.setColor(MetalLookAndFeel.getWhite());
g.drawLine(x + 1, y + 1, x + 1, selRect.y + 1);
if (selRect.y + selRect.height < y + h - 2) {
g.drawLine(x + 1, selRect.y + selRect.height + 1,
x + 1, y+h+2);
}
}
}
}
protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h) {
Rectangle selRect = selectedIndex < 0? null :
getTabBounds(selectedIndex, calcRect);
g.setColor(darkShadow);
// Draw unbroken line if tabs are not on RIGHT, OR
// selected tab is not in run adjacent to content, OR
// selected tab is not visible (SCROLL_TAB_LAYOUT)
//
if (tabPlacement != RIGHT || selectedIndex < 0 ||
(selRect.x - 1 > w) ||
(selRect.y < y || selRect.y > y + h)) {
if (ocean && tabPlacement == RIGHT) {
g.setColor(oceanSelectedBorderColor);
}
g.drawLine(x+w-1, y, x+w-1, y+h-1);
} else {
// Break line to show visual connection to selected tab
if (ocean) {
g.setColor(oceanSelectedBorderColor);
}
g.drawLine(x+w-1, y, x+w-1, selRect.y);
if (selRect.y + selRect.height < y + h - 2) {
g.drawLine(x+w-1, selRect.y + selRect.height,
x+w-1, y+h-2);
}
}
}
protected int calculateMaxTabHeight( int tabPlacement ) {
FontMetrics metrics = getFontMetrics();
int height = metrics.getHeight();
boolean tallerIcons = false;
for ( int i = 0; i < tabPane.getTabCount(); ++i ) {
Icon icon = tabPane.getIconAt( i );
if ( icon != null ) {
if ( icon.getIconHeight() > height ) {
tallerIcons = true;
break;
}
}
}
return super.calculateMaxTabHeight( tabPlacement ) -
(tallerIcons ? (tabInsets.top + tabInsets.bottom) : 0);
}
protected int getTabRunOverlay( int tabPlacement ) {
// Tab runs laid out vertically should overlap
// at least as much as the largest slant
if ( tabPlacement == LEFT || tabPlacement == RIGHT ) {
int maxTabHeight = calculateMaxTabHeight(tabPlacement);
return maxTabHeight / 2;
}
return 0;
}
Returns true
if tab runs should be rotated. Params: - tabPlacement – a tab placement
- selectedRun – a selected run
Returns: true
if tab runs should be rotated.
/**
* Returns {@code true} if tab runs should be rotated.
*
* @param tabPlacement a tab placement
* @param selectedRun a selected run
* @return {@code true} if tab runs should be rotated.
*/
protected boolean shouldRotateTabRuns( int tabPlacement, int selectedRun ) {
return false;
}
// Don't pad last run
protected boolean shouldPadTabRun( int tabPlacement, int run ) {
return runCount > 1 && run < runCount - 1;
}
private boolean isLastInRun( int tabIndex ) {
int run = getRunForTab( tabPane.getTabCount(), tabIndex );
int lastIndex = lastTabInRun( tabPane.getTabCount(), run );
return tabIndex == lastIndex;
}
Returns the color to use for the specified tab.
/**
* Returns the color to use for the specified tab.
*/
private Color getUnselectedBackgroundAt(int index) {
Color color = tabPane.getBackgroundAt(index);
if (color instanceof UIResource) {
if (unselectedBackground != null) {
return unselectedBackground;
}
}
return color;
}
Returns the tab index of JTabbedPane the mouse is currently over
/**
* Returns the tab index of JTabbedPane the mouse is currently over
*/
int getRolloverTabIndex() {
return getRolloverTab();
}
This class should be treated as a "protected" inner class. Instantiate it only within subclasses of MetalTabbedPaneUI
. /**
* This class should be treated as a "protected" inner class.
* Instantiate it only within subclasses of {@code MetalTabbedPaneUI}.
*/
public class TabbedPaneLayout extends BasicTabbedPaneUI.TabbedPaneLayout {
Constructs TabbedPaneLayout
. /**
* Constructs {@code TabbedPaneLayout}.
*/
public TabbedPaneLayout() {
MetalTabbedPaneUI.this.super();
}
protected void normalizeTabRuns( int tabPlacement, int tabCount,
int start, int max ) {
// Only normalize the runs for top & bottom; normalizing
// doesn't look right for Metal's vertical tabs
// because the last run isn't padded and it looks odd to have
// fat tabs in the first vertical runs, but slimmer ones in the
// last (this effect isn't noticeable for horizontal tabs).
if ( tabPlacement == TOP || tabPlacement == BOTTOM ) {
super.normalizeTabRuns( tabPlacement, tabCount, start, max );
}
}
// Don't rotate runs!
protected void rotateTabRuns( int tabPlacement, int selectedRun ) {
}
// Don't pad selected tab
protected void padSelectedTab( int tabPlacement, int selectedIndex ) {
}
}
}