/******************************************************************************* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 ); } } } }