1 /* 2 * Copyright (c) 2011, 2012, 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 26 package com.apple.laf; 27 28 import java.awt.*; 29 import java.awt.image.BufferedImage; 30 import java.io.File; 31 32 import javax.swing.*; 33 import javax.swing.plaf.*; 34 35 import apple.laf.JRSUIConstants.Size; 36 import apple.laf.*; 37 38 import com.apple.laf.AquaUtilControlSize.*; 39 import com.apple.laf.AquaUtils.RecyclableSingleton; 40 41 public class AquaIcon { 42 interface InvertableIcon extends Icon { 43 public Icon getInvertedIcon(); 44 } 45 46 static UIResource getIconFor(final JRSUIControlSpec spec, final int width, final int height) { 47 return new CachableJRSUIIcon(width, height) { 48 public void initIconPainter(final AquaPainter<JRSUIState> painter) { 49 spec.initIconPainter(painter); 50 } 51 }; 52 } 53 54 // converts an object that is an icon into an image so we can hand it off to AppKit 55 public static Image getImageForIcon(final Icon i) { 56 if (i instanceof ImageIcon) return ((ImageIcon)i).getImage(); 57 58 final int w = i.getIconWidth(); 59 final int h = i.getIconHeight(); 60 61 if (w <= 0 || h <= 0) return null; 62 63 // This could be any kind of icon, so we need to make a buffer for it, draw it and then pass the new image off to appkit. 64 final BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 65 final Graphics g = image.getGraphics(); 66 i.paintIcon(null, g, 0, 0); 67 g.dispose(); 68 return image; 69 } 70 71 public interface JRSUIControlSpec { 72 public void initIconPainter(final AquaPainter<? extends JRSUIState> painter); 73 } 74 75 static abstract class JRSUIIcon implements Icon, UIResource { 76 protected final AquaPainter<JRSUIState> painter = AquaPainter.create(JRSUIState.getInstance()); 77 78 public void paintIcon(final Component c, final Graphics g, final int x, final int y) { 79 painter.paint(g, c, x, y, getIconWidth(), getIconHeight()); 80 } 81 } 82 83 static abstract class DynamicallySizingJRSUIIcon extends JRSUIIcon { 84 protected final SizeDescriptor sizeDescriptor; 85 protected SizeVariant sizeVariant; 86 87 public DynamicallySizingJRSUIIcon(final SizeDescriptor sizeDescriptor) { 88 this.sizeDescriptor = sizeDescriptor; 89 this.sizeVariant = sizeDescriptor.regular; 90 initJRSUIState(); 91 } 92 93 public abstract void initJRSUIState(); 94 95 public int getIconHeight() { 96 return sizeVariant == null ? 0 : sizeVariant.h; 97 } 98 99 public int getIconWidth() { 100 return sizeVariant == null ? 0 : sizeVariant.w; 101 } 102 103 public void paintIcon(final Component c, final Graphics g, final int x, final int y) { 104 final Size size = c instanceof JComponent ? AquaUtilControlSize.getUserSizeFrom((JComponent)c) : Size.REGULAR; 105 sizeVariant = sizeDescriptor.get(size); 106 painter.state.set(size); 107 super.paintIcon(c, g, x, y); 108 } 109 } 110 111 static abstract class CachingScalingIcon implements Icon, UIResource { 112 int width; 113 int height; 114 Image image; 115 116 public CachingScalingIcon(final int width, final int height) { 117 this.width = width; 118 this.height = height; 119 } 120 121 void setSize(final int width, final int height) { 122 this.width = width; 123 this.height = height; 124 this.image = null; 125 } 126 127 Image getImage() { 128 if (image != null) return image; 129 130 if (!GraphicsEnvironment.isHeadless()) { 131 image = getOptimizedImage(); 132 } 133 134 return image; 135 } 136 137 private Image getOptimizedImage() { 138 final Image img = createImage(); 139 // TODO: no RuntimeOptions for now 140 //if (RuntimeOptions.getRenderer(null) != RuntimeOptions.Sun) return img; 141 return getProgressiveOptimizedImage(img, getIconWidth(), getIconHeight()); 142 } 143 144 static Image getProgressiveOptimizedImage(final Image img, final int w, final int h) { 145 if (img == null) return null; 146 147 final int halfImgW = img.getWidth(null) / 2; 148 final int halfImgH = img.getHeight(null) / 2; 149 if (w * 2 > halfImgW && h * 2 > halfImgH) return img; 150 151 final BufferedImage halfImage = new BufferedImage(halfImgW, halfImgH, BufferedImage.TYPE_INT_ARGB); 152 final Graphics g = halfImage.getGraphics(); 153 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 154 g.drawImage(img, 0, 0, halfImgW, halfImgH, null); 155 g.dispose(); 156 157 return getProgressiveOptimizedImage(halfImage, w, h); 158 } 159 160 abstract Image createImage(); 161 162 public boolean hasIconRef() { 163 return getImage() != null; 164 } 165 166 public void paintIcon(final Component c, Graphics g, final int x, final int y) { 167 g = g.create(); 168 169 if (g instanceof Graphics2D) { 170 // improves icon rendering quality in Quartz 171 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 172 } 173 174 final Image myImage = getImage(); 175 if (myImage != null) { 176 g.drawImage(myImage, x, y, getIconWidth(), getIconHeight(), null); 177 } 178 179 g.dispose(); 180 } 181 182 public int getIconWidth() { 183 return width; 184 } 185 186 public int getIconHeight() { 187 return height; 188 } 189 190 } 191 192 static abstract class CachableJRSUIIcon extends CachingScalingIcon implements UIResource { 193 public CachableJRSUIIcon(final int width, final int height) { 194 super(width, height); 195 } 196 197 Image createImage() { 198 final AquaPainter<JRSUIState> painter = AquaPainter.create(JRSUIState.getInstance()); 199 initIconPainter(painter); 200 201 final BufferedImage img = new BufferedImage(getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB_PRE); 202 final Graphics g = img.getGraphics(); 203 g.setClip(new Rectangle(0, 0, getIconWidth(), getIconHeight())); 204 painter.paint(g, null, 0, 0, getIconWidth(), getIconHeight()); 205 g.dispose(); 206 return img; 207 } 208 209 public abstract void initIconPainter(final AquaPainter<JRSUIState> painter); 210 } 211 212 static class FileIcon extends CachingScalingIcon { 213 final File file; 214 215 public FileIcon(final File file, final int width, final int height) { 216 super(width, height); 217 this.file = file; 218 } 219 220 public FileIcon(final File file) { 221 this(file, 16, 16); 222 } 223 224 Image createImage() { 225 return AquaUtils.getCImageCreator().createImageOfFile(file.getAbsolutePath(), getIconWidth(), getIconHeight()); 226 } 227 } 228 229 static class SystemIconSingleton extends RecyclableSingleton<SystemIcon> { 230 final String selector; 231 232 public SystemIconSingleton(String selector) { 233 this.selector = selector; 234 } 235 236 @Override 237 protected SystemIcon getInstance() { 238 return new SystemIcon(selector); 239 } 240 } 241 242 static class SystemIconUIResourceSingleton extends RecyclableSingleton<IconUIResource> { 243 final String selector; 244 245 public SystemIconUIResourceSingleton(String selector) { 246 this.selector = selector; 247 } 248 249 @Override 250 protected IconUIResource getInstance() { 251 return new IconUIResource(new SystemIcon(selector)); 252 } 253 } 254 255 static class SystemIcon extends CachingScalingIcon { 256 private static final SystemIconUIResourceSingleton folderIcon = new SystemIconUIResourceSingleton("fldr"); 257 static IconUIResource getFolderIconUIResource() { return folderIcon.get(); } 258 259 private static final SystemIconUIResourceSingleton openFolderIcon = new SystemIconUIResourceSingleton("ofld"); 260 static IconUIResource getOpenFolderIconUIResource() { return openFolderIcon.get(); } 261 262 private static final SystemIconUIResourceSingleton desktopIcon = new SystemIconUIResourceSingleton("desk"); 263 static IconUIResource getDesktopIconUIResource() { return desktopIcon.get(); } 264 265 private static final SystemIconUIResourceSingleton computerIcon = new SystemIconUIResourceSingleton("FNDR"); 266 static IconUIResource getComputerIconUIResource() { return computerIcon.get(); } 267 268 private static final SystemIconUIResourceSingleton documentIcon = new SystemIconUIResourceSingleton("docu"); 269 static IconUIResource getDocumentIconUIResource() { return documentIcon.get(); } 270 271 private static final SystemIconUIResourceSingleton hardDriveIcon = new SystemIconUIResourceSingleton("hdsk"); 272 static IconUIResource getHardDriveIconUIResource() { return hardDriveIcon.get(); } 273 274 private static final SystemIconUIResourceSingleton floppyIcon = new SystemIconUIResourceSingleton("flpy"); 275 static IconUIResource getFloppyIconUIResource() { return floppyIcon.get(); } 276 277 //private static final SystemIconUIResourceSingleton noteIcon = new SystemIconUIResourceSingleton("note"); 278 //static IconUIResource getNoteIconUIResource() { return noteIcon.get(); } 279 280 private static final SystemIconSingleton caut = new SystemIconSingleton("caut"); 281 static SystemIcon getCautionIcon() { return caut.get(); } 282 283 private static final SystemIconSingleton stop = new SystemIconSingleton("stop"); 284 static SystemIcon getStopIcon() { return stop.get(); } 285 286 final String selector; 287 288 public SystemIcon(final String iconSelector, final int width, final int height) { 289 super(width, height); 290 selector = iconSelector; 291 } 292 293 public SystemIcon(final String iconSelector) { 294 this(iconSelector, 16, 16); 295 } 296 297 Image createImage() { 298 int w = getIconWidth(); 299 int h = getIconHeight(); 300 return new AquaImageFactory.MultiResolutionIconImage( 301 AquaUtils.getCImageCreator().createSystemImageFromSelector( 302 selector, w, h), 303 AquaUtils.getCImageCreator().createSystemImageFromSelector( 304 selector, 2 * w, 2 * h) 305 ); 306 } 307 } 308 }