1
#define __SP_COLOR_WHEEL_C__
7
* Lauris Kaplinski <lauris@kaplinski.com>
8
* Jon A. Cruz <jon@joncruz.org>
9
* John Bintz <jcoswell@coswellproductions.org>
11
* Copyright (C) 2001-2002 Lauris Kaplinski
12
* Copyright (C) 2003-2004 Authors
14
* This code is in public domain
20
#include <gtk/gtksignal.h>
21
#include "sp-color-wheel.h"
23
#include "libnr/nr-rotate-ops.h"
24
#include <2geom/transforms.h>
33
#define noDUMP_CHANGE_INFO
34
#define FOO_NAME(x) g_type_name( G_TYPE_FROM_INSTANCE(x) )
36
static void sp_color_wheel_class_init (SPColorWheelClass *klass);
37
static void sp_color_wheel_init (SPColorWheel *wheel);
38
static void sp_color_wheel_destroy (GtkObject *object);
40
static void sp_color_wheel_realize (GtkWidget *widget);
41
static void sp_color_wheel_size_request (GtkWidget *widget, GtkRequisition *requisition);
42
static void sp_color_wheel_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
44
static gint sp_color_wheel_expose (GtkWidget *widget, GdkEventExpose *event);
45
static gint sp_color_wheel_button_press (GtkWidget *widget, GdkEventButton *event);
46
static gint sp_color_wheel_button_release (GtkWidget *widget, GdkEventButton *event);
47
static gint sp_color_wheel_motion_notify (GtkWidget *widget, GdkEventMotion *event);
49
static void sp_color_wheel_set_hue(SPColorWheel *wheel, gdouble hue);
50
static void sp_color_wheel_set_sv( SPColorWheel *wheel, gdouble sat, gdouble value );
51
static void sp_color_wheel_recalc_triangle(SPColorWheel *wheel);
53
static void sp_color_wheel_paint (SPColorWheel *wheel, GdkRectangle *area);
54
static void sp_color_wheel_render_hue_wheel (SPColorWheel *wheel);
55
static void sp_color_wheel_render_triangle (SPColorWheel *wheel);
58
static gboolean sp_color_wheel_focus(GtkWidget *widget,
59
GtkDirectionType direction);
61
static void sp_color_wheel_process_in_triangle( SPColorWheel *wheel, gdouble x, gdouble y );
63
static GtkWidgetClass *parent_class;
64
static guint wheel_signals[LAST_SIGNAL] = {0};
71
g_get_current_time (&tv);
72
return tv.tv_sec + 1e-6 * tv.tv_usec;
76
GType sp_color_wheel_get_type(void)
78
static GType type = 0;
81
sizeof(SPColorWheelClass),
84
(GClassInitFunc)sp_color_wheel_class_init,
89
(GInstanceInitFunc)sp_color_wheel_init,
92
type = g_type_register_static(GTK_TYPE_WIDGET, "SPColorWheel", &info, static_cast<GTypeFlags>(0));
98
sp_color_wheel_class_init (SPColorWheelClass *klass)
100
GtkObjectClass *object_class;
101
GtkWidgetClass *widget_class;
103
object_class = (GtkObjectClass *) klass;
104
widget_class = (GtkWidgetClass *) klass;
106
parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET);
108
wheel_signals[CHANGED] = gtk_signal_new ("changed",
109
(GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
110
GTK_CLASS_TYPE(object_class),
111
GTK_SIGNAL_OFFSET (SPColorWheelClass, changed),
112
gtk_marshal_NONE__NONE,
115
object_class->destroy = sp_color_wheel_destroy;
117
widget_class->realize = sp_color_wheel_realize;
118
widget_class->size_request = sp_color_wheel_size_request;
119
widget_class->size_allocate = sp_color_wheel_size_allocate;
121
widget_class->focus = sp_color_wheel_focus;
123
widget_class->expose_event = sp_color_wheel_expose;
124
widget_class->button_press_event = sp_color_wheel_button_press;
125
widget_class->button_release_event = sp_color_wheel_button_release;
126
widget_class->motion_notify_event = sp_color_wheel_motion_notify;
130
sp_color_wheel_init (SPColorWheel *wheel)
132
/* We are widget with window */
133
GTK_WIDGET_UNSET_FLAGS (wheel, GTK_NO_WINDOW);
134
GTK_WIDGET_SET_FLAGS (wheel, GTK_CAN_FOCUS );
136
wheel->dragging = FALSE;
138
wheel->_inTriangle = FALSE;
139
wheel->_triDirty = TRUE;
140
wheel->_triangle = NULL;
141
for ( guint i = 0; i < G_N_ELEMENTS(wheel->_triPoints); i++ )
143
wheel->_triPoints[i].x = 0;
144
wheel->_triPoints[i].y = 0;
146
wheel->_triImage = NULL;
149
wheel->_image = NULL;
153
wheel->_value = 0.25;
156
wheel->_spotValue = 1.0;
160
sp_color_wheel_destroy (GtkObject *object)
164
wheel = SP_COLOR_WHEEL (object);
168
g_free( wheel->_image );
169
wheel->_image = NULL;
173
if ( wheel->_triImage )
175
g_free( wheel->_triImage );
176
wheel->_triImage = NULL;
180
if (((GtkObjectClass *) (parent_class))->destroy)
181
(* ((GtkObjectClass *) (parent_class))->destroy) (object);
185
void sp_color_wheel_get_color( SPColorWheel *wheel, SPColor* color )
189
g_return_if_fail (SP_IS_COLOR_WHEEL (wheel));
190
g_return_if_fail (wheel != NULL);
191
g_return_if_fail (color != NULL);
193
sp_color_hsv_to_rgb_floatv (rgb, wheel->_hue, 1.0, 1.0);
194
for ( i = 0; i < 3; i++ )
196
rgb[i] = (rgb[i] * wheel->_sat) + (wheel->_value * (1.0 - wheel->_sat));
199
color->set( rgb[0], rgb[1], rgb[2] );
202
void sp_color_wheel_set_color( SPColorWheel *wheel, const SPColor* color )
204
#ifdef DUMP_CHANGE_INFO
205
g_message("sp_color_wheel_set_color( wheel=%p, %f, %f, %f)", wheel, color->v.c[0], color->v.c[1], color->v.c[2] );
207
g_return_if_fail (SP_IS_COLOR_WHEEL (wheel));
208
g_return_if_fail (wheel != NULL);
209
g_return_if_fail (color != NULL);
215
sp_color_get_rgb_floatv (color, rgb);
216
sp_color_rgb_to_hsv_floatv (scratch, rgb[0], rgb[1], rgb[2]);
219
sp_color_hsv_to_rgb_floatv (scratch, hue, 1.0, 1.0);
223
for ( int i = 1; i < 3; i++ )
225
if ( scratch[i] < scratch[lowInd] )
229
if ( scratch[i] > scratch[hiInd] )
234
// scratch[lowInd] should always be 0
235
gdouble sat = (rgb[hiInd] - rgb[lowInd])/(scratch[hiInd]-scratch[lowInd]);
236
gdouble val = sat < 1.0 ? (rgb[hiInd] - sat * scratch[hiInd])/(1.0-sat) : 0.0;
239
sp_color_wheel_set_hue(wheel, hue);
240
sp_color_wheel_set_sv(wheel, sat, val);
243
gboolean sp_color_wheel_is_adjusting( SPColorWheel *wheel )
245
g_return_val_if_fail( SP_IS_COLOR_WHEEL(wheel), FALSE );
246
return wheel->dragging;
250
sp_color_wheel_realize (GtkWidget *widget)
253
GdkWindowAttr attributes;
254
gint attributes_mask;
256
wheel = SP_COLOR_WHEEL (widget);
258
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
260
attributes.window_type = GDK_WINDOW_CHILD;
261
attributes.x = widget->allocation.x;
262
attributes.y = widget->allocation.y;
263
attributes.width = widget->allocation.width;
264
attributes.height = widget->allocation.height;
265
attributes.wclass = GDK_INPUT_OUTPUT;
266
attributes.visual = gdk_rgb_get_visual ();
267
attributes.colormap = gdk_rgb_get_cmap ();
268
attributes.event_mask = gtk_widget_get_events (widget);
269
attributes.event_mask |= (GDK_EXPOSURE_MASK |
270
GDK_BUTTON_PRESS_MASK |
271
GDK_BUTTON_RELEASE_MASK |
272
GDK_POINTER_MOTION_MASK |
273
GDK_ENTER_NOTIFY_MASK |
274
GDK_LEAVE_NOTIFY_MASK |
275
GDK_FOCUS_CHANGE_MASK );
276
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
278
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
279
gdk_window_set_user_data (widget->window, widget);
281
widget->style = gtk_style_attach (widget->style, widget->window);
285
sp_color_wheel_size_request (GtkWidget *widget, GtkRequisition *requisition)
289
wheel = SP_COLOR_WHEEL (widget);
291
requisition->width = WHEEL_SIZE + widget->style->xthickness * 2;
292
requisition->height = WHEEL_SIZE + widget->style->ythickness * 2;
296
sp_color_wheel_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
300
wheel = SP_COLOR_WHEEL (widget);
302
widget->allocation = *allocation;
304
wheel->_center = MIN(allocation->width, allocation->height)/2;
305
wheel->_inner = (3 * wheel->_center)/4;
308
g_free( wheel->_image );
309
wheel->_image = NULL;
313
// Need to render the gradient before we do the triangle over
314
sp_color_wheel_render_hue_wheel(wheel);
315
sp_color_wheel_recalc_triangle(wheel);
316
sp_color_wheel_render_triangle(wheel);
318
if (GTK_WIDGET_REALIZED (widget)) {
319
/* Resize GdkWindow */
320
gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
325
sp_color_wheel_expose (GtkWidget *widget, GdkEventExpose *event)
329
wheel = SP_COLOR_WHEEL (widget);
331
if (GTK_WIDGET_DRAWABLE (widget)) {
333
width = widget->allocation.width;
334
height = widget->allocation.height;
335
sp_color_wheel_paint (wheel, &event->area);
342
sp_color_wheel_button_press (GtkWidget *widget, GdkEventButton *event)
346
wheel = SP_COLOR_WHEEL (widget);
348
if (event->button == 1) {
350
cx = widget->style->xthickness;
351
cw = widget->allocation.width - 2 * cx;
352
gboolean grabbed = FALSE;
355
double dx = event->x - wheel->_center;
356
double dy = event->y - wheel->_center;
357
gint hyp = static_cast<gint>(ABS(dx*dx) + ABS(dy*dy));
358
if ( hyp <= (wheel->_center*wheel->_center) )
360
if ( hyp >= (wheel->_inner*wheel->_inner) )
362
gdouble rot = atan2( dy, -dx );
363
sp_color_wheel_set_hue (wheel, (rot + M_PI) / (2.0 * M_PI));
365
wheel->_inTriangle = FALSE;
368
else if ( wheel->_triangle && gdk_region_point_in( wheel->_triangle, (gint)event->x, (gint)event->y ) )
370
wheel->_inTriangle = TRUE;
371
sp_color_wheel_process_in_triangle( wheel, event->x, event->y );
379
gtk_widget_queue_draw( widget );
380
gtk_widget_grab_focus( widget );
382
wheel->dragging = TRUE;
383
#ifdef DUMP_CHANGE_INFO
386
sp_color_wheel_get_color( wheel, &color );
387
g_message( "%s:%d: About to signal %s to color %08x in %s", __FILE__, __LINE__,
389
color.toRGBA32( 0 ), FOO_NAME(wheel));
392
gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]);
393
gdk_pointer_grab (widget->window, FALSE,
394
(GdkEventMask)(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
395
NULL, NULL, event->time);
403
sp_color_wheel_button_release (GtkWidget *widget, GdkEventButton *event)
407
wheel = SP_COLOR_WHEEL (widget);
409
if (event->button == 1) {
410
gdk_pointer_ungrab (event->time);
411
wheel->dragging = FALSE;
413
#ifdef DUMP_CHANGE_INFO
416
sp_color_wheel_get_color( wheel, &color );
417
g_message( "%s:%d: About to signal %s to color %08x in %s", __FILE__, __LINE__,
419
color.toRGBA32( 0 ), FOO_NAME(wheel));
422
gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]);
429
sp_color_wheel_motion_notify (GtkWidget *widget, GdkEventMotion *event)
433
wheel = SP_COLOR_WHEEL (widget);
435
if (wheel->dragging) {
436
double dx = event->x - wheel->_center;
437
double dy = event->y - wheel->_center;
438
if ( !wheel->_inTriangle )
440
gdouble rot = atan2( dy, -dx );
441
sp_color_wheel_set_hue (wheel, (rot + M_PI) / (2.0 * M_PI));
445
sp_color_wheel_process_in_triangle( wheel, event->x, event->y );
448
#ifdef DUMP_CHANGE_INFO
451
sp_color_wheel_get_color( wheel, &color );
452
g_message( "%s:%d: About to signal %s to color %08x in %s", __FILE__, __LINE__,
454
color.toRGBA32( 0 ), FOO_NAME(wheel));
457
gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]);
464
sp_color_wheel_new ()
468
wheel = (SPColorWheel*)gtk_type_new (SP_TYPE_COLOR_WHEEL);
470
return GTK_WIDGET (wheel);
473
static void sp_color_wheel_set_hue(SPColorWheel *wheel, gdouble hue)
475
g_return_if_fail (SP_IS_COLOR_WHEEL (wheel));
477
if ( wheel->_hue != hue )
481
sp_color_wheel_recalc_triangle(wheel);
485
sp_color_wheel_get_color( wheel, &color );
486
sp_color_get_rgb_floatv (&color, rgb);
488
wheel->_spotValue = ( (0.299 * rgb[0]) + (0.587 * rgb[1]) + (0.114 * rgb[2]) );
490
gtk_widget_queue_draw (GTK_WIDGET (wheel));
495
static void sp_color_wheel_set_sv( SPColorWheel *wheel, gdouble sat, gdouble value )
497
static gdouble epsilon = 1e-6;
498
gboolean changed = FALSE;
500
if ( ABS( wheel->_sat - sat ) > epsilon )
505
if ( ABS( wheel->_value - value ) > epsilon )
507
wheel->_value = value;
515
sp_color_wheel_get_color( wheel, &color );
516
sp_color_get_rgb_floatv (&color, rgb);
518
wheel->_spotValue = ( (0.299 * rgb[0]) + (0.587 * rgb[1]) + (0.114 * rgb[2]) );
520
#ifdef DUMP_CHANGE_INFO
523
sp_color_wheel_get_color( wheel, &color );
524
g_message( "%s:%d: About to signal %s to color %08x in %s", __FILE__, __LINE__,
526
color.toRGBA32( 0 ), FOO_NAME(wheel));
529
gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]);
531
gtk_widget_queue_draw (GTK_WIDGET (wheel));
534
static void sp_color_wheel_recalc_triangle(SPColorWheel *wheel)
536
if ( wheel->_triangle )
538
gdk_region_destroy( wheel->_triangle );
539
wheel->_triangle = NULL;
541
wheel->_triDirty = TRUE;
543
if ( wheel->_center > 0 && wheel->_inner > 0 )
545
gdouble dx = cos( M_PI * 2 * wheel->_hue );
546
gdouble dy = -sin( M_PI * 2 * wheel->_hue );
548
wheel->_triPoints[0].x = wheel->_center + static_cast<gint>(dx * wheel->_inner);
549
wheel->_triPoints[0].y = wheel->_center + static_cast<gint>(dy * wheel->_inner);
551
dx = cos( M_PI * 2 * wheel->_hue + ((M_PI * 2)/ 3) );
552
dy = -sin( M_PI * 2 * wheel->_hue + ((M_PI * 2) / 3) );
553
wheel->_triPoints[1].x = wheel->_center + static_cast<gint>(dx * wheel->_inner);
554
wheel->_triPoints[1].y = wheel->_center + static_cast<gint>(dy * wheel->_inner);
556
dx = cos( M_PI * 2 * wheel->_hue - ((M_PI*2) / 3) );
557
dy = -sin( M_PI * 2 * wheel->_hue - ((M_PI*2) / 3) );
558
wheel->_triPoints[2].x = wheel->_center + static_cast<gint>(dx * wheel->_inner);
559
wheel->_triPoints[2].y = wheel->_center + static_cast<gint>(dy * wheel->_inner);
562
wheel->_triangle = gdk_region_polygon( wheel->_triPoints,
568
#define VERT_SWAP( X, Y ) { \
572
point##X.x = point##Y.x; \
576
point##X.y = point##Y.y; \
580
rgb##X[0] = rgb##Y[0]; \
584
rgb##X[1] = rgb##Y[1]; \
588
rgb##X[2] = rgb##Y[2]; \
592
#define VERT_COPY( dst, src ) { \
593
point##dst.x = point##src.x; \
595
point##dst.y = point##src.y; \
597
rgb##dst[0] = rgb##src[0]; \
598
rgb##dst[1] = rgb##src[1]; \
599
rgb##dst[2] = rgb##src[2]; \
608
* Render the provided color wheel information as a triangle.
610
static void sp_color_wheel_render_triangle (SPColorWheel *wheel)
614
if ( wheel->_triBs < wheel->_bs )
616
g_free( wheel->_triImage );
617
wheel->_triImage = NULL;
620
if (wheel->_triDirty || !wheel->_triImage)
622
if ( !wheel->_triImage )
624
wheel->_triBs = wheel->_bs;
625
wheel->_triImage = g_new (guchar, wheel->_triBs * 3);
626
//g_message( "just allocated %fKB for tri", ((wheel->_triBs * 3.0)/1024.0) );
629
memcpy( wheel->_triImage, wheel->_image, wheel->_bs * 3 );
631
PointF pointA, pointB, pointC;
632
pointA.x = wheel->_triPoints[0].x;
633
pointA.y = wheel->_triPoints[0].y;
634
pointB.x = wheel->_triPoints[1].x;
635
pointB.y = wheel->_triPoints[1].y;
636
pointC.x = wheel->_triPoints[2].x;
637
pointC.y = wheel->_triPoints[2].y;
640
gfloat rgbB[3] = {0.0, 0.0, 0.0};
641
gfloat rgbC[3] = {1.0, 1.0, 1.0};
643
sp_color_hsv_to_rgb_floatv (rgbA, wheel->_hue, 1.0, 1.0);
645
// Start of Gouraud fill ============================================================
646
gint rowStride = wheel->_center * 2 * 3;
647
guchar* dst = wheel->_triImage;
649
if ( pointC.y < pointB.y )
652
if ( pointC.y < pointA.y )
655
if ( pointB.y < pointA.y )
658
if ( pointA.y == pointB.y && pointB.x < pointA.x )
677
if (pointB.y-pointA.y > 0)
679
dx1=(pointB.x-pointA.x)/(pointB.y-pointA.y);
680
dr1=(rgbB[0]-rgbA[0])/(pointB.y-pointA.y);
681
dg1=(rgbB[1]-rgbA[1])/(pointB.y-pointA.y);
682
db1=(rgbB[2]-rgbA[2])/(pointB.y-pointA.y);
689
if (pointC.y-pointA.y > 0)
691
dx2=(pointC.x-pointA.x)/(pointC.y-pointA.y);
692
dr2=(rgbC[0]-rgbA[0])/(pointC.y-pointA.y);
693
dg2=(rgbC[1]-rgbA[1])/(pointC.y-pointA.y);
694
db2=(rgbC[2]-rgbA[2])/(pointC.y-pointA.y);
701
if (pointC.y-pointB.y > 0)
703
dx3=(pointC.x-pointB.x)/(pointC.y-pointB.y);
704
dr3=(rgbC[0]-rgbB[0])/(pointC.y-pointB.y);
705
dg3=(rgbC[1]-rgbB[1])/(pointC.y-pointB.y);
706
db3=(rgbC[2]-rgbB[2])/(pointC.y-pointB.y);
716
int runs = 1; int fill_mode = 0;
722
else if ( dx1 > dx2 )
724
fill_mode = 1; runs = 2;
728
fill_mode = 2; runs = 2;
732
int fill_direction_mode = 0;
734
for (int current_run = 0; current_run < runs; current_run++)
741
fill_direction_mode = 0;
744
if (current_run == 0) {
746
fill_direction_mode = 1;
749
fill_direction_mode = 0;
753
if (current_run == 0) {
755
fill_direction_mode = 2;
758
fill_direction_mode = 3;
763
for(;pointS.y <= targetY; pointS.y++,pointE.y++)
765
if (pointE.x-pointS.x > 0)
767
dr=(rgbE[0]-rgbS[0])/(pointE.x-pointS.x);
768
dg=(rgbE[1]-rgbS[1])/(pointE.x-pointS.x);
769
db=(rgbE[2]-rgbS[2])/(pointE.x-pointS.x);
776
dst = wheel->_triImage + (static_cast<gint>(pointP.y) * rowStride);
777
dst += static_cast<gint>(pointP.x) * 3;
778
for(;pointP.x < pointE.x;pointP.x++)
781
dst[0] = SP_COLOR_F_TO_U(rgbP[0]);
782
dst[1] = SP_COLOR_F_TO_U(rgbP[1]);
783
dst[2] = SP_COLOR_F_TO_U(rgbP[2]);
785
rgbP[0]+=dr; rgbP[1]+=dg; rgbP[2]+=db;
788
switch (fill_direction_mode) {
790
pointS.x+=dx2; rgbS[0]+=dr2; rgbS[1]+=dg2; rgbS[2]+=db2;
791
pointE.x+=dx3; rgbE[0]+=dr3; rgbE[1]+=dg3; rgbE[2]+=db3;
794
pointS.x+=dx2; rgbS[0]+=dr2; rgbS[1]+=dg2; rgbS[2]+=db2;
795
pointE.x+=dx1; rgbE[0]+=dr1; rgbE[1]+=dg1; rgbE[2]+=db1;
798
pointS.x+=dx1; rgbS[0]+=dr1; rgbS[1]+=dg1; rgbS[2]+=db1;
799
pointE.x+=dx2; rgbE[0]+=dr2; rgbE[1]+=dg2; rgbE[2]+=db2;
802
pointS.x+=dx3; rgbS[0]+=dr3; rgbS[1]+=dg3; rgbS[2]+=db3;
803
pointE.x+=dx2; rgbE[0]+=dr2; rgbE[1]+=dg2; rgbE[2]+=db2;
810
// End of Gouraud fill ============================================================
812
wheel->_triDirty = FALSE;
813
//g_message( "Just updated triangle" );
819
sp_color_wheel_paint (SPColorWheel *wheel, GdkRectangle *area)
822
GdkRectangle warea, carea;
823
GdkRectangle wpaint, cpaint;
825
widget = GTK_WIDGET (wheel);
830
warea.width = widget->allocation.width;
831
warea.height = widget->allocation.height;
833
/* Color gradient area */
834
carea.x = widget->style->xthickness;
835
carea.y = widget->style->ythickness;
836
carea.width = widget->allocation.width - 2 * carea.x;
837
carea.height = widget->allocation.height - 2 * carea.y;
839
/* Actual paintable area */
840
if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return;
842
//g_message( "Painted as state %d", widget->state );
844
/* Paintable part of color gradient area */
845
if (gdk_rectangle_intersect (area, &carea, &cpaint)) {
846
sp_color_wheel_render_hue_wheel (wheel);
847
sp_color_wheel_render_triangle (wheel);
851
gtk_draw_box (widget->style,
853
(GtkStateType)widget->state,
861
gtk_style_apply_default_background( widget->style,
864
(GtkStateType)widget->state,
874
gtk_paint_shadow (widget->style, widget->window,
875
(GtkStateType)widget->state, GTK_SHADOW_IN,
876
NULL, widget, "colorwheel",
878
warea.width, warea.height);
882
/* Draw pixelstore */
883
if (wheel->_triImage != NULL) {
884
//gdouble start, end;
885
//start = get_time();
886
gdk_draw_rgb_image (widget->window, widget->style->black_gc,
887
0, 0,//cpaint.x, cpaint.y,
888
//cpaint.width, cpaint.height,
889
wheel->_center * 2, wheel->_center * 2,
891
wheel->_triImage, wheel->_center * 6);
894
//g_message( "blits took %f", (end-start) );
898
gdouble dx = cos( M_PI * 2 * wheel->_hue );
899
gdouble dy = -sin( M_PI * 2 * wheel->_hue );
902
sp_color_hsv_to_rgb_floatv (rgb, wheel->_hue, 1.0, 1.0);
904
GdkGC *line_gc = (( (0.299 * rgb[0]) + (0.587 * rgb[1]) + (0.114 * rgb[2]) ) < 0.5) ? widget->style->white_gc : widget->style->black_gc;
906
gint inx = wheel->_center + static_cast<gint>(dx * wheel->_inner);
907
gint iny = wheel->_center + static_cast<gint>(dy * wheel->_inner);
910
gdk_draw_line (widget->window, line_gc,
912
wheel->_center + static_cast<gint>(dx * wheel->_center), wheel->_center + static_cast<gint>(dy * wheel->_center) );
917
if ( GTK_WIDGET_HAS_FOCUS(wheel) )
919
line_gc = widget->style->black_gc;
921
gdk_gc_get_values ( line_gc, &values );
923
gdk_gc_set_line_attributes ( line_gc,
925
values.line_style, //GDK_LINE_SOLID,
926
values.cap_style, //GDK_CAP_BUTT,
927
values.join_style ); //GDK_JOIN_MITER );
929
if ( wheel->_inTriangle )
931
gdk_draw_line (widget->window, line_gc,
932
wheel->_triPoints[0].x, wheel->_triPoints[0].y,
933
wheel->_triPoints[1].x, wheel->_triPoints[1].y );
935
gdk_draw_line (widget->window, line_gc,
936
wheel->_triPoints[1].x, wheel->_triPoints[1].y,
937
wheel->_triPoints[2].x, wheel->_triPoints[2].y );
939
gdk_draw_line (widget->window, line_gc,
940
wheel->_triPoints[2].x, wheel->_triPoints[2].y,
941
wheel->_triPoints[0].x, wheel->_triPoints[0].y );
945
gdk_draw_arc (widget->window, line_gc,
948
wheel->_center * 2, wheel->_center * 2,
951
gint diff = wheel->_center - wheel->_inner;
953
gdk_draw_arc (widget->window, line_gc,
956
wheel->_inner * 2, wheel->_inner * 2,
960
gdk_gc_set_line_attributes ( line_gc,
961
values.line_width, // Line width
962
values.line_style, //GDK_LINE_SOLID,
963
values.cap_style, //GDK_CAP_BUTT,
964
values.join_style ); //GDK_JOIN_MITER );
968
// line_gc = (p[3] < 0x80) ? widget->style->white_gc : widget->style->black_gc;
969
line_gc = (wheel->_spotValue < 0.5) ? widget->style->white_gc : widget->style->black_gc;
971
gdk_gc_get_values ( line_gc, &values );
973
gdk_gc_set_line_attributes ( line_gc,
975
values.line_style, //GDK_LINE_SOLID,
976
values.cap_style, //GDK_CAP_BUTT,
977
values.join_style ); //GDK_JOIN_MITER );
979
gint pointX = (gint)( (1.0 - wheel->_sat) * ((1.0-wheel->_value)*(gdouble)wheel->_triPoints[1].x + wheel->_value*(gdouble)wheel->_triPoints[2].x)
980
+ (wheel->_sat * wheel->_triPoints[0].x) );
982
gint pointY = (gint)( (1.0 - wheel->_sat) * ((1.0-wheel->_value)*(gdouble)wheel->_triPoints[1].y + wheel->_value*(gdouble)wheel->_triPoints[2].y)
983
+ (wheel->_sat * wheel->_triPoints[0].y) );
986
gdk_gc_set_line_attributes ( line_gc,
987
values.line_width, // Line width
988
values.line_style, //GDK_LINE_SOLID,
989
values.cap_style, //GDK_CAP_BUTT,
990
values.join_style ); //GDK_JOIN_MITER );
992
gdk_draw_arc (widget->window, line_gc,
994
pointX - 4, pointY - 4,
998
gdk_draw_arc (widget->window, line_gc,
1000
pointX - 3, pointY - 3,
1009
/* Colors are << 16 */
1012
sp_color_wheel_render_hue_wheel (SPColorWheel *wheel)
1017
gint size = wheel->_center * 2;
1018
gboolean dirty = FALSE;
1020
if (wheel->_image && (wheel->_bs < (size * size) )) {
1021
g_free (wheel->_image);
1022
wheel->_image = NULL;
1025
if ( wheel->_triImage )
1027
g_free( wheel->_triImage );
1028
wheel->_triImage = NULL;
1030
wheel->_triDirty = TRUE;
1034
if (!wheel->_image) {
1035
wheel->_image = g_new (guchar, size * size * 3);
1036
wheel->_bs = size * size;
1038
//g_message( "just allocated %fKB for hue", ((wheel->_bs * 3.0)/1024.0) );
1043
GtkWidget* widget = GTK_WIDGET (wheel);
1045
r = widget->style->bg[widget->state].red >> 8;
1046
g = widget->style->bg[widget->state].green >> 8;
1047
b = widget->style->bg[widget->state].blue >> 8;
1048
//g_message( "Rendered as state %d", widget->state );
1050
gint offset = wheel->_center;
1051
gint inner = wheel->_inner * wheel->_inner;
1052
gint rad = wheel->_center * wheel->_center;
1054
for (x = 0; x < size; x++) {
1056
for (y = 0; y < size; y++) {
1057
gint dx = x - offset;
1058
gint dy = y - offset;
1059
gint hyp = (ABS(dx*dx) + ABS(dy*dy));
1060
if ( hyp >= inner && hyp <= rad)
1062
gdouble rot = atan2( static_cast<gdouble>(dy), static_cast<gdouble>(-dx) );
1065
sp_color_hsv_to_rgb_floatv (rgb, (rot + M_PI) / (2.0 * M_PI), 1.0, 1.0);
1067
d[0] = SP_COLOR_F_TO_U (rgb[0]);
1068
d[1] = SP_COLOR_F_TO_U (rgb[1]);
1069
d[2] = SP_COLOR_F_TO_U (rgb[2]);
1073
/* Background value */
1086
static gboolean sp_color_wheel_focus(GtkWidget *widget,
1087
GtkDirectionType direction)
1089
gboolean focusKept = FALSE;
1090
gboolean wasFocused = GTK_WIDGET_HAS_FOCUS(widget);
1091
SPColorWheel* wheel = SP_COLOR_WHEEL(widget);
1092
gboolean goingUp = FALSE;
1094
switch ( direction )
1096
case GTK_DIR_TAB_FORWARD:
1102
case GTK_DIR_TAB_BACKWARD:
1113
wheel->_inTriangle = !goingUp;
1114
gtk_widget_grab_focus (widget);
1117
else if ( (!wheel->_inTriangle) == (!goingUp) )
1123
wheel->_inTriangle = !wheel->_inTriangle;
1124
gtk_widget_queue_draw( widget );
1131
static void sp_color_wheel_process_in_triangle( SPColorWheel *wheel, gdouble x, gdouble y )
1133
// njh: dot(rot90(B-C), x) = saturation
1134
// njh: dot(B-C, x) = value
1135
Geom::Point delta( x - (((gdouble)(wheel->_triPoints[1].x + wheel->_triPoints[2].x)) / 2.0),
1136
y - (((gdouble)(wheel->_triPoints[1].y + wheel->_triPoints[2].y)) / 2.0) );
1138
gdouble rot = (M_PI * 2 * wheel->_hue );
1140
Geom::Point result = delta * Geom::Rotate(rot);
1142
gdouble sat = CLAMP( result[Geom::X] / (wheel->_inner * 1.5), 0.0, 1.0 );
1144
gdouble halfHeight = (wheel->_inner * sin(M_PI/3.0)) * (1.0 - sat);
1145
gdouble value = CLAMP( ((result[Geom::Y]+ halfHeight) / (2.0*halfHeight)), 0.0, 1.0 );
1147
wheel->_triDirty = TRUE;
1149
sp_color_wheel_set_sv( wheel, sat, value );
1156
c-file-style:"stroustrup"
1157
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1158
indent-tabs-mode:nil
1162
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :