1/* 2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.java.swing.plaf.windows; 27 28import javax.swing.*; 29import javax.swing.plaf.ButtonUI; 30import javax.swing.plaf.UIResource; 31 32import java.awt.*; 33import java.io.Serializable; 34 35import static com.sun.java.swing.plaf.windows.TMSchema.*; 36import static com.sun.java.swing.plaf.windows.XPStyle.Skin; 37 38import sun.swing.MenuItemCheckIconFactory; 39import sun.swing.SwingUtilities2; 40 41/** 42 * Factory object that can vend Icons appropriate for the Windows {@literal L & F}. 43 * <p> 44 * <strong>Warning:</strong> 45 * Serialized objects of this class will not be compatible with 46 * future Swing releases. The current serialization support is appropriate 47 * for short term storage or RMI between applications running the same 48 * version of Swing. A future release of Swing will provide support for 49 * long term persistence. 50 * 51 * @author David Kloba 52 * @author Georges Saab 53 * @author Rich Schiavi 54 */ 55@SuppressWarnings("serial") // Same-version serialization only 56public class WindowsIconFactory implements Serializable 57{ 58 private static Icon frame_closeIcon; 59 private static Icon frame_iconifyIcon; 60 private static Icon frame_maxIcon; 61 private static Icon frame_minIcon; 62 private static Icon frame_resizeIcon; 63 private static Icon checkBoxIcon; 64 private static Icon radioButtonIcon; 65 private static Icon checkBoxMenuItemIcon; 66 private static Icon radioButtonMenuItemIcon; 67 private static Icon menuItemCheckIcon; 68 private static Icon menuItemArrowIcon; 69 private static Icon menuArrowIcon; 70 private static VistaMenuItemCheckIconFactory menuItemCheckIconFactory; 71 72 public static Icon getMenuItemCheckIcon() { 73 if (menuItemCheckIcon == null) { 74 menuItemCheckIcon = new MenuItemCheckIcon(); 75 } 76 return menuItemCheckIcon; 77 } 78 79 public static Icon getMenuItemArrowIcon() { 80 if (menuItemArrowIcon == null) { 81 menuItemArrowIcon = new MenuItemArrowIcon(); 82 } 83 return menuItemArrowIcon; 84 } 85 86 public static Icon getMenuArrowIcon() { 87 if (menuArrowIcon == null) { 88 menuArrowIcon = new MenuArrowIcon(); 89 } 90 return menuArrowIcon; 91 } 92 93 public static Icon getCheckBoxIcon() { 94 if (checkBoxIcon == null) { 95 checkBoxIcon = new CheckBoxIcon(); 96 } 97 return checkBoxIcon; 98 } 99 100 public static Icon getRadioButtonIcon() { 101 if (radioButtonIcon == null) { 102 radioButtonIcon = new RadioButtonIcon(); 103 } 104 return radioButtonIcon; 105 } 106 107 public static Icon getCheckBoxMenuItemIcon() { 108 if (checkBoxMenuItemIcon == null) { 109 checkBoxMenuItemIcon = new CheckBoxMenuItemIcon(); 110 } 111 return checkBoxMenuItemIcon; 112 } 113 114 public static Icon getRadioButtonMenuItemIcon() { 115 if (radioButtonMenuItemIcon == null) { 116 radioButtonMenuItemIcon = new RadioButtonMenuItemIcon(); 117 } 118 return radioButtonMenuItemIcon; 119 } 120 121 static 122 synchronized VistaMenuItemCheckIconFactory getMenuItemCheckIconFactory() { 123 if (menuItemCheckIconFactory == null) { 124 menuItemCheckIconFactory = 125 new VistaMenuItemCheckIconFactory(); 126 } 127 return menuItemCheckIconFactory; 128 } 129 130 public static Icon createFrameCloseIcon() { 131 if (frame_closeIcon == null) { 132 frame_closeIcon = new FrameButtonIcon(Part.WP_CLOSEBUTTON); 133 } 134 return frame_closeIcon; 135 } 136 137 public static Icon createFrameIconifyIcon() { 138 if (frame_iconifyIcon == null) { 139 frame_iconifyIcon = new FrameButtonIcon(Part.WP_MINBUTTON); 140 } 141 return frame_iconifyIcon; 142 } 143 144 public static Icon createFrameMaximizeIcon() { 145 if (frame_maxIcon == null) { 146 frame_maxIcon = new FrameButtonIcon(Part.WP_MAXBUTTON); 147 } 148 return frame_maxIcon; 149 } 150 151 public static Icon createFrameMinimizeIcon() { 152 if (frame_minIcon == null) { 153 frame_minIcon = new FrameButtonIcon(Part.WP_RESTOREBUTTON); 154 } 155 return frame_minIcon; 156 } 157 158 public static Icon createFrameResizeIcon() { 159 if(frame_resizeIcon == null) 160 frame_resizeIcon = new ResizeIcon(); 161 return frame_resizeIcon; 162 } 163 164 165 @SuppressWarnings("serial") // Same-version serialization only 166 private static class FrameButtonIcon implements Icon, Serializable { 167 private Part part; 168 169 private FrameButtonIcon(Part part) { 170 this.part = part; 171 } 172 173 public void paintIcon(Component c, Graphics g, int x0, int y0) { 174 int width = getIconWidth(); 175 int height = getIconHeight(); 176 177 XPStyle xp = XPStyle.getXP(); 178 if (xp != null) { 179 Skin skin = xp.getSkin(c, part); 180 AbstractButton b = (AbstractButton)c; 181 ButtonModel model = b.getModel(); 182 183 // Find out if frame is inactive 184 JInternalFrame jif = (JInternalFrame)SwingUtilities. 185 getAncestorOfClass(JInternalFrame.class, b); 186 boolean jifSelected = (jif != null && jif.isSelected()); 187 188 State state; 189 if (jifSelected) { 190 if (!model.isEnabled()) { 191 state = State.DISABLED; 192 } else if (model.isArmed() && model.isPressed()) { 193 state = State.PUSHED; 194 } else if (model.isRollover()) { 195 state = State.HOT; 196 } else { 197 state = State.NORMAL; 198 } 199 } else { 200 if (!model.isEnabled()) { 201 state = State.INACTIVEDISABLED; 202 } else if (model.isArmed() && model.isPressed()) { 203 state = State.INACTIVEPUSHED; 204 } else if (model.isRollover()) { 205 state = State.INACTIVEHOT; 206 } else { 207 state = State.INACTIVENORMAL; 208 } 209 } 210 skin.paintSkin(g, 0, 0, width, height, state); 211 } else { 212 g.setColor(Color.black); 213 int x = width / 12 + 2; 214 int y = height / 5; 215 int h = height - y * 2 - 1; 216 int w = width * 3/4 -3; 217 int thickness2 = Math.max(height / 8, 2); 218 int thickness = Math.max(width / 15, 1); 219 if (part == Part.WP_CLOSEBUTTON) { 220 int lineWidth; 221 if (width > 47) lineWidth = 6; 222 else if (width > 37) lineWidth = 5; 223 else if (width > 26) lineWidth = 4; 224 else if (width > 16) lineWidth = 3; 225 else if (width > 12) lineWidth = 2; 226 else lineWidth = 1; 227 y = height / 12 + 2; 228 if (lineWidth == 1) { 229 if (w % 2 == 1) { x++; w++; } 230 g.drawLine(x, y, x+w-2, y+w-2); 231 g.drawLine(x+w-2, y, x, y+w-2); 232 } else if (lineWidth == 2) { 233 if (w > 6) { x++; w--; } 234 g.drawLine(x, y, x+w-2, y+w-2); 235 g.drawLine(x+w-2, y, x, y+w-2); 236 g.drawLine(x+1, y, x+w-1, y+w-2); 237 g.drawLine(x+w-1, y, x+1, y+w-2); 238 } else { 239 x += 2; y++; w -= 2; 240 g.drawLine(x, y, x+w-1, y+w-1); 241 g.drawLine(x+w-1, y, x, y+w-1); 242 g.drawLine(x+1, y, x+w-1, y+w-2); 243 g.drawLine(x+w-2, y, x, y+w-2); 244 g.drawLine(x, y+1, x+w-2, y+w-1); 245 g.drawLine(x+w-1, y+1, x+1, y+w-1); 246 for (int i = 4; i <= lineWidth; i++) { 247 g.drawLine(x+i-2, y, x+w-1, y+w-i+1); 248 g.drawLine(x, y+i-2, x+w-i+1, y+w-1); 249 g.drawLine(x+w-i+1, y, x, y+w-i+1); 250 g.drawLine(x+w-1, y+i-2, x+i-2, y+w-1); 251 } 252 } 253 } else if (part == Part.WP_MINBUTTON) { 254 g.fillRect(x, y+h-thickness2, w-w/3, thickness2); 255 } else if (part == Part.WP_MAXBUTTON) { 256 g.fillRect(x, y, w, thickness2); 257 g.fillRect(x, y, thickness, h); 258 g.fillRect(x+w-thickness, y, thickness, h); 259 g.fillRect(x, y+h-thickness, w, thickness); 260 } else if (part == Part.WP_RESTOREBUTTON) { 261 g.fillRect(x+w/3, y, w-w/3, thickness2); 262 g.fillRect(x+w/3, y, thickness, h/3); 263 g.fillRect(x+w-thickness, y, thickness, h-h/3); 264 g.fillRect(x+w-w/3, y+h-h/3-thickness, w/3, thickness); 265 266 g.fillRect(x, y+h/3, w-w/3, thickness2); 267 g.fillRect(x, y+h/3, thickness, h-h/3); 268 g.fillRect(x+w-w/3-thickness, y+h/3, thickness, h-h/3); 269 g.fillRect(x, y+h-thickness, w-w/3, thickness); 270 } 271 } 272 } 273 274 public int getIconWidth() { 275 int width; 276 if (XPStyle.getXP() != null) { 277 // Fix for XP bug where sometimes these sizes aren't updated properly 278 // Assume for now that height is correct and derive width using the 279 // ratio from the uxtheme part 280 width = UIManager.getInt("InternalFrame.titleButtonHeight") -2; 281 Dimension d = XPStyle.getPartSize(Part.WP_CLOSEBUTTON, State.NORMAL); 282 if (d != null && d.width != 0 && d.height != 0) { 283 width = (int) ((float) width * d.width / d.height); 284 } 285 } else { 286 width = UIManager.getInt("InternalFrame.titleButtonWidth") -2; 287 } 288 if (XPStyle.getXP() != null) { 289 width -= 2; 290 } 291 return width; 292 } 293 294 public int getIconHeight() { 295 int height = UIManager.getInt("InternalFrame.titleButtonHeight")-4; 296 return height; 297 } 298 } 299 300 301 302 @SuppressWarnings("serial") // Same-version serialization only 303 private static class ResizeIcon implements Icon, Serializable { 304 public void paintIcon(Component c, Graphics g, int x, int y) { 305 g.setColor(UIManager.getColor("InternalFrame.resizeIconHighlight")); 306 g.drawLine(0, 11, 11, 0); 307 g.drawLine(4, 11, 11, 4); 308 g.drawLine(8, 11, 11, 8); 309 310 g.setColor(UIManager.getColor("InternalFrame.resizeIconShadow")); 311 g.drawLine(1, 11, 11, 1); 312 g.drawLine(2, 11, 11, 2); 313 g.drawLine(5, 11, 11, 5); 314 g.drawLine(6, 11, 11, 6); 315 g.drawLine(9, 11, 11, 9); 316 g.drawLine(10, 11, 11, 10); 317 } 318 public int getIconWidth() { return 13; } 319 public int getIconHeight() { return 13; } 320 }; 321 322 @SuppressWarnings("serial") // Same-version serialization only 323 private static class CheckBoxIcon implements Icon, Serializable 324 { 325 static final int csize = 13; 326 public void paintIcon(Component c, Graphics g, int x, int y) { 327 JCheckBox cb = (JCheckBox) c; 328 ButtonModel model = cb.getModel(); 329 XPStyle xp = XPStyle.getXP(); 330 331 if (xp != null) { 332 State state; 333 if (model.isSelected()) { 334 state = State.CHECKEDNORMAL; 335 if (!model.isEnabled()) { 336 state = State.CHECKEDDISABLED; 337 } else if (model.isPressed() && model.isArmed()) { 338 state = State.CHECKEDPRESSED; 339 } else if (model.isRollover()) { 340 state = State.CHECKEDHOT; 341 } 342 } else { 343 state = State.UNCHECKEDNORMAL; 344 if (!model.isEnabled()) { 345 state = State.UNCHECKEDDISABLED; 346 } else if (model.isPressed() && model.isArmed()) { 347 state = State.UNCHECKEDPRESSED; 348 } else if (model.isRollover()) { 349 state = State.UNCHECKEDHOT; 350 } 351 } 352 Part part = Part.BP_CHECKBOX; 353 xp.getSkin(c, part).paintSkin(g, x, y, state); 354 } else { 355 // outer bevel 356 if(!cb.isBorderPaintedFlat()) { 357 // Outer top/left 358 g.setColor(UIManager.getColor("CheckBox.shadow")); 359 g.drawLine(x, y, x+11, y); 360 g.drawLine(x, y+1, x, y+11); 361 362 // Outer bottom/right 363 g.setColor(UIManager.getColor("CheckBox.highlight")); 364 g.drawLine(x+12, y, x+12, y+12); 365 g.drawLine(x, y+12, x+11, y+12); 366 367 // Inner top.left 368 g.setColor(UIManager.getColor("CheckBox.darkShadow")); 369 g.drawLine(x+1, y+1, x+10, y+1); 370 g.drawLine(x+1, y+2, x+1, y+10); 371 372 // Inner bottom/right 373 g.setColor(UIManager.getColor("CheckBox.light")); 374 g.drawLine(x+1, y+11, x+11, y+11); 375 g.drawLine(x+11, y+1, x+11, y+10); 376 377 // inside box 378 if((model.isPressed() && model.isArmed()) || !model.isEnabled()) { 379 g.setColor(UIManager.getColor("CheckBox.background")); 380 } else { 381 g.setColor(UIManager.getColor("CheckBox.interiorBackground")); 382 } 383 g.fillRect(x+2, y+2, csize-4, csize-4); 384 } else { 385 g.setColor(UIManager.getColor("CheckBox.shadow")); 386 g.drawRect(x+1, y+1, csize-3, csize-3); 387 388 if((model.isPressed() && model.isArmed()) || !model.isEnabled()) { 389 g.setColor(UIManager.getColor("CheckBox.background")); 390 } else { 391 g.setColor(UIManager.getColor("CheckBox.interiorBackground")); 392 } 393 g.fillRect(x+2, y+2, csize-4, csize-4); 394 } 395 396 if(model.isEnabled()) { 397 g.setColor(UIManager.getColor("CheckBox.foreground")); 398 } else { 399 g.setColor(UIManager.getColor("CheckBox.shadow")); 400 } 401 402 // paint check 403 if (model.isSelected()) { 404 if (SwingUtilities2.isScaledGraphics(g)) { 405 int[] xPoints = {3, 5, 9, 9, 5, 3}; 406 int[] yPoints = {5, 7, 3, 5, 9, 7}; 407 g.translate(x, y); 408 g.fillPolygon(xPoints, yPoints, 6); 409 g.drawPolygon(xPoints, yPoints, 6); 410 g.translate(-x, -y); 411 } else { 412 g.drawLine(x + 9, y + 3, x + 9, y + 3); 413 g.drawLine(x + 8, y + 4, x + 9, y + 4); 414 g.drawLine(x + 7, y + 5, x + 9, y + 5); 415 g.drawLine(x + 6, y + 6, x + 8, y + 6); 416 g.drawLine(x + 3, y + 7, x + 7, y + 7); 417 g.drawLine(x + 4, y + 8, x + 6, y + 8); 418 g.drawLine(x + 5, y + 9, x + 5, y + 9); 419 g.drawLine(x + 3, y + 5, x + 3, y + 5); 420 g.drawLine(x + 3, y + 6, x + 4, y + 6); 421 } 422 } 423 } 424 } 425 426 public int getIconWidth() { 427 XPStyle xp = XPStyle.getXP(); 428 if (xp != null) { 429 return xp.getSkin(null, Part.BP_CHECKBOX).getWidth(); 430 } else { 431 return csize; 432 } 433 } 434 435 public int getIconHeight() { 436 XPStyle xp = XPStyle.getXP(); 437 if (xp != null) { 438 return xp.getSkin(null, Part.BP_CHECKBOX).getHeight(); 439 } else { 440 return csize; 441 } 442 } 443 } 444 445 @SuppressWarnings("serial") // Same-version serialization only 446 private static class RadioButtonIcon implements Icon, UIResource, Serializable 447 { 448 public void paintIcon(Component c, Graphics g, int x, int y) { 449 AbstractButton b = (AbstractButton) c; 450 ButtonModel model = b.getModel(); 451 XPStyle xp = XPStyle.getXP(); 452 453 if (xp != null) { 454 Part part = Part.BP_RADIOBUTTON; 455 Skin skin = xp.getSkin(b, part); 456 State state; 457 int index = 0; 458 if (model.isSelected()) { 459 state = State.CHECKEDNORMAL; 460 if (!model.isEnabled()) { 461 state = State.CHECKEDDISABLED; 462 } else if (model.isPressed() && model.isArmed()) { 463 state = State.CHECKEDPRESSED; 464 } else if (model.isRollover()) { 465 state = State.CHECKEDHOT; 466 } 467 } else { 468 state = State.UNCHECKEDNORMAL; 469 if (!model.isEnabled()) { 470 state = State.UNCHECKEDDISABLED; 471 } else if (model.isPressed() && model.isArmed()) { 472 state = State.UNCHECKEDPRESSED; 473 } else if (model.isRollover()) { 474 state = State.UNCHECKEDHOT; 475 } 476 } 477 skin.paintSkin(g, x, y, state); 478 } else { 479 // fill interior 480 if((model.isPressed() && model.isArmed()) || !model.isEnabled()) { 481 g.setColor(UIManager.getColor("RadioButton.background")); 482 } else { 483 g.setColor(UIManager.getColor("RadioButton.interiorBackground")); 484 } 485 g.fillRect(x+2, y+2, 8, 8); 486 487 488 boolean isScaledGraphics = SwingUtilities2.isScaledGraphics(g); 489 490 if (isScaledGraphics) { 491 492 Graphics2D g2d = (Graphics2D) g; 493 Stroke oldStroke = g2d.getStroke(); 494 g2d.setStroke(new BasicStroke(1.03f, BasicStroke.CAP_ROUND, 495 BasicStroke.JOIN_ROUND)); 496 Object aaHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING); 497 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 498 RenderingHints.VALUE_ANTIALIAS_ON); 499 500 // outter left arc 501 g.setColor(UIManager.getColor("RadioButton.shadow")); 502 g.drawArc(x, y, 11, 11, 45, 180); 503 // outter right arc 504 g.setColor(UIManager.getColor("RadioButton.highlight")); 505 g.drawArc(x, y, 11, 11, 45, -180); 506 // inner left arc 507 g.setColor(UIManager.getColor("RadioButton.darkShadow")); 508 g.drawArc(x + 1, y + 1, 9, 9, 45, 180); 509 // inner right arc 510 g.setColor(UIManager.getColor("RadioButton.light")); 511 g.drawArc(x + 1, y + 1, 9, 9, 45, -180); 512 513 g2d.setStroke(oldStroke); 514 515 if (model.isSelected()) { 516 if (model.isEnabled()) { 517 g.setColor(UIManager.getColor("RadioButton.foreground")); 518 } else { 519 g.setColor(UIManager.getColor("RadioButton.shadow")); 520 } 521 g.fillOval(x + 3, y + 3, 5, 5); 522 } 523 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aaHint); 524 525 } else { 526 527 // outter left arc 528 g.setColor(UIManager.getColor("RadioButton.shadow")); 529 g.drawLine(x+4, y+0, x+7, y+0); 530 g.drawLine(x+2, y+1, x+3, y+1); 531 g.drawLine(x+8, y+1, x+9, y+1); 532 g.drawLine(x+1, y+2, x+1, y+3); 533 g.drawLine(x+0, y+4, x+0, y+7); 534 g.drawLine(x+1, y+8, x+1, y+9); 535 536 // outter right arc 537 g.setColor(UIManager.getColor("RadioButton.highlight")); 538 g.drawLine(x+2, y+10, x+3, y+10); 539 g.drawLine(x+4, y+11, x+7, y+11); 540 g.drawLine(x+8, y+10, x+9, y+10); 541 g.drawLine(x+10, y+9, x+10, y+8); 542 g.drawLine(x+11, y+7, x+11, y+4); 543 g.drawLine(x+10, y+3, x+10, y+2); 544 545 546 // inner left arc 547 g.setColor(UIManager.getColor("RadioButton.darkShadow")); 548 g.drawLine(x+4, y+1, x+7, y+1); 549 g.drawLine(x+2, y+2, x+3, y+2); 550 g.drawLine(x+8, y+2, x+9, y+2); 551 g.drawLine(x+2, y+3, x+2, y+3); 552 g.drawLine(x+1, y+4, x+1, y+7); 553 g.drawLine(x+2, y+8, x+2, y+8); 554 555 556 // inner right arc 557 g.setColor(UIManager.getColor("RadioButton.light")); 558 g.drawLine(x+2, y+9, x+3, y+9); 559 g.drawLine(x+4, y+10, x+7, y+10); 560 g.drawLine(x+8, y+9, x+9, y+9); 561 g.drawLine(x+9, y+8, x+9, y+8); 562 g.drawLine(x+10, y+7, x+10, y+4); 563 g.drawLine(x+9, y+3, x+9, y+3); 564 565 566 // indicate whether selected or not 567 if (model.isSelected()) { 568 if (model.isEnabled()) { 569 g.setColor(UIManager.getColor("RadioButton.foreground")); 570 } else { 571 g.setColor(UIManager.getColor("RadioButton.shadow")); 572 } 573 g.fillRect(x+4, y+5, 4, 2); 574 g.fillRect(x+5, y+4, 2, 4); 575 } 576 } 577 } 578 } 579 580 public int getIconWidth() { 581 XPStyle xp = XPStyle.getXP(); 582 if (xp != null) { 583 return xp.getSkin(null, Part.BP_RADIOBUTTON).getWidth(); 584 } else { 585 return 13; 586 } 587 } 588 589 public int getIconHeight() { 590 XPStyle xp = XPStyle.getXP(); 591 if (xp != null) { 592 return xp.getSkin(null, Part.BP_RADIOBUTTON).getHeight(); 593 } else { 594 return 13; 595 } 596 } 597 } // end class RadioButtonIcon 598 599 600 @SuppressWarnings("serial") // Same-version serialization only 601 private static class CheckBoxMenuItemIcon implements Icon, UIResource, Serializable 602 { 603 public void paintIcon(Component c, Graphics g, int x, int y) { 604 AbstractButton b = (AbstractButton) c; 605 ButtonModel model = b.getModel(); 606 boolean isSelected = model.isSelected(); 607 if (isSelected) { 608 y = y - getIconHeight() / 2; 609 g.drawLine(x+9, y+3, x+9, y+3); 610 g.drawLine(x+8, y+4, x+9, y+4); 611 g.drawLine(x+7, y+5, x+9, y+5); 612 g.drawLine(x+6, y+6, x+8, y+6); 613 g.drawLine(x+3, y+7, x+7, y+7); 614 g.drawLine(x+4, y+8, x+6, y+8); 615 g.drawLine(x+5, y+9, x+5, y+9); 616 g.drawLine(x+3, y+5, x+3, y+5); 617 g.drawLine(x+3, y+6, x+4, y+6); 618 } 619 } 620 public int getIconWidth() { return 9; } 621 public int getIconHeight() { return 9; } 622 623 } // End class CheckBoxMenuItemIcon 624 625 626 @SuppressWarnings("serial") // Same-version serialization only 627 private static class RadioButtonMenuItemIcon implements Icon, UIResource, Serializable 628 { 629 public void paintIcon(Component c, Graphics g, int x, int y) { 630 AbstractButton b = (AbstractButton) c; 631 ButtonModel model = b.getModel(); 632 if (b.isSelected() == true) { 633 g.fillRoundRect(x+3,y+3, getIconWidth()-6, getIconHeight()-6, 634 4, 4); 635 } 636 } 637 public int getIconWidth() { return 12; } 638 public int getIconHeight() { return 12; } 639 640 } // End class RadioButtonMenuItemIcon 641 642 643 @SuppressWarnings("serial") // Same-version serialization only 644 private static class MenuItemCheckIcon implements Icon, UIResource, Serializable{ 645 public void paintIcon(Component c, Graphics g, int x, int y) { 646 /* For debugging: 647 Color oldColor = g.getColor(); 648 g.setColor(Color.orange); 649 g.fill3DRect(x,y,getIconWidth(), getIconHeight(), true); 650 g.setColor(oldColor); 651 */ 652 } 653 public int getIconWidth() { return 9; } 654 public int getIconHeight() { return 9; } 655 656 } // End class MenuItemCheckIcon 657 658 @SuppressWarnings("serial") // Same-version serialization only 659 private static class MenuItemArrowIcon implements Icon, UIResource, Serializable { 660 public void paintIcon(Component c, Graphics g, int x, int y) { 661 /* For debugging: 662 Color oldColor = g.getColor(); 663 g.setColor(Color.green); 664 g.fill3DRect(x,y,getIconWidth(), getIconHeight(), true); 665 g.setColor(oldColor); 666 */ 667 } 668 public int getIconWidth() { return 4; } 669 public int getIconHeight() { return 8; } 670 671 } // End class MenuItemArrowIcon 672 673 @SuppressWarnings("serial") // Same-version serialization only 674 private static class MenuArrowIcon implements Icon, UIResource, Serializable { 675 public void paintIcon(Component c, Graphics g, int x, int y) { 676 XPStyle xp = XPStyle.getXP(); 677 if (WindowsMenuItemUI.isVistaPainting(xp)) { 678 State state = State.NORMAL; 679 if (c instanceof JMenuItem) { 680 state = ((JMenuItem) c).getModel().isEnabled() 681 ? State.NORMAL : State.DISABLED; 682 } 683 Skin skin = xp.getSkin(c, Part.MP_POPUPSUBMENU); 684 if (WindowsGraphicsUtils.isLeftToRight(c)) { 685 skin.paintSkin(g, x, y, state); 686 } else { 687 Graphics2D g2d = (Graphics2D)g.create(); 688 g2d.translate(x + skin.getWidth(), y); 689 g2d.scale(-1, 1); 690 skin.paintSkin(g2d, 0, 0, state); 691 g2d.dispose(); 692 } 693 } else { 694 g.translate(x,y); 695 if( WindowsGraphicsUtils.isLeftToRight(c) ) { 696 g.drawLine( 0, 0, 0, 7 ); 697 g.drawLine( 1, 1, 1, 6 ); 698 g.drawLine( 2, 2, 2, 5 ); 699 g.drawLine( 3, 3, 3, 4 ); 700 } else { 701 g.drawLine( 4, 0, 4, 7 ); 702 g.drawLine( 3, 1, 3, 6 ); 703 g.drawLine( 2, 2, 2, 5 ); 704 g.drawLine( 1, 3, 1, 4 ); 705 } 706 g.translate(-x,-y); 707 } 708 } 709 public int getIconWidth() { 710 XPStyle xp = XPStyle.getXP(); 711 if (WindowsMenuItemUI.isVistaPainting(xp)) { 712 Skin skin = xp.getSkin(null, Part.MP_POPUPSUBMENU); 713 return skin.getWidth(); 714 } else { 715 return 4; 716 } 717 } 718 public int getIconHeight() { 719 XPStyle xp = XPStyle.getXP(); 720 if (WindowsMenuItemUI.isVistaPainting(xp)) { 721 Skin skin = xp.getSkin(null, Part.MP_POPUPSUBMENU); 722 return skin.getHeight(); 723 } else { 724 return 8; 725 } 726 } 727 } // End class MenuArrowIcon 728 729 static class VistaMenuItemCheckIconFactory 730 implements MenuItemCheckIconFactory { 731 private static final int OFFSET = 3; 732 733 public Icon getIcon(JMenuItem component) { 734 return new VistaMenuItemCheckIcon(component); 735 } 736 737 public boolean isCompatible(Object icon, String prefix) { 738 return icon instanceof VistaMenuItemCheckIcon 739 && ((VistaMenuItemCheckIcon) icon).type == getType(prefix); 740 } 741 742 public Icon getIcon(String type) { 743 return new VistaMenuItemCheckIcon(type); 744 } 745 746 static int getIconWidth() { 747 XPStyle xp = XPStyle.getXP(); 748 return ((xp != null) ? xp.getSkin(null, Part.MP_POPUPCHECK).getWidth() : 16) 749 + 2 * OFFSET; 750 } 751 752 private static Class<? extends JMenuItem> getType(Component c) { 753 Class<? extends JMenuItem> rv = null; 754 if (c instanceof JCheckBoxMenuItem) { 755 rv = JCheckBoxMenuItem.class; 756 } else if (c instanceof JRadioButtonMenuItem) { 757 rv = JRadioButtonMenuItem.class; 758 } else if (c instanceof JMenu) { 759 rv = JMenu.class; 760 } else if (c instanceof JMenuItem) { 761 rv = JMenuItem.class; 762 } 763 return rv; 764 } 765 766 private static Class<? extends JMenuItem> getType(String type) { 767 Class<? extends JMenuItem> rv = null; 768 if (type == "CheckBoxMenuItem") { 769 rv = JCheckBoxMenuItem.class; 770 } else if (type == "RadioButtonMenuItem") { 771 rv = JRadioButtonMenuItem.class; 772 } else if (type == "Menu") { 773 rv = JMenu.class; 774 } else if (type == "MenuItem") { 775 rv = JMenuItem.class; 776 } else { 777 // this should never happen 778 rv = JMenuItem.class; 779 } 780 return rv; 781 } 782 783 /** 784 * CheckIcon for JMenuItem, JMenu, JCheckBoxMenuItem and 785 * JRadioButtonMenuItem. 786 * Note: to be used on Vista only. 787 */ 788 @SuppressWarnings("serial") // Same-version serialization only 789 private static class VistaMenuItemCheckIcon 790 implements Icon, UIResource, Serializable { 791 792 private final JMenuItem menuItem; 793 private final Class<? extends JMenuItem> type; 794 795 VistaMenuItemCheckIcon(JMenuItem menuItem) { 796 this.type = getType(menuItem); 797 this.menuItem = menuItem; 798 } 799 VistaMenuItemCheckIcon(String type) { 800 this.type = getType(type); 801 this.menuItem = null; 802 } 803 804 public int getIconHeight() { 805 Icon lafIcon = getLaFIcon(); 806 if (lafIcon != null) { 807 return lafIcon.getIconHeight(); 808 } 809 Icon icon = getIcon(); 810 int height = 0; 811 if (icon != null) { 812 height = icon.getIconHeight(); 813 } else { 814 XPStyle xp = XPStyle.getXP(); 815 if (xp != null) { 816 Skin skin = xp.getSkin(null, Part.MP_POPUPCHECK); 817 height = skin.getHeight(); 818 } else { 819 height = 16; 820 } 821 } 822 height += 2 * OFFSET; 823 return height; 824 } 825 826 public int getIconWidth() { 827 Icon lafIcon = getLaFIcon(); 828 if (lafIcon != null) { 829 return lafIcon.getIconWidth(); 830 } 831 Icon icon = getIcon(); 832 int width = 0; 833 if (icon != null) { 834 width = icon.getIconWidth() + 2 * OFFSET; 835 } else { 836 width = VistaMenuItemCheckIconFactory.getIconWidth(); 837 } 838 return width; 839 } 840 841 public void paintIcon(Component c, Graphics g, int x, int y) { 842 Icon lafIcon = getLaFIcon(); 843 if (lafIcon != null) { 844 lafIcon.paintIcon(c, g, x, y); 845 return; 846 } 847 assert menuItem == null || c == menuItem; 848 Icon icon = getIcon(); 849 if (type == JCheckBoxMenuItem.class 850 || type == JRadioButtonMenuItem.class) { 851 AbstractButton b = (AbstractButton) c; 852 if (b.isSelected()) { 853 Part backgroundPart = Part.MP_POPUPCHECKBACKGROUND; 854 Part part = Part.MP_POPUPCHECK; 855 State backgroundState; 856 State state; 857 if (isEnabled(c, null)) { 858 backgroundState = 859 (icon != null) ? State.BITMAP : State.NORMAL; 860 state = (type == JRadioButtonMenuItem.class) 861 ? State.BULLETNORMAL 862 : State.CHECKMARKNORMAL; 863 } else { 864 backgroundState = State.DISABLEDPUSHED; 865 state = 866 (type == JRadioButtonMenuItem.class) 867 ? State.BULLETDISABLED 868 : State.CHECKMARKDISABLED; 869 } 870 XPStyle xp = XPStyle.getXP(); 871 if (xp != null) { 872 Skin skin; 873 skin = xp.getSkin(c, backgroundPart); 874 skin.paintSkin(g, x, y, 875 getIconWidth(), getIconHeight(), backgroundState); 876 if (icon == null) { 877 skin = xp.getSkin(c, part); 878 skin.paintSkin(g, x + OFFSET, y + OFFSET, state); 879 } 880 } 881 } 882 } 883 if (icon != null) { 884 icon.paintIcon(c, g, x + OFFSET, y + OFFSET); 885 } 886 } 887 private static WindowsMenuItemUIAccessor getAccessor( 888 JMenuItem menuItem) { 889 WindowsMenuItemUIAccessor rv = null; 890 ButtonUI uiObject = (menuItem != null) ? menuItem.getUI() 891 : null; 892 if (uiObject instanceof WindowsMenuItemUI) { 893 rv = ((WindowsMenuItemUI) uiObject).accessor; 894 } else if (uiObject instanceof WindowsMenuUI) { 895 rv = ((WindowsMenuUI) uiObject).accessor; 896 } else if (uiObject instanceof WindowsCheckBoxMenuItemUI) { 897 rv = ((WindowsCheckBoxMenuItemUI) uiObject).accessor; 898 } else if (uiObject instanceof WindowsRadioButtonMenuItemUI) { 899 rv = ((WindowsRadioButtonMenuItemUI) uiObject).accessor; 900 } 901 return rv; 902 } 903 904 private static boolean isEnabled(Component c, State state) { 905 if (state == null && c instanceof JMenuItem) { 906 WindowsMenuItemUIAccessor accessor = 907 getAccessor((JMenuItem) c); 908 if (accessor != null) { 909 state = accessor.getState((JMenuItem) c); 910 } 911 } 912 if (state == null) { 913 if (c != null) { 914 return c.isEnabled(); 915 } else { 916 return true; 917 } 918 } else { 919 return (state != State.DISABLED) 920 && (state != State.DISABLEDHOT) 921 && (state != State.DISABLEDPUSHED); 922 } 923 } 924 private Icon getIcon() { 925 Icon rv = null; 926 if (menuItem == null) { 927 return rv; 928 } 929 WindowsMenuItemUIAccessor accessor = 930 getAccessor(menuItem); 931 State state = (accessor != null) ? accessor.getState(menuItem) 932 : null; 933 if (isEnabled(menuItem, null)) { 934 if (state == State.PUSHED) { 935 rv = menuItem.getPressedIcon(); 936 } else { 937 rv = menuItem.getIcon(); 938 } 939 } else { 940 rv = menuItem.getDisabledIcon(); 941 } 942 return rv; 943 } 944 /** 945 * Check if developer changed icon in the UI table. 946 * 947 * @return the icon to use or {@code null} if the current one is to 948 * be used 949 */ 950 private Icon getLaFIcon() { 951 // use icon from the UI table if it does not match this one. 952 Icon rv = (Icon) UIManager.getDefaults().get(typeToString(type)); 953 if (rv instanceof VistaMenuItemCheckIcon 954 && ((VistaMenuItemCheckIcon) rv).type == type) { 955 rv = null; 956 } 957 return rv; 958 } 959 960 private static String typeToString( 961 Class<? extends JMenuItem> type) { 962 assert type == JMenuItem.class 963 || type == JMenu.class 964 || type == JCheckBoxMenuItem.class 965 || type == JRadioButtonMenuItem.class; 966 StringBuilder sb = new StringBuilder(type.getName()); 967 // remove package name, dot and the first character 968 sb.delete(0, sb.lastIndexOf("J") + 1); 969 sb.append(".checkIcon"); 970 return sb.toString(); 971 } 972 } 973 } // End class VistaMenuItemCheckIconFactory 974} 975