001 /* 002 * $Id: BasicTaskPaneUI.java 3366 2009-06-17 02:28:19Z kschaefe $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 package org.jdesktop.swingx.plaf.basic; 022 023 import java.awt.Color; 024 import java.awt.Component; 025 import java.awt.Cursor; 026 import java.awt.Dimension; 027 import java.awt.Font; 028 import java.awt.Graphics; 029 import java.awt.Insets; 030 import java.awt.Rectangle; 031 import java.awt.event.ActionEvent; 032 import java.awt.event.FocusEvent; 033 import java.awt.event.FocusListener; 034 import java.awt.event.MouseEvent; 035 import java.beans.PropertyChangeEvent; 036 import java.beans.PropertyChangeListener; 037 038 import javax.swing.AbstractAction; 039 import javax.swing.Action; 040 import javax.swing.ActionMap; 041 import javax.swing.BorderFactory; 042 import javax.swing.Icon; 043 import javax.swing.InputMap; 044 import javax.swing.JComponent; 045 import javax.swing.JLabel; 046 import javax.swing.LookAndFeel; 047 import javax.swing.SwingUtilities; 048 import javax.swing.UIManager; 049 import javax.swing.border.Border; 050 import javax.swing.border.CompoundBorder; 051 import javax.swing.event.MouseInputAdapter; 052 import javax.swing.event.MouseInputListener; 053 import javax.swing.plaf.ActionMapUIResource; 054 import javax.swing.plaf.ColorUIResource; 055 import javax.swing.plaf.ComponentUI; 056 import javax.swing.plaf.FontUIResource; 057 import javax.swing.plaf.UIResource; 058 import javax.swing.plaf.basic.BasicGraphicsUtils; 059 060 import org.jdesktop.swingx.JXCollapsiblePane; 061 import org.jdesktop.swingx.JXHyperlink; 062 import org.jdesktop.swingx.JXTaskPane; 063 import org.jdesktop.swingx.SwingXUtilities; 064 import org.jdesktop.swingx.icon.EmptyIcon; 065 import org.jdesktop.swingx.plaf.TaskPaneUI; 066 067 /** 068 * Base implementation of the <code>JXTaskPane</code> UI. 069 * 070 * @author <a href="mailto:fred@L2FProd.com">Frederic Lavigne</a> 071 */ 072 public class BasicTaskPaneUI extends TaskPaneUI { 073 074 private static FocusListener focusListener = new RepaintOnFocus(); 075 076 public static ComponentUI createUI(JComponent c) { 077 return new BasicTaskPaneUI(); 078 } 079 080 protected int titleHeight = 25; 081 protected int roundHeight = 5; 082 083 protected JXTaskPane group; 084 085 protected boolean mouseOver; 086 protected MouseInputListener mouseListener; 087 088 protected PropertyChangeListener propertyListener; 089 090 /** 091 * {@inheritDoc} 092 */ 093 @Override 094 public void installUI(JComponent c) { 095 super.installUI(c); 096 group = (JXTaskPane) c; 097 098 installDefaults(); 099 installListeners(); 100 installKeyboardActions(); 101 } 102 103 /** 104 * Installs default properties. Following properties are installed: 105 * <ul> 106 * <li>TaskPane.background</li> 107 * <li>TaskPane.foreground</li> 108 * <li>TaskPane.font</li> 109 * <li>TaskPane.borderColor</li> 110 * <li>TaskPane.titleForeground</li> 111 * <li>TaskPane.titleBackgroundGradientStart</li> 112 * <li>TaskPane.titleBackgroundGradientEnd</li> 113 * <li>TaskPane.titleOver</li> 114 * <li>TaskPane.specialTitleOver</li> 115 * <li>TaskPane.specialTitleForeground</li> 116 * <li>TaskPane.specialTitleBackground</li> 117 * </ul> 118 */ 119 protected void installDefaults() { 120 LookAndFeel.installProperty(group, "opaque", true); 121 group.setBorder(createPaneBorder()); 122 ((JComponent) group.getContentPane()) 123 .setBorder(createContentPaneBorder()); 124 125 LookAndFeel.installColorsAndFont(group, "TaskPane.background", 126 "TaskPane.foreground", "TaskPane.font"); 127 128 LookAndFeel.installColorsAndFont((JComponent) group.getContentPane(), 129 "TaskPane.background", "TaskPane.foreground", "TaskPane.font"); 130 } 131 132 /** 133 * Installs listeners for UI delegate. 134 */ 135 protected void installListeners() { 136 mouseListener = createMouseInputListener(); 137 group.addMouseMotionListener(mouseListener); 138 group.addMouseListener(mouseListener); 139 140 group.addFocusListener(focusListener); 141 propertyListener = createPropertyListener(); 142 group.addPropertyChangeListener(propertyListener); 143 } 144 145 /** 146 * Installs keyboard actions to allow task pane to react on hot keys. 147 */ 148 protected void installKeyboardActions() { 149 InputMap inputMap = (InputMap) UIManager.get("TaskPane.focusInputMap"); 150 if (inputMap != null) { 151 SwingUtilities.replaceUIInputMap(group, JComponent.WHEN_FOCUSED, 152 inputMap); 153 } 154 155 ActionMap map = getActionMap(); 156 if (map != null) { 157 SwingUtilities.replaceUIActionMap(group, map); 158 } 159 } 160 161 ActionMap getActionMap() { 162 ActionMap map = new ActionMapUIResource(); 163 map.put("toggleCollapsed", new ToggleCollapsedAction()); 164 return map; 165 } 166 167 @Override 168 public void uninstallUI(JComponent c) { 169 uninstallListeners(); 170 super.uninstallUI(c); 171 } 172 173 /** 174 * Uninstalls previously installed listeners to free component for garbage collection. 175 */ 176 protected void uninstallListeners() { 177 group.removeMouseListener(mouseListener); 178 group.removeMouseMotionListener(mouseListener); 179 group.removeFocusListener(focusListener); 180 group.removePropertyChangeListener(propertyListener); 181 } 182 183 /** 184 * Creates new toggle listener. 185 * @return MouseInputListener reacting on toggle events of task pane. 186 */ 187 protected MouseInputListener createMouseInputListener() { 188 return new ToggleListener(); 189 } 190 191 /** 192 * Creates property change listener for task pane. 193 * @return Property change listener reacting on changes to the task pane. 194 */ 195 protected PropertyChangeListener createPropertyListener() { 196 return new ChangeListener(); 197 } 198 199 /** 200 * Evaluates whenever given mouse even have occurred within borders of task pane. 201 * @param event Evaluated event. 202 * @return True if event occurred within task pane area, false otherwise. 203 */ 204 protected boolean isInBorder(MouseEvent event) { 205 return event.getY() < getTitleHeight(event.getComponent()); 206 } 207 208 /** 209 * Gets current title height. Default value is 25 if not specified otherwise. Method checks 210 * provided component for user set font (!instanceof FontUIResource), if font is set, height 211 * will be calculated from font metrics instead of using internal preset height. 212 * @return Current title height. 213 */ 214 protected int getTitleHeight(Component c) { 215 if (c instanceof JXTaskPane) { 216 JXTaskPane taskPane = (JXTaskPane) c; 217 Font font = taskPane.getFont(); 218 int height = titleHeight; 219 220 if (font != null && !(font instanceof FontUIResource)) { 221 height = Math.max(height, taskPane.getFontMetrics(font).getHeight()); 222 } 223 224 Icon icon = taskPane.getIcon(); 225 226 if (icon != null) { 227 height = Math.max(height, icon.getIconHeight() + 4); 228 } 229 230 return height; 231 } 232 233 return titleHeight; 234 } 235 236 /** 237 * Creates new border for task pane. 238 * @return Fresh border on every call. 239 */ 240 protected Border createPaneBorder() { 241 return new PaneBorder(); 242 } 243 244 @Override 245 public Dimension getPreferredSize(JComponent c) { 246 Component component = group.getComponent(0); 247 if (!(component instanceof JXCollapsiblePane)) { 248 // something wrong in this JXTaskPane 249 return super.getPreferredSize(c); 250 } 251 252 JXCollapsiblePane collapsible = (JXCollapsiblePane) component; 253 Dimension dim = collapsible.getPreferredSize(); 254 255 Border groupBorder = group.getBorder(); 256 if (groupBorder instanceof PaneBorder) { 257 ((PaneBorder) groupBorder).label.setDisplayedMnemonic(group 258 .getMnemonic()); 259 Dimension border = ((PaneBorder) groupBorder) 260 .getPreferredSize(group); 261 dim.width = Math.max(dim.width, border.width); 262 dim.height += border.height; 263 } else { 264 dim.height += getTitleHeight(c); 265 } 266 267 return dim; 268 } 269 270 /** 271 * Creates content pane border. 272 * @return Fresh content pane border initialized with current value of TaskPane.borderColor 273 * on every call. 274 */ 275 protected Border createContentPaneBorder() { 276 Color borderColor = UIManager.getColor("TaskPane.borderColor"); 277 return new CompoundBorder(new ContentPaneBorder(borderColor), 278 BorderFactory.createEmptyBorder(10, 10, 10, 10)); 279 } 280 281 @Override 282 public Component createAction(Action action) { 283 JXHyperlink link = new JXHyperlink(action) { 284 @Override 285 public void updateUI() { 286 super.updateUI(); 287 // ensure the ui of this link is correctly update on l&f changes 288 configure(this); 289 } 290 }; 291 configure(link); 292 return link; 293 } 294 295 /** 296 * Configures internally used hyperlink on new action creation and on every call to 297 * <code>updateUI()</code>. 298 * @param link Configured hyperlink. 299 */ 300 protected void configure(JXHyperlink link) { 301 link.setOpaque(false); 302 link.setBorderPainted(false); 303 link.setFocusPainted(true); 304 link.setForeground(UIManager.getColor("TaskPane.titleForeground")); 305 } 306 307 /** 308 * Ensures expanded group is visible. Issues delayed request for scrolling to visible. 309 */ 310 protected void ensureVisible() { 311 SwingUtilities.invokeLater(new Runnable() { 312 public void run() { 313 group.scrollRectToVisible(new Rectangle(group.getWidth(), group 314 .getHeight())); 315 } 316 }); 317 } 318 319 /** 320 * Focus listener responsible for repainting of the taskpane on focus change. 321 */ 322 static class RepaintOnFocus implements FocusListener { 323 public void focusGained(FocusEvent e) { 324 e.getComponent().repaint(); 325 } 326 327 public void focusLost(FocusEvent e) { 328 e.getComponent().repaint(); 329 } 330 } 331 332 /** 333 * Change listener responsible for change handling. 334 */ 335 class ChangeListener implements PropertyChangeListener { 336 public void propertyChange(PropertyChangeEvent evt) { 337 // if group is expanded but not animated 338 // or if animated has reached expanded state 339 // scroll to visible if scrollOnExpand is enabled 340 if (("collapsed".equals(evt.getPropertyName()) 341 && Boolean.TRUE.equals(evt.getNewValue()) && !group 342 .isAnimated()) 343 || (JXCollapsiblePane.ANIMATION_STATE_KEY.equals(evt 344 .getPropertyName()) && "expanded".equals(evt 345 .getNewValue()))) { 346 if (group.isScrollOnExpand()) { 347 ensureVisible(); 348 } 349 } else if (JXTaskPane.ICON_CHANGED_KEY 350 .equals(evt.getPropertyName()) 351 || JXTaskPane.TITLE_CHANGED_KEY.equals(evt 352 .getPropertyName()) 353 || JXTaskPane.SPECIAL_CHANGED_KEY.equals(evt 354 .getPropertyName())) { 355 // icon, title, special must lead to a repaint() 356 group.repaint(); 357 } else if ("mnemonic".equals(evt.getPropertyName())) { 358 SwingXUtilities.updateMnemonicBinding(group, "toggleCollapsed"); 359 360 Border b = group.getBorder(); 361 362 if (b instanceof PaneBorder) { 363 int key = (Integer) evt.getNewValue(); 364 ((PaneBorder) b).label.setDisplayedMnemonic(key); 365 } 366 } 367 } 368 } 369 370 /** 371 * Mouse listener responsible for handling of toggle events. 372 */ 373 class ToggleListener extends MouseInputAdapter { 374 public void mouseEntered(MouseEvent e) { 375 if (isInBorder(e)) { 376 e.getComponent().setCursor( 377 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 378 } else { 379 mouseOver = false; 380 group.repaint(0, 0, group.getWidth(), getTitleHeight(group)); 381 } 382 } 383 384 public void mouseExited(MouseEvent e) { 385 e.getComponent().setCursor(null); 386 mouseOver = false; 387 group.repaint(0, 0, group.getWidth(), getTitleHeight(group)); 388 } 389 390 public void mouseMoved(MouseEvent e) { 391 if (isInBorder(e)) { 392 e.getComponent().setCursor( 393 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 394 mouseOver = true; 395 } else { 396 e.getComponent().setCursor(null); 397 mouseOver = false; 398 } 399 400 group.repaint(0, 0, group.getWidth(), getTitleHeight(group)); 401 } 402 403 public void mouseReleased(MouseEvent e) { 404 if (SwingUtilities.isLeftMouseButton(e) && isInBorder(e)) { 405 group.setCollapsed(!group.isCollapsed()); 406 } 407 } 408 } 409 410 /** 411 * Toggle expanded action. 412 */ 413 class ToggleCollapsedAction extends AbstractAction { 414 /** 415 * Serial version UID. 416 */ 417 private static final long serialVersionUID = 5676859881615358815L; 418 419 public ToggleCollapsedAction() { 420 super("toggleCollapsed"); 421 } 422 423 public void actionPerformed(ActionEvent e) { 424 group.setCollapsed(!group.isCollapsed()); 425 } 426 427 public boolean isEnabled() { 428 return group.isVisible(); 429 } 430 } 431 432 /** 433 * Toggle icon. 434 */ 435 protected static class ChevronIcon implements Icon { 436 boolean up = true; 437 438 public ChevronIcon(boolean up) { 439 this.up = up; 440 } 441 442 public int getIconHeight() { 443 return 3; 444 } 445 446 public int getIconWidth() { 447 return 6; 448 } 449 450 public void paintIcon(Component c, Graphics g, int x, int y) { 451 if (up) { 452 g.drawLine(x + 3, y, x, y + 3); 453 g.drawLine(x + 3, y, x + 6, y + 3); 454 } else { 455 g.drawLine(x, y, x + 3, y + 3); 456 g.drawLine(x + 3, y + 3, x + 6, y); 457 } 458 } 459 } 460 461 /** 462 * The border around the content pane 463 */ 464 protected static class ContentPaneBorder implements Border, UIResource { 465 Color color; 466 467 public ContentPaneBorder(Color color) { 468 this.color = color; 469 } 470 471 public Insets getBorderInsets(Component c) { 472 return new Insets(0, 1, 1, 1); 473 } 474 475 public boolean isBorderOpaque() { 476 return true; 477 } 478 479 public void paintBorder(Component c, Graphics g, int x, int y, 480 int width, int height) { 481 g.setColor(color); 482 g.drawLine(x, y, x, y + height - 1); 483 g.drawLine(x, y + height - 1, x + width - 1, y + height - 1); 484 g.drawLine(x + width - 1, y, x + width - 1, y + height - 1); 485 } 486 } 487 488 /** 489 * The border of the taskpane group paints the "text", the "icon", the 490 * "expanded" status and the "special" type. 491 * 492 */ 493 protected class PaneBorder implements Border, UIResource { 494 495 protected Color borderColor; 496 protected Color titleForeground; 497 protected Color specialTitleBackground; 498 protected Color specialTitleForeground; 499 protected Color titleBackgroundGradientStart; 500 protected Color titleBackgroundGradientEnd; 501 502 protected Color titleOver; 503 protected Color specialTitleOver; 504 505 protected JLabel label; 506 507 /** 508 * Creates new instance of individual pane border. 509 */ 510 public PaneBorder() { 511 borderColor = UIManager.getColor("TaskPane.borderColor"); 512 513 titleForeground = UIManager.getColor("TaskPane.titleForeground"); 514 515 specialTitleBackground = UIManager 516 .getColor("TaskPane.specialTitleBackground"); 517 specialTitleForeground = UIManager 518 .getColor("TaskPane.specialTitleForeground"); 519 520 titleBackgroundGradientStart = UIManager 521 .getColor("TaskPane.titleBackgroundGradientStart"); 522 titleBackgroundGradientEnd = UIManager 523 .getColor("TaskPane.titleBackgroundGradientEnd"); 524 525 titleOver = UIManager.getColor("TaskPane.titleOver"); 526 if (titleOver == null) { 527 titleOver = specialTitleBackground.brighter(); 528 } 529 specialTitleOver = UIManager.getColor("TaskPane.specialTitleOver"); 530 if (specialTitleOver == null) { 531 specialTitleOver = specialTitleBackground.brighter(); 532 } 533 534 label = new JLabel(); 535 label.setOpaque(false); 536 label.setIconTextGap(8); 537 } 538 539 public Insets getBorderInsets(Component c) { 540 return new Insets(getTitleHeight(c), 0, 0, 0); 541 } 542 543 /** 544 * Overwritten to always return <code>true</code> to speed up 545 * painting. Don't use transparent borders unless providing UI delegate 546 * that provides proper return value when calling this method. 547 * 548 * @see javax.swing.border.Border#isBorderOpaque() 549 */ 550 public boolean isBorderOpaque() { 551 return true; 552 } 553 554 /** 555 * Calculates the preferred border size, its size so all its content 556 * fits. 557 * 558 * @param group 559 * Selected group. 560 */ 561 public Dimension getPreferredSize(JXTaskPane group) { 562 // calculate the title width so it is fully visible 563 // it starts with the title width 564 configureLabel(group); 565 Dimension dim = label.getPreferredSize(); 566 // add the title left offset 567 dim.width += 3; 568 // add the controls width 569 dim.width += getTitleHeight(group); 570 // and some space between label and controls 571 dim.width += 3; 572 573 dim.height = getTitleHeight(group); 574 return dim; 575 } 576 577 /** 578 * Paints background of the title. This may differ based on properties 579 * of the group. 580 * 581 * @param group 582 * Selected group. 583 * @param g 584 * Target graphics. 585 */ 586 protected void paintTitleBackground(JXTaskPane group, Graphics g) { 587 if (group.isSpecial()) { 588 g.setColor(specialTitleBackground); 589 } else { 590 g.setColor(titleBackgroundGradientStart); 591 } 592 g.fillRect(0, 0, group.getWidth(), getTitleHeight(group) - 1); 593 } 594 595 /** 596 * Paints current group title. 597 * 598 * @param group 599 * Selected group. 600 * @param g 601 * Target graphics. 602 * @param textColor 603 * Title color. 604 * @param x 605 * X coordinate of the top left corner. 606 * @param y 607 * Y coordinate of the top left corner. 608 * @param width 609 * Width of the box. 610 * @param height 611 * Height of the box. 612 */ 613 protected void paintTitle(JXTaskPane group, Graphics g, 614 Color textColor, int x, int y, int width, int height) { 615 configureLabel(group); 616 label.setForeground(textColor); 617 if (group.getFont() != null && ! (group.getFont() instanceof FontUIResource)) { 618 label.setFont(group.getFont()); 619 } 620 g.translate(x, y); 621 label.setBounds(0, 0, width, height); 622 label.paint(g); 623 g.translate(-x, -y); 624 } 625 626 /** 627 * Configures label for the group using its title, font, icon and 628 * orientation. 629 * 630 * @param group 631 * Selected group. 632 */ 633 protected void configureLabel(JXTaskPane group) { 634 label.applyComponentOrientation(group.getComponentOrientation()); 635 label.setFont(group.getFont()); 636 label.setText(group.getTitle()); 637 label.setIcon(group.getIcon() == null ? new EmptyIcon() : group 638 .getIcon()); 639 } 640 641 /** 642 * Paints expanded controls. Default implementation does nothing. 643 * 644 * @param group 645 * Expanded group. 646 * @param g 647 * Target graphics. 648 * @param x 649 * X coordinate of the top left corner. 650 * @param y 651 * Y coordinate of the top left corner. 652 * @param width 653 * Width of the box. 654 * @param height 655 * Height of the box. 656 */ 657 protected void paintExpandedControls(JXTaskPane group, Graphics g, 658 int x, int y, int width, int height) { 659 } 660 661 /** 662 * Gets current paint color. 663 * 664 * @param group 665 * Selected group. 666 * @return Color to be used for painting provided group. 667 */ 668 protected Color getPaintColor(JXTaskPane group) { 669 Color paintColor; 670 if (isMouseOverBorder()) { 671 if (mouseOver) { 672 if (group.isSpecial()) { 673 paintColor = specialTitleOver; 674 } else { 675 paintColor = titleOver; 676 } 677 } else { 678 if (group.isSpecial()) { 679 paintColor = specialTitleForeground; 680 } else { 681 paintColor = group.getForeground() == null || group.getForeground() instanceof ColorUIResource ? titleForeground : group.getForeground(); 682 } 683 } 684 } else { 685 if (group.isSpecial()) { 686 paintColor = specialTitleForeground; 687 } else { 688 paintColor = group.getForeground() == null || group.getForeground() instanceof ColorUIResource ? titleForeground : group.getForeground(); 689 } 690 } 691 return paintColor; 692 } 693 694 /* 695 * @see javax.swing.border.Border#paintBorder(java.awt.Component, 696 * java.awt.Graphics, int, int, int, int) 697 */ 698 public void paintBorder(Component c, Graphics g, int x, int y, 699 int width, int height) { 700 701 JXTaskPane group = (JXTaskPane) c; 702 703 // calculate position of title and toggle controls 704 int controlWidth = getTitleHeight(group) - 2 * getRoundHeight(); 705 int controlX = group.getWidth() - getTitleHeight(group); 706 int controlY = getRoundHeight() - 1; 707 int titleX = 3; 708 int titleY = 0; 709 int titleWidth = group.getWidth() - getTitleHeight(group) - 3; 710 int titleHeight = getTitleHeight(group); 711 712 if (!group.getComponentOrientation().isLeftToRight()) { 713 controlX = group.getWidth() - controlX - controlWidth; 714 titleX = group.getWidth() - titleX - titleWidth; 715 } 716 717 // paint the title background 718 paintTitleBackground(group, g); 719 720 // paint the the toggles 721 paintExpandedControls(group, g, controlX, controlY, controlWidth, 722 controlWidth); 723 724 // paint the title text and icon 725 Color paintColor = getPaintColor(group); 726 727 // focus painted same color as text 728 if (group.hasFocus()) { 729 paintFocus(g, paintColor, 3, 3, width - 6, getTitleHeight(group) - 6); 730 } 731 732 paintTitle(group, g, paintColor, titleX, titleY, titleWidth, 733 titleHeight); 734 } 735 736 /** 737 * Paints oval 'border' area around the control itself. 738 * 739 * @param group 740 * Expanded group. 741 * @param g 742 * Target graphics. 743 * @param x 744 * X coordinate of the top left corner. 745 * @param y 746 * Y coordinate of the top left corner. 747 * @param width 748 * Width of the box. 749 * @param height 750 * Height of the box. 751 */ 752 protected void paintRectAroundControls(JXTaskPane group, Graphics g, 753 int x, int y, int width, int height, Color highColor, 754 Color lowColor) { 755 if (mouseOver) { 756 int x2 = x + width; 757 int y2 = y + height; 758 g.setColor(highColor); 759 g.drawLine(x, y, x2, y); 760 g.drawLine(x, y, x, y2); 761 g.setColor(lowColor); 762 g.drawLine(x2, y, x2, y2); 763 g.drawLine(x, y2, x2, y2); 764 } 765 } 766 767 /** 768 * Paints oval 'border' area around the control itself. 769 * 770 * @param group 771 * Expanded group. 772 * @param g 773 * Target graphics. 774 * @param x 775 * X coordinate of the top left corner. 776 * @param y 777 * Y coordinate of the top left corner. 778 * @param width 779 * Width of the box. 780 * @param height 781 * Height of the box. 782 */ 783 protected void paintOvalAroundControls(JXTaskPane group, Graphics g, 784 int x, int y, int width, int height) { 785 if (group.isSpecial()) { 786 g.setColor(specialTitleBackground.brighter()); 787 g.drawOval(x, y, width, height); 788 } else { 789 g.setColor(titleBackgroundGradientStart); 790 g.fillOval(x, y, width, height); 791 792 g.setColor(titleBackgroundGradientEnd.darker()); 793 g.drawOval(x, y, width, width); 794 } 795 } 796 797 /** 798 * Paints controls for the group. 799 * 800 * @param group 801 * Expanded group. 802 * @param g 803 * Target graphics. 804 * @param x 805 * X coordinate of the top left corner. 806 * @param y 807 * Y coordinate of the top left corner. 808 * @param width 809 * Width of the box. 810 * @param height 811 * Height of the box. 812 */ 813 protected void paintChevronControls(JXTaskPane group, Graphics g, 814 int x, int y, int width, int height) { 815 ChevronIcon chevron; 816 if (group.isCollapsed()) { 817 chevron = new ChevronIcon(false); 818 } else { 819 chevron = new ChevronIcon(true); 820 } 821 int chevronX = x + width / 2 - chevron.getIconWidth() / 2; 822 int chevronY = y + (height / 2 - chevron.getIconHeight()); 823 chevron.paintIcon(group, g, chevronX, chevronY); 824 chevron.paintIcon(group, g, chevronX, chevronY 825 + chevron.getIconHeight() + 1); 826 } 827 828 /** 829 * Paints focused group. 830 * 831 * @param g 832 * Target graphics. 833 * @param paintColor 834 * Focused group color. 835 * @param x 836 * X coordinate of the top left corner. 837 * @param y 838 * Y coordinate of the top left corner. 839 * @param width 840 * Width of the box. 841 * @param height 842 * Height of the box. 843 */ 844 protected void paintFocus(Graphics g, Color paintColor, int x, int y, 845 int width, int height) { 846 g.setColor(paintColor); 847 BasicGraphicsUtils.drawDashedRect(g, x, y, width, height); 848 } 849 850 /** 851 * Default implementation returns false. 852 * 853 * @return true if this border wants to display things differently when 854 * the mouse is over it 855 */ 856 protected boolean isMouseOverBorder() { 857 return false; 858 } 859 } 860 861 /** 862 * Gets size of arc used to round corners. 863 * 864 * @return size of arc used to round corners of the panel. 865 */ 866 protected int getRoundHeight() { 867 return roundHeight; 868 } 869 870 }