001    /* MetalScrollButton.java
002       Copyright (C) 2005 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing.plaf.metal;
040    
041    import java.awt.Color;
042    import java.awt.Dimension;
043    import java.awt.Graphics;
044    import java.awt.Rectangle;
045    
046    import javax.swing.SwingUtilities;
047    import javax.swing.plaf.basic.BasicArrowButton;
048    
049    /**
050     * A button used by the {@link MetalScrollBarUI}.  The button appearance
051     * varies according to the button direction, whether or not it is part of a 
052     * "free standing" scroll bar, and the current state of the button. 
053     */
054    public class MetalScrollButton extends BasicArrowButton 
055    {
056      
057      /** 
058       * The maximum size for buttons.
059       * @see #getMaximumSize()
060       */
061      private static Dimension maximumSize;     
062      
063      /** The width of the button. */
064      private int buttonWidth;
065      
066      /** 
067       * A flag that indicates whether the button is part of a free standing 
068       * scroll bar.  This affects how the border is drawn.
069       */
070      private boolean freeStanding;
071      
072      /**
073       * Creates a new button.
074       * 
075       * @param direction  the direction (this should be one of {@link #NORTH}, 
076       *                   {@link #SOUTH}, {@link #EAST} and {@link #WEST}, but 
077       *                   this is not enforced).
078       * @param width  the button width.
079       * @param freeStanding  a flag indicating whether the scroll button is free
080       *                      standing or not.
081       */
082      public MetalScrollButton(int direction, int width, boolean freeStanding)
083      {
084        super(direction);
085        buttonWidth = width;
086        this.freeStanding = freeStanding;
087        setFocusable(false);
088      }
089      
090      /**
091       * Returns the button width.
092       * 
093       * @return The button width.
094       */
095      public int getButtonWidth()
096      {
097        return buttonWidth;   
098      }
099    
100      /**
101       * Sets the free standing flag.  This controls how the button border is
102       * drawn.
103       * 
104       * @param freeStanding  the new value of the flag.
105       */
106      public void setFreeStanding(boolean freeStanding)
107      {
108        this.freeStanding = freeStanding;
109      }
110      
111      /**
112       * Paints the button.
113       * 
114       * @param g  the graphics device.
115       */
116      public void paint(Graphics g)
117      {
118        Rectangle bounds = SwingUtilities.getLocalBounds(this);
119    
120        // fill the background
121        if (getModel().isPressed())
122          g.setColor(MetalLookAndFeel.getControlShadow());
123        else
124          g.setColor(MetalLookAndFeel.getControl());
125        g.fillRect(0, 0, bounds.width, bounds.height);
126        
127        paintArrow(g, bounds.width, bounds.height);
128        
129        // paint a border manually - I tried using a real (custom) Border
130        // but couldn't get it to stay set for the button, something was 
131        // overwriting it...
132        if (freeStanding) 
133          {
134            if (direction == WEST)
135              paintWestBorderFreeStanding(g, bounds.width, bounds.height);        
136            else if (direction == EAST)
137              paintEastBorderFreeStanding(g, bounds.width, bounds.height);
138            else if (direction == SOUTH)
139              paintSouthBorderFreeStanding(g, bounds.width, bounds.height);
140            else // asume NORTH
141              paintNorthBorderFreeStanding(g, bounds.width, bounds.height);
142          }
143        else
144          {
145            if (direction == WEST)
146              paintWestBorder(g, bounds.width, bounds.height);        
147            else if (direction == EAST)
148              paintEastBorder(g, bounds.width, bounds.height);
149            else if (direction == SOUTH)
150              paintSouthBorder(g, bounds.width, bounds.height);
151            else // asume NORTH
152              paintNorthBorder(g, bounds.width, bounds.height);
153          }
154      }
155      
156      private void paintArrow(Graphics g, int w, int h)
157      {
158        if (isEnabled())
159          g.setColor(MetalLookAndFeel.getBlack());
160        else
161          g.setColor(MetalLookAndFeel.getControlDisabled());
162        
163        if (direction == SOUTH)
164          {
165            int x = w / 2;
166            int y = h / 2 + 2;
167            for (int i = 1; i < 5; i++)
168              g.drawLine(x - i, y - i, x + i - 1, y - i);
169          }
170        else if (direction == EAST)
171          {
172            int x = w / 2 + 2;
173            int y = h / 2;
174            for (int i = 1; i < 5; i++)
175              g.drawLine(x - i, y - i, x - i, y + i - 1);
176          }
177        else if (direction == WEST)
178          {
179            int x = w / 2 - 3;
180            int y = h / 2;
181            for (int i = 1; i < 5; i++)
182              g.drawLine(x + i, y - i, x + i, y + i - 1);        
183          }
184        else // assume NORTH
185          {
186            int x = w / 2;
187            int y = h / 2 - 3;
188            for (int i = 1; i < 5; i++)
189              g.drawLine(x - i, y + i, x + i - 1, y + i);
190          }
191      }
192      /**
193       * Paints the border for a button with a {@link #NORTH} direction that
194       * belongs to a free standing scroll bar.
195       * 
196       * @param g  the graphics device.
197       * @param w  the button width.
198       * @param h  the button height.
199       */
200      private void paintNorthBorderFreeStanding(Graphics g, int w, int h) 
201      {
202        if (isEnabled())
203          {
204            g.setColor(MetalLookAndFeel.getControlDarkShadow());
205            g.drawLine(0, 0, w - 2, 0);
206            g.drawLine(0, 0, 0, h - 1);
207            g.drawLine(2, h - 1, w - 2, h - 1);
208            g.drawLine(w - 2, 2, w - 2, h - 1);
209            
210            g.setColor(MetalLookAndFeel.getControlHighlight());
211            g.drawLine(1, 1, 1, h - 2);
212            g.drawLine(1, 1, w - 3, 1);
213            g.drawLine(w - 1, 1, w - 1, h - 1);
214          
215            g.setColor(MetalLookAndFeel.getControl());
216            g.drawLine(1, h - 1, 1, h - 1);
217            g.drawLine(w - 2, 1, w - 2, 1);
218          }
219        else
220          {
221            g.setColor(MetalLookAndFeel.getControlDisabled());
222            g.drawLine(0, 0, w - 1, 0);
223            g.drawLine(w - 1, 0, w - 1, h - 1);
224            g.drawLine(0, 0, 0, h - 1);
225          }
226      }
227      
228      /**
229       * Paints the border for a button with a {@link #SOUTH} direction that
230       * belongs to a free standing scroll bar.
231       * 
232       * @param g  the graphics device.
233       * @param w  the button width.
234       * @param h  the button height.
235       */
236      private void paintSouthBorderFreeStanding(Graphics g, int w, int h)
237      {
238        if (isEnabled())
239          {
240            g.setColor(MetalLookAndFeel.getControlDarkShadow());
241            g.drawLine(0, 0, w - 2, 0);
242            g.drawLine(0, 0, 0, h - 1);
243            g.drawLine(2, h - 1, w - 2, h - 1);
244            g.drawLine(w - 2, 2, w - 2, h - 1);
245            
246            g.setColor(MetalLookAndFeel.getControlHighlight());
247            g.drawLine(1, 1, 1, h - 1);
248            g.drawLine(1, 1, w - 1, 1);
249            g.drawLine(w - 1, 1, w - 1, h - 1);
250          
251            g.setColor(MetalLookAndFeel.getControl());
252            g.drawLine(1, h - 1, 1, h - 1);
253            g.drawLine(w - 1, 1, w - 1, 1);
254          }
255        else
256          {
257            g.setColor(MetalLookAndFeel.getControlDisabled());
258            g.drawLine(0, h - 1, w - 1, h - 1);
259            g.drawLine(w - 1, 0, w - 1, h - 1);
260            g.drawLine(0, 0, 0, h - 1);
261          }
262      }
263      
264      /**
265       * Paints the border for a button with an {@link #EAST} direction that
266       * belongs to a free standing scroll bar.
267       * 
268       * @param g  the graphics device.
269       * @param w  the button width.
270       * @param h  the button height.
271       */
272      private void paintEastBorderFreeStanding(Graphics g, int w, int h)
273      {
274        if (isEnabled())
275          {
276            g.setColor(MetalLookAndFeel.getControlDarkShadow());
277            g.drawLine(0, 0, w - 2, 0);
278            g.drawLine(w - 2, 0, w - 2, h - 2);
279            g.drawLine(0, h - 2, w - 2, h - 2);
280            
281            g.setColor(MetalLookAndFeel.getControlHighlight());
282            g.drawLine(0, 1, w - 1, 1);
283            g.drawLine(w - 1, 1, w - 1, h - 1);
284            g.drawLine(0, h - 1, w - 1, h - 1);
285          
286            g.setColor(MetalLookAndFeel.getControl());
287            g.drawLine(w - 2, 1, w - 2, 1);
288          }
289        else
290          {
291            g.setColor(MetalLookAndFeel.getControlDisabled());
292            g.drawLine(0, 0, w - 1, 0);
293            g.drawLine(w - 1, 0, w - 1, h - 1);
294            g.drawLine(0, h - 1, w - 1, h - 1);
295          }
296      }
297      
298      /**
299       * Paints the border for a button with a {@link #WEST} direction that
300       * belongs to a free standing scroll bar.
301       * 
302       * @param g  the graphics device.
303       * @param w  the button width.
304       * @param h  the button height.
305       */
306      private void paintWestBorderFreeStanding(Graphics g, int w, int h)
307      {
308        if (isEnabled())
309          {
310            g.setColor(MetalLookAndFeel.getControlDarkShadow());
311            g.drawLine(0, 0, w - 1, 0);
312            g.drawLine(0, 0, 0, h - 2);
313            g.drawLine(0, h - 2, w - 1, h - 2);
314            
315            g.setColor(MetalLookAndFeel.getControlHighlight());
316            g.drawLine(1, 1, w - 1, 1);
317            g.drawLine(1, 1, 1, h - 1);
318            g.drawLine(1, h - 1, w - 1, h - 1);
319          
320            g.setColor(MetalLookAndFeel.getControl());
321            g.drawLine(1, h - 2, 1, h - 2);
322          }
323        else
324          {
325            g.setColor(MetalLookAndFeel.getControlDisabled());
326            g.drawLine(0, 0, w - 1, 0);
327            g.drawLine(0, 0, 0, h - 1);
328            g.drawLine(0, h - 1, w - 1, h - 1);
329          }
330      }
331      
332      /**
333       * Paints the border for a button with a {@link #NORTH} direction that
334       * belongs to a scroll bar that is not free standing.
335       * 
336       * @param g  the graphics device.
337       * @param w  the button width.
338       * @param h  the button height.
339       */
340      private void paintNorthBorder(Graphics g, int w, int h) 
341      {
342        if (isEnabled())
343          {
344            g.setColor(MetalLookAndFeel.getControlDarkShadow());
345            g.drawLine(0, 0, 0, h - 1);
346             
347            g.setColor(MetalLookAndFeel.getControlHighlight());
348            g.drawLine(1, 0, 1, h - 1);
349            g.drawLine(1, 0, w - 1, 0);
350          }
351        else
352          {
353            g.setColor(MetalLookAndFeel.getControlDisabled());
354            g.drawLine(0, 0, 0, h - 1);
355          }
356      }
357      
358      /**
359       * Paints the border for a button with a {@link #SOUTH} direction that
360       * belongs to a scroll bar that is not free standing.
361       * 
362       * @param g  the graphics device.
363       * @param w  the button width.
364       * @param h  the button height.
365       */
366      private void paintSouthBorder(Graphics g, int w, int h)
367      {
368        if (isEnabled())
369          {
370            g.setColor(MetalLookAndFeel.getControlDarkShadow());
371            g.drawLine(0, 0, 0, h - 1);
372            g.drawLine(0, h - 1, w - 1, h - 1);
373             
374            g.setColor(MetalLookAndFeel.getControlHighlight());
375            g.drawLine(1, 0, 1, h - 1);
376            g.drawLine(1, 0, w - 1, 0);
377            
378            g.setColor(MetalLookAndFeel.getControl());
379            g.drawLine(1, h - 1, 1, h - 1);
380          }
381        else
382          {
383            g.setColor(MetalLookAndFeel.getControlDisabled());
384            g.drawLine(0, 0, 0, h - 1);
385          }
386      }
387    
388      /**
389       * Paints the border for a button with an {@link #EAST} direction that
390       * belongs to a scroll bar that is not free standing.
391       * 
392       * @param g  the graphics device.
393       * @param w  the button width.
394       * @param h  the button height.
395       */
396      private void paintEastBorder(Graphics g, int w, int h)
397      {
398        if (isEnabled())
399          {
400            g.setColor(MetalLookAndFeel.getControlDarkShadow());
401            g.drawLine(0, 0, w - 1, 0);
402            g.drawLine(w - 1, 2, w - 1, h - 1);
403            g.setColor(MetalLookAndFeel.getControlHighlight());
404            g.drawLine(0, 1, w - 2, 1);
405            g.drawLine(0, 1, 0, h - 1);
406          }
407        else
408          {
409            g.setColor(MetalLookAndFeel.getControlDisabled());
410            g.drawLine(0, 0, w - 1, 0);
411          }
412      }
413      
414      /**
415       * Paints the border for a button with a {@link #WEST} direction that
416       * belongs to a scroll bar that is not free standing.
417       * 
418       * @param g  the graphics device.
419       * @param w  the button width.
420       * @param h  the button height.
421       */
422      private void paintWestBorder(Graphics g, int w, int h)
423      {
424        Rectangle bounds = SwingUtilities.getLocalBounds(this);
425        if (isEnabled())
426          {
427            g.setColor(MetalLookAndFeel.getControlDarkShadow());
428            g.drawLine(0, 0, bounds.width - 1, 0);
429            g.setColor(MetalLookAndFeel.getControlHighlight());
430            g.drawLine(0, 1, bounds.width - 1, 1);
431            g.drawLine(0, 1, 0, bounds.height - 1);
432          }
433        else
434          {
435            g.setColor(MetalLookAndFeel.getControlDisabled());
436            g.drawLine(0, 0, bounds.width - 1, 0);
437          }
438      }
439        
440      /**
441       * Returns the preferred size for the button, which varies depending on 
442       * the direction of the button and whether or not it is free standing.
443       * 
444       * @return The preferred size.
445       */
446      public Dimension getPreferredSize()
447      {
448        int adj = 1;
449        if (!freeStanding)
450          adj = 2;
451        
452        if (direction == EAST)
453          return new Dimension(buttonWidth - adj, buttonWidth);    
454        else if (direction == WEST)
455          return new Dimension(buttonWidth - 2, buttonWidth);
456        else if (direction == SOUTH)
457          return new Dimension(buttonWidth, buttonWidth - adj);
458        else // assume NORTH
459          return new Dimension(buttonWidth, buttonWidth - 2);
460      }
461      
462      /**
463       * Returns the minimum size for the button.
464       * 
465       * @return The minimum size for the button.
466       */
467      public Dimension getMinimumSize()
468      {
469        return getPreferredSize();
470      }
471     
472      /**
473       * Returns the maximum size for the button.
474       * 
475       * @return <code>Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE)</code>.
476       */
477      public Dimension getMaximumSize()
478      {
479        if (maximumSize == null)
480          maximumSize = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
481        return maximumSize; 
482      }
483      
484    }