1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package com.android.ide.eclipse.adt.internal.editors; 19 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 import com.android.sdklib.SdkConstants; 22 23 import org.eclipse.jface.resource.ImageDescriptor; 24 import org.eclipse.swt.SWT; 25 import org.eclipse.swt.graphics.Font; 26 import org.eclipse.swt.graphics.FontData; 27 import org.eclipse.swt.graphics.GC; 28 import org.eclipse.swt.graphics.Image; 29 import org.eclipse.swt.graphics.ImageData; 30 import org.eclipse.swt.graphics.Point; 31 import org.eclipse.swt.widgets.Display; 32 33 import java.util.HashMap; 34 35 /** 36 * Factory to generate icons for Android Editors. 37 * <p/> 38 * Icons are kept here and reused. 39 */ 40 public class IconFactory { 41 42 public static final int COLOR_RED = SWT.COLOR_DARK_RED; 43 public static final int COLOR_GREEN = SWT.COLOR_DARK_GREEN; 44 public static final int COLOR_BLUE = SWT.COLOR_DARK_BLUE; 45 public static final int COLOR_DEFAULT = SWT.COLOR_BLACK; 46 47 public static final int SHAPE_CIRCLE = 'C'; 48 public static final int SHAPE_RECT = 'R'; 49 public static final int SHAPE_DEFAULT = SHAPE_CIRCLE; 50 51 private static IconFactory sInstance; 52 53 private HashMap<String, Image> mIconMap = new HashMap<String, Image>(); 54 private HashMap<String, ImageDescriptor> mImageDescMap = new HashMap<String, ImageDescriptor>(); 55 56 private IconFactory() { 57 } 58 59 public static synchronized IconFactory getInstance() { 60 if (sInstance == null) { 61 sInstance = new IconFactory(); 62 } 63 return sInstance; 64 } 65 66 public void Dispose() { 67 // Dispose icons 68 for (Image icon : mIconMap.values()) { 69 // The map can contain null values 70 if (icon != null) { 71 icon.dispose(); 72 } 73 } 74 mIconMap.clear(); 75 } 76 77 /** 78 * Returns an Image for a given icon name. 79 * <p/> 80 * Callers should not dispose it. 81 * 82 * @param osName The leaf name, without the extension, of an existing icon in the 83 * editor's "icons" directory. If it doesn't exists, a default icon will be 84 * generated automatically based on the name. 85 */ 86 public Image getIcon(String osName) { 87 return getIcon(osName, COLOR_DEFAULT, SHAPE_DEFAULT); 88 } 89 90 /** 91 * Returns an Image for a given icon name. 92 * <p/> 93 * Callers should not dispose it. 94 * 95 * @param osName The leaf name, without the extension, of an existing icon in the 96 * editor's "icons" directory. If it doesn't exists, a default icon will be 97 * generated automatically based on the name. 98 * @param color The color of the text in the automatically generated icons, 99 * one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED. 100 * @param shape The shape of the icon in the automatically generated icons, 101 * one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT. 102 */ 103 public Image getIcon(String osName, int color, int shape) { 104 String key = Character.toString((char) shape) + Integer.toString(color) + osName; 105 Image icon = mIconMap.get(key); 106 if (icon == null && !mIconMap.containsKey(key)) { 107 ImageDescriptor id = getImageDescriptor(osName, color, shape); 108 if (id != null) { 109 icon = id.createImage(); 110 } 111 // Note that we store null references in the icon map, to avoid looking them 112 // up every time. If it didn't exist once, it will not exist later. 113 mIconMap.put(key, icon); 114 } 115 return icon; 116 } 117 118 /** 119 * Returns an ImageDescriptor for a given icon name. 120 * <p/> 121 * Callers should not dispose it. 122 * 123 * @param osName The leaf name, without the extension, of an existing icon in the 124 * editor's "icons" directory. If it doesn't exists, a default icon will be 125 * generated automatically based on the name. 126 */ 127 public ImageDescriptor getImageDescriptor(String osName) { 128 return getImageDescriptor(osName, COLOR_DEFAULT, SHAPE_DEFAULT); 129 } 130 131 /** 132 * Returns an ImageDescriptor for a given icon name. 133 * <p/> 134 * Callers should not dispose it. 135 * 136 * @param osName The leaf name, without the extension, of an existing icon in the 137 * editor's "icons" directory. If it doesn't exists, a default icon will be 138 * generated automatically based on the name. 139 * @param color The color of the text in the automatically generated icons. 140 * one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED. 141 * @param shape The shape of the icon in the automatically generated icons, 142 * one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT. 143 */ 144 public ImageDescriptor getImageDescriptor(String osName, int color, int shape) { 145 String key = Character.toString((char) shape) + Integer.toString(color) + osName; 146 ImageDescriptor id = mImageDescMap.get(key); 147 if (id == null && !mImageDescMap.containsKey(key)) { 148 id = AdtPlugin.imageDescriptorFromPlugin( 149 AdtPlugin.PLUGIN_ID, 150 String.format("/icons/%1$s.png", osName)); //$NON-NLS-1$ 151 152 if (id == null) { 153 id = new LetterImageDescriptor(osName.charAt(0), color, shape); 154 } 155 156 // Note that we store null references in the icon map, to avoid looking them 157 // up every time. If it didn't exist once, it will not exist later. 158 mImageDescMap.put(key, id); 159 } 160 return id; 161 } 162 163 /** 164 * A simple image description that generates a 16x16 image which consists 165 * of a colored letter inside a black & white circle. 166 */ 167 private static class LetterImageDescriptor extends ImageDescriptor { 168 169 private final char mLetter; 170 private final int mColor; 171 private final int mShape; 172 173 public LetterImageDescriptor(char letter, int color, int shape) { 174 mLetter = letter; 175 mColor = color; 176 mShape = shape; 177 } 178 179 @Override 180 public ImageData getImageData() { 181 182 final int SX = 15; 183 final int SY = 15; 184 final int RX = 4; 185 final int RY = 4; 186 187 Display display = Display.getCurrent(); 188 if (display == null) { 189 return null; 190 } 191 192 Image image = new Image(display, SX, SY); 193 194 image.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); 195 196 GC gc = new GC(image); 197 gc.setAdvanced(true); 198 gc.setAntialias(SWT.ON); 199 gc.setTextAntialias(SWT.ON); 200 201 gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); 202 if (mShape == SHAPE_CIRCLE) { 203 gc.fillOval(0, 0, SX - 1, SY - 1); 204 } else if (mShape == SHAPE_RECT) { 205 gc.fillRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY); 206 } 207 208 gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK)); 209 gc.setLineWidth(1); 210 if (mShape == SHAPE_CIRCLE) { 211 gc.drawOval(0, 0, SX - 1, SY - 1); 212 } else if (mShape == SHAPE_RECT) { 213 gc.drawRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY); 214 } 215 216 // Get a bold version of the default system font, if possible. 217 Font font = display.getSystemFont(); 218 FontData[] fds = font.getFontData(); 219 fds[0].setStyle(SWT.BOLD); 220 // use 3/4th of the circle diameter for the font size (in pixels) 221 // and convert it to "font points" (font points in SWT are hardcoded in an 222 // arbitrary 72 dpi and then converted in real pixels using whatever is 223 // indicated by getDPI -- at least that's how it works under Win32). 224 fds[0].setHeight((int) ((SY + 1) * 3./4. * 72./display.getDPI().y)); 225 // Note: win32 implementation always uses fds[0] so we change just that one. 226 // getFontData indicates that the array of fd is really an unusual thing for X11. 227 font = new Font(display, fds); 228 gc.setFont(font); 229 gc.setForeground(display.getSystemColor(mColor)); 230 231 // Text measurement varies so slightly depending on the platform 232 int ofx = 0; 233 int ofy = 0; 234 if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) { 235 ofx = +1; 236 ofy = -1; 237 } 238 239 String s = Character.toString(mLetter).toUpperCase(); 240 Point p = gc.textExtent(s); 241 int tx = (SX + ofx - p.x) / 2; 242 int ty = (SY + ofy - p.y) / 2; 243 gc.drawText(s, tx, ty, true /* isTransparent */); 244 245 font.dispose(); 246 gc.dispose(); 247 248 ImageData data = image.getImageData(); 249 image.dispose(); 250 return data; 251 } 252 253 } 254 255 } 256