1 /* 2 * @(#)QuaquaSliderUI.java 2.0.1 2008-07-07 3 * 4 * Copyright (c) 2005-2008 Werner Randelshofer 5 * Staldenmattweg 2, Immensee, CH-6405, Switzerland. 6 * All rights reserved. 7 * 8 * The copyright of this software is owned by Werner Randelshofer. 9 * You may not use, copy or modify this software, except in 10 * accordance with the license agreement you entered into with 11 * Werner Randelshofer. For details see accompanying license terms. 12 */ 13 package ch.randelshofer.quaqua; 14 15 import ch.randelshofer.quaqua.util.Debug; 16 import ch.randelshofer.quaqua.util.InsetsUtil; 17 import java.awt.*; 18 import java.awt.event.*; 19 import java.beans.*; 20 import javax.swing.*; 21 import javax.swing.border.*; 22 import javax.swing.event.*; 23 import javax.swing.plaf.*; 24 import javax.swing.plaf.basic.*; 25 26 /** 27 * QuaquaSliderUI. 28 * 29 * @author Werner Randelshofer 30 * @version 2.0.1 2008-07-07 Determine whether to request focus on mouse pressed 31 * from the UIManager. 32 * <br>2.0 2007-12-02 Rewritten. 33 * <br>1.0 December 9, 2005 Created. 34 */ 35 public class QuaquaSliderUI extends BasicSliderUI 36 implements VisuallyLayoutable { 37 38 private Handler handler; 39 private transient boolean isDragging; 40 createUI(JComponent b)41 public static ComponentUI createUI(JComponent b) { 42 return new QuaquaSliderUI((JSlider) b); 43 } 44 QuaquaSliderUI(JSlider b)45 public QuaquaSliderUI(JSlider b) { 46 super(b); 47 } 48 installUI(JComponent c)49 public void installUI(JComponent c) { 50 super.installUI(c); 51 QuaquaUtilities.installProperty(c, "opaque", UIManager.get("Slider.opaque")); 52 //slider.setOpaque(false); 53 } 54 installDefaults(JSlider slider)55 public void installDefaults(JSlider slider) { 56 super.installDefaults(slider); 57 58 focusInsets = getVisualMargin(slider); 59 slider.setRequestFocusEnabled(QuaquaManager.getBoolean("Slider.requestFocusEnabled")); 60 } 61 uninstallListeners(JSlider slider)62 protected void uninstallListeners(JSlider slider) { 63 super.uninstallListeners(slider); 64 handler = null; 65 } 66 createTrackListener(JSlider slider)67 protected TrackListener createTrackListener(JSlider slider) { 68 return new QuaquaTrackListener(); 69 } 70 createChangeListener(JSlider slider)71 protected ChangeListener createChangeListener(JSlider slider) { 72 return getHandler(); 73 } 74 createComponentListener(JSlider slider)75 protected ComponentListener createComponentListener(JSlider slider) { 76 return getHandler(); 77 } 78 createFocusListener(JSlider slider)79 protected FocusListener createFocusListener(JSlider slider) { 80 return getHandler(); 81 } 82 createScrollListener(JSlider slider)83 protected ScrollListener createScrollListener(JSlider slider) { 84 return new ScrollListener(); 85 } 86 createPropertyChangeListener( JSlider slider)87 protected PropertyChangeListener createPropertyChangeListener( 88 JSlider slider) { 89 return getHandler(); 90 } 91 getHandler()92 private Handler getHandler() { 93 if (handler == null) { 94 handler = new Handler(); 95 } 96 return handler; 97 } 98 getThumbSize()99 protected Dimension getThumbSize() { 100 Icon thumb = getThumbIcon(); 101 return new Dimension(thumb.getIconWidth(), thumb.getIconHeight()); 102 } 103 isSmall()104 protected boolean isSmall() { 105 return QuaquaUtilities.isSmallSizeVariant(slider); 106 } 107 getThumbIcon()108 protected Icon getThumbIcon() { 109 String suffix = isSmall() ? ".small" : ""; 110 if (slider.getPaintTicks()) { 111 if (slider.getOrientation() == JSlider.HORIZONTAL) { 112 if (QuaquaUtilities.isLeftToRight(slider)) { 113 return UIManager.getIcon("Slider.southThumb" + suffix); 114 } else { 115 return UIManager.getIcon("Slider.northThumb" + suffix); 116 } 117 } else { 118 if (QuaquaUtilities.isLeftToRight(slider)) { 119 return UIManager.getIcon("Slider.eastThumb" + suffix); 120 } else { 121 return UIManager.getIcon("Slider.westThumb" + suffix); 122 } 123 } 124 } else { 125 return UIManager.getIcon("Slider.roundThumb" + suffix); 126 } 127 } 128 paint(Graphics gr, JComponent c)129 public void paint(Graphics gr, JComponent c) { 130 Graphics2D g = (Graphics2D) gr; 131 Object oldHints = QuaquaUtilities.beginGraphics(g); 132 super.paint(g, c); 133 QuaquaUtilities.endGraphics(g, oldHints); 134 Debug.paint(g, c, this); 135 } 136 paintThumb(Graphics g)137 public void paintThumb(Graphics g) { 138 Rectangle knobBounds = thumbRect; 139 int x = knobBounds.x; 140 int y = knobBounds.y; 141 getThumbIcon().paintIcon(slider, g, x, y); 142 } 143 paintLabels(Graphics g)144 public void paintLabels(Graphics g) { 145 g.setColor(slider.getForeground()); 146 super.paintLabels(g); 147 } 148 paintFocus(Graphics g)149 public void paintFocus(Graphics g) { 150 // empty 151 } 152 calculateGeometry()153 protected void calculateGeometry() { 154 focusInsets = getVisualMargin(slider); 155 super.calculateGeometry(); 156 } calculateContentRect()157 protected void calculateContentRect() { 158 contentRect.x = focusRect.x + focusInsets.left; 159 contentRect.y = focusRect.y + focusInsets.top; 160 contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right); 161 contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom); 162 } 163 calculateThumbLocation()164 protected void calculateThumbLocation() { 165 if (slider.getSnapToTicks()) { 166 int sliderValue = slider.getValue(); 167 int snappedValue = sliderValue; 168 int majorTickSpacing = slider.getMajorTickSpacing(); 169 int minorTickSpacing = slider.getMinorTickSpacing(); 170 int tickSpacing = 0; 171 172 if (minorTickSpacing > 0) { 173 tickSpacing = minorTickSpacing; 174 } else if (majorTickSpacing > 0) { 175 tickSpacing = majorTickSpacing; 176 } 177 178 if (tickSpacing != 0) { 179 // If it's not on a tick, change the value 180 if ((sliderValue - slider.getMinimum()) % tickSpacing != 0) { 181 float temp = (float) (sliderValue - slider.getMinimum()) / (float) tickSpacing; 182 int whichTick = Math.round(temp); 183 snappedValue = slider.getMinimum() + (whichTick * tickSpacing); 184 } 185 186 if (snappedValue != sliderValue) { 187 slider.setValue(snappedValue); 188 } 189 } 190 } 191 192 if (slider.getOrientation() == JSlider.HORIZONTAL) { 193 int valuePosition = xPositionForValue(slider.getValue()); 194 195 thumbRect.x = valuePosition - (thumbRect.width / 2); 196 thumbRect.y = trackRect.y + (trackRect.height - thumbRect.height) / 2; 197 /* 198 if (slider.getPaintTicks()) { 199 if (QuaquaUtilities.isLeftToRight(slider)) { 200 thumbRect.y += 3; 201 } else { 202 thumbRect.y -= 3; 203 } 204 }*/ 205 } else { 206 int valuePosition = yPositionForValue(slider.getValue()); 207 208 thumbRect.x = trackRect.x + (trackRect.width - thumbRect.width) / 2; 209 thumbRect.y = valuePosition - (thumbRect.height / 2); 210 /* 211 if (slider.getPaintTicks()) { 212 if (QuaquaUtilities.isLeftToRight(slider)) { 213 thumbRect.x += 3; 214 } else { 215 thumbRect.x -= 3; 216 } 217 }*/ 218 } 219 } 220 calculateLabelRect()221 protected void calculateLabelRect() { 222 if (slider.getPaintLabels()) { 223 if (slider.getOrientation() == JSlider.HORIZONTAL) { 224 labelRect.x = tickRect.x - trackBuffer; 225 labelRect.width = tickRect.width + (trackBuffer * 2); 226 labelRect.height = getHeightOfTallestLabel(); 227 if (QuaquaUtilities.isLeftToRight(slider)) { 228 labelRect.y = tickRect.y + tickRect.height; 229 } else { 230 labelRect.y = tickRect.y - labelRect.height; 231 } 232 } else { 233 labelRect.y = tickRect.y - trackBuffer; 234 labelRect.height = tickRect.height + (trackBuffer * 2); 235 labelRect.width = getWidthOfWidestLabel(); 236 if (QuaquaUtilities.isLeftToRight(slider)) { 237 labelRect.x = tickRect.x + tickRect.width; 238 } else { 239 labelRect.x = tickRect.x - labelRect.width; 240 } 241 } 242 } else { 243 if (slider.getOrientation() == JSlider.HORIZONTAL) { 244 labelRect.x = tickRect.x; 245 labelRect.y = tickRect.y + tickRect.height; 246 labelRect.width = tickRect.width; 247 labelRect.height = 0; 248 } else { 249 if (QuaquaUtilities.isLeftToRight(slider)) { 250 labelRect.x = tickRect.x + tickRect.width; 251 } else { 252 labelRect.x = tickRect.x; 253 } 254 labelRect.y = tickRect.y; 255 labelRect.width = 0; 256 labelRect.height = tickRect.height; 257 } 258 } 259 } 260 calculateTickRect()261 protected void calculateTickRect() { 262 if (slider.getOrientation() == JSlider.HORIZONTAL) { 263 tickRect.x = trackRect.x; 264 tickRect.width = trackRect.width; 265 tickRect.height = getTickLength(); 266 267 if (QuaquaUtilities.isLeftToRight(slider)) { 268 tickRect.y = trackRect.y + trackRect.height; 269 } else { 270 tickRect.y = trackRect.y - tickRect.height; 271 } 272 if (!slider.getPaintTicks()) { 273 --tickRect.y; 274 tickRect.height = 0; 275 } 276 } else { 277 tickRect.y = trackRect.y; 278 tickRect.height = trackRect.height; 279 tickRect.width = getTickLength(); 280 if (QuaquaUtilities.isLeftToRight(slider)) { 281 tickRect.x = trackRect.x + trackRect.width; 282 } else { 283 tickRect.x = trackRect.x - tickRect.width - 1; 284 } 285 286 if (!slider.getPaintTicks()) { 287 --tickRect.x; 288 tickRect.width = 0; 289 } 290 } 291 } 292 calculateTrackRect()293 protected void calculateTrackRect() { 294 int centerSpacing = 0; // used to center sliders added using BorderLayout.CENTER (bug 4275631) 295 if (slider.getOrientation() == JSlider.HORIZONTAL) { 296 centerSpacing = thumbRect.height; 297 if (QuaquaUtilities.isLeftToRight(slider)) { 298 if (slider.getPaintTicks()) { 299 centerSpacing += getTickLength(); 300 } 301 if (slider.getPaintLabels()) { 302 centerSpacing += getHeightOfTallestLabel(); 303 } 304 } else { 305 if (slider.getPaintTicks()) { 306 centerSpacing -= getTickLength(); 307 } 308 if (slider.getPaintLabels()) { 309 centerSpacing -= getHeightOfTallestLabel(); 310 } 311 } 312 trackRect.x = contentRect.x + trackBuffer; 313 trackRect.y = contentRect.y + (contentRect.height - centerSpacing - 1) / 2 + 1; 314 trackRect.width = contentRect.width - (trackBuffer * 2); 315 trackRect.height = thumbRect.height - 2; 316 } else { 317 centerSpacing = thumbRect.width; 318 if (QuaquaUtilities.isLeftToRight(slider)) { 319 if (slider.getPaintTicks()) { 320 centerSpacing += getTickLength(); 321 } 322 if (slider.getPaintLabels()) { 323 centerSpacing += getWidthOfWidestLabel(); 324 } 325 } else { 326 if (slider.getPaintTicks()) { 327 centerSpacing -= getTickLength(); 328 } 329 if (slider.getPaintLabels()) { 330 centerSpacing -= getWidthOfWidestLabel(); 331 } 332 } 333 trackRect.x = contentRect.x + (contentRect.width - centerSpacing - 1) / 2 + 1; 334 trackRect.y = contentRect.y + trackBuffer; 335 trackRect.width = thumbRect.width - 2; 336 trackRect.height = contentRect.height - (trackBuffer * 2); 337 } 338 } 339 paintTrack(Graphics g)340 public void paintTrack(Graphics g) { 341 int cx, cy, cw, ch; 342 int pad; 343 344 Rectangle trackBounds = trackRect; 345 346 if (slider.getOrientation() == JSlider.HORIZONTAL) { 347 int index = slider.isEnabled() ? 0 : 1; 348 Border border = ((Border[]) UIManager.get("Slider.horizontalTracks"))[index]; 349 Insets insets = border.getBorderInsets(slider); 350 int offset = 0; 351 if (slider.getPaintTicks()) { 352 if (isSmall()) { 353 offset = (QuaquaUtilities.isLeftToRight(slider)) ? -1 : 1; 354 } else { 355 offset = (QuaquaUtilities.isLeftToRight(slider)) ? -3 : 3; 356 } 357 } 358 border.paintBorder( 359 slider, 360 g, 361 trackBounds.x - thumbRect.width / 2 + 3, 362 trackBounds.y + (trackBounds.height - insets.top - insets.bottom) / 2 + offset, 363 trackBounds.width + thumbRect.width - 6, 364 insets.top + insets.bottom); 365 } else { 366 int index = slider.isEnabled() ? 0 : 1; 367 Border border = ((Border[]) UIManager.get("Slider.verticalTracks"))[index]; 368 Insets insets = border.getBorderInsets(slider); 369 int offset = 0; 370 if (slider.getPaintTicks()) { 371 if (isSmall()) { 372 offset = (QuaquaUtilities.isLeftToRight(slider)) ? -1 : 1; 373 } else { 374 offset = (QuaquaUtilities.isLeftToRight(slider)) ? -3 : 3; 375 } 376 } 377 378 int x = trackBounds.x + (trackBounds.width - insets.left - insets.right) / 2; 379 border.paintBorder( 380 slider, 381 g, 382 x + offset, 383 trackBounds.y - thumbRect.height / 2 + 3, 384 insets.left + insets.right, 385 trackBounds.height + thumbRect.height - 6); 386 } 387 } 388 paintTicks(Graphics g)389 public void paintTicks(Graphics g) { 390 Rectangle tickBounds = tickRect; 391 int i; 392 int maj, min, max; 393 int w = tickBounds.width; 394 int h = tickBounds.height; 395 int centerEffect, tickHeight; 396 397 g.setColor(UIManager.getColor("Slider.tickColor")); 398 399 maj = slider.getMajorTickSpacing(); 400 min = slider.getMinorTickSpacing(); 401 402 if (slider.getOrientation() == JSlider.HORIZONTAL) { 403 g.translate(0, tickBounds.y); 404 405 int value = slider.getMinimum(); 406 int xPos = 0; 407 408 if (slider.getMinorTickSpacing() > 0) { 409 int offset = 0; 410 if (!QuaquaUtilities.isLeftToRight(slider)) { 411 offset = tickBounds.height - tickBounds.height / 2; 412 g.translate(0, offset); 413 } 414 while (value <= slider.getMaximum()) { 415 xPos = xPositionForValue(value); 416 paintMinorTickForHorizSlider(g, tickBounds, xPos); 417 value += slider.getMinorTickSpacing(); 418 } 419 if (!QuaquaUtilities.isLeftToRight(slider)) { 420 g.translate(0, -offset); 421 } 422 } 423 424 if (slider.getMajorTickSpacing() > 0) { 425 value = slider.getMinimum(); 426 if (!QuaquaUtilities.isLeftToRight(slider)) { 427 g.translate(0, 1); 428 } 429 430 while (value <= slider.getMaximum()) { 431 xPos = xPositionForValue(value); 432 paintMajorTickForHorizSlider(g, tickBounds, xPos); 433 value += slider.getMajorTickSpacing(); 434 } 435 if (!QuaquaUtilities.isLeftToRight(slider)) { 436 g.translate(0, -1); 437 } 438 } 439 440 g.translate(0, -tickBounds.y); 441 } else { 442 g.translate(tickBounds.x, 0); 443 444 int value = slider.getMinimum(); 445 int yPos = 0; 446 447 if (slider.getMinorTickSpacing() > 0) { 448 int offset = 0; 449 if (!QuaquaUtilities.isLeftToRight(slider)) { 450 offset = tickBounds.width - tickBounds.width / 2; 451 g.translate(offset, 0); 452 } 453 454 while (value <= slider.getMaximum()) { 455 yPos = yPositionForValue(value); 456 paintMinorTickForVertSlider(g, tickBounds, yPos); 457 value += slider.getMinorTickSpacing(); 458 } 459 460 if (!QuaquaUtilities.isLeftToRight(slider)) { 461 g.translate(-offset, 0); 462 } 463 } 464 465 if (slider.getMajorTickSpacing() > 0) { 466 value = slider.getMinimum(); 467 if (!QuaquaUtilities.isLeftToRight(slider)) { 468 g.translate(2, 0); 469 } 470 471 while (value <= slider.getMaximum()) { 472 yPos = yPositionForValue(value); 473 paintMajorTickForVertSlider(g, tickBounds, yPos); 474 value += slider.getMajorTickSpacing(); 475 } 476 477 if (!QuaquaUtilities.isLeftToRight(slider)) { 478 g.translate(-2, 0); 479 } 480 } 481 g.translate(-tickBounds.x, 0); 482 } 483 } 484 getInputMap(int condition, JSlider slider)485 InputMap getInputMap(int condition, JSlider slider) { 486 if (condition == JComponent.WHEN_FOCUSED) { 487 InputMap keyMap = (InputMap) UIManager.get( 488 "Slider.focusInputMap"); 489 InputMap rtlKeyMap; 490 491 if (slider.getComponentOrientation().isLeftToRight() || 492 ((rtlKeyMap = (InputMap) UIManager.get( 493 "Slider.focusInputMap.RightToLeft")) == null)) { 494 return keyMap; 495 } else { 496 rtlKeyMap.setParent(keyMap); 497 return rtlKeyMap; 498 } 499 } 500 return null; 501 } 502 getVisualMargin(JSlider tc)503 public Insets getVisualMargin(JSlider tc) { 504 Insets margin = (Insets) tc.getClientProperty("Quaqua.Component.visualMargin"); 505 if (margin == null) { 506 margin = UIManager.getInsets("Component.visualMargin"); 507 } 508 return (margin == null) ? new Insets(0, 0, 0, 0) : (Insets) margin.clone(); 509 } 510 getVisualBounds(JComponent c, int type, int width, int height)511 public Rectangle getVisualBounds(JComponent c, int type, int width, int height) { 512 Rectangle bounds = new Rectangle(0, 0, width, height); 513 if (type == VisuallyLayoutable.CLIP_BOUNDS) { 514 return bounds; 515 } 516 517 JSlider b = (JSlider) c; 518 if (type == VisuallyLayoutable.COMPONENT_BOUNDS) { 519 Border border = b.getBorder(); 520 if (border == null || border instanceof UIResource) { 521 InsetsUtil.subtractInto(getVisualMargin(b), bounds); 522 } 523 } 524 return bounds; 525 } 526 527 private class Handler implements ChangeListener, 528 ComponentListener, FocusListener, PropertyChangeListener { 529 // Change Handler stateChanged(ChangeEvent e)530 public void stateChanged(ChangeEvent e) { 531 if (!isDragging) { 532 calculateThumbLocation(); 533 slider.repaint(); 534 } 535 } 536 537 // Component Handler componentHidden(ComponentEvent e)538 public void componentHidden(ComponentEvent e) { 539 } 540 componentMoved(ComponentEvent e)541 public void componentMoved(ComponentEvent e) { 542 } 543 componentResized(ComponentEvent e)544 public void componentResized(ComponentEvent e) { 545 calculateGeometry(); 546 slider.repaint(); 547 } 548 componentShown(ComponentEvent e)549 public void componentShown(ComponentEvent e) { 550 } 551 552 // Focus Handler focusGained(FocusEvent e)553 public void focusGained(FocusEvent e) { 554 slider.repaint(); 555 } 556 focusLost(FocusEvent e)557 public void focusLost(FocusEvent e) { 558 slider.repaint(); 559 } 560 561 // Property Change Handler propertyChange(PropertyChangeEvent e)562 public void propertyChange(PropertyChangeEvent e) { 563 String name = e.getPropertyName(); 564 if (name == "orientation" || 565 name == "inverted" || 566 name == "labelTable" || 567 name == "majorTickSpacing" || 568 name == "minorTickSpacing" || 569 name == "paintTicks" || 570 name == "paintTrack" || 571 name == "paintLabels") { 572 calculateGeometry(); 573 slider.repaint(); 574 } else if (name == "componentOrientation") { 575 calculateGeometry(); 576 slider.repaint(); 577 InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider); 578 SwingUtilities.replaceUIInputMap(slider, 579 JComponent.WHEN_FOCUSED, km); 580 } else if (name == "model") { 581 ((BoundedRangeModel) e.getOldValue()).removeChangeListener( 582 changeListener); 583 ((BoundedRangeModel) e.getNewValue()).addChangeListener( 584 changeListener); 585 calculateThumbLocation(); 586 slider.repaint(); 587 } else if (name == "Frame.active") { 588 slider.repaint(thumbRect); 589 } else if (name.equals("JComponent.sizeVariant")) { 590 QuaquaUtilities.applySizeVariant(slider); 591 } 592 } 593 } 594 595 /** 596 * Track mouse movements. 597 * 598 * This class should be treated as a "protected" inner class. 599 * Instantiate it only within subclasses of <Foo>. 600 */ 601 public class QuaquaTrackListener extends TrackListener { 602 //protected transient int offset; 603 //protected transient int currentMouseX, currentMouseY; mouseReleased(MouseEvent e)604 public void mouseReleased(MouseEvent e) { 605 if (!slider.isEnabled()) { 606 return; 607 } 608 609 offset = 0; 610 scrollTimer.stop(); 611 612 // This is the way we have to determine snap-to-ticks. It's 613 // hard to explain but since ChangeEvents don't give us any 614 // idea what has changed we don't have a way to stop the thumb 615 // bounds from being recalculated. Recalculating the thumb 616 // bounds moves the thumb over the current value (i.e., snapping 617 // to the ticks). 618 if (slider.getSnapToTicks() /*|| slider.getSnapToValue()*/) { 619 isDragging = false; 620 slider.setValueIsAdjusting(false); 621 } else { 622 slider.setValueIsAdjusting(false); 623 isDragging = false; 624 } 625 slider.repaint(); 626 } 627 628 /** 629 * If the mouse is pressed above the "thumb" component 630 * then reduce the scrollbars value by one page ("page up"), 631 * otherwise increase it by one page. If there is no 632 * thumb then page up if the mouse is in the upper half 633 * of the track. 634 */ mousePressed(MouseEvent e)635 public void mousePressed(MouseEvent e) { 636 if (!slider.isEnabled()) { 637 return; 638 } 639 640 currentMouseX = e.getX(); 641 currentMouseY = e.getY(); 642 643 if (slider.isRequestFocusEnabled()) { 644 slider.requestFocus(); 645 } 646 647 // Clicked in the Thumb area? 648 if (thumbRect.contains(currentMouseX, currentMouseY)) { 649 switch (slider.getOrientation()) { 650 case JSlider.VERTICAL: 651 offset = currentMouseY - thumbRect.y; 652 break; 653 case JSlider.HORIZONTAL: 654 offset = currentMouseX - thumbRect.x; 655 break; 656 } 657 isDragging = true; 658 return; 659 } 660 isDragging = false; 661 slider.setValueIsAdjusting(true); 662 663 Dimension sbSize = slider.getSize(); 664 int direction = POSITIVE_SCROLL; 665 666 switch (slider.getOrientation()) { 667 case JSlider.VERTICAL: 668 if (thumbRect.isEmpty()) { 669 int scrollbarCenter = sbSize.height / 2; 670 if (!drawInverted()) { 671 direction = (currentMouseY < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; 672 } else { 673 direction = (currentMouseY < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; 674 } 675 } else { 676 int thumbY = thumbRect.y; 677 if (!drawInverted()) { 678 direction = (currentMouseY < thumbY) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; 679 } else { 680 direction = (currentMouseY < thumbY) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; 681 } 682 } 683 break; 684 case JSlider.HORIZONTAL: 685 if (thumbRect.isEmpty()) { 686 int scrollbarCenter = sbSize.width / 2; 687 if (!drawInverted()) { 688 direction = (currentMouseX < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; 689 } else { 690 direction = (currentMouseX < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; 691 } 692 } else { 693 int thumbX = thumbRect.x; 694 if (!drawInverted()) { 695 direction = (currentMouseX < thumbX) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; 696 } else { 697 direction = (currentMouseX < thumbX) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; 698 } 699 } 700 break; 701 } 702 scrollDueToClickInTrack(direction); 703 Rectangle r = thumbRect; 704 if (!r.contains(currentMouseX, currentMouseY)) { 705 if (shouldScroll(direction)) { 706 scrollTimer.stop(); 707 scrollListener.setDirection(direction); 708 scrollTimer.start(); 709 } 710 } 711 } 712 shouldScroll(int direction)713 public boolean shouldScroll(int direction) { 714 Rectangle r = thumbRect; 715 if (slider.getOrientation() == JSlider.VERTICAL) { 716 if (drawInverted() ? direction < 0 : direction > 0) { 717 if (r.y + r.height <= currentMouseY) { 718 return false; 719 } 720 } else if (r.y >= currentMouseY) { 721 return false; 722 } 723 } else { 724 if (drawInverted() ? direction < 0 : direction > 0) { 725 if (r.x + r.width >= currentMouseX) { 726 return false; 727 } 728 } else if (r.x <= currentMouseX) { 729 return false; 730 } 731 } 732 733 if (direction > 0 && slider.getValue() + slider.getExtent() >= 734 slider.getMaximum()) { 735 return false; 736 } else if (direction < 0 && slider.getValue() <= 737 slider.getMinimum()) { 738 return false; 739 } 740 741 return true; 742 } 743 744 /** 745 * Set the models value to the position of the top/left 746 * of the thumb relative to the origin of the track. 747 */ mouseDragged(MouseEvent e)748 public void mouseDragged(MouseEvent e) { 749 int thumbMiddle = 0; 750 751 if (!slider.isEnabled()) { 752 return; 753 } 754 755 currentMouseX = e.getX(); 756 currentMouseY = e.getY(); 757 758 if (!isDragging) { 759 return; 760 } 761 762 slider.setValueIsAdjusting(true); 763 764 switch (slider.getOrientation()) { 765 case JSlider.VERTICAL: 766 int halfThumbHeight = thumbRect.height / 2; 767 int thumbTop = e.getY() - offset; 768 int trackTop = trackRect.y; 769 int trackBottom = trackRect.y + (trackRect.height - 1); 770 int vMax = yPositionForValue(slider.getMaximum() - 771 slider.getExtent()); 772 773 if (drawInverted()) { 774 trackBottom = vMax; 775 } else { 776 trackTop = vMax; 777 } 778 thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); 779 thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); 780 781 setThumbLocation(thumbRect.x, thumbTop); 782 783 thumbMiddle = thumbTop + halfThumbHeight; 784 slider.setValue(valueForYPosition(thumbMiddle)); 785 break; 786 case JSlider.HORIZONTAL: 787 int halfThumbWidth = thumbRect.width / 2; 788 int thumbLeft = e.getX() - offset; 789 int trackLeft = trackRect.x; 790 int trackRight = trackRect.x + (trackRect.width - 1); 791 int hMax = xPositionForValue(slider.getMaximum() - 792 slider.getExtent()); 793 794 if (drawInverted()) { 795 trackLeft = hMax; 796 } else { 797 trackRight = hMax; 798 } 799 thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); 800 thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); 801 802 setThumbLocation(thumbLeft, thumbRect.y); 803 804 thumbMiddle = thumbLeft + halfThumbWidth; 805 slider.setValue(valueForXPosition(thumbMiddle)); 806 break; 807 default: 808 return; 809 } 810 } 811 mouseMoved(MouseEvent e)812 public void mouseMoved(MouseEvent e) { 813 } 814 } 815 getBaseline(JComponent c, int width, int height)816 public int getBaseline(JComponent c, int width, int height) { 817 return -1; 818 } 819 } 820