1 /*
   2  * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.java.swing.plaf.motif;
  27 
  28 import java.awt.*;
  29 import java.awt.event.*;
  30 import javax.swing.*;
  31 import javax.swing.event.*;
  32 import javax.swing.plaf.*;
  33 import javax.swing.plaf.basic.BasicTabbedPaneUI;
  34 import java.io.Serializable;
  35 
  36 /**
  37  * A Motif L&F implementation of TabbedPaneUI.
  38  * <p>
  39  * <strong>Warning:</strong>
  40  * Serialized objects of this class will not be compatible with
  41  * future Swing releases.  The current serialization support is appropriate
  42  * for short term storage or RMI between applications running the same
  43  * version of Swing.  A future release of Swing will provide support for
  44  * long term persistence.
  45  *
  46  * @author Amy Fowler
  47  * @author Philip Milne
  48  */
  49 public class MotifTabbedPaneUI extends BasicTabbedPaneUI
  50 {
  51 
  52 // Instance variables initialized at installation
  53 
  54     protected Color unselectedTabBackground;
  55     protected Color unselectedTabForeground;
  56     protected Color unselectedTabShadow;
  57     protected Color unselectedTabHighlight;
  58 
  59 
  60 // UI creation
  61 
  62     public static ComponentUI createUI(JComponent tabbedPane) {
  63         return new MotifTabbedPaneUI();
  64     }
  65 
  66 
  67 // UI Installation/De-installation
  68 
  69 
  70     protected void installDefaults() {
  71         super.installDefaults();
  72 
  73         unselectedTabBackground = UIManager.getColor("TabbedPane.unselectedTabBackground");
  74         unselectedTabForeground = UIManager.getColor("TabbedPane.unselectedTabForeground");
  75         unselectedTabShadow = UIManager.getColor("TabbedPane.unselectedTabShadow");
  76         unselectedTabHighlight = UIManager.getColor("TabbedPane.unselectedTabHighlight");
  77     }
  78 
  79     protected void uninstallDefaults() {
  80         super.uninstallDefaults();
  81 
  82         unselectedTabBackground = null;
  83         unselectedTabForeground = null;
  84         unselectedTabShadow = null;
  85         unselectedTabHighlight = null;
  86     }
  87 
  88 // UI Rendering
  89 
  90    protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
  91                                             int selectedIndex,
  92                                             int x, int y, int w, int h) {
  93         Rectangle selRect = selectedIndex < 0? null :
  94                                getTabBounds(selectedIndex, calcRect);
  95         g.setColor(lightHighlight);
  96 
  97         // Draw unbroken line if tabs are not on TOP, OR
  98         // selected tab is not visible (SCROLL_TAB_LAYOUT)
  99         //
 100         if (tabPlacement != TOP || selectedIndex < 0 ||
 101             (selRect.x < x || selRect.x > x + w)) {
 102             g.drawLine(x, y, x+w-2, y);
 103         } else {
 104             // Break line to show visual connection to selected tab
 105             g.drawLine(x, y, selRect.x - 1, y);
 106             if (selRect.x + selRect.width < x + w - 2) {
 107                 g.drawLine(selRect.x + selRect.width, y,
 108                            x+w-2, y);
 109             }
 110         }
 111     }
 112 
 113     protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
 114                                                int selectedIndex,
 115                                                int x, int y, int w, int h) {
 116         Rectangle selRect = selectedIndex < 0? null :
 117                                getTabBounds(selectedIndex, calcRect);
 118         g.setColor(shadow);
 119 
 120         // Draw unbroken line if tabs are not on BOTTOM, OR
 121         // selected tab is not visible (SCROLL_TAB_LAYOUT)
 122         //
 123         if (tabPlacement != BOTTOM || selectedIndex < 0 ||
 124              (selRect.x < x || selRect.x > x + w)) {
 125             g.drawLine(x+1, y+h-1, x+w-1, y+h-1);
 126         } else {
 127             // Break line to show visual connection to selected tab
 128             g.drawLine(x+1, y+h-1, selRect.x - 1, y+h-1);
 129             if (selRect.x + selRect.width < x + w - 2) {
 130                 g.drawLine(selRect.x + selRect.width, y+h-1, x+w-2, y+h-1);
 131             }
 132         }
 133     }
 134 
 135     protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
 136                                                int selectedIndex,
 137                                                int x, int y, int w, int h) {
 138         Rectangle selRect = selectedIndex < 0? null :
 139                                getTabBounds(selectedIndex, calcRect);
 140         g.setColor(shadow);
 141         // Draw unbroken line if tabs are not on RIGHT, OR
 142         // selected tab is not visible (SCROLL_TAB_LAYOUT)
 143         //
 144         if (tabPlacement != RIGHT || selectedIndex < 0 ||
 145              (selRect.y < y || selRect.y > y + h)) {
 146             g.drawLine(x+w-1, y+1, x+w-1, y+h-1);
 147         } else {
 148             // Break line to show visual connection to selected tab
 149             g.drawLine(x+w-1, y+1, x+w-1, selRect.y - 1);
 150             if (selRect.y + selRect.height < y + h - 2 ) {
 151                 g.drawLine(x+w-1, selRect.y + selRect.height,
 152                            x+w-1, y+h-2);
 153             }
 154         }
 155     }
 156 
 157     protected void paintTabBackground(Graphics g,
 158                                       int tabPlacement, int tabIndex,
 159                                       int x, int y, int w, int h,
 160                                       boolean isSelected ) {
 161         g.setColor(isSelected? tabPane.getBackgroundAt(tabIndex) : unselectedTabBackground);
 162         switch(tabPlacement) {
 163           case LEFT:
 164               g.fillRect(x+1, y+1, w-1, h-2);
 165               break;
 166           case RIGHT:
 167               g.fillRect(x, y+1, w-1, h-2);
 168               break;
 169           case BOTTOM:
 170               g.fillRect(x+1, y, w-2, h-3);
 171               g.drawLine(x+2, y+h-3, x+w-3, y+h-3);
 172               g.drawLine(x+3, y+h-2, x+w-4, y+h-2);
 173               break;
 174           case TOP:
 175           default:
 176               g.fillRect(x+1, y+3, w-2, h-3);
 177               g.drawLine(x+2, y+2, x+w-3, y+2);
 178               g.drawLine(x+3, y+1, x+w-4, y+1);
 179         }
 180 
 181     }
 182 
 183     protected void paintTabBorder(Graphics g,
 184                                   int tabPlacement, int tabIndex,
 185                                   int x, int y, int w, int h,
 186                                   boolean isSelected) {
 187         g.setColor(isSelected? lightHighlight : unselectedTabHighlight);
 188 
 189         switch(tabPlacement) {
 190           case LEFT:
 191               g.drawLine(x, y+2, x, y+h-3);
 192               g.drawLine(x+1, y+1, x+1, y+2);
 193               g.drawLine(x+2, y, x+2, y+1);
 194               g.drawLine(x+3, y, x+w-1, y);
 195               g.setColor(isSelected? shadow : unselectedTabShadow);
 196               g.drawLine(x+1, y+h-3, x+1, y+h-2);
 197               g.drawLine(x+2, y+h-2, x+2, y+h-1);
 198               g.drawLine(x+3, y+h-1, x+w-1, y+h-1);
 199               break;
 200           case RIGHT:
 201               g.drawLine(x, y, x+w-3, y);
 202               g.setColor(isSelected? shadow : unselectedTabShadow);
 203               g.drawLine(x+w-3, y, x+w-3, y+1);
 204               g.drawLine(x+w-2, y+1, x+w-2, y+2);
 205               g.drawLine(x+w-1, y+2, x+w-1, y+h-3);
 206               g.drawLine(x+w-2, y+h-3, x+w-2, y+h-2);
 207               g.drawLine(x+w-3, y+h-2, x+w-3, y+h-1);
 208               g.drawLine(x, y+h-1, x+w-3, y+h-1);
 209               break;
 210           case BOTTOM:
 211               g.drawLine(x, y, x, y+h-3);
 212               g.drawLine(x+1, y+h-3, x+1, y+h-2);
 213               g.drawLine(x+2, y+h-2, x+2, y+h-1);
 214               g.setColor(isSelected? shadow : unselectedTabShadow);
 215               g.drawLine(x+3, y+h-1, x+w-4, y+h-1);
 216               g.drawLine(x+w-3, y+h-2, x+w-3, y+h-1);
 217               g.drawLine(x+w-2, y+h-3, x+w-2, y+h-2);
 218               g.drawLine(x+w-1, y, x+w-1, y+h-3);
 219               break;
 220           case TOP:
 221           default:
 222               g.drawLine(x, y+2, x, y+h-1);
 223               g.drawLine(x+1, y+1, x+1, y+2);
 224               g.drawLine(x+2, y, x+2, y+1);
 225               g.drawLine(x+3, y, x+w-4, y);
 226               g.setColor(isSelected? shadow : unselectedTabShadow);
 227               g.drawLine(x+w-3, y, x+w-3, y+1);
 228               g.drawLine(x+w-2, y+1, x+w-2, y+2);
 229               g.drawLine(x+w-1, y+2, x+w-1, y+h-1);
 230         }
 231 
 232     }
 233 
 234     protected void paintFocusIndicator(Graphics g, int tabPlacement,
 235                                        Rectangle[] rects, int tabIndex,
 236                                        Rectangle iconRect, Rectangle textRect,
 237                                        boolean isSelected) {
 238         Rectangle tabRect = rects[tabIndex];
 239         if (tabPane.hasFocus() && isSelected) {
 240             int x, y, w, h;
 241             g.setColor(focus);
 242             switch(tabPlacement) {
 243               case LEFT:
 244                   x = tabRect.x + 3;
 245                   y = tabRect.y + 3;
 246                   w = tabRect.width - 6;
 247                   h = tabRect.height - 7;
 248                   break;
 249               case RIGHT:
 250                   x = tabRect.x + 2;
 251                   y = tabRect.y + 3;
 252                   w = tabRect.width - 6;
 253                   h = tabRect.height - 7;
 254                   break;
 255               case BOTTOM:
 256                   x = tabRect.x + 3;
 257                   y = tabRect.y + 2;
 258                   w = tabRect.width - 7;
 259                   h = tabRect.height - 6;
 260                   break;
 261               case TOP:
 262               default:
 263                   x = tabRect.x + 3;
 264                   y = tabRect.y + 3;
 265                   w = tabRect.width - 7;
 266                   h = tabRect.height - 6;
 267             }
 268             g.drawRect(x, y, w, h);
 269         }
 270     }
 271 
 272     protected int getTabRunIndent(int tabPlacement, int run) {
 273         return run*3;
 274     }
 275 
 276     protected int getTabRunOverlay(int tabPlacement) {
 277         tabRunOverlay = (tabPlacement == LEFT || tabPlacement == RIGHT)?
 278             (int)Math.round((float)maxTabWidth * .10) :
 279             (int)Math.round((float)maxTabHeight * .22);
 280 
 281         // Ensure that runover lay is not more than insets
 282         // 2 pixel offset is set from insets to each run
 283         switch(tabPlacement) {
 284         case LEFT:
 285                 if( tabRunOverlay > tabInsets.right - 2 )
 286                     tabRunOverlay = tabInsets.right - 2 ;
 287                 break;
 288         case RIGHT:
 289                 if( tabRunOverlay > tabInsets.left - 2 )
 290                     tabRunOverlay = tabInsets.left - 2 ;
 291                 break;
 292         case TOP:
 293                 if( tabRunOverlay > tabInsets.bottom - 2 )
 294                     tabRunOverlay = tabInsets.bottom - 2 ;
 295                 break;
 296         case BOTTOM:
 297                 if( tabRunOverlay > tabInsets.top - 2 )
 298                     tabRunOverlay = tabInsets.top - 2 ;
 299                 break;
 300 
 301         }
 302 
 303         return tabRunOverlay;
 304     }
 305 
 306 }