/* * This file is part of WebLookAndFeel library. * * WebLookAndFeel library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * WebLookAndFeel library 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 for more details. * * You should have received a copy of the GNU General Public License * along with WebLookAndFeel library. If not, see . */ package com.alee.laf.tabbedpane; import com.alee.extended.painter.Painter; import com.alee.extended.painter.PainterSupport; import com.alee.global.StyleConstants; import com.alee.utils.GraphicsUtils; import com.alee.utils.LafUtils; import com.alee.utils.SwingUtils; import com.alee.utils.laf.ShapeProvider; import com.alee.utils.swing.BorderMethods; import javax.swing.*; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicTabbedPaneUI; import javax.swing.text.View; import java.awt.*; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.util.HashMap; import java.util.Map; /** * User: mgarin Date: 27.04.11 Time: 18:39 */ public class WebTabbedPaneUI extends BasicTabbedPaneUI implements ShapeProvider, BorderMethods { private TabbedPaneStyle tabbedPaneStyle = WebTabbedPaneStyle.tabbedPaneStyle; private Color selectedTopBg = WebTabbedPaneStyle.selectedTopBg; private Color selectedBottomBg = WebTabbedPaneStyle.selectedBottomBg; private Color topBg = WebTabbedPaneStyle.topBg; private Color bottomBg = WebTabbedPaneStyle.bottomBg; private int round = WebTabbedPaneStyle.round; private int shadeWidth = WebTabbedPaneStyle.shadeWidth; private boolean rotateTabInsets = WebTabbedPaneStyle.rotateTabInsets; private Insets contentInsets = WebTabbedPaneStyle.contentInsets; private Insets tabInsets = WebTabbedPaneStyle.tabInsets; private Painter painter = WebTabbedPaneStyle.painter; private int tabRunIndent = WebTabbedPaneStyle.tabRunIndent; private int tabOverlay = WebTabbedPaneStyle.tabOverlay; private TabStretchType tabStretchType = WebTabbedPaneStyle.tabStretchType; private final Map selectedForegroundAt = new HashMap (); private final Map backgroundPainterAt = new HashMap (); private FocusAdapter focusAdapter; // private MouseAdapter mouseAdapter; // private int rolloverTab = -1; @SuppressWarnings ("UnusedParameters") public static ComponentUI createUI ( final JComponent c ) { return new WebTabbedPaneUI (); } @Override public void installUI ( final JComponent c ) { super.installUI ( c ); // Default settings SwingUtils.setOrientation ( tabPane ); tabPane.setBackground ( StyleConstants.backgroundColor ); PainterSupport.installPainter ( tabPane, this.painter ); // Updating border updateBorder (); // Focus updater focusAdapter = new FocusAdapter () { @Override public void focusGained ( final FocusEvent e ) { tabPane.repaint (); } @Override public void focusLost ( final FocusEvent e ) { tabPane.repaint (); } }; tabPane.addFocusListener ( focusAdapter ); // mouseAdapter = new MouseAdapter () // { // public void mouseEntered ( MouseEvent e ) // { // updateRolloverTab ( e ); // } // // public void mouseExited ( MouseEvent e ) // { // updateRolloverTab ( e ); // } // // public void mouseMoved ( MouseEvent e ) // { // updateRolloverTab ( e ); // } // // public void mouseDragged ( MouseEvent e ) // { // updateRolloverTab ( e ); // } // }; // c.addMouseListener ( mouseAdapter ); // c.addMouseMotionListener ( mouseAdapter ); } @Override public void uninstallUI ( final JComponent c ) { PainterSupport.uninstallPainter ( tabPane, this.painter ); if ( focusAdapter != null ) { c.removeFocusListener ( focusAdapter ); } // if ( mouseAdapter != null ) // { // c.removeMouseListener ( mouseAdapter ); // c.removeMouseMotionListener ( mouseAdapter ); // } super.uninstallUI ( c ); } @Override public Shape provideShape () { return LafUtils.getWebBorderShape ( tabPane, getShadeWidth (), getRound () ); } /** * {@inheritDoc} */ @Override public void updateBorder () { if ( tabPane != null ) { // Preserve old borders if ( SwingUtils.isPreserveBorders ( tabPane ) ) { return; } final Insets bgInsets = getBackgroundInsets ( tabPane ); if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { // Standalone style border tabPane.setBorder ( LafUtils.createWebBorder ( SwingUtils.max ( bgInsets, new Insets ( shadeWidth, shadeWidth, shadeWidth, shadeWidth ) ) ) ); } else { // Attached style border tabPane.setBorder ( LafUtils.createWebBorder ( bgInsets ) ); } } } private Insets getBackgroundInsets ( final JComponent c ) { return painter != null ? painter.getMargin ( c ) : new Insets ( 0, 0, 0, 0 ); } public int getShadeWidth () { return shadeWidth; } public void setShadeWidth ( final int shadeWidth ) { this.shadeWidth = shadeWidth; updateBorder (); } public boolean isRotateTabInsets () { return rotateTabInsets; } public void setRotateTabInsets ( final boolean rotateTabInsets ) { this.rotateTabInsets = rotateTabInsets; } public int getRound () { return round; } public void setRound ( final int round ) { this.round = round; } public Insets getContentInsets () { return contentInsets; } public void setContentInsets ( final Insets contentInsets ) { this.contentInsets = contentInsets; } public Insets getTabInsets () { return tabInsets; } public void setTabInsets ( final Insets tabInsets ) { this.tabInsets = tabInsets; } public Color getSelectedTopBg () { return selectedTopBg; } public void setSelectedTopBg ( final Color selectedTopBg ) { this.selectedTopBg = selectedTopBg; } public Color getSelectedBottomBg () { return selectedBottomBg; } public void setSelectedBottomBg ( final Color selectedBottomBg ) { this.selectedBottomBg = selectedBottomBg; } public Color getTopBg () { return topBg; } public void setTopBg ( final Color topBg ) { this.topBg = topBg; } public Color getBottomBg () { return bottomBg; } public void setBottomBg ( final Color bottomBg ) { this.bottomBg = bottomBg; } public void setSelectedForegroundAt ( final int tabIndex, final Color foreground ) { selectedForegroundAt.put ( tabIndex, foreground ); } public Color getSelectedForegroundAt ( final int tabIndex ) { return selectedForegroundAt.get ( tabIndex ); } public void setBackgroundPainterAt ( final int tabIndex, final Painter painter ) { backgroundPainterAt.put ( tabIndex, painter ); } public Painter getBackgroundPainterAt ( final int tabIndex ) { return backgroundPainterAt.get ( tabIndex ); } public TabbedPaneStyle getTabbedPaneStyle () { return tabbedPaneStyle; } public void setTabbedPaneStyle ( final TabbedPaneStyle tabbedPaneStyle ) { this.tabbedPaneStyle = tabbedPaneStyle; updateBorder (); } // private void updateRolloverTab ( MouseEvent e ) // { // if ( tabPane != null ) // { // int old = rolloverTab; // rolloverTab = tabForCoordinate ( tabPane, e.getX (), e.getY () ); // if ( old != rolloverTab ) // { // tabPane.repaint (); // } // } // } public Painter getPainter () { return painter; } public void setPainter ( final Painter painter ) { PainterSupport.uninstallPainter ( tabPane, this.painter ); this.painter = painter; PainterSupport.installPainter ( tabPane, this.painter ); updateBorder (); } public int getTabRunIndent () { return tabRunIndent; } public void setTabRunIndent ( final int tabRunIndent ) { this.tabRunIndent = tabRunIndent; } public int getTabOverlay () { return tabOverlay; } public void setTabOverlay ( final int tabOverlay ) { this.tabOverlay = tabOverlay; } public TabStretchType getTabStretchType () { return tabStretchType; } public void setTabStretchType ( final TabStretchType tabStretchType ) { this.tabStretchType = tabStretchType; } @Override protected int getTabRunIndent ( final int tabPlacement, final int run ) { return tabRunIndent; } @Override protected int getTabRunOverlay ( final int tabPlacement ) { return tabOverlay; } @Override protected boolean shouldPadTabRun ( final int tabPlacement, final int run ) { return !tabStretchType.equals ( TabStretchType.never ) && ( tabStretchType.equals ( TabStretchType.always ) || tabStretchType.equals ( TabStretchType.multiline ) && runCount > 1 ); } @Override protected boolean shouldRotateTabRuns ( final int tabPlacement ) { // todo Requires style changes return true; } @Override protected Insets getContentBorderInsets ( final int tabPlacement ) { if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { final Insets insets; if ( tabPlacement == JTabbedPane.TOP ) { insets = new Insets ( 1, 2, 1, 2 ); } else if ( tabPlacement == JTabbedPane.BOTTOM ) { insets = new Insets ( 2, 2, 0, 2 ); } else if ( tabPlacement == JTabbedPane.LEFT ) { insets = new Insets ( 2, 1, 2, 1 ); } else if ( tabPlacement == JTabbedPane.RIGHT ) { insets = new Insets ( 2, 2, 2, 0 ); } else { insets = new Insets ( 0, 0, 0, 0 ); } insets.top += contentInsets.top - 1; insets.left += contentInsets.left - 1; insets.bottom += contentInsets.bottom - 1; insets.right += contentInsets.right - 1; return insets; } else { return new Insets ( 0, 0, 0, 0 ); } } @Override protected Insets getTabAreaInsets ( final int tabPlacement ) { final Insets targetInsets = new Insets ( 0, 0, 0, 0 ); rotateInsets ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ? new Insets ( tabPlacement == RIGHT ? 1 : 0, 1, 0, 2 ) : new Insets ( -1, -1, 0, 0 ), targetInsets, tabPlacement ); return targetInsets; } @Override protected Insets getTabInsets ( final int tabPlacement, final int tabIndex ) { final Insets insets = SwingUtils.copy ( tabInsets ); if ( tabIndex == 0 && tabPane.getSelectedIndex () == 0 ) { // Fix for 1st element insets.left -= 1; insets.right += 1; } if ( rotateTabInsets ) { final Insets targetInsets = new Insets ( 0, 0, 0, 0 ); rotateInsets ( insets, targetInsets, tabPlacement ); return targetInsets; } else { return insets; } } @Override protected Insets getSelectedTabPadInsets ( final int tabPlacement ) { final Insets targetInsets = new Insets ( 0, 0, 0, 0 ); rotateInsets ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ? new Insets ( 2, 2, 2, 1 ) : new Insets ( 0, 0, 0, 0 ), targetInsets, tabPlacement ); return targetInsets; } @Override protected int getTabLabelShiftX ( final int tabPlacement, final int tabIndex, final boolean isSelected ) { if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { return super.getTabLabelShiftX ( tabPlacement, tabIndex, isSelected ); } else { return 0; } } @Override protected int getTabLabelShiftY ( final int tabPlacement, final int tabIndex, final boolean isSelected ) { if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { return super.getTabLabelShiftY ( tabPlacement, tabIndex, isSelected ); } else { return 0; } } @Override protected void paintTabBorder ( final Graphics g, final int tabPlacement, final int tabIndex, final int x, final int y, final int w, final int h, final boolean isSelected ) { // We don't need this one } @Override protected void paintTabBackground ( final Graphics g, final int tabPlacement, final int tabIndex, final int x, final int y, final int w, final int h, final boolean isSelected ) { final Graphics2D g2d = ( Graphics2D ) g; final Object aa = GraphicsUtils.setupAntialias ( g2d ); // Border shape final GeneralPath borderShape = createTabShape ( TabShapeType.border, tabPlacement, x, y, w, h, isSelected ); // Tab shade if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { final GeneralPath shadeShape = createTabShape ( TabShapeType.shade, tabPlacement, x, y, w, h, isSelected ); GraphicsUtils.drawShade ( g2d, shadeShape, StyleConstants.shadeColor, shadeWidth, new Rectangle2D.Double ( 0, 0, tabPane.getWidth (), y + h ), round > 0 ); } // Tab background final GeneralPath bgShape = createTabShape ( TabShapeType.background, tabPlacement, x, y, w, h, isSelected ); if ( backgroundPainterAt.containsKey ( tabIndex ) && isSelected ) { final Shape old = GraphicsUtils.intersectClip ( g2d, bgShape ); final Painter bp = backgroundPainterAt.get ( tabIndex ); bp.paint ( g2d, new Rectangle ( x, y, w, h ), tabPane ); GraphicsUtils.restoreClip ( g2d, old ); } else { final Point topPoint = getTopTabBgPoint ( tabPlacement, x, y, w, h ); final Point bottomPoint = getBottomTabBgPoint ( tabPlacement, x, y, w, h ); if ( isSelected ) { Color bg = tabPane.getBackgroundAt ( tabIndex ); bg = bg != null ? bg : tabPane.getBackground (); g2d.setPaint ( new GradientPaint ( topPoint.x, topPoint.y, selectedTopBg, bottomPoint.x, bottomPoint.y, bg ) ); } else { g2d.setPaint ( new GradientPaint ( topPoint.x, topPoint.y, topBg, bottomPoint.x, bottomPoint.y, bottomBg ) ); } g2d.fill ( isSelected ? borderShape : bgShape ); } // Tab border g2d.setPaint ( StyleConstants.darkBorderColor ); g2d.draw ( borderShape ); // Tab focus final boolean drawFocus = isSelected && tabPane.isFocusOwner (); if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { LafUtils.drawCustomWebFocus ( g2d, null, StyleConstants.focusType, borderShape, null, drawFocus ); } // else if ( drawFocus ) // { // g2d.setPaint ( StyleConstants.fieldFocusColor ); // g2d.drawLine ( x, y + 1, x + w, y + 1 ); // } //todo Paint selected tab together with area GraphicsUtils.restoreAntialias ( g2d, aa ); } @Override protected void paintText ( final Graphics g, final int tabPlacement, final Font font, final FontMetrics metrics, final int tabIndex, final String title, final Rectangle textRect, final boolean isSelected ) { g.setFont ( font ); final View v = getTextViewForTab ( tabIndex ); if ( v != null ) { // html v.paint ( g, textRect ); } else { // plain text final int mnemIndex = tabPane.getDisplayedMnemonicIndexAt ( tabIndex ); if ( tabPane.isEnabled () && tabPane.isEnabledAt ( tabIndex ) ) { Color fg = tabPane.getForegroundAt ( tabIndex ); if ( isSelected && ( fg instanceof UIResource ) ) { if ( selectedForegroundAt.containsKey ( tabIndex ) ) { fg = selectedForegroundAt.get ( tabIndex ); } else { final Color selectedFG = UIManager.getColor ( "TabbedPane.selectedForeground" ); if ( selectedFG != null ) { fg = selectedFG; } } } g.setColor ( fg ); SwingUtils.drawStringUnderlineCharAt ( g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent () ); } else { // tab disabled g.setColor ( tabPane.getBackgroundAt ( tabIndex ).brighter () ); SwingUtils.drawStringUnderlineCharAt ( g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent () ); g.setColor ( tabPane.getBackgroundAt ( tabIndex ).darker () ); SwingUtils.drawStringUnderlineCharAt ( g, title, mnemIndex, textRect.x - 1, textRect.y + metrics.getAscent () - 1 ); } } } private GeneralPath createTabShape ( final TabShapeType tabShapeType, final int tabPlacement, int x, final int y, int w, final int h, final boolean isSelected ) { // Fix for basic layouting of selected left-sided tab x coordinate final Insets insets = tabPane.getInsets (); if ( tabbedPaneStyle.equals ( TabbedPaneStyle.attached ) && isSelected ) { // todo fix for other tabPlacement values aswell if ( tabPlacement == TOP && x == insets.left ) { x = x - 1; w = w + 1; } } final int actualRound = tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ? round : 0; final GeneralPath bgShape = new GeneralPath ( GeneralPath.WIND_EVEN_ODD ); if ( tabPlacement == JTabbedPane.TOP ) { bgShape.moveTo ( x, y + h + getChange ( tabShapeType ) ); bgShape.lineTo ( x, y + actualRound ); bgShape.quadTo ( x, y, x + actualRound, y ); bgShape.lineTo ( x + w - actualRound, y ); bgShape.quadTo ( x + w, y, x + w, y + actualRound ); bgShape.lineTo ( x + w, y + h + getChange ( tabShapeType ) ); } else if ( tabPlacement == JTabbedPane.BOTTOM ) { bgShape.moveTo ( x, y - getChange ( tabShapeType ) ); bgShape.lineTo ( x, y + h - actualRound ); bgShape.quadTo ( x, y + h, x + actualRound, y + h ); bgShape.lineTo ( x + w - actualRound, y + h ); bgShape.quadTo ( x + w, y + h, x + w, y + h - actualRound ); bgShape.lineTo ( x + w, y - getChange ( tabShapeType ) ); } else if ( tabPlacement == JTabbedPane.LEFT ) { bgShape.moveTo ( x + w + getChange ( tabShapeType ), y ); bgShape.lineTo ( x + actualRound, y ); bgShape.quadTo ( x, y, x, y + actualRound ); bgShape.lineTo ( x, y + h - actualRound ); bgShape.quadTo ( x, y + h, x + actualRound, y + h ); bgShape.lineTo ( x + w + getChange ( tabShapeType ), y + h ); } else { bgShape.moveTo ( x - getChange ( tabShapeType ), y ); bgShape.lineTo ( x + w - actualRound, y ); bgShape.quadTo ( x + w, y, x + w, y + actualRound ); bgShape.lineTo ( x + w, y + h - actualRound ); bgShape.quadTo ( x + w, y + h, x + w - actualRound, y + h ); bgShape.lineTo ( x - getChange ( tabShapeType ), y + h ); } return bgShape; } private int getChange ( final TabShapeType tabShapeType ) { if ( tabShapeType.equals ( TabShapeType.shade ) ) { return -( round > 0 ? round : 1 ); } else if ( tabShapeType.equals ( TabShapeType.border ) ) { return -1; } else if ( tabShapeType.equals ( TabShapeType.backgroundPainter ) ) { return 2; } else { return 0; } } private enum TabShapeType { shade, background, backgroundPainter, border } private Point getTopTabBgPoint ( final int tabPlacement, final int x, final int y, final int w, final int h ) { if ( tabPlacement == JTabbedPane.TOP ) { return new Point ( x, y ); } else if ( tabPlacement == JTabbedPane.BOTTOM ) { return new Point ( x, y + h ); } else if ( tabPlacement == JTabbedPane.LEFT ) { return new Point ( x, y ); } else { return new Point ( x + w, y ); } } private Point getBottomTabBgPoint ( final int tabPlacement, final int x, final int y, final int w, final int h ) { if ( tabPlacement == JTabbedPane.TOP ) { return new Point ( x, y + h - 4 ); } else if ( tabPlacement == JTabbedPane.BOTTOM ) { return new Point ( x, y + 4 ); } else if ( tabPlacement == JTabbedPane.LEFT ) { return new Point ( x + w - 4, y ); } else { return new Point ( x + 4, y ); } } @Override protected void paintContentBorder ( final Graphics g, final int tabPlacement, final int selectedIndex ) { final Graphics2D g2d = ( Graphics2D ) g; final Object aa = GraphicsUtils.setupAntialias ( g2d ); final int tabAreaSize = getTabAreaLength ( tabPlacement ); final Insets bi = tabPane.getInsets (); if ( tabPlacement == JTabbedPane.TOP || tabPlacement == JTabbedPane.BOTTOM ) { bi.right += 1; } else { bi.bottom += 1; } // Selected tab bounds final Rectangle selected = selectedIndex != -1 ? getTabBounds ( tabPane, selectedIndex ) : null; // Background shape final Shape bs = createBackgroundShape ( tabPlacement, tabAreaSize, bi, selected ); if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { // Proper clip final GeneralPath clip = new GeneralPath ( GeneralPath.WIND_EVEN_ODD ); clip.append ( new Rectangle2D.Double ( 0, 0, tabPane.getWidth (), tabPane.getHeight () ), false ); clip.append ( bs, false ); GraphicsUtils.drawShade ( g2d, bs, StyleConstants.shadeColor, shadeWidth, clip, round > 0 ); // // Corners covering for large round // if ( round > 2 ) // { // Insets tai = getTabAreaInsets ( tabPlacement ); // if ( tabPlacement == TOP ) // { // if ( selected.x > bi.left ) // { // g2d.setPaint ( bottomBg ); // g2d.fillRect ( bi.left + tai.left, bi.top + tabAreaSize, round, round ); // // g2d.setPaint ( StyleConstants.darkBorderColor ); // g2d.drawLine ( bi.left + tai.left, bi.top + tabAreaSize, bi.left + tai.left, // bi.top + tabAreaSize + round ); // } //// if ( selected.x + selected.width < tabPane.getWidth () - bi.right ) //// { //// g2d.setPaint ( bottomBg ); //// g2d.fillRect ( bi.rightbi.left + tai.left, bi.top + tabAreaSize, round, round ); //// //// g2d.setPaint ( StyleConstants.darkBorderColor ); //// g2d.drawLine ( bi.left + tai.left, bi.top + tabAreaSize, bi.left + tai.left, //// bi.top + tabAreaSize + round ); //// } // } // } // Area background if ( backgroundPainterAt.containsKey ( selectedIndex ) ) { final Shape old = GraphicsUtils.intersectClip ( g2d, bs ); backgroundPainterAt.get ( selectedIndex ).paint ( g2d, bs.getBounds (), tabPane ); GraphicsUtils.restoreClip ( g2d, old ); } else { final Color bg = selectedIndex != -1 ? tabPane.getBackgroundAt ( selectedIndex ) : null; g2d.setPaint ( bg != null ? bg : tabPane.getBackground () ); g2d.fill ( bs ); } // Area border g2d.setPaint ( StyleConstants.darkBorderColor ); g2d.draw ( bs ); // Area focus LafUtils.drawCustomWebFocus ( g2d, null, StyleConstants.focusType, bs, null, tabPane.isFocusOwner () ); } else { // Area background if ( backgroundPainterAt.containsKey ( selectedIndex ) ) { backgroundPainterAt.get ( selectedIndex ).paint ( g2d, bs.getBounds (), tabPane ); } else { final Color bg = selectedIndex != -1 ? tabPane.getBackgroundAt ( selectedIndex ) : null; g2d.setPaint ( bg != null ? bg : tabPane.getBackground () ); g2d.fill ( bs ); } // todo draw for other tabPlacement values aswell // Area border g2d.setPaint ( Color.GRAY ); if ( tabPlacement == JTabbedPane.TOP ) { if ( selected != null ) { if ( bi.left < selected.x ) { g2d.drawLine ( bi.left, bi.top + tabAreaSize, selected.x, bi.top + tabAreaSize ); } if ( selected.x + selected.width < tabPane.getWidth () - bi.right ) { g2d.drawLine ( selected.x + selected.width, bi.top + tabAreaSize, tabPane.getWidth () - bi.right, bi.top + tabAreaSize ); } } else { g2d.drawLine ( bi.left, bi.top + tabAreaSize, tabPane.getWidth () - bi.right, bi.top + tabAreaSize ); } } // else if ( tabPlacement == JTabbedPane.BOTTOM ) // { // // // } // else if ( tabPlacement == JTabbedPane.LEFT ) // { // // // } // else if ( tabPlacement == JTabbedPane.RIGHT ) // { // // // } } GraphicsUtils.restoreAntialias ( g2d, aa ); } public int getTabAreaLength ( final int tabPlacement ) { return tabPlacement == JTabbedPane.TOP || tabPlacement == JTabbedPane.BOTTOM ? calculateTabAreaHeight ( tabPlacement, runCount, maxTabHeight ) - 1 : calculateTabAreaWidth ( tabPlacement, runCount, maxTabWidth ) - 1; } private Shape createBackgroundShape ( final int tabPlacement, final int tabAreaSize, final Insets bi, final Rectangle selected ) { if ( tabbedPaneStyle.equals ( TabbedPaneStyle.standalone ) ) { if ( selected != null ) { final GeneralPath gp = new GeneralPath ( GeneralPath.WIND_EVEN_ODD ); if ( tabPlacement == JTabbedPane.TOP ) { final int topY = bi.top + tabAreaSize; gp.moveTo ( selected.x, topY ); if ( selected.x > bi.left + round && round > 0 ) { gp.lineTo ( bi.left + round, topY ); gp.quadTo ( bi.left, topY, bi.left, topY + round ); } else { gp.lineTo ( bi.left, topY ); } if ( round > 0 ) { gp.lineTo ( bi.left, tabPane.getHeight () - bi.bottom - round ); gp.quadTo ( bi.left, tabPane.getHeight () - bi.bottom, bi.left + round, tabPane.getHeight () - bi.bottom ); gp.lineTo ( tabPane.getWidth () - bi.right - round, tabPane.getHeight () - bi.bottom ); gp.quadTo ( tabPane.getWidth () - bi.right, tabPane.getHeight () - bi.bottom, tabPane.getWidth () - bi.right, tabPane.getHeight () - bi.bottom - round ); } else { gp.lineTo ( bi.left, tabPane.getHeight () - bi.bottom ); gp.lineTo ( tabPane.getWidth () - bi.right, tabPane.getHeight () - bi.bottom ); } if ( selected.x + selected.width < tabPane.getWidth () - bi.right - round && round > 0 ) { gp.lineTo ( tabPane.getWidth () - bi.right, topY + round ); gp.quadTo ( tabPane.getWidth () - bi.right, topY, tabPane.getWidth () - bi.right - round, topY ); } else { gp.lineTo ( tabPane.getWidth () - bi.right, topY ); } gp.lineTo ( selected.x + selected.width, topY ); } else if ( tabPlacement == JTabbedPane.BOTTOM ) { final int bottomY = tabPane.getHeight () - bi.bottom - tabAreaSize; gp.moveTo ( selected.x, bottomY ); if ( selected.x > bi.left + round && round > 0 ) { gp.lineTo ( bi.left + round, bottomY ); gp.quadTo ( bi.left, bottomY, bi.left, bottomY - round ); } else { gp.lineTo ( bi.left, bottomY ); } if ( round > 0 ) { gp.lineTo ( bi.left, bi.top + round ); gp.quadTo ( bi.left, bi.top, bi.left + round, bi.top ); gp.lineTo ( tabPane.getWidth () - bi.right - round, bi.top ); gp.quadTo ( tabPane.getWidth () - bi.right, bi.top, tabPane.getWidth () - bi.right, bi.top + round ); } else { gp.lineTo ( bi.left, bi.top ); gp.lineTo ( tabPane.getWidth () - bi.right, bi.top ); } if ( selected.x + selected.width < tabPane.getWidth () - bi.right - round && round > 0 ) { gp.lineTo ( tabPane.getWidth () - bi.right, bottomY - round ); gp.quadTo ( tabPane.getWidth () - bi.right, bottomY, tabPane.getWidth () - bi.right - round, bottomY ); } else { gp.lineTo ( tabPane.getWidth () - bi.right, bottomY ); } gp.lineTo ( selected.x + selected.width, bottomY ); } else if ( tabPlacement == JTabbedPane.LEFT ) { final int leftX = bi.left + tabAreaSize; gp.moveTo ( leftX, selected.y ); if ( selected.y > bi.top + round && round > 0 ) { gp.lineTo ( leftX, bi.top + round ); gp.quadTo ( leftX, bi.top, leftX + round, bi.top ); } else { gp.lineTo ( leftX, bi.top ); } if ( round > 0 ) { gp.lineTo ( tabPane.getWidth () - bi.right - round, bi.top ); gp.quadTo ( tabPane.getWidth () - bi.right, bi.top, tabPane.getWidth () - bi.right, bi.top + round ); gp.lineTo ( tabPane.getWidth () - bi.right, tabPane.getHeight () - bi.bottom - round ); gp.quadTo ( tabPane.getWidth () - bi.right, tabPane.getHeight () - bi.bottom, tabPane.getWidth () - bi.right - round, tabPane.getHeight () - bi.bottom ); } else { gp.lineTo ( tabPane.getWidth () - bi.right, bi.top ); gp.lineTo ( tabPane.getWidth () - bi.right, tabPane.getHeight () - bi.bottom ); } if ( selected.y + selected.height < tabPane.getHeight () - bi.bottom - round && round > 0 ) { gp.lineTo ( leftX + round, tabPane.getHeight () - bi.bottom ); gp.quadTo ( leftX, tabPane.getHeight () - bi.bottom, leftX, tabPane.getHeight () - bi.bottom - round ); } else { gp.lineTo ( leftX, tabPane.getHeight () - bi.bottom ); } gp.lineTo ( leftX, selected.y + selected.height ); } else { final int rightX = tabPane.getWidth () - bi.right - tabAreaSize; gp.moveTo ( rightX, selected.y ); if ( selected.y > bi.top + round && round > 0 ) { gp.lineTo ( rightX, bi.top + round ); gp.quadTo ( rightX, bi.top, rightX - round, bi.top ); } else { gp.lineTo ( rightX, bi.top ); } if ( round > 0 ) { gp.lineTo ( bi.left + round, bi.top ); gp.quadTo ( bi.left, bi.top, bi.left, bi.top + round ); gp.lineTo ( bi.left, tabPane.getHeight () - bi.bottom - round ); gp.quadTo ( bi.left, tabPane.getHeight () - bi.bottom, bi.left + round, tabPane.getHeight () - bi.bottom ); } else { gp.lineTo ( bi.left, bi.top ); gp.lineTo ( bi.left, tabPane.getHeight () - bi.bottom ); } if ( selected.y + selected.height < tabPane.getHeight () - bi.bottom - round && round > 0 ) { gp.lineTo ( rightX - round, tabPane.getHeight () - bi.bottom ); gp.quadTo ( rightX, tabPane.getHeight () - bi.bottom, rightX, tabPane.getHeight () - bi.bottom - round ); } else { gp.lineTo ( rightX, tabPane.getHeight () - bi.bottom ); } gp.lineTo ( rightX, selected.y + selected.height ); } return gp; } else { final boolean top = tabPlacement == JTabbedPane.TOP; final boolean bottom = tabPlacement == JTabbedPane.BOTTOM; final boolean left = tabPlacement == JTabbedPane.LEFT; final boolean right = tabPlacement == JTabbedPane.RIGHT; return new RoundRectangle2D.Double ( bi.left + ( left ? tabAreaSize : 0 ), bi.top + ( top ? tabAreaSize : 0 ), tabPane.getWidth () - bi.left - bi.right - ( left || right ? tabAreaSize : 0 ), tabPane.getHeight () - bi.top - bi.bottom - ( top || bottom ? tabAreaSize : 0 ), round * 2, round * 2 ); } } else { final int x = bi.left + ( tabPlacement == JTabbedPane.LEFT ? tabAreaSize : 0 ); final int y = bi.top + ( tabPlacement == JTabbedPane.TOP ? tabAreaSize : 0 ); final int width = tabPane.getWidth () - bi.left - bi.right - ( tabPlacement == JTabbedPane.LEFT || tabPlacement == JTabbedPane.RIGHT ? tabAreaSize : 0 ); final int height = tabPane.getHeight () - bi.top - bi.bottom - ( tabPlacement == JTabbedPane.TOP || tabPlacement == JTabbedPane.BOTTOM ? tabAreaSize : 0 ); return new Rectangle ( x, y, width + 1, height ); } } public Shape getContentClip () { Shape clip = null; final int tabPlacement = tabPane.getTabPlacement (); final int tabAreaLength = getTabAreaLength ( tabPlacement ); final Insets insets = tabPane.getInsets (); if ( tabPlacement == JTabbedPane.TOP ) { clip = new RoundRectangle2D.Double ( insets.left, insets.top + tabAreaLength, tabPane.getWidth () - insets.left - insets.right, tabPane.getHeight () - insets.top - tabAreaLength - insets.bottom, round * 2, round * 2 ); } else if ( tabPlacement == JTabbedPane.BOTTOM ) { clip = new RoundRectangle2D.Double ( insets.left, insets.top, tabPane.getWidth () - insets.left - insets.right, tabPane.getHeight () - insets.top - tabAreaLength - insets.bottom, round * 2, round * 2 ); } else if ( tabPlacement == JTabbedPane.LEFT ) { clip = new RoundRectangle2D.Double ( insets.left + tabAreaLength, insets.top, tabPane.getWidth () - insets.left - tabAreaLength - insets.right, tabPane.getHeight () - insets.top - insets.bottom, round * 2, round * 2 ); } else if ( tabPlacement == JTabbedPane.RIGHT ) { clip = new RoundRectangle2D.Double ( insets.left, insets.top, tabPane.getWidth () - insets.left - tabAreaLength - insets.right, tabPane.getHeight () - insets.top - insets.bottom, round * 2, round * 2 ); } return clip; } @Override protected void paintFocusIndicator ( final Graphics g, final int tabPlacement, final Rectangle[] rects, final int tabIndex, final Rectangle iconRect, final Rectangle textRect, final boolean isSelected ) { // We don't need this one } @Override public void paint ( final Graphics g, final JComponent c ) { // Background painter if ( painter != null ) { painter.paint ( ( Graphics2D ) g, SwingUtils.size ( c ), c ); } // Basic paintings final Map hints = SwingUtils.setupTextAntialias ( g ); super.paint ( g, c ); SwingUtils.restoreTextAntialias ( g, hints ); } // protected void setRolloverTab ( int index ) // { // super.setRolloverTab ( index ); // // // todo Animate rollover // } // public Dimension getPreferredSize ( JComponent c ) // { // if ( tabPane.getTabPlacement () == JTabbedPane.TOP || // tabPane.getTabPlacement () == JTabbedPane.BOTTOM ) // { // getTab // }else { // // } // } // protected LayoutManager createLayoutManager () // { // return new TabbedPaneLayout (); // } // // public class TabbedPaneLayout extends BasicTabbedPaneUI.TabbedPaneLayout // { // // public TabbedPaneLayout () // { // WebTabbedPaneUI.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 ) // { // } // } // public static void main ( String[] args ) // { // new TestFrame ( new WebTabbedPane ( ){ // { // getWebUI ().setTabbedPaneStyle ( TabbedPaneStyle.attached ); // addTab ( "Tab 1", new WebTabbedPane ( ){ // { // setTabPlacement ( LEFT ); // getWebUI ().setTabbedPaneStyle ( TabbedPaneStyle.attached ); // addTab ( "Tab 1", new JLabel ( ) ); // addTab ( "Tab 2", new JLabel ( ) ); // addTab ( "Tab 3", new JLabel ( ) ); // addTab ( "Tab 4", new JLabel ( ) ); // } // } ); // addTab ( "Tab 2", new WebTabbedPane ( ){ // { // setTabPlacement ( RIGHT ); // getWebUI ().setTabbedPaneStyle ( TabbedPaneStyle.attached ); // addTab ( "Tab 1", new JLabel ( ) ); // addTab ( "Tab 2", new JLabel ( ) ); // addTab ( "Tab 3", new JLabel ( ) ); // addTab ( "Tab 4", new JLabel ( ) ); // } // } ); // addTab ( "Tab 3", new WebTabbedPane ( ){ // { // setTabPlacement ( BOTTOM ); // getWebUI ().setTabbedPaneStyle ( TabbedPaneStyle.attached ); // addTab ( "Tab 1", new JLabel ( ) ); // addTab ( "Tab 2", new JLabel ( ) ); // addTab ( "Tab 3", new JLabel ( ) ); // addTab ( "Tab 4", new JLabel ( ) ); // } // } ); // addTab ( "Tab 4", new JLabel ( ) ); // } // }); // } }