1 package org
.argeo
.cms
.ui
.eclipse
.forms
;
3 import java
.util
.HashMap
;
6 import org
.eclipse
.jface
.resource
.JFaceResources
;
7 import org
.eclipse
.jface
.resource
.LocalResourceManager
;
8 import org
.eclipse
.swt
.SWT
;
9 import org
.eclipse
.swt
.graphics
.Color
;
10 import org
.eclipse
.swt
.graphics
.RGB
;
11 //import org.eclipse.swt.internal.graphics.Graphics;
12 import org
.eclipse
.swt
.widgets
.Display
;
15 * Manages colors that will be applied to forms and form widgets. The colors are
16 * chosen to make the widgets look correct in the editor area. If a different
17 * set of colors is needed, subclass this class and override 'initialize' and/or
22 public class FormColors
{
24 * Key for the form title foreground color.
26 * @deprecated use <code>IFormColors.TITLE</code>.
28 public static final String TITLE
= IFormColors
.TITLE
;
31 * Key for the tree/table border color.
33 * @deprecated use <code>IFormColors.BORDER</code>
35 public static final String BORDER
= IFormColors
.BORDER
;
38 * Key for the section separator color.
40 * @deprecated use <code>IFormColors.SEPARATOR</code>.
42 public static final String SEPARATOR
= IFormColors
.SEPARATOR
;
45 * Key for the section title bar background.
47 * @deprecated use <code>IFormColors.TB_BG
49 public static final String TB_BG
= IFormColors
.TB_BG
;
52 * Key for the section title bar foreground.
54 * @deprecated use <code>IFormColors.TB_FG</code>
56 public static final String TB_FG
= IFormColors
.TB_FG
;
59 * Key for the section title bar gradient.
61 * @deprecated use <code>IFormColors.TB_GBG</code>
63 public static final String TB_GBG
= IFormColors
.TB_GBG
;
66 * Key for the section title bar border.
68 * @deprecated use <code>IFormColors.TB_BORDER</code>.
70 public static final String TB_BORDER
= IFormColors
.TB_BORDER
;
73 * Key for the section toggle color. Since 3.1, this color is used for all
76 * @deprecated use <code>IFormColors.TB_TOGGLE</code>.
78 public static final String TB_TOGGLE
= IFormColors
.TB_TOGGLE
;
81 * Key for the section toggle hover color.
83 * @deprecated use <code>IFormColors.TB_TOGGLE_HOVER</code>.
85 public static final String TB_TOGGLE_HOVER
= IFormColors
.TB_TOGGLE_HOVER
;
87 protected Map colorRegistry
= new HashMap(10);
89 private LocalResourceManager resources
;
91 protected Color background
;
93 protected Color foreground
;
95 private boolean shared
;
97 protected Display display
;
99 protected Color border
;
102 * Creates form colors using the provided display.
107 public FormColors(Display display
) {
108 this.display
= display
;
113 * Returns the display used to create colors.
115 * @return the display
117 public Display
getDisplay() {
122 * Initializes the colors. Subclasses can override this method to change the
123 * way colors are created. Alternatively, only the color table can be
124 * modified by overriding <code>initializeColorTable()</code>.
126 * @see #initializeColorTable
128 protected void initialize() {
129 background
= display
.getSystemColor(SWT
.COLOR_LIST_BACKGROUND
);
130 foreground
= display
.getSystemColor(SWT
.COLOR_LIST_FOREGROUND
);
131 initializeColorTable();
136 * Allocates colors for the following keys: BORDER, SEPARATOR and
137 * TITLE. Subclasses can override to allocate these colors differently.
139 protected void initializeColorTable() {
141 createColor(IFormColors
.SEPARATOR
, getColor(IFormColors
.TITLE
).getRGB());
142 RGB black
= getSystemColor(SWT
.COLOR_BLACK
);
143 RGB borderRGB
= getSystemColor(SWT
.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT
);
144 createColor(IFormColors
.BORDER
, blend(borderRGB
, black
, 80));
148 * Allocates colors for the section tool bar (all the keys that start with
149 * TB). Since these colors are only needed when TITLE_BAR style is used with
150 * the Section widget, they are not needed all the time and are allocated on
151 * demand. Consequently, this method will do nothing if the colors have been
152 * already initialized. Call this method prior to using colors with the TB
153 * keys to ensure they are available.
155 public void initializeSectionToolBarColors() {
156 if (colorRegistry
.containsKey(IFormColors
.TB_BG
))
158 createTitleBarGradientColors();
159 createTitleBarOutlineColors();
160 createTwistieColors();
164 * Allocates additional colors for the form header, namely background
165 * gradients, bottom separator keylines and DND highlights. Since these
166 * colors are only needed for clients that want to use these particular
167 * style of header rendering, they are not needed all the time and are
168 * allocated on demand. Consequently, this method will do nothing if the
169 * colors have been already initialized. Call this method prior to using
170 * color keys with the H_ prefix to ensure they are available.
172 protected void initializeFormHeaderColors() {
173 if (colorRegistry
.containsKey(IFormColors
.H_BOTTOM_KEYLINE2
))
175 createFormHeaderColors();
179 * Returns the RGB value of the system color represented by the code
180 * argument, as defined in <code>SWT</code> class.
183 * the system color constant as defined in <code>SWT</code>
185 * @return the RGB value of the system color
187 public RGB
getSystemColor(int code
) {
188 return getDisplay().getSystemColor(code
).getRGB();
192 * Creates the color for the specified key using the provided RGB object.
193 * The color object will be returned and also put into the registry. When
194 * the class is disposed, the color will be disposed with it.
197 * the unique color key
200 * @return the allocated color object
202 public Color
createColor(String key
, RGB rgb
) {
203 // RAP [rh] changes due to missing Color constructor
204 // Color c = getResourceManager().createColor(rgb);
205 // Color prevC = (Color) colorRegistry.get(key);
206 // if (prevC != null && !prevC.isDisposed())
207 // getResourceManager().destroyColor(prevC.getRGB());
208 // Color c = Graphics.getColor(rgb);
209 Color c
= new Color(display
, rgb
);
210 colorRegistry
.put(key
, c
);
215 * Creates a color that can be used for areas of the form that is inactive.
216 * These areas can contain images, links, controls and other content but are
217 * considered auxilliary to the main content area.
220 * The color should not be disposed because it is managed by this class.
222 * @return the inactive form color
224 public Color
getInactiveBackground() {
225 String key
= "__ncbg__"; //$NON-NLS-1$
226 Color color
= getColor(key
);
228 RGB sel
= getSystemColor(SWT
.COLOR_LIST_SELECTION
);
229 // a blend of 95% white and 5% list selection system color
230 RGB ncbg
= blend(sel
, getSystemColor(SWT
.COLOR_WHITE
), 5);
231 color
= createColor(key
, ncbg
);
237 * Creates the color for the specified key using the provided RGB values.
238 * The color object will be returned and also put into the registry. If
239 * there is already another color object under the same key in the registry,
240 * the existing object will be disposed. When the class is disposed, the
241 * color will be disposed with it.
244 * the unique color key
251 * @return the allocated color object
253 public Color
createColor(String key
, int r
, int g
, int b
) {
254 return createColor(key
, new RGB(r
,g
,b
));
258 * Computes the border color relative to the background. Allocated border
259 * color is designed to work well with white. Otherwise, stanard widget
260 * background color will be used.
262 protected void updateBorderColor() {
263 if (isWhiteBackground())
264 border
= getColor(IFormColors
.BORDER
);
266 border
= display
.getSystemColor(SWT
.COLOR_WIDGET_BACKGROUND
);
267 Color bg
= getImpliedBackground();
268 if (border
.getRed() == bg
.getRed()
269 && border
.getGreen() == bg
.getGreen()
270 && border
.getBlue() == bg
.getBlue())
271 border
= display
.getSystemColor(SWT
.COLOR_WIDGET_DARK_SHADOW
);
276 * Sets the background color. All the toolkits that use this class will
277 * share the same background.
282 public void setBackground(Color bg
) {
283 this.background
= bg
;
285 updateFormHeaderColors();
289 * Sets the foreground color. All the toolkits that use this class will
290 * share the same foreground.
295 public void setForeground(Color fg
) {
296 this.foreground
= fg
;
300 * Returns the current background color.
302 * @return the background color
304 public Color
getBackground() {
309 * Returns the current foreground color.
311 * @return the foreground color
313 public Color
getForeground() {
318 * Returns the computed border color. Border color depends on the background
319 * and is recomputed whenever the background changes.
321 * @return the current border color
323 public Color
getBorderColor() {
328 * Tests if the background is white. White background has RGB value
331 * @return <samp>true</samp> if background is white, <samp>false</samp>
334 public boolean isWhiteBackground() {
335 Color bg
= getImpliedBackground();
336 return bg
.getRed() == 255 && bg
.getGreen() == 255
337 && bg
.getBlue() == 255;
341 * Returns the color object for the provided key or <samp>null </samp> if
342 * not in the registry.
346 * @return color object if found, or <samp>null </samp> if not.
348 public Color
getColor(String key
) {
349 if (key
.startsWith(IFormColors
.TB_PREFIX
))
350 initializeSectionToolBarColors();
351 else if (key
.startsWith(IFormColors
.H_PREFIX
))
352 initializeFormHeaderColors();
353 return (Color
) colorRegistry
.get(key
);
357 * Disposes all the colors in the registry.
359 public void dispose() {
360 if (resources
!= null)
363 colorRegistry
= null;
367 * Marks the colors shared. This prevents toolkits that share this object
370 public void markShared() {
375 * Tests if the colors are shared.
377 * @return <code>true</code> if shared, <code>false</code> otherwise.
379 public boolean isShared() {
384 * Blends c1 and c2 based in the provided ratio.
391 * percentage of the first color in the blend (0-100)
392 * @return the RGB value of the blended color
394 public static RGB
blend(RGB c1
, RGB c2
, int ratio
) {
395 int r
= blend(c1
.red
, c2
.red
, ratio
);
396 int g
= blend(c1
.green
, c2
.green
, ratio
);
397 int b
= blend(c1
.blue
, c2
.blue
, ratio
);
398 return new RGB(r
, g
, b
);
402 * Tests the source RGB for range.
407 * range start (excluding the value itself)
409 * range end (excluding the value itself)
410 * @return <code>true</code> if at least one of the primary colors in the
411 * source RGB are within the provided range, <code>false</code>
414 public static boolean testAnyPrimaryColor(RGB rgb
, int from
, int to
) {
415 if (testPrimaryColor(rgb
.red
, from
, to
))
417 if (testPrimaryColor(rgb
.green
, from
, to
))
419 if (testPrimaryColor(rgb
.blue
, from
, to
))
425 * Tests the source RGB for range.
430 * range start (excluding the value itself)
432 * tange end (excluding the value itself)
433 * @return <code>true</code> if at least two of the primary colors in the
434 * source RGB are within the provided range, <code>false</code>
437 public static boolean testTwoPrimaryColors(RGB rgb
, int from
, int to
) {
439 if (testPrimaryColor(rgb
.red
, from
, to
))
441 if (testPrimaryColor(rgb
.green
, from
, to
))
443 if (testPrimaryColor(rgb
.blue
, from
, to
))
449 * Blends two primary color components based on the provided ratio.
456 * percentage of the first component in the blend
459 private static int blend(int v1
, int v2
, int ratio
) {
460 int b
= (ratio
* v1
+ (100 - ratio
) * v2
) / 100;
461 return Math
.min(255, b
);
464 private Color
getImpliedBackground() {
465 if (getBackground() != null)
466 return getBackground();
467 return getDisplay().getSystemColor(SWT
.COLOR_WIDGET_BACKGROUND
);
470 private static boolean testPrimaryColor(int value
, int from
, int to
) {
471 return value
> from
&& value
< to
;
474 private void createTitleColor() {
476 * RGB rgb = getSystemColor(SWT.COLOR_LIST_SELECTION); // test too light
477 * if (testTwoPrimaryColors(rgb, 120, 151)) rgb = blend(rgb, BLACK, 80);
478 * else if (testTwoPrimaryColors(rgb, 150, 256)) rgb = blend(rgb, BLACK,
479 * 50); createColor(TITLE, rgb);
481 RGB bg
= getImpliedBackground().getRGB();
482 RGB listSelection
= getSystemColor(SWT
.COLOR_LIST_SELECTION
);
483 RGB listForeground
= getSystemColor(SWT
.COLOR_LIST_FOREGROUND
);
484 RGB rgb
= listSelection
;
487 // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
488 // between 0 and 120, then use 100% LIST_SELECTION as it is (no
490 // Examples: XP Default, Win Classic Standard, Win High Con White, Win
492 if (testTwoPrimaryColors(listSelection
, -1, 121))
495 // When LIST_BACKGROUND = white (255, 255, 255) or not black, text
496 // colour = LIST_SELECTION @ 100% Opacity + 50% LIST_FOREGROUND over
498 // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
499 // between 121 and 255, then add 50% LIST_FOREGROUND to LIST_SELECTION
501 // Examples: Win Vista, XP Silver, XP Olive , Win Classic Plum, OSX
502 // Aqua, OSX Graphite, Linux GTK
503 else if (testTwoPrimaryColors(listSelection
, 120, 256)
504 || (bg
.red
== 0 && bg
.green
== 0 && bg
.blue
== 0))
505 rgb
= blend(listSelection
, listForeground
, 50);
507 // When LIST_BACKGROUND = black (0, 0, 0), text colour = LIST_SELECTION
508 // @ 100% Opacity + 50% LIST_FOREGROUND over LIST_BACKGROUND
509 // Rule: If LIST_BACKGROUND = 0, 0, 0, then add 50% LIST_FOREGROUND to
510 // LIST_SELECTION foreground colour
511 // Examples: Win High Con Black, Win High Con #1, Win High Con #2
512 // (covered in the second part of the OR clause above)
513 createColor(IFormColors
.TITLE
, rgb
);
516 private void createTwistieColors() {
517 RGB rgb
= getColor(IFormColors
.TITLE
).getRGB();
518 RGB white
= getSystemColor(SWT
.COLOR_WHITE
);
519 createColor(TB_TOGGLE
, rgb
);
520 rgb
= blend(rgb
, white
, 60);
521 createColor(TB_TOGGLE_HOVER
, rgb
);
524 private void createTitleBarGradientColors() {
525 RGB tbBg
= getSystemColor(SWT
.COLOR_TITLE_BACKGROUND
);
526 RGB bg
= getImpliedBackground().getRGB();
529 // Rule: If at least 2 of the RGB values are equal to or between 180 and
530 // 255, then apply specified opacity for Group 1
531 // Examples: Vista, XP Silver, Wn High Con #2
532 // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
533 // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
534 if (testTwoPrimaryColors(tbBg
, 179, 256))
535 tbBg
= blend(tbBg
, bg
, 30);
538 // Rule: If at least 2 of the RGB values are equal to or between 121 and
539 // 179, then apply specified opacity for Group 2
540 // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
541 // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
542 // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
543 else if (testTwoPrimaryColors(tbBg
, 120, 180))
544 tbBg
= blend(tbBg
, bg
, 20);
547 // Rule: Everything else
548 // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
549 // Aqua, Wn High Con White, Wn High Con #1
550 // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
551 // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
553 tbBg
= blend(tbBg
, bg
, 10);
556 createColor(IFormColors
.TB_BG
, tbBg
);
558 // for backward compatibility
559 createColor(TB_GBG
, tbBg
);
562 private void createTitleBarOutlineColors() {
563 // title bar outline - border color
564 RGB tbBorder
= getSystemColor(SWT
.COLOR_TITLE_BACKGROUND
);
565 RGB bg
= getImpliedBackground().getRGB();
567 // Rule: If at least 2 of the RGB values are equal to or between 180 and
568 // 255, then apply specified opacity for Group 1
569 // Examples: Vista, XP Silver, Wn High Con #2
570 // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
571 if (testTwoPrimaryColors(tbBorder
, 179, 256))
572 tbBorder
= blend(tbBorder
, bg
, 70);
575 // Rule: If at least 2 of the RGB values are equal to or between 121 and
576 // 179, then apply specified opacity for Group 2
577 // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
579 // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
580 else if (testTwoPrimaryColors(tbBorder
, 120, 180))
581 tbBorder
= blend(tbBorder
, bg
, 50);
584 // Rule: Everything else
585 // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
586 // Aqua, Wn High Con White, Wn High Con #1
588 // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
590 tbBorder
= blend(tbBorder
, bg
, 30);
592 createColor(FormColors
.TB_BORDER
, tbBorder
);
595 private void updateFormHeaderColors() {
596 if (colorRegistry
.containsKey(IFormColors
.H_GRADIENT_END
)) {
597 disposeIfFound(IFormColors
.H_GRADIENT_END
);
598 disposeIfFound(IFormColors
.H_GRADIENT_START
);
599 disposeIfFound(IFormColors
.H_BOTTOM_KEYLINE1
);
600 disposeIfFound(IFormColors
.H_BOTTOM_KEYLINE2
);
601 disposeIfFound(IFormColors
.H_HOVER_LIGHT
);
602 disposeIfFound(IFormColors
.H_HOVER_FULL
);
603 initializeFormHeaderColors();
607 private void disposeIfFound(String key
) {
608 Color color
= getColor(key
);
610 colorRegistry
.remove(key
);
611 // RAP [rh] changes due to missing Color#dispose()
616 private void createFormHeaderColors() {
617 createFormHeaderGradientColors();
618 createFormHeaderKeylineColors();
619 createFormHeaderDNDColors();
622 private void createFormHeaderGradientColors() {
623 RGB titleBg
= getSystemColor(SWT
.COLOR_TITLE_BACKGROUND
);
624 Color bgColor
= getImpliedBackground();
625 RGB bg
= bgColor
.getRGB();
628 // Rule: If at least 2 of the RGB values are equal to or between 180 and
629 // 255, then apply specified opacity for Group 1
630 // Examples: Vista, XP Silver, Wn High Con #2
631 // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
632 // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
633 if (testTwoPrimaryColors(titleBg
, 179, 256)) {
634 bottom
= blend(titleBg
, bg
, 30);
639 // Rule: If at least 2 of the RGB values are equal to or between 121 and
640 // 179, then apply specified opacity for Group 2
641 // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
642 // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
643 // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
644 else if (testTwoPrimaryColors(titleBg
, 120, 180)) {
645 bottom
= blend(titleBg
, bg
, 20);
650 // Rule: If at least 2 of the RGB values are equal to or between 0 and
651 // 120, then apply specified opacity for Group 3
652 // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
653 // Aqua, Wn High Con White, Wn High Con #1
654 // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
655 // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
657 bottom
= blend(titleBg
, bg
, 10);
660 createColor(IFormColors
.H_GRADIENT_END
, top
);
661 createColor(IFormColors
.H_GRADIENT_START
, bottom
);
664 private void createFormHeaderKeylineColors() {
665 RGB titleBg
= getSystemColor(SWT
.COLOR_TITLE_BACKGROUND
);
666 Color bgColor
= getImpliedBackground();
667 RGB bg
= bgColor
.getRGB();
670 createColor(IFormColors
.H_BOTTOM_KEYLINE1
, new RGB(255, 255, 255));
674 // Rule: If at least 2 of the RGB values are equal to or between 180 and
675 // 255, then apply specified opacity for Group 1
676 // Examples: Vista, XP Silver, Wn High Con #2
677 // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
678 if (testTwoPrimaryColors(titleBg
, 179, 256))
679 keyline2
= blend(titleBg
, bg
, 70);
682 // Rule: If at least 2 of the RGB values are equal to or between 121 and
683 // 179, then apply specified opacity for Group 2
684 // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
685 // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
686 else if (testTwoPrimaryColors(titleBg
, 120, 180))
687 keyline2
= blend(titleBg
, bg
, 50);
690 // Rule: If at least 2 of the RGB values are equal to or between 0 and
691 // 120, then apply specified opacity for Group 3
692 // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
693 // Aqua, Wn High Con White, Wn High Con #1
695 // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
697 keyline2
= blend(titleBg
, bg
, 30);
699 createColor(IFormColors
.H_BOTTOM_KEYLINE2
, keyline2
);
702 private void createFormHeaderDNDColors() {
703 RGB titleBg
= getSystemColor(SWT
.COLOR_TITLE_BACKGROUND_GRADIENT
);
704 Color bgColor
= getImpliedBackground();
705 RGB bg
= bgColor
.getRGB();
710 // When *near* the 'hot' area
711 // Rule: If near the title in the 'hot' area, show background highlight
712 // TITLE_BACKGROUND_GRADIENT @ 40%
713 light
= blend(titleBg
, bg
, 40);
715 // When *on* the title area (regions 1 and 2)
716 // Rule: If near the title in the 'hot' area, show background highlight
717 // TITLE_BACKGROUND_GRADIENT @ 60%
718 full
= blend(titleBg
, bg
, 60);
721 createColor(IFormColors
.H_HOVER_LIGHT
, light
);
722 createColor(IFormColors
.H_HOVER_FULL
, full
);
725 private LocalResourceManager
getResourceManager() {
726 if (resources
== null)
727 resources
= new LocalResourceManager(JFaceResources
.getResources());