diff --git a/gtk/Makefile.am b/gtk/Makefile.am index fddc1204a2..d4b12a58b1 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -415,6 +415,7 @@ gtk_private_h_sources = \ gtkcellareaboxcontextprivate.h \ gtkcolorswatch.h \ gtkcoloreditor.h \ + gtkcolorplane.h \ gtkcolorchooserprivate.h \ gtkcontainerprivate.h \ gtkcsscomputedvaluesprivate.h \ @@ -599,6 +600,7 @@ gtk_base_c_sources = \ gtkcolorsel.c \ gtkcolorseldialog.c \ gtkcoloreditor.c \ + gtkcolorplane.c \ gtkcolorswatch.c \ gtkcolorchooser.c \ gtkcolorchooserwidget.c \ diff --git a/gtk/gtkcolorchooserwidget.c b/gtk/gtkcolorchooserwidget.c index c14510133d..0f7c1bf9bb 100644 --- a/gtk/gtkcolorchooserwidget.c +++ b/gtk/gtkcolorchooserwidget.c @@ -61,12 +61,18 @@ static void select_swatch (GtkColorChooserWidget *cc, GtkColorSwatch *swatch) { + GdkRGBA color; + if (cc->priv->current == swatch) return; if (cc->priv->current != NULL) gtk_color_swatch_set_selected (cc->priv->current, FALSE); gtk_color_swatch_set_selected (swatch, TRUE); cc->priv->current = swatch; + gtk_color_swatch_get_color (swatch, &color); + g_settings_set (cc->priv->settings, "selected-color", "(bdddd)", + TRUE, color.red, color.green, color.blue, color.alpha); + g_object_notify (G_OBJECT (cc), "color"); } diff --git a/gtk/gtkcoloreditor.c b/gtk/gtkcoloreditor.c index d10dc31f44..b79628d6ed 100644 --- a/gtk/gtkcoloreditor.c +++ b/gtk/gtkcoloreditor.c @@ -18,8 +18,6 @@ */ /* TODO - * - split out sv-plane - * - focus indication * - custom sliders * - pop-up entries */ @@ -28,6 +26,7 @@ #include "gtkcolorchooserprivate.h" #include "gtkcoloreditor.h" +#include "gtkcolorplane.h" #include "gtkgrid.h" #include "gtkscale.h" #include "gtkaspectframe.h" @@ -50,11 +49,8 @@ struct _GtkColorEditorPrivate GtkAdjustment *h_adj; GtkAdjustment *a_adj; - cairo_surface_t *surface; GdkRGBA color; gdouble h, s, v; - gint x, y; - gboolean in_drag; gboolean text_changed; }; @@ -70,163 +66,6 @@ G_DEFINE_TYPE_WITH_CODE (GtkColorEditor, gtk_color_editor, GTK_TYPE_BOX, G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER, gtk_color_editor_iface_init)) -static gboolean -sv_draw (GtkWidget *widget, - cairo_t *cr, - GtkColorEditor *editor) -{ - gint x, y; - gint width, height; - - cairo_set_source_surface (cr, editor->priv->surface, 0, 0); - cairo_paint (cr); - - x = editor->priv->x; - y = editor->priv->y; - width = gtk_widget_get_allocated_width (widget); - height = gtk_widget_get_allocated_height (widget); - - cairo_move_to (cr, 0, y + 0.5); - cairo_line_to (cr, width, y + 0.5); - - cairo_move_to (cr, x + 0.5, 0); - cairo_line_to (cr, x + 0.5, height); - - cairo_set_line_width (cr, 3.0); - cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6); - cairo_stroke_preserve (cr); - - cairo_set_line_width (cr, 1.0); - cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8); - cairo_stroke (cr); - - return FALSE; -} - -static void -create_sv_surface (GtkColorEditor *editor) -{ - GtkWidget *sv_plane; - cairo_t *cr; - cairo_surface_t *surface; - gint width, height, stride; - cairo_surface_t *tmp; - guint red, green, blue; - guint32 *data, *p; - gdouble h, s, v; - gdouble r, g, b; - gdouble sf, vf; - gint x, y; - - sv_plane = editor->priv->sv_plane; - - if (!gtk_widget_get_realized (sv_plane)) - return; - - width = gtk_widget_get_allocated_width (sv_plane); - height = gtk_widget_get_allocated_height (sv_plane); - - surface = gdk_window_create_similar_surface (gtk_widget_get_window (sv_plane), - CAIRO_CONTENT_COLOR, - width, height); - - if (editor->priv->surface) - cairo_surface_destroy (editor->priv->surface); - editor->priv->surface = surface; - - if (width == 1 || height == 1) - return; - - stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width); - - data = g_malloc (4 * height * stride); - - h = editor->priv->h; - sf = 1.0 / (height - 1); - vf = 1.0 / (width - 1); - for (y = 0; y < height; y++) - { - s = CLAMP (1.0 - y * sf, 0.0, 1.0); - p = data + y * (stride / 4); - for (x = 0; x < width; x++) - { - v = x * vf; - gtk_hsv_to_rgb (h, s, v, &r, &g, &b); - red = CLAMP (r * 255, 0, 255); - green = CLAMP (g * 255, 0, 255); - blue = CLAMP (b * 255, 0, 255); - p[x] = (red << 16) | (green << 8) | blue; - } - } - - tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24, - width, height, stride); - cr = cairo_create (surface); - - cairo_set_source_surface (cr, tmp, 0, 0); - cairo_paint (cr); - - cairo_destroy (cr); - cairo_surface_destroy (tmp); - g_free (data); -} - -static void -hsv_to_xy (GtkColorEditor *editor) -{ - GtkWidget *sv_plane; - gint width, height; - - sv_plane = editor->priv->sv_plane; - - width = gtk_widget_get_allocated_width (GTK_WIDGET (sv_plane)); - height = gtk_widget_get_allocated_height (GTK_WIDGET (sv_plane)); - - editor->priv->x = CLAMP (width * editor->priv->v, 0, width - 1); - editor->priv->y = CLAMP (height * (1 - editor->priv->s), 0, height - 1); -} - -static gboolean -sv_configure (GtkWidget *widget, - GdkEventConfigure *event, - GtkColorEditor *editor) -{ - create_sv_surface (editor); - hsv_to_xy (editor); - return TRUE; -} - -static void -set_cross_grab (GtkWidget *widget, - GdkDevice *device, - guint32 time) -{ - GdkCursor *cursor; - - cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (widget)), - GDK_CROSSHAIR); - gdk_device_grab (device, - gtk_widget_get_window (widget), - GDK_OWNERSHIP_NONE, - FALSE, - GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK - | GDK_BUTTON_RELEASE_MASK, - cursor, - time); - g_object_unref (cursor); -} - -static gboolean -sv_grab_broken (GtkWidget *widget, - GdkEventGrabBroken *event, - GtkColorEditor *editor) -{ - editor->priv->in_drag = FALSE; - - return TRUE; -} - static guint scale_round (gdouble value, gdouble scale) { @@ -250,167 +89,6 @@ update_entry (GtkColorEditor *editor) g_free (text); } -static void -sv_update_color (GtkColorEditor *editor, - gint x, - gint y) -{ - GtkWidget *sv_plane; - - sv_plane = editor->priv->sv_plane; - - editor->priv->x = x; - editor->priv->y = y; - - editor->priv->s = CLAMP (1 - y * (1.0 / gtk_widget_get_allocated_height (sv_plane)), 0, 1); - editor->priv->v = CLAMP (x * (1.0 / gtk_widget_get_allocated_width (sv_plane)), 0, 1); - gtk_hsv_to_rgb (editor->priv->h, editor->priv->s, editor->priv->v, - &editor->priv->color.red, - &editor->priv->color.green, - &editor->priv->color.blue); - update_entry (editor); - gtk_adjustment_set_value (editor->priv->h_adj, editor->priv->h); - gtk_widget_queue_draw (editor->priv->swatch); - gtk_widget_queue_draw (sv_plane); -} - -static gboolean -sv_button_press (GtkWidget *widget, - GdkEventButton *event, - GtkColorEditor *editor) -{ - if (editor->priv->in_drag || event->button != GDK_BUTTON_PRIMARY) - return FALSE; - - editor->priv->in_drag = TRUE; - set_cross_grab (widget, gdk_event_get_device ((GdkEvent*)event), event->time); - sv_update_color (editor, event->x, event->y); - gtk_widget_grab_focus (widget); - - return TRUE; -} - -static gboolean -sv_button_release (GtkWidget *widget, - GdkEventButton *event, - GtkColorEditor *editor) -{ - if (!editor->priv->in_drag || event->button != GDK_BUTTON_PRIMARY) - return FALSE; - - editor->priv->in_drag = FALSE; - - sv_update_color (editor, event->x, event->y); - gdk_device_ungrab (gdk_event_get_device ((GdkEvent *) event), event->time); - - return TRUE; -} - -static gboolean -sv_motion (GtkWidget *widget, - GdkEventMotion *event, - GtkColorEditor *editor) -{ - if (!editor->priv->in_drag) - return FALSE; - - gdk_event_request_motions (event); - sv_update_color (editor, event->x, event->y); - - return TRUE; -} - -static void -sv_move (GtkColorEditor *editor, - gdouble ds, - gdouble dv) -{ - if (editor->priv->s + ds > 1) - { - if (editor->priv->s < 1) - editor->priv->s = 1; - else - goto error; - } - else if (editor->priv->s + ds < 0) - { - if (editor->priv->s > 0) - editor->priv->s = 0; - else - goto error; - } - else - { - editor->priv->s += ds; - } - - if (editor->priv->v + dv > 1) - { - if (editor->priv->v < 1) - editor->priv->v = 1; - else - goto error; - } - else if (editor->priv->v + dv < 0) - { - if (editor->priv->v > 0) - editor->priv->v = 0; - else - goto error; - } - else - { - editor->priv->v += dv; - } - - gtk_hsv_to_rgb (editor->priv->h, editor->priv->s, editor->priv->v, - &editor->priv->color.red, - &editor->priv->color.green, - &editor->priv->color.blue); - - hsv_to_xy (editor); - - update_entry (editor); - gtk_adjustment_set_value (editor->priv->h_adj, editor->priv->h); - gtk_widget_queue_draw (editor->priv->swatch); - gtk_widget_queue_draw (editor->priv->sv_plane); - return; - -error: - gtk_widget_error_bell (editor->priv->sv_plane); -} - -static gboolean -sv_key_press (GtkWidget *widget, - GdkEventKey *event, - GtkColorEditor *editor) -{ - gdouble step; - - /* FIXME: turn into bindings */ - if ((event->state & GDK_MOD1_MASK) != 0) - step = 0.1; - else - step = 0.01; - - if (event->keyval == GDK_KEY_Up || - event->keyval == GDK_KEY_KP_Up) - sv_move (editor, step, 0); - else if (event->keyval == GDK_KEY_Down || - event->keyval == GDK_KEY_KP_Down) - sv_move (editor, -step, 0); - else if (event->keyval == GDK_KEY_Left || - event->keyval == GDK_KEY_KP_Left) - sv_move (editor, 0, -step); - else if (event->keyval == GDK_KEY_Right || - event->keyval == GDK_KEY_KP_Right) - sv_move (editor, 0, step); - else - return FALSE; - - return TRUE; -} - static void entry_apply (GtkWidget *entry, GtkColorEditor *editor) @@ -424,17 +102,8 @@ entry_apply (GtkWidget *entry, text = gtk_editable_get_chars (GTK_EDITABLE (editor->priv->entry), 0, -1); if (gdk_rgba_parse (&color, text)) { - editor->priv->color.red = color.red; - editor->priv->color.green = color.green; - editor->priv->color.blue = color.blue; - gtk_rgb_to_hsv (editor->priv->color.red, - editor->priv->color.green, - editor->priv->color.blue, - &editor->priv->h, &editor->priv->s, &editor->priv->v); - hsv_to_xy (editor); - gtk_adjustment_set_value (editor->priv->h_adj, editor->priv->h); - gtk_widget_queue_draw (GTK_WIDGET (editor)); - g_object_notify (G_OBJECT (editor), "color"); + color.alpha = editor->priv->color.alpha; + gtk_color_chooser_set_color (GTK_COLOR_CHOOSER (editor), &color); } editor->priv->text_changed = FALSE; @@ -464,18 +133,30 @@ h_changed (GtkAdjustment *adj, GtkColorEditor *editor) { editor->priv->h = gtk_adjustment_get_value (adj); - gtk_hsv_to_rgb (editor->priv->h, editor->priv->s, editor->priv->v, &editor->priv->color.red, &editor->priv->color.green, &editor->priv->color.blue); - create_sv_surface (editor); - gtk_widget_queue_draw (editor->priv->sv_plane); + gtk_color_plane_set_h (GTK_COLOR_PLANE (editor->priv->sv_plane), editor->priv->h); gtk_widget_queue_draw (editor->priv->swatch); update_entry (editor); g_object_notify (G_OBJECT (editor), "color"); } +static void +sv_changed (GtkColorPlane *plane, + GtkColorEditor *editor) +{ + editor->priv->s = gtk_color_plane_get_s (plane); + editor->priv->v = gtk_color_plane_get_v (plane); + gtk_hsv_to_rgb (editor->priv->h, editor->priv->s, editor->priv->v, + &editor->priv->color.red, + &editor->priv->color.green, + &editor->priv->color.blue); + update_entry (editor); + gtk_widget_queue_draw (editor->priv->swatch); +} + static void a_changed (GtkAdjustment *adj, GtkColorEditor *editor) @@ -560,31 +241,19 @@ gtk_color_editor_init (GtkColorEditor *editor) editor->priv->h_adj = adj; gtk_scale_set_draw_value (GTK_SCALE (editor->priv->h_slider), FALSE); - editor->priv->sv_plane = gtk_drawing_area_new (); + editor->priv->sv_plane = gtk_color_plane_new (); gtk_widget_set_size_request (editor->priv->sv_plane, 300, 300); gtk_widget_set_hexpand (editor->priv->sv_plane, TRUE); gtk_widget_set_vexpand (editor->priv->sv_plane, TRUE); + g_signal_connect (editor->priv->sv_plane, "changed", G_CALLBACK (sv_changed), editor); + adj = gtk_adjustment_new (1, 0, 1, 0.01, 0.1, 0); editor->priv->a_slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adj); g_signal_connect (adj, "value-changed", G_CALLBACK (a_changed), editor); gtk_scale_set_draw_value (GTK_SCALE (editor->priv->a_slider), FALSE); editor->priv->a_adj = adj; - gtk_widget_set_can_focus (editor->priv->sv_plane, TRUE); - gtk_widget_set_events (editor->priv->sv_plane, GDK_KEY_PRESS_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK); - - g_signal_connect (editor->priv->sv_plane, "draw", G_CALLBACK (sv_draw), editor); - g_signal_connect (editor->priv->sv_plane, "configure-event", G_CALLBACK (sv_configure), editor); - g_signal_connect (editor->priv->sv_plane, "button-press-event", G_CALLBACK (sv_button_press), editor); - g_signal_connect (editor->priv->sv_plane, "button-release-event", G_CALLBACK (sv_button_release), editor); - g_signal_connect (editor->priv->sv_plane, "motion-notify-event", G_CALLBACK (sv_motion), editor); - g_signal_connect (editor->priv->sv_plane, "grab-broken-event", G_CALLBACK (sv_grab_broken), editor); - g_signal_connect (editor->priv->sv_plane, "key-press-event", G_CALLBACK (sv_key_press), editor); - 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); @@ -676,7 +345,9 @@ gtk_color_editor_set_color (GtkColorChooser *chooser, editor->priv->color.green, editor->priv->color.blue, &editor->priv->h, &editor->priv->s, &editor->priv->v); - hsv_to_xy (editor); + gtk_color_plane_set_h (GTK_COLOR_PLANE (editor->priv->sv_plane), editor->priv->h); + gtk_color_plane_set_s (GTK_COLOR_PLANE (editor->priv->sv_plane), editor->priv->s); + gtk_color_plane_set_v (GTK_COLOR_PLANE (editor->priv->sv_plane), editor->priv->v); gtk_adjustment_set_value (editor->priv->h_adj, editor->priv->h); update_entry (editor); diff --git a/gtk/gtkcolorplane.c b/gtk/gtkcolorplane.c new file mode 100644 index 0000000000..6442034844 --- /dev/null +++ b/gtk/gtkcolorplane.c @@ -0,0 +1,455 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "gtkhsv.h" +#include "gtkcolorplane.h" + +struct _GtkColorPlanePrivate +{ + cairo_surface_t *surface; + gdouble h, s, v; + gint x, y; + gboolean in_drag; +}; + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE (GtkColorPlane, gtk_color_plane, GTK_TYPE_DRAWING_AREA) + +static gboolean +sv_draw (GtkWidget *widget, + cairo_t *cr) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (widget); + gint x, y; + gint width, height; + + cairo_set_source_surface (cr, plane->priv->surface, 0, 0); + cairo_paint (cr); + + x = plane->priv->x; + y = plane->priv->y; + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + cairo_move_to (cr, 0, y + 0.5); + cairo_line_to (cr, width, y + 0.5); + + cairo_move_to (cr, x + 0.5, 0); + cairo_line_to (cr, x + 0.5, height); + + if (gtk_widget_has_visible_focus (widget)) + { + cairo_set_line_width (cr, 3.0); + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6); + cairo_stroke_preserve (cr); + + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8); + cairo_stroke (cr); + } + else + { + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.8); + cairo_stroke (cr); + } + + return FALSE; +} + +static void +create_sv_surface (GtkColorPlane *plane) +{ + GtkWidget *widget = GTK_WIDGET (plane); + cairo_t *cr; + cairo_surface_t *surface; + gint width, height, stride; + cairo_surface_t *tmp; + guint red, green, blue; + guint32 *data, *p; + gdouble h, s, v; + gdouble r, g, b; + gdouble sf, vf; + gint x, y; + + if (!gtk_widget_get_realized (widget)) + return; + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), + CAIRO_CONTENT_COLOR, + width, height); + + if (plane->priv->surface) + cairo_surface_destroy (plane->priv->surface); + plane->priv->surface = surface; + + if (width == 1 || height == 1) + return; + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width); + + data = g_malloc (4 * height * stride); + + h = plane->priv->h; + sf = 1.0 / (height - 1); + vf = 1.0 / (width - 1); + for (y = 0; y < height; y++) + { + s = CLAMP (1.0 - y * sf, 0.0, 1.0); + p = data + y * (stride / 4); + for (x = 0; x < width; x++) + { + v = x * vf; + gtk_hsv_to_rgb (h, s, v, &r, &g, &b); + red = CLAMP (r * 255, 0, 255); + green = CLAMP (g * 255, 0, 255); + blue = CLAMP (b * 255, 0, 255); + p[x] = (red << 16) | (green << 8) | blue; + } + } + + tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24, + width, height, stride); + cr = cairo_create (surface); + + cairo_set_source_surface (cr, tmp, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + cairo_surface_destroy (tmp); + g_free (data); +} + +static void +hsv_to_xy (GtkColorPlane *plane) +{ + gint width, height; + + width = gtk_widget_get_allocated_width (GTK_WIDGET (plane)); + height = gtk_widget_get_allocated_height (GTK_WIDGET (plane)); + + plane->priv->x = CLAMP (width * plane->priv->v, 0, width - 1); + plane->priv->y = CLAMP (height * (1 - plane->priv->s), 0, height - 1); +} + +static gboolean +sv_configure (GtkWidget *widget, + GdkEventConfigure *event) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (widget); + + create_sv_surface (plane); + hsv_to_xy (plane); + return TRUE; +} + +static void +set_cross_grab (GtkWidget *widget, + GdkDevice *device, + guint32 time) +{ + GdkCursor *cursor; + + cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (widget)), + GDK_CROSSHAIR); + gdk_device_grab (device, + gtk_widget_get_window (widget), + GDK_OWNERSHIP_NONE, + FALSE, + GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_RELEASE_MASK, + cursor, + time); + g_object_unref (cursor); +} + +static gboolean +sv_grab_broken (GtkWidget *widget, + GdkEventGrabBroken *event) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (widget); + + plane->priv->in_drag = FALSE; + + return TRUE; +} + +static void +sv_update_color (GtkColorPlane *plane, + gint x, + gint y) +{ + GtkWidget *widget = GTK_WIDGET (plane); + + plane->priv->x = x; + plane->priv->y = y; + + plane->priv->s = CLAMP (1 - y * (1.0 / gtk_widget_get_allocated_height (widget)), 0, 1); + plane->priv->v = CLAMP (x * (1.0 / gtk_widget_get_allocated_width (widget)), 0, 1); + g_signal_emit (plane, signals[CHANGED], 0); + gtk_widget_queue_draw (widget); +} + +static gboolean +sv_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (widget); + + if (plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY) + return FALSE; + + plane->priv->in_drag = TRUE; + set_cross_grab (widget, gdk_event_get_device ((GdkEvent*)event), event->time); + sv_update_color (plane, event->x, event->y); + gtk_widget_grab_focus (widget); + + return TRUE; +} + +static gboolean +sv_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (widget); + + if (!plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY) + return FALSE; + + plane->priv->in_drag = FALSE; + + sv_update_color (plane, event->x, event->y); + gdk_device_ungrab (gdk_event_get_device ((GdkEvent *) event), event->time); + + return TRUE; +} + +static gboolean +sv_motion (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (widget); + + if (!plane->priv->in_drag) + return FALSE; + + gdk_event_request_motions (event); + sv_update_color (plane, event->x, event->y); + + return TRUE; +} + +static void +sv_move (GtkColorPlane *plane, + gdouble ds, + gdouble dv) +{ + if (plane->priv->s + ds > 1) + { + if (plane->priv->s < 1) + plane->priv->s = 1; + else + goto error; + } + else if (plane->priv->s + ds < 0) + { + if (plane->priv->s > 0) + plane->priv->s = 0; + else + goto error; + } + else + { + plane->priv->s += ds; + } + + if (plane->priv->v + dv > 1) + { + if (plane->priv->v < 1) + plane->priv->v = 1; + else + goto error; + } + else if (plane->priv->v + dv < 0) + { + if (plane->priv->v > 0) + plane->priv->v = 0; + else + goto error; + } + else + { + plane->priv->v += dv; + } + + hsv_to_xy (plane); + g_signal_emit (plane, signals[CHANGED], 0); + + gtk_widget_queue_draw (GTK_WIDGET (plane)); + return; + +error: + gtk_widget_error_bell (GTK_WIDGET (plane)); +} + +static gboolean +sv_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (widget); + gdouble step; + + /* FIXME: turn into bindings */ + if ((event->state & GDK_MOD1_MASK) != 0) + step = 0.1; + else + step = 0.01; + + if (event->keyval == GDK_KEY_Up || + event->keyval == GDK_KEY_KP_Up) + sv_move (plane, step, 0); + else if (event->keyval == GDK_KEY_Down || + event->keyval == GDK_KEY_KP_Down) + sv_move (plane, -step, 0); + else if (event->keyval == GDK_KEY_Left || + event->keyval == GDK_KEY_KP_Left) + sv_move (plane, 0, -step); + else if (event->keyval == GDK_KEY_Right || + event->keyval == GDK_KEY_KP_Right) + sv_move (plane, 0, step); + else + return FALSE; + + return TRUE; +} + +static void +gtk_color_plane_init (GtkColorPlane *plane) +{ + plane->priv = G_TYPE_INSTANCE_GET_PRIVATE (plane, + GTK_TYPE_COLOR_PLANE, + GtkColorPlanePrivate); + gtk_widget_set_can_focus (GTK_WIDGET (plane), TRUE); + gtk_widget_set_events (GTK_WIDGET (plane), GDK_KEY_PRESS_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK); +} + +static void +sv_finalize (GObject *object) +{ + GtkColorPlane *plane = GTK_COLOR_PLANE (object); + + cairo_surface_destroy (plane->priv->surface); + + G_OBJECT_CLASS (gtk_color_plane_parent_class)->finalize (object); +} + +static void +gtk_color_plane_class_init (GtkColorPlaneClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + object_class->finalize = sv_finalize; + + widget_class->draw = sv_draw; + widget_class->configure_event = sv_configure; + widget_class->button_press_event = sv_button_press; + widget_class->button_release_event = sv_button_release; + widget_class->motion_notify_event = sv_motion; + widget_class->grab_broken_event = sv_grab_broken; + widget_class->key_press_event = sv_key_press; + + signals[CHANGED] = + g_signal_new ("changed", + GTK_TYPE_COLOR_PLANE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkColorPlaneClass, changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + g_type_class_add_private (class, sizeof (GtkColorPlanePrivate)); +} + +gdouble +gtk_color_plane_get_h (GtkColorPlane *plane) +{ + return plane->priv->h; +} + +gdouble +gtk_color_plane_get_s (GtkColorPlane *plane) +{ + return plane->priv->s; +} + +gdouble +gtk_color_plane_get_v (GtkColorPlane *plane) +{ + return plane->priv->v; +} + +void +gtk_color_plane_set_h (GtkColorPlane *plane, + gdouble h) +{ + plane->priv->h = h; + create_sv_surface (plane); + gtk_widget_queue_draw (GTK_WIDGET (plane)); +} + +void +gtk_color_plane_set_s (GtkColorPlane *plane, + gdouble s) +{ + plane->priv->s = s; + hsv_to_xy (plane); + gtk_widget_queue_draw (GTK_WIDGET (plane)); +} + +void +gtk_color_plane_set_v (GtkColorPlane *plane, + gdouble v) +{ + plane->priv->v = v; + hsv_to_xy (plane); + gtk_widget_queue_draw (GTK_WIDGET (plane)); +} + +GtkWidget * +gtk_color_plane_new (void) +{ + return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_PLANE, NULL); +} diff --git a/gtk/gtkcolorplane.h b/gtk/gtkcolorplane.h new file mode 100644 index 0000000000..33dbe04761 --- /dev/null +++ b/gtk/gtkcolorplane.h @@ -0,0 +1,80 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GTK_COLOR_PLANE_H__ +#define __GTK_COLOR_PLANE_H__ + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_COLOR_PLANE (gtk_color_plane_get_type ()) +#define GTK_COLOR_PLANE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_PLANE, GtkColorPlane)) +#define GTK_COLOR_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_PLANE, GtkColorPlaneClass)) +#define GTK_IS_COLOR_PLANE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_PLANE)) +#define GTK_IS_COLOR_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_PLANE)) +#define GTK_COLOR_PLANE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_PLANE, GtkColorPlaneClass)) + + +typedef struct _GtkColorPlane GtkColorPlane; +typedef struct _GtkColorPlaneClass GtkColorPlaneClass; +typedef struct _GtkColorPlanePrivate GtkColorPlanePrivate; + +struct _GtkColorPlane +{ + GtkDrawingArea parent_instance; + + GtkColorPlanePrivate *priv; +}; + +struct _GtkColorPlaneClass +{ + GtkDrawingAreaClass parent_class; + + void (* changed) (GtkColorPlane *plane); + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); +}; + + +GType gtk_color_plane_get_type (void) G_GNUC_CONST; + +GtkWidget * gtk_color_plane_new (void); + +gdouble gtk_color_plane_get_h (GtkColorPlane *plane); +void gtk_color_plane_set_h (GtkColorPlane *plane, + gdouble h); +gdouble gtk_color_plane_get_s (GtkColorPlane *plane); +void gtk_color_plane_set_s (GtkColorPlane *plane, + gdouble s); +gdouble gtk_color_plane_get_v (GtkColorPlane *plane); +void gtk_color_plane_set_v (GtkColorPlane *plane, + gdouble v); + +G_END_DECLS + +#endif /* __GTK_COLOR_PLANE_H__ */