* Boston, MA 02111-1307, USA.
*/
+#include <config.h>
#include <math.h>
-#include "gtksignal.h"
+#include <string.h>
#include "gtkhsv.h"
+#include "gdk/gdkkeysyms.h"
+#include "gtkbindings.h"
+#include "gtkcontainer.h"
+#include "gtkmarshalers.h"
+#include "gtkintl.h"
+#include "gtkalias.h"
/*
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
/* Dragging mode */
DragMode mode;
+
+ guint focus_on_ring : 1;
+
} HSVPrivate;
\f
enum {
CHANGED,
+ MOVE,
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 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_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.
- **/
-GtkType
-gtk_hsv_get_type (void)
-{
- static GtkType hsv_type = 0;
-
- if (!hsv_type) {
- static const GtkTypeInfo hsv_info = {
- "GtkHSV",
- sizeof (GtkHSV),
- sizeof (GtkHSVClass),
- (GtkClassInitFunc) gtk_hsv_class_init,
- (GtkObjectInitFunc) gtk_hsv_init,
- NULL, /* reserved_1 */
- NULL, /* reserved_2 */
- (GtkClassInitFunc) NULL
- };
-
- hsv_type = gtk_type_unique (GTK_TYPE_WIDGET, &hsv_info);
- }
-
- 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)
{
+ GObjectClass *gobject_class;
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
+ GtkHSVClass *hsv_class;
+ GtkBindingSet *binding_set;
+ gobject_class = (GObjectClass *) class;
object_class = (GtkObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
-
- parent_class = gtk_type_class (GTK_TYPE_WIDGET);
-
- hsv_signals[CHANGED] =
- gtk_signal_new ("changed",
- GTK_RUN_FIRST,
- GTK_CLASS_TYPE (object_class),
- GTK_SIGNAL_OFFSET (GtkHSVClass, changed),
- gtk_marshal_NONE__NONE,
- GTK_TYPE_NONE, 0);
- gtk_object_class_add_signals (object_class, hsv_signals, LAST_SIGNAL);
+ hsv_class = GTK_HSV_CLASS (class);
object_class->destroy = gtk_hsv_destroy;
widget_class->map = gtk_hsv_map;
- widget_class->unmap = gtk_hsv_unmap;
+ widget_class->unmap = gtk_hsv_unmap;
widget_class->realize = gtk_hsv_realize;
widget_class->unrealize = gtk_hsv_unrealize;
widget_class->size_request = gtk_hsv_size_request;
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->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 (I_("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);
+
+ hsv_signals[MOVE] =
+ g_signal_new (I_("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);
+
+ binding_set = gtk_binding_set_by_class (class);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_UP);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_UP);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_DOWN);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_DOWN);
+
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_RIGHT);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_RIGHT);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_LEFT);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
+ "move", 1,
+ G_TYPE_ENUM, GTK_DIR_LEFT);
+
+ g_type_class_add_private (gobject_class, sizeof (HSVPrivate));
}
/* Object initialization function for the HSV color selector */
gtk_hsv_init (GtkHSV *hsv)
{
HSVPrivate *priv;
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (hsv, GTK_TYPE_HSV, HSVPrivate);
- priv = g_new0 (HSVPrivate, 1);
hsv->priv = priv;
-
+
GTK_WIDGET_SET_FLAGS (hsv, GTK_NO_WINDOW);
+ GTK_WIDGET_SET_FLAGS (hsv, GTK_CAN_FOCUS);
priv->h = 0.0;
priv->s = 0.0;
static void
gtk_hsv_destroy (GtkObject *object)
{
- 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);
+ GTK_OBJECT_CLASS (gtk_hsv_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;
-
- if (GTK_WIDGET_MAPPED (widget))
- return;
-
- GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
-
+
+ GTK_WIDGET_CLASS (gtk_hsv_parent_class)->map (widget);
+
gdk_window_show (priv->window);
}
/* 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;
-
- if (!GTK_WIDGET_MAPPED (widget))
- return;
-
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
-
+
gdk_window_hide (priv->window);
-}
+ GTK_WIDGET_CLASS (gtk_hsv_parent_class)->unmap (widget);
+}
+
/* Realize handler for the HSV color selector */
static void
gtk_hsv_realize (GtkWidget *widget)
attr.height = widget->allocation.height;
attr.wclass = GDK_INPUT_ONLY;
attr.event_mask = gtk_widget_get_events (widget);
- attr.event_mask |= (GDK_BUTTON_PRESS_MASK
+ attr.event_mask |= (GDK_KEY_PRESS_MASK
+ | GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
- | GDK_POINTER_MOTION_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;
- gdk_window_ref (widget->window);
+ g_object_ref (widget->window);
priv->window = gdk_window_new (parent_window, &attr, attr_mask);
gdk_window_set_user_data (priv->window, hsv);
gdk_window_destroy (priv->window);
priv->window = NULL;
- gdk_gc_unref (priv->gc);
+ g_object_unref (priv->gc);
priv->gc = NULL;
- if (GTK_WIDGET_CLASS (parent_class)->unrealize)
- GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
+ if (GTK_WIDGET_CLASS (gtk_hsv_parent_class)->unrealize)
+ GTK_WIDGET_CLASS (gtk_hsv_parent_class)->unrealize (widget);
}
/* Size_request handler for the HSV color selector */
gtk_hsv_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
- GtkHSV *hsv;
- HSVPrivate *priv;
-
- hsv = GTK_HSV (widget);
- priv = hsv->priv;
+ GtkHSV *hsv = GTK_HSV (widget);
+ HSVPrivate *priv = hsv->priv;
+ gint focus_width;
+ gint focus_pad;
+
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
- requisition->width = priv->size;
- requisition->height = priv->size;
+ requisition->width = priv->size + 2 * (focus_width + focus_pad);
+ requisition->height = priv->size + 2 * (focus_width + focus_pad);
}
/* Size_allocate handler for the HSV color selector */
priv = hsv->priv;
- center = priv->size / 2.0;
+ center = GTK_WIDGET (hsv)->requisition.width / 2.0;
outer = priv->size / 2.0;
inner = outer - priv->ring_width;
angle = priv->h * 2.0 * G_PI;
gdouble *s,
gdouble *v)
{
- HSVPrivate *priv;
int ihx, ihy, isx, isy, ivx, ivy;
double hx, hy, sx, sy, vx, vy;
double center;
- priv = hsv->priv;
-
compute_triangle (hsv, &ihx, &ihy, &isx, &isy, &ivx, &ivy);
- center = priv->size / 2.0;
+ center = GTK_WIDGET (hsv)->requisition.width / 2.0;
hx = ihx - center;
hy = center - ihy;
sx = isx - center;
{
if (*v > 1.0)
*v = 1.0;
-
- *s = (y - sy - *v * (vy - sy)) / (*v * (hy - vy));
+
+ 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)
gdouble x,
gdouble y)
{
- HSVPrivate *priv;
double center;
double dx, dy;
double angle;
- priv = hsv->priv;
-
- center = priv->size / 2.0;
+ center = GTK_WIDGET (hsv)->requisition.width / 2.0;
dx = x - center;
dy = center - y;
priv = hsv->priv;
- cursor = gdk_cursor_new (GDK_CROSSHAIR);
+ cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (hsv)),
+ GDK_CROSSHAIR);
gdk_pointer_grab (priv->window, FALSE,
(GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
NULL,
cursor,
time);
- gdk_cursor_destroy (cursor);
+ gdk_cursor_unref (cursor);
+}
+
+static gboolean
+gtk_hsv_grab_broken (GtkWidget *widget,
+ GdkEventGrabBroken *event)
+{
+ GtkHSV *hsv = GTK_HSV (widget);
+ HSVPrivate *priv;
+
+ priv = hsv->priv;
+
+ priv->mode = DRAG_NONE;
+
+ return TRUE;
}
/* Button_press_event handler for the HSV color selector */
compute_v (hsv, x, y),
priv->s,
priv->v);
+
+ gtk_widget_grab_focus (widget);
+ priv->focus_on_ring = TRUE;
return TRUE;
}
compute_sv (hsv, x, y, &s, &v);
gtk_hsv_set_color (hsv, priv->h, s, v);
+
+ gtk_widget_grab_focus (widget);
+ priv->focus_on_ring = FALSE;
+
return TRUE;
}
} else
g_assert_not_reached ();
- gdk_pointer_ungrab (event->time);
-
+ gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
+ event->time);
return TRUE;
}
GtkHSV *hsv;
HSVPrivate *priv;
double x, y;
- gint ix, iy;
GdkModifierType mods;
hsv = GTK_HSV (widget);
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);
/* Paints the hue ring */
static void
paint_ring (GtkHSV *hsv,
- GdkDrawable *drawable,
+ cairo_t *cr,
gint x,
gint y,
gint width,
gint height)
{
+ GtkWidget *widget = GTK_WIDGET (hsv);
HSVPrivate *priv;
int xx, yy;
gdouble dx, dy, dist;
gdouble center;
gdouble inner, outer;
- guchar *buf, *p;
+ guint32 *buf, *p;
gdouble angle;
gdouble hue;
gdouble r, g, b;
- GdkBitmap *mask;
- GdkGC *gc;
- GdkColor color;
+ cairo_surface_t *source;
+ cairo_t *source_cr;
+ gint focus_width;
+ gint focus_pad;
+
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
priv = hsv->priv;
- center = priv->size / 2.0;
+ center = widget->requisition.width / 2.0;
outer = priv->size / 2.0;
inner = outer - priv->ring_width;
- /* Paint the ring */
+ /* Create an image initialized with the ring colors */
- buf = g_new (guchar, width * height * 3);
+ buf = g_new (guint32, width * height);
for (yy = 0; yy < height; yy++)
{
- p = buf + yy * width * 3;
+ p = buf + yy * width;
dy = -(yy + y - center);
dx = xx + x - center;
dist = dx * dx + dy * dy;
- if (dist < (inner * inner) || dist > (outer * outer))
+ if (dist < ((inner-1) * (inner-1)) || dist > ((outer+1) * (outer+1)))
{
- *p++ = 0;
- *p++ = 0;
*p++ = 0;
continue;
}
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);
+ *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 (NULL, 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);
-
- gdk_gc_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 ((char *)buf,
+ CAIRO_FORMAT_RGB24,
+ width, height, 4 * width);
+
+ /* 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;
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,
+ cairo_set_source_rgb (source_cr, 1., 1., 1.);
+
+ cairo_move_to (source_cr, -x + center, - y + center);
+ cairo_line_to (source_cr,
-x + center + cos (priv->h * 2.0 * G_PI) * center,
-y + center - sin (priv->h * 2.0 * G_PI) * center);
+ cairo_stroke (source_cr);
+ cairo_destroy (source_cr);
+
+ /* Draw the ring using the source image */
+
+ cairo_save (cr);
+
+ cairo_set_source_surface (cr, source, x, y);
+ cairo_surface_destroy (source);
+
+ cairo_set_line_width (cr, priv->ring_width);
+ cairo_new_path (cr);
+ cairo_arc (cr,
+ center, center,
+ priv->size / 2. - priv->ring_width / 2.,
+ 0, 2 * G_PI);
+ cairo_stroke (cr);
- gdk_gc_set_clip_mask (priv->gc, NULL);
- gdk_bitmap_unref (mask);
+ cairo_restore (cr);
g_free (buf);
-
- /* Draw ring outline */
-
- gdk_rgb_gc_set_foreground (priv->gc, 0x000000);
-
- gdk_draw_arc (drawable, priv->gc, FALSE,
- -x, -y,
- priv->size - 1, priv->size - 1,
- 0, 360 * 64);
- gdk_draw_arc (drawable, priv->gc, FALSE,
- -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);
}
/* Converts an HSV triplet to an integer RGB triplet */
? ((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,
+ cairo_t *cr,
gint x,
gint y,
gint width,
gint height)
{
+ GtkWidget *widget = GTK_WIDGET (hsv);
HSVPrivate *priv;
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;
priv = hsv->priv;
/* Shade the triangle */
- buf = g_new (guchar, width * height * 3);
+ buf = g_new (guint32, width * height);
for (yy = 0; yy < height; yy++)
{
- p = buf + yy * width * 3;
+ p = buf + yy * width;
- if (yy + y < y1 || yy + y > y3)
- for (xx = 0; xx < width; xx++)
- {
- *p++ = 0;
- *p++ = 0;
- *p++ = 0;
- }
- else {
- if (yy + y < y2)
+ if (yy + y >= y1 - PAD && yy + y < y3 + PAD) {
+ y_interp = CLAMP (yy + y, y1, y3);
+
+ if (y_interp < y2)
{
- xl = LERP (x1, x2, y1, y2, yy + y);
+ xl = LERP (x1, x2, y1, y2, y_interp);
- rl = LERP (r1, r2, y1, y2, yy + y);
- gl = LERP (g1, g2, y1, y2, yy + y);
- bl = LERP (b1, b2, y1, y2, yy + y);
+ 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, yy + y);
+ xl = LERP (x2, x3, y2, y3, y_interp);
- rl = LERP (r2, r3, y2, y3, yy + y);
- gl = LERP (g2, g3, y2, y3, yy + y);
- bl = LERP (b2, b3, y2, y3, yy + y);
+ 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, yy + y);
+ xr = LERP (x1, x3, y1, y3, y_interp);
- rr = LERP (r1, r3, y1, y3, yy + y);
- gr = LERP (g1, g3, y1, y3, yy + y);
- br = LERP (b1, b3, y1, y3, yy + y);
+ 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 (gl, gr, t);
SWAP (bl, br, t);
}
-
- for (xx = 0; xx < width; xx++)
+
+ x_start = MAX (xl - PAD, x);
+ x_end = MIN (xr + PAD, x + width);
+ x_start = MIN (x_start, x_end);
+
+ c = (rl << 16) | (gl << 8) | bl;
+
+ for (xx = x; xx < x_start; xx++)
+ *p++ = c;
+
+ for (; xx < x_end; 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);
- }
+ 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 < x + width; xx++)
+ *p++ = c;
}
}
+
+ source = cairo_image_surface_create_for_data ((char *)buf,
+ CAIRO_FORMAT_RGB24,
+ width, height, 4 * width);
- /* Create clipping mask */
-
- mask = gdk_pixmap_new (NULL, 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);
-
- gdk_gc_unref (gc);
-
- gdk_gc_set_clip_mask (priv->gc, mask);
- gdk_gc_set_clip_origin (priv->gc, 0, 0);
-
- /* Draw triangle */
-
- 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, x, y);
+ cairo_surface_destroy (source);
- gdk_gc_set_clip_mask (priv->gc, NULL);
- gdk_bitmap_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 outline */
-
- gdk_rgb_gc_set_foreground (priv->gc, 0x000000);
-
- gdk_draw_polygon (drawable, priv->gc, FALSE, points, 3);
-
/* Draw value marker */
xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
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);
-
- gdk_draw_arc (drawable, priv->gc, FALSE,
- xx - 3, yy - 3,
- 6, 6,
- 0, 360 * 64);
- gdk_draw_arc (drawable, priv->gc, FALSE,
- xx - 2, yy - 2,
- 4, 4,
- 0, 360 * 64);
+ {
+ detail = "colorwheel_dark";
+ cairo_set_source_rgb (cr, 1., 1., 1.);
+ }
+
+#define RADIUS 4
+#define FOCUS_RADIUS 6
+
+ cairo_new_path (cr);
+ cairo_arc (cr, xx, yy, RADIUS, 0, 2 * G_PI);
+ cairo_stroke (cr);
+
+ /* Draw focus outline */
+
+ if (GTK_WIDGET_HAS_FOCUS (hsv) &&
+ !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 (widget->style, widget->window,
+ GTK_WIDGET_STATE (widget),
+ NULL, widget, detail,
+ widget->allocation.x + xx - FOCUS_RADIUS - focus_width - focus_pad,
+ widget->allocation.y + 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,
+ cairo_t *cr,
gint x,
gint y,
gint width,
gint height)
{
- paint_ring (hsv, drawable, x, y, width, height);
- paint_triangle (hsv, drawable, x, y, width, height);
+ paint_ring (hsv, cr, x, y, width, height);
+ paint_triangle (hsv, cr, x, y, width, height);
}
/* Expose_event handler for the HSV color selector */
GtkHSV *hsv;
HSVPrivate *priv;
GdkRectangle rect, dest;
- GdkPixmap *pixmap;
+ cairo_t *cr;
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;
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,
+ cr = gdk_cairo_create (widget->window);
+
+ cairo_translate (cr, widget->allocation.x, widget->allocation.y);
+ paint (hsv, cr,
+ dest.x - widget->allocation.x,
+ dest.y - widget->allocation.y,
dest.width, dest.height);
-
- gdk_draw_pixmap (widget->window,
- priv->gc,
- pixmap,
- 0, 0,
- dest.x,
- dest.y,
- event->area.width, event->area.height);
-
- gdk_pixmap_unref (pixmap);
-
+ cairo_destroy (cr);
+
+ if (GTK_WIDGET_HAS_FOCUS (hsv) && priv->focus_on_ring)
+ gtk_paint_focus (widget->style, widget->window,
+ GTK_WIDGET_STATE (widget),
+ &event->area, widget, NULL,
+ widget->allocation.x,
+ widget->allocation.y,
+ widget->allocation.width,
+ widget->allocation.height);
+
return FALSE;
}
+static gboolean
+gtk_hsv_focus (GtkWidget *widget,
+ GtkDirectionType dir)
+{
+ GtkHSV *hsv;
+ HSVPrivate *priv;
+
+ hsv = GTK_HSV (widget);
+ priv = hsv->priv;
+
+ if (!GTK_WIDGET_HAS_FOCUS (hsv))
+ {
+ if (dir == GTK_DIR_TAB_BACKWARD)
+ priv->focus_on_ring = FALSE;
+ else
+ priv->focus_on_ring = TRUE;
+
+ gtk_widget_grab_focus (GTK_WIDGET (hsv));
+ return TRUE;
+ }
+
+ switch (dir)
+ {
+ case GTK_DIR_UP:
+ if (priv->focus_on_ring)
+ return FALSE;
+ else
+ priv->focus_on_ring = TRUE;
+ break;
+
+ case GTK_DIR_DOWN:
+ if (priv->focus_on_ring)
+ priv->focus_on_ring = FALSE;
+ else
+ return FALSE;
+ break;
+
+ case GTK_DIR_LEFT:
+ case GTK_DIR_TAB_BACKWARD:
+ if (priv->focus_on_ring)
+ return FALSE;
+ else
+ priv->focus_on_ring = TRUE;
+ break;
+
+ case GTK_DIR_RIGHT:
+ case GTK_DIR_TAB_FORWARD:
+ if (priv->focus_on_ring)
+ priv->focus_on_ring = FALSE;
+ else
+ return FALSE;
+ break;
+ }
+
+ gtk_widget_queue_draw (GTK_WIDGET (hsv));
+
+ return TRUE;
+}
/**
* gtk_hsv_new:
GtkWidget*
gtk_hsv_new (void)
{
- return GTK_WIDGET (gtk_type_new (GTK_TYPE_HSV));
+ return g_object_new (GTK_TYPE_HSV, NULL);
}
/**
{
HSVPrivate *priv;
- g_return_if_fail (hsv != NULL);
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);
priv->s = s;
priv->v = v;
- gtk_signal_emit (GTK_OBJECT (hsv), hsv_signals[CHANGED]);
+ g_signal_emit (hsv, hsv_signals[CHANGED], 0);
gtk_widget_queue_draw (GTK_WIDGET (hsv));
}
{
HSVPrivate *priv;
- g_return_if_fail (hsv != NULL);
g_return_if_fail (GTK_IS_HSV (hsv));
priv = hsv->priv;
HSVPrivate *priv;
int same_size;
- g_return_if_fail (hsv != NULL);
g_return_if_fail (GTK_IS_HSV (hsv));
g_return_if_fail (size > 0);
g_return_if_fail (ring_width > 0);
{
HSVPrivate *priv;
- g_return_if_fail (hsv != NULL);
g_return_if_fail (GTK_IS_HSV (hsv));
priv = hsv->priv;
{
HSVPrivate *priv;
- g_return_val_if_fail (hsv != NULL, FALSE);
g_return_val_if_fail (GTK_IS_HSV (hsv), FALSE);
priv = hsv->priv;
if (v)
*v = b;
}
+
+static void
+gtk_hsv_move (GtkHSV *hsv,
+ GtkDirectionType dir)
+{
+ HSVPrivate *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;
+ val = priv->v;
+
+ compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
+
+ x = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
+ y = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5);
+
+#define HUE_DELTA 0.002
+ switch (dir)
+ {
+ case GTK_DIR_UP:
+ if (priv->focus_on_ring)
+ hue += HUE_DELTA;
+ else
+ {
+ y -= 1;
+ compute_sv (hsv, x, y, &sat, &val);
+ }
+ break;
+
+ case GTK_DIR_DOWN:
+ if (priv->focus_on_ring)
+ hue -= HUE_DELTA;
+ else
+ {
+ y += 1;
+ compute_sv (hsv, x, y, &sat, &val);
+ }
+ break;
+
+ case GTK_DIR_LEFT:
+ if (priv->focus_on_ring)
+ hue += HUE_DELTA;
+ else
+ {
+ x -= 1;
+ compute_sv (hsv, x, y, &sat, &val);
+ }
+ break;
+
+ case GTK_DIR_RIGHT:
+ if (priv->focus_on_ring)
+ hue -= HUE_DELTA
+ ;
+ else
+ {
+ x += 1;
+ compute_sv (hsv, x, y, &sat, &val);
+ }
+ break;
+
+ default:
+ /* we don't care about the tab directions */
+ break;
+ }
+
+ /* Wrap */
+ if (hue < 0.0)
+ hue = 1.0;
+ else if (hue > 1.0)
+ hue = 0.0;
+
+ gtk_hsv_set_color (hsv, hue, sat, val);
+}
+
+#define __GTK_HSV_C__
+#include "gtkaliasdef.c"