1 30 31 package com.jgoodies.looks.common; 32 33 import java.awt.*; 34 import java.awt.event.KeyEvent ; 35 36 import javax.swing.*; 37 import javax.swing.plaf.basic.BasicGraphicsUtils ; 38 import javax.swing.plaf.basic.BasicHTML ; 39 import javax.swing.text.View ; 40 41 import com.jgoodies.looks.Options; 42 43 49 50 public final class MenuItemRenderer { 51 52 58 protected static final String HTML_KEY = BasicHTML.propertyKey; 59 60 61 private static final String MAX_TEXT_WIDTH = "maxTextWidth"; 62 private static final String MAX_ACC_WIDTH = "maxAccWidth"; 63 64 private static final Icon NO_ICON = new NullIcon(); 65 66 67 static Rectangle zeroRect = new Rectangle(0,0,0,0); 68 static Rectangle iconRect = new Rectangle(); 69 static Rectangle textRect = new Rectangle(); 70 static Rectangle acceleratorRect= new Rectangle(); 71 static Rectangle checkIconRect = new Rectangle(); 72 static Rectangle arrowIconRect = new Rectangle(); 73 static Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE); 74 static Rectangle r = new Rectangle(); 75 76 77 private final JMenuItem menuItem; 78 private final boolean iconBorderEnabled; private final Font acceleratorFont; 80 private final Color selectionForeground; 81 private final Color disabledForeground; 82 private final Color acceleratorForeground; 83 private final Color acceleratorSelectionForeground; 84 85 private final String acceleratorDelimiter; 86 private final Icon fillerIcon; 87 88 89 90 93 public MenuItemRenderer(JMenuItem menuItem, boolean iconBorderEnabled, 94 Font acceleratorFont, 95 Color selectionForeground, 96 Color disabledForeground, 97 Color acceleratorForeground, 98 Color acceleratorSelectionForeground) { 99 this.menuItem = menuItem; 100 this.iconBorderEnabled = iconBorderEnabled; 101 this.acceleratorFont = acceleratorFont; 102 this.selectionForeground = selectionForeground; 103 this.disabledForeground = disabledForeground; 104 this.acceleratorForeground = acceleratorForeground; 105 this.acceleratorSelectionForeground = acceleratorSelectionForeground; 106 this.acceleratorDelimiter = UIManager.getString("MenuItem.acceleratorDelimiter"); 107 this.fillerIcon = new MinimumSizedIcon(); 108 } 109 110 111 114 private Icon getIcon(JMenuItem aMenuItem, Icon defaultIcon) { 115 Icon icon = aMenuItem.getIcon(); 116 if (icon == null) 117 return defaultIcon; 118 119 ButtonModel model = aMenuItem.getModel(); 120 if (!model.isEnabled()) { 121 return model.isSelected() 122 ? aMenuItem.getDisabledSelectedIcon() 123 : aMenuItem.getDisabledIcon(); 124 } else if (model.isPressed() && model.isArmed()) { 125 Icon pressedIcon = aMenuItem.getPressedIcon(); 126 return pressedIcon != null ? pressedIcon : icon; 127 } else if (model.isSelected()) { 128 Icon selectedIcon = aMenuItem.getSelectedIcon(); 129 return selectedIcon != null ? selectedIcon : icon; 130 } else 131 return icon; 132 } 133 134 135 138 private boolean hasCustomIcon() { 139 return getIcon(menuItem, null) != null; 140 } 141 142 143 146 private Icon getWrappedIcon(Icon icon) { 147 if (hideIcons()) 148 return NO_ICON; 149 if (icon == null) 150 return fillerIcon; 151 return iconBorderEnabled && hasCustomIcon() 152 ? new MinimumSizedCheckIcon(icon, menuItem) 153 : new MinimumSizedIcon(icon); 154 } 155 156 157 private void resetRects() { 158 iconRect.setBounds(zeroRect); 159 textRect.setBounds(zeroRect); 160 acceleratorRect.setBounds(zeroRect); 161 checkIconRect.setBounds(zeroRect); 162 arrowIconRect.setBounds(zeroRect); 163 viewRect.setBounds(0, 0, Short.MAX_VALUE, Short.MAX_VALUE); 164 r.setBounds(zeroRect); 165 } 166 167 168 public Dimension getPreferredMenuItemSize(JComponent c, 169 Icon checkIcon, Icon arrowIcon, int defaultTextIconGap) { 170 171 JMenuItem b = (JMenuItem) c; 172 String text = b.getText(); 173 KeyStroke accelerator = b.getAccelerator(); 174 String acceleratorText = ""; 175 176 if (accelerator != null) { 177 int modifiers = accelerator.getModifiers(); 178 if (modifiers > 0) { 179 acceleratorText = KeyEvent.getKeyModifiersText(modifiers); 180 acceleratorText += acceleratorDelimiter; 181 } 182 int keyCode = accelerator.getKeyCode(); 183 if (keyCode != 0) { 184 acceleratorText += KeyEvent.getKeyText(keyCode); 185 } else { 186 acceleratorText += accelerator.getKeyChar(); 187 } 188 } 189 190 Font font = b.getFont(); 191 FontMetrics fm = b.getFontMetrics(font); 192 FontMetrics fmAccel = b.getFontMetrics(acceleratorFont); 193 194 resetRects(); 195 196 Icon wrappedIcon = getWrappedIcon(getIcon(menuItem, checkIcon)); 197 Icon wrappedArrowIcon = getWrappedIcon(arrowIcon); 198 Icon icon = wrappedIcon.getIconHeight() > fillerIcon.getIconHeight() 199 ? wrappedIcon 200 : null; 201 202 layoutMenuItem(fm, text, fmAccel, acceleratorText, 203 icon, wrappedIcon, 205 wrappedArrowIcon, b.getVerticalAlignment(), b.getHorizontalAlignment(), 207 b.getVerticalTextPosition(), b.getHorizontalTextPosition(), 208 viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect, 209 text == null ? 0 : defaultTextIconGap, 210 defaultTextIconGap); 211 r.setBounds(textRect); 213 r = SwingUtilities.computeUnion(iconRect.x, iconRect.y, iconRect.width, iconRect.height, r); 214 216 219 Container parent = menuItem.getParent(); 221 222 if (parent != null 224 && parent instanceof JComponent 225 && !(menuItem instanceof JMenu && ((JMenu) menuItem).isTopLevelMenu())) { 226 JComponent p = (JComponent) parent; 227 228 Integer maxTextWidth = (Integer ) p.getClientProperty(MAX_TEXT_WIDTH); 230 Integer maxAccWidth = (Integer ) p.getClientProperty(MAX_ACC_WIDTH); 231 232 int maxTextValue = maxTextWidth != null ? maxTextWidth.intValue() : 0; 233 int maxAccValue = maxAccWidth != null ? maxAccWidth.intValue() : 0; 234 235 if (r.width < maxTextValue) { 237 r.width = maxTextValue; 238 } else { 239 p.putClientProperty(MAX_TEXT_WIDTH, new Integer (r.width)); 240 } 241 242 if (acceleratorRect.width > maxAccValue) { 244 maxAccValue = acceleratorRect.width; 245 p.putClientProperty(MAX_ACC_WIDTH, new Integer (acceleratorRect.width)); 246 } 247 248 r.width += maxAccValue; 250 r.width += 10; 251 } 252 253 if (useCheckAndArrow()) { 254 r.width += checkIconRect.width; 256 r.width += defaultTextIconGap; 257 258 r.width += defaultTextIconGap; 260 r.width += arrowIconRect.width; 261 } 262 263 r.width += 2 * defaultTextIconGap; 264 265 Insets insets = b.getInsets(); 266 if (insets != null) { 267 r.width += insets.left + insets.right; 268 r.height += insets.top + insets.bottom; 269 } 270 271 277 278 if(r.height % 2 == 1) { 282 r.height++; 283 } 284 return r.getSize(); 285 } 286 287 288 public void paintMenuItem(Graphics g, JComponent c, 289 Icon checkIcon, Icon arrowIcon, 290 Color background, Color foreground, int defaultTextIconGap) { 291 JMenuItem b = (JMenuItem) c; 292 ButtonModel model = b.getModel(); 293 294 int menuWidth = b.getWidth(); 296 int menuHeight = b.getHeight(); 297 Insets i = c.getInsets(); 298 299 resetRects(); 300 301 viewRect.setBounds(0, 0, menuWidth, menuHeight); 302 303 viewRect.x += i.left; 304 viewRect.y += i.top; 305 viewRect.width -= (i.right + viewRect.x); 306 viewRect.height -= (i.bottom + viewRect.y); 307 308 Font holdf = g.getFont(); 309 Font f = c.getFont(); 310 g.setFont(f); 311 FontMetrics fm = g.getFontMetrics(f); 312 FontMetrics fmAccel = g.getFontMetrics(acceleratorFont); 313 314 KeyStroke accelerator = b.getAccelerator(); 316 String acceleratorText = ""; 317 if (accelerator != null) { 318 int modifiers = accelerator.getModifiers(); 319 if (modifiers > 0) { 320 acceleratorText = KeyEvent.getKeyModifiersText(modifiers); 321 acceleratorText += acceleratorDelimiter; 322 } 323 324 int keyCode = accelerator.getKeyCode(); 325 if (keyCode != 0) { 326 acceleratorText += KeyEvent.getKeyText(keyCode); 327 } else { 328 acceleratorText += accelerator.getKeyChar(); 329 } 330 } 331 332 Icon wrappedIcon = getWrappedIcon(getIcon(menuItem, checkIcon)); 333 Icon wrappedArrowIcon = new MinimumSizedIcon(arrowIcon); 334 335 String text = layoutMenuItem(fm, b.getText(), fmAccel, acceleratorText, 337 null, wrappedIcon, 339 wrappedArrowIcon, b.getVerticalAlignment(), b.getHorizontalAlignment(), 341 b.getVerticalTextPosition(), b.getHorizontalTextPosition(), 342 viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect, 343 b.getText() == null ? 0 : defaultTextIconGap, 344 defaultTextIconGap); 345 346 paintBackground(g, b, background); 348 349 Color holdc = g.getColor(); 351 if (model.isArmed() || (c instanceof JMenu && model.isSelected())) { 352 g.setColor(foreground); 353 } 354 wrappedIcon.paintIcon(c, g, checkIconRect.x, checkIconRect.y); 355 g.setColor(holdc); 356 357 358 if (text != null) { 360 View v = (View ) c.getClientProperty(HTML_KEY); 361 if (v != null) { 362 v.paint(g, textRect); 363 } else { 364 paintText(g, b, textRect, text); 365 } 366 } 367 368 if (acceleratorText != null && !acceleratorText.equals("")) { 370 371 int accOffset = 0; 373 Container parent = menuItem.getParent(); 374 if (parent != null && parent instanceof JComponent) { 375 JComponent p = (JComponent) parent; 376 Integer maxValueInt = (Integer ) p.getClientProperty(MAX_ACC_WIDTH); 377 int maxValue = maxValueInt != null ? maxValueInt.intValue() : acceleratorRect.width; 378 379 accOffset = maxValue - acceleratorRect.width; 381 } 382 383 g.setFont(acceleratorFont); 384 if (!model.isEnabled()) { 385 if (disabledForeground != null) { 387 g.setColor(disabledForeground); 388 BasicGraphicsUtils.drawString(g, acceleratorText, 0, 389 acceleratorRect.x - accOffset, 390 acceleratorRect.y + fmAccel.getAscent()); 391 } else { 392 g.setColor(b.getBackground().brighter()); 393 BasicGraphicsUtils.drawString(g, acceleratorText, 0, 394 acceleratorRect.x - accOffset, 395 acceleratorRect.y + fmAccel.getAscent()); 396 g.setColor(b.getBackground().darker()); 397 BasicGraphicsUtils.drawString(g, acceleratorText, 0, 398 acceleratorRect.x - accOffset - 1, 399 acceleratorRect.y + fmAccel.getAscent() - 1); 400 } 401 } else { 402 if (model.isArmed() || (c instanceof JMenu && model.isSelected())) { 404 g.setColor(acceleratorSelectionForeground); 405 } else { 406 g.setColor(acceleratorForeground); 407 } 408 BasicGraphicsUtils.drawString(g, acceleratorText, 0, 409 acceleratorRect.x - accOffset, 410 acceleratorRect.y + fmAccel.getAscent()); 411 } 412 } 413 414 if (arrowIcon != null) { 416 if (model.isArmed() || (c instanceof JMenu && model.isSelected())) 417 g.setColor(foreground); 418 if (useCheckAndArrow()) 419 wrappedArrowIcon.paintIcon(c, g, arrowIconRect.x, arrowIconRect.y); 420 } 421 g.setColor(holdc); 422 g.setFont(holdf); 423 } 424 425 431 private String layoutMenuItem(FontMetrics fm, String text, 432 FontMetrics fmAccel, String acceleratorText, 433 Icon icon, Icon checkIcon, Icon arrowIcon, 434 int verticalAlignment, int horizontalAlignment, 435 int verticalTextPosition, int horizontalTextPosition, 436 Rectangle viewRectangle, 437 Rectangle iconRectangle, 438 Rectangle textRectangle, 439 Rectangle acceleratorRectangle, 440 Rectangle checkIconRectangle, 441 Rectangle arrowIconRectangle, 442 int textIconGap, 443 int menuItemGap) { 444 445 SwingUtilities.layoutCompoundLabel(menuItem, fm, text, icon, 446 verticalAlignment, horizontalAlignment, 447 verticalTextPosition, horizontalTextPosition, 448 viewRectangle, iconRectangle, textRectangle, textIconGap); 449 450 454 if ((acceleratorText == null) || acceleratorText.equals("")) { 455 acceleratorRectangle.width = acceleratorRectangle.height = 0; 456 acceleratorText = ""; 457 } else { 458 acceleratorRectangle.width = SwingUtilities.computeStringWidth(fmAccel, acceleratorText); 459 acceleratorRectangle.height = fmAccel.getHeight(); 460 } 461 462 boolean useCheckAndArrow = useCheckAndArrow(); 463 464 466 if (useCheckAndArrow) { 467 if (checkIcon != null) { 468 checkIconRectangle.width = checkIcon.getIconWidth(); 469 checkIconRectangle.height = checkIcon.getIconHeight(); 470 } else { 471 checkIconRectangle.width = checkIconRectangle.height = 0; 472 } 473 474 476 if (arrowIcon != null) { 477 arrowIconRectangle.width = arrowIcon.getIconWidth(); 478 arrowIconRectangle.height = arrowIcon.getIconHeight(); 479 } else { 480 arrowIconRectangle.width = arrowIconRectangle.height = 0; 481 } 482 } 483 484 Rectangle labelRect = iconRectangle.union(textRectangle); 485 if (isLeftToRight(menuItem)) { 486 textRectangle.x += menuItemGap; 487 iconRectangle.x += menuItemGap; 488 489 acceleratorRectangle.x = viewRectangle.x 491 + viewRectangle.width 492 - arrowIconRectangle.width 493 - menuItemGap 494 - acceleratorRectangle.width; 495 496 if (useCheckAndArrow) { 498 checkIconRectangle.x = viewRectangle.x; textRectangle.x += menuItemGap + checkIconRectangle.width; 500 iconRectangle.x += menuItemGap + checkIconRectangle.width; 501 arrowIconRectangle.x = viewRectangle.x + viewRectangle.width - menuItemGap - arrowIconRectangle.width; 502 } 503 } else { 504 textRectangle.x -= menuItemGap; 505 iconRectangle.x -= menuItemGap; 506 507 acceleratorRectangle.x = viewRectangle.x + arrowIconRectangle.width + menuItemGap; 509 510 if (useCheckAndArrow) { 512 checkIconRectangle.x = viewRectangle.x + viewRectangle.width - checkIconRectangle.width; 514 textRectangle.x -= menuItemGap + checkIconRectangle.width; 515 iconRectangle.x -= menuItemGap + checkIconRectangle.width; 516 arrowIconRectangle.x = viewRectangle.x + menuItemGap; 517 } 518 } 519 520 acceleratorRectangle.y = labelRect.y + (labelRect.height / 2) - (acceleratorRectangle.height / 2); 523 if (useCheckAndArrow) { 524 arrowIconRectangle.y = labelRect.y + (labelRect.height / 2) - (arrowIconRectangle.height / 2); 525 checkIconRectangle.y = labelRect.y + (labelRect.height / 2) - (checkIconRectangle.height / 2); 526 } 527 528 534 535 return text; 536 } 537 538 542 private boolean useCheckAndArrow() { 543 boolean isTopLevelMenu = menuItem instanceof JMenu && 544 ((JMenu) menuItem).isTopLevelMenu(); 545 return !isTopLevelMenu; 546 } 547 548 549 private boolean isLeftToRight(Component c) { 550 return c.getComponentOrientation().isLeftToRight(); 551 } 552 553 554 556 557 567 public void paintBackground(Graphics g, JMenuItem aMenuItem, Color bgColor) { 568 ButtonModel model = aMenuItem.getModel(); 569 570 if (aMenuItem.isOpaque()) { 571 int menuWidth = aMenuItem.getWidth(); 572 int menuHeight = aMenuItem.getHeight(); 573 Color c = model.isArmed() || 574 (aMenuItem instanceof JMenu && model.isSelected()) 575 ? bgColor 576 : aMenuItem.getBackground(); 577 Color oldColor = g.getColor(); 578 g.setColor(c); 579 g.fillRect(0, 0, menuWidth, menuHeight); 580 g.setColor(oldColor); 581 } 582 } 583 584 585 594 public void paintText(Graphics g, JMenuItem aMenuItem, Rectangle textRectangle, String text) { 595 ButtonModel model = aMenuItem.getModel(); 596 FontMetrics fm = g.getFontMetrics(); 597 int mnemIndex = aMenuItem.getDisplayedMnemonicIndex(); 598 599 if(!model.isEnabled()) { 600 if ( UIManager.get("MenuItem.disabledForeground") instanceof Color ) { 602 g.setColor( UIManager.getColor("MenuItem.disabledForeground") ); 603 BasicGraphicsUtils.drawStringUnderlineCharAt(g,text,mnemIndex, 604 textRectangle.x, 605 textRectangle.y + fm.getAscent()); 606 } else { 607 g.setColor(aMenuItem.getBackground().brighter()); 608 BasicGraphicsUtils.drawStringUnderlineCharAt(g,text,mnemIndex, 609 textRectangle.x, 610 textRectangle.y + fm.getAscent()); 611 g.setColor(aMenuItem.getBackground().darker()); 612 BasicGraphicsUtils.drawStringUnderlineCharAt(g,text,mnemIndex, 613 textRectangle.x - 1, 614 textRectangle.y + fm.getAscent() - 1); 615 } 616 } else { 617 if (model.isArmed()|| (aMenuItem instanceof JMenu && model.isSelected())) { 619 g.setColor(selectionForeground); } 621 BasicGraphicsUtils.drawStringUnderlineCharAt(g,text, mnemIndex, 622 textRectangle.x, 623 textRectangle.y + fm.getAscent()); 624 } 625 } 626 627 628 630 633 private boolean hideIcons() { 634 Component parent = menuItem.getParent(); 635 if (!(parent instanceof JPopupMenu)) { 636 return false; 637 } 638 JPopupMenu popupMenu = (JPopupMenu) parent; 639 Object value = popupMenu.getClientProperty(Options.NO_ICONS_KEY); 640 if (value == null) { 641 Component invoker = popupMenu.getInvoker(); 642 if (invoker != null && invoker instanceof JMenu) 643 value = ((JMenu) invoker).getClientProperty(Options.NO_ICONS_KEY); 644 } 645 return Boolean.TRUE.equals(value); 646 } 647 648 649 private static class NullIcon implements Icon { 651 public int getIconWidth() { return 0; } 652 public int getIconHeight() { return 0; } 653 public void paintIcon(Component c, Graphics g, int x, int y) { 654 } 656 } 657 658 659 660 } | Popular Tags |