diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/widgets/sp-color-wheel.cpp | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/widgets/sp-color-wheel.cpp')
| -rw-r--r-- | src/widgets/sp-color-wheel.cpp | 1163 |
1 files changed, 1163 insertions, 0 deletions
diff --git a/src/widgets/sp-color-wheel.cpp b/src/widgets/sp-color-wheel.cpp new file mode 100644 index 000000000..9038b6d38 --- /dev/null +++ b/src/widgets/sp-color-wheel.cpp @@ -0,0 +1,1163 @@ +#define __SP_COLOR_WHEEL_C__ + +/* + * A wheel color widget + * + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2003-2004 Authors + * + * This code is in public domain + */ + +#include <gtk/gtksignal.h> +#include "sp-color-wheel.h" + +#include "libnr/nr-rotate-ops.h" + +#define WHEEL_SIZE 96 + +enum { + CHANGED, + LAST_SIGNAL +}; + +static void sp_color_wheel_class_init (SPColorWheelClass *klass); +static void sp_color_wheel_init (SPColorWheel *wheel); +static void sp_color_wheel_destroy (GtkObject *object); + +static void sp_color_wheel_realize (GtkWidget *widget); +static void sp_color_wheel_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void sp_color_wheel_size_allocate (GtkWidget *widget, GtkAllocation *allocation); + +static gint sp_color_wheel_expose (GtkWidget *widget, GdkEventExpose *event); +static gint sp_color_wheel_button_press (GtkWidget *widget, GdkEventButton *event); +static gint sp_color_wheel_button_release (GtkWidget *widget, GdkEventButton *event); +static gint sp_color_wheel_motion_notify (GtkWidget *widget, GdkEventMotion *event); + +static void sp_color_wheel_set_hue(SPColorWheel *wheel, gdouble hue); +static void sp_color_wheel_set_sv( SPColorWheel *wheel, gdouble sat, gdouble value ); +static void sp_color_wheel_recalc_triangle(SPColorWheel *wheel); + +static void sp_color_wheel_paint (SPColorWheel *wheel, GdkRectangle *area); +static void sp_color_wheel_render_hue_wheel (SPColorWheel *wheel); +static void sp_color_wheel_render_triangle (SPColorWheel *wheel); + + +static gboolean sp_color_wheel_focus(GtkWidget *widget, + GtkDirectionType direction); + +static void sp_color_wheel_process_in_triangle( SPColorWheel *wheel, gdouble x, gdouble y ); + +static GtkWidgetClass *parent_class; +static guint wheel_signals[LAST_SIGNAL] = {0}; + +/* +static double +get_time (void) +{ + GTimeVal tv; + g_get_current_time (&tv); + return tv.tv_sec + 1e-6 * tv.tv_usec; +} +*/ + +GtkType +sp_color_wheel_get_type (void) +{ + static GtkType type = 0; + if (!type) { + GtkTypeInfo info = { + "SPColorWheel", + sizeof (SPColorWheel), + sizeof (SPColorWheelClass), + (GtkClassInitFunc) sp_color_wheel_class_init, + (GtkObjectInitFunc) sp_color_wheel_init, + NULL, NULL, NULL + }; + type = gtk_type_unique (GTK_TYPE_WIDGET, &info); + } + return type; +} + +static void +sp_color_wheel_class_init (SPColorWheelClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass *) klass; + widget_class = (GtkWidgetClass *) klass; + + parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET); + + wheel_signals[CHANGED] = gtk_signal_new ("changed", + (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE), + GTK_CLASS_TYPE(object_class), + GTK_SIGNAL_OFFSET (SPColorWheelClass, changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + object_class->destroy = sp_color_wheel_destroy; + + widget_class->realize = sp_color_wheel_realize; + widget_class->size_request = sp_color_wheel_size_request; + widget_class->size_allocate = sp_color_wheel_size_allocate; + + widget_class->focus = sp_color_wheel_focus; + + widget_class->expose_event = sp_color_wheel_expose; + widget_class->button_press_event = sp_color_wheel_button_press; + widget_class->button_release_event = sp_color_wheel_button_release; + widget_class->motion_notify_event = sp_color_wheel_motion_notify; +} + +static void +sp_color_wheel_init (SPColorWheel *wheel) +{ + /* We are widget with window */ + GTK_WIDGET_UNSET_FLAGS (wheel, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (wheel, GTK_CAN_FOCUS ); + + wheel->dragging = FALSE; + + wheel->_inTriangle = FALSE; + wheel->_triDirty = TRUE; + wheel->_triangle = NULL; + for ( guint i = 0; i < G_N_ELEMENTS(wheel->_triPoints); i++ ) + { + wheel->_triPoints[i].x = 0; + wheel->_triPoints[i].y = 0; + } + wheel->_triImage = NULL; + wheel->_triBs = 0; + + wheel->_image = NULL; + wheel->_bs = 0; + wheel->_hue = 0.0; + wheel->_sat = 0.9; + wheel->_value = 0.25; + wheel->_inner = 0; + wheel->_center = 0; + wheel->_spotValue = 1.0; +} + +static void +sp_color_wheel_destroy (GtkObject *object) +{ + SPColorWheel *wheel; + + wheel = SP_COLOR_WHEEL (object); + + if ( wheel->_image ) + { + g_free( wheel->_image ); + wheel->_image = NULL; + wheel->_bs = 0; + } + + if ( wheel->_triImage ) + { + g_free( wheel->_triImage ); + wheel->_triImage = NULL; + wheel->_triBs = 0; + } + + if (((GtkObjectClass *) (parent_class))->destroy) + (* ((GtkObjectClass *) (parent_class))->destroy) (object); +} + + +void sp_color_wheel_get_color( SPColorWheel *wheel, SPColor* color ) +{ + float rgb[3]; + gint i; + g_return_if_fail (SP_IS_COLOR_WHEEL (wheel)); + g_return_if_fail (wheel != NULL); + g_return_if_fail (color != NULL); + + sp_color_hsv_to_rgb_floatv (rgb, wheel->_hue, 1.0, 1.0); + for ( i = 0; i < 3; i++ ) + { + rgb[i] = (rgb[i] * wheel->_sat) + (wheel->_value * (1.0 - wheel->_sat)); + } + + sp_color_set_rgb_float (color, rgb[0], rgb[1], rgb[2]); +} + +void sp_color_wheel_set_color( SPColorWheel *wheel, const SPColor* color ) +{ + g_return_if_fail (SP_IS_COLOR_WHEEL (wheel)); + g_return_if_fail (wheel != NULL); + g_return_if_fail (color != NULL); + + float hue; + float scratch[3]; + float rgb[3]; + + sp_color_get_rgb_floatv (color, rgb); + sp_color_rgb_to_hsv_floatv (scratch, rgb[0], rgb[1], rgb[2]); + hue = scratch[0]; + + sp_color_hsv_to_rgb_floatv (scratch, hue, 1.0, 1.0); + + gint lowInd = 0; + gint hiInd = 0; + for ( int i = 1; i < 3; i++ ) + { + if ( scratch[i] < scratch[lowInd] ) + { + lowInd = i; + } + if ( scratch[i] > scratch[hiInd] ) + { + hiInd = i; + } + } + // scratch[lowInd] should always be 0 + gdouble sat = (rgb[hiInd] - rgb[lowInd])/(scratch[hiInd]-scratch[lowInd]); + gdouble val = sat < 1.0 ? (rgb[hiInd] - sat * scratch[hiInd])/(1.0-sat) : 0.0; + + + sp_color_wheel_set_hue(wheel, hue); + sp_color_wheel_set_sv(wheel, sat, val); +} + +gboolean sp_color_wheel_is_adjusting( SPColorWheel *wheel ) +{ + g_return_val_if_fail( SP_IS_COLOR_WHEEL(wheel), FALSE ); + return wheel->dragging; +} + +static void +sp_color_wheel_realize (GtkWidget *widget) +{ + SPColorWheel *wheel; + GdkWindowAttr attributes; + gint attributes_mask; + + wheel = SP_COLOR_WHEEL (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gdk_rgb_get_visual (); + attributes.colormap = gdk_rgb_get_cmap (); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_FOCUS_CHANGE_MASK ); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); +} + +static void +sp_color_wheel_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + SPColorWheel *wheel; + + wheel = SP_COLOR_WHEEL (widget); + + requisition->width = WHEEL_SIZE + widget->style->xthickness * 2; + requisition->height = WHEEL_SIZE + widget->style->ythickness * 2; +} + +static void +sp_color_wheel_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + SPColorWheel *wheel; + + wheel = SP_COLOR_WHEEL (widget); + + widget->allocation = *allocation; + + wheel->_center = MIN(allocation->width, allocation->height)/2; + wheel->_inner = (3 * wheel->_center)/4; + if ( wheel->_image ) + { + g_free( wheel->_image ); + wheel->_image = NULL; + wheel->_bs = 0; + } + + // Need to render the gradient before we do the triangle over + sp_color_wheel_render_hue_wheel(wheel); + sp_color_wheel_recalc_triangle(wheel); + sp_color_wheel_render_triangle(wheel); + + if (GTK_WIDGET_REALIZED (widget)) { + /* Resize GdkWindow */ + gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); + } +} + +static gint +sp_color_wheel_expose (GtkWidget *widget, GdkEventExpose *event) +{ + SPColorWheel *wheel; + + wheel = SP_COLOR_WHEEL (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) { + gint width, height; + width = widget->allocation.width; + height = widget->allocation.height; + sp_color_wheel_paint (wheel, &event->area); + } + + return TRUE; +} + +static gint +sp_color_wheel_button_press (GtkWidget *widget, GdkEventButton *event) +{ + SPColorWheel *wheel; + + wheel = SP_COLOR_WHEEL (widget); + + if (event->button == 1) { + gint cx, cw; + cx = widget->style->xthickness; + cw = widget->allocation.width - 2 * cx; + gboolean grabbed = FALSE; + + { + double dx = event->x - wheel->_center; + double dy = event->y - wheel->_center; + gint hyp = static_cast<gint>(ABS(dx*dx) + ABS(dy*dy)); + if ( hyp <= (wheel->_center*wheel->_center) ) + { + if ( hyp >= (wheel->_inner*wheel->_inner) ) + { + gdouble rot = atan2( dy, -dx ); + sp_color_wheel_set_hue (wheel, (rot + M_PI) / (2.0 * M_PI)); + + wheel->_inTriangle = FALSE; + grabbed = TRUE; + } + else if ( wheel->_triangle && gdk_region_point_in( wheel->_triangle, (gint)event->x, (gint)event->y ) ) + { + wheel->_inTriangle = TRUE; + sp_color_wheel_process_in_triangle( wheel, event->x, event->y ); + grabbed = TRUE; + } + } + } + + if ( grabbed ) + { + gtk_widget_queue_draw( widget ); + gtk_widget_grab_focus( widget ); + + wheel->dragging = TRUE; + gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]); + gdk_pointer_grab (widget->window, FALSE, + (GdkEventMask)(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), + NULL, NULL, event->time); + } + } + + return TRUE; +} + +static gint +sp_color_wheel_button_release (GtkWidget *widget, GdkEventButton *event) +{ + SPColorWheel *wheel; + + wheel = SP_COLOR_WHEEL (widget); + + if (event->button == 1) { + gdk_pointer_ungrab (event->time); + wheel->dragging = FALSE; + + gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]); + } + + return TRUE; +} + +static gint +sp_color_wheel_motion_notify (GtkWidget *widget, GdkEventMotion *event) +{ + SPColorWheel *wheel; + + wheel = SP_COLOR_WHEEL (widget); + + if (wheel->dragging) { + double dx = event->x - wheel->_center; + double dy = event->y - wheel->_center; + if ( !wheel->_inTriangle ) + { + gdouble rot = atan2( dy, -dx ); + sp_color_wheel_set_hue (wheel, (rot + M_PI) / (2.0 * M_PI)); + } + else + { + sp_color_wheel_process_in_triangle( wheel, event->x, event->y ); + } + + gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]); + } + + return TRUE; +} + +GtkWidget * +sp_color_wheel_new () +{ + SPColorWheel *wheel; + + wheel = (SPColorWheel*)gtk_type_new (SP_TYPE_COLOR_WHEEL); + + return GTK_WIDGET (wheel); +} + +static void sp_color_wheel_set_hue(SPColorWheel *wheel, gdouble hue) +{ + g_return_if_fail (SP_IS_COLOR_WHEEL (wheel)); + + if ( wheel->_hue != hue ) + { + wheel->_hue = hue; + + sp_color_wheel_recalc_triangle(wheel); + + SPColor color; + gfloat rgb[3]; + sp_color_wheel_get_color( wheel, &color ); + sp_color_get_rgb_floatv (&color, rgb); + + wheel->_spotValue = ( (0.299 * rgb[0]) + (0.587 * rgb[1]) + (0.114 * rgb[2]) ); + + gtk_widget_queue_draw (GTK_WIDGET (wheel)); + } +} + + +static void sp_color_wheel_set_sv( SPColorWheel *wheel, gdouble sat, gdouble value ) +{ + static gdouble epsilon = 1e-6; + gboolean changed = FALSE; + + if ( ABS( wheel->_sat - sat ) > epsilon ) + { + wheel->_sat = sat; + changed = TRUE; + } + if ( ABS( wheel->_value - value ) > epsilon ) + { + wheel->_value = value; + changed = TRUE; + } + + if ( changed ) + { + SPColor color; + gfloat rgb[3]; + sp_color_wheel_get_color( wheel, &color ); + sp_color_get_rgb_floatv (&color, rgb); + + wheel->_spotValue = ( (0.299 * rgb[0]) + (0.587 * rgb[1]) + (0.114 * rgb[2]) ); + + gtk_signal_emit (GTK_OBJECT (wheel), wheel_signals[CHANGED]); + } + gtk_widget_queue_draw (GTK_WIDGET (wheel)); +} + +static void sp_color_wheel_recalc_triangle(SPColorWheel *wheel) +{ + if ( wheel->_triangle ) + { + gdk_region_destroy( wheel->_triangle ); + wheel->_triangle = NULL; + } + wheel->_triDirty = TRUE; + + if ( wheel->_center > 0 && wheel->_inner > 0 ) + { + gdouble dx = cos( M_PI * 2 * wheel->_hue ); + gdouble dy = -sin( M_PI * 2 * wheel->_hue ); + + wheel->_triPoints[0].x = wheel->_center + static_cast<gint>(dx * wheel->_inner); + wheel->_triPoints[0].y = wheel->_center + static_cast<gint>(dy * wheel->_inner); + + dx = cos( M_PI * 2 * wheel->_hue + ((M_PI * 2)/ 3) ); + dy = -sin( M_PI * 2 * wheel->_hue + ((M_PI * 2) / 3) ); + wheel->_triPoints[1].x = wheel->_center + static_cast<gint>(dx * wheel->_inner); + wheel->_triPoints[1].y = wheel->_center + static_cast<gint>(dy * wheel->_inner); + + dx = cos( M_PI * 2 * wheel->_hue - ((M_PI*2) / 3) ); + dy = -sin( M_PI * 2 * wheel->_hue - ((M_PI*2) / 3) ); + wheel->_triPoints[2].x = wheel->_center + static_cast<gint>(dx * wheel->_inner); + wheel->_triPoints[2].y = wheel->_center + static_cast<gint>(dy * wheel->_inner); + + + wheel->_triangle = gdk_region_polygon( wheel->_triPoints, + 3, + GDK_EVEN_ODD_RULE ); + } +} + +#define VERT_SWAP( X, Y ) { \ + gfloat tmpF; \ + \ + tmpF = point##X.x; \ + point##X.x = point##Y.x; \ + point##Y.x = tmpF; \ + \ + tmpF = point##X.y; \ + point##X.y = point##Y.y; \ + point##Y.y = tmpF; \ + \ + tmpF = rgb##X[0]; \ + rgb##X[0] = rgb##Y[0]; \ + rgb##Y[0] = tmpF; \ + \ + tmpF = rgb##X[1]; \ + rgb##X[1] = rgb##Y[1]; \ + rgb##Y[1] = tmpF; \ + \ + tmpF = rgb##X[2]; \ + rgb##X[2] = rgb##Y[2]; \ + rgb##Y[2] = tmpF; \ +} + +#define VERT_COPY( dst, src ) { \ + point##dst.x = point##src.x; \ + \ + point##dst.y = point##src.y; \ + \ + rgb##dst[0] = rgb##src[0]; \ + rgb##dst[1] = rgb##src[1]; \ + rgb##dst[2] = rgb##src[2]; \ +} + +typedef struct { + gfloat x; + gfloat y; +} PointF; + +static void sp_color_wheel_render_triangle (SPColorWheel *wheel) +{ + if ( wheel->_image ) + { + if ( wheel->_triBs < wheel->_bs ) + { + g_free( wheel->_triImage ); + wheel->_triImage = NULL; + } + + if (wheel->_triDirty || !wheel->_triImage) + { + if ( !wheel->_triImage ) + { + wheel->_triBs = wheel->_bs; + wheel->_triImage = g_new (guchar, wheel->_triBs * 3); + //g_message( "just allocated %fKB for tri", ((wheel->_triBs * 3.0)/1024.0) ); + } + + memcpy( wheel->_triImage, wheel->_image, wheel->_bs * 3 ); + + PointF pointA, pointB, pointC; + pointA.x = wheel->_triPoints[0].x; + pointA.y = wheel->_triPoints[0].y; + pointB.x = wheel->_triPoints[1].x; + pointB.y = wheel->_triPoints[1].y; + pointC.x = wheel->_triPoints[2].x; + pointC.y = wheel->_triPoints[2].y; + + gfloat rgbA[3]; + gfloat rgbB[3] = {0.0, 0.0, 0.0}; + gfloat rgbC[3] = {1.0, 1.0, 1.0}; + + sp_color_hsv_to_rgb_floatv (rgbA, wheel->_hue, 1.0, 1.0); + +// Start of Gouraud fill ============================================================ + gint rowStride = wheel->_center * 2 * 3; + guchar* dst = wheel->_triImage; + + if ( pointC.y < pointB.y ) + VERT_SWAP( C, B ); + + if ( pointC.y < pointA.y ) + VERT_SWAP( C, A ); + + if ( pointB.y < pointA.y ) + VERT_SWAP( B, A ); + + if ( pointA.y == pointB.y && pointB.x < pointA.x ) + VERT_SWAP( A, B ); + + gfloat dr, dg, db; + + gfloat dx1,dx2,dx3; + gfloat dr1,dr2,dr3; + gfloat dg1,dg2,dg3; + gfloat db1,db2,db3; + + + PointF pointS; + PointF pointE; + PointF pointP; + gfloat rgbS[3]; + gfloat rgbE[3]; + gfloat rgbP[3]; + + + if (pointB.y-pointA.y > 0) + { + dx1=(pointB.x-pointA.x)/(pointB.y-pointA.y); + dr1=(rgbB[0]-rgbA[0])/(pointB.y-pointA.y); + dg1=(rgbB[1]-rgbA[1])/(pointB.y-pointA.y); + db1=(rgbB[2]-rgbA[2])/(pointB.y-pointA.y); + } + else + { + dx1=dr1=dg1=db1=0; + } + + if (pointC.y-pointA.y > 0) + { + dx2=(pointC.x-pointA.x)/(pointC.y-pointA.y); + dr2=(rgbC[0]-rgbA[0])/(pointC.y-pointA.y); + dg2=(rgbC[1]-rgbA[1])/(pointC.y-pointA.y); + db2=(rgbC[2]-rgbA[2])/(pointC.y-pointA.y); + } + else + { + dx2=dr2=dg2=db2=0; + } + + if (pointC.y-pointB.y > 0) + { + dx3=(pointC.x-pointB.x)/(pointC.y-pointB.y); + dr3=(rgbC[0]-rgbB[0])/(pointC.y-pointB.y); + dg3=(rgbC[1]-rgbB[1])/(pointC.y-pointB.y); + db3=(rgbC[2]-rgbB[2])/(pointC.y-pointB.y); + } + else + { + dx3=dr3=dg3=db3=0; + } + + VERT_COPY(S, A); + VERT_COPY(E, A); + + if ( dx1 == 0 ) + { + VERT_COPY(E,B); + for(;pointS.y <= pointC.y; pointS.y++,pointE.y++) + { + if (pointE.x-pointS.x > 0) + { + dr=(rgbE[0]-rgbS[0])/(pointE.x-pointS.x); + dg=(rgbE[1]-rgbS[1])/(pointE.x-pointS.x); + db=(rgbE[2]-rgbS[2])/(pointE.x-pointS.x); + } + else + { + dr=dg=db=0; + } + VERT_COPY(P,S); + dst = wheel->_triImage + (static_cast<gint>(pointP.y) * rowStride); + dst += static_cast<gint>(pointP.x) * 3; + for(;pointP.x < pointE.x;pointP.x++) + { + //putpixel(P); + dst[0] = SP_COLOR_F_TO_U(rgbP[0]); + dst[1] = SP_COLOR_F_TO_U(rgbP[1]); + dst[2] = SP_COLOR_F_TO_U(rgbP[2]); + dst += 3; + rgbP[0]+=dr; rgbP[1]+=dg; rgbP[2]+=db; + } + pointS.x+=dx2; rgbS[0]+=dr2; rgbS[1]+=dg2; rgbS[2]+=db2; + pointE.x+=dx3; rgbE[0]+=dr3; rgbE[1]+=dg3; rgbE[2]+=db3; + } + } + else if (dx1 > dx2) + { + for(;pointS.y <= pointB.y; pointS.y++,pointE.y++) + { + if (pointE.x-pointS.x > 0) + { + dr=(rgbE[0]-rgbS[0])/(pointE.x-pointS.x); + dg=(rgbE[1]-rgbS[1])/(pointE.x-pointS.x); + db=(rgbE[2]-rgbS[2])/(pointE.x-pointS.x); + } + else + { + dr=dg=db=0; + } + VERT_COPY(P,S); + dst = wheel->_triImage + (static_cast<gint>(pointP.y) * rowStride); + dst += static_cast<gint>(pointP.x) * 3; + for(;pointP.x < pointE.x;pointP.x++) + { + //putpixel(P); + dst[0] = SP_COLOR_F_TO_U(rgbP[0]); + dst[1] = SP_COLOR_F_TO_U(rgbP[1]); + dst[2] = SP_COLOR_F_TO_U(rgbP[2]); + dst += 3; + rgbP[0]+=dr; rgbP[1]+=dg; rgbP[2]+=db; + } + pointS.x+=dx2; rgbS[0]+=dr2; rgbS[1]+=dg2; rgbS[2]+=db2; + pointE.x+=dx1; rgbE[0]+=dr1; rgbE[1]+=dg1; rgbE[2]+=db1; + } + VERT_COPY(E,B); + for(;pointS.y <= pointC.y; pointS.y++,pointE.y++) + { + if (pointE.x-pointS.x > 0) + { + dr=(rgbE[0]-rgbS[0])/(pointE.x-pointS.x); + dg=(rgbE[1]-rgbS[1])/(pointE.x-pointS.x); + db=(rgbE[2]-rgbS[2])/(pointE.x-pointS.x); + } + else + { + dr=dg=db=0; + } + VERT_COPY(P,S); + dst = wheel->_triImage + (static_cast<gint>(pointP.y) * rowStride); + dst += static_cast<gint>(pointP.x) * 3; + for(;pointP.x < pointE.x;pointP.x++) + { + //putpixel(P); + dst[0] = SP_COLOR_F_TO_U(rgbP[0]); + dst[1] = SP_COLOR_F_TO_U(rgbP[1]); + dst[2] = SP_COLOR_F_TO_U(rgbP[2]); + dst += 3; + rgbP[0]+=dr; rgbP[1]+=dg; rgbP[2]+=db; + } + pointS.x+=dx2; rgbS[0]+=dr2; rgbS[1]+=dg2; rgbS[2]+=db2; + pointE.x+=dx3; rgbE[0]+=dr3; rgbE[1]+=dg3; rgbE[2]+=db3; + } + } + else if ( dx1 ) + { + for(;pointS.y <= pointB.y; pointS.y++,pointE.y++) + { + if (pointE.x-pointS.x > 0) + { + dr=(rgbE[0]-rgbS[0])/(pointE.x-pointS.x); + dg=(rgbE[1]-rgbS[1])/(pointE.x-pointS.x); + db=(rgbE[2]-rgbS[2])/(pointE.x-pointS.x); + } + else + { + dr=dg=db=0; + } + VERT_COPY(P,S); + dst = wheel->_triImage + (static_cast<gint>(pointP.y) * rowStride); + dst += static_cast<gint>(pointP.x) * 3; + for(;pointP.x < pointE.x;pointP.x++) + { + //putpixel(P); + dst[0] = SP_COLOR_F_TO_U(rgbP[0]); + dst[1] = SP_COLOR_F_TO_U(rgbP[1]); + dst[2] = SP_COLOR_F_TO_U(rgbP[2]); + dst += 3; + rgbP[0]+=dr; rgbP[1]+=dg; rgbP[2]+=db; + } + pointS.x+=dx1; rgbS[0]+=dr1; rgbS[1]+=dg1; rgbS[2]+=db1; + pointE.x+=dx2; rgbE[0]+=dr2; rgbE[1]+=dg2; rgbE[2]+=db2; + } + VERT_COPY(S,B); + for(;pointS.y <= pointC.y; pointS.y++,pointE.y++) + { + if (pointE.x-pointS.x > 0) + { + dr=(rgbE[0]-rgbS[0])/(pointE.x-pointS.x); + dg=(rgbE[1]-rgbS[1])/(pointE.x-pointS.x); + db=(rgbE[2]-rgbS[2])/(pointE.x-pointS.x); + } + else + { + dr=dg=db=0; + } + VERT_COPY(P,S); + dst = wheel->_triImage + (static_cast<gint>(pointP.y) * rowStride); + dst += static_cast<gint>(pointP.x) * 3; + for(;pointP.x < pointE.x;pointP.x++) + { + //putpixel(P); + dst[0] = SP_COLOR_F_TO_U(rgbP[0]); + dst[1] = SP_COLOR_F_TO_U(rgbP[1]); + dst[2] = SP_COLOR_F_TO_U(rgbP[2]); + dst += 3; + rgbP[0]+=dr; rgbP[1]+=dg; rgbP[2]+=db; + } + pointS.x+=dx3; rgbS[0]+=dr3; rgbS[1]+=dg3; rgbS[2]+=db3; + pointE.x+=dx2; rgbE[0]+=dr2; rgbE[1]+=dg2; rgbE[2]+=db2; + } + } + +// End of Gouraud fill ============================================================ + + wheel->_triDirty = FALSE; + //g_message( "Just updated triangle" ); + } + } +} + +static void +sp_color_wheel_paint (SPColorWheel *wheel, GdkRectangle *area) +{ + GtkWidget *widget; + GdkRectangle warea, carea; + GdkRectangle wpaint, cpaint; + + widget = GTK_WIDGET (wheel); + + /* Widget area */ + warea.x = 0; + warea.y = 0; + warea.width = widget->allocation.width; + warea.height = widget->allocation.height; + + /* Color gradient area */ + carea.x = widget->style->xthickness; + carea.y = widget->style->ythickness; + carea.width = widget->allocation.width - 2 * carea.x; + carea.height = widget->allocation.height - 2 * carea.y; + + /* Actual paintable area */ + if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return; + + //g_message( "Painted as state %d", widget->state ); + + /* Paintable part of color gradient area */ + if (gdk_rectangle_intersect (area, &carea, &cpaint)) { + sp_color_wheel_render_hue_wheel (wheel); + sp_color_wheel_render_triangle (wheel); + } + +/* + gtk_draw_box (widget->style, + widget->window, + (GtkStateType)widget->state, + GTK_SHADOW_NONE, + warea.x, + warea.y, + warea.width, + warea.height); +*/ + + gtk_style_apply_default_background( widget->style, + widget->window, + TRUE, + (GtkStateType)widget->state, + NULL, + 0, + 0, + warea.width, + warea.height); + + + /* Draw shadow */ +/* + gtk_paint_shadow (widget->style, widget->window, + (GtkStateType)widget->state, GTK_SHADOW_IN, + NULL, widget, "colorwheel", + 0, 0, + warea.width, warea.height); +*/ + + + /* Draw pixelstore */ + if (wheel->_triImage != NULL) { + //gdouble start, end; + //start = get_time(); + gdk_draw_rgb_image (widget->window, widget->style->black_gc, + 0, 0,//cpaint.x, cpaint.y, + //cpaint.width, cpaint.height, + wheel->_center * 2, wheel->_center * 2, + GDK_RGB_DITHER_MAX, + wheel->_triImage, wheel->_center * 6); + + //end = get_time(); + //g_message( "blits took %f", (end-start) ); + } + + { + gdouble dx = cos( M_PI * 2 * wheel->_hue ); + gdouble dy = -sin( M_PI * 2 * wheel->_hue ); + + gfloat rgb[3]; + sp_color_hsv_to_rgb_floatv (rgb, wheel->_hue, 1.0, 1.0); + + 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; + + gint inx = wheel->_center + static_cast<gint>(dx * wheel->_inner); + gint iny = wheel->_center + static_cast<gint>(dy * wheel->_inner); + + + gdk_draw_line (widget->window, line_gc, + inx, iny, + wheel->_center + static_cast<gint>(dx * wheel->_center), wheel->_center + static_cast<gint>(dy * wheel->_center) ); + + + GdkGCValues values; + + if ( GTK_WIDGET_HAS_FOCUS(wheel) ) + { + line_gc = widget->style->black_gc; + + gdk_gc_get_values ( line_gc, &values ); + + gdk_gc_set_line_attributes ( line_gc, + 3, // Line width + values.line_style, //GDK_LINE_SOLID, + values.cap_style, //GDK_CAP_BUTT, + values.join_style ); //GDK_JOIN_MITER ); + + if ( wheel->_inTriangle ) + { + gdk_draw_line (widget->window, line_gc, + wheel->_triPoints[0].x, wheel->_triPoints[0].y, + wheel->_triPoints[1].x, wheel->_triPoints[1].y ); + + gdk_draw_line (widget->window, line_gc, + wheel->_triPoints[1].x, wheel->_triPoints[1].y, + wheel->_triPoints[2].x, wheel->_triPoints[2].y ); + + gdk_draw_line (widget->window, line_gc, + wheel->_triPoints[2].x, wheel->_triPoints[2].y, + wheel->_triPoints[0].x, wheel->_triPoints[0].y ); + } + else + { + gdk_draw_arc (widget->window, line_gc, + FALSE, // filled + 0, 0, + wheel->_center * 2, wheel->_center * 2, + 0, 64 * 360 ); + + gint diff = wheel->_center - wheel->_inner; + + gdk_draw_arc (widget->window, line_gc, + FALSE, // filled + diff, diff, + wheel->_inner * 2, wheel->_inner * 2, + 0, 64 * 360 ); + + } + gdk_gc_set_line_attributes ( line_gc, + values.line_width, // Line width + values.line_style, //GDK_LINE_SOLID, + values.cap_style, //GDK_CAP_BUTT, + values.join_style ); //GDK_JOIN_MITER ); + } +// ========== + +// line_gc = (p[3] < 0x80) ? widget->style->white_gc : widget->style->black_gc; + line_gc = (wheel->_spotValue < 0.5) ? widget->style->white_gc : widget->style->black_gc; + + gdk_gc_get_values ( line_gc, &values ); + + gdk_gc_set_line_attributes ( line_gc, + 2, // Line width + values.line_style, //GDK_LINE_SOLID, + values.cap_style, //GDK_CAP_BUTT, + values.join_style ); //GDK_JOIN_MITER ); + + gint pointX = (gint)( (1.0 - wheel->_sat) * ((1.0-wheel->_value)*(gdouble)wheel->_triPoints[1].x + wheel->_value*(gdouble)wheel->_triPoints[2].x) + + (wheel->_sat * wheel->_triPoints[0].x) ); + + gint pointY = (gint)( (1.0 - wheel->_sat) * ((1.0-wheel->_value)*(gdouble)wheel->_triPoints[1].y + wheel->_value*(gdouble)wheel->_triPoints[2].y) + + (wheel->_sat * wheel->_triPoints[0].y) ); + + + gdk_gc_set_line_attributes ( line_gc, + values.line_width, // Line width + values.line_style, //GDK_LINE_SOLID, + values.cap_style, //GDK_CAP_BUTT, + values.join_style ); //GDK_JOIN_MITER ); + + gdk_draw_arc (widget->window, line_gc, + FALSE, // filled + pointX - 4, pointY - 4, + 8, 8, + 0, 64 * 360 ); + + gdk_draw_arc (widget->window, line_gc, + FALSE, // filled + pointX - 3, pointY - 3, + 6, 6, + 0, 64 * 360 ); + + + + } +} + +/* Colors are << 16 */ + +static void +sp_color_wheel_render_hue_wheel (SPColorWheel *wheel) +{ + guchar *dp; + gint x, y; + guint r, g, b; + gint size = wheel->_center * 2; + gboolean dirty = FALSE; + + if (wheel->_image && (wheel->_bs < (size * size) )) { + g_free (wheel->_image); + wheel->_image = NULL; + wheel->_bs = 0; + + if ( wheel->_triImage ) + { + g_free( wheel->_triImage ); + wheel->_triImage = NULL; + wheel->_triBs = 0; + wheel->_triDirty = TRUE; + } + } + + if (!wheel->_image) { + wheel->_image = g_new (guchar, size * size * 3); + wheel->_bs = size * size; + dirty = TRUE; + //g_message( "just allocated %fKB for hue", ((wheel->_bs * 3.0)/1024.0) ); + } + + if ( dirty ) + { + GtkWidget* widget = GTK_WIDGET (wheel); + dp = wheel->_image; + r = widget->style->bg[widget->state].red >> 8; + g = widget->style->bg[widget->state].green >> 8; + b = widget->style->bg[widget->state].blue >> 8; + //g_message( "Rendered as state %d", widget->state ); + + gint offset = wheel->_center; + gint inner = wheel->_inner * wheel->_inner; + gint rad = wheel->_center * wheel->_center; + + for (x = 0; x < size; x++) { + guchar *d = dp; + for (y = 0; y < size; y++) { + gint dx = x - offset; + gint dy = y - offset; + gint hyp = (ABS(dx*dx) + ABS(dy*dy)); + if ( hyp >= inner && hyp <= rad) + { + gdouble rot = atan2( static_cast<gdouble>(dy), static_cast<gdouble>(-dx) ); + + gfloat rgb[3]; + sp_color_hsv_to_rgb_floatv (rgb, (rot + M_PI) / (2.0 * M_PI), 1.0, 1.0); + + d[0] = SP_COLOR_F_TO_U (rgb[0]); + d[1] = SP_COLOR_F_TO_U (rgb[1]); + d[2] = SP_COLOR_F_TO_U (rgb[2]); + } + else + { + /* Background value */ + d[0] = r; + d[1] = g; + d[2] = b; + } + + d += 3 * size; + } + dp += 3; + } + } +} + +static gboolean sp_color_wheel_focus(GtkWidget *widget, + GtkDirectionType direction) +{ + gboolean focusKept = FALSE; + gboolean wasFocused = GTK_WIDGET_HAS_FOCUS(widget); + SPColorWheel* wheel = SP_COLOR_WHEEL(widget); + gboolean goingUp = FALSE; + + switch ( direction ) + { + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_UP: + case GTK_DIR_LEFT: + goingUp = TRUE; + break; + + case GTK_DIR_TAB_BACKWARD: + case GTK_DIR_DOWN: + case GTK_DIR_RIGHT: + goingUp = FALSE; + break; + default: + ; + } + + if ( !wasFocused ) + { + wheel->_inTriangle = !goingUp; + gtk_widget_grab_focus (widget); + focusKept = TRUE; + } + else if ( (!wheel->_inTriangle) == (!goingUp) ) + { + focusKept = FALSE; + } + else + { + wheel->_inTriangle = !wheel->_inTriangle; + gtk_widget_queue_draw( widget ); + focusKept = TRUE; + } + + return focusKept; +} + +static void sp_color_wheel_process_in_triangle( SPColorWheel *wheel, gdouble x, gdouble y ) +{ +// njh: dot(rot90(B-C), x) = saturation +// njh: dot(B-C, x) = value + NR::Point delta( x - (((gdouble)(wheel->_triPoints[1].x + wheel->_triPoints[2].x)) / 2.0), + y - (((gdouble)(wheel->_triPoints[1].y + wheel->_triPoints[2].y)) / 2.0) ); + + gdouble rot = (M_PI * 2 * wheel->_hue ); + + NR::Point result = delta * NR::rotate(rot); + + gdouble sat = CLAMP( result[NR::X] / (wheel->_inner * 1.5), 0.0, 1.0 ); + + gdouble halfHeight = (wheel->_inner * sin(M_PI/3.0)) * (1.0 - sat); + gdouble value = CLAMP( ((result[NR::Y]+ halfHeight) / (2.0*halfHeight)), 0.0, 1.0 ); + + wheel->_triDirty = TRUE; + + sp_color_wheel_set_sv( wheel, sat, value ); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : |
