X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkhsv.c;h=80128f98f080dae640812159242aaa4a849db231;hb=af7afbbe06690281d9703aaab7d1b9522cede3cb;hp=7b72f9511e66ee2bb4b8b87d4b3a15cd9b2b446c;hpb=9565f3ffb2276ec2132b6211344329aec296b7ce;p=~andy%2Fgtk diff --git a/gtk/gtkhsv.c b/gtk/gtkhsv.c index 7b72f9511..80128f98f 100644 --- a/gtk/gtkhsv.c +++ b/gtk/gtkhsv.c @@ -22,14 +22,6 @@ * Boston, MA 02111-1307, USA. */ -#include -#include -#include "gtkhsv.h" -#include "gdk/gdkkeysyms.h" -#include "gtkbindings.h" -#include "gtkcontainer.h" -#include "gtkmarshalers.h" - /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog @@ -37,6 +29,19 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include "config.h" + +#include +#include + +#include "gdk/gdkkeysyms.h" + +#include "gtkhsv.h" +#include "gtkbindings.h" +#include "gtkmarshalers.h" +#include "gtktypeutils.h" +#include "gtkintl.h" + /* Default width/height */ #define DEFAULT_SIZE 100 @@ -52,7 +57,8 @@ typedef enum { } DragMode; /* Private part of the GtkHSV structure */ -typedef struct { +struct _GtkHSVPrivate +{ /* Color value */ double h; double s; @@ -65,17 +71,12 @@ typedef struct { /* Window for capturing events */ GdkWindow *window; - /* GC for drawing */ - GdkGC *gc; - /* Dragging mode */ DragMode mode; guint focus_on_ring : 1; - -} HSVPrivate; +}; - /* Signal IDs */ @@ -85,329 +86,245 @@ enum { LAST_SIGNAL }; -static void gtk_hsv_class_init (GtkHSVClass *class); -static void gtk_hsv_init (GtkHSV *hsv); -static void gtk_hsv_destroy (GtkObject *object); -static void gtk_hsv_map (GtkWidget *widget); -static void gtk_hsv_unmap (GtkWidget *widget); -static void gtk_hsv_realize (GtkWidget *widget); -static void gtk_hsv_unrealize (GtkWidget *widget); -static void gtk_hsv_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_hsv_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static gint gtk_hsv_button_press (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_hsv_button_release (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_hsv_motion (GtkWidget *widget, - GdkEventMotion *event); -static gint gtk_hsv_expose (GtkWidget *widget, - GdkEventExpose *event); -static gboolean gtk_hsv_focus (GtkWidget *widget, - GtkDirectionType direction); -static void gtk_hsv_move (GtkHSV *hsv, - GtkDirectionType dir); -static GdkGC * gtk_hsv_get_focus_gc (GtkHSV *hsv, - gint *line_width); +static void gtk_hsv_destroy (GtkWidget *widget); +static void gtk_hsv_realize (GtkWidget *widget); +static void gtk_hsv_unrealize (GtkWidget *widget); +static void gtk_hsv_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural); +static void gtk_hsv_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural); +static void gtk_hsv_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gboolean gtk_hsv_button_press (GtkWidget *widget, + GdkEventButton *event); +static gboolean gtk_hsv_button_release (GtkWidget *widget, + GdkEventButton *event); +static gboolean gtk_hsv_motion (GtkWidget *widget, + GdkEventMotion *event); +static gboolean gtk_hsv_draw (GtkWidget *widget, + cairo_t *cr); +static gboolean gtk_hsv_grab_broken (GtkWidget *widget, + GdkEventGrabBroken *event); +static gboolean gtk_hsv_focus (GtkWidget *widget, + GtkDirectionType direction); +static void gtk_hsv_move (GtkHSV *hsv, + GtkDirectionType dir); static guint hsv_signals[LAST_SIGNAL]; -static GtkWidgetClass *parent_class; - -/** - * gtk_hsv_get_type: - * @void: - * - * Registers the &GtkHSV class if necessary, and returns the type ID associated - * to it. - * - * Return value: The type ID of the &GtkHSV class. - **/ -GType -gtk_hsv_get_type (void) -{ - static GType hsv_type = 0; - - if (!hsv_type) { - static const GTypeInfo hsv_info = { - sizeof (GtkHSVClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_hsv_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkHSV), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_hsv_init, - }; - - hsv_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkHSV", - &hsv_info, 0); - } - - return hsv_type; -} +G_DEFINE_TYPE (GtkHSV, gtk_hsv, GTK_TYPE_WIDGET) /* Class initialization function for the HSV color selector */ static void gtk_hsv_class_init (GtkHSVClass *class) { - GtkObjectClass *object_class; + GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkHSVClass *hsv_class; GtkBindingSet *binding_set; - - object_class = (GtkObjectClass *) class; + + gobject_class = (GObjectClass *) class; widget_class = (GtkWidgetClass *) class; hsv_class = GTK_HSV_CLASS (class); - - parent_class = g_type_class_peek_parent (class); - - object_class->destroy = gtk_hsv_destroy; - - widget_class->map = gtk_hsv_map; - widget_class->unmap = gtk_hsv_unmap; + + widget_class->destroy = gtk_hsv_destroy; widget_class->realize = gtk_hsv_realize; widget_class->unrealize = gtk_hsv_unrealize; - widget_class->size_request = gtk_hsv_size_request; + widget_class->get_preferred_width = gtk_hsv_get_preferred_width; + widget_class->get_preferred_height = gtk_hsv_get_preferred_height; widget_class->size_allocate = gtk_hsv_size_allocate; widget_class->button_press_event = gtk_hsv_button_press; widget_class->button_release_event = gtk_hsv_button_release; widget_class->motion_notify_event = gtk_hsv_motion; - widget_class->expose_event = gtk_hsv_expose; + widget_class->draw = gtk_hsv_draw; widget_class->focus = gtk_hsv_focus; - + widget_class->grab_broken_event = gtk_hsv_grab_broken; + hsv_class->move = gtk_hsv_move; - + hsv_signals[CHANGED] = - g_signal_new ("changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkHSVClass, changed), - NULL, NULL, - _gtk_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new (I_("changed"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkHSVClass, changed), + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); hsv_signals[MOVE] = - g_signal_new ("move", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GtkHSVClass, move), - NULL, NULL, - _gtk_marshal_VOID__ENUM, - G_TYPE_NONE, 1, - GTK_TYPE_DIRECTION_TYPE); + g_signal_new (I_("move"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkHSVClass, move), + NULL, NULL, + _gtk_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_DIRECTION_TYPE); binding_set = gtk_binding_set_by_class (class); - gtk_binding_entry_add_signal (binding_set, GDK_Up, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_UP); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Up, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_UP); - - gtk_binding_entry_add_signal (binding_set, GDK_Down, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_DOWN); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Down, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_DOWN); - - - gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_RIGHT); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_RIGHT); - - gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_LEFT); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move", 1, G_TYPE_ENUM, GTK_DIR_LEFT); + + g_type_class_add_private (gobject_class, sizeof (GtkHSVPrivate)); } -/* Object initialization function for the HSV color selector */ static void gtk_hsv_init (GtkHSV *hsv) { - HSVPrivate *priv; - - priv = g_new0 (HSVPrivate, 1); + GtkHSVPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (hsv, GTK_TYPE_HSV, GtkHSVPrivate); + hsv->priv = priv; - - GTK_WIDGET_SET_FLAGS (hsv, GTK_NO_WINDOW); - GTK_WIDGET_SET_FLAGS (hsv, GTK_CAN_FOCUS); - + + gtk_widget_set_has_window (GTK_WIDGET (hsv), FALSE); + gtk_widget_set_can_focus (GTK_WIDGET (hsv), TRUE); + priv->h = 0.0; priv->s = 0.0; priv->v = 0.0; - + priv->size = DEFAULT_SIZE; priv->ring_width = DEFAULT_RING_WIDTH; } -/* Destroy handler for the HSV color selector */ static void -gtk_hsv_destroy (GtkObject *object) +gtk_hsv_destroy (GtkWidget *widget) { - GtkHSV *hsv; - - g_return_if_fail (GTK_IS_HSV (object)); - - hsv = GTK_HSV (object); - - if (hsv->priv) - { - g_free (hsv->priv); - hsv->priv = NULL; - } - - GTK_OBJECT_CLASS (parent_class)->destroy (object); -} - -/* Default signal handlers */ - - -/* Map handler for the HSV color selector */ - -static void -gtk_hsv_map (GtkWidget *widget) -{ - GtkHSV *hsv; - HSVPrivate *priv; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - - GTK_WIDGET_CLASS (parent_class)->map (widget); - - gdk_window_show (priv->window); + GTK_WIDGET_CLASS (gtk_hsv_parent_class)->destroy (widget); } -/* Unmap handler for the HSV color selector */ - -static void -gtk_hsv_unmap (GtkWidget *widget) -{ - GtkHSV *hsv; - HSVPrivate *priv; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - - gdk_window_hide (priv->window); - - GTK_WIDGET_CLASS (parent_class)->unmap (widget); -} - -/* Realize handler for the HSV color selector */ static void gtk_hsv_realize (GtkWidget *widget) { - GtkHSV *hsv; - HSVPrivate *priv; + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; + GtkAllocation allocation; + GdkWindow *parent_window; GdkWindowAttr attr; int attr_mask; - GdkWindow *parent_window; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - - /* Create window */ - + + gtk_widget_set_realized (widget, TRUE); + + gtk_widget_get_allocation (widget, &allocation); + attr.window_type = GDK_WINDOW_CHILD; - attr.x = widget->allocation.x; - attr.y = widget->allocation.y; - attr.width = widget->allocation.width; - attr.height = widget->allocation.height; + attr.x = allocation.x; + attr.y = allocation.y; + attr.width = allocation.width; + attr.height = allocation.height; attr.wclass = GDK_INPUT_ONLY; attr.event_mask = gtk_widget_get_events (widget); attr.event_mask |= (GDK_KEY_PRESS_MASK | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - attr_mask = GDK_WA_X | GDK_WA_Y; - + parent_window = gtk_widget_get_parent_window (widget); - - widget->window = parent_window; - g_object_ref (widget->window); - + gtk_widget_set_window (widget, parent_window); + g_object_ref (parent_window); + priv->window = gdk_window_new (parent_window, &attr, attr_mask); gdk_window_set_user_data (priv->window, hsv); - - widget->style = gtk_style_attach (widget->style, widget->window); - - /* Create GC */ - - priv->gc = gdk_gc_new (parent_window); + gdk_window_show (priv->window); + + gtk_widget_style_attach (widget); } -/* Unrealize handler for the HSV color selector */ static void gtk_hsv_unrealize (GtkWidget *widget) { - GtkHSV *hsv; - HSVPrivate *priv; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; + gdk_window_set_user_data (priv->window, NULL); gdk_window_destroy (priv->window); priv->window = NULL; - - g_object_unref (priv->gc); - priv->gc = NULL; - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - GTK_WIDGET_CLASS (parent_class)->unrealize (widget); + + GTK_WIDGET_CLASS (gtk_hsv_parent_class)->unrealize (widget); } -/* Size_request handler for the HSV color selector */ static void -gtk_hsv_size_request (GtkWidget *widget, - GtkRequisition *requisition) +gtk_hsv_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) { - GtkHSV *hsv; - HSVPrivate *priv; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - - requisition->width = priv->size; - requisition->height = priv->size; + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; + gint focus_width; + gint focus_pad; + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + *minimum = priv->size + 2 * (focus_width + focus_pad); + *natural = priv->size + 2 * (focus_width + focus_pad); +} + +static void +gtk_hsv_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; + gint focus_width; + gint focus_pad; + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + *minimum = priv->size + 2 * (focus_width + focus_pad); + *natural = priv->size + 2 * (focus_width + focus_pad); } -/* Size_allocate handler for the HSV color selector */ static void gtk_hsv_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) + GtkAllocation *allocation) { - GtkHSV *hsv; - HSVPrivate *priv; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - - widget->allocation = *allocation; - - if (GTK_WIDGET_REALIZED (widget)) + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_realized (widget)) gdk_window_move_resize (priv->window, - allocation->x, - allocation->y, - allocation->width, - allocation->height); + allocation->x, + allocation->y, + allocation->width, + allocation->height); } @@ -418,12 +335,12 @@ gtk_hsv_size_allocate (GtkWidget *widget, /* Converts from HSV to RGB */ static void hsv_to_rgb (gdouble *h, - gdouble *s, - gdouble *v) + gdouble *s, + gdouble *v) { gdouble hue, saturation, value; gdouble f, p, q, t; - + if (*s == 0.0) { *h = *v; @@ -435,129 +352,129 @@ hsv_to_rgb (gdouble *h, hue = *h * 6.0; saturation = *s; value = *v; - + if (hue == 6.0) - hue = 0.0; - + hue = 0.0; + f = hue - (int) hue; p = value * (1.0 - saturation); q = value * (1.0 - saturation * f); t = value * (1.0 - saturation * (1.0 - f)); - + switch ((int) hue) - { - case 0: - *h = value; - *s = t; - *v = p; - break; - - case 1: - *h = q; - *s = value; - *v = p; - break; - - case 2: - *h = p; - *s = value; - *v = t; - break; - - case 3: - *h = p; - *s = q; - *v = value; - break; - - case 4: - *h = t; - *s = p; - *v = value; - break; - - case 5: - *h = value; - *s = p; - *v = q; - break; - - default: - g_assert_not_reached (); - } + { + case 0: + *h = value; + *s = t; + *v = p; + break; + + case 1: + *h = q; + *s = value; + *v = p; + break; + + case 2: + *h = p; + *s = value; + *v = t; + break; + + case 3: + *h = p; + *s = q; + *v = value; + break; + + case 4: + *h = t; + *s = p; + *v = value; + break; + + case 5: + *h = value; + *s = p; + *v = q; + break; + + default: + g_assert_not_reached (); + } } } /* Converts from RGB to HSV */ static void rgb_to_hsv (gdouble *r, - gdouble *g, - gdouble *b) + gdouble *g, + gdouble *b) { gdouble red, green, blue; gdouble h, s, v; gdouble min, max; gdouble delta; - + red = *r; green = *g; blue = *b; - + h = 0.0; - + if (red > green) { if (red > blue) - max = red; + max = red; else - max = blue; - + max = blue; + if (green < blue) - min = green; + min = green; else - min = blue; + min = blue; } else { if (green > blue) - max = green; + max = green; else - max = blue; - + max = blue; + if (red < blue) - min = red; + min = red; else - min = blue; + min = blue; } - + v = max; - + if (max != 0.0) s = (max - min) / max; else s = 0.0; - + if (s == 0.0) h = 0.0; else { delta = max - min; - + if (red == max) - h = (green - blue) / delta; + h = (green - blue) / delta; else if (green == max) - h = 2 + (blue - red) / delta; + h = 2 + (blue - red) / delta; else if (blue == max) - h = 4 + (red - green) / delta; - + h = 4 + (red - green) / delta; + h /= 6.0; - + if (h < 0.0) - h += 1.0; + h += 1.0; else if (h > 1.0) - h -= 1.0; + h -= 1.0; } - + *r = h; *g = s; *b = v; @@ -566,148 +483,151 @@ rgb_to_hsv (gdouble *r, /* Computes the vertices of the saturation/value triangle */ static void compute_triangle (GtkHSV *hsv, - gint *hx, - gint *hy, - gint *sx, - gint *sy, - gint *vx, - gint *vy) + gint *hx, + gint *hy, + gint *sx, + gint *sy, + gint *vx, + gint *vy) { - HSVPrivate *priv; - gdouble center; + GtkHSVPrivate *priv = hsv->priv; + GtkWidget *widget = GTK_WIDGET (hsv); + gdouble center_x; + gdouble center_y; gdouble inner, outer; gdouble angle; - - priv = hsv->priv; - - center = priv->size / 2.0; + + center_x = gtk_widget_get_allocated_width (widget) / 2.0; + center_y = gtk_widget_get_allocated_height (widget) / 2.0; outer = priv->size / 2.0; inner = outer - priv->ring_width; angle = priv->h * 2.0 * G_PI; - - *hx = floor (center + cos (angle) * inner + 0.5); - *hy = floor (center - sin (angle) * inner + 0.5); - *sx = floor (center + cos (angle + 2.0 * G_PI / 3.0) * inner + 0.5); - *sy = floor (center - sin (angle + 2.0 * G_PI / 3.0) * inner + 0.5); - *vx = floor (center + cos (angle + 4.0 * G_PI / 3.0) * inner + 0.5); - *vy = floor (center - sin (angle + 4.0 * G_PI / 3.0) * inner + 0.5); + + *hx = floor (center_x + cos (angle) * inner + 0.5); + *hy = floor (center_y - sin (angle) * inner + 0.5); + *sx = floor (center_x + cos (angle + 2.0 * G_PI / 3.0) * inner + 0.5); + *sy = floor (center_y - sin (angle + 2.0 * G_PI / 3.0) * inner + 0.5); + *vx = floor (center_x + cos (angle + 4.0 * G_PI / 3.0) * inner + 0.5); + *vy = floor (center_y - sin (angle + 4.0 * G_PI / 3.0) * inner + 0.5); } /* Computes whether a point is inside the hue ring */ static gboolean is_in_ring (GtkHSV *hsv, - gdouble x, - gdouble y) + gdouble x, + gdouble y) { - HSVPrivate *priv; + GtkHSVPrivate *priv = hsv->priv; + GtkWidget *widget = GTK_WIDGET (hsv); gdouble dx, dy, dist; - gdouble center, inner, outer; - - priv = hsv->priv; - - center = priv->size / 2.0; + gdouble center_x; + gdouble center_y; + gdouble inner, outer; + + center_x = gtk_widget_get_allocated_width (widget) / 2.0; + center_y = gtk_widget_get_allocated_height (widget) / 2.0; outer = priv->size / 2.0; inner = outer - priv->ring_width; - - dx = x - center; - dy = center - y; + + dx = x - center_x; + dy = center_y - y; dist = dx * dx + dy * dy; - + return (dist >= inner * inner && dist <= outer * outer); } /* Computes a saturation/value pair based on the mouse coordinates */ static void compute_sv (GtkHSV *hsv, - gdouble x, - gdouble y, - gdouble *s, - gdouble *v) + gdouble x, + gdouble y, + gdouble *s, + gdouble *v) { - HSVPrivate *priv; + GtkWidget *widget = GTK_WIDGET (hsv); int ihx, ihy, isx, isy, ivx, ivy; double hx, hy, sx, sy, vx, vy; - double center; - - priv = hsv->priv; - + double center_x; + double center_y; + compute_triangle (hsv, &ihx, &ihy, &isx, &isy, &ivx, &ivy); - center = priv->size / 2.0; - hx = ihx - center; - hy = center - ihy; - sx = isx - center; - sy = center - isy; - vx = ivx - center; - vy = center - ivy; - x -= center; - y = center - y; + center_x = gtk_widget_get_allocated_width (widget) / 2.0; + center_y = gtk_widget_get_allocated_height (widget) / 2.0; + hx = ihx - center_x; + hy = center_y - ihy; + sx = isx - center_x; + sy = center_y - isy; + vx = ivx - center_x; + vy = center_y - ivy; + x -= center_x; + y = center_y - y; if (vx * (x - sx) + vy * (y - sy) < 0.0) { *s = 1.0; *v = (((x - sx) * (hx - sx) + (y - sy) * (hy-sy)) - / ((hx - sx) * (hx - sx) + (hy - sy) * (hy - sy))); + / ((hx - sx) * (hx - sx) + (hy - sy) * (hy - sy))); if (*v < 0.0) - *v = 0.0; + *v = 0.0; else if (*v > 1.0) - *v = 1.0; + *v = 1.0; } else if (hx * (x - sx) + hy * (y - sy) < 0.0) { *s = 0.0; *v = (((x - sx) * (vx - sx) + (y - sy) * (vy - sy)) - / ((vx - sx) * (vx - sx) + (vy - sy) * (vy - sy))); + / ((vx - sx) * (vx - sx) + (vy - sy) * (vy - sy))); if (*v < 0.0) - *v = 0.0; + *v = 0.0; else if (*v > 1.0) - *v = 1.0; + *v = 1.0; } else if (sx * (x - hx) + sy * (y - hy) < 0.0) { *v = 1.0; *s = (((x - vx) * (hx - vx) + (y - vy) * (hy - vy)) / - ((hx - vx) * (hx - vx) + (hy - vy) * (hy - vy))); + ((hx - vx) * (hx - vx) + (hy - vy) * (hy - vy))); if (*s < 0.0) - *s = 0.0; + *s = 0.0; else if (*s > 1.0) - *s = 1.0; + *s = 1.0; } else { *v = (((x - sx) * (hy - vy) - (y - sy) * (hx - vx)) - / ((vx - sx) * (hy - vy) - (vy - sy) * (hx - vx))); + / ((vx - sx) * (hy - vy) - (vy - sy) * (hx - vx))); if (*v<= 0.0) - { - *v = 0.0; - *s = 0.0; - } + { + *v = 0.0; + *s = 0.0; + } else - { - if (*v > 1.0) - *v = 1.0; - - if (fabs (hy - vy) < fabs (hx - vx)) - *s = (x - sx - *v * (vx - sx)) / (*v * (hx - vx)); - else - *s = (y - sy - *v * (vy - sy)) / (*v * (hy - vy)); - - if (*s < 0.0) - *s = 0.0; - else if (*s > 1.0) - *s = 1.0; - } + { + if (*v > 1.0) + *v = 1.0; + + if (fabs (hy - vy) < fabs (hx - vx)) + *s = (x - sx - *v * (vx - sx)) / (*v * (hx - vx)); + else + *s = (y - sy - *v * (vy - sy)) / (*v * (hy - vy)); + + if (*s < 0.0) + *s = 0.0; + else if (*s > 1.0) + *s = 1.0; + } } } /* Computes whether a point is inside the saturation/value triangle */ static gboolean is_in_triangle (GtkHSV *hsv, - gdouble x, - gdouble y) + gdouble x, + gdouble y) { int hx, hy, sx, sy, vx, vy; double det, s, v; @@ -725,24 +645,24 @@ is_in_triangle (GtkHSV *hsv, /* Computes a value based on the mouse coordinates */ static double compute_v (GtkHSV *hsv, - gdouble x, - gdouble y) + gdouble x, + gdouble y) { - HSVPrivate *priv; - double center; + GtkWidget *widget = GTK_WIDGET (hsv); + double center_x; + double center_y; double dx, dy; double angle; - - priv = hsv->priv; - - center = priv->size / 2.0; - dx = x - center; - dy = center - y; - + + center_x = gtk_widget_get_allocated_width (widget) / 2.0; + center_y = gtk_widget_get_allocated_height (widget) / 2.0; + dx = x - center_x; + dy = center_y - y; + angle = atan2 (dy, dx); if (angle < 0.0) angle += 2.0 * G_PI; - + return angle / (2.0 * G_PI); } @@ -750,37 +670,43 @@ compute_v (GtkHSV *hsv, static void set_cross_grab (GtkHSV *hsv, - guint32 time) + guint32 time) { - HSVPrivate *priv; + GtkHSVPrivate *priv = hsv->priv; GdkCursor *cursor; - - priv = hsv->priv; - + cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (hsv)), - GDK_CROSSHAIR); + GDK_CROSSHAIR); gdk_pointer_grab (priv->window, FALSE, - (GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK - | GDK_BUTTON_RELEASE_MASK), - NULL, - cursor, - time); - gdk_cursor_unref (cursor); + (GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_RELEASE_MASK), + NULL, + cursor, + time); + g_object_unref (cursor); +} + +static gboolean +gtk_hsv_grab_broken (GtkWidget *widget, + GdkEventGrabBroken *event) +{ + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; + + priv->mode = DRAG_NONE; + + return TRUE; } -/* Button_press_event handler for the HSV color selector */ static gint gtk_hsv_button_press (GtkWidget *widget, - GdkEventButton *event) + GdkEventButton *event) { - GtkHSV *hsv; - HSVPrivate *priv; + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; double x, y; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - + if (priv->mode != DRAG_NONE || event->button != 1) return FALSE; @@ -793,9 +719,9 @@ gtk_hsv_button_press (GtkWidget *widget, set_cross_grab (hsv, event->time); gtk_hsv_set_color (hsv, - compute_v (hsv, x, y), - priv->s, - priv->v); + compute_v (hsv, x, y), + priv->s, + priv->v); gtk_widget_grab_focus (widget); priv->focus_on_ring = TRUE; @@ -822,19 +748,15 @@ gtk_hsv_button_press (GtkWidget *widget, return FALSE; } -/* Button_release_event handler for the HSV color selector */ static gint gtk_hsv_button_release (GtkWidget *widget, - GdkEventButton *event) + GdkEventButton *event) { - GtkHSV *hsv; - HSVPrivate *priv; + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; DragMode mode; gdouble x, y; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - + if (priv->mode == DRAG_NONE || event->button != 1) return FALSE; @@ -847,51 +769,45 @@ gtk_hsv_button_release (GtkWidget *widget, x = event->x; y = event->y; - + if (mode == DRAG_H) - gtk_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v); - else if (mode == DRAG_SV) { - double s, v; - - compute_sv (hsv, x, y, &s, &v); - gtk_hsv_set_color (hsv, priv->h, s, v); - } else - g_assert_not_reached (); - - gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window), - event->time); + { + gtk_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v); + } + else if (mode == DRAG_SV) + { + gdouble s, v; + + compute_sv (hsv, x, y, &s, &v); + gtk_hsv_set_color (hsv, priv->h, s, v); + } + else + { + g_assert_not_reached (); + } + + gdk_display_pointer_ungrab (gdk_window_get_display (event->window), + event->time); return TRUE; } -/* Motion_notify_event handler for the HSV color selector */ static gint gtk_hsv_motion (GtkWidget *widget, - GdkEventMotion *event) + GdkEventMotion *event) { - GtkHSV *hsv; - HSVPrivate *priv; - double x, y; - gint ix, iy; + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; GdkModifierType mods; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - + double x, y; + if (priv->mode == DRAG_NONE) return FALSE; - - if (event->is_hint) - { - gdk_window_get_pointer (priv->window, &ix, &iy, &mods); - x = ix; - y = iy; - } - else - { - x = event->x; - y = event->y; - } - + + gdk_event_request_motions (event); + x = event->x; + y = event->y; + mods = event->state; + if (priv->mode == DRAG_H) { gtk_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v); @@ -899,14 +815,15 @@ gtk_hsv_motion (GtkWidget *widget, } else if (priv->mode == DRAG_SV) { - double s, v; - + gdouble s, v; + compute_sv (hsv, x, y, &s, &v); gtk_hsv_set_color (hsv, priv->h, s, v); return TRUE; } - + g_assert_not_reached (); + return FALSE; } @@ -915,113 +832,87 @@ gtk_hsv_motion (GtkWidget *widget, /* Paints the hue ring */ static void -paint_ring (GtkHSV *hsv, - GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height) +paint_ring (GtkHSV *hsv, + cairo_t *cr) { - HSVPrivate *priv; - int xx, yy; + GtkHSVPrivate *priv = hsv->priv; + GtkWidget *widget = GTK_WIDGET (hsv); + int xx, yy, width, height; gdouble dx, dy, dist; - gdouble center; + gdouble center_x; + gdouble center_y; gdouble inner, outer; - guchar *buf, *p; + guint32 *buf, *p; gdouble angle; gdouble hue; gdouble r, g, b; - GdkBitmap *mask; - GdkGC *gc; - GdkColor color; - - priv = hsv->priv; - - center = priv->size / 2.0; - + cairo_surface_t *source; + cairo_t *source_cr; + gint stride; + gint focus_width; + gint focus_pad; + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + center_x = width / 2.0; + center_y = height / 2.0; + outer = priv->size / 2.0; inner = outer - priv->ring_width; - - /* Paint the ring */ - - buf = g_new (guchar, width * height * 3); - + + /* Create an image initialized with the ring colors */ + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width); + buf = g_new (guint32, height * stride / 4); + for (yy = 0; yy < height; yy++) { - p = buf + yy * width * 3; - - dy = -(yy + y - center); - + p = buf + yy * width; + + dy = -(yy - center_y); + for (xx = 0; xx < width; xx++) - { - dx = xx + x - center; - - dist = dx * dx + dy * dy; - if (dist < ((inner-1) * (inner-1)) || dist > ((outer+1) * (outer+1))) - { - *p++ = 0; - *p++ = 0; - *p++ = 0; - continue; - } - - angle = atan2 (dy, dx); - if (angle < 0.0) - angle += 2.0 * G_PI; - - hue = angle / (2.0 * G_PI); - - r = hue; - g = 1.0; - b = 1.0; - hsv_to_rgb (&r, &g, &b); - - *p++ = floor (r * 255 + 0.5); - *p++ = floor (g * 255 + 0.5); - *p++ = floor (b * 255 + 0.5); - } + { + dx = xx - center_x; + + dist = dx * dx + dy * dy; + if (dist < ((inner-1) * (inner-1)) || dist > ((outer+1) * (outer+1))) + { + *p++ = 0; + continue; + } + + angle = atan2 (dy, dx); + if (angle < 0.0) + angle += 2.0 * G_PI; + + hue = angle / (2.0 * G_PI); + + r = hue; + g = 1.0; + b = 1.0; + hsv_to_rgb (&r, &g, &b); + + *p++ = (((int)floor (r * 255 + 0.5) << 16) | + ((int)floor (g * 255 + 0.5) << 8) | + (int)floor (b * 255 + 0.5)); + } } - - /* Create clipping mask */ - - mask = gdk_pixmap_new (GTK_WIDGET (hsv)->window, width, height, 1); - gc = gdk_gc_new (mask); - - color.pixel = 0; - gdk_gc_set_foreground (gc, &color); - gdk_draw_rectangle (mask, gc, TRUE, - 0, 0, width, height); - - - color.pixel = 1; - gdk_gc_set_foreground (gc, &color); - gdk_draw_arc (mask, gc, TRUE, - -x, -y, - priv->size - 1, priv->size - 1, - 0, 360 * 64); - - color.pixel = 0; - gdk_gc_set_foreground (gc, &color); - gdk_draw_arc (mask, gc, TRUE, - -x + priv->ring_width - 1, -y + priv->ring_width - 1, - priv->size - 2 * priv->ring_width + 1, priv->size - 2 * priv->ring_width + 1, - 0, 360 * 64); - - g_object_unref (gc); - - gdk_gc_set_clip_mask (priv->gc, mask); - gdk_gc_set_clip_origin (priv->gc, 0, 0); - - /* Draw ring */ - - gdk_draw_rgb_image_dithalign (drawable, priv->gc, 0, 0, width, height, - GDK_RGB_DITHER_MAX, - buf, - width * 3, - x, y); - - /* Draw value marker */ + source = cairo_image_surface_create_for_data ((unsigned char *)buf, + CAIRO_FORMAT_RGB24, + width, height, stride); + + /* Now draw the value marker onto the source image, so that it + * will get properly clipped at the edges of the ring + */ + source_cr = cairo_create (source); r = priv->h; g = 1.0; @@ -1029,52 +920,45 @@ paint_ring (GtkHSV *hsv, hsv_to_rgb (&r, &g, &b); if (INTENSITY (r, g, b) > 0.5) - gdk_rgb_gc_set_foreground (priv->gc, 0x000000); + cairo_set_source_rgb (source_cr, 0., 0., 0.); else - gdk_rgb_gc_set_foreground (priv->gc, 0xffffff); - - gdk_draw_line (drawable, priv->gc, - -x + center, -y + center, - -x + center + cos (priv->h * 2.0 * G_PI) * center, - -y + center - sin (priv->h * 2.0 * G_PI) * center); + cairo_set_source_rgb (source_cr, 1., 1., 1.); + + cairo_move_to (source_cr, center_x, center_y); + cairo_line_to (source_cr, + center_x + cos (priv->h * 2.0 * G_PI) * priv->size / 2, + center_y - sin (priv->h * 2.0 * G_PI) * priv->size / 2); + cairo_stroke (source_cr); + cairo_destroy (source_cr); + + /* Draw the ring using the source image */ + + cairo_save (cr); + + cairo_set_source_surface (cr, source, 0, 0); + cairo_surface_destroy (source); + + cairo_set_line_width (cr, priv->ring_width); + cairo_new_path (cr); + cairo_arc (cr, + center_x, center_y, + priv->size / 2. - priv->ring_width / 2., + 0, 2 * G_PI); + cairo_stroke (cr); - gdk_gc_set_clip_mask (priv->gc, NULL); - g_object_unref (mask); + cairo_restore (cr); g_free (buf); - - /* Draw ring outline */ - - if (GTK_WIDGET_HAS_FOCUS (hsv) && - priv->focus_on_ring) - { - gint focus_width; - gint focus_halfwidth; - GdkGC *gc = gtk_hsv_get_focus_gc (hsv, &focus_width); - focus_halfwidth = (focus_width + 1) / 2; - - gdk_draw_arc (drawable, gc, FALSE, - -x + focus_width/2, -y + focus_width/2, - priv->size - focus_width, priv->size - focus_width, - 0, 360 * 64); - gdk_draw_arc (drawable, gc, FALSE, - -x + priv->ring_width - focus_halfwidth, -y + priv->ring_width - focus_halfwidth, - priv->size - 2 * priv->ring_width + focus_width, - priv->size - 2 * priv->ring_width + focus_width, - 0, 360 * 64); - - g_object_unref (gc); - } } /* Converts an HSV triplet to an integer RGB triplet */ static void get_color (gdouble h, - gdouble s, - gdouble v, - gint *r, - gint *g, - gint *b) + gdouble s, + gdouble v, + gint *r, + gint *g, + gint *b) { hsv_to_rgb (&h, &s, &v); @@ -1085,36 +969,41 @@ get_color (gdouble h, #define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) -#define LERP(a, b, v1, v2, i) (((v2) - (v1) != 0) \ - ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2) - (v1))) \ - : (a)) +#define LERP(a, b, v1, v2, i) (((v2) - (v1) != 0) \ + ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2) - (v1))) \ + : (a)) + +/* Number of pixels we extend out from the edges when creating + * color source to avoid artifacts + */ +#define PAD 3 /* Paints the HSV triangle */ static void paint_triangle (GtkHSV *hsv, - GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height) + cairo_t *cr) { - HSVPrivate *priv; + GtkHSVPrivate *priv = hsv->priv; + GtkWidget *widget = GTK_WIDGET (hsv); gint hx, hy, sx, sy, vx, vy; /* HSV vertices */ gint x1, y1, r1, g1, b1; /* First vertex in scanline order */ gint x2, y2, r2, g2, b2; /* Second vertex */ gint x3, y3, r3, g3, b3; /* Third vertex */ gint t; - guchar *buf, *p; + guint32 *buf, *p, c; gint xl, xr, rl, rr, gl, gr, bl, br; /* Scanline data */ gint xx, yy; - GdkBitmap *mask; - GdkGC *gc; - GdkColor color; - GdkPoint points[3]; + gint x_interp, y_interp; + gint x_start, x_end; + cairo_surface_t *source; gdouble r, g, b; + gchar *detail; + gint stride; + int width, height; priv = hsv->priv; - + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); /* Compute triangle's vertices */ compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy); @@ -1122,15 +1011,15 @@ paint_triangle (GtkHSV *hsv, x1 = hx; y1 = hy; get_color (priv->h, 1.0, 1.0, &r1, &g1, &b1); - + x2 = sx; y2 = sy; get_color (priv->h, 1.0, 0.0, &r2, &g2, &b2); - + x3 = vx; y3 = vy; get_color (priv->h, 0.0, 1.0, &r3, &g3, &b3); - + if (y2 > y3) { SWAP (x2, x3, t); @@ -1139,7 +1028,7 @@ paint_triangle (GtkHSV *hsv, SWAP (g2, g3, t); SWAP (b2, b3, t); } - + if (y1 > y3) { SWAP (x1, x3, t); @@ -1148,7 +1037,7 @@ paint_triangle (GtkHSV *hsv, SWAP (g1, g3, t); SWAP (b1, b3, t); } - + if (y1 > y2) { SWAP (x1, x2, t); @@ -1157,214 +1046,164 @@ paint_triangle (GtkHSV *hsv, SWAP (g1, g2, t); SWAP (b1, b2, t); } - + /* Shade the triangle */ - - buf = g_new (guchar, width * height * 3); - + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width); + buf = g_new (guint32, height * stride / 4); + for (yy = 0; yy < height; yy++) { - p = buf + yy * width * 3; - - if (yy + y < y1 || yy + y > y3) - for (xx = 0; xx < width; xx++) - { - *p++ = 0; - *p++ = 0; - *p++ = 0; - } - else { - if (yy + y < y2) - { - xl = LERP (x1, x2, y1, y2, yy + y); - - rl = LERP (r1, r2, y1, y2, yy + y); - gl = LERP (g1, g2, y1, y2, yy + y); - bl = LERP (b1, b2, y1, y2, yy + y); - } - else - { - xl = LERP (x2, x3, y2, y3, yy + y); - - rl = LERP (r2, r3, y2, y3, yy + y); - gl = LERP (g2, g3, y2, y3, yy + y); - bl = LERP (b2, b3, y2, y3, yy + y); - } - - xr = LERP (x1, x3, y1, y3, yy + y); - - rr = LERP (r1, r3, y1, y3, yy + y); - gr = LERP (g1, g3, y1, y3, yy + y); - br = LERP (b1, b3, y1, y3, yy + y); - - if (xl > xr) - { - SWAP (xl, xr, t); - SWAP (rl, rr, t); - SWAP (gl, gr, t); - SWAP (bl, br, t); - } - - for (xx = 0; xx < width; xx++) - { - if (xx + x < xl || xx + x > xr) - { - *p++ = 0; - *p++ = 0; - *p++ = 0; - } - else - { - *p++ = LERP (rl, rr, xl, xr, xx + x); - *p++ = LERP (gl, gr, xl, xr, xx + x); - *p++ = LERP (bl, br, xl, xr, xx + x); - } - } + p = buf + yy * width; + + if (yy >= y1 - PAD && yy < y3 + PAD) { + y_interp = CLAMP (yy, y1, y3); + + if (y_interp < y2) + { + xl = LERP (x1, x2, y1, y2, y_interp); + + rl = LERP (r1, r2, y1, y2, y_interp); + gl = LERP (g1, g2, y1, y2, y_interp); + bl = LERP (b1, b2, y1, y2, y_interp); + } + else + { + xl = LERP (x2, x3, y2, y3, y_interp); + + rl = LERP (r2, r3, y2, y3, y_interp); + gl = LERP (g2, g3, y2, y3, y_interp); + bl = LERP (b2, b3, y2, y3, y_interp); + } + + xr = LERP (x1, x3, y1, y3, y_interp); + + rr = LERP (r1, r3, y1, y3, y_interp); + gr = LERP (g1, g3, y1, y3, y_interp); + br = LERP (b1, b3, y1, y3, y_interp); + + if (xl > xr) + { + SWAP (xl, xr, t); + SWAP (rl, rr, t); + SWAP (gl, gr, t); + SWAP (bl, br, t); + } + + x_start = MAX (xl - PAD, 0); + x_end = MIN (xr + PAD, width); + x_start = MIN (x_start, x_end); + + c = (rl << 16) | (gl << 8) | bl; + + for (xx = 0; xx < x_start; xx++) + *p++ = c; + + for (; xx < x_end; xx++) + { + x_interp = CLAMP (xx, xl, xr); + + *p++ = ((LERP (rl, rr, xl, xr, x_interp) << 16) | + (LERP (gl, gr, xl, xr, x_interp) << 8) | + LERP (bl, br, xl, xr, x_interp)); + } + + c = (rr << 16) | (gr << 8) | br; + + for (; xx < width; xx++) + *p++ = c; } } - - /* Create clipping mask */ - - mask = gdk_pixmap_new (GTK_WIDGET (hsv)->window, width, height, 1); - gc = gdk_gc_new (mask); - - color.pixel = 0; - gdk_gc_set_foreground (gc, &color); - gdk_draw_rectangle (mask, gc, TRUE, - 0, 0, width, height); - - color.pixel = 1; - gdk_gc_set_foreground (gc, &color); - - points[0].x = x1 - x; - points[0].y = y1 - y; - points[1].x = x2 - x; - points[1].y = y2 - y; - points[2].x = x3 - x; - points[2].y = y3 - y; - gdk_draw_polygon (mask, gc, TRUE, points, 3); - - g_object_unref (gc); - - gdk_gc_set_clip_mask (priv->gc, mask); - gdk_gc_set_clip_origin (priv->gc, 0, 0); - - /* Draw triangle */ + source = cairo_image_surface_create_for_data ((unsigned char *)buf, + CAIRO_FORMAT_RGB24, + width, height, stride); - gdk_draw_rgb_image_dithalign (drawable, priv->gc, 0, 0, width, height, - GDK_RGB_DITHER_MAX, - buf, - width * 3, - x, y); + /* Draw a triangle with the image as a source */ + + cairo_set_source_surface (cr, source, 0, 0); + cairo_surface_destroy (source); - gdk_gc_set_clip_mask (priv->gc, NULL); - g_object_unref (mask); + cairo_move_to (cr, x1, y1); + cairo_line_to (cr, x2, y2); + cairo_line_to (cr, x3, y3); + cairo_close_path (cr); + cairo_fill (cr); g_free (buf); - /* Draw triangle focus outline */ - - if (GTK_WIDGET_HAS_FOCUS (hsv) && - !priv->focus_on_ring) - { - gint focus_width = 1; - GdkGC *gc = gtk_hsv_get_focus_gc (hsv, &focus_width); - - gdk_draw_polygon (drawable, gc, FALSE, points, 3); - g_object_unref (gc); - } - /* Draw value marker */ - xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5) - x; - yy = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5) - y; + xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5); + yy = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5); r = priv->h; g = priv->s; b = priv->v; hsv_to_rgb (&r, &g, &b); - + if (INTENSITY (r, g, b) > 0.5) - gdk_rgb_gc_set_foreground (priv->gc, 0x000000); + { + detail = "colorwheel_light"; + cairo_set_source_rgb (cr, 0., 0., 0.); + } else - gdk_rgb_gc_set_foreground (priv->gc, 0xffffff); + { + detail = "colorwheel_dark"; + cairo_set_source_rgb (cr, 1., 1., 1.); + } + +#define RADIUS 4 +#define FOCUS_RADIUS 6 -#define OUTER_RADIUS 4 -#define INNER_RADIUS 3 + cairo_new_path (cr); + cairo_arc (cr, xx, yy, RADIUS, 0, 2 * G_PI); + cairo_stroke (cr); - gdk_draw_arc (drawable, priv->gc, FALSE, - xx - OUTER_RADIUS, yy - OUTER_RADIUS, - OUTER_RADIUS * 2, OUTER_RADIUS * 2, - 0, 360 * 64); - gdk_draw_arc (drawable, priv->gc, FALSE, - xx - INNER_RADIUS, yy - INNER_RADIUS, - INNER_RADIUS * 2, INNER_RADIUS * 2, - 0, 360 * 64); + /* Draw focus outline */ + + if (gtk_widget_has_focus (widget) && + !priv->focus_on_ring) + { + gint focus_width; + gint focus_pad; + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + gtk_paint_focus (gtk_widget_get_style (widget), + cr, + gtk_widget_get_state (widget), + widget, detail, + xx - FOCUS_RADIUS - focus_width - focus_pad, + yy - FOCUS_RADIUS - focus_width - focus_pad, + 2 * (FOCUS_RADIUS + focus_width + focus_pad), + 2 * (FOCUS_RADIUS + focus_width + focus_pad)); + } } /* Paints the contents of the HSV color selector */ -static void -paint (GtkHSV *hsv, - GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height) +static gboolean +gtk_hsv_draw (GtkWidget *widget, + cairo_t *cr) { - paint_ring (hsv, drawable, x, y, width, height); - paint_triangle (hsv, drawable, x, y, width, height); -} + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; + + paint_ring (hsv, cr); + paint_triangle (hsv, cr); + + if (gtk_widget_has_focus (widget) && priv->focus_on_ring) + gtk_paint_focus (gtk_widget_get_style (widget), + cr, + gtk_widget_get_state (widget), + widget, NULL, + 0, 0, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); -/* Expose_event handler for the HSV color selector */ -static gint -gtk_hsv_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - GtkHSV *hsv; - HSVPrivate *priv; - GdkRectangle rect, dest; - GdkPixmap *pixmap; - - hsv = GTK_HSV (widget); - priv = hsv->priv; - - if (!(GTK_WIDGET_DRAWABLE (widget) && event->window == widget->window)) - return FALSE; - - rect.x = widget->allocation.x; - rect.y = widget->allocation.y; - rect.width = widget->allocation.width; - rect.height = widget->allocation.height; - - if (!gdk_rectangle_intersect (&event->area, &rect, &dest)) - return FALSE; - - pixmap = gdk_pixmap_new (widget->window, dest.width, dest.height, - gtk_widget_get_visual (widget)->depth); - - rect = dest; - rect.x = 0; - rect.y = 0; - - gdk_draw_rectangle (pixmap, - widget->style->bg_gc[GTK_WIDGET_STATE (widget)], - TRUE, - 0, 0, dest.width, dest.height); - paint (hsv, pixmap, - dest.x - widget->allocation.x, dest.y - widget->allocation.y, - dest.width, dest.height); - - gdk_draw_drawable (widget->window, - priv->gc, - pixmap, - 0, 0, - dest.x, - dest.y, - event->area.width, event->area.height); - - g_object_unref (pixmap); - return FALSE; } @@ -1372,13 +1211,10 @@ static gboolean gtk_hsv_focus (GtkWidget *widget, GtkDirectionType dir) { - GtkHSV *hsv; - HSVPrivate *priv; + GtkHSV *hsv = GTK_HSV (widget); + GtkHSVPrivate *priv = hsv->priv; - hsv = GTK_HSV (widget); - priv = hsv->priv; - - if (!GTK_WIDGET_HAS_FOCUS (hsv)) + if (!gtk_widget_has_focus (widget)) { if (dir == GTK_DIR_TAB_BACKWARD) priv->focus_on_ring = FALSE; @@ -1429,12 +1265,13 @@ gtk_hsv_focus (GtkWidget *widget, /** * gtk_hsv_new: - * @void: * * Creates a new HSV color selector. * * Return value: A newly-created HSV color selector. - **/ + * + * Since: 2.14 + */ GtkWidget* gtk_hsv_new (void) { @@ -1443,30 +1280,31 @@ gtk_hsv_new (void) /** * gtk_hsv_set_color: - * @hsv: An HSV color selector. - * @h: Hue. - * @s: Saturation. - * @v: Value. + * @hsv: An HSV color selector + * @h: Hue + * @s: Saturation + * @v: Value + * + * Sets the current color in an HSV color selector. + * Color component values must be in the [0.0, 1.0] range. * - * Sets the current color in an HSV color selector. Color component values must - * be in the [0.0, 1.0] range. - **/ + * Since: 2.14 + */ void gtk_hsv_set_color (GtkHSV *hsv, - gdouble h, - gdouble s, - gdouble v) + gdouble h, + gdouble s, + gdouble v) { - HSVPrivate *priv; - - g_return_if_fail (hsv != NULL); + GtkHSVPrivate *priv; + g_return_if_fail (GTK_IS_HSV (hsv)); g_return_if_fail (h >= 0.0 && h <= 1.0); g_return_if_fail (s >= 0.0 && s <= 1.0); g_return_if_fail (v >= 0.0 && v <= 1.0); - + priv = hsv->priv; - + priv->h = h; priv->s = s; priv->v = v; @@ -1478,21 +1316,26 @@ gtk_hsv_set_color (GtkHSV *hsv, /** * gtk_hsv_get_color: - * @hsv: An HSV color selector. - * @h: Return value for the hue. - * @s: Return value for the saturation. - * @v: Return value for the value. + * @hsv: An HSV color selector + * @h: Return value for the hue + * @s: Return value for the saturation + * @v: Return value for the value * - * Queries the current color in an HSV color selector. Returned values will be - * in the [0.0, 1.0] range. - **/ + * Queries the current color in an HSV color selector. + * Returned values will be in the [0.0, 1.0] range. + * + * Since: 2.14 + */ void -gtk_hsv_get_color (GtkHSV *hsv, double *h, double *s, double *v) +gtk_hsv_get_color (GtkHSV *hsv, + double *h, + double *s, + double *v) { - HSVPrivate *priv; - + GtkHSVPrivate *priv = hsv->priv; + g_return_if_fail (GTK_IS_HSV (hsv)); - + priv = hsv->priv; if (h) @@ -1507,27 +1350,29 @@ gtk_hsv_get_color (GtkHSV *hsv, double *h, double *s, double *v) /** * gtk_hsv_set_metrics: - * @hsv: An HSV color selector. - * @size: Diameter for the hue ring. - * @ring_width: Width of the hue ring. + * @hsv: An HSV color selector + * @size: Diameter for the hue ring + * @ring_width: Width of the hue ring * * Sets the size and ring width of an HSV color selector. - **/ + * + * Since: 2.14 + */ void gtk_hsv_set_metrics (GtkHSV *hsv, - gint size, - gint ring_width) + gint size, + gint ring_width) { - HSVPrivate *priv; + GtkHSVPrivate *priv = hsv->priv; int same_size; - + g_return_if_fail (GTK_IS_HSV (hsv)); g_return_if_fail (size > 0); g_return_if_fail (ring_width > 0); g_return_if_fail (2 * ring_width + 1 <= size); - + priv = hsv->priv; - + same_size = (priv->size == size); priv->size = size; @@ -1541,23 +1386,25 @@ gtk_hsv_set_metrics (GtkHSV *hsv, /** * gtk_hsv_get_metrics: - * @hsv: An HSV color selector. - * @size: Return value for the diameter of the hue ring. - * @ring_width: Return value for the width of the hue ring. + * @hsv: An HSV color selector + * @size: Return value for the diameter of the hue ring + * @ring_width: Return value for the width of the hue ring * * Queries the size and ring width of an HSV color selector. - **/ + * + * Since: 2.14 + */ void gtk_hsv_get_metrics (GtkHSV *hsv, - gint *size, - gint *ring_width) + gint *size, + gint *ring_width) { - HSVPrivate *priv; - + GtkHSVPrivate *priv = hsv->priv; + g_return_if_fail (GTK_IS_HSV (hsv)); - + priv = hsv->priv; - + if (size) *size = priv->size; @@ -1567,24 +1414,26 @@ gtk_hsv_get_metrics (GtkHSV *hsv, /** * gtk_hsv_is_adjusting: - * @hsv: + * @hsv: A #GtkHSV + * + * An HSV color selector can be said to be adjusting if multiple rapid + * changes are being made to its value, for example, when the user is + * adjusting the value with the mouse. This function queries whether + * the HSV color selector is being adjusted or not. * - * An HSV color selector can be said to be adjusting if multiple rapid changes - * are being made to its value, for example, when the user is adjusting the - * value with the mouse. This function queries whether the HSV color selector - * is being adjusted or not. + * Return value: %TRUE if clients can ignore changes to the color value, + * since they may be transitory, or %FALSE if they should consider + * the color value status to be final. * - * Return value: TRUE if clients can ignore changes to the color value, since - * they may be transitory, or FALSE if they should consider the color value - * status to be final. - **/ + * Since: 2.14 + */ gboolean gtk_hsv_is_adjusting (GtkHSV *hsv) { - HSVPrivate *priv; - + GtkHSVPrivate *priv = hsv->priv; + g_return_val_if_fail (GTK_IS_HSV (hsv), FALSE); - + priv = hsv->priv; return priv->mode != DRAG_NONE; @@ -1592,23 +1441,26 @@ gtk_hsv_is_adjusting (GtkHSV *hsv) /** * gtk_hsv_to_rgb: - * @h: Hue. - * @s: Saturation. - * @v: Value. - * @r: Return value for the red component. - * @g: Return value for the green component. - * @b: Return value for the blue component. - * - * Converts a color from HSV space to RGB. Input values must be in the - * [0.0, 1.0] range; output values will be in the same range. - **/ + * @h: Hue + * @s: Saturation + * @v: Value + * @r: Return value for the red component + * @g: Return value for the green component + * @b: Return value for the blue component + * + * Converts a color from HSV space to RGB. + * Input values must be in the [0.0, 1.0] range; + * output values will be in the same range. + * + * Since: 2.14 + */ void gtk_hsv_to_rgb (gdouble h, - gdouble s, - gdouble v, - gdouble *r, - gdouble *g, - gdouble *b) + gdouble s, + gdouble v, + gdouble *r, + gdouble *g, + gdouble *b) { g_return_if_fail (h >= 0.0 && h <= 1.0); g_return_if_fail (s >= 0.0 && s <= 1.0); @@ -1627,24 +1479,27 @@ gtk_hsv_to_rgb (gdouble h, } /** - * gtk_hsv_to_rgb: - * @r: Red. - * @g: Green. - * @b: Blue. - * @h: Return value for the hue component. - * @s: Return value for the saturation component. - * @v: Return value for the value component. - * - * Converts a color from RGB space to HSV. Input values must be in the - * [0.0, 1.0] range; output values will be in the same range. - **/ + * gtk_rgb_to_hsv: + * @r: Red + * @g: Green + * @b: Blue + * @h: Return value for the hue component + * @s: Return value for the saturation component + * @v: Return value for the value component + * + * Converts a color from RGB space to HSV. + * Input values must be in the [0.0, 1.0] range; + * output values will be in the same range. + * + * Since: 2.14 + */ void gtk_rgb_to_hsv (gdouble r, - gdouble g, - gdouble b, - gdouble *h, - gdouble *s, - gdouble *v) + gdouble g, + gdouble b, + gdouble *h, + gdouble *s, + gdouble *v) { g_return_if_fail (r >= 0.0 && r <= 1.0); g_return_if_fail (g >= 0.0 && g <= 1.0); @@ -1666,12 +1521,10 @@ static void gtk_hsv_move (GtkHSV *hsv, GtkDirectionType dir) { - HSVPrivate *priv; + GtkHSVPrivate *priv = hsv->priv; gdouble hue, sat, val; gint hx, hy, sx, sy, vx, vy; /* HSV vertices */ gint x, y; /* position in triangle */ - - priv = hsv->priv; hue = priv->h; sat = priv->s; @@ -1739,30 +1592,3 @@ gtk_hsv_move (GtkHSV *hsv, gtk_hsv_set_color (hsv, hue, sat, val); } - -static GdkGC * -gtk_hsv_get_focus_gc (GtkHSV *hsv, - gint *line_width) -{ - GdkGC *focus_gc; - GtkWidget *widget = GTK_WIDGET (hsv); - gint8 *dash_list; - - focus_gc = gdk_gc_new (widget->window); - gdk_gc_copy (focus_gc, widget->style->fg_gc[GTK_WIDGET_STATE (widget)]); - - gtk_widget_style_get (widget, - "focus-line-width", line_width, - "focus-line-pattern", (gchar *)&dash_list, - NULL); - - gdk_gc_set_line_attributes (focus_gc, *line_width, - dash_list[0] ? GDK_LINE_ON_OFF_DASH : GDK_LINE_SOLID, - GDK_CAP_BUTT, GDK_JOIN_MITER); - if (dash_list[0]) - gdk_gc_set_dashes (focus_gc, 0, dash_list, strlen (dash_list)); - - g_free (dash_list); - - return focus_gc; -}