Color Selection

The color selection widget is, not surprisingly, a widget for interactive selection of colors. This composite widget lets the user select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue, Saturation, Value) triples. This is done either by adjusting single values with sliders or entries, or by picking the desired color from a hue-saturation wheel/value bar. Optionally, the opacity of the color can also be set.

The color selection widget currently emits only one signal, "color_changed", which is emitted whenever the current color in the widget changes, either when the user changes it or if it's set explicitly through gtk_color_selection_set_color().

Lets have a look at what the color selection widget has to offer us. The widget comes in two flavours: gtk_color_selection and gtk_color_selection_dialog.

GtkWidget *gtk_color_selection_new( void );

You'll probably not be using this constructor directly. It creates an orphan ColorSelection widget which you'll have to parent yourself. The ColorSelection widget inherits from the VBox widget.

GtkWidget *gtk_color_selection_dialog_new( const gchar *title );

This is the most common color selection constructor. It creates a ColorSelectionDialog. It consists of a Frame containing a ColorSelection widget, an HSeparator and an HBox with three buttons, "Ok", "Cancel" and "Help". You can reach these buttons by accessing the "ok_button", "cancel_button" and "help_button" widgets in the ColorSelectionDialog structure, (i.e., GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button)).

void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel, 
                                            GtkUpdateType      policy );

This function sets the update policy. The default policy is GTK_UPDATE_CONTINUOUS which means that the current color is updated continuously when the user drags the sliders or presses the mouse and drags in the hue-saturation wheel or value bar. If you experience performance problems, you may want to set the policy to GTK_UPDATE_DISCONTINUOUS or GTK_UPDATE_DELAYED.

void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
                                      gint               use_opacity );

The color selection widget supports adjusting the opacity of a color (also known as the alpha channel). This is disabled by default. Calling this function with use_opacity set to TRUE enables opacity. Likewise, use_opacity set to FALSE will disable opacity.

void gtk_color_selection_set_color( GtkColorSelection *colorsel,
                                    gdouble           *color );

You can set the current color explicitly by calling this function with a pointer to an array of colors (gdouble). The length of the array depends on whether opacity is enabled or not. Position 0 contains the red component, 1 is green, 2 is blue and opacity is at position 3 (only if opacity is enabled, see gtk_color_selection_set_opacity()). All values are between 0.0 and 1.0.

void gtk_color_selection_get_color( GtkColorSelection *colorsel,
                                    gdouble           *color );

When you need to query the current color, typically when you've received a "color_changed" signal, you use this function. Color is a pointer to the array of colors to fill in. See the gtk_color_selection_set_color() function for the description of this array.

Here's a simple example demonstrating the use of the ColorSelectionDialog. The program displays a window containing a drawing area. Clicking on it opens a color selection dialog, and changing the color in the color selection dialog changes the background color.

/* example-start colorsel colorsel.c */

#include <glib.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>

GtkWidget *colorseldlg = NULL;
GtkWidget *drawingarea = NULL;

/* Color changed handler */

void color_changed_cb( GtkWidget         *widget,
                       GtkColorSelection *colorsel )
{
  gdouble color[3];
  GdkColor gdk_color;
  GdkColormap *colormap;

  /* Get drawingarea colormap */

  colormap = gdk_window_get_colormap (drawingarea->window);

  /* Get current color */

  gtk_color_selection_get_color (colorsel,color);

  /* Fit to a unsigned 16 bit integer (0..65535) and
   * insert into the GdkColor structure */

  gdk_color.red = (guint16)(color[0]*65535.0);
  gdk_color.green = (guint16)(color[1]*65535.0);
  gdk_color.blue = (guint16)(color[2]*65535.0);

  /* Allocate color */

  gdk_color_alloc (colormap, &gdk_color);

  /* Set window background color */

  gdk_window_set_background (drawingarea->window, &gdk_color);

  /* Clear window */

  gdk_window_clear (drawingarea->window);
}

/* Drawingarea event handler */

gint area_event( GtkWidget *widget,
                 GdkEvent  *event,
                 gpointer   client_data )
{
  gint handled = FALSE;
  GtkWidget *colorsel;

  /* Check if we've received a button pressed event */

  if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
    {
      /* Yes, we have an event and there's no colorseldlg yet! */

      handled = TRUE;

      /* Create color selection dialog */

      colorseldlg = gtk_color_selection_dialog_new("Select background color");

      /* Get the ColorSelection widget */

      colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;

      /* Connect to the "color_changed" signal, set the client-data
       * to the colorsel widget */

      gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
        (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);

      /* Show the dialog */

      gtk_widget_show(colorseldlg);
    }

  return handled;
}

/* Close down and exit handler */

gint destroy_window( GtkWidget *widget,
                     GdkEvent  *event,
                     gpointer   client_data )
{
  gtk_main_quit ();
  return(TRUE);
}

/* Main */

gint main( gint   argc,
           gchar *argv[] )
{
  GtkWidget *window;

  /* Initialize the toolkit, remove gtk-related commandline stuff */

  gtk_init (&argc,&argv);

  /* Create toplevel window, set title and policies */

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
  gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);

  /* Attach to the "delete" and "destroy" events so we can exit */

  gtk_signal_connect (GTK_OBJECT(window), "delete_event",
    (GtkSignalFunc)destroy_window, (gpointer)window);
  
  /* Create drawingarea, set size and catch button events */

  drawingarea = gtk_drawing_area_new ();

  gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);

  gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);

  gtk_signal_connect (GTK_OBJECT(drawingarea), "event", 
    (GtkSignalFunc)area_event, (gpointer)drawingarea);
  
  /* Add drawingarea to window, then show them both */

  gtk_container_add (GTK_CONTAINER(window), drawingarea);

  gtk_widget_show (drawingarea);
  gtk_widget_show (window);
  
  /* Enter the gtk main loop (this never returns) */

  gtk_main ();

  /* Satisfy grumpy compilers */

  return(0);
}
/* example-end */