Source for javax.swing.plaf.metal.MetalScrollBarUI

   1: /* MetalScrollBarUI.java
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.metal;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Dimension;
  43: import java.awt.Graphics;
  44: import java.awt.Rectangle;
  45: import java.beans.PropertyChangeEvent;
  46: import java.beans.PropertyChangeListener;
  47: 
  48: import javax.swing.JButton;
  49: import javax.swing.JComponent;
  50: import javax.swing.JScrollBar;
  51: import javax.swing.UIManager;
  52: import javax.swing.plaf.ComponentUI;
  53: import javax.swing.plaf.basic.BasicScrollBarUI;
  54: 
  55: /**
  56:  * A UI delegate for the {@link JScrollBar} component.
  57:  */
  58: public class MetalScrollBarUI extends BasicScrollBarUI
  59: {
  60:   
  61:   /**
  62:    * A property change handler for the UI delegate that monitors for
  63:    * changes to the "JScrollBar.isFreeStanding" property, and updates
  64:    * the buttons and track rendering as appropriate.
  65:    */
  66:   class MetalScrollBarPropertyChangeHandler 
  67:     extends BasicScrollBarUI.PropertyChangeHandler
  68:   {
  69:     /**
  70:      * Creates a new handler.
  71:      * 
  72:      * @see #createPropertyChangeListener()
  73:      */
  74:     public MetalScrollBarPropertyChangeHandler()
  75:     {
  76:       // Nothing to do here.
  77:     }
  78:     
  79:     /**
  80:      * Handles a property change event.  If the event name is
  81:      * <code>JSlider.isFreeStanding</code>, this method updates the 
  82:      * delegate, otherwise the event is passed up to the super class.
  83:      * 
  84:      * @param e  the property change event.
  85:      */
  86:     public void propertyChange(PropertyChangeEvent e)
  87:     {
  88:       if (e.getPropertyName().equals(FREE_STANDING_PROP))
  89:         {
  90:           Boolean prop = (Boolean) e.getNewValue();
  91:           isFreeStanding = (prop == null ? true : prop.booleanValue());
  92:       if (increaseButton != null)
  93:         increaseButton.setFreeStanding(isFreeStanding);
  94:       if (decreaseButton != null)
  95:         decreaseButton.setFreeStanding(isFreeStanding);
  96:         }
  97:       else
  98:     super.propertyChange(e);
  99:     }
 100:   }
 101:   
 102:   /** The name for the 'free standing' property. */
 103:   public static final String FREE_STANDING_PROP = "JScrollBar.isFreeStanding";
 104: 
 105:   /** The minimum thumb size for a scroll bar that is not free standing. */
 106:   private static final Dimension MIN_THUMB_SIZE = new Dimension(15, 15);
 107: 
 108:   /** The minimum thumb size for a scroll bar that is free standing. */
 109:   private static final Dimension MIN_THUMB_SIZE_FREE_STANDING 
 110:     = new Dimension(17, 17);
 111:   
 112:   /** The button that increases the value in the scroll bar. */
 113:   protected MetalScrollButton increaseButton;
 114:   
 115:   /** The button that decreases the value in the scroll bar. */
 116:   protected MetalScrollButton decreaseButton;
 117:   
 118:   /** 
 119:    * The scroll bar width. 
 120:    */
 121:   protected int scrollBarWidth;
 122:   
 123:   /** 
 124:    * A flag that indicates whether the scroll bar is "free standing", which 
 125:    * means it has complete borders and can be used anywhere in the UI.  A 
 126:    * scroll bar which is not free standing has borders missing from one
 127:    * side, and relies on being part of another container with its own borders
 128:    * to look right visually. */
 129:   protected boolean isFreeStanding = true;
 130:   
 131:   /** 
 132:    * The color for the scroll bar shadow (this is read from the UIDefaults in 
 133:    * the installDefaults() method).
 134:    */
 135:   Color scrollBarShadowColor;
 136:   
 137:   /**
 138:    * Constructs a new instance of <code>MetalScrollBarUI</code>, with no
 139:    * specific initialisation.
 140:    */
 141:   public MetalScrollBarUI()
 142:   {
 143:     super();
 144:   }
 145: 
 146:   /**
 147:    * Returns a new instance of <code>MetalScrollBarUI</code>.
 148:    *
 149:    * @param component the component for which we return an UI instance
 150:    *
 151:    * @return An instance of MetalScrollBarUI
 152:    */
 153:   public static ComponentUI createUI(JComponent component)
 154:   {
 155:     return new MetalScrollBarUI();
 156:   }
 157: 
 158:   /**
 159:    * Installs the defaults.
 160:    */
 161:   protected void installDefaults()
 162:   {    
 163:     // need to initialise isFreeStanding before calling the super class, 
 164:     // so that the value is set when createIncreaseButton() and 
 165:     // createDecreaseButton() are called (unless there is somewhere earlier
 166:     // that we can do this).
 167:     Boolean prop = (Boolean) scrollbar.getClientProperty(FREE_STANDING_PROP);
 168:     isFreeStanding = (prop == null ? true : prop.booleanValue());
 169:     scrollBarShadowColor = UIManager.getColor("ScrollBar.shadow");
 170:     super.installDefaults();
 171:   }
 172:     
 173:   /**
 174:    * Creates a property change listener for the delegate to use.  This
 175:    * overrides the method to provide a custom listener for the 
 176:    * {@link MetalLookAndFeel} that can handle the 
 177:    * <code>JScrollBar.isFreeStanding</code> property.
 178:    * 
 179:    * @return A property change listener.
 180:    */
 181:   protected PropertyChangeListener createPropertyChangeListener()
 182:   {
 183:     return new MetalScrollBarPropertyChangeHandler();
 184:   }
 185:   
 186:   /**
 187:    * Creates a new button to use as the control at the lower end of the
 188:    * {@link JScrollBar}.
 189:    * 
 190:    * @param orientation  the orientation of the button ({@link #NORTH},
 191:    *                     {@link #SOUTH}, {@link #EAST} or {@link #WEST}).
 192:    * 
 193:    * @return The button.
 194:    */
 195:   protected JButton createDecreaseButton(int orientation)
 196:   {
 197:     scrollBarWidth = UIManager.getInt("ScrollBar.width");
 198:     decreaseButton = new MetalScrollButton(orientation, scrollBarWidth, 
 199:             isFreeStanding);
 200:     return decreaseButton;
 201:   }
 202: 
 203:   /**
 204:    * Creates a new button to use as the control at the upper end of the
 205:    * {@link JScrollBar}.
 206:    * 
 207:    * @param orientation  the orientation of the button ({@link #NORTH},
 208:    *                     {@link #SOUTH}, {@link #EAST} or {@link #WEST}).
 209:    * 
 210:    * @return The button.
 211:    */
 212:   protected JButton createIncreaseButton(int orientation)
 213:   {
 214:     scrollBarWidth = UIManager.getInt("ScrollBar.width");
 215:     increaseButton = new MetalScrollButton(orientation, scrollBarWidth, 
 216:             isFreeStanding);
 217:     return increaseButton;
 218:   }
 219:   
 220:   /**
 221:    * Paints the track for the scrollbar.
 222:    * 
 223:    * @param g  the graphics device.
 224:    * @param c  the component.
 225:    * @param trackBounds  the track bounds.
 226:    */
 227:   protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
 228:   {
 229:     g.setColor(MetalLookAndFeel.getControl());
 230:     g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, 
 231:             trackBounds.height);
 232:     if (scrollbar.getOrientation() == HORIZONTAL) 
 233:       paintTrackHorizontal(g, c, trackBounds.x, trackBounds.y, 
 234:           trackBounds.width, trackBounds.height);
 235:     else 
 236:       paintTrackVertical(g, c, trackBounds.x, trackBounds.y, 
 237:           trackBounds.width, trackBounds.height);
 238:     
 239:   }
 240:   
 241:   /**
 242:    * Paints the track for a horizontal scrollbar.
 243:    * 
 244:    * @param g  the graphics device.
 245:    * @param c  the component.
 246:    * @param x  the x-coordinate for the track bounds.
 247:    * @param y  the y-coordinate for the track bounds.
 248:    * @param w  the width for the track bounds.
 249:    * @param h  the height for the track bounds.
 250:    */
 251:   private void paintTrackHorizontal(Graphics g, JComponent c, 
 252:       int x, int y, int w, int h)
 253:   {
 254:     if (c.isEnabled())
 255:       {
 256:         g.setColor(MetalLookAndFeel.getControlDarkShadow());
 257:         g.drawLine(x, y, x, y + h - 1);
 258:         g.drawLine(x, y, x + w - 1, y);
 259:         g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
 260:         
 261:         g.setColor(scrollBarShadowColor);
 262:         g.drawLine(x + 1, y + 1, x + 1, y + h - 1);
 263:         g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
 264:         
 265:         if (isFreeStanding) 
 266:           {
 267:             g.setColor(MetalLookAndFeel.getControlDarkShadow());
 268:             g.drawLine(x, y + h - 2, x + w - 1, y + h - 2);
 269:             g.setColor(scrollBarShadowColor);
 270:             g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
 271:           }
 272:       }
 273:     else
 274:       {
 275:         g.setColor(MetalLookAndFeel.getControlDisabled());
 276:         if (isFreeStanding)
 277:           g.drawRect(x, y, w - 1, h - 1);
 278:         else
 279:           {
 280:             g.drawLine(x, y, x + w - 1, y);
 281:             g.drawLine(x, y, x, y + h - 1);
 282:             g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
 283:           }
 284:       }
 285:   }
 286:     
 287:   /**
 288:    * Paints the track for a vertical scrollbar.
 289:    * 
 290:    * @param g  the graphics device.
 291:    * @param c  the component.
 292:    * @param x  the x-coordinate for the track bounds.
 293:    * @param y  the y-coordinate for the track bounds.
 294:    * @param w  the width for the track bounds.
 295:    * @param h  the height for the track bounds.
 296:    */
 297:   private void paintTrackVertical(Graphics g, JComponent c, 
 298:       int x, int y, int w, int h)
 299:   {
 300:     if (c.isEnabled())
 301:       {
 302:         g.setColor(MetalLookAndFeel.getControlDarkShadow());
 303:         g.drawLine(x, y, x, y + h - 1);
 304:         g.drawLine(x, y, x + w - 1, y);
 305:         g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
 306:         
 307:         g.setColor(scrollBarShadowColor);
 308:         g.drawLine(x + 1, y + 1, x + w - 1, y + 1);
 309:         g.drawLine(x + 1, y + 1, x + 1, y + h - 2);
 310:         
 311:         if (isFreeStanding) 
 312:           {
 313:             g.setColor(MetalLookAndFeel.getControlDarkShadow());
 314:             g.drawLine(x + w - 2, y, x + w - 2, y + h - 1);
 315:             g.setColor(MetalLookAndFeel.getControlHighlight());
 316:             g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
 317:           }
 318:       }
 319:     else
 320:       {
 321:         g.setColor(MetalLookAndFeel.getControlDisabled());
 322:         if (isFreeStanding)
 323:           g.drawRect(x, y, w - 1, h - 1);
 324:         else
 325:           {
 326:             g.drawLine(x, y, x + w - 1, y);
 327:             g.drawLine(x, y, x, y + h - 1);
 328:             g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
 329:           }
 330:       }
 331:   }
 332: 
 333:   /**
 334:    * Paints the slider button of the ScrollBar.
 335:    *
 336:    * @param g the Graphics context to use
 337:    * @param c the JComponent on which we paint
 338:    * @param thumbBounds the rectangle that is the slider button
 339:    */
 340:   protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
 341:   {
 342:     // a disabled scrollbar has no thumb in the metal look and feel
 343:     if (!c.isEnabled())
 344:       return;
 345:     if (scrollbar.getOrientation() == HORIZONTAL)
 346:       paintThumbHorizontal(g, c, thumbBounds);
 347:     else 
 348:       paintThumbVertical(g, c, thumbBounds);
 349: 
 350:     // draw the pattern
 351:     MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3,
 352:             thumbBounds.width - 6, thumbBounds.height - 6,
 353:             thumbHighlightColor, thumbLightShadowColor);
 354:   }
 355: 
 356:   /**
 357:    * Paints the thumb for a horizontal scroll bar.
 358:    * 
 359:    * @param g  the graphics device.
 360:    * @param c  the scroll bar component.
 361:    * @param thumbBounds  the thumb bounds.
 362:    */
 363:   private void paintThumbHorizontal(Graphics g, JComponent c, 
 364:           Rectangle thumbBounds) 
 365:   {
 366:     int x = thumbBounds.x;
 367:     int y = thumbBounds.y;
 368:     int w = thumbBounds.width;
 369:     int h = thumbBounds.height;
 370:     
 371:     // first we fill the background
 372:     g.setColor(thumbColor);
 373:     if (isFreeStanding)
 374:       g.fillRect(x, y, w, h - 1);
 375:     else
 376:       g.fillRect(x, y, w, h);
 377:     
 378:     // then draw the dark box
 379:     g.setColor(thumbLightShadowColor);
 380:     if (isFreeStanding)
 381:       g.drawRect(x, y, w - 1, h - 2);
 382:     else
 383:       {
 384:         g.drawLine(x, y, x + w - 1, y);
 385:         g.drawLine(x, y, x, y + h - 1);
 386:         g.drawLine(x + w - 1, y, x + w - 1, y + h -1);
 387:       }
 388:     
 389:     // then the highlight
 390:     g.setColor(thumbHighlightColor);
 391:     if (isFreeStanding)
 392:       {
 393:         g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
 394:         g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
 395:       }
 396:     else
 397:       {
 398:         g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
 399:         g.drawLine(x + 1, y + 1, x + 1, y + h - 1);
 400:       }
 401:     
 402:     // draw the shadow line
 403:     g.setColor(UIManager.getColor("ScrollBar.shadow"));
 404:     g.drawLine(x + w, y + 1, x + w, y + h - 1);
 405: 
 406:   }
 407:   
 408:   /**
 409:    * Paints the thumb for a vertical scroll bar.
 410:    * 
 411:    * @param g  the graphics device.
 412:    * @param c  the scroll bar component.
 413:    * @param thumbBounds  the thumb bounds.
 414:    */
 415:   private void paintThumbVertical(Graphics g, JComponent c, 
 416:           Rectangle thumbBounds)
 417:   {
 418:     int x = thumbBounds.x;
 419:     int y = thumbBounds.y;
 420:     int w = thumbBounds.width;
 421:     int h = thumbBounds.height;
 422:     
 423:     // first we fill the background
 424:     g.setColor(thumbColor);
 425:     if (isFreeStanding)
 426:       g.fillRect(x, y, w - 1, h);
 427:     else
 428:       g.fillRect(x, y, w, h);
 429:      
 430:     // then draw the dark box
 431:     g.setColor(thumbLightShadowColor);
 432:     if (isFreeStanding)
 433:       g.drawRect(x, y, w - 2, h - 1);
 434:     else
 435:       {
 436:         g.drawLine(x, y, x + w - 1, y);
 437:         g.drawLine(x, y, x, y + h - 1);
 438:         g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
 439:       }
 440:     
 441:     // then the highlight
 442:     g.setColor(thumbHighlightColor);
 443:     if (isFreeStanding)
 444:       {
 445:         g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
 446:         g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
 447:       }
 448:     else
 449:       {
 450:         g.drawLine(x + 1, y + 1, x + w - 1, y + 1);
 451:         g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
 452:       }
 453:     
 454:     // draw the shadow line
 455:     g.setColor(UIManager.getColor("ScrollBar.shadow"));
 456:     g.drawLine(x + 1, y + h, x + w - 2, y + h);
 457:   }
 458:   
 459:   /**
 460:    * Returns the minimum thumb size.  For a free standing scroll bar the 
 461:    * minimum size is <code>17 x 17</code> pixels, whereas for a non free 
 462:    * standing scroll bar the minimum size is <code>15 x 15</code> pixels.
 463:    *
 464:    * @return The minimum thumb size.
 465:    */
 466:   protected Dimension getMinimumThumbSize()
 467:   {
 468:     if (isFreeStanding)
 469:       return MIN_THUMB_SIZE_FREE_STANDING;
 470:     else
 471:       return MIN_THUMB_SIZE;
 472:   }
 473:   
 474: }