comparison src/xs_curve.c @ 660:b0743dc9165d

Change tabs to 4 spaces, everywhere.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 02 Apr 2008 22:10:05 +0300
parents ce1fe59627f2
children b5b6b13a6d85
comparison
equal deleted inserted replaced
659:04ea91a61225 660:b0743dc9165d
31 #include <gtk/gtkdrawingarea.h> 31 #include <gtk/gtkdrawingarea.h>
32 #include <gtk/gtkmain.h> 32 #include <gtk/gtkmain.h>
33 #include <gtk/gtksignal.h> 33 #include <gtk/gtksignal.h>
34 34
35 35
36 #define RADIUS 3 /* radius of the control points */ 36 #define RADIUS 3 /* radius of the control points */
37 #define RADIUS2 (RADIUS * 2) 37 #define RADIUS2 (RADIUS * 2)
38 #define MIN_DISTANCE 7 /* min distance between control points */ 38 #define MIN_DISTANCE 7 /* min distance between control points */
39 39
40 40
41 #define GRAPH_MASK (GDK_EXPOSURE_MASK | \ 41 #define GRAPH_MASK (GDK_EXPOSURE_MASK | \
42 GDK_POINTER_MOTION_MASK | \ 42 GDK_POINTER_MOTION_MASK | \
43 GDK_POINTER_MOTION_HINT_MASK | \ 43 GDK_POINTER_MOTION_HINT_MASK | \
44 GDK_ENTER_NOTIFY_MASK | \ 44 GDK_ENTER_NOTIFY_MASK | \
45 GDK_BUTTON_PRESS_MASK | \ 45 GDK_BUTTON_PRESS_MASK | \
46 GDK_BUTTON_RELEASE_MASK | \ 46 GDK_BUTTON_RELEASE_MASK | \
47 GDK_BUTTON1_MOTION_MASK) 47 GDK_BUTTON1_MOTION_MASK)
48 48
49 #define GET_X(i) curve->ctlpoints[i].x 49 #define GET_X(i) curve->ctlpoints[i].x
50 #define GET_Y(i) curve->ctlpoints[i].y 50 #define GET_Y(i) curve->ctlpoints[i].y
51 51
52 52
53 enum { 53 enum {
54 ARG_0, 54 ARG_0,
55 ARG_MIN_X, 55 ARG_MIN_X,
56 ARG_MAX_X, 56 ARG_MAX_X,
57 ARG_MIN_Y, 57 ARG_MIN_Y,
58 ARG_MAX_Y 58 ARG_MAX_Y
59 }; 59 };
60 60
61 static GtkDrawingAreaClass *parent_class = NULL; 61 static GtkDrawingAreaClass *parent_class = NULL;
62 62
63 static void xs_curve_class_init(XSCurveClass * class); 63 static void xs_curve_class_init(XSCurveClass * class);
69 static void xs_curve_size_graph(XSCurve * curve); 69 static void xs_curve_size_graph(XSCurve * curve);
70 70
71 71
72 GtkType xs_curve_get_type(void) 72 GtkType xs_curve_get_type(void)
73 { 73 {
74 static GtkType curve_type = 0; 74 static GtkType curve_type = 0;
75 75
76 if (!curve_type) { 76 if (!curve_type) {
77 static const GtkTypeInfo curve_info = { 77 static const GtkTypeInfo curve_info = {
78 "XSCurve", 78 "XSCurve",
79 sizeof(XSCurve), 79 sizeof(XSCurve),
80 sizeof(XSCurveClass), 80 sizeof(XSCurveClass),
81 (GtkClassInitFunc) xs_curve_class_init, 81 (GtkClassInitFunc) xs_curve_class_init,
82 (GtkObjectInitFunc) xs_curve_init, 82 (GtkObjectInitFunc) xs_curve_init,
83 /* reserved_1 */ NULL, 83 /* reserved_1 */ NULL,
84 /* reserved_2 */ NULL, 84 /* reserved_2 */ NULL,
85 (GtkClassInitFunc) NULL, 85 (GtkClassInitFunc) NULL,
86 }; 86 };
87 87
88 curve_type = gtk_type_unique(GTK_TYPE_DRAWING_AREA, &curve_info); 88 curve_type = gtk_type_unique(GTK_TYPE_DRAWING_AREA, &curve_info);
89 } 89 }
90 return curve_type; 90 return curve_type;
91 } 91 }
92 92
93 93
94 static void xs_curve_class_init(XSCurveClass *class) 94 static void xs_curve_class_init(XSCurveClass *class)
95 { 95 {
96 GtkObjectClass *object_class; 96 GtkObjectClass *object_class;
97 97
98 parent_class = gtk_type_class(GTK_TYPE_DRAWING_AREA); 98 parent_class = gtk_type_class(GTK_TYPE_DRAWING_AREA);
99 99
100 object_class = (GtkObjectClass *) class; 100 object_class = (GtkObjectClass *) class;
101 101
102 object_class->set_arg = xs_curve_set_arg; 102 object_class->set_arg = xs_curve_set_arg;
103 object_class->get_arg = xs_curve_get_arg; 103 object_class->get_arg = xs_curve_get_arg;
104 object_class->finalize = xs_curve_finalize; 104 object_class->finalize = xs_curve_finalize;
105 105
106 gtk_object_add_arg_type("XSCurve::min_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_X); 106 gtk_object_add_arg_type("XSCurve::min_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_X);
107 gtk_object_add_arg_type("XSCurve::max_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_X); 107 gtk_object_add_arg_type("XSCurve::max_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_X);
108 gtk_object_add_arg_type("XSCurve::min_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_Y); 108 gtk_object_add_arg_type("XSCurve::min_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_Y);
109 gtk_object_add_arg_type("XSCurve::max_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_Y); 109 gtk_object_add_arg_type("XSCurve::max_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_Y);
110 } 110 }
111 111
112 112
113 static void xs_curve_init(XSCurve *curve) 113 static void xs_curve_init(XSCurve *curve)
114 { 114 {
115 gint old_mask; 115 gint old_mask;
116 116
117 curve->pixmap = NULL; 117 curve->pixmap = NULL;
118 curve->grab_point = -1; 118 curve->grab_point = -1;
119 119
120 curve->nctlpoints = 0; 120 curve->nctlpoints = 0;
121 curve->ctlpoints = NULL; 121 curve->ctlpoints = NULL;
122 122
123 curve->min_x = 0.0; 123 curve->min_x = 0.0;
124 curve->max_x = 2047.0; 124 curve->max_x = 2047.0;
125 curve->min_y = 0.0; 125 curve->min_y = 0.0;
126 curve->max_y = 24000.0; 126 curve->max_y = 24000.0;
127 127
128 old_mask = gtk_widget_get_events(GTK_WIDGET(curve)); 128 old_mask = gtk_widget_get_events(GTK_WIDGET(curve));
129 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK); 129 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK);
130 gtk_signal_connect(GTK_OBJECT(curve), "event", (GtkSignalFunc) xs_curve_graph_events, curve); 130 gtk_signal_connect(GTK_OBJECT(curve), "event", (GtkSignalFunc) xs_curve_graph_events, curve);
131 xs_curve_size_graph(curve); 131 xs_curve_size_graph(curve);
132 } 132 }
133 133
134 134
135 static void xs_curve_set_arg(GtkObject *object, GtkArg *arg, guint arg_id) 135 static void xs_curve_set_arg(GtkObject *object, GtkArg *arg, guint arg_id)
136 { 136 {
137 XSCurve *curve = XS_CURVE(object); 137 XSCurve *curve = XS_CURVE(object);
138 138
139 switch (arg_id) { 139 switch (arg_id) {
140 case ARG_MIN_X: 140 case ARG_MIN_X:
141 xs_curve_set_range(curve, GTK_VALUE_FLOAT(*arg), curve->max_x, curve->min_y, curve->max_y); 141 xs_curve_set_range(curve, GTK_VALUE_FLOAT(*arg), curve->max_x, curve->min_y, curve->max_y);
142 break; 142 break;
143 case ARG_MAX_X: 143 case ARG_MAX_X:
144 xs_curve_set_range(curve, curve->min_x, GTK_VALUE_FLOAT(*arg), curve->min_y, curve->max_y); 144 xs_curve_set_range(curve, curve->min_x, GTK_VALUE_FLOAT(*arg), curve->min_y, curve->max_y);
145 break; 145 break;
146 case ARG_MIN_Y: 146 case ARG_MIN_Y:
147 xs_curve_set_range(curve, curve->min_x, curve->max_x, GTK_VALUE_FLOAT(*arg), curve->max_y); 147 xs_curve_set_range(curve, curve->min_x, curve->max_x, GTK_VALUE_FLOAT(*arg), curve->max_y);
148 break; 148 break;
149 case ARG_MAX_Y: 149 case ARG_MAX_Y:
150 xs_curve_set_range(curve, curve->min_x, curve->max_x, curve->min_y, GTK_VALUE_FLOAT(*arg)); 150 xs_curve_set_range(curve, curve->min_x, curve->max_x, curve->min_y, GTK_VALUE_FLOAT(*arg));
151 break; 151 break;
152 } 152 }
153 } 153 }
154 154
155 155
156 static void xs_curve_get_arg(GtkObject *object, GtkArg *arg, guint arg_id) 156 static void xs_curve_get_arg(GtkObject *object, GtkArg *arg, guint arg_id)
157 { 157 {
158 XSCurve *curve = XS_CURVE(object); 158 XSCurve *curve = XS_CURVE(object);
159 159
160 switch (arg_id) { 160 switch (arg_id) {
161 case ARG_MIN_X: 161 case ARG_MIN_X:
162 GTK_VALUE_FLOAT(*arg) = curve->min_x; 162 GTK_VALUE_FLOAT(*arg) = curve->min_x;
163 break; 163 break;
164 case ARG_MAX_X: 164 case ARG_MAX_X:
165 GTK_VALUE_FLOAT(*arg) = curve->max_x; 165 GTK_VALUE_FLOAT(*arg) = curve->max_x;
166 break; 166 break;
167 case ARG_MIN_Y: 167 case ARG_MIN_Y:
168 GTK_VALUE_FLOAT(*arg) = curve->min_y; 168 GTK_VALUE_FLOAT(*arg) = curve->min_y;
169 break; 169 break;
170 case ARG_MAX_Y: 170 case ARG_MAX_Y:
171 GTK_VALUE_FLOAT(*arg) = curve->max_y; 171 GTK_VALUE_FLOAT(*arg) = curve->max_y;
172 break; 172 break;
173 default: 173 default:
174 arg->type = GTK_TYPE_INVALID; 174 arg->type = GTK_TYPE_INVALID;
175 break; 175 break;
176 } 176 }
177 } 177 }
178 178
179 179
180 static int xs_project(gfloat value, gfloat min, gfloat max, int norm) 180 static int xs_project(gfloat value, gfloat min, gfloat max, int norm)
181 { 181 {
182 return (norm - 1) * ((value - min) / (max - min)) + 0.5; 182 return (norm - 1) * ((value - min) / (max - min)) + 0.5;
183 } 183 }
184 184
185 185
186 static gfloat xs_unproject(gint value, gfloat min, gfloat max, int norm) 186 static gfloat xs_unproject(gint value, gfloat min, gfloat max, int norm)
187 { 187 {
188 return value / (gfloat) (norm - 1) * (max - min) + min; 188 return value / (gfloat) (norm - 1) * (max - min) + min;
189 } 189 }
190 190
191 191
192 static inline void xs_cubic_coeff(gfloat x1, gfloat y1, 192 static inline void xs_cubic_coeff(gfloat x1, gfloat y1,
193 gfloat x2, gfloat y2, 193 gfloat x2, gfloat y2,
194 gfloat k1, gfloat k2, 194 gfloat k1, gfloat k2,
195 gfloat *a, gfloat *b, 195 gfloat *a, gfloat *b,
196 gfloat *c, gfloat *d) 196 gfloat *c, gfloat *d)
197 { 197 {
198 gfloat dx = x2 - x1, dy = y2 - y1; 198 gfloat dx = x2 - x1, dy = y2 - y1;
199 199
200 *a = ((k1 + k2) - 2 * dy / dx) / (dx * dx); 200 *a = ((k1 + k2) - 2 * dy / dx) / (dx * dx);
201 *b = ((k2 - k1) / dx - 3 * (x1 + x2) * (*a)) / 2; 201 *b = ((k2 - k1) / dx - 3 * (x1 + x2) * (*a)) / 2;
202 *c = k1 - (3 * x1 * (*a) + 2 * (*b)) * x1; 202 *c = k1 - (3 * x1 * (*a) + 2 * (*b)) * x1;
203 *d = y1 - ((x1 * (*a) + (*b)) * x1 + (*c)) * x1; 203 *d = y1 - ((x1 * (*a) + (*b)) * x1 + (*c)) * x1;
204 } 204 }
205 205
206 206
207 static void xs_curve_draw(XSCurve *curve, gint width, gint height) 207 static void xs_curve_draw(XSCurve *curve, gint width, gint height)
208 { 208 {
209 gfloat res = 5.0f; 209 gfloat res = 5.0f;
210 GtkStateType state; 210 GtkStateType state;
211 GtkStyle *style; 211 GtkStyle *style;
212 gint i, ox = -1, oy = -1; 212 gint i, ox = -1, oy = -1;
213 t_xs_point *p0, *p1, *p2, *p3; 213 t_xs_point *p0, *p1, *p2, *p3;
214 214
215 if (!curve->pixmap) 215 if (!curve->pixmap)
216 return; 216 return;
217 217
218 state = GTK_STATE_NORMAL; 218 state = GTK_STATE_NORMAL;
219 if (!GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(curve))) 219 if (!GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(curve)))
220 state = GTK_STATE_INSENSITIVE; 220 state = GTK_STATE_INSENSITIVE;
221 221
222 style = GTK_WIDGET(curve)->style; 222 style = GTK_WIDGET(curve)->style;
223 223
224 /* Clear the pixmap */ 224 /* Clear the pixmap */
225 gtk_paint_flat_box(style, curve->pixmap, 225 gtk_paint_flat_box(style, curve->pixmap,
226 GTK_STATE_NORMAL, GTK_SHADOW_NONE, 226 GTK_STATE_NORMAL, GTK_SHADOW_NONE,
227 NULL, GTK_WIDGET(curve), "curve_bg", 227 NULL, GTK_WIDGET(curve), "curve_bg",
228 0, 0, 228 0, 0,
229 width + RADIUS2, 229 width + RADIUS2,
230 height + RADIUS2); 230 height + RADIUS2);
231 231
232 232
233 /* Draw the grid */ 233 /* Draw the grid */
234 for (i = 0; i < 5; i++) { 234 for (i = 0; i < 5; i++) {
235 gdk_draw_line(curve->pixmap, style->dark_gc[state], 235 gdk_draw_line(curve->pixmap, style->dark_gc[state],
236 RADIUS, i * (height / 4.0) + RADIUS, 236 RADIUS, i * (height / 4.0) + RADIUS,
237 width + RADIUS, i * (height / 4.0) + RADIUS); 237 width + RADIUS, i * (height / 4.0) + RADIUS);
238 238
239 gdk_draw_line(curve->pixmap, style->dark_gc[state], 239 gdk_draw_line(curve->pixmap, style->dark_gc[state],
240 i * (width / 4.0) + RADIUS, RADIUS, 240 i * (width / 4.0) + RADIUS, RADIUS,
241 i * (width / 4.0) + RADIUS, height + RADIUS); 241 i * (width / 4.0) + RADIUS, height + RADIUS);
242 } 242 }
243 243
244 #if 1 244 #if 1
245 /* Draw the spline/curve itself */ 245 /* Draw the spline/curve itself */
246 p0 = curve->ctlpoints; 246 p0 = curve->ctlpoints;
247 p1 = p0; 247 p1 = p0;
248 p2 = p1; p2++; 248 p2 = p1; p2++;
249 p3 = p2; p3++; 249 p3 = p2; p3++;
250 250
251 /* Draw each curve segment */ 251 /* Draw each curve segment */
252 if (curve->nctlpoints > 5) 252 if (curve->nctlpoints > 5)
253 for (i = 0; i < curve->nctlpoints; i++, ++p0, ++p1, ++p2, ++p3) { 253 for (i = 0; i < curve->nctlpoints; i++, ++p0, ++p1, ++p2, ++p3) {
254 gint n; 254 gint n;
255 gfloat k1, k2, a, b, c, d, x; 255 gfloat k1, k2, a, b, c, d, x;
256 256
257 if (p1->x == p2->x) 257 if (p1->x == p2->x)
258 continue; 258 continue;
259 259
260 if (p0->x == p1->x && p2->x == p3->x) { 260 if (p0->x == p1->x && p2->x == p3->x) {
261 k1 = k2 = (p2->y - p1->y) / (p2->x - p1->x); 261 k1 = k2 = (p2->y - p1->y) / (p2->x - p1->x);
262 } else if (p0->x == p1->x) { 262 } else if (p0->x == p1->x) {
263 k2 = (p3->y - p1->y) / (p3->x - p1->x); 263 k2 = (p3->y - p1->y) / (p3->x - p1->x);
264 k1 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k2) / 2; 264 k1 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k2) / 2;
265 } else if (p2->x == p3->x) { 265 } else if (p2->x == p3->x) {
266 k1 = (p2->y - p0->y) / (p2->x - p0->x); 266 k1 = (p2->y - p0->y) / (p2->x - p0->x);
267 k2 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k1) / 2; 267 k2 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k1) / 2;
268 } else { 268 } else {
269 k1 = (p2->y - p0->y) / (p2->x - p0->x); 269 k1 = (p2->y - p0->y) / (p2->x - p0->x);
270 k2 = (p3->y - p1->y) / (p3->x - p1->x); 270 k2 = (p3->y - p1->y) / (p3->x - p1->x);
271 } 271 }
272 272
273 xs_cubic_coeff(p1->x, p1->y, p2->x, p2->y, k1, k2, &a, &b, &c, &d); 273 xs_cubic_coeff(p1->x, p1->y, p2->x, p2->y, k1, k2, &a, &b, &c, &d);
274 274
275 for (x = p1->x; x <= p2->x; x += res, n++) { 275 for (x = p1->x; x <= p2->x; x += res, n++) {
276 gfloat y = ((a * x + b) * x + c) * x + d; 276 gfloat y = ((a * x + b) * x + c) * x + d;
277 gint qx, qy; 277 gint qx, qy;
278 qx = RADIUS + xs_project(x, curve->min_x, curve->max_x, width); 278 qx = RADIUS + xs_project(x, curve->min_x, curve->max_x, width);
279 qy = RADIUS + xs_project(y, curve->min_y, curve->max_y, height); 279 qy = RADIUS + xs_project(y, curve->min_y, curve->max_y, height);
280 280
281 if (ox != -1) { 281 if (ox != -1) {
282 gdk_draw_line(curve->pixmap, style->fg_gc[state], 282 gdk_draw_line(curve->pixmap, style->fg_gc[state],
283 ox, oy, qx, qy); 283 ox, oy, qx, qy);
284 } 284 }
285 ox = qx; oy = qy; 285 ox = qx; oy = qy;
286 } 286 }
287 } 287 }
288 288
289 #endif 289 #endif
290 290
291 /* Draw control points */ 291 /* Draw control points */
292 for (i = 0; i < curve->nctlpoints; ++i) { 292 for (i = 0; i < curve->nctlpoints; ++i) {
293 gint x, y; 293 gint x, y;
294 GtkStateType cstate; 294 GtkStateType cstate;
295 295
296 if (GET_X(i) < curve->min_x || GET_Y(i) < curve->min_y || 296 if (GET_X(i) < curve->min_x || GET_Y(i) < curve->min_y ||
297 GET_X(i) >= curve->max_x || GET_Y(i) >= curve->max_y) 297 GET_X(i) >= curve->max_x || GET_Y(i) >= curve->max_y)
298 continue; 298 continue;
299 299
300 x = xs_project(GET_X(i), curve->min_x, curve->max_x, width); 300 x = xs_project(GET_X(i), curve->min_x, curve->max_x, width);
301 y = xs_project(GET_Y(i), curve->min_y, curve->max_y, height); 301 y = xs_project(GET_Y(i), curve->min_y, curve->max_y, height);
302 302
303 if (i == curve->grab_point) { 303 if (i == curve->grab_point) {
304 cstate = GTK_STATE_SELECTED; 304 cstate = GTK_STATE_SELECTED;
305 gdk_draw_line(curve->pixmap, style->fg_gc[cstate], 305 gdk_draw_line(curve->pixmap, style->fg_gc[cstate],
306 x + RADIUS, RADIUS, x + RADIUS, height + RADIUS); 306 x + RADIUS, RADIUS, x + RADIUS, height + RADIUS);
307 gdk_draw_line(curve->pixmap, style->fg_gc[cstate], 307 gdk_draw_line(curve->pixmap, style->fg_gc[cstate],
308 RADIUS, y + RADIUS, width + RADIUS, y + RADIUS); 308 RADIUS, y + RADIUS, width + RADIUS, y + RADIUS);
309 } else 309 } else
310 cstate = state; 310 cstate = state;
311 311
312 gdk_draw_arc(curve->pixmap, style->fg_gc[cstate], TRUE, 312 gdk_draw_arc(curve->pixmap, style->fg_gc[cstate], TRUE,
313 x, y, RADIUS2, RADIUS2, 0, 360 * 64); 313 x, y, RADIUS2, RADIUS2, 0, 360 * 64);
314 } 314 }
315 315
316 /* Draw pixmap in the widget */ 316 /* Draw pixmap in the widget */
317 gdk_draw_pixmap(GTK_WIDGET(curve)->window, 317 gdk_draw_pixmap(GTK_WIDGET(curve)->window,
318 style->fg_gc[state], curve->pixmap, 318 style->fg_gc[state], curve->pixmap,
319 0, 0, 0, 0, 319 0, 0, 0, 0,
320 width + RADIUS2, 320 width + RADIUS2,
321 height + RADIUS2); 321 height + RADIUS2);
322 } 322 }
323 323
324 324
325 static gint xs_curve_graph_events(GtkWidget *widget, GdkEvent *event, XSCurve *curve) 325 static gint xs_curve_graph_events(GtkWidget *widget, GdkEvent *event, XSCurve *curve)
326 { 326 {
327 GdkCursorType new_type = curve->cursor_type; 327 GdkCursorType new_type = curve->cursor_type;
328 GdkEventButton *bevent; 328 GdkEventButton *bevent;
329 GtkWidget *w; 329 GtkWidget *w;
330 gint i, width, height, x, y, tx, ty, cx, closest_point = 0, min_x; 330 gint i, width, height, x, y, tx, ty, cx, closest_point = 0, min_x;
331 guint distance; 331 guint distance;
332 332
333 w = GTK_WIDGET(curve); 333 w = GTK_WIDGET(curve);
334 width = w->allocation.width - RADIUS2; 334 width = w->allocation.width - RADIUS2;
335 height = w->allocation.height - RADIUS2; 335 height = w->allocation.height - RADIUS2;
336 336
337 if ((width < 0) || (height < 0)) 337 if ((width < 0) || (height < 0))
338 return FALSE; 338 return FALSE;
339 339
340 /* get the pointer position */ 340 /* get the pointer position */
341 gdk_window_get_pointer(w->window, &tx, &ty, NULL); 341 gdk_window_get_pointer(w->window, &tx, &ty, NULL);
342 x = CLAMP((tx - RADIUS), 0, width - 1); 342 x = CLAMP((tx - RADIUS), 0, width - 1);
343 y = CLAMP((ty - RADIUS), 0, height - 1); 343 y = CLAMP((ty - RADIUS), 0, height - 1);
344 min_x = curve->min_x; 344 min_x = curve->min_x;
345 345
346 distance = ~0U; 346 distance = ~0U;
347 for (i = 0; i < curve->nctlpoints; ++i) { 347 for (i = 0; i < curve->nctlpoints; ++i) {
348 cx = xs_project(GET_X(i), min_x, curve->max_x, width); 348 cx = xs_project(GET_X(i), min_x, curve->max_x, width);
349 if ((guint) abs(x - cx) < distance) { 349 if ((guint) abs(x - cx) < distance) {
350 distance = abs(x - cx); 350 distance = abs(x - cx);
351 closest_point = i; 351 closest_point = i;
352 } 352 }
353 } 353 }
354 354
355 /* Act based on event type */ 355 /* Act based on event type */
356 switch (event->type) { 356 switch (event->type) {
357 case GDK_CONFIGURE: 357 case GDK_CONFIGURE:
358 if (curve->pixmap) 358 if (curve->pixmap)
359 gdk_pixmap_unref(curve->pixmap); 359 gdk_pixmap_unref(curve->pixmap);
360 curve->pixmap = 0; 360 curve->pixmap = 0;
361 361
362 /* fall through */ 362 /* fall through */
363 363
364 case GDK_EXPOSE: 364 case GDK_EXPOSE:
365 if (!curve->pixmap) { 365 if (!curve->pixmap) {
366 curve->pixmap = gdk_pixmap_new(w->window, 366 curve->pixmap = gdk_pixmap_new(w->window,
367 w->allocation.width, w->allocation.height, -1); 367 w->allocation.width, w->allocation.height, -1);
368 } 368 }
369 xs_curve_draw(curve, width, height); 369 xs_curve_draw(curve, width, height);
370 break; 370 break;
371 371
372 case GDK_BUTTON_PRESS: 372 case GDK_BUTTON_PRESS:
373 gtk_grab_add(widget); 373 gtk_grab_add(widget);
374 374
375 bevent = (GdkEventButton *) event; 375 bevent = (GdkEventButton *) event;
376 new_type = GDK_TCROSS; 376 new_type = GDK_TCROSS;
377 377
378 if (distance > MIN_DISTANCE) { 378 if (distance > MIN_DISTANCE) {
379 /* insert a new control point */ 379 /* insert a new control point */
380 if (curve->nctlpoints > 0) { 380 if (curve->nctlpoints > 0) {
381 cx = xs_project(GET_X(closest_point), min_x, curve->max_x, width); 381 cx = xs_project(GET_X(closest_point), min_x, curve->max_x, width);
382 if (x > cx) closest_point++; 382 if (x > cx) closest_point++;
383 } 383 }
384 384
385 curve->nctlpoints++; 385 curve->nctlpoints++;
386 386
387 curve->ctlpoints = g_realloc(curve->ctlpoints, 387 curve->ctlpoints = g_realloc(curve->ctlpoints,
388 curve->nctlpoints * sizeof(*curve->ctlpoints)); 388 curve->nctlpoints * sizeof(*curve->ctlpoints));
389 389
390 for (i = curve->nctlpoints - 1; i > closest_point; --i) { 390 for (i = curve->nctlpoints - 1; i > closest_point; --i) {
391 memcpy(curve->ctlpoints + i, 391 memcpy(curve->ctlpoints + i,
392 curve->ctlpoints + i - 1, 392 curve->ctlpoints + i - 1,
393 sizeof(*curve->ctlpoints)); 393 sizeof(*curve->ctlpoints));
394 } 394 }
395 } 395 }
396 396
397 curve->grab_point = closest_point; 397 curve->grab_point = closest_point;
398 GET_X(curve->grab_point) = xs_unproject(x, min_x, curve->max_x, width); 398 GET_X(curve->grab_point) = xs_unproject(x, min_x, curve->max_x, width);
399 GET_Y(curve->grab_point) = xs_unproject(y, curve->min_y, curve->max_y, height); 399 GET_Y(curve->grab_point) = xs_unproject(y, curve->min_y, curve->max_y, height);
400 400
401 xs_curve_draw(curve, width, height); 401 xs_curve_draw(curve, width, height);
402 break; 402 break;
403 403
404 case GDK_BUTTON_RELEASE: 404 case GDK_BUTTON_RELEASE:
405 { 405 {
406 gint src, dst; 406 gint src, dst;
407 407
408 gtk_grab_remove(widget); 408 gtk_grab_remove(widget);
409 409
410 /* delete inactive points: */ 410 /* delete inactive points: */
411 for (src = dst = 0; src < curve->nctlpoints; ++src) { 411 for (src = dst = 0; src < curve->nctlpoints; ++src) {
412 if (GET_X(src) >= min_x) { 412 if (GET_X(src) >= min_x) {
413 memcpy(curve->ctlpoints + dst, 413 memcpy(curve->ctlpoints + dst,
414 curve->ctlpoints + src, 414 curve->ctlpoints + src,
415 sizeof(*curve->ctlpoints)); 415 sizeof(*curve->ctlpoints));
416 dst++; 416 dst++;
417 } 417 }
418 } 418 }
419 419
420 if (dst < src) { 420 if (dst < src) {
421 curve->nctlpoints -= (src - dst); 421 curve->nctlpoints -= (src - dst);
422 if (curve->nctlpoints <= 0) { 422 if (curve->nctlpoints <= 0) {
423 curve->nctlpoints = 1; 423 curve->nctlpoints = 1;
424 GET_X(0) = min_x; 424 GET_X(0) = min_x;
425 GET_Y(0) = curve->min_y; 425 GET_Y(0) = curve->min_y;
426 xs_curve_draw(curve, width, height); 426 xs_curve_draw(curve, width, height);
427 } 427 }
428 curve->ctlpoints = g_realloc(curve->ctlpoints, 428 curve->ctlpoints = g_realloc(curve->ctlpoints,
429 curve->nctlpoints * sizeof(*curve->ctlpoints)); 429 curve->nctlpoints * sizeof(*curve->ctlpoints));
430 } 430 }
431 431
432 new_type = GDK_FLEUR; 432 new_type = GDK_FLEUR;
433 curve->grab_point = -1; 433 curve->grab_point = -1;
434 } 434 }
435 xs_curve_draw(curve, width, height); 435 xs_curve_draw(curve, width, height);
436 break; 436 break;
437 437
438 case GDK_MOTION_NOTIFY: 438 case GDK_MOTION_NOTIFY:
439 if (curve->grab_point == -1) { 439 if (curve->grab_point == -1) {
440 /* if no point is grabbed... */ 440 /* if no point is grabbed... */
441 if (distance <= MIN_DISTANCE) 441 if (distance <= MIN_DISTANCE)
442 new_type = GDK_FLEUR; 442 new_type = GDK_FLEUR;
443 else 443 else
444 new_type = GDK_TCROSS; 444 new_type = GDK_TCROSS;
445 } else { 445 } else {
446 gint leftbound, rightbound; 446 gint leftbound, rightbound;
447 447
448 /* drag the grabbed point */ 448 /* drag the grabbed point */
449 new_type = GDK_TCROSS; 449 new_type = GDK_TCROSS;
450 450
451 leftbound = -MIN_DISTANCE; 451 leftbound = -MIN_DISTANCE;
452 if (curve->grab_point > 0) { 452 if (curve->grab_point > 0) {
453 leftbound = xs_project( 453 leftbound = xs_project(
454 GET_X(curve->grab_point-1), 454 GET_X(curve->grab_point-1),
455 min_x, curve->max_x, width); 455 min_x, curve->max_x, width);
456 } 456 }
457 457
458 rightbound = width + RADIUS2 + MIN_DISTANCE; 458 rightbound = width + RADIUS2 + MIN_DISTANCE;
459 if (curve->grab_point + 1 < curve->nctlpoints) { 459 if (curve->grab_point + 1 < curve->nctlpoints) {
460 rightbound = xs_project( 460 rightbound = xs_project(
461 GET_X(curve->grab_point+1), 461 GET_X(curve->grab_point+1),
462 min_x, curve->max_x, width); 462 min_x, curve->max_x, width);
463 } 463 }
464 464
465 if ((tx <= leftbound) || (tx >= rightbound) || 465 if ((tx <= leftbound) || (tx >= rightbound) ||
466 (ty > height + RADIUS2 + MIN_DISTANCE) || (ty < -MIN_DISTANCE)) { 466 (ty > height + RADIUS2 + MIN_DISTANCE) || (ty < -MIN_DISTANCE)) {
467 GET_X(curve->grab_point) = min_x - 1.0; 467 GET_X(curve->grab_point) = min_x - 1.0;
468 } else { 468 } else {
469 GET_X(curve->grab_point) = 469 GET_X(curve->grab_point) =
470 xs_unproject(x, min_x, curve->max_x, width); 470 xs_unproject(x, min_x, curve->max_x, width);
471 GET_Y(curve->grab_point) = 471 GET_Y(curve->grab_point) =
472 xs_unproject(y, curve->min_y, curve->max_y, height); 472 xs_unproject(y, curve->min_y, curve->max_y, height);
473 } 473 }
474 474
475 xs_curve_draw(curve, width, height); 475 xs_curve_draw(curve, width, height);
476 } 476 }
477 477
478 /* See if cursor type was changed and update accordingly */ 478 /* See if cursor type was changed and update accordingly */
479 if (new_type != (GdkCursorType) curve->cursor_type) { 479 if (new_type != (GdkCursorType) curve->cursor_type) {
480 GdkCursor *cursor; 480 GdkCursor *cursor;
481 curve->cursor_type = new_type; 481 curve->cursor_type = new_type;
482 cursor = gdk_cursor_new(curve->cursor_type); 482 cursor = gdk_cursor_new(curve->cursor_type);
483 gdk_window_set_cursor(w->window, cursor); 483 gdk_window_set_cursor(w->window, cursor);
484 gdk_cursor_destroy(cursor); 484 gdk_cursor_destroy(cursor);
485 } 485 }
486 break; 486 break;
487 487
488 default: 488 default:
489 break; 489 break;
490 } 490 }
491 491
492 return FALSE; 492 return FALSE;
493 } 493 }
494 494
495 495
496 static void xs_curve_size_graph(XSCurve *curve) 496 static void xs_curve_size_graph(XSCurve *curve)
497 { 497 {
498 gint width, height; 498 gint width, height;
499 gfloat aspect; 499 gfloat aspect;
500 500
501 width = (curve->max_x - curve->min_x) + 1; 501 width = (curve->max_x - curve->min_x) + 1;
502 height = (curve->max_y - curve->min_y) + 1; 502 height = (curve->max_y - curve->min_y) + 1;
503 aspect = width / (gfloat) height; 503 aspect = width / (gfloat) height;
504 504
505 if (width > gdk_screen_width() / 4) 505 if (width > gdk_screen_width() / 4)
506 width = gdk_screen_width() / 4; 506 width = gdk_screen_width() / 4;
507 507
508 if (height > gdk_screen_height() / 4) 508 if (height > gdk_screen_height() / 4)
509 height = gdk_screen_height() / 4; 509 height = gdk_screen_height() / 4;
510 510
511 if (aspect < 1.0) 511 if (aspect < 1.0)
512 width = height * aspect; 512 width = height * aspect;
513 else 513 else
514 height = width / aspect; 514 height = width / aspect;
515 515
516 gtk_drawing_area_size(GTK_DRAWING_AREA(curve), width + RADIUS2, height + RADIUS2); 516 gtk_drawing_area_size(GTK_DRAWING_AREA(curve), width + RADIUS2, height + RADIUS2);
517 } 517 }
518 518
519 519
520 static void xs_curve_update(XSCurve *curve) 520 static void xs_curve_update(XSCurve *curve)
521 { 521 {
522 if (curve->pixmap) { 522 if (curve->pixmap) {
523 gint width, height; 523 gint width, height;
524 524
525 width = GTK_WIDGET(curve)->allocation.width - RADIUS2; 525 width = GTK_WIDGET(curve)->allocation.width - RADIUS2;
526 height = GTK_WIDGET(curve)->allocation.height - RADIUS2; 526 height = GTK_WIDGET(curve)->allocation.height - RADIUS2;
527 xs_curve_draw(curve, width, height); 527 xs_curve_draw(curve, width, height);
528 } 528 }
529 } 529 }
530 530
531 531
532 void xs_curve_reset(XSCurve *curve) 532 void xs_curve_reset(XSCurve *curve)
533 { 533 {
534 if (curve->ctlpoints) 534 if (curve->ctlpoints)
535 g_free(curve->ctlpoints); 535 g_free(curve->ctlpoints);
536 536
537 curve->nctlpoints = 4; 537 curve->nctlpoints = 4;
538 curve->ctlpoints = g_malloc(curve->nctlpoints * sizeof(curve->ctlpoints[0])); 538 curve->ctlpoints = g_malloc(curve->nctlpoints * sizeof(curve->ctlpoints[0]));
539 539
540 GET_X(0) = curve->min_x; 540 GET_X(0) = curve->min_x;
541 GET_Y(0) = curve->min_y; 541 GET_Y(0) = curve->min_y;
542 GET_X(1) = curve->min_x; 542 GET_X(1) = curve->min_x;
543 GET_Y(1) = curve->min_y; 543 GET_Y(1) = curve->min_y;
544 544
545 GET_X(2) = curve->max_x; 545 GET_X(2) = curve->max_x;
546 GET_Y(2) = curve->max_y; 546 GET_Y(2) = curve->max_y;
547 GET_X(3) = curve->max_x; 547 GET_X(3) = curve->max_x;
548 GET_Y(3) = curve->max_y; 548 GET_Y(3) = curve->max_y;
549 549
550 xs_curve_update(curve); 550 xs_curve_update(curve);
551 } 551 }
552 552
553 553
554 void xs_curve_set_range(XSCurve *curve, gfloat min_x, gfloat min_y, gfloat max_x, gfloat max_y) 554 void xs_curve_set_range(XSCurve *curve, gfloat min_x, gfloat min_y, gfloat max_x, gfloat max_y)
555 { 555 {
556 curve->min_x = min_x; 556 curve->min_x = min_x;
557 curve->max_x = max_x; 557 curve->max_x = max_x;
558 558
559 curve->min_y = min_y; 559 curve->min_y = min_y;
560 curve->max_y = max_y; 560 curve->max_y = max_y;
561 561
562 xs_curve_size_graph(curve); 562 xs_curve_size_graph(curve);
563 xs_curve_reset(curve); 563 xs_curve_reset(curve);
564 } 564 }
565 565
566 566
567 gboolean xs_curve_realloc_data(XSCurve *curve, gint npoints) 567 gboolean xs_curve_realloc_data(XSCurve *curve, gint npoints)
568 { 568 {
569 if (npoints != curve->nctlpoints) { 569 if (npoints != curve->nctlpoints) {
570 curve->nctlpoints = npoints; 570 curve->nctlpoints = npoints;
571 curve->ctlpoints = (t_xs_point *) g_realloc(curve->ctlpoints, 571 curve->ctlpoints = (t_xs_point *) g_realloc(curve->ctlpoints,
572 curve->nctlpoints * sizeof(*curve->ctlpoints)); 572 curve->nctlpoints * sizeof(*curve->ctlpoints));
573 573
574 if (curve->ctlpoints == NULL) 574 if (curve->ctlpoints == NULL)
575 return FALSE; 575 return FALSE;
576 } 576 }
577 577
578 return TRUE; 578 return TRUE;
579 } 579 }
580 580
581 581
582 void xs_curve_get_data(XSCurve *curve, t_xs_point ***points, gint **npoints) 582 void xs_curve_get_data(XSCurve *curve, t_xs_point ***points, gint **npoints)
583 { 583 {
584 *points = &(curve->ctlpoints); 584 *points = &(curve->ctlpoints);
585 *npoints = &(curve->nctlpoints); 585 *npoints = &(curve->nctlpoints);
586 } 586 }
587 587
588 588
589 gboolean xs_curve_set_points(XSCurve *curve, t_xs_int_point *points, gint npoints) 589 gboolean xs_curve_set_points(XSCurve *curve, t_xs_int_point *points, gint npoints)
590 { 590 {
591 gint i; 591 gint i;
592 592
593 if (!xs_curve_realloc_data(curve, npoints + 4)) 593 if (!xs_curve_realloc_data(curve, npoints + 4))
594 return FALSE; 594 return FALSE;
595 595
596 GET_X(0) = curve->min_x; 596 GET_X(0) = curve->min_x;
597 GET_Y(0) = curve->min_y; 597 GET_Y(0) = curve->min_y;
598 GET_X(1) = curve->min_x; 598 GET_X(1) = curve->min_x;
599 GET_Y(1) = curve->min_y; 599 GET_Y(1) = curve->min_y;
600 600
601 for (i = 0; i < npoints; i++) { 601 for (i = 0; i < npoints; i++) {
602 GET_X(i+2) = points[i].x; 602 GET_X(i+2) = points[i].x;
603 GET_Y(i+2) = points[i].y; 603 GET_Y(i+2) = points[i].y;
604 } 604 }
605 605
606 GET_X(npoints+2) = curve->max_x; 606 GET_X(npoints+2) = curve->max_x;
607 GET_Y(npoints+2) = curve->max_y; 607 GET_Y(npoints+2) = curve->max_y;
608 GET_X(npoints+3) = curve->max_x; 608 GET_X(npoints+3) = curve->max_x;
609 GET_Y(npoints+3) = curve->max_y; 609 GET_Y(npoints+3) = curve->max_y;
610 610
611 xs_curve_update(curve); 611 xs_curve_update(curve);
612 return TRUE; 612 return TRUE;
613 } 613 }
614 614
615 615
616 gboolean xs_curve_get_points(XSCurve *curve, t_xs_int_point **points, gint *npoints) 616 gboolean xs_curve_get_points(XSCurve *curve, t_xs_int_point **points, gint *npoints)
617 { 617 {
618 gint i, n; 618 gint i, n;
619 619
620 n = curve->nctlpoints - 4; 620 n = curve->nctlpoints - 4;
621 621
622 *points = g_malloc(n * sizeof(t_xs_int_point)); 622 *points = g_malloc(n * sizeof(t_xs_int_point));
623 if (*points == NULL) 623 if (*points == NULL)
624 return FALSE; 624 return FALSE;
625 625
626 *npoints = n; 626 *npoints = n;
627 for (i = 2; i < curve->nctlpoints - 2; i++) { 627 for (i = 2; i < curve->nctlpoints - 2; i++) {
628 (*points)[i].x = GET_X(i); 628 (*points)[i].x = GET_X(i);
629 (*points)[i].y = GET_Y(i); 629 (*points)[i].y = GET_Y(i);
630 } 630 }
631 631
632 return TRUE; 632 return TRUE;
633 } 633 }
634 634
635 635
636 GtkWidget *xs_curve_new(void) 636 GtkWidget *xs_curve_new(void)
637 { 637 {
638 return gtk_type_new(xs_curve_get_type()); 638 return gtk_type_new(xs_curve_get_type());
639 } 639 }
640 640
641 641
642 static void xs_curve_finalize(GtkObject *object) 642 static void xs_curve_finalize(GtkObject *object)
643 { 643 {
644 XSCurve *curve; 644 XSCurve *curve;
645 645
646 g_return_if_fail(object != NULL); 646 g_return_if_fail(object != NULL);
647 g_return_if_fail(XS_IS_CURVE(object)); 647 g_return_if_fail(XS_IS_CURVE(object));
648 648
649 curve = XS_CURVE(object); 649 curve = XS_CURVE(object);
650 if (curve->pixmap) 650 if (curve->pixmap)
651 gdk_pixmap_unref(curve->pixmap); 651 gdk_pixmap_unref(curve->pixmap);
652 if (curve->ctlpoints) 652 if (curve->ctlpoints)
653 g_free(curve->ctlpoints); 653 g_free(curve->ctlpoints);
654 654
655 (*GTK_OBJECT_CLASS(parent_class)->finalize) (object); 655 (*GTK_OBJECT_CLASS(parent_class)->finalize) (object);
656 } 656 }