Beispiel #1
0
static void
gtk_color_swatch_measure (GtkCssGadget   *gadget,
                          GtkOrientation  orientation,
                          int             for_size,
                          int            *minimum,
                          int            *natural,
                          int            *minimum_baseline,
                          int            *natural_baseline,
                          gpointer        unused)
{
    GtkWidget *widget;
    GtkColorSwatch *swatch;
    gint w, h, min;

    widget = gtk_css_gadget_get_owner (gadget);
    swatch = GTK_COLOR_SWATCH (widget);

    gtk_css_gadget_get_preferred_size (swatch->priv->overlay_gadget,
                                       orientation,
                                       -1,
                                       minimum, natural,
                                       NULL, NULL);

    gtk_widget_get_size_request (widget, &w, &h);
    if (orientation == GTK_ORIENTATION_HORIZONTAL)
        min = w < 0 ? 48 : w;
    else
        min = h < 0 ? 32 : h;

    *minimum = MAX (*minimum, min);
    *natural = MAX (*natural, min);
}
Beispiel #2
0
static gboolean
swatch_button_press (GtkWidget      *widget,
                     GdkEventButton *event)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

  gtk_widget_grab_focus (widget);

  if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
      swatch->priv->has_color)
    {
      do_popup (widget, event);
      return TRUE;
    }
  else if (event->type == GDK_2BUTTON_PRESS &&
           event->button == GDK_BUTTON_PRIMARY)
    {
      g_signal_emit (swatch, signals[ACTIVATE], 0);
      return TRUE;
    }
  else if (event->button == GDK_BUTTON_PRIMARY)
    {
      return TRUE;
    }

  return FALSE;
}
Beispiel #3
0
static void
swatch_realize (GtkWidget *widget)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
    GtkAllocation allocation;
    GdkWindow *window;
    GdkWindowAttr attributes;
    gint attributes_mask;

    gtk_widget_get_allocation (widget, &allocation);
    gtk_widget_set_realized (widget, TRUE);

    attributes.window_type = GDK_WINDOW_CHILD;
    attributes.x = allocation.x;
    attributes.y = allocation.y;
    attributes.width = allocation.width;
    attributes.height = allocation.height;
    attributes.wclass = GDK_INPUT_ONLY;
    attributes.event_mask = gtk_widget_get_events (widget);
    attributes.event_mask |= GDK_BUTTON_PRESS_MASK
                             | GDK_BUTTON_RELEASE_MASK
                             | GDK_ENTER_NOTIFY_MASK
                             | GDK_LEAVE_NOTIFY_MASK
                             | GDK_TOUCH_MASK;

    attributes_mask = GDK_WA_X | GDK_WA_Y;

    window = gtk_widget_get_parent_window (widget);
    gtk_widget_set_window (widget, window);
    g_object_ref (window);

    swatch->priv->event_window = gdk_window_new (window, &attributes, attributes_mask);
    gtk_widget_register_window (widget, swatch->priv->event_window);
}
Beispiel #4
0
static gboolean
swatch_key_press (GtkWidget   *widget,
                  GdkEventKey *event)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

    if (event->keyval == GDK_KEY_space ||
            event->keyval == GDK_KEY_Return ||
            event->keyval == GDK_KEY_ISO_Enter||
            event->keyval == GDK_KEY_KP_Enter ||
            event->keyval == GDK_KEY_KP_Space)
    {
        if (swatch->priv->has_color &&
                swatch->priv->selectable &&
                (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0)
            gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
        else
            g_signal_emit (swatch, signals[ACTIVATE], 0);
        return TRUE;
    }

    if (GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->key_press_event (widget, event))
        return TRUE;

    return FALSE;
}
Beispiel #5
0
static void
gtk_color_swatch_allocate (GtkCssGadget        *gadget,
                           const GtkAllocation *allocation,
                           int                  baseline,
                           GtkAllocation       *out_clip,
                           gpointer             unused)
{
    GtkColorSwatch *swatch;
    GtkAllocation overlay_alloc;
    gint overlay_width, overlay_height;

    swatch = GTK_COLOR_SWATCH (gtk_css_gadget_get_owner (gadget));

    gtk_css_gadget_get_preferred_size (swatch->priv->overlay_gadget,
                                       GTK_ORIENTATION_HORIZONTAL,
                                       -1,
                                       &overlay_width, NULL,
                                       NULL, NULL);
    gtk_css_gadget_get_preferred_size (swatch->priv->overlay_gadget,
                                       GTK_ORIENTATION_VERTICAL,
                                       -1,
                                       &overlay_height, NULL,
                                       NULL, NULL);

    overlay_alloc.x = allocation->x + (allocation->width - overlay_width) / 2;
    overlay_alloc.y = allocation->y + (allocation->height - overlay_height) / 2;
    overlay_alloc.width = overlay_width;
    overlay_alloc.height = overlay_height;

    gtk_css_gadget_allocate (swatch->priv->overlay_gadget, &overlay_alloc, baseline, out_clip);
}
Beispiel #6
0
static gboolean
swatch_touch (GtkWidget     *widget,
              GdkEventTouch *event)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

  if (!swatch->priv->press_and_hold)
    {
      gint drag_threshold;

      g_object_get (gtk_widget_get_settings (widget),
                    "gtk-dnd-drag-threshold", &drag_threshold,
                    NULL);

      swatch->priv->press_and_hold = gtk_press_and_hold_new ();

      g_object_set (swatch->priv->press_and_hold,
                    "drag-threshold", drag_threshold,
                    "hold-time", 1000,
                    NULL);

      g_signal_connect (swatch->priv->press_and_hold, "hold",
                        G_CALLBACK (hold_action), swatch);
      g_signal_connect (swatch->priv->press_and_hold, "tap",
                        G_CALLBACK (tap_action), swatch);
    }

  gtk_press_and_hold_process_event (swatch->priv->press_and_hold, (GdkEvent *)event);

  return TRUE;
}
Beispiel #7
0
static void
swatch_get_property (GObject    *object,
                     guint       prop_id,
                     GValue     *value,
                     GParamSpec *pspec)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
    GdkRGBA color;

    switch (prop_id)
    {
    case PROP_RGBA:
        gtk_color_swatch_get_rgba (swatch, &color);
        g_value_set_boxed (value, &color);
        break;
    case PROP_SELECTABLE:
        g_value_set_boolean (value, gtk_color_swatch_get_selectable (swatch));
        break;
    case PROP_HAS_MENU:
        g_value_set_boolean (value, swatch->priv->has_menu);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}
Beispiel #8
0
static void
swatch_state_flags_changed (GtkWidget     *widget,
                            GtkStateFlags  previous_state)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

  gtk_css_node_set_state (swatch->priv->overlay_node, gtk_widget_get_state_flags (widget));
}
Beispiel #9
0
static gboolean
swatch_draw (GtkWidget *widget,
             cairo_t   *cr)
{
    gtk_css_gadget_draw (GTK_COLOR_SWATCH (widget)->priv->gadget, cr);

    return FALSE;
}
Beispiel #10
0
static void
swatch_finalize (GObject *object)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);

  g_free (swatch->priv->icon);

  G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
}
Beispiel #11
0
static void
swatch_drag_begin (GtkWidget      *widget,
                   GdkDragContext *context)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
    GdkRGBA color;

    gtk_color_swatch_get_rgba (swatch, &color);
    drag_set_color_icon (context, &color);
}
Beispiel #12
0
static void
swatch_unmap (GtkWidget *widget)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

    if (swatch->priv->event_window)
        gdk_window_hide (swatch->priv->event_window);

    GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->unmap (widget);
}
Beispiel #13
0
static gboolean
swatch_leave_notify (GtkWidget        *widget,
                     GdkEventCrossing *event)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
  swatch->priv->contains_pointer = FALSE;
  gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_PRELIGHT);

  return FALSE;
}
Beispiel #14
0
static void
swatch_get_preferred_height (GtkWidget *widget,
                             gint      *minimum,
                             gint      *natural)
{
    gtk_css_gadget_get_preferred_size (GTK_COLOR_SWATCH (widget)->priv->gadget,
                                       GTK_ORIENTATION_VERTICAL,
                                       -1,
                                       minimum, natural,
                                       NULL, NULL);
}
Beispiel #15
0
static void
gtk_color_editor_set_use_alpha (GtkColorEditor *editor,
                                gboolean        use_alpha)
{
  if (editor->priv->use_alpha != use_alpha)
    {
      editor->priv->use_alpha = use_alpha;
      gtk_widget_set_visible (editor->priv->a_slider, use_alpha);
      gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (editor->priv->swatch), use_alpha);
    }
}
Beispiel #16
0
static void
swatch_state_flags_changed (GtkWidget     *widget,
                            GtkStateFlags  previous_state)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

    gtk_css_node_set_state (gtk_css_gadget_get_node (swatch->priv->gadget), gtk_widget_get_state_flags (widget));
    gtk_css_node_set_state (gtk_css_gadget_get_node (swatch->priv->overlay_gadget), gtk_widget_get_state_flags (widget));

    GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->state_flags_changed (widget, previous_state);
}
Beispiel #17
0
static void
swatch_finalize (GObject *object)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);

  g_free (swatch->priv->icon);

  g_object_unref (swatch->priv->long_press_gesture);
  g_object_unref (swatch->priv->multipress_gesture);

  G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
}
Beispiel #18
0
static gboolean
swatch_button_release (GtkWidget      *widget,
                       GdkEventButton *event)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

  if (event->button == GDK_BUTTON_PRIMARY &&
      swatch->priv->contains_pointer)
    return swatch_primary_action (swatch);

  return FALSE;
}
Beispiel #19
0
static void
swatch_unrealize (GtkWidget *widget)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

    if (swatch->priv->event_window)
    {
        gtk_widget_unregister_window (widget, swatch->priv->event_window);
        gdk_window_destroy (swatch->priv->event_window);
        swatch->priv->event_window = NULL;
    }

    GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->unrealize (widget);
}
Beispiel #20
0
static void
swatch_size_allocate (GtkWidget *widget,
                      GtkAllocation *allocation)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);

  gtk_widget_set_allocation (widget, allocation);

  if (gtk_widget_get_realized (widget))
    gdk_window_move_resize (swatch->priv->event_window,
                            allocation->x,
                            allocation->y,
                            allocation->width,
                            allocation->height);
}
Beispiel #21
0
static void
swatch_dispose (GObject *object)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);

    if (swatch->priv->popover)
    {
        gtk_widget_destroy (swatch->priv->popover);
        swatch->priv->popover = NULL;
    }

    g_clear_object (&swatch->priv->long_press_gesture);
    g_clear_object (&swatch->priv->multipress_gesture);

    G_OBJECT_CLASS (gtk_color_swatch_parent_class)->dispose (object);
}
Beispiel #22
0
static void
hsv_changed (GtkColorEditor *editor)
{
  GdkRGBA color;
  gdouble h, s, v, a;

  h = gtk_adjustment_get_value (editor->priv->h_adj);
  s = gtk_adjustment_get_value (editor->priv->s_adj);
  v = gtk_adjustment_get_value (editor->priv->v_adj);
  a = gtk_adjustment_get_value (editor->priv->a_adj);

  gtk_hsv_to_rgb (h, s, v, &color.red, &color.green, &color.blue);
  color.alpha = a;

  gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->priv->swatch), &color);
  gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->priv->a_slider), &color);
  entry_set_rgba (editor, &color);

  g_object_notify (G_OBJECT (editor), "rgba");
}
Beispiel #23
0
static void
swatch_set_property (GObject      *object,
                     guint         prop_id,
                     const GValue *value,
                     GParamSpec   *pspec)
{
  GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);

  switch (prop_id)
    {
    case PROP_RGBA:
      gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
      break;
    case PROP_SELECTABLE:
      gtk_color_swatch_set_selectable (swatch, g_value_get_boolean (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}
Beispiel #24
0
static void
swatch_drag_data_get (GtkWidget        *widget,
                      GdkDragContext   *context,
                      GtkSelectionData *selection_data,
                      guint             info,
                      guint             time)
{
    GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
    guint16 vals[4];
    GdkRGBA color;

    gtk_color_swatch_get_rgba (swatch, &color);

    vals[0] = color.red * 0xffff;
    vals[1] = color.green * 0xffff;
    vals[2] = color.blue * 0xffff;
    vals[3] = color.alpha * 0xffff;

    gtk_selection_data_set (selection_data,
                            gdk_atom_intern_static_string ("application/x-color"),
                            16, (guchar *)vals, 8);
}
Beispiel #25
0
static void
swatch_drag_data_received (GtkWidget        *widget,
                           GdkDragContext   *context,
                           gint              x,
                           gint              y,
                           GtkSelectionData *selection_data,
                           guint             info,
                           guint             time)
{
    gint length;
    guint16 *vals;
    GdkRGBA color;

    length = gtk_selection_data_get_length (selection_data);

    if (length < 0)
        return;

    /* We accept drops with the wrong format, since the KDE color
     * chooser incorrectly drops application/x-color with format 8.
     */
    if (length != 8)
    {
        g_warning ("Received invalid color data\n");
        return;
    }

    vals = (guint16 *) gtk_selection_data_get_data (selection_data);

    color.red   = (gdouble)vals[0] / 0xffff;
    color.green = (gdouble)vals[1] / 0xffff;
    color.blue  = (gdouble)vals[2] / 0xffff;
    color.alpha = (gdouble)vals[3] / 0xffff;

    gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color);
}
Beispiel #26
0
static gboolean
gtk_color_swatch_render_overlay (GtkCssGadget *gadget,
                                 cairo_t      *cr,
                                 int           x,
                                 int           y,
                                 int           width,
                                 int           height,
                                 gpointer      data)
{
    GtkWidget *widget;
    GtkColorSwatch *swatch;
    GtkStyleContext *context;
    GtkStateFlags state;
    GtkIconTheme *theme;
    GtkIconInfo *icon_info = NULL;
    gint scale;

    widget = gtk_css_gadget_get_owner (gadget);
    swatch = GTK_COLOR_SWATCH (widget);

    theme = gtk_icon_theme_get_default ();
    context = gtk_widget_get_style_context (widget);
    state = gtk_style_context_get_state (context);

    scale = gtk_widget_get_scale_factor (widget);
    if (swatch->priv->icon)
    {
        icon_info = gtk_icon_theme_lookup_icon_for_scale (theme, swatch->priv->icon, PIXBUF_SIZE,
                    scale,
                    GTK_ICON_LOOKUP_GENERIC_FALLBACK
                    | GTK_ICON_LOOKUP_USE_BUILTIN);
    }
    else if ((state & GTK_STATE_FLAG_SELECTED) != 0)
    {
        GIcon *gicon;

        gicon = g_themed_icon_new ("object-select-symbolic");
        /* fallback for themes that don't have object-select-symbolic */
        g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");

        icon_info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, gicon, PIXBUF_SIZE,
                    scale,
                    GTK_ICON_LOOKUP_USE_BUILTIN);
        g_object_unref (gicon);
    }

    /* now draw the overlay image */
    if (icon_info != NULL)
    {
        GdkPixbuf *pixbuf;

        pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context, NULL, NULL);
        if (pixbuf != NULL)
        {
            cairo_surface_t *surface;

            surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (widget));
            gtk_render_icon_surface (context, cr, surface, x, y);
            cairo_surface_destroy (surface);
            g_object_unref (pixbuf);
        }

        g_object_unref (icon_info);
    }

    return FALSE;
}
Beispiel #27
0
static gboolean
swatch_popup_menu (GtkWidget *widget)
{
    do_popup (GTK_COLOR_SWATCH (widget));
    return TRUE;
}
Beispiel #28
0
static gboolean
gtk_color_swatch_render (GtkCssGadget *gadget,
                         cairo_t      *cr,
                         int           x,
                         int           y,
                         int           width,
                         int           height,
                         gpointer      data)
{
    GtkWidget *widget;
    GtkColorSwatch *swatch;
    GtkStyleContext *context;

    widget = gtk_css_gadget_get_owner (gadget);
    swatch = GTK_COLOR_SWATCH (widget);
    context = gtk_widget_get_style_context (widget);

    if (swatch->priv->has_color)
    {
        cairo_pattern_t *pattern;
        cairo_matrix_t matrix;

        gtk_render_content_path (context, cr, x, y, width, height);

        if (swatch->priv->use_alpha)
        {
            cairo_save (cr);

            cairo_clip_preserve (cr);

            cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
            cairo_fill_preserve (cr);

            pattern = _gtk_color_chooser_get_checkered_pattern ();
            cairo_matrix_init_scale (&matrix, 0.125, 0.125);
            cairo_pattern_set_matrix (pattern, &matrix);

            cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
            cairo_mask (cr, pattern);
            cairo_pattern_destroy (pattern);

            cairo_restore (cr);

            gdk_cairo_set_source_rgba (cr, &swatch->priv->color);
        }
        else
        {
            cairo_set_source_rgb (cr,
                                  swatch->priv->color.red,
                                  swatch->priv->color.green,
                                  swatch->priv->color.blue);
        }

        cairo_fill (cr);
    }

    gtk_render_frame (context, cr, x, y, width, height);

    gtk_css_gadget_draw (swatch->priv->overlay_gadget, cr);

    return gtk_widget_has_visible_focus (widget);
}
Beispiel #29
0
static void
gtk_color_editor_init (GtkColorEditor *editor)
{
  GtkWidget *grid;
  GtkWidget *slider;
  GtkWidget *entry;
  GtkWidget *swatch;
  GtkAdjustment *h_adj, *s_adj, *v_adj, *a_adj;
  AtkObject *atk_obj;
  GdkRGBA transparent = { 0, 0, 0, 0 };

  editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (editor,
                                              GTK_TYPE_COLOR_EDITOR,
                                              GtkColorEditorPrivate);
  editor->priv->use_alpha = TRUE;

  editor->priv->h_adj = h_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
  editor->priv->s_adj = s_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
  editor->priv->v_adj = v_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
  editor->priv->a_adj = a_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);

  g_object_ref_sink (h_adj);
  g_object_ref_sink (s_adj);
  g_object_ref_sink (v_adj);
  g_object_ref_sink (a_adj);

  g_signal_connect_swapped (h_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
  g_signal_connect_swapped (s_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
  g_signal_connect_swapped (v_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
  g_signal_connect_swapped (a_adj, "value-changed", G_CALLBACK (hsv_changed), editor);

  gtk_widget_push_composite_child ();

  /* Construct the main UI */
  editor->priv->swatch = swatch = gtk_color_swatch_new ();
  gtk_color_swatch_set_selectable (GTK_COLOR_SWATCH (editor->priv->swatch), FALSE);
  gtk_widget_set_events (swatch, gtk_widget_get_events (swatch)
                                 & ~(GDK_BUTTON_PRESS_MASK
                                     | GDK_BUTTON_RELEASE_MASK
                                     | GDK_KEY_PRESS_MASK
                                     | GDK_KEY_RELEASE_MASK));
  gtk_widget_set_can_focus (swatch, FALSE);

  editor->priv->entry = entry = gtk_entry_new ();
  atk_obj = gtk_widget_get_accessible (entry);
  atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
  atk_object_set_name (atk_obj, _("Color Name"));
  g_signal_connect (entry, "activate", G_CALLBACK (entry_apply), editor);
  g_signal_connect (entry, "notify::text", G_CALLBACK (entry_text_changed), editor);
  g_signal_connect (entry, "focus-out-event", G_CALLBACK (entry_focus_out), editor);

  editor->priv->h_slider = slider = gtk_color_scale_new (h_adj, GTK_COLOR_SCALE_HUE);
  gtk_orientable_set_orientation (GTK_ORIENTABLE (slider), GTK_ORIENTATION_VERTICAL);
  if (gtk_widget_get_direction (slider) == GTK_TEXT_DIR_RTL)
    gtk_style_context_add_class (gtk_widget_get_style_context (slider),
                                 GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE);
  else
    gtk_style_context_add_class (gtk_widget_get_style_context (slider),
                                 GTK_STYLE_CLASS_SCALE_HAS_MARKS_BELOW);

  editor->priv->sv_plane = gtk_color_plane_new (h_adj, s_adj, v_adj);
  gtk_widget_set_size_request (editor->priv->sv_plane, 300, 300);

  editor->priv->a_slider = slider = gtk_color_scale_new (a_adj, GTK_COLOR_SCALE_ALPHA);
  gtk_orientable_set_orientation (GTK_ORIENTABLE (slider), GTK_ORIENTATION_HORIZONTAL);
  gtk_style_context_add_class (gtk_widget_get_style_context (slider),
                               GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE);

  editor->priv->grid = grid = gtk_grid_new ();
  gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
  gtk_grid_set_column_spacing (GTK_GRID (grid), 12);

  gtk_grid_attach (GTK_GRID (grid), editor->priv->swatch,   1, 0, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->entry,    2, 0, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->h_slider, 0, 1, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->sv_plane, 1, 1, 2, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->a_slider, 1, 2, 2, 1);

  /* This extra margin is necessary so we have room to the sides
   * to place the popups as desired
   */
  gtk_widget_set_margin_left (grid, 30);
  gtk_widget_set_margin_right (grid, 30);

  editor->priv->overlay = gtk_overlay_new ();
  gtk_widget_override_background_color (editor->priv->overlay, 0, &transparent);
  gtk_container_add (GTK_CONTAINER (editor->priv->overlay), grid);

  /* Construct the sv popup */
  editor->priv->s_entry = entry = gtk_spin_button_new (scaled_adjustment (s_adj, 100), 1, 0);
  atk_obj = gtk_widget_get_accessible (entry);
  atk_object_set_name (atk_obj, C_("Color channel", "Saturation"));
  atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
  g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);

  editor->priv->v_entry = entry = gtk_spin_button_new (scaled_adjustment (v_adj, 100), 1, 0);
  atk_obj = gtk_widget_get_accessible (entry);
  atk_object_set_name (atk_obj, C_("Color channel", "Value"));
  atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
  g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);

  grid = gtk_grid_new ();
  gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);

  gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "S")), 0, 0, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->s_entry, 1, 0, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "V")), 0, 1, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->v_entry, 1, 1, 1, 1);

  editor->priv->sv_popup = create_popup (editor, editor->priv->sv_plane, grid);

  /* Construct the h popup */
  editor->priv->h_entry = entry = gtk_spin_button_new (scaled_adjustment (h_adj, 100), 1, 0);
  atk_obj = gtk_widget_get_accessible (entry);
  atk_object_set_name (atk_obj, C_("Color channel", "Hue"));
  atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
  g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);

  grid = gtk_grid_new ();
  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);

  gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "H")), 0, 0, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->h_entry, 1, 0, 1, 1);

  editor->priv->h_popup = create_popup (editor, editor->priv->h_slider, grid);

  /* Construct the a popup */
  editor->priv->a_entry = entry = gtk_spin_button_new (scaled_adjustment (a_adj, 100), 1, 0);
  atk_obj = gtk_widget_get_accessible (entry);
  atk_object_set_name (atk_obj, C_("Color channel", "Alpha"));
  atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
  g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);

  grid = gtk_grid_new ();
  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);

  gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "A")), 0, 0, 1, 1);
  gtk_grid_attach (GTK_GRID (grid), editor->priv->a_entry, 1, 0, 1, 1);

  editor->priv->a_popup = create_popup (editor, editor->priv->a_slider, grid);

  /* Hook up popup positioning */
  g_signal_connect (editor->priv->overlay, "get-child-position", G_CALLBACK (get_child_position), editor);
  g_signal_connect (editor, "notify::visible", G_CALLBACK (dismiss_current_popup), NULL);

  gtk_widget_show_all (editor->priv->overlay);
  gtk_container_add (GTK_CONTAINER (editor), editor->priv->overlay);

  gtk_widget_pop_composite_child ();
}