Click here to Skip to main content
Click here to Skip to main content

The Known Colors Palette Tool

, 1 Dec 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
Presents a tool that assists in choosing colors from the known colors
Known Colors Palette

Introduction

Colors are the breath of the Internet. This article discusses some color palettes and then describes a tool that may be used to choose appropriate colors for a web page.

Background

Color History

In the early history of computing, color was not an important attribute of a successful application. Most computer terminals had a green or amber display. Furthermore, most terminals were text oriented, displaying a fixed number of characters per row and a fixed number of rows per screen. In large part, most of the applications that ran on computer terminals were command line interpreters, text editors, and modem control applications. Although there were graphical terminals available, they were very expensive and used only in specialized environments.

In 1973, the Xerox Palo Alto Research Center (PARC) developed the personal workstation, the forerunner of the modern personal computer. In 1975, PARC introduced the Graphical User Interface, with its familiar desktop and icons. To support these Parc developed bit-mapped graphics.

In 1981, with the introduction of the personal computer, IBM also introduced the Computer Graphics Adapter (CGA), sixteen colors became available to the application developer.

CGA Color Palette

In 1984, IBM introduced the Enhanced Graphics Adapter (EGA) with 64 colors.

EGA Color Palette

Then, in 1987, IBM introduced the Video Graphics Array (VGA). The VGA palette provided 256 colors.

Default VGA Palette

With the introduction of X windows, a palette, known as the X11 color names became available. The most important distinction between the X11 color names and the earlier color palettes was the ability to choose a color by specifying either its name or its RGB triplet.

Finally, with the introduction of .NET Framework 1.1, the Known Colors Palette was formalized by Microsoft. Although this palette includes some colors used by Microsoft to display various system entities (e.g., ActiveBorder, AppWorkspace, Control Dark, etc.), during the enumeration of the known colors, we can exclude these Microsoft system colors.

Need

While testing the Color Hit Testing User Control, I required a test image. I decided that a display of the US Time Zones would suffice. Because I was preparing the article for viewing on the Internet, I decided to color the image with the known colors.

I was using Microsoft Paint to create the image. During the image preparation, I stumbled across a couple of limitations in that tool's Colors?Edit Colors... dialog:

  • The colors that are displayed are not the known colors.
  • The colors that are initially displayed are not the known colors.
  • The dialog does not display a color name when the mouse hovers over the color.

To solve these two problems, I built the Known Colors Palette Tool. The requirements levied against the tool included:

  • The colors that are displayed are to be the known colors.
  • When the mouse hovers over a color swatch, the color name is to be displayed.
  • The colors may be sorted either by known color name or by the known colors' ARGB values.
  • When the mouse clicks on a color swatch, the ARGB value of the known color shall be displayed along with the individual ARGB component values.
  • A context menu shall be provided that allows the user to perform the sorts, keep the tool on top, and allow the appropriate color information to be copied to the Clipboard.

Known Colors Palette Tool

The Known Colors Palette Tool is based upon the KnownColor Enumeration that is provided by Microsoft as part of the System.Drawing assembly. Microsoft's enumeration, with the exception of the system colors, is equivalent to the CSS color names. During the enumeration of the Microsoft known color names, those known colors that are Microsoft system colors are excluded.

  // ************************** get_known_colors_from_Microsoft

  // http://www.dreamincode.net/code/snippet1405.htm

  private List < Color > get_known_colors_from_Microsoft ( )
      {
      List < Color >  colors = new List<Color> ( );
      string [ ]      color_names = 
                          Enum.GetNames ( typeof ( 
                                              KnownColor ) );

      foreach ( string color_name in color_names )
          {
          KnownColor known_color = ( KnownColor ) Enum.Parse ( 
                                       typeof ( KnownColor ), 
                                       color_name );

          if ( ( known_color > KnownColor.Transparent ) &&
               ( known_color < KnownColor.ButtonFace ) )
              {
              colors.Add ( Color.FromName ( color_name ) );
              }
          }

      return ( colors );
      }

The first task, after the colors are enumerated, is to create two panels, one to display the colors by name, the other to display the colors by ARGB. Both panels are created and then hidden. I create two separate panels to improve performance when switching between the two displays.

  // ****************************** create_colors_by_name_panel

  private void create_colors_by_name_panel ( )
      {
      NameComparer  nc = new NameComparer ( );

      known_colors.Sort ( nc );
      colors_by_name_panel = populate_panel ( );
      this.Controls.Add ( colors_by_name_panel );
      colors_by_name_panel.Visible = false;
      }

  // ****************************** create_colors_by_ARGB_panel

  private void create_colors_by_ARGB_panel ( )
      {
      ARGBComparer  ac = new ARGBComparer ( );

      known_colors.Sort ( ac );
      colors_by_ARGB_panel = populate_panel ( );
      this.Controls.Add ( colors_by_ARGB_panel );
      colors_by_ARGB_panel.Visible = false;
      }

Two classes, NameComparer and ARGBComparer, were implemented to perform the comparisons.

  // ******************************************* class NameComparer

  public class NameComparer : IComparer < Color >
      {

      // ************************************************** Compare

      public int Compare ( Color color_1,
                           Color color_2 )
          {

          if ( color_1 == null )
              {
              if ( color_2 == null )
                  {
                                      // If color_1 is null and 
                                      // color_2 is null, they're
                                      // equal 
                  return ( 0 );
                  }
              else
                  {
                                      // If color_1 is null and 
                                      // color_2 is not null, 
                                      // color_2 is greater. 
                  return ( -1 );
                  }
              }
          else
              {
                                      // If color_1 is not null...
              if ( color_2 == null )
                                      // ...and color_2 is null, 
                                      // color_1 is greater.
                  {
                  return ( 1 );
                  }
              else
                  {
                                      // ...and color_2 is not 
                                      // null, compare the names
                                      // of the two colors
                  return ( color_1.Name.CompareTo ( 
                               color_2.Name ) );
                  }
              }
          }
          
      } // class NameComparer

  // ******************************************* class ARGBComparer

  public class ARGBComparer : IComparer < Color >
      {

      // ************************************************** Compare

      public int Compare ( Color  color_1,
                           Color  color_2 )
          {

          if ( color_1 == null )
              {
              if ( color_2 == null )
                  {
                                      // If color_1 is null and 
                                      // color_2 is null, they're
                                      // equal 
                  return ( 0 );
                  }
              else
                  {
                                      // If color_1 is null and 
                                      // color_2 is not null, 
                                      // color_2 is greater. 
                  return ( -1 );
                  }
              }
          else
              {
                                      // If color_1 is not null...
              if ( color_2 == null )
                                      // ...and color_2 is null, 
                                      // color_1 is greater.
                  {
                  return ( 1 );
                  }
              else
                  {
                                      // ...and color_2 is not 
                                      // null, compare the ARGBs
                                      // of the two colors
                  uint  ARGB_1;
                  uint  ARGB_2;

                  ARGB_1 = Utilities.ColorToUIntARGB ( color_1 );
                  ARGB_2 = Utilities.ColorToUIntARGB ( color_2 );
                  
                  return ( ARGB_1.CompareTo ( ARGB_2 ) );
                  }
              }
          }
          
      } // class ARGBComparer

When the known colors list is sorted, it is used to populate the panel.

  // ******************************************* populate_panel

  private Panel populate_panel ( )
      {
      Point   color_square_location;
      Size    color_square_size;
      int     column = 0;
      Panel   panel = new Panel ( );

      panel.Location = new Point ( PANEL_LEFT, PANEL_TOP );
      panel.Size = new Size ( PANEL_WIDTH, PANEL_HEIGHT );
      
      color_square_location = new Point ( INITIAL_LEFT, 
                                          INITIAL_TOP );
      color_square_size = new Size ( COLOR_SQUARE_EDGE,
                                     COLOR_SQUARE_EDGE );

      foreach ( Color color in known_colors )
          {
          Button   color_square = new Button ( );
          ToolTip  tooltip = new ToolTip ( );

          color_square.Location = color_square_location;
          color_square.Size = color_square_size;
          color_square.BackColor = color;
          color_square.Click += new System.EventHandler (
                                    color_square_BUT_Click );
          tooltip.SetToolTip ( color_square, color.Name );
          tooltip.AutomaticDelay = TOOLTIP_DELAY;
          
          panel.Controls.Add ( color_square );
          column++;

          if ( column >= COLOR_SQUARES_PER_ROW )
              {
              column = 0;
              
              color_square_location.X = INITIAL_LEFT;
              color_square_location.Y += 
                  COLOR_SQUARE_EDGE + COLOR_SQUARE_SEPARATION;
              }
          else
              {
              color_square_location.X +=
                  COLOR_SQUARE_EDGE + COLOR_SQUARE_SEPARATION;
              }
          }
      
      return ( panel );
      }

On initialization, the variable sort_by_name is true and the colors by name panel is displayed.

  // ******************************************* initialize_GUI

  private void initialize_GUI ( )
      {

      if ( sort_by_name )
          {
          byNameToolStripMenuItem.Checked = true;
          sortByNameToolStripMenuItem.Checked = true;
          byARGBToolStripMenuItem.Checked = false;
          sortByARGBToolStripMenuItem.Checked = false;
          
          colors_by_name_panel.Visible = true;
          colors_by_ARGB_panel.Visible = false;
          }
      else
          {
          byNameToolStripMenuItem.Checked = false;
          sortByNameToolStripMenuItem.Checked = false;
          byARGBToolStripMenuItem.Checked = true;
          sortByARGBToolStripMenuItem.Checked = true;
          
          colors_by_name_panel.Visible = false;
          colors_by_ARGB_panel.Visible = true;
          }
      }

If the user toggles the display, the variable sort_by_name becomes false and the colors by ARGB panel is displayed.

When a color is selected, the information about the color is displayed.

Known Color Selected

Once a color is selected, either clicking on the color swatch or pressing Ctrl-S causes the color information to be copied to the Clipboard. For the known color DarkRed, the information copied to the Clipboard is:

{Name=DarkRed,ARGB=(255,139,0,0)=#FF8B0000=(FF,8B,00,00)} 

Although the transfer to the Clipboard is not the same as setting the color in Microsoft Paint, it does provide a means by which the data can be captured and copied into Microsoft Paint. If I can figure out how to subclass Microsoft Paint, I will revise the Know Colors Palette Tool to interact directly with Microsoft Paint. Any suggestions for this upgrade would be appreciated.

Revision

As pointed out by a reader, the screen resolution at tool development may not be the same as the screen resolution at tool execution. What looks fine at 1024x768 may not look very well at other resolutions. What is worse is that the tool may become useless as the tool shrinks at higher resolutions.

To address this issue, I redeveloped the tool at a screen resolution of 800x600. Once that was completed, I added code to initialize two screen resolution multipliers, one for horizontal, the other for vertical adjustment.

  // ************************ initialize_resolution_multipliers

  private void initialize_resolution_multipliers ( )
      {
      
      if ( ( SystemInformation.PrimaryMonitorSize.Height >
             CREATED_IN_SCREEN_HEIGHT ) ||
           ( SystemInformation.PrimaryMonitorSize.Width >
             CREATED_IN_SCREEN_WIDTH ) ) 
          {
          screen_height_multiplier = 
              ( float ) SystemInformation.
                            PrimaryMonitorSize.Height /
              ( float ) CREATED_IN_SCREEN_HEIGHT;
          screen_height_multiplier *= 4.0F;
          screen_height_multiplier /= 5.0F;

          screen_width_multiplier = 
              ( float ) SystemInformation.
                            PrimaryMonitorSize.Width /
              ( float ) CREATED_IN_SCREEN_WIDTH;
          screen_width_multiplier *= 4.0F;
          screen_width_multiplier /= 5.0F;

          color_square_edge = 
              ( int ) ( ( float ) color_square_edge * 
                        screen_width_multiplier );
          color_square_separation = 
              ( int ) ( ( float ) color_square_separation * 
                        screen_width_multiplier );

          resolution_changed = true;
          }
      }

In addition to the multipliers, two global variables, color_square_edge and color_square_separation are assigned adjusted values. These two variables replace the constants COLOR_SQUARE_EDGE and COLOR_SQUARE_SEPARATION in the populate_panel method (see above).

Once these multipliers are initialized (note both will be 1.0F if the execution resolution is 800x600), the actual adjustment waits for the Load event to fire, that, in turn, executes the adjust_GUI_to_resolution method.

  // ********************************** KnownColorsPalette_Load

  private void KnownColorsPalette_Load ( object       sender, 
                                         EventArgs    e )
      {
      adjust_GUI_to_resolution ( );
      }

If the execution resolution is different from the execution resolution (i.e., the variable resolution_changed is true), the adjust_GUI_to_resolution method modifies the location, size, and font size of each control.

  // ********************************* adjust_GUI_to_resolution

  // http://cshark.wordpress.com/2009/06/01/
  //    how-to-change-form-size-depending-on-screen-resolution/

  private void adjust_GUI_to_resolution ( )
      {
      
      if ( resolution_changed ) 
          {
          float   font_size;
          int     height;
          int     width;
          float   x;
          float   y;

          font_size = this.Font.Size * 
                      screen_height_multiplier;
          height = ( int ) ( ( float ) this.Height * 
                             screen_height_multiplier );
          width = ( int ) ( ( float ) this.Width * 
                            screen_height_multiplier );
          x = this.Location.X * screen_width_multiplier;
          y = this.Location.Y * screen_height_multiplier;
          
          this.Height = height;
          this.Width = width;
          this.Font = new Font ( this.Font.FontFamily, 
                                 font_size, 
                                 this.Font.Style );

          foreach ( Control control in this.Controls )
              {
              font_size = control.Font.Size * 
                          screen_height_multiplier;
              height = ( int ) ( ( float ) control.Height * 
                                 screen_height_multiplier );
              width = ( int ) ( ( float ) control.Width * 
                                screen_height_multiplier );
              x = control.Location.X * screen_width_multiplier;
              y = control.Location.Y * screen_height_multiplier;

              control.Width = ( int ) Math.Ceiling ( ( double ) width );
              control.Height = ( int ) Math.Ceiling ( ( double ) height );
              control.Location = new Point ( ( int ) x, 
                                             ( int ) y );
              control.Font = new Font ( control.Font.FontFamily, 
                                        ( int ) font_size, 
                                        control.Font.Style );
              }                
          } 
      }

There is a problem with the font size of tooltips and menu items that I am still researching. When I have a solution, I will again revise this article.

References

History

  • 11/26/2010 - Revised article to address reader's comments and correct typographic and logic errors
  • 11/29/2010 - Revised the tool such that it reacts to execution screen resolutions that differ from the development resolution

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

gggustafson
Software Developer (Senior)
United States United States
I started programming more than 42 years ago using AutoCoder and RPG (note no suffixing numbers). Programs and data were entered using punched cards. Turnaround between submitting a job for compilation and execution was about 3 hours. So much for the "good old days!" Today, I particularly enjoy programming real-time software. I consider myself capable in WinForms, Mobile Apps, and C# although there are occasions that I yearn to return to C and the Win32 API.

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermanoj kumar choubey20-Feb-12 21:34 
Generalnice one PinmemberPranay Rana17-Jan-11 0:57 
GeneralOn selection of colors PinmemberSergeyAndreyev26-Nov-10 21:17 
AnswerRe: On selection of colors Pinmembergggustafson27-Nov-10 10:10 
GeneralRe: On selection of colors PinmemberSergeyAndreyev27-Nov-10 21:20 
GeneralRe: On selection of colors Pinmembergggustafson29-Nov-10 15:01 
GeneralMy vote of 1 PinmvpDave Kreskowiak3-May-10 8:40 
GeneralRe: My vote of 1 Pinmembergggustafson3-May-10 10:51 
QuestionRe: My vote of 1 Pinmembergggustafson1-Dec-10 4:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141022.2 | Last Updated 1 Dec 2010
Article Copyright 2010 by gggustafson
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid