001 /*
002 * Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.swing.plaf.metal;
027
028 import java.awt.Component;
029 import java.awt.Container;
030 import java.awt.LayoutManager;
031 import java.awt.Adjustable;
032 import java.awt.event.AdjustmentListener;
033 import java.awt.event.AdjustmentEvent;
034 import java.awt.event.ActionListener;
035 import java.awt.event.ActionEvent;
036 import java.awt.event.MouseListener;
037 import java.awt.event.MouseMotionListener;
038 import java.awt.event.MouseAdapter;
039 import java.awt.event.MouseEvent;
040 import java.awt.Graphics;
041 import java.awt.Dimension;
042 import java.awt.Rectangle;
043 import java.awt.Point;
044 import java.awt.Insets;
045 import java.awt.Color;
046 import java.awt.IllegalComponentStateException;
047
048 import java.beans.*;
049
050 import javax.swing.*;
051 import javax.swing.event.*;
052
053 import javax.swing.plaf.*;
054 import javax.swing.plaf.basic.BasicScrollBarUI;
055
056 /**
057 * Implementation of ScrollBarUI for the Metal Look and Feel
058 * <p>
059 *
060 * @version 1.21 08/26/98
061 * @author Tom Santos
062 * @author Steve Wilson
063 */
064 public class MetalScrollBarUI extends BasicScrollBarUI {
065 private static Color shadowColor;
066 private static Color highlightColor;
067 private static Color darkShadowColor;
068 private static Color thumbColor;
069 private static Color thumbShadow;
070 private static Color thumbHighlightColor;
071
072 protected MetalBumps bumps;
073
074 protected MetalScrollButton increaseButton;
075 protected MetalScrollButton decreaseButton;
076
077 protected int scrollBarWidth;
078
079 public static final String FREE_STANDING_PROP = "JScrollBar.isFreeStanding";
080 protected boolean isFreeStanding = true;
081
082 public static ComponentUI createUI(JComponent c) {
083 return new MetalScrollBarUI();
084 }
085
086 protected void installDefaults() {
087 scrollBarWidth = ((Integer) (UIManager.get("ScrollBar.width")))
088 .intValue();
089 super .installDefaults();
090 bumps = new MetalBumps(10, 10, thumbHighlightColor,
091 thumbShadow, thumbColor);
092 }
093
094 protected void installListeners() {
095 super .installListeners();
096 ((ScrollBarListener) propertyChangeListener)
097 .handlePropertyChange(scrollbar
098 .getClientProperty(FREE_STANDING_PROP));
099 }
100
101 protected PropertyChangeListener createPropertyChangeListener() {
102 return new ScrollBarListener();
103 }
104
105 protected void configureScrollBarColors() {
106 super .configureScrollBarColors();
107 shadowColor = UIManager.getColor("ScrollBar.shadow");
108 highlightColor = UIManager.getColor("ScrollBar.highlight");
109 darkShadowColor = UIManager.getColor("ScrollBar.darkShadow");
110 thumbColor = UIManager.getColor("ScrollBar.thumb");
111 thumbShadow = UIManager.getColor("ScrollBar.thumbShadow");
112 thumbHighlightColor = UIManager
113 .getColor("ScrollBar.thumbHighlight");
114
115 }
116
117 public Dimension getPreferredSize(JComponent c) {
118 if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
119 return new Dimension(scrollBarWidth,
120 scrollBarWidth * 3 + 10);
121 } else // Horizontal
122 {
123 return new Dimension(scrollBarWidth * 3 + 10,
124 scrollBarWidth);
125 }
126
127 }
128
129 /** Returns the view that represents the decrease view.
130 */
131 protected JButton createDecreaseButton(int orientation) {
132 decreaseButton = new MetalScrollButton(orientation,
133 scrollBarWidth, isFreeStanding);
134 return decreaseButton;
135 }
136
137 /** Returns the view that represents the increase view. */
138 protected JButton createIncreaseButton(int orientation) {
139 increaseButton = new MetalScrollButton(orientation,
140 scrollBarWidth, isFreeStanding);
141 return increaseButton;
142 }
143
144 protected void paintTrack(Graphics g, JComponent c,
145 Rectangle trackBounds) {
146 g.translate(trackBounds.x, trackBounds.y);
147
148 boolean leftToRight = MetalUtils.isLeftToRight(c);
149
150 if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
151 if (!isFreeStanding) {
152 trackBounds.width += 2;
153 if (!leftToRight) {
154 g.translate(-1, 0);
155 }
156 }
157
158 if (c.isEnabled()) {
159 g.setColor(darkShadowColor);
160 g.drawLine(0, 0, 0, trackBounds.height - 1);
161 g.drawLine(trackBounds.width - 2, 0,
162 trackBounds.width - 2, trackBounds.height - 1);
163 g.drawLine(2, trackBounds.height - 1,
164 trackBounds.width - 1, trackBounds.height - 1);
165 g.drawLine(2, 0, trackBounds.width - 2, 0);
166
167 g.setColor(shadowColor);
168 // g.setColor( Color.red);
169 g.drawLine(1, 1, 1, trackBounds.height - 2);
170 g.drawLine(1, 1, trackBounds.width - 3, 1);
171 if (scrollbar.getValue() != scrollbar.getMaximum()) { // thumb shadow
172 int y = thumbRect.y + thumbRect.height
173 - trackBounds.y;
174 g.drawLine(1, y, trackBounds.width - 1, y);
175 }
176 g.setColor(highlightColor);
177 g.drawLine(trackBounds.width - 1, 0,
178 trackBounds.width - 1, trackBounds.height - 1);
179 } else {
180 MetalUtils.drawDisabledBorder(g, 0, 0,
181 trackBounds.width, trackBounds.height);
182 }
183
184 if (!isFreeStanding) {
185 trackBounds.width -= 2;
186 if (!leftToRight) {
187 g.translate(1, 0);
188 }
189 }
190 } else // HORIZONTAL
191 {
192 if (!isFreeStanding) {
193 trackBounds.height += 2;
194 }
195
196 if (c.isEnabled()) {
197 g.setColor(darkShadowColor);
198 g.drawLine(0, 0, trackBounds.width - 1, 0); // top
199 g.drawLine(0, 2, 0, trackBounds.height - 2); // left
200 g.drawLine(0, trackBounds.height - 2,
201 trackBounds.width - 1, trackBounds.height - 2); // bottom
202 g.drawLine(trackBounds.width - 1, 2,
203 trackBounds.width - 1, trackBounds.height - 1); // right
204
205 g.setColor(shadowColor);
206 // g.setColor( Color.red);
207 g.drawLine(1, 1, trackBounds.width - 2, 1); // top
208 g.drawLine(1, 1, 1, trackBounds.height - 3); // left
209 g.drawLine(0, trackBounds.height - 1,
210 trackBounds.width - 1, trackBounds.height - 1); // bottom
211 if (scrollbar.getValue() != scrollbar.getMaximum()) { // thumb shadow
212 int x = thumbRect.x + thumbRect.width
213 - trackBounds.x;
214 g.drawLine(x, 1, x, trackBounds.height - 1);
215 }
216 } else {
217 MetalUtils.drawDisabledBorder(g, 0, 0,
218 trackBounds.width, trackBounds.height);
219 }
220
221 if (!isFreeStanding) {
222 trackBounds.height -= 2;
223 }
224 }
225
226 g.translate(-trackBounds.x, -trackBounds.y);
227 }
228
229 protected void paintThumb(Graphics g, JComponent c,
230 Rectangle thumbBounds) {
231 if (!c.isEnabled()) {
232 return;
233 }
234
235 if (MetalLookAndFeel.usingOcean()) {
236 oceanPaintThumb(g, c, thumbBounds);
237 return;
238 }
239
240 boolean leftToRight = MetalUtils.isLeftToRight(c);
241
242 g.translate(thumbBounds.x, thumbBounds.y);
243
244 if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
245 if (!isFreeStanding) {
246 thumbBounds.width += 2;
247 if (!leftToRight) {
248 g.translate(-1, 0);
249 }
250 }
251
252 g.setColor(thumbColor);
253 g.fillRect(0, 0, thumbBounds.width - 2,
254 thumbBounds.height - 1);
255
256 g.setColor(thumbShadow);
257 g.drawRect(0, 0, thumbBounds.width - 2,
258 thumbBounds.height - 1);
259
260 g.setColor(thumbHighlightColor);
261 g.drawLine(1, 1, thumbBounds.width - 3, 1);
262 g.drawLine(1, 1, 1, thumbBounds.height - 2);
263
264 bumps.setBumpArea(thumbBounds.width - 6,
265 thumbBounds.height - 7);
266 bumps.paintIcon(c, g, 3, 4);
267
268 if (!isFreeStanding) {
269 thumbBounds.width -= 2;
270 if (!leftToRight) {
271 g.translate(1, 0);
272 }
273 }
274 } else // HORIZONTAL
275 {
276 if (!isFreeStanding) {
277 thumbBounds.height += 2;
278 }
279
280 g.setColor(thumbColor);
281 g.fillRect(0, 0, thumbBounds.width - 1,
282 thumbBounds.height - 2);
283
284 g.setColor(thumbShadow);
285 g.drawRect(0, 0, thumbBounds.width - 1,
286 thumbBounds.height - 2);
287
288 g.setColor(thumbHighlightColor);
289 g.drawLine(1, 1, thumbBounds.width - 3, 1);
290 g.drawLine(1, 1, 1, thumbBounds.height - 3);
291
292 bumps.setBumpArea(thumbBounds.width - 7,
293 thumbBounds.height - 6);
294 bumps.paintIcon(c, g, 4, 3);
295
296 if (!isFreeStanding) {
297 thumbBounds.height -= 2;
298 }
299 }
300
301 g.translate(-thumbBounds.x, -thumbBounds.y);
302 }
303
304 private void oceanPaintThumb(Graphics g, JComponent c,
305 Rectangle thumbBounds) {
306 boolean leftToRight = MetalUtils.isLeftToRight(c);
307
308 g.translate(thumbBounds.x, thumbBounds.y);
309
310 if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
311 if (!isFreeStanding) {
312 thumbBounds.width += 2;
313 if (!leftToRight) {
314 g.translate(-1, 0);
315 }
316 }
317
318 if (thumbColor != null) {
319 g.setColor(thumbColor);
320 g.fillRect(0, 0, thumbBounds.width - 2,
321 thumbBounds.height - 1);
322 }
323
324 g.setColor(thumbShadow);
325 g.drawRect(0, 0, thumbBounds.width - 2,
326 thumbBounds.height - 1);
327
328 g.setColor(thumbHighlightColor);
329 g.drawLine(1, 1, thumbBounds.width - 3, 1);
330 g.drawLine(1, 1, 1, thumbBounds.height - 2);
331
332 MetalUtils.drawGradient(c, g, "ScrollBar.gradient", 2, 2,
333 thumbBounds.width - 4, thumbBounds.height - 3,
334 false);
335
336 int gripSize = thumbBounds.width - 8;
337 if (gripSize > 2 && thumbBounds.height >= 10) {
338 g.setColor(MetalLookAndFeel
339 .getPrimaryControlDarkShadow());
340 int gripY = thumbBounds.height / 2 - 2;
341 for (int counter = 0; counter < 6; counter += 2) {
342 g.fillRect(4, counter + gripY, gripSize, 1);
343 }
344
345 g.setColor(MetalLookAndFeel.getWhite());
346 gripY++;
347 for (int counter = 0; counter < 6; counter += 2) {
348 g.fillRect(5, counter + gripY, gripSize, 1);
349 }
350 }
351 if (!isFreeStanding) {
352 thumbBounds.width -= 2;
353 if (!leftToRight) {
354 g.translate(1, 0);
355 }
356 }
357 } else { // HORIZONTAL
358 if (!isFreeStanding) {
359 thumbBounds.height += 2;
360 }
361
362 if (thumbColor != null) {
363 g.setColor(thumbColor);
364 g.fillRect(0, 0, thumbBounds.width - 1,
365 thumbBounds.height - 2);
366 }
367
368 g.setColor(thumbShadow);
369 g.drawRect(0, 0, thumbBounds.width - 1,
370 thumbBounds.height - 2);
371
372 g.setColor(thumbHighlightColor);
373 g.drawLine(1, 1, thumbBounds.width - 2, 1);
374 g.drawLine(1, 1, 1, thumbBounds.height - 3);
375
376 MetalUtils
377 .drawGradient(c, g, "ScrollBar.gradient", 2, 2,
378 thumbBounds.width - 3,
379 thumbBounds.height - 4, true);
380
381 int gripSize = thumbBounds.height - 8;
382 if (gripSize > 2 && thumbBounds.width >= 10) {
383 g.setColor(MetalLookAndFeel
384 .getPrimaryControlDarkShadow());
385 int gripX = thumbBounds.width / 2 - 2;
386 for (int counter = 0; counter < 6; counter += 2) {
387 g.fillRect(gripX + counter, 4, 1, gripSize);
388 }
389
390 g.setColor(MetalLookAndFeel.getWhite());
391 gripX++;
392 for (int counter = 0; counter < 6; counter += 2) {
393 g.fillRect(gripX + counter, 5, 1, gripSize);
394 }
395 }
396
397 if (!isFreeStanding) {
398 thumbBounds.height -= 2;
399 }
400 }
401
402 g.translate(-thumbBounds.x, -thumbBounds.y);
403 }
404
405 protected Dimension getMinimumThumbSize() {
406 return new Dimension(scrollBarWidth, scrollBarWidth);
407 }
408
409 /**
410 * This is overridden only to increase the invalid area. This
411 * ensures that the "Shadow" below the thumb is invalidated
412 */
413 protected void setThumbBounds(int x, int y, int width, int height) {
414 /* If the thumbs bounds haven't changed, we're done.
415 */
416 if ((thumbRect.x == x) && (thumbRect.y == y)
417 && (thumbRect.width == width)
418 && (thumbRect.height == height)) {
419 return;
420 }
421
422 /* Update thumbRect, and repaint the union of x,y,w,h and
423 * the old thumbRect.
424 */
425 int minX = Math.min(x, thumbRect.x);
426 int minY = Math.min(y, thumbRect.y);
427 int maxX = Math.max(x + width, thumbRect.x + thumbRect.width);
428 int maxY = Math.max(y + height, thumbRect.y + thumbRect.height);
429
430 thumbRect.setBounds(x, y, width, height);
431 scrollbar.repaint(minX, minY, (maxX - minX) + 1,
432 (maxY - minY) + 1);
433 }
434
435 class ScrollBarListener extends
436 BasicScrollBarUI.PropertyChangeHandler {
437 public void propertyChange(PropertyChangeEvent e) {
438 String name = e.getPropertyName();
439 if (name.equals(FREE_STANDING_PROP)) {
440 handlePropertyChange(e.getNewValue());
441 } else {
442 super .propertyChange(e);
443 }
444 }
445
446 public void handlePropertyChange(Object newValue) {
447 if (newValue != null) {
448 boolean temp = ((Boolean) newValue).booleanValue();
449 boolean becameFlush = temp == false
450 && isFreeStanding == true;
451 boolean becameNormal = temp == true
452 && isFreeStanding == false;
453
454 isFreeStanding = temp;
455
456 if (becameFlush) {
457 toFlush();
458 } else if (becameNormal) {
459 toFreeStanding();
460 }
461 } else {
462
463 if (!isFreeStanding) {
464 isFreeStanding = true;
465 toFreeStanding();
466 }
467
468 // This commented-out block is used for testing flush scrollbars.
469 /*
470 if ( isFreeStanding ) {
471 isFreeStanding = false;
472 toFlush();
473 }
474 */
475 }
476
477 if (increaseButton != null) {
478 increaseButton.setFreeStanding(isFreeStanding);
479 }
480 if (decreaseButton != null) {
481 decreaseButton.setFreeStanding(isFreeStanding);
482 }
483 }
484
485 protected void toFlush() {
486 scrollBarWidth -= 2;
487 }
488
489 protected void toFreeStanding() {
490 scrollBarWidth += 2;
491 }
492 } // end class ScrollBarListener
493 }
|