comparison src/xs_curve.c @ 545:425da926d310

Working on XSCurve widget implementation.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 23 Feb 2007 05:10:00 +0000
parents 81481e59e195
children b37c7f430c3f
comparison
equal deleted inserted replaced
544:260c286108e6 545:425da926d310
1 /*
2 *
3 *
4 *
5 */
1 #include <stdlib.h> 6 #include <stdlib.h>
2 #include <string.h> 7 #include <string.h>
3 #include <math.h> 8 #include <math.h>
4
5 #include <stdio.h> 9 #include <stdio.h>
6
7 #include "xs_curve.h" 10 #include "xs_curve.h"
8 #include <gtk/gtkdrawingarea.h> 11 #include <gtk/gtkdrawingarea.h>
9 #include <gtk/gtkmain.h> 12 #include <gtk/gtkmain.h>
10 #include <gtk/gtksignal.h> 13 #include <gtk/gtksignal.h>
11 14
12 15
13 #define RADIUS 3 /* radius of the control points */ 16 #define RADIUS 3 /* radius of the control points */
14 #define RADIUS2 (RADIUS * 2) 17 #define RADIUS2 (RADIUS * 2)
15 18 #define MIN_DISTANCE 7 /* min distance between control points */
16 #define MIN_DISTANCE 8 /* min distance between control points */ 19
17 20
18 #define GRAPH_MASK (GDK_EXPOSURE_MASK | \ 21 #define GRAPH_MASK (GDK_EXPOSURE_MASK | \
19 GDK_POINTER_MOTION_MASK | \ 22 GDK_POINTER_MOTION_MASK | \
20 GDK_POINTER_MOTION_HINT_MASK | \ 23 GDK_POINTER_MOTION_HINT_MASK | \
21 GDK_ENTER_NOTIFY_MASK | \ 24 GDK_ENTER_NOTIFY_MASK | \
27 #define GET_Y(i) curve->ctlpoints[i].y 30 #define GET_Y(i) curve->ctlpoints[i].y
28 31
29 32
30 enum { 33 enum {
31 ARG_0, 34 ARG_0,
32 ARG_CURVE_TYPE,
33 ARG_MIN_X, 35 ARG_MIN_X,
34 ARG_MAX_X, 36 ARG_MAX_X,
35 ARG_MIN_Y, 37 ARG_MIN_Y,
36 ARG_MAX_Y 38 ARG_MAX_Y
37 }; 39 };
94 96
95 curve->pixmap = NULL; 97 curve->pixmap = NULL;
96 curve->height = 0; 98 curve->height = 0;
97 curve->grab_point = -1; 99 curve->grab_point = -1;
98 100
99 curve->num_ctlpoints = 0; 101 curve->nctlpoints = 0;
100 curve->ctlpoints = NULL; 102 curve->ctlpoints = NULL;
101 103
102 curve->min_x = 0.0; 104 curve->min_x = 0.0;
103 curve->max_x = 2048.0; 105 curve->max_x = 2047.0;
104 curve->min_y = 0.0; 106 curve->min_y = 0.0;
105 curve->max_y = 22000.0; 107 curve->max_y = 24000.0;
106 108
107 old_mask = gtk_widget_get_events(GTK_WIDGET(curve)); 109 old_mask = gtk_widget_get_events(GTK_WIDGET(curve));
108 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK); 110 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK);
109 gtk_signal_connect(GTK_OBJECT(curve), "event", (GtkSignalFunc) xs_curve_graph_events, curve); 111 gtk_signal_connect(GTK_OBJECT(curve), "event", (GtkSignalFunc) xs_curve_graph_events, curve);
110 xs_curve_size_graph(curve); 112 xs_curve_size_graph(curve);
218 gdk_draw_line(curve->pixmap, style->dark_gc[state], 220 gdk_draw_line(curve->pixmap, style->dark_gc[state],
219 i * (width / 4.0) + RADIUS, RADIUS, 221 i * (width / 4.0) + RADIUS, RADIUS,
220 i * (width / 4.0) + RADIUS, height + RADIUS); 222 i * (width / 4.0) + RADIUS, height + RADIUS);
221 } 223 }
222 224
225 #define Qprintf(x,y,...)
223 226
224 #if 1 227 #if 1
225 /* Draw the spline/curve itself */ 228 /* Draw the spline/curve itself */
226 p0 = curve->ctlpoints; 229 p0 = curve->ctlpoints;
227 p1 = p0; 230 p1 = p0;
228 p2 = p1; p2++; 231 p2 = p1; p2++;
229 p3 = p2; p3++; 232 p3 = p2; p3++;
230 233
231 /* Draw each curve segment */ 234 /* Draw each curve segment */
232 fprintf(stderr, "-- npoints = %d\n", curve->num_ctlpoints); 235 Qprintf(stderr, "-- npoints = %d\n", curve->nctlpoints);
233 if (curve->num_ctlpoints > 5) 236 if (curve->nctlpoints > 5)
234 for (i = 0; i < curve->num_ctlpoints; i++, ++p0, ++p1, ++p2, ++p3) { 237 for (i = 0; i < curve->nctlpoints; i++, ++p0, ++p1, ++p2, ++p3) {
235 gfloat k1, k2, a, b, c, d, x; 238 gfloat k1, k2, a, b, c, d, x;
236 fprintf(stderr, "#%d: ", i); 239
240 Qprintf(stderr, "#%d: ", i);
237 if (p1->x == p2->x) 241 if (p1->x == p2->x)
238 continue; 242 continue;
239 #define PPASK(q, p) fprintf(stderr, q "=[%1.3f, %1.3f] ", p->x, p->y) 243 #define PPASK(q, p) Qprintf(stderr, q "=[%1.3f, %1.3f] ", p->x, p->y)
240 244
241 PPASK("p0", p1); 245 PPASK("p0", p1);
242 PPASK("p1", p1); 246 PPASK("p1", p1);
243 PPASK("p2", p2); 247 PPASK("p2", p2);
244 PPASK("p3", p3); 248 PPASK("p3", p3);
245 249
246 fprintf(stderr, "\ncase #"); 250 Qprintf(stderr, "\ncase #");
247 if (p0->x == p1->x && p2->x == p3->x) { 251 if (p0->x == p1->x && p2->x == p3->x) {
248 fprintf(stderr, "1"); 252 Qprintf(stderr, "1");
249 k1 = k2 = (p2->y - p1->y) / (p2->x - p1->x); 253 k1 = k2 = (p2->y - p1->y) / (p2->x - p1->x);
250 } else if (p0->x == p1->x) { 254 } else if (p0->x == p1->x) {
251 fprintf(stderr, "2"); 255 Qprintf(stderr, "2");
252 k2 = (p3->y - p1->y) / (p3->x - p1->x); 256 k2 = (p3->y - p1->y) / (p3->x - p1->x);
253 k1 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k2) / 2; 257 k1 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k2) / 2;
254 } else if (p2->x == p3->x) { 258 } else if (p2->x == p3->x) {
255 fprintf(stderr, "3"); 259 Qprintf(stderr, "3");
256 k1 = (p2->y - p0->y) / (p2->x - p0->x); 260 k1 = (p2->y - p0->y) / (p2->x - p0->x);
257 k2 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k1) / 2; 261 k2 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k1) / 2;
258 } else { 262 } else {
259 fprintf(stderr, "4"); 263 Qprintf(stderr, "4");
260 k1 = (p2->y - p0->y) / (p2->x - p0->x); 264 k1 = (p2->y - p0->y) / (p2->x - p0->x);
261 k2 = (p3->y - p1->y) / (p3->x - p1->x); 265 k2 = (p3->y - p1->y) / (p3->x - p1->x);
262 } 266 }
263 267
264 xs_cubic_coeff(p1->x, p1->y, p2->x, p2->y, k1, k2, &a, &b, &c, &d); 268 xs_cubic_coeff(p1->x, p1->y, p2->x, p2->y, k1, k2, &a, &b, &c, &d);
265 fprintf(stderr, " seg[%1.3f, %1.3f] => [%1.3f, %1.3f] k1=%1.3f, k2=%1.3f\n\n", 269
270 Qprintf(stderr, " seg[%1.3f, %1.3f] => [%1.3f, %1.3f] k1=%1.3f, k2=%1.3f\n\n",
266 p1->x, p1->y, 271 p1->x, p1->y,
267 p2->x, p2->y, 272 p2->x, p2->y,
268 k1, k2); 273 k1, k2);
269 #if 1 274
270 for (x = p1->x; x <= p2->x; x += res) { 275 for (x = p1->x; x <= p2->x; x += res) {
271 gfloat y = ((a * x + b) * x + c) * x + d; 276 gfloat y = ((a * x + b) * x + c) * x + d;
272 gint qx, qy; 277 gint qx, qy;
273 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);
274 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);
276 gdk_draw_point(curve->pixmap, style->fg_gc[state], 281 gdk_draw_point(curve->pixmap, style->fg_gc[state],
277 RADIUS + xs_project(x, curve->min_x, curve->max_x, width), 282 RADIUS + xs_project(x, curve->min_x, curve->max_x, width),
278 RADIUS + xs_project(y, curve->min_y, curve->max_y, height)); 283 RADIUS + xs_project(y, curve->min_y, curve->max_y, height));
279 284
280 } 285 }
286 }
287
288 Qprintf(stderr, "-------\n");
281 #endif 289 #endif
282 }
283 fprintf(stderr, "-------\n");
284 #endif
285 290
286 /* Draw control points */ 291 /* Draw control points */
287 for (i = 0; i < curve->num_ctlpoints; ++i) { 292 for (i = 0; i < curve->nctlpoints; ++i) {
288 gint x, y; 293 gint x, y;
289 294
290 if (GET_X(i) < curve->min_x || GET_Y(i) < curve->min_y || 295 if (GET_X(i) < curve->min_x || GET_Y(i) < curve->min_y ||
291 GET_X(i) >= curve->max_x || GET_Y(i) >= curve->max_y) 296 GET_X(i) >= curve->max_x || GET_Y(i) >= curve->max_y)
292 continue; 297 continue;
309 314
310 static gint xs_curve_graph_events(GtkWidget *widget, GdkEvent *event, XSCurve *curve) 315 static gint xs_curve_graph_events(GtkWidget *widget, GdkEvent *event, XSCurve *curve)
311 { 316 {
312 GdkCursorType new_type = curve->cursor_type; 317 GdkCursorType new_type = curve->cursor_type;
313 GdkEventButton *bevent; 318 GdkEventButton *bevent;
314 GdkEventMotion *mevent;
315 GtkWidget *w; 319 GtkWidget *w;
316 gint i, width, height, x, y, tx, ty, cx, closest_point = 0, min_x; 320 gint i, width, height, x, y, tx, ty, cx, closest_point = 0, min_x;
317 guint distance; 321 guint distance;
318 322
319 w = GTK_WIDGET(curve); 323 w = GTK_WIDGET(curve);
325 329
326 /* get the pointer position */ 330 /* get the pointer position */
327 gdk_window_get_pointer(w->window, &tx, &ty, NULL); 331 gdk_window_get_pointer(w->window, &tx, &ty, NULL);
328 x = CLAMP((tx - RADIUS), 0, width - 1); 332 x = CLAMP((tx - RADIUS), 0, width - 1);
329 y = CLAMP((ty - RADIUS), 0, height - 1); 333 y = CLAMP((ty - RADIUS), 0, height - 1);
330
331 min_x = curve->min_x; 334 min_x = curve->min_x;
332 335
333 distance = ~0U; 336 distance = ~0U;
334 for (i = 0; i < curve->num_ctlpoints; ++i) { 337 for (i = 0; i < curve->nctlpoints; ++i) {
335 cx = xs_project(GET_X(i), min_x, curve->max_x, width); 338 cx = xs_project(GET_X(i), min_x, curve->max_x, width);
336 if ((guint) abs(x - cx) < distance) { 339 if ((guint) abs(x - cx) < distance) {
337 distance = abs(x - cx); 340 distance = abs(x - cx);
338 closest_point = i; 341 closest_point = i;
339 } 342 }
362 bevent = (GdkEventButton *) event; 365 bevent = (GdkEventButton *) event;
363 new_type = GDK_TCROSS; 366 new_type = GDK_TCROSS;
364 367
365 if (distance > MIN_DISTANCE) { 368 if (distance > MIN_DISTANCE) {
366 /* insert a new control point */ 369 /* insert a new control point */
367 if (curve->num_ctlpoints > 0) { 370 if (curve->nctlpoints > 0) {
368 cx = xs_project(GET_X(closest_point), min_x, curve->max_x, width); 371 cx = xs_project(GET_X(closest_point), min_x, curve->max_x, width);
369 if (x > cx) closest_point++; 372 if (x > cx) closest_point++;
370 } 373 }
371 374
372 curve->num_ctlpoints++; 375 curve->nctlpoints++;
373 376
374 curve->ctlpoints = g_realloc(curve->ctlpoints, curve->num_ctlpoints * sizeof(*curve->ctlpoints)); 377 curve->ctlpoints = g_realloc(curve->ctlpoints,
375 for (i = curve->num_ctlpoints - 1; i > closest_point; --i) { 378 curve->nctlpoints * sizeof(*curve->ctlpoints));
376 memcpy(curve->ctlpoints + i, curve->ctlpoints + i - 1, sizeof(*curve->ctlpoints)); 379
380 for (i = curve->nctlpoints - 1; i > closest_point; --i) {
381 memcpy(curve->ctlpoints + i,
382 curve->ctlpoints + i - 1,
383 sizeof(*curve->ctlpoints));
377 } 384 }
378 } 385 }
379 386
380 curve->grab_point = closest_point; 387 curve->grab_point = closest_point;
381 GET_X(curve->grab_point) = xs_unproject(x, min_x, curve->max_x, width); 388 GET_X(curve->grab_point) = xs_unproject(x, min_x, curve->max_x, width);
389 gint src, dst; 396 gint src, dst;
390 397
391 gtk_grab_remove(widget); 398 gtk_grab_remove(widget);
392 399
393 /* delete inactive points: */ 400 /* delete inactive points: */
394 for (src = dst = 0; src < curve->num_ctlpoints; ++src) 401 for (src = dst = 0; src < curve->nctlpoints; ++src) {
395 if (GET_X(src) >= min_x) { 402 if (GET_X(src) >= min_x) {
396 memcpy(curve->ctlpoints + dst, curve->ctlpoints + src, sizeof(*curve->ctlpoints)); 403 memcpy(curve->ctlpoints + dst,
397 dst++; 404 curve->ctlpoints + src,
405 sizeof(*curve->ctlpoints));
406 dst++;
407 }
398 } 408 }
399 409
400 if (dst < src) { 410 if (dst < src) {
401 curve->num_ctlpoints -= (src - dst); 411 curve->nctlpoints -= (src - dst);
402 if (curve->num_ctlpoints <= 0) { 412 if (curve->nctlpoints <= 0) {
403 curve->num_ctlpoints = 1; 413 curve->nctlpoints = 1;
404 GET_X(0) = min_x; 414 GET_X(0) = min_x;
405 GET_Y(0) = curve->min_y; 415 GET_Y(0) = curve->min_y;
406 xs_curve_draw(curve, width, height); 416 xs_curve_draw(curve, width, height);
407 } 417 }
408 curve->ctlpoints = g_realloc(curve->ctlpoints, curve->num_ctlpoints * sizeof(*curve->ctlpoints)); 418 curve->ctlpoints = g_realloc(curve->ctlpoints,
419 curve->nctlpoints * sizeof(*curve->ctlpoints));
409 } 420 }
410 421
411 new_type = GDK_FLEUR; 422 new_type = GDK_FLEUR;
412 curve->grab_point = -1; 423 curve->grab_point = -1;
413 } 424 }
414 break; 425 break;
415 426
416 case GDK_MOTION_NOTIFY: 427 case GDK_MOTION_NOTIFY:
417 mevent = (GdkEventMotion *) event;
418
419 if (curve->grab_point == -1) { 428 if (curve->grab_point == -1) {
420 /* if no point is grabbed... */ 429 /* if no point is grabbed... */
421 if (distance <= MIN_DISTANCE) 430 if (distance <= MIN_DISTANCE)
422 new_type = GDK_FLEUR; 431 new_type = GDK_FLEUR;
423 else 432 else
434 GET_X(curve->grab_point-1), 443 GET_X(curve->grab_point-1),
435 min_x, curve->max_x, width); 444 min_x, curve->max_x, width);
436 } 445 }
437 446
438 rightbound = width + RADIUS2 + MIN_DISTANCE; 447 rightbound = width + RADIUS2 + MIN_DISTANCE;
439 if (curve->grab_point + 1 < curve->num_ctlpoints) { 448 if (curve->grab_point + 1 < curve->nctlpoints) {
440 rightbound = xs_project( 449 rightbound = xs_project(
441 GET_X(curve->grab_point+1), 450 GET_X(curve->grab_point+1),
442 min_x, curve->max_x, width); 451 min_x, curve->max_x, width);
443 } 452 }
444 453
452 xs_unproject(y, curve->min_y, curve->max_y, height); 461 xs_unproject(y, curve->min_y, curve->max_y, height);
453 } 462 }
454 463
455 xs_curve_draw(curve, width, height); 464 xs_curve_draw(curve, width, height);
456 } 465 }
457 466
467 /* See if cursor type was changed and update accordingly */
458 if (new_type != (GdkCursorType) curve->cursor_type) { 468 if (new_type != (GdkCursorType) curve->cursor_type) {
459 GdkCursor *cursor; 469 GdkCursor *cursor;
460
461 curve->cursor_type = new_type; 470 curve->cursor_type = new_type;
462
463 cursor = gdk_cursor_new(curve->cursor_type); 471 cursor = gdk_cursor_new(curve->cursor_type);
464 gdk_window_set_cursor(w->window, cursor); 472 gdk_window_set_cursor(w->window, cursor);
465 gdk_cursor_destroy(cursor); 473 gdk_cursor_destroy(cursor);
466 } 474 }
467 break; 475 break;
496 504
497 gtk_drawing_area_size(GTK_DRAWING_AREA(curve), width + RADIUS2, height + RADIUS2); 505 gtk_drawing_area_size(GTK_DRAWING_AREA(curve), width + RADIUS2, height + RADIUS2);
498 } 506 }
499 507
500 508
501 void xs_curve_reset(XSCurve *curve) 509 static void xs_curve_update(XSCurve *curve)
502 { 510 {
503 if (curve->ctlpoints)
504 g_free(curve->ctlpoints);
505
506 curve->num_ctlpoints = 4;
507 curve->ctlpoints = g_malloc(curve->num_ctlpoints * sizeof(curve->ctlpoints[0]));
508
509 GET_X(0) = curve->min_x;
510 GET_Y(0) = curve->min_y;
511
512 GET_X(1) = curve->min_x;
513 GET_Y(1) = curve->min_y;
514
515 GET_X(2) = curve->max_x;
516 GET_Y(2) = curve->max_y;
517
518 GET_X(3) = curve->max_x;
519 GET_Y(3) = curve->max_y;
520
521 if (curve->pixmap) { 511 if (curve->pixmap) {
522 gint width, height; 512 gint width, height;
523 513
524 width = GTK_WIDGET(curve)->allocation.width - RADIUS2; 514 width = GTK_WIDGET(curve)->allocation.width - RADIUS2;
525 height = GTK_WIDGET(curve)->allocation.height - RADIUS2; 515 height = GTK_WIDGET(curve)->allocation.height - RADIUS2;
526 xs_curve_draw(curve, width, height); 516 xs_curve_draw(curve, width, height);
527 } 517 }
528 } 518 }
529 519
530 520
531 void xs_curve_set_range(XSCurve *curve, gfloat min_x, gfloat max_x, gfloat min_y, gfloat max_y) 521 void xs_curve_reset(XSCurve *curve)
522 {
523 if (curve->ctlpoints)
524 g_free(curve->ctlpoints);
525
526 curve->nctlpoints = 4;
527 curve->ctlpoints = g_malloc(curve->nctlpoints * sizeof(curve->ctlpoints[0]));
528
529 GET_X(0) = curve->min_x;
530 GET_Y(0) = curve->min_y;
531 GET_X(1) = curve->min_x;
532 GET_Y(1) = curve->min_y;
533
534 GET_X(2) = curve->max_x;
535 GET_Y(2) = curve->max_y;
536 GET_X(3) = curve->max_x;
537 GET_Y(3) = curve->max_y;
538
539 xs_curve_update(curve);
540 }
541
542
543 void xs_curve_set_range(XSCurve *curve, gfloat min_x, gfloat min_y, gfloat max_x, gfloat max_y)
532 { 544 {
533 curve->min_x = min_x; 545 curve->min_x = min_x;
534 curve->max_x = max_x; 546 curve->max_x = max_x;
547
535 curve->min_y = min_y; 548 curve->min_y = min_y;
536 curve->max_y = max_y; 549 curve->max_y = max_y;
537 550
538 xs_curve_size_graph(curve); 551 xs_curve_size_graph(curve);
539 xs_curve_reset(curve); 552 xs_curve_reset(curve);
540 } 553 }
541 554
542 555
556 gboolean xs_curve_realloc_data(XSCurve *curve, gint npoints)
557 {
558 if (npoints != curve->nctlpoints) {
559 curve->nctlpoints = npoints;
560 curve->ctlpoints = (t_xs_point *) g_realloc(curve->ctlpoints,
561 curve->nctlpoints * sizeof(*curve->ctlpoints));
562
563 if (curve->ctlpoints == NULL)
564 return FALSE;
565 }
566
567 return TRUE;
568 }
569
570
571 void xs_curve_get_data(XSCurve *curve, t_xs_point ***points, gint **npoints)
572 {
573 *points = &(curve->ctlpoints);
574 *npoints = &(curve->nctlpoints);
575 }
576
577
578 gboolean xs_curve_set_points(XSCurve *curve, t_xs_int_point *points, gint npoints)
579 {
580 gint i;
581
582 if (!xs_curve_realloc_data(curve, npoints + 4))
583 return FALSE;
584
585 GET_X(0) = curve->min_x;
586 GET_Y(0) = curve->min_y;
587 GET_X(1) = curve->min_x;
588 GET_Y(1) = curve->min_y;
589
590 for (i = 0; i < npoints; i++) {
591 GET_X(i+2) = points[i].x;
592 GET_Y(i+2) = points[i].y;
593 }
594
595 GET_X(npoints+2) = curve->max_x;
596 GET_Y(npoints+2) = curve->max_y;
597 GET_X(npoints+3) = curve->max_x;
598 GET_Y(npoints+3) = curve->max_y;
599
600 xs_curve_update(curve);
601 return TRUE;
602 }
603
604
605 gboolean xs_curve_get_points(XSCurve *curve, t_xs_int_point **points, gint *npoints)
606 {
607 gint i, n;
608
609 n = curve->nctlpoints - 4;
610
611 *points = g_malloc(n * sizeof(t_xs_int_point));
612 if (*points == NULL)
613 return FALSE;
614
615 *npoints = n;
616 for (i = 2; i < curve->nctlpoints - 2; i++) {
617 (*points)[i].x = GET_X(i);
618 (*points)[i].y = GET_Y(i);
619 }
620
621 return TRUE;
622 }
623
624
543 GtkWidget *xs_curve_new(void) 625 GtkWidget *xs_curve_new(void)
544 { 626 {
545 return gtk_type_new(xs_curve_get_type()); 627 return gtk_type_new(xs_curve_get_type());
546 } 628 }
547 629
561 if (curve->ctlpoints) 643 if (curve->ctlpoints)
562 g_free(curve->ctlpoints); 644 g_free(curve->ctlpoints);
563 645
564 (*GTK_OBJECT_CLASS(parent_class)->finalize) (object); 646 (*GTK_OBJECT_CLASS(parent_class)->finalize) (object);
565 } 647 }
566