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: GtkColorSelection and GtkColorSelectionDialog.

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_has_opacity_control( GtkColorSelection *colorsel,
                                                  gboolean           has_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 has_opacity set to TRUE enables opacity. Likewise, has_opacity set to FALSE will disable opacity.

void gtk_color_selection_set_current_color( GtkColorSelection *colorsel,
                                            GdkColor          *color );

void gtk_color_selection_set_current_alpha( GtkColorSelection *colorsel,
                                            guint16            alpha );

You can set the current color explicitly by calling gtk_color_selection_set_current_color() with a pointer to a GdkColor. Setting the opacity (alpha channel) is done with gtk_color_selection_set_current_alpha(). The alpha value should be between 0 (fully transparent) and 65636 (fully opaque).

void gtk_color_selection_get_current_color( GtkColorSelection *colorsel,
	                                    GdkColor *color );

void gtk_color_selection_get_current_alpha( GtkColorSelection *colorsel,
                                            guint16           *alpha );

When you need to query the current color, typically when you've received a "color_changed" signal, you use these functions.

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.


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

GtkWidget *colorseldlg = NULL;
GtkWidget *drawingarea = NULL;
GdkColor color;

/* Color changed handler */

void color_changed_cb( GtkWidget         *widget,
                       GtkColorSelection *colorsel )
{
  GdkColor ncolor;

  gtk_color_selection_get_current_color (colorsel, &ncolor);
  gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &ncolor);       
}

/* Drawingarea event handler */

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

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

  if (event->type == GDK_BUTTON_PRESS)
    {
      handled = TRUE;

       /* Create color selection dialog */
      if (colorseldlg == NULL)
        colorseldlg = gtk_color_selection_dialog_new ("Select background color");

      /* Get the ColorSelection widget */
      colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (colorseldlg)->colorsel);

      gtk_color_selection_set_previous_color (colorsel, &color);
      gtk_color_selection_set_current_color (colorsel, &color);
      gtk_color_selection_set_has_palette (colorsel, TRUE);

      /* Connect to the "color_changed" signal, set the client-data
       * to the colorsel widget */
      g_signal_connect (G_OBJECT (colorsel), "color_changed",
                        G_CALLBACK (color_changed_cb), (gpointer) colorsel);

      /* Show the dialog */
      response = gtk_dialog_run (GTK_DIALOG (colorseldlg));

      if (response == GTK_RESPONSE_OK)
        gtk_color_selection_get_current_color (colorsel, &color);
      else 
        gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &color);

      gtk_widget_hide (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 */

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

  drawingarea = gtk_drawing_area_new ();

  color.red = 0;
  color.blue = 65535;
  color.green = 0;
  gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &color);       

  gtk_widget_set_size_request (GTK_WIDGET (drawingarea), 200, 200);

  gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);

  g_signal_connect (GTK_OBJECT (drawingarea), "event", 
	            GTK_SIGNAL_FUNC (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;
}