OSDN Git Service

2006-06-09 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / plaf / metal / MetalScrollBarUI.java
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.Insets;
45 import java.awt.Rectangle;
46 import java.beans.PropertyChangeEvent;
47 import java.beans.PropertyChangeListener;
48
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;
56
57 /**
58  * A UI delegate for the {@link JScrollBar} component.
59  */
60 public class MetalScrollBarUI extends BasicScrollBarUI
61 {
62   
63   /**
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.
67    */
68   class MetalScrollBarPropertyChangeHandler 
69     extends BasicScrollBarUI.PropertyChangeHandler
70   {
71     /**
72      * Creates a new handler.
73      * 
74      * @see #createPropertyChangeListener()
75      */
76     public MetalScrollBarPropertyChangeHandler()
77     {
78       // Nothing to do here.
79     }
80     
81     /**
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.
85      * 
86      * @param e  the property change event.
87      */
88     public void propertyChange(PropertyChangeEvent e)
89     {
90       if (e.getPropertyName().equals(FREE_STANDING_PROP))
91         {
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);
98         }
99       else
100         super.propertyChange(e);
101     }
102   }
103   
104   /** The name for the 'free standing' property. */
105   public static final String FREE_STANDING_PROP = "JScrollBar.isFreeStanding";
106
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);
109
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);
113   
114   /** The button that increases the value in the scroll bar. */
115   protected MetalScrollButton increaseButton;
116   
117   /** The button that decreases the value in the scroll bar. */
118   protected MetalScrollButton decreaseButton;
119   
120   /** 
121    * The scroll bar width. 
122    */
123   protected int scrollBarWidth;
124   
125   /** 
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;
132   
133   /** 
134    * The color for the scroll bar shadow (this is read from the UIDefaults in 
135    * the installDefaults() method).
136    */
137   Color scrollBarShadowColor;
138   
139   /**
140    * Constructs a new instance of <code>MetalScrollBarUI</code>, with no
141    * specific initialisation.
142    */
143   public MetalScrollBarUI()
144   {
145     super();
146   }
147
148   /**
149    * Returns a new instance of <code>MetalScrollBarUI</code>.
150    *
151    * @param component the component for which we return an UI instance
152    *
153    * @return An instance of MetalScrollBarUI
154    */
155   public static ComponentUI createUI(JComponent component)
156   {
157     return new MetalScrollBarUI();
158   }
159
160   /**
161    * Installs the defaults.
162    */
163   protected void installDefaults()
164   {    
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();
173   }
174     
175   /**
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.
180    * 
181    * @return A property change listener.
182    */
183   protected PropertyChangeListener createPropertyChangeListener()
184   {
185     return new MetalScrollBarPropertyChangeHandler();
186   }
187   
188   /**
189    * Creates a new button to use as the control at the lower end of the
190    * {@link JScrollBar}.
191    * 
192    * @param orientation  the orientation of the button ({@link #NORTH},
193    *                     {@link #SOUTH}, {@link #EAST} or {@link #WEST}).
194    * 
195    * @return The button.
196    */
197   protected JButton createDecreaseButton(int orientation)
198   {
199     scrollBarWidth = UIManager.getInt("ScrollBar.width");
200     decreaseButton = new MetalScrollButton(orientation, scrollBarWidth, 
201             isFreeStanding);
202     return decreaseButton;
203   }
204
205   /**
206    * Creates a new button to use as the control at the upper end of the
207    * {@link JScrollBar}.
208    * 
209    * @param orientation  the orientation of the button ({@link #NORTH},
210    *                     {@link #SOUTH}, {@link #EAST} or {@link #WEST}).
211    * 
212    * @return The button.
213    */
214   protected JButton createIncreaseButton(int orientation)
215   {
216     scrollBarWidth = UIManager.getInt("ScrollBar.width");
217     increaseButton = new MetalScrollButton(orientation, scrollBarWidth, 
218             isFreeStanding);
219     return increaseButton;
220   }
221   
222   /**
223    * Paints the track for the scrollbar.
224    * 
225    * @param g  the graphics device.
226    * @param c  the component.
227    * @param trackBounds  the track bounds.
228    */
229   protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
230   {
231     g.setColor(MetalLookAndFeel.getControl());
232     g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, 
233             trackBounds.height);
234     if (scrollbar.getOrientation() == HORIZONTAL) 
235       paintTrackHorizontal(g, c, trackBounds.x, trackBounds.y, 
236           trackBounds.width, trackBounds.height);
237     else 
238       paintTrackVertical(g, c, trackBounds.x, trackBounds.y, 
239           trackBounds.width, trackBounds.height);
240     
241   }
242   
243   /**
244    * Paints the track for a horizontal scrollbar.
245    * 
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.
252    */
253   private void paintTrackHorizontal(Graphics g, JComponent c, 
254       int x, int y, int w, int h)
255   {
256     if (c.isEnabled())
257       {
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);
262         
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);
266         
267         if (isFreeStanding) 
268           {
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);
273           }
274       }
275     else
276       {
277         g.setColor(MetalLookAndFeel.getControlDisabled());
278         if (isFreeStanding)
279           g.drawRect(x, y, w - 1, h - 1);
280         else
281           {
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);
285           }
286       }
287   }
288     
289   /**
290    * Paints the track for a vertical scrollbar.
291    * 
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.
298    */
299   private void paintTrackVertical(Graphics g, JComponent c, 
300       int x, int y, int w, int h)
301   {
302     if (c.isEnabled())
303       {
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);
308         
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);
312         
313         if (isFreeStanding) 
314           {
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);
319           }
320       }
321     else
322       {
323         g.setColor(MetalLookAndFeel.getControlDisabled());
324         if (isFreeStanding)
325           g.drawRect(x, y, w - 1, h - 1);
326         else
327           {
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);
331           }
332       }
333   }
334
335   /**
336    * Paints the slider button of the ScrollBar.
337    *
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
341    */
342   protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
343   {
344     // a disabled scrollbar has no thumb in the metal look and feel
345     if (!c.isEnabled())
346       return;
347     if (scrollbar.getOrientation() == HORIZONTAL)
348       paintThumbHorizontal(g, c, thumbBounds);
349     else 
350       paintThumbVertical(g, c, thumbBounds);
351
352     // Draw the pattern when the theme is not Ocean.
353     if (! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme))
354       {
355         MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3,
356                                     thumbBounds.width - 6,
357                                     thumbBounds.height - 6,
358                                     thumbHighlightColor,
359                                     thumbLightShadowColor);
360       }
361   }
362
363   /**
364    * Paints the thumb for a horizontal scroll bar.
365    * 
366    * @param g  the graphics device.
367    * @param c  the scroll bar component.
368    * @param thumbBounds  the thumb bounds.
369    */
370   private void paintThumbHorizontal(Graphics g, JComponent c, 
371           Rectangle thumbBounds) 
372   {
373     int x = thumbBounds.x;
374     int y = thumbBounds.y;
375     int w = thumbBounds.width;
376     int h = thumbBounds.height;
377     
378     // First we fill the background.
379     MetalTheme theme = MetalLookAndFeel.getCurrentTheme();
380     if (theme instanceof OceanTheme
381         && UIManager.get("ScrollBar.gradient") != null)
382       {
383         MetalUtils.paintGradient(g, x + 2, y + 2, w - 4, h - 2,
384                                  SwingConstants.VERTICAL,
385                                  "ScrollBar.gradient");
386       }
387     else
388       {
389         g.setColor(thumbColor);
390         if (isFreeStanding)
391           g.fillRect(x, y, w, h - 1);
392         else
393           g.fillRect(x, y, w, h);
394       }
395
396     // then draw the dark box
397     g.setColor(thumbLightShadowColor);
398     if (isFreeStanding)
399       g.drawRect(x, y, w - 1, h - 2);
400     else
401       {
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);
405       }
406     
407     // then the highlight
408     g.setColor(thumbHighlightColor);
409     if (isFreeStanding)
410       {
411         g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
412         g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
413       }
414     else
415       {
416         g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
417         g.drawLine(x + 1, y + 1, x + 1, y + h - 1);
418       }
419     
420     // draw the shadow line
421     g.setColor(UIManager.getColor("ScrollBar.shadow"));
422     g.drawLine(x + w, y + 1, x + w, y + h - 1);
423
424     // For the OceanTheme, draw the 3 lines in the middle.
425     if (theme instanceof OceanTheme)
426       {
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);
436       }
437   }
438   
439   /**
440    * Paints the thumb for a vertical scroll bar.
441    * 
442    * @param g  the graphics device.
443    * @param c  the scroll bar component.
444    * @param thumbBounds  the thumb bounds.
445    */
446   private void paintThumbVertical(Graphics g, JComponent c, 
447           Rectangle thumbBounds)
448   {
449     int x = thumbBounds.x;
450     int y = thumbBounds.y;
451     int w = thumbBounds.width;
452     int h = thumbBounds.height;
453     
454     // First we fill the background.
455     MetalTheme theme = MetalLookAndFeel.getCurrentTheme();
456     if (theme instanceof OceanTheme
457         && UIManager.get("ScrollBar.gradient") != null)
458       {
459         MetalUtils.paintGradient(g, x + 2, y + 2, w - 2, h - 4,
460                                  SwingConstants.HORIZONTAL,
461                                  "ScrollBar.gradient");
462       }
463     else
464       {
465         g.setColor(thumbColor);
466         if (isFreeStanding)
467           g.fillRect(x, y, w - 1, h);
468         else
469           g.fillRect(x, y, w, h);
470       }
471
472     // then draw the dark box
473     g.setColor(thumbLightShadowColor);
474     if (isFreeStanding)
475       g.drawRect(x, y, w - 2, h - 1);
476     else
477       {
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);
481       }
482     
483     // then the highlight
484     g.setColor(thumbHighlightColor);
485     if (isFreeStanding)
486       {
487         g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
488         g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
489       }
490     else
491       {
492         g.drawLine(x + 1, y + 1, x + w - 1, y + 1);
493         g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
494       }
495     
496     // draw the shadow line
497     g.setColor(UIManager.getColor("ScrollBar.shadow"));
498     g.drawLine(x + 1, y + h, x + w - 2, y + h);
499
500     // For the OceanTheme, draw the 3 lines in the middle.
501     if (theme instanceof OceanTheme)
502       {
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);
512       }
513   }
514   
515   /**
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.
519    *
520    * @return The minimum thumb size.
521    */
522   protected Dimension getMinimumThumbSize()
523   {
524     Dimension retVal;
525     if (scrollbar != null)
526       {
527         if (isFreeStanding)
528           retVal = MIN_THUMB_SIZE_FREE_STANDING;
529         else
530           retVal = MIN_THUMB_SIZE;
531       }
532     else
533       retVal = new Dimension(0, 0);
534     return retVal;
535   }
536
537   /**
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>.
542    *
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>.
546    *
547    * @param c the scrollbar for which to calculate the preferred size
548    *
549    * @return the <code>preferredSize</code> for the specified scroll bar
550    */
551   public Dimension getPreferredSize(JComponent c)
552   {
553     int height;
554     int width;
555     height = width = 0;
556
557     if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
558       {
559         width += incrButton.getPreferredSize().getWidth();
560         width += decrButton.getPreferredSize().getWidth();
561         width += 30;
562         height = UIManager.getInt("ScrollBar.width");
563       }
564     else
565       {
566         height += incrButton.getPreferredSize().getHeight();
567         height += decrButton.getPreferredSize().getHeight();
568         height += 30;
569         width = UIManager.getInt("ScrollBar.width");
570       }
571
572     Insets insets = scrollbar.getInsets();
573
574     height += insets.top + insets.bottom;
575     width += insets.left + insets.right;
576
577     return new Dimension(width, height);
578   } 
579 }
580