1 /* MetalScrollBarUI.java
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package javax.swing.plaf.metal;
41 import java.awt.Color;
42 import java.awt.Dimension;
43 import java.awt.Graphics;
44 import java.awt.Insets;
45 import java.awt.Rectangle;
46 import java.beans.PropertyChangeEvent;
47 import java.beans.PropertyChangeListener;
49 import javax.swing.JButton;
50 import javax.swing.JComponent;
51 import javax.swing.JScrollBar;
52 import javax.swing.SwingConstants;
53 import javax.swing.UIManager;
54 import javax.swing.plaf.ComponentUI;
55 import javax.swing.plaf.basic.BasicScrollBarUI;
58 * A UI delegate for the {@link JScrollBar} component.
60 public class MetalScrollBarUI extends BasicScrollBarUI
64 * A property change handler for the UI delegate that monitors for
65 * changes to the "JScrollBar.isFreeStanding" property, and updates
66 * the buttons and track rendering as appropriate.
68 class MetalScrollBarPropertyChangeHandler
69 extends BasicScrollBarUI.PropertyChangeHandler
72 * Creates a new handler.
74 * @see #createPropertyChangeListener()
76 public MetalScrollBarPropertyChangeHandler()
78 // Nothing to do here.
82 * Handles a property change event. If the event name is
83 * <code>JSlider.isFreeStanding</code>, this method updates the
84 * delegate, otherwise the event is passed up to the super class.
86 * @param e the property change event.
88 public void propertyChange(PropertyChangeEvent e)
90 if (e.getPropertyName().equals(FREE_STANDING_PROP))
92 Boolean prop = (Boolean) e.getNewValue();
93 isFreeStanding = prop == null ? true : prop.booleanValue();
94 if (increaseButton != null)
95 increaseButton.setFreeStanding(isFreeStanding);
96 if (decreaseButton != null)
97 decreaseButton.setFreeStanding(isFreeStanding);
100 super.propertyChange(e);
104 /** The name for the 'free standing' property. */
105 public static final String FREE_STANDING_PROP = "JScrollBar.isFreeStanding";
107 /** The minimum thumb size for a scroll bar that is not free standing. */
108 private static final Dimension MIN_THUMB_SIZE = new Dimension(15, 15);
110 /** The minimum thumb size for a scroll bar that is free standing. */
111 private static final Dimension MIN_THUMB_SIZE_FREE_STANDING
112 = new Dimension(17, 17);
114 /** The button that increases the value in the scroll bar. */
115 protected MetalScrollButton increaseButton;
117 /** The button that decreases the value in the scroll bar. */
118 protected MetalScrollButton decreaseButton;
121 * The scroll bar width.
123 protected int scrollBarWidth;
126 * A flag that indicates whether the scroll bar is "free standing", which
127 * means it has complete borders and can be used anywhere in the UI. A
128 * scroll bar which is not free standing has borders missing from one
129 * side, and relies on being part of another container with its own borders
130 * to look right visually. */
131 protected boolean isFreeStanding = true;
134 * The color for the scroll bar shadow (this is read from the UIDefaults in
135 * the installDefaults() method).
137 Color scrollBarShadowColor;
140 * Constructs a new instance of <code>MetalScrollBarUI</code>, with no
141 * specific initialisation.
143 public MetalScrollBarUI()
149 * Returns a new instance of <code>MetalScrollBarUI</code>.
151 * @param component the component for which we return an UI instance
153 * @return An instance of MetalScrollBarUI
155 public static ComponentUI createUI(JComponent component)
157 return new MetalScrollBarUI();
161 * Installs the defaults.
163 protected void installDefaults()
165 // need to initialise isFreeStanding before calling the super class,
166 // so that the value is set when createIncreaseButton() and
167 // createDecreaseButton() are called (unless there is somewhere earlier
168 // that we can do this).
169 Boolean prop = (Boolean) scrollbar.getClientProperty(FREE_STANDING_PROP);
170 isFreeStanding = prop == null ? true : prop.booleanValue();
171 scrollBarShadowColor = UIManager.getColor("ScrollBar.shadow");
172 super.installDefaults();
176 * Creates a property change listener for the delegate to use. This
177 * overrides the method to provide a custom listener for the
178 * {@link MetalLookAndFeel} that can handle the
179 * <code>JScrollBar.isFreeStanding</code> property.
181 * @return A property change listener.
183 protected PropertyChangeListener createPropertyChangeListener()
185 return new MetalScrollBarPropertyChangeHandler();
189 * Creates a new button to use as the control at the lower end of the
190 * {@link JScrollBar}.
192 * @param orientation the orientation of the button ({@link #NORTH},
193 * {@link #SOUTH}, {@link #EAST} or {@link #WEST}).
195 * @return The button.
197 protected JButton createDecreaseButton(int orientation)
199 scrollBarWidth = UIManager.getInt("ScrollBar.width");
200 decreaseButton = new MetalScrollButton(orientation, scrollBarWidth,
202 return decreaseButton;
206 * Creates a new button to use as the control at the upper end of the
207 * {@link JScrollBar}.
209 * @param orientation the orientation of the button ({@link #NORTH},
210 * {@link #SOUTH}, {@link #EAST} or {@link #WEST}).
212 * @return The button.
214 protected JButton createIncreaseButton(int orientation)
216 scrollBarWidth = UIManager.getInt("ScrollBar.width");
217 increaseButton = new MetalScrollButton(orientation, scrollBarWidth,
219 return increaseButton;
223 * Paints the track for the scrollbar.
225 * @param g the graphics device.
226 * @param c the component.
227 * @param trackBounds the track bounds.
229 protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
231 g.setColor(MetalLookAndFeel.getControl());
232 g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width,
234 if (scrollbar.getOrientation() == HORIZONTAL)
235 paintTrackHorizontal(g, c, trackBounds.x, trackBounds.y,
236 trackBounds.width, trackBounds.height);
238 paintTrackVertical(g, c, trackBounds.x, trackBounds.y,
239 trackBounds.width, trackBounds.height);
244 * Paints the track for a horizontal scrollbar.
246 * @param g the graphics device.
247 * @param c the component.
248 * @param x the x-coordinate for the track bounds.
249 * @param y the y-coordinate for the track bounds.
250 * @param w the width for the track bounds.
251 * @param h the height for the track bounds.
253 private void paintTrackHorizontal(Graphics g, JComponent c,
254 int x, int y, int w, int h)
258 g.setColor(MetalLookAndFeel.getControlDarkShadow());
259 g.drawLine(x, y, x, y + h - 1);
260 g.drawLine(x, y, x + w - 1, y);
261 g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
263 g.setColor(scrollBarShadowColor);
264 g.drawLine(x + 1, y + 1, x + 1, y + h - 1);
265 g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
269 g.setColor(MetalLookAndFeel.getControlDarkShadow());
270 g.drawLine(x, y + h - 2, x + w - 1, y + h - 2);
271 g.setColor(scrollBarShadowColor);
272 g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
277 g.setColor(MetalLookAndFeel.getControlDisabled());
279 g.drawRect(x, y, w - 1, h - 1);
282 g.drawLine(x, y, x + w - 1, y);
283 g.drawLine(x, y, x, y + h - 1);
284 g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
290 * Paints the track for a vertical scrollbar.
292 * @param g the graphics device.
293 * @param c the component.
294 * @param x the x-coordinate for the track bounds.
295 * @param y the y-coordinate for the track bounds.
296 * @param w the width for the track bounds.
297 * @param h the height for the track bounds.
299 private void paintTrackVertical(Graphics g, JComponent c,
300 int x, int y, int w, int h)
304 g.setColor(MetalLookAndFeel.getControlDarkShadow());
305 g.drawLine(x, y, x, y + h - 1);
306 g.drawLine(x, y, x + w - 1, y);
307 g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
309 g.setColor(scrollBarShadowColor);
310 g.drawLine(x + 1, y + 1, x + w - 1, y + 1);
311 g.drawLine(x + 1, y + 1, x + 1, y + h - 2);
315 g.setColor(MetalLookAndFeel.getControlDarkShadow());
316 g.drawLine(x + w - 2, y, x + w - 2, y + h - 1);
317 g.setColor(MetalLookAndFeel.getControlHighlight());
318 g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
323 g.setColor(MetalLookAndFeel.getControlDisabled());
325 g.drawRect(x, y, w - 1, h - 1);
328 g.drawLine(x, y, x + w - 1, y);
329 g.drawLine(x, y, x, y + h - 1);
330 g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
336 * Paints the slider button of the ScrollBar.
338 * @param g the Graphics context to use
339 * @param c the JComponent on which we paint
340 * @param thumbBounds the rectangle that is the slider button
342 protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
344 // a disabled scrollbar has no thumb in the metal look and feel
347 if (scrollbar.getOrientation() == HORIZONTAL)
348 paintThumbHorizontal(g, c, thumbBounds);
350 paintThumbVertical(g, c, thumbBounds);
352 // Draw the pattern when the theme is not Ocean.
353 if (! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme))
355 MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3,
356 thumbBounds.width - 6,
357 thumbBounds.height - 6,
359 thumbLightShadowColor);
364 * Paints the thumb for a horizontal scroll bar.
366 * @param g the graphics device.
367 * @param c the scroll bar component.
368 * @param thumbBounds the thumb bounds.
370 private void paintThumbHorizontal(Graphics g, JComponent c,
371 Rectangle thumbBounds)
373 int x = thumbBounds.x;
374 int y = thumbBounds.y;
375 int w = thumbBounds.width;
376 int h = thumbBounds.height;
378 // First we fill the background.
379 MetalTheme theme = MetalLookAndFeel.getCurrentTheme();
380 if (theme instanceof OceanTheme
381 && UIManager.get("ScrollBar.gradient") != null)
383 MetalUtils.paintGradient(g, x + 2, y + 2, w - 4, h - 2,
384 SwingConstants.VERTICAL,
385 "ScrollBar.gradient");
389 g.setColor(thumbColor);
391 g.fillRect(x, y, w, h - 1);
393 g.fillRect(x, y, w, h);
396 // then draw the dark box
397 g.setColor(thumbLightShadowColor);
399 g.drawRect(x, y, w - 1, h - 2);
402 g.drawLine(x, y, x + w - 1, y);
403 g.drawLine(x, y, x, y + h - 1);
404 g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
407 // then the highlight
408 g.setColor(thumbHighlightColor);
411 g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
412 g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
416 g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
417 g.drawLine(x + 1, y + 1, x + 1, y + h - 1);
420 // draw the shadow line
421 g.setColor(UIManager.getColor("ScrollBar.shadow"));
422 g.drawLine(x + w, y + 1, x + w, y + h - 1);
424 // For the OceanTheme, draw the 3 lines in the middle.
425 if (theme instanceof OceanTheme)
427 g.setColor(thumbLightShadowColor);
428 int middle = x + w / 2;
429 g.drawLine(middle - 2, y + 4, middle - 2, y + h - 5);
430 g.drawLine(middle, y + 4, middle, y + h - 5);
431 g.drawLine(middle + 2, y + 4, middle + 2, y + h - 5);
432 g.setColor(UIManager.getColor("ScrollBar.highlight"));
433 g.drawLine(middle - 1, y + 5, middle - 1, y + h - 4);
434 g.drawLine(middle + 1, y + 5, middle + 1, y + h - 4);
435 g.drawLine(middle + 3, y + 5, middle + 3, y + h - 4);
440 * Paints the thumb for a vertical scroll bar.
442 * @param g the graphics device.
443 * @param c the scroll bar component.
444 * @param thumbBounds the thumb bounds.
446 private void paintThumbVertical(Graphics g, JComponent c,
447 Rectangle thumbBounds)
449 int x = thumbBounds.x;
450 int y = thumbBounds.y;
451 int w = thumbBounds.width;
452 int h = thumbBounds.height;
454 // First we fill the background.
455 MetalTheme theme = MetalLookAndFeel.getCurrentTheme();
456 if (theme instanceof OceanTheme
457 && UIManager.get("ScrollBar.gradient") != null)
459 MetalUtils.paintGradient(g, x + 2, y + 2, w - 2, h - 4,
460 SwingConstants.HORIZONTAL,
461 "ScrollBar.gradient");
465 g.setColor(thumbColor);
467 g.fillRect(x, y, w - 1, h);
469 g.fillRect(x, y, w, h);
472 // then draw the dark box
473 g.setColor(thumbLightShadowColor);
475 g.drawRect(x, y, w - 2, h - 1);
478 g.drawLine(x, y, x + w - 1, y);
479 g.drawLine(x, y, x, y + h - 1);
480 g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
483 // then the highlight
484 g.setColor(thumbHighlightColor);
487 g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
488 g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
492 g.drawLine(x + 1, y + 1, x + w - 1, y + 1);
493 g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
496 // draw the shadow line
497 g.setColor(UIManager.getColor("ScrollBar.shadow"));
498 g.drawLine(x + 1, y + h, x + w - 2, y + h);
500 // For the OceanTheme, draw the 3 lines in the middle.
501 if (theme instanceof OceanTheme)
503 g.setColor(thumbLightShadowColor);
504 int middle = y + h / 2;
505 g.drawLine(x + 4, middle - 2, x + w - 5, middle - 2);
506 g.drawLine(x + 4, middle, x + w - 5, middle);
507 g.drawLine(x + 4, middle + 2, x + w - 5, middle + 2);
508 g.setColor(UIManager.getColor("ScrollBar.highlight"));
509 g.drawLine(x + 5, middle - 1, x + w - 4, middle - 1);
510 g.drawLine(x + 5, middle + 1, x + w - 4, middle + 1);
511 g.drawLine(x + 5, middle + 3, x + w - 4, middle + 3);
516 * Returns the minimum thumb size. For a free standing scroll bar the
517 * minimum size is <code>17 x 17</code> pixels, whereas for a non free
518 * standing scroll bar the minimum size is <code>15 x 15</code> pixels.
520 * @return The minimum thumb size.
522 protected Dimension getMinimumThumbSize()
525 if (scrollbar != null)
528 retVal = MIN_THUMB_SIZE_FREE_STANDING;
530 retVal = MIN_THUMB_SIZE;
533 retVal = new Dimension(0, 0);
538 * Returns the <code>preferredSize</code> for the specified scroll bar.
539 * For a vertical scrollbar the height is the sum of the preferred heights
540 * of the buttons plus <code>30</code>. The width is fetched from the
541 * <code>UIManager</code> property <code>ScrollBar.width</code>.
543 * For horizontal scrollbars the width is the sum of the preferred widths
544 * of the buttons plus <code>30</code>. The height is fetched from the
545 * <code>UIManager</code> property <code>ScrollBar.height</code>.
547 * @param c the scrollbar for which to calculate the preferred size
549 * @return the <code>preferredSize</code> for the specified scroll bar
551 public Dimension getPreferredSize(JComponent c)
557 if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
559 width += incrButton.getPreferredSize().getWidth();
560 width += decrButton.getPreferredSize().getWidth();
562 height = UIManager.getInt("ScrollBar.width");
566 height += incrButton.getPreferredSize().getHeight();
567 height += decrButton.getPreferredSize().getHeight();
569 width = UIManager.getInt("ScrollBar.width");
572 Insets insets = scrollbar.getInsets();
574 height += insets.top + insets.bottom;
575 width += insets.left + insets.right;
577 return new Dimension(width, height);