diff org.eclipse.ui.forms/src/org/eclipse/ui/forms/FormColors.d @ 12:bc29606a740c

Added dwt-addons in original directory structure of eclipse.org
author Frank Benoit <benoit@tionex.de>
date Sat, 14 Mar 2009 18:23:29 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.ui.forms/src/org/eclipse/ui/forms/FormColors.d	Sat Mar 14 18:23:29 2009 +0100
@@ -0,0 +1,740 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module org.eclipse.ui.forms.FormColors;
+
+import org.eclipse.ui.forms.IFormColors;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+import java.lang.all;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+
+/**
+ * Manages colors that will be applied to forms and form widgets. The colors are
+ * chosen to make the widgets look correct in the editor area. If a different
+ * set of colors is needed, subclass this class and override 'initialize' and/or
+ * 'initializeColors'.
+ *
+ * @since 3.0
+ */
+public class FormColors {
+    /**
+     * Key for the form title foreground color.
+     *
+     * @deprecated use <code>IFormColors.TITLE</code>.
+     */
+    public static const String TITLE = IFormColors.TITLE;
+
+    /**
+     * Key for the tree/table border color.
+     *
+     * @deprecated use <code>IFormColors.BORDER</code>
+     */
+    public static const String BORDER = IFormColors.BORDER;
+
+    /**
+     * Key for the section separator color.
+     *
+     * @deprecated use <code>IFormColors.SEPARATOR</code>.
+     */
+    public static const String SEPARATOR = IFormColors.SEPARATOR;
+
+    /**
+     * Key for the section title bar background.
+     *
+     * @deprecated use <code>IFormColors.TB_BG
+     */
+    public static const String TB_BG = IFormColors.TB_BG;
+
+    /**
+     * Key for the section title bar foreground.
+     *
+     * @deprecated use <code>IFormColors.TB_FG</code>
+     */
+    public static const String TB_FG = IFormColors.TB_FG;
+
+    /**
+     * Key for the section title bar gradient.
+     *
+     * @deprecated use <code>IFormColors.TB_GBG</code>
+     */
+    public static const String TB_GBG = IFormColors.TB_GBG;
+
+    /**
+     * Key for the section title bar border.
+     *
+     * @deprecated use <code>IFormColors.TB_BORDER</code>.
+     */
+    public static const String TB_BORDER = IFormColors.TB_BORDER;
+
+    /**
+     * Key for the section toggle color. Since 3.1, this color is used for all
+     * section styles.
+     *
+     * @deprecated use <code>IFormColors.TB_TOGGLE</code>.
+     */
+    public static const String TB_TOGGLE = IFormColors.TB_TOGGLE;
+
+    /**
+     * Key for the section toggle hover color.
+     *
+     * @since 3.1
+     * @deprecated use <code>IFormColors.TB_TOGGLE_HOVER</code>.
+     */
+    public static const String TB_TOGGLE_HOVER = IFormColors.TB_TOGGLE_HOVER;
+
+    protected Map colorRegistry;
+
+    protected Color background;
+
+    protected Color foreground;
+
+    private bool shared;
+
+    protected Display display;
+
+    protected Color border;
+
+    /**
+     * Creates form colors using the provided display.
+     *
+     * @param display
+     *            the display to use
+     */
+    public this(Display display) {
+        colorRegistry = new HashMap(10);
+        this.display = display;
+        initialize();
+    }
+
+    /**
+     * Returns the display used to create colors.
+     *
+     * @return the display
+     */
+    public Display getDisplay() {
+        return display;
+    }
+
+    /**
+     * Initializes the colors. Subclasses can override this method to change the
+     * way colors are created. Alternatively, only the color table can be
+     * modified by overriding <code>initializeColorTable()</code>.
+     *
+     * @see #initializeColorTable
+     */
+    protected void initialize() {
+        background = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+        foreground = display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
+        initializeColorTable();
+        updateBorderColor();
+    }
+
+    /**
+     * Allocates colors for the following keys: BORDER, SEPARATOR and
+     * TITLE. Subclasses can override to allocate these colors differently.
+     */
+    protected void initializeColorTable() {
+        createTitleColor();
+        createColor(IFormColors.SEPARATOR, getColor(IFormColors.TITLE).getRGB());
+        RGB black = getSystemColor(SWT.COLOR_BLACK);
+        RGB borderRGB = getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
+        createColor(IFormColors.BORDER, blend(borderRGB, black, 80));
+    }
+
+    /**
+     * Allocates colors for the section tool bar (all the keys that start with
+     * TB). Since these colors are only needed when TITLE_BAR style is used with
+     * the Section widget, they are not needed all the time and are allocated on
+     * demand. Consequently, this method will do nothing if the colors have been
+     * already initialized. Call this method prior to using colors with the TB
+     * keys to ensure they are available.
+     */
+    public void initializeSectionToolBarColors() {
+        if (colorRegistry.containsKey(IFormColors.TB_BG))
+            return;
+        createTitleBarGradientColors();
+        createTitleBarOutlineColors();
+        createTwistieColors();
+    }
+
+    /**
+     * Allocates additional colors for the form header, namely background
+     * gradients, bottom separator keylines and DND highlights. Since these
+     * colors are only needed for clients that want to use these particular
+     * style of header rendering, they are not needed all the time and are
+     * allocated on demand. Consequently, this method will do nothing if the
+     * colors have been already initialized. Call this method prior to using
+     * color keys with the H_ prefix to ensure they are available.
+     *
+     * @since 3.3
+     */
+    protected void initializeFormHeaderColors() {
+        if (colorRegistry.containsKey(IFormColors.H_BOTTOM_KEYLINE2))
+            return;
+        createFormHeaderColors();
+    }
+
+    /**
+     * Returns the RGB value of the system color represented by the code
+     * argument, as defined in <code>SWT</code> class.
+     *
+     * @param code
+     *            the system color constant as defined in <code>SWT</code>
+     *            class.
+     * @return the RGB value of the system color
+     */
+    public RGB getSystemColor(int code) {
+        return getDisplay().getSystemColor(code).getRGB();
+    }
+
+    /**
+     * Creates the color for the specified key using the provided RGB object.
+     * The color object will be returned and also put into the registry. When
+     * the class is disposed, the color will be disposed with it.
+     *
+     * @param key
+     *            the unique color key
+     * @param rgb
+     *            the RGB object
+     * @return the allocated color object
+     */
+    public Color createColor(String key, RGB rgb) {
+        return createColor(key, rgb.red, rgb.green, rgb.blue);
+    }
+
+    /**
+     * Creates a color that can be used for areas of the form that is inactive.
+     * These areas can contain images, links, controls and other content but are
+     * considered auxilliary to the main content area.
+     *
+     * <p>
+     * The color should not be disposed because it is managed by this class.
+     *
+     * @return the inactive form color
+     * @since 3.1
+     */
+    public Color getInactiveBackground() {
+        String key = "__ncbg__"; //$NON-NLS-1$
+        Color color = getColor(key);
+        if (color is null) {
+            RGB sel = getSystemColor(SWT.COLOR_LIST_SELECTION);
+            // a blend of 95% white and 5% list selection system color
+            RGB ncbg = blend(sel, getSystemColor(SWT.COLOR_WHITE), 5);
+            color = createColor(key, ncbg);
+        }
+        return color;
+    }
+
+    /**
+     * Creates the color for the specified key using the provided RGB values.
+     * The color object will be returned and also put into the registry. If
+     * there is already another color object under the same key in the registry,
+     * the existing object will be disposed. When the class is disposed, the
+     * color will be disposed with it.
+     *
+     * @param key
+     *            the unique color key
+     * @param r
+     *            red value
+     * @param g
+     *            green value
+     * @param b
+     *            blue value
+     * @return the allocated color object
+     */
+    public Color createColor(String key, int r, int g, int b) {
+        Color c = new Color(display, r, g, b);
+        Color prevC = cast(Color) colorRegistry.get(key);
+        if (prevC !is null)
+            prevC.dispose();
+        colorRegistry.put(key, c);
+        return c;
+    }
+
+    /**
+     * Computes the border color relative to the background. Allocated border
+     * color is designed to work well with white. Otherwise, stanard widget
+     * background color will be used.
+     */
+    protected void updateBorderColor() {
+        if (isWhiteBackground())
+            border = getColor(IFormColors.BORDER);
+        else {
+            border = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+            Color bg = getImpliedBackground();
+            if (border.getRed() is bg.getRed()
+                    && border.getGreen() is bg.getGreen()
+                    && border.getBlue() is bg.getBlue())
+                border = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
+        }
+    }
+
+    /**
+     * Sets the background color. All the toolkits that use this class will
+     * share the same background.
+     *
+     * @param bg
+     *            background color
+     */
+    public void setBackground(Color bg) {
+        this.background = bg;
+        updateBorderColor();
+        updateFormHeaderColors();
+    }
+
+    /**
+     * Sets the foreground color. All the toolkits that use this class will
+     * share the same foreground.
+     *
+     * @param fg
+     *            foreground color
+     */
+    public void setForeground(Color fg) {
+        this.foreground = fg;
+    }
+
+    /**
+     * Returns the current background color.
+     *
+     * @return the background color
+     */
+    public Color getBackground() {
+        return background;
+    }
+
+    /**
+     * Returns the current foreground color.
+     *
+     * @return the foreground color
+     */
+    public Color getForeground() {
+        return foreground;
+    }
+
+    /**
+     * Returns the computed border color. Border color depends on the background
+     * and is recomputed whenever the background changes.
+     *
+     * @return the current border color
+     */
+    public Color getBorderColor() {
+        return border;
+    }
+
+    /**
+     * Tests if the background is white. White background has RGB value
+     * 255,255,255.
+     *
+     * @return <samp>true</samp> if background is white, <samp>false</samp>
+     *         otherwise.
+     */
+    public bool isWhiteBackground() {
+        Color bg = getImpliedBackground();
+        return bg.getRed() is 255 && bg.getGreen() is 255
+                && bg.getBlue() is 255;
+    }
+
+    /**
+     * Returns the color object for the provided key or <samp>null </samp> if
+     * not in the registry.
+     *
+     * @param key
+     *            the color key
+     * @return color object if found, or <samp>null </samp> if not.
+     */
+    public Color getColor(String key) {
+        if (key.startsWith(IFormColors.TB_PREFIX))
+            initializeSectionToolBarColors();
+        else if (key.startsWith(IFormColors.H_PREFIX))
+            initializeFormHeaderColors();
+        return cast(Color) colorRegistry.get(key);
+    }
+
+    /**
+     * Disposes all the colors in the registry.
+     */
+    public void dispose() {
+        Iterator e = colorRegistry.values().iterator();
+        while (e.hasNext())
+            (cast(Color) e.next()).dispose();
+        colorRegistry = null;
+    }
+
+    /**
+     * Marks the colors shared. This prevents toolkits that share this object
+     * from disposing it.
+     */
+    public void markShared() {
+        this.shared = true;
+    }
+
+    /**
+     * Tests if the colors are shared.
+     *
+     * @return <code>true</code> if shared, <code>false</code> otherwise.
+     */
+    public bool isShared() {
+        return shared;
+    }
+
+    /**
+     * Blends c1 and c2 based in the provided ratio.
+     *
+     * @param c1
+     *            first color
+     * @param c2
+     *            second color
+     * @param ratio
+     *            percentage of the first color in the blend (0-100)
+     * @return the RGB value of the blended color
+     * @since 3.1
+     */
+    public static RGB blend(RGB c1, RGB c2, int ratio) {
+        int r = blend(c1.red, c2.red, ratio);
+        int g = blend(c1.green, c2.green, ratio);
+        int b = blend(c1.blue, c2.blue, ratio);
+        return new RGB(r, g, b);
+    }
+
+    /**
+     * Tests the source RGB for range.
+     *
+     * @param rgb
+     *            the tested RGB
+     * @param from
+     *            range start (excluding the value itself)
+     * @param to
+     *            range end (excluding the value itself)
+     * @return <code>true</code> if at least one of the primary colors in the
+     *         source RGB are within the provided range, <code>false</code>
+     *         otherwise.
+     * @since 3.1
+     */
+    public static bool testAnyPrimaryColor(RGB rgb, int from, int to) {
+        if (testPrimaryColor(rgb.red, from, to))
+            return true;
+        if (testPrimaryColor(rgb.green, from, to))
+            return true;
+        if (testPrimaryColor(rgb.blue, from, to))
+            return true;
+        return false;
+    }
+
+    /**
+     * Tests the source RGB for range.
+     *
+     * @param rgb
+     *            the tested RGB
+     * @param from
+     *            range start (excluding the value itself)
+     * @param to
+     *            tange end (excluding the value itself)
+     * @return <code>true</code> if at least two of the primary colors in the
+     *         source RGB are within the provided range, <code>false</code>
+     *         otherwise.
+     * @since 3.1
+     */
+    public static bool testTwoPrimaryColors(RGB rgb, int from, int to) {
+        int total = 0;
+        if (testPrimaryColor(rgb.red, from, to))
+            total++;
+        if (testPrimaryColor(rgb.green, from, to))
+            total++;
+        if (testPrimaryColor(rgb.blue, from, to))
+            total++;
+        return total >= 2;
+    }
+
+    /**
+     * Blends two primary color components based on the provided ratio.
+     *
+     * @param v1
+     *            first component
+     * @param v2
+     *            second component
+     * @param ratio
+     *            percentage of the first component in the blend
+     * @return
+     */
+    private static int blend(int v1, int v2, int ratio) {
+        int b = (ratio * v1 + (100 - ratio) * v2) / 100;
+        return Math.min(255, b);
+    }
+
+    private Color getImpliedBackground() {
+        if (getBackground() !is null)
+            return getBackground();
+        return getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+    }
+
+    private static bool testPrimaryColor(int value, int from, int to) {
+        return value > from && value < to;
+    }
+
+    private void createTitleColor() {
+        /*
+         * RGB rgb = getSystemColor(SWT.COLOR_LIST_SELECTION); // test too light
+         * if (testTwoPrimaryColors(rgb, 120, 151)) rgb = blend(rgb, BLACK, 80);
+         * else if (testTwoPrimaryColors(rgb, 150, 256)) rgb = blend(rgb, BLACK,
+         * 50); createColor(TITLE, rgb);
+         */
+        RGB bg = getImpliedBackground().getRGB();
+        RGB listSelection = getSystemColor(SWT.COLOR_LIST_SELECTION);
+        RGB listForeground = getSystemColor(SWT.COLOR_LIST_FOREGROUND);
+        RGB rgb = listSelection;
+
+        // Group 1
+        // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
+        // between 0 and 120, then use 100% LIST_SELECTION as it is (no
+        // additions)
+        // Examples: XP Default, Win Classic Standard, Win High Con White, Win
+        // Classic Marine
+        if (testTwoPrimaryColors(listSelection, -1, 121))
+            rgb = listSelection;
+        // Group 2
+        // When LIST_BACKGROUND = white (255, 255, 255) or not black, text
+        // colour = LIST_SELECTION @ 100% Opacity + 50% LIST_FOREGROUND over
+        // LIST_BACKGROUND
+        // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
+        // between 121 and 255, then add 50% LIST_FOREGROUND to LIST_SELECTION
+        // foreground colour
+        // Examples: Win Vista, XP Silver, XP Olive , Win Classic Plum, OSX
+        // Aqua, OSX Graphite, Linux GTK
+        else if (testTwoPrimaryColors(listSelection, 120, 256)
+                || (bg.red is 0 && bg.green is 0 && bg.blue is 0))
+            rgb = blend(listSelection, listForeground, 50);
+        // Group 3
+        // When LIST_BACKGROUND = black (0, 0, 0), text colour = LIST_SELECTION
+        // @ 100% Opacity + 50% LIST_FOREGROUND over LIST_BACKGROUND
+        // Rule: If LIST_BACKGROUND = 0, 0, 0, then add 50% LIST_FOREGROUND to
+        // LIST_SELECTION foreground colour
+        // Examples: Win High Con Black, Win High Con #1, Win High Con #2
+        // (covered in the second part of the OR clause above)
+        createColor(IFormColors.TITLE, rgb);
+    }
+
+    private void createTwistieColors() {
+        RGB rgb = getColor(IFormColors.TITLE).getRGB();
+        RGB white = getSystemColor(SWT.COLOR_WHITE);
+        createColor(TB_TOGGLE, rgb);
+        rgb = blend(rgb, white, 60);
+        createColor(TB_TOGGLE_HOVER, rgb);
+    }
+
+    private void createTitleBarGradientColors() {
+        RGB tbBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+        RGB bg = getImpliedBackground().getRGB();
+
+        // Group 1
+        // Rule: If at least 2 of the RGB values are equal to or between 180 and
+        // 255, then apply specified opacity for Group 1
+        // Examples: Vista, XP Silver, Wn High Con #2
+        // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+        // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+        if (testTwoPrimaryColors(tbBg, 179, 256))
+            tbBg = blend(tbBg, bg, 30);
+
+        // Group 2
+        // Rule: If at least 2 of the RGB values are equal to or between 121 and
+        // 179, then apply specified opacity for Group 2
+        // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+        // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
+        // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+        else if (testTwoPrimaryColors(tbBg, 120, 180))
+            tbBg = blend(tbBg, bg, 20);
+
+        // Group 3
+        // Rule: Everything else
+        // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+        // Aqua, Wn High Con White, Wn High Con #1
+        // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
+        // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+        else {
+            tbBg = blend(tbBg, bg, 10);
+        }
+
+        createColor(IFormColors.TB_BG, tbBg);
+
+        // for backward compatibility
+        createColor(TB_GBG, tbBg);
+    }
+
+    private void createTitleBarOutlineColors() {
+        // title bar outline - border color
+        RGB tbBorder = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+        RGB bg = getImpliedBackground().getRGB();
+        // Group 1
+        // Rule: If at least 2 of the RGB values are equal to or between 180 and
+        // 255, then apply specified opacity for Group 1
+        // Examples: Vista, XP Silver, Wn High Con #2
+        // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
+        if (testTwoPrimaryColors(tbBorder, 179, 256))
+            tbBorder = blend(tbBorder, bg, 70);
+
+        // Group 2
+        // Rule: If at least 2 of the RGB values are equal to or between 121 and
+        // 179, then apply specified opacity for Group 2
+        // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+
+        // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
+        else if (testTwoPrimaryColors(tbBorder, 120, 180))
+            tbBorder = blend(tbBorder, bg, 50);
+
+        // Group 3
+        // Rule: Everything else
+        // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+        // Aqua, Wn High Con White, Wn High Con #1
+
+        // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+        else {
+            tbBorder = blend(tbBorder, bg, 30);
+        }
+        createColor(FormColors.TB_BORDER, tbBorder);
+    }
+
+    private void updateFormHeaderColors() {
+        if (colorRegistry.containsKey(IFormColors.H_GRADIENT_END)) {
+            disposeIfFound(IFormColors.H_GRADIENT_END);
+            disposeIfFound(IFormColors.H_GRADIENT_START);
+            disposeIfFound(IFormColors.H_BOTTOM_KEYLINE1);
+            disposeIfFound(IFormColors.H_BOTTOM_KEYLINE2);
+            disposeIfFound(IFormColors.H_HOVER_LIGHT);
+            disposeIfFound(IFormColors.H_HOVER_FULL);
+            initializeFormHeaderColors();
+        }
+    }
+
+    private void disposeIfFound(String key) {
+        Color color = getColor(key);
+        if (color !is null) {
+            colorRegistry.remove(key);
+            color.dispose();
+        }
+    }
+
+    private void createFormHeaderColors() {
+        createFormHeaderGradientColors();
+        createFormHeaderKeylineColors();
+        createFormHeaderDNDColors();
+    }
+
+    private void createFormHeaderGradientColors() {
+        RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+        Color bgColor = getImpliedBackground();
+        RGB bg = bgColor.getRGB();
+        RGB bottom, top;
+        // Group 1
+        // Rule: If at least 2 of the RGB values are equal to or between 180 and
+        // 255, then apply specified opacity for Group 1
+        // Examples: Vista, XP Silver, Wn High Con #2
+        // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+        // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+        if (testTwoPrimaryColors(titleBg, 179, 256)) {
+            bottom = blend(titleBg, bg, 30);
+            top = bg;
+        }
+
+        // Group 2
+        // Rule: If at least 2 of the RGB values are equal to or between 121 and
+        // 179, then apply specified opacity for Group 2
+        // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+        // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
+        // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+        else if (testTwoPrimaryColors(titleBg, 120, 180)) {
+            bottom = blend(titleBg, bg, 20);
+            top = bg;
+        }
+
+        // Group 3
+        // Rule: If at least 2 of the RGB values are equal to or between 0 and
+        // 120, then apply specified opacity for Group 3
+        // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+        // Aqua, Wn High Con White, Wn High Con #1
+        // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
+        // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+        else {
+            bottom = blend(titleBg, bg, 10);
+            top = bg;
+        }
+        createColor(IFormColors.H_GRADIENT_END, top);
+        createColor(IFormColors.H_GRADIENT_START, bottom);
+    }
+
+    private void createFormHeaderKeylineColors() {
+        RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+        Color bgColor = getImpliedBackground();
+        RGB bg = bgColor.getRGB();
+        RGB keyline2;
+        // H_BOTTOM_KEYLINE1
+        createColor(IFormColors.H_BOTTOM_KEYLINE1, new RGB(255, 255, 255));
+
+        // H_BOTTOM_KEYLINE2
+        // Group 1
+        // Rule: If at least 2 of the RGB values are equal to or between 180 and
+        // 255, then apply specified opacity for Group 1
+        // Examples: Vista, XP Silver, Wn High Con #2
+        // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
+        if (testTwoPrimaryColors(titleBg, 179, 256))
+            keyline2 = blend(titleBg, bg, 70);
+
+        // Group 2
+        // Rule: If at least 2 of the RGB values are equal to or between 121 and
+        // 179, then apply specified opacity for Group 2
+        // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+        // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
+        else if (testTwoPrimaryColors(titleBg, 120, 180))
+            keyline2 = blend(titleBg, bg, 50);
+
+        // Group 3
+        // Rule: If at least 2 of the RGB values are equal to or between 0 and
+        // 120, then apply specified opacity for Group 3
+        // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+        // Aqua, Wn High Con White, Wn High Con #1
+
+        // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+        else
+            keyline2 = blend(titleBg, bg, 30);
+        // H_BOTTOM_KEYLINE2
+        createColor(IFormColors.H_BOTTOM_KEYLINE2, keyline2);
+    }
+
+    private void createFormHeaderDNDColors() {
+        RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT);
+        Color bgColor = getImpliedBackground();
+        RGB bg = bgColor.getRGB();
+        RGB light, full;
+        // ALL Themes
+        //
+        // Light Highlight
+        // When *near* the 'hot' area
+        // Rule: If near the title in the 'hot' area, show background highlight
+        // TITLE_BACKGROUND_GRADIENT @ 40%
+        light = blend(titleBg, bg, 40);
+        // Full Highlight
+        // When *on* the title area (regions 1 and 2)
+        // Rule: If near the title in the 'hot' area, show background highlight
+        // TITLE_BACKGROUND_GRADIENT @ 60%
+        full = blend(titleBg, bg, 60);
+        // H_DND_LIGHT
+        // H_DND_FULL
+        createColor(IFormColors.H_HOVER_LIGHT, light);
+        createColor(IFormColors.H_HOVER_FULL, full);
+    }
+}