155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project/*
255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project *
455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * you may not use this file except in compliance with the License.
655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * You may obtain a copy of the License at
755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project *
855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project *
1055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * See the License for the specific language governing permissions and
1455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * limitations under the License.
1555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */
1655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
1769425d803b34589309a69eddc53a338e1409b30cXavier Ducrohetpackage com.android.ide.eclipse.adt.internal.editors;
1855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
1981cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport com.android.SdkConstants;
203e75d4f79a8328ed18505830c786402369082efaTor Norbyeimport com.android.annotations.NonNull;
21b9317238c40c76f9a31647021f232adba6da0979Tor Norbyeimport com.android.annotations.Nullable;
2255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport com.android.ide.eclipse.adt.AdtPlugin;
235ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.ui.ErrorImageComposite;
245ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbyeimport com.google.common.collect.Maps;
2555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
2655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.jface.resource.ImageDescriptor;
2755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.SWT;
2893b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbyeimport org.eclipse.swt.graphics.Color;
2955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.graphics.Font;
3055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.graphics.FontData;
3155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.graphics.GC;
3255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.graphics.Image;
3355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.graphics.ImageData;
3455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.graphics.Point;
3593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbyeimport org.eclipse.swt.graphics.RGB;
3655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectimport org.eclipse.swt.widgets.Display;
37a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbyeimport org.eclipse.ui.plugin.AbstractUIPlugin;
3855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
39a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbyeimport java.net.URL;
405ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbyeimport java.util.IdentityHashMap;
415ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbyeimport java.util.Map;
4255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
4355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project/**
4455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Factory to generate icons for Android Editors.
4555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * <p/>
4655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project * Icons are kept here and reused.
4755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project */
4855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectpublic class IconFactory {
4955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static final int COLOR_RED     = SWT.COLOR_DARK_RED;
5055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static final int COLOR_GREEN   = SWT.COLOR_DARK_GREEN;
5155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static final int COLOR_BLUE    = SWT.COLOR_DARK_BLUE;
5255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static final int COLOR_DEFAULT = SWT.COLOR_BLACK;
5355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
5455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static final int SHAPE_CIRCLE  = 'C';
5555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static final int SHAPE_RECT    = 'R';
5655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static final int SHAPE_DEFAULT = SHAPE_CIRCLE;
5793b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
5855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    private static IconFactory sInstance;
5955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
605ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    private Map<String, Image> mIconMap = Maps.newHashMap();
615ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    private Map<URL, Image> mUrlMap = Maps.newHashMap();
625ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    private Map<String, ImageDescriptor> mImageDescMap = Maps.newHashMap();
635ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    private Map<Image, Image> mErrorIcons;
645ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    private Map<Image, Image> mWarningIcons;
6593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
6655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    private IconFactory() {
6755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
6893b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
6955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public static synchronized IconFactory getInstance() {
7055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        if (sInstance == null) {
7155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            sInstance = new IconFactory();
7255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        }
7355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        return sInstance;
7455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
7593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
76a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye    public void dispose() {
7755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        // Dispose icons
7855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        for (Image icon : mIconMap.values()) {
7955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // The map can contain null values
8055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            if (icon != null) {
8155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                icon.dispose();
8255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            }
8355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        }
8455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        mIconMap.clear();
85a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye        for (Image icon : mUrlMap.values()) {
86a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye            // The map can contain null values
87a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye            if (icon != null) {
88a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye                icon.dispose();
89a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye            }
90a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye        }
91a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye        mUrlMap.clear();
925ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        if (mErrorIcons != null) {
935ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            for (Image icon : mErrorIcons.values()) {
945ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                // The map can contain null values
955ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                if (icon != null) {
965ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                    icon.dispose();
975ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                }
985ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            }
995ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            mErrorIcons = null;
1005ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        }
1015ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        if (mWarningIcons != null) {
1025ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            for (Image icon : mWarningIcons.values()) {
1035ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                // The map can contain null values
1045ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                if (icon != null) {
1055ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                    icon.dispose();
1065ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                }
1075ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            }
1085ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            mWarningIcons = null;
1095ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        }
11055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
11155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
11255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    /**
11355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Returns an Image for a given icon name.
11455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * <p/>
11555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Callers should not dispose it.
11693b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye     *
11755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param osName The leaf name, without the extension, of an existing icon in the
11855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        editor's "icons" directory. If it doesn't exists, a default icon will be
11955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        generated automatically based on the name.
12055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     */
12155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public Image getIcon(String osName) {
12255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        return getIcon(osName, COLOR_DEFAULT, SHAPE_DEFAULT);
12355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
12455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
12555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    /**
12655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Returns an Image for a given icon name.
12755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * <p/>
12855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Callers should not dispose it.
12993b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye     *
13055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param osName The leaf name, without the extension, of an existing icon in the
1313e75d4f79a8328ed18505830c786402369082efaTor Norbye     *        editor's "icons" directory. If it doesn't exist, a default icon will be
13255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        generated automatically based on the name.
13355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param color The color of the text in the automatically generated icons,
13455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED.
13555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param shape The shape of the icon in the automatically generated icons,
13655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT.
13755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     */
13855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public Image getIcon(String osName, int color, int shape) {
13955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        String key = Character.toString((char) shape) + Integer.toString(color) + osName;
14055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        Image icon = mIconMap.get(key);
14155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        if (icon == null && !mIconMap.containsKey(key)) {
14255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            ImageDescriptor id = getImageDescriptor(osName, color, shape);
14355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            if (id != null) {
14455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                icon = id.createImage();
14555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            }
14655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // Note that we store null references in the icon map, to avoid looking them
14755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // up every time. If it didn't exist once, it will not exist later.
14855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            mIconMap.put(key, icon);
14955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        }
15055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        return icon;
15155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
15255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
15355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    /**
15455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Returns an ImageDescriptor for a given icon name.
15555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * <p/>
15655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Callers should not dispose it.
15793b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye     *
15855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param osName The leaf name, without the extension, of an existing icon in the
15955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        editor's "icons" directory. If it doesn't exists, a default icon will be
16055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        generated automatically based on the name.
16155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     */
16255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public ImageDescriptor getImageDescriptor(String osName) {
16355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        return getImageDescriptor(osName, COLOR_DEFAULT, SHAPE_DEFAULT);
16455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
16593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
16655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    /**
16755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Returns an ImageDescriptor for a given icon name.
16855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * <p/>
16955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * Callers should not dispose it.
17093b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye     *
17155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param osName The leaf name, without the extension, of an existing icon in the
17255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        editor's "icons" directory. If it doesn't exists, a default icon will be
17355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        generated automatically based on the name.
17455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param color The color of the text in the automatically generated icons.
17555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED.
17655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * @param shape The shape of the icon in the automatically generated icons,
17755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     *        one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT.
17855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     */
17955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    public ImageDescriptor getImageDescriptor(String osName, int color, int shape) {
18055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        String key = Character.toString((char) shape) + Integer.toString(color) + osName;
18155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        ImageDescriptor id = mImageDescMap.get(key);
18255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        if (id == null && !mImageDescMap.containsKey(key)) {
183a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye            id = AbstractUIPlugin.imageDescriptorFromPlugin(
18455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                    AdtPlugin.PLUGIN_ID,
18555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                    String.format("/icons/%1$s.png", osName)); //$NON-NLS-1$
18655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
18755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            if (id == null) {
18855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                id = new LetterImageDescriptor(osName.charAt(0), color, shape);
18955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            }
19093b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
19155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // Note that we store null references in the icon map, to avoid looking them
19255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // up every time. If it didn't exist once, it will not exist later.
19355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            mImageDescMap.put(key, id);
19455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        }
19555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        return id;
19655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
19755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
19855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    /**
1993e75d4f79a8328ed18505830c786402369082efaTor Norbye     * Returns an Image for a given icon name.
2003e75d4f79a8328ed18505830c786402369082efaTor Norbye     * <p/>
2013e75d4f79a8328ed18505830c786402369082efaTor Norbye     * Callers should not dispose it.
2023e75d4f79a8328ed18505830c786402369082efaTor Norbye     *
2033e75d4f79a8328ed18505830c786402369082efaTor Norbye     * @param osName The leaf name, without the extension, of an existing icon
2043e75d4f79a8328ed18505830c786402369082efaTor Norbye     *            in the editor's "icons" directory. If it doesn't exist, the
2053e75d4f79a8328ed18505830c786402369082efaTor Norbye     *            fallback will be used instead.
2063e75d4f79a8328ed18505830c786402369082efaTor Norbye     * @param fallback the fallback icon name to use if the primary icon does
207b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     *            not exist, or null if the method should return null if the
208b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     *            image does not exist
209b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     * @return the icon, which should not be disposed by the caller, or null
210b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     * if the image does not exist *and*
2113e75d4f79a8328ed18505830c786402369082efaTor Norbye     */
212b9317238c40c76f9a31647021f232adba6da0979Tor Norbye    @Nullable
213b9317238c40c76f9a31647021f232adba6da0979Tor Norbye    public Image getIcon(@NonNull String osName, @Nullable String fallback) {
2143e75d4f79a8328ed18505830c786402369082efaTor Norbye        String key = osName;
2153e75d4f79a8328ed18505830c786402369082efaTor Norbye        Image icon = mIconMap.get(key);
2163e75d4f79a8328ed18505830c786402369082efaTor Norbye        if (icon == null && !mIconMap.containsKey(key)) {
2173e75d4f79a8328ed18505830c786402369082efaTor Norbye            ImageDescriptor id = getImageDescriptor(osName, fallback);
2183e75d4f79a8328ed18505830c786402369082efaTor Norbye            if (id != null) {
2193e75d4f79a8328ed18505830c786402369082efaTor Norbye                icon = id.createImage();
2203e75d4f79a8328ed18505830c786402369082efaTor Norbye            }
2213e75d4f79a8328ed18505830c786402369082efaTor Norbye            // Note that we store null references in the icon map, to avoid looking them
2223e75d4f79a8328ed18505830c786402369082efaTor Norbye            // up every time. If it didn't exist once, it will not exist later.
2233e75d4f79a8328ed18505830c786402369082efaTor Norbye            mIconMap.put(key, icon);
2243e75d4f79a8328ed18505830c786402369082efaTor Norbye        }
2253e75d4f79a8328ed18505830c786402369082efaTor Norbye        return icon;
2263e75d4f79a8328ed18505830c786402369082efaTor Norbye    }
2273e75d4f79a8328ed18505830c786402369082efaTor Norbye
2283e75d4f79a8328ed18505830c786402369082efaTor Norbye    /**
229b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     * Returns an icon of the given name, or if that image does not exist and
230b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     * icon of the given fallback name.
2313e75d4f79a8328ed18505830c786402369082efaTor Norbye     *
2323e75d4f79a8328ed18505830c786402369082efaTor Norbye     * @param key the icon name
233b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     * @param fallbackKey the fallback image to use if the primary key does not
234b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     *            exist
235b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     * @return the image descriptor, or null if the image does not exist and the
236b9317238c40c76f9a31647021f232adba6da0979Tor Norbye     *         fallbackKey is null
2373e75d4f79a8328ed18505830c786402369082efaTor Norbye     */
238b9317238c40c76f9a31647021f232adba6da0979Tor Norbye    @Nullable
239b9317238c40c76f9a31647021f232adba6da0979Tor Norbye    public ImageDescriptor getImageDescriptor(@NonNull String key, @Nullable String fallbackKey) {
2403e75d4f79a8328ed18505830c786402369082efaTor Norbye        ImageDescriptor id = mImageDescMap.get(key);
2413e75d4f79a8328ed18505830c786402369082efaTor Norbye        if (id == null && !mImageDescMap.containsKey(key)) {
2423e75d4f79a8328ed18505830c786402369082efaTor Norbye            id = AbstractUIPlugin.imageDescriptorFromPlugin(
2433e75d4f79a8328ed18505830c786402369082efaTor Norbye                    AdtPlugin.PLUGIN_ID,
2443e75d4f79a8328ed18505830c786402369082efaTor Norbye                    String.format("/icons/%1$s.png", key)); //$NON-NLS-1$
2453e75d4f79a8328ed18505830c786402369082efaTor Norbye            if (id == null) {
246b9317238c40c76f9a31647021f232adba6da0979Tor Norbye                if (fallbackKey == null) {
247b9317238c40c76f9a31647021f232adba6da0979Tor Norbye                    return null;
248b9317238c40c76f9a31647021f232adba6da0979Tor Norbye                }
2493e75d4f79a8328ed18505830c786402369082efaTor Norbye                id = getImageDescriptor(fallbackKey);
2503e75d4f79a8328ed18505830c786402369082efaTor Norbye            }
2513e75d4f79a8328ed18505830c786402369082efaTor Norbye
2523e75d4f79a8328ed18505830c786402369082efaTor Norbye            // Place the fallback image for this key as well such that we don't keep trying
2533e75d4f79a8328ed18505830c786402369082efaTor Norbye            // to load the failed image
2543e75d4f79a8328ed18505830c786402369082efaTor Norbye            mImageDescMap.put(key, id);
2553e75d4f79a8328ed18505830c786402369082efaTor Norbye        }
2563e75d4f79a8328ed18505830c786402369082efaTor Norbye
2573e75d4f79a8328ed18505830c786402369082efaTor Norbye        return id;
2583e75d4f79a8328ed18505830c786402369082efaTor Norbye    }
2593e75d4f79a8328ed18505830c786402369082efaTor Norbye
2603e75d4f79a8328ed18505830c786402369082efaTor Norbye    /**
261a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye     * Returns the image indicated by the given URL
262a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye     *
263a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye     * @param url the url to the image resources
264a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye     * @return the image for the url, or null if it cannot be initialized
265a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye     */
266a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye    public Image getIcon(URL url) {
267a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye        Image image = mUrlMap.get(url);
268a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye        if (image == null) {
269a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye            ImageDescriptor descriptor = ImageDescriptor.createFromURL(url);
270a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye            image = descriptor.createImage();
271a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye            mUrlMap.put(url, image);
272a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye        }
273a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye
274a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye        return image;
275a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye    }
276a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye
277a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye    /**
2785ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * Returns an image with an error icon overlaid on it. The icons are cached,
2795ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * so the base image should be cached as well, or this method will keep
2805ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * storing new overlays into its cache.
2815ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     *
2825ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * @param image the base image
2835ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * @return the combined image
2845ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     */
2855ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    @NonNull
2865ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    public Image addErrorIcon(@NonNull Image image) {
2875ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        if (mErrorIcons != null) {
2885ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            Image combined = mErrorIcons.get(image);
2895ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            if (combined != null) {
2905ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                return combined;
2915ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            }
2925ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        } else {
2935ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            mErrorIcons = new IdentityHashMap<Image, Image>();
2945ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        }
2955ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye
2965ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        Image combined = new ErrorImageComposite(image, false).createImage();
2975ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        mErrorIcons.put(image, combined);
2985ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye
2995ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        return combined;
3005ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    }
3015ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye
3025ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    /**
3035ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * Returns an image with a warning icon overlaid on it. The icons are
3045ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * cached, so the base image should be cached as well, or this method will
3055ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * keep storing new overlays into its cache.
3065ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     *
3075ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * @param image the base image
3085ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     * @return the combined image
3095ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye     */
3105ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    @NonNull
3115ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    public Image addWarningIcon(@NonNull Image image) {
3125ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        if (mWarningIcons != null) {
3135ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            Image combined = mWarningIcons.get(image);
3145ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            if (combined != null) {
3155ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye                return combined;
3165ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            }
3175ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        } else {
3185ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye            mWarningIcons = new IdentityHashMap<Image, Image>();
3195ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        }
3205ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye
3215ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        Image combined = new ErrorImageComposite(image, true).createImage();
3225ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        mWarningIcons.put(image, combined);
3235ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye
3245ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye        return combined;
3255ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    }
3265ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye
3275ae903bf8670f40e9eb40ebbd0a25c15eaac5962Tor Norbye    /**
32855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * A simple image description that generates a 16x16 image which consists
32955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     * of a colored letter inside a black & white circle.
33055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project     */
33155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    private static class LetterImageDescriptor extends ImageDescriptor {
33255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
33355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        private final char mLetter;
33455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        private final int mColor;
33555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        private final int mShape;
33655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
33755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        public LetterImageDescriptor(char letter, int color, int shape) {
33893b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            mLetter = Character.toUpperCase(letter);
33955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            mColor = color;
34055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            mShape = shape;
34155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        }
34293b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
34355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        @Override
34455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        public ImageData getImageData() {
34593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
34655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            final int SX = 15;
34755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            final int SY = 15;
34855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            final int RX = 4;
34955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            final int RY = 4;
35093b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
35155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            Display display = Display.getCurrent();
35255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            if (display == null) {
35355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                return null;
35455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            }
35555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
35655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            Image image = new Image(display, SX, SY);
35793b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
35855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            GC gc = new GC(image);
35955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setAdvanced(true);
36055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setAntialias(SWT.ON);
36155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setTextAntialias(SWT.ON);
36255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
363a2d7874ed23bfc2fa7665cc84901e0f4781b4e51Tor Norbye            // image.setBackground() does not appear to have any effect; we must explicitly
36493b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // paint into the image the background color we want masked out later.
36593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // HOWEVER, alpha transparency does not work; we only get to mark a single color
36693b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // as transparent. You might think we could pick a system color (to avoid having
36793b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // to allocate and dispose the color), or a wildly unique color (to make sure we
36893b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // don't accidentally pick up any extra pixels in the image as transparent), but
36993b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // this has the very unfortunate side effect of making neighbor pixels in the
37093b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // antialiased rendering of the circle pick up shades of that alternate color,
37193b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // which looks bad. Therefore we pick a color which is similar to one of our
37293b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // existing colors but hopefully different from most pixels. A visual check
37393b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // confirms that this seems to work pretty well:
37493b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            RGB backgroundRgb = new RGB(254, 254, 254);
37593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            Color backgroundColor = new Color(display, backgroundRgb);
37693b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            gc.setBackground(backgroundColor);
37793b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            gc.fillRectangle(0, 0, SX, SY);
37893b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
37955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
38055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            if (mShape == SHAPE_CIRCLE) {
38155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                gc.fillOval(0, 0, SX - 1, SY - 1);
38255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            } else if (mShape == SHAPE_RECT) {
38355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                gc.fillRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY);
38455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            }
38593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
38655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
38755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setLineWidth(1);
38855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            if (mShape == SHAPE_CIRCLE) {
38955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                gc.drawOval(0, 0, SX - 1, SY - 1);
39055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            } else if (mShape == SHAPE_RECT) {
39155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                gc.drawRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY);
39255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            }
39355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
39455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // Get a bold version of the default system font, if possible.
39555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            Font font = display.getSystemFont();
39655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            FontData[] fds = font.getFontData();
39755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            fds[0].setStyle(SWT.BOLD);
39855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // use 3/4th of the circle diameter for the font size (in pixels)
39955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // and convert it to "font points" (font points in SWT are hardcoded in an
40055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // arbitrary 72 dpi and then converted in real pixels using whatever is
40155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // indicated by getDPI -- at least that's how it works under Win32).
40255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            fds[0].setHeight((int) ((SY + 1) * 3./4. * 72./display.getDPI().y));
40355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // Note: win32 implementation always uses fds[0] so we change just that one.
40455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // getFontData indicates that the array of fd is really an unusual thing for X11.
40555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            font = new Font(display, fds);
40655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setFont(font);
40755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.setForeground(display.getSystemColor(mColor));
40855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
40955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            // Text measurement varies so slightly depending on the platform
41055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            int ofx = 0;
41155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            int ofy = 0;
41255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) {
41355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                ofx = +1;
41455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project                ofy = -1;
41593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            } else if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN) {
41693b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye                // Tweak pixel positioning of some letters that don't look good on the Mac
41793b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye                if (mLetter != 'T' && mLetter != 'V') {
41893b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye                    ofy = -1;
41993b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye                }
42093b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye                if (mLetter == 'I') {
42193b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye                    ofx = -2;
42293b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye                }
42355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            }
42493b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
42593b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            String s = Character.toString(mLetter);
42655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            Point p = gc.textExtent(s);
42755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            int tx = (SX + ofx - p.x) / 2;
42855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            int ty = (SY + ofy - p.y) / 2;
42955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.drawText(s, tx, ty, true /* isTransparent */);
43055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
43155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            font.dispose();
43255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            gc.dispose();
43393b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
43455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            ImageData data = image.getImageData();
43555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            image.dispose();
43693b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            backgroundColor.dispose();
43793b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
43893b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // Set transparent pixel in the palette such that on paint (over palette,
43993b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // which has a background of SWT.COLOR_WIDGET_BACKGROUND, and over the tree
44093b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // which has a white background) we will substitute the background in for
44193b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            // the backgroundPixel.
44293b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            int backgroundPixel = data.palette.getPixel(backgroundRgb);
44393b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye            data.transparentPixel = backgroundPixel;
44493b86c1f3185c8df21e2a45a31e4cd9ce567cef0Tor Norbye
44555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            return data;
44655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        }
44755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
44855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project}
449