Mercurial > audlegacy-plugins
comparison src/sid/xs_curve.c @ 735:6c3c7b841382 trunk
[svn] - sync audacious-sid with latest xmms-sid, from Matti Hamalainen (ccr).
author | nenolod |
---|---|
date | Tue, 27 Feb 2007 01:40:23 -0800 |
parents | |
children | 64ded0b8f80e |
comparison
equal
deleted
inserted
replaced
734:ff62f5530a36 | 735:6c3c7b841382 |
---|---|
1 /* | |
2 XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS) | |
3 | |
4 XSCurve, a custom Gtk+ spline widget for representing SIDPlay2/reSID | |
5 filter curves in the configuration GUI. Implementation based heavily | |
6 on GtkCurve from Gtk+ 1.2.10 (C) 1997 David Mosberger. | |
7 Spline formula from reSID 0.16 (C) 2004 Dag Lem. | |
8 | |
9 Programmed by Matti 'ccr' Hamalainen <ccr@tnsp.org> | |
10 (C) Copyright 2006-2007 Tecnic Software productions (TNSP) | |
11 | |
12 This program is free software; you can redistribute it and/or modify | |
13 it under the terms of the GNU General Public License as published by | |
14 the Free Software Foundation; either version 2 of the License, or | |
15 (at your option) any later version. | |
16 | |
17 This program is distributed in the hope that it will be useful, | |
18 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 GNU General Public License for more details. | |
21 | |
22 You should have received a copy of the GNU General Public License along | |
23 with this program; if not, write to the Free Software Foundation, Inc., | |
24 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
25 */ | |
26 #include <stdlib.h> | |
27 #include <string.h> | |
28 #include <math.h> | |
29 #include <stdio.h> | |
30 #include "xs_curve.h" | |
31 #include <gtk/gtkdrawingarea.h> | |
32 #include <gtk/gtkmain.h> | |
33 #include <gtk/gtkprivate.h> | |
34 | |
35 | |
36 #define RADIUS 3 /* radius of the control points */ | |
37 #define RADIUS2 (RADIUS * 2) | |
38 #define MIN_DISTANCE 7 /* min distance between control points */ | |
39 | |
40 | |
41 #define GRAPH_MASK (GDK_EXPOSURE_MASK | \ | |
42 GDK_POINTER_MOTION_MASK | \ | |
43 GDK_POINTER_MOTION_HINT_MASK | \ | |
44 GDK_ENTER_NOTIFY_MASK | \ | |
45 GDK_BUTTON_PRESS_MASK | \ | |
46 GDK_BUTTON_RELEASE_MASK | \ | |
47 GDK_BUTTON1_MOTION_MASK) | |
48 | |
49 #define GET_X(i) curve->ctlpoints[i].x | |
50 #define GET_Y(i) curve->ctlpoints[i].y | |
51 | |
52 | |
53 enum { | |
54 PROP_0, | |
55 PROP_MIN_X, | |
56 PROP_MAX_X, | |
57 PROP_MIN_Y, | |
58 PROP_MAX_Y | |
59 }; | |
60 | |
61 static GtkDrawingAreaClass *parent_class = NULL; | |
62 | |
63 static void xs_curve_class_init(XSCurveClass * class); | |
64 static void xs_curve_init(XSCurve * curve); | |
65 static void xs_curve_get_property(GObject * object, guint param_id, | |
66 GValue * value, GParamSpec * pspec); | |
67 static void xs_curve_set_property(GObject * object, guint param_id, | |
68 const GValue * value, GParamSpec * pspec); | |
69 static void xs_curve_finalize(GObject * object); | |
70 static gint xs_curve_graph_events(GtkWidget * widget, GdkEvent * event, XSCurve * c); | |
71 static void xs_curve_size_graph(XSCurve * curve); | |
72 | |
73 | |
74 GtkType xs_curve_get_type(void) | |
75 { | |
76 static GType curve_type = 0; | |
77 | |
78 if (!curve_type) { | |
79 static const GTypeInfo curve_info = { | |
80 sizeof(XSCurveClass), | |
81 NULL, /* base_init */ | |
82 NULL, /* base_finalize */ | |
83 (GClassInitFunc) xs_curve_class_init, | |
84 NULL, /* class_finalize */ | |
85 NULL, /* class_data */ | |
86 sizeof(XSCurve), | |
87 0, /* n_preallocs */ | |
88 (GInstanceInitFunc) xs_curve_init, | |
89 }; | |
90 | |
91 curve_type = g_type_register_static( | |
92 GTK_TYPE_DRAWING_AREA, "XSCurve", | |
93 &curve_info, 0); | |
94 } | |
95 return curve_type; | |
96 } | |
97 | |
98 | |
99 static void xs_curve_class_init(XSCurveClass *class) | |
100 { | |
101 GObjectClass *gobject_class = G_OBJECT_CLASS(class); | |
102 | |
103 parent_class = g_type_class_peek_parent(class); | |
104 | |
105 gobject_class->finalize = xs_curve_finalize; | |
106 | |
107 gobject_class->set_property = xs_curve_set_property; | |
108 gobject_class->get_property = xs_curve_get_property; | |
109 | |
110 g_object_class_install_property(gobject_class, PROP_MIN_X, | |
111 g_param_spec_float("min-x", | |
112 "Minimum X", | |
113 "Minimum possible value for X", | |
114 -G_MAXFLOAT, G_MAXFLOAT, 0.0, | |
115 GTK_PARAM_READWRITE) | |
116 ); | |
117 | |
118 g_object_class_install_property(gobject_class, PROP_MAX_X, | |
119 g_param_spec_float("max-x", | |
120 "Maximum X", | |
121 "Maximum possible X value", | |
122 -G_MAXFLOAT, G_MAXFLOAT, 1.0, | |
123 GTK_PARAM_READWRITE) | |
124 ); | |
125 | |
126 g_object_class_install_property(gobject_class, PROP_MIN_Y, | |
127 g_param_spec_float("min-y", | |
128 "Minimum Y", | |
129 "Minimum possible value for Y", | |
130 -G_MAXFLOAT, G_MAXFLOAT, 0.0, | |
131 GTK_PARAM_READWRITE) | |
132 ); | |
133 | |
134 g_object_class_install_property(gobject_class, PROP_MAX_Y, | |
135 g_param_spec_float("max-y", | |
136 "Maximum Y", | |
137 "Maximum possible value for Y", | |
138 -G_MAXFLOAT, G_MAXFLOAT, 1.0, | |
139 GTK_PARAM_READWRITE) | |
140 ); | |
141 } | |
142 | |
143 | |
144 static void xs_curve_init(XSCurve *curve) | |
145 { | |
146 gint old_mask; | |
147 | |
148 curve->cursor_type = GDK_TOP_LEFT_ARROW; | |
149 curve->pixmap = NULL; | |
150 curve->height = 0; | |
151 curve->grab_point = -1; | |
152 | |
153 curve->nctlpoints = 0; | |
154 curve->ctlpoints = NULL; | |
155 | |
156 curve->min_x = 0.0; | |
157 curve->max_x = 1.0; | |
158 curve->min_y = 0.0; | |
159 curve->max_y = 1.0; | |
160 | |
161 old_mask = gtk_widget_get_events(GTK_WIDGET(curve)); | |
162 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK); | |
163 g_signal_connect(curve, "event", G_CALLBACK(xs_curve_graph_events), curve); | |
164 xs_curve_size_graph(curve); | |
165 } | |
166 | |
167 | |
168 static void xs_curve_set_property(GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) | |
169 { | |
170 XSCurve *curve = XS_CURVE(object); | |
171 | |
172 switch (prop_id) { | |
173 case PROP_MIN_X: | |
174 gtk_curve_set_range(curve, | |
175 g_value_get_float(value), curve->max_x, | |
176 curve->min_y, curve->max_y); | |
177 break; | |
178 case PROP_MAX_X: | |
179 gtk_curve_set_range(curve, | |
180 curve->min_x, g_value_get_float(value), | |
181 curve->min_y, curve->max_y); | |
182 break; | |
183 case PROP_MIN_Y: | |
184 gtk_curve_set_range(curve, | |
185 curve->min_x, curve->max_x, | |
186 g_value_get_float(value), curve->max_y); | |
187 break; | |
188 case PROP_MAX_Y: | |
189 gtk_curve_set_range(curve, | |
190 curve->min_x, curve->max_x, | |
191 curve->min_y, g_value_get_float(value)); | |
192 break; | |
193 default: | |
194 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); | |
195 break; | |
196 } | |
197 } | |
198 | |
199 | |
200 static void xs_curve_get_property(GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) | |
201 { | |
202 XSCurve *curve = XS_CURVE(object); | |
203 | |
204 switch (prop_id) { | |
205 case PROP_MIN_X: | |
206 g_value_set_float(value, curve->min_x); | |
207 break; | |
208 case PROP_MAX_X: | |
209 g_value_set_float(value, curve->max_x); | |
210 break; | |
211 case PROP_MIN_Y: | |
212 g_value_set_float(value, curve->min_y); | |
213 break; | |
214 case PROP_MAX_Y: | |
215 g_value_set_float(value, curve->max_y); | |
216 break; | |
217 default: | |
218 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); | |
219 break; | |
220 } | |
221 } | |
222 | |
223 | |
224 static int xs_project(gfloat value, gfloat min, gfloat max, int norm) | |
225 { | |
226 return (norm - 1) * ((value - min) / (max - min)) + 0.5; | |
227 } | |
228 | |
229 | |
230 static gfloat xs_unproject(gint value, gfloat min, gfloat max, int norm) | |
231 { | |
232 return value / (gfloat) (norm - 1) * (max - min) + min; | |
233 } | |
234 | |
235 | |
236 static inline void xs_cubic_coeff(gfloat x1, gfloat y1, | |
237 gfloat x2, gfloat y2, | |
238 gfloat k1, gfloat k2, | |
239 gfloat *a, gfloat *b, | |
240 gfloat *c, gfloat *d) | |
241 { | |
242 gfloat dx = x2 - x1, dy = y2 - y1; | |
243 | |
244 *a = ((k1 + k2) - 2 * dy / dx) / (dx * dx); | |
245 *b = ((k2 - k1) / dx - 3 * (x1 + x2) * (*a)) / 2; | |
246 *c = k1 - (3 * x1 * (*a) + 2 * (*b)) * x1; | |
247 *d = y1 - ((x1 * (*a) + (*b)) * x1 + (*c)) * x1; | |
248 } | |
249 | |
250 | |
251 static void xs_curve_draw(XSCurve *curve, gint width, gint height) | |
252 { | |
253 gfloat res = 10.0f; | |
254 GtkStateType state; | |
255 GtkStyle *style; | |
256 gint i; | |
257 t_xs_point *p0, *p1, *p2, *p3; | |
258 | |
259 if (!curve->pixmap) | |
260 return; | |
261 | |
262 state = GTK_STATE_NORMAL; | |
263 if (!GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(curve))) | |
264 state = GTK_STATE_INSENSITIVE; | |
265 | |
266 style = GTK_WIDGET(curve)->style; | |
267 | |
268 /* Clear the pixmap */ | |
269 gtk_paint_flat_box(style, curve->pixmap, | |
270 GTK_STATE_NORMAL, GTK_SHADOW_NONE, | |
271 NULL, GTK_WIDGET(curve), "curve_bg", | |
272 0, 0, | |
273 width + RADIUS2, | |
274 height + RADIUS2); | |
275 | |
276 | |
277 /* Draw the grid */ | |
278 for (i = 0; i < 5; i++) { | |
279 gdk_draw_line(curve->pixmap, style->dark_gc[state], | |
280 RADIUS, i * (height / 4.0) + RADIUS, | |
281 width + RADIUS, i * (height / 4.0) + RADIUS); | |
282 | |
283 gdk_draw_line(curve->pixmap, style->dark_gc[state], | |
284 i * (width / 4.0) + RADIUS, RADIUS, | |
285 i * (width / 4.0) + RADIUS, height + RADIUS); | |
286 } | |
287 | |
288 #define Qprintf(x,y,...) | |
289 | |
290 #if 1 | |
291 /* Draw the spline/curve itself */ | |
292 p0 = curve->ctlpoints; | |
293 p1 = p0; | |
294 p2 = p1; p2++; | |
295 p3 = p2; p3++; | |
296 | |
297 /* Draw each curve segment */ | |
298 Qprintf(stderr, "-- npoints = %d\n", curve->nctlpoints); | |
299 if (curve->nctlpoints > 5) | |
300 for (i = 0; i < curve->nctlpoints; i++, ++p0, ++p1, ++p2, ++p3) { | |
301 gfloat k1, k2, a, b, c, d, x; | |
302 | |
303 Qprintf(stderr, "#%d: ", i); | |
304 if (p1->x == p2->x) | |
305 continue; | |
306 #define PPASK(q, p) Qprintf(stderr, q "=[%1.3f, %1.3f] ", p->x, p->y) | |
307 | |
308 PPASK("p0", p1); | |
309 PPASK("p1", p1); | |
310 PPASK("p2", p2); | |
311 PPASK("p3", p3); | |
312 | |
313 Qprintf(stderr, "\ncase #"); | |
314 if (p0->x == p1->x && p2->x == p3->x) { | |
315 Qprintf(stderr, "1"); | |
316 k1 = k2 = (p2->y - p1->y) / (p2->x - p1->x); | |
317 } else if (p0->x == p1->x) { | |
318 Qprintf(stderr, "2"); | |
319 k2 = (p3->y - p1->y) / (p3->x - p1->x); | |
320 k1 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k2) / 2; | |
321 } else if (p2->x == p3->x) { | |
322 Qprintf(stderr, "3"); | |
323 k1 = (p2->y - p0->y) / (p2->x - p0->x); | |
324 k2 = (3 * (p2->y - p1->y) / (p2->x - p1->x) - k1) / 2; | |
325 } else { | |
326 Qprintf(stderr, "4"); | |
327 k1 = (p2->y - p0->y) / (p2->x - p0->x); | |
328 k2 = (p3->y - p1->y) / (p3->x - p1->x); | |
329 } | |
330 | |
331 xs_cubic_coeff(p1->x, p1->y, p2->x, p2->y, k1, k2, &a, &b, &c, &d); | |
332 | |
333 Qprintf(stderr, " seg[%1.3f, %1.3f] => [%1.3f, %1.3f] k1=%1.3f, k2=%1.3f\n\n", | |
334 p1->x, p1->y, | |
335 p2->x, p2->y, | |
336 k1, k2); | |
337 | |
338 for (x = p1->x; x <= p2->x; x += res) { | |
339 gfloat y = ((a * x + b) * x + c) * x + d; | |
340 gint qx, qy; | |
341 qx = RADIUS + xs_project(x, curve->min_x, curve->max_x, width); | |
342 qy = RADIUS + xs_project(y, curve->min_y, curve->max_y, height); | |
343 | |
344 gdk_draw_point(curve->pixmap, style->fg_gc[state], | |
345 RADIUS + xs_project(x, curve->min_x, curve->max_x, width), | |
346 RADIUS + xs_project(y, curve->min_y, curve->max_y, height)); | |
347 | |
348 } | |
349 } | |
350 | |
351 Qprintf(stderr, "-------\n"); | |
352 #endif | |
353 | |
354 /* Draw control points */ | |
355 for (i = 0; i < curve->nctlpoints; ++i) { | |
356 gint x, y; | |
357 | |
358 if (GET_X(i) < curve->min_x || GET_Y(i) < curve->min_y || | |
359 GET_X(i) >= curve->max_x || GET_Y(i) >= curve->max_y) | |
360 continue; | |
361 | |
362 x = xs_project(GET_X(i), curve->min_x, curve->max_x, width); | |
363 y = xs_project(GET_Y(i), curve->min_y, curve->max_y, height); | |
364 | |
365 gdk_draw_arc(curve->pixmap, style->fg_gc[state], TRUE, | |
366 x, y, RADIUS2, RADIUS2, 0, 360 * 64); | |
367 } | |
368 | |
369 /* Draw pixmap in the widget */ | |
370 gdk_draw_pixmap(GTK_WIDGET(curve)->window, | |
371 style->fg_gc[state], curve->pixmap, | |
372 0, 0, 0, 0, | |
373 width + RADIUS2, | |
374 height + RADIUS2); | |
375 } | |
376 | |
377 | |
378 static gint xs_curve_graph_events(GtkWidget *widget, GdkEvent *event, XSCurve *curve) | |
379 { | |
380 GdkCursorType new_type = curve->cursor_type; | |
381 GdkEventButton *bevent; | |
382 GtkWidget *w; | |
383 gint i, width, height, x, y, tx, ty, cx, closest_point = 0, min_x; | |
384 guint distance; | |
385 | |
386 w = GTK_WIDGET(curve); | |
387 width = w->allocation.width - RADIUS2; | |
388 height = w->allocation.height - RADIUS2; | |
389 | |
390 if ((width < 0) || (height < 0)) | |
391 return FALSE; | |
392 | |
393 /* get the pointer position */ | |
394 gdk_window_get_pointer(w->window, &tx, &ty, NULL); | |
395 x = CLAMP((tx - RADIUS), 0, width - 1); | |
396 y = CLAMP((ty - RADIUS), 0, height - 1); | |
397 min_x = curve->min_x; | |
398 | |
399 distance = ~0U; | |
400 for (i = 0; i < curve->nctlpoints; ++i) { | |
401 cx = xs_project(GET_X(i), min_x, curve->max_x, width); | |
402 if ((guint) abs(x - cx) < distance) { | |
403 distance = abs(x - cx); | |
404 closest_point = i; | |
405 } | |
406 } | |
407 | |
408 /* Act based on event type */ | |
409 switch (event->type) { | |
410 case GDK_CONFIGURE: | |
411 if (curve->pixmap) | |
412 gdk_pixmap_unref(curve->pixmap); | |
413 curve->pixmap = 0; | |
414 | |
415 /* fall through */ | |
416 | |
417 case GDK_EXPOSE: | |
418 if (!curve->pixmap) { | |
419 curve->pixmap = gdk_pixmap_new(w->window, | |
420 w->allocation.width, w->allocation.height, -1); | |
421 } | |
422 xs_curve_draw(curve, width, height); | |
423 break; | |
424 | |
425 case GDK_BUTTON_PRESS: | |
426 gtk_grab_add(widget); | |
427 | |
428 bevent = (GdkEventButton *) event; | |
429 new_type = GDK_TCROSS; | |
430 | |
431 if (distance > MIN_DISTANCE) { | |
432 /* insert a new control point */ | |
433 if (curve->nctlpoints > 0) { | |
434 cx = xs_project(GET_X(closest_point), min_x, curve->max_x, width); | |
435 if (x > cx) closest_point++; | |
436 } | |
437 | |
438 curve->nctlpoints++; | |
439 | |
440 curve->ctlpoints = g_realloc(curve->ctlpoints, | |
441 curve->nctlpoints * sizeof(*curve->ctlpoints)); | |
442 | |
443 for (i = curve->nctlpoints - 1; i > closest_point; --i) { | |
444 memcpy(curve->ctlpoints + i, | |
445 curve->ctlpoints + i - 1, | |
446 sizeof(*curve->ctlpoints)); | |
447 } | |
448 } | |
449 | |
450 curve->grab_point = closest_point; | |
451 GET_X(curve->grab_point) = xs_unproject(x, min_x, curve->max_x, width); | |
452 GET_Y(curve->grab_point) = xs_unproject(y, curve->min_y, curve->max_y, height); | |
453 | |
454 xs_curve_draw(curve, width, height); | |
455 break; | |
456 | |
457 case GDK_BUTTON_RELEASE: | |
458 { | |
459 gint src, dst; | |
460 | |
461 gtk_grab_remove(widget); | |
462 | |
463 /* delete inactive points: */ | |
464 for (src = dst = 0; src < curve->nctlpoints; ++src) { | |
465 if (GET_X(src) >= min_x) { | |
466 memcpy(curve->ctlpoints + dst, | |
467 curve->ctlpoints + src, | |
468 sizeof(*curve->ctlpoints)); | |
469 dst++; | |
470 } | |
471 } | |
472 | |
473 if (dst < src) { | |
474 curve->nctlpoints -= (src - dst); | |
475 if (curve->nctlpoints <= 0) { | |
476 curve->nctlpoints = 1; | |
477 GET_X(0) = min_x; | |
478 GET_Y(0) = curve->min_y; | |
479 xs_curve_draw(curve, width, height); | |
480 } | |
481 curve->ctlpoints = g_realloc(curve->ctlpoints, | |
482 curve->nctlpoints * sizeof(*curve->ctlpoints)); | |
483 } | |
484 | |
485 new_type = GDK_FLEUR; | |
486 curve->grab_point = -1; | |
487 } | |
488 break; | |
489 | |
490 case GDK_MOTION_NOTIFY: | |
491 if (curve->grab_point == -1) { | |
492 /* if no point is grabbed... */ | |
493 if (distance <= MIN_DISTANCE) | |
494 new_type = GDK_FLEUR; | |
495 else | |
496 new_type = GDK_TCROSS; | |
497 } else { | |
498 gint leftbound, rightbound; | |
499 | |
500 /* drag the grabbed point */ | |
501 new_type = GDK_TCROSS; | |
502 | |
503 leftbound = -MIN_DISTANCE; | |
504 if (curve->grab_point > 0) { | |
505 leftbound = xs_project( | |
506 GET_X(curve->grab_point-1), | |
507 min_x, curve->max_x, width); | |
508 } | |
509 | |
510 rightbound = width + RADIUS2 + MIN_DISTANCE; | |
511 if (curve->grab_point + 1 < curve->nctlpoints) { | |
512 rightbound = xs_project( | |
513 GET_X(curve->grab_point+1), | |
514 min_x, curve->max_x, width); | |
515 } | |
516 | |
517 if ((tx <= leftbound) || (tx >= rightbound) || | |
518 (ty > height + RADIUS2 + MIN_DISTANCE) || (ty < -MIN_DISTANCE)) { | |
519 GET_X(curve->grab_point) = min_x - 1.0; | |
520 } else { | |
521 GET_X(curve->grab_point) = | |
522 xs_unproject(x, min_x, curve->max_x, width); | |
523 GET_Y(curve->grab_point) = | |
524 xs_unproject(y, curve->min_y, curve->max_y, height); | |
525 } | |
526 | |
527 xs_curve_draw(curve, width, height); | |
528 } | |
529 | |
530 /* See if cursor type was changed and update accordingly */ | |
531 if (new_type != (GdkCursorType) curve->cursor_type) { | |
532 GdkCursor *cursor; | |
533 curve->cursor_type = new_type; | |
534 cursor = gdk_cursor_new(curve->cursor_type); | |
535 gdk_window_set_cursor(w->window, cursor); | |
536 gdk_cursor_destroy(cursor); | |
537 } | |
538 break; | |
539 | |
540 default: | |
541 break; | |
542 } | |
543 | |
544 return FALSE; | |
545 } | |
546 | |
547 | |
548 static void xs_curve_size_graph(XSCurve *curve) | |
549 { | |
550 gint width, height; | |
551 gfloat aspect; | |
552 GdkScreen *screen = gtk_widget_get_screen(GTK_WIDGET(curve)); | |
553 | |
554 width = (curve->max_x - curve->min_x) + 1; | |
555 height = (curve->max_y - curve->min_y) + 1; | |
556 aspect = width / (gfloat) height; | |
557 | |
558 if (width > gdk_screen_get_width(screen) / 4) | |
559 width = gdk_screen_get_width(screen) / 4; | |
560 | |
561 if (height > gdk_screen_get_height(screen) / 4) | |
562 height = gdk_screen_get_height(screen) / 4; | |
563 | |
564 if (aspect < 1.0) | |
565 width = height * aspect; | |
566 else | |
567 height = width / aspect; | |
568 | |
569 gtk_widget_set_size_request(GTK_WIDGET(curve), width + RADIUS2, height + RADIUS2); | |
570 } | |
571 | |
572 | |
573 static void xs_curve_update(XSCurve *curve) | |
574 { | |
575 if (curve->pixmap) { | |
576 gint width, height; | |
577 | |
578 width = GTK_WIDGET(curve)->allocation.width - RADIUS2; | |
579 height = GTK_WIDGET(curve)->allocation.height - RADIUS2; | |
580 xs_curve_draw(curve, width, height); | |
581 } | |
582 } | |
583 | |
584 | |
585 void xs_curve_reset(XSCurve *curve) | |
586 { | |
587 if (curve->ctlpoints) | |
588 g_free(curve->ctlpoints); | |
589 | |
590 curve->nctlpoints = 4; | |
591 curve->ctlpoints = g_malloc(curve->nctlpoints * sizeof(curve->ctlpoints[0])); | |
592 | |
593 GET_X(0) = curve->min_x; | |
594 GET_Y(0) = curve->min_y; | |
595 GET_X(1) = curve->min_x; | |
596 GET_Y(1) = curve->min_y; | |
597 | |
598 GET_X(2) = curve->max_x; | |
599 GET_Y(2) = curve->max_y; | |
600 GET_X(3) = curve->max_x; | |
601 GET_Y(3) = curve->max_y; | |
602 | |
603 xs_curve_update(curve); | |
604 } | |
605 | |
606 | |
607 void xs_curve_set_range(XSCurve *curve, gfloat min_x, gfloat min_y, gfloat max_x, gfloat max_y) | |
608 { | |
609 g_object_freeze_notify(G_OBJECT(curve)); | |
610 if (curve->min_x != min_x) { | |
611 curve->min_x = min_x; | |
612 g_object_notify(G_OBJECT(curve), "min-x"); | |
613 } | |
614 if (curve->max_x != max_x) { | |
615 curve->max_x = max_x; | |
616 g_object_notify(G_OBJECT(curve), "max-x"); | |
617 } | |
618 if (curve->min_y != min_y) { | |
619 curve->min_y = min_y; | |
620 g_object_notify(G_OBJECT(curve), "min-y"); | |
621 } | |
622 if (curve->max_y != max_y) { | |
623 curve->max_y = max_y; | |
624 g_object_notify(G_OBJECT(curve), "max-y"); | |
625 } | |
626 g_object_thaw_notify(G_OBJECT(curve)); | |
627 | |
628 xs_curve_size_graph(curve); | |
629 xs_curve_reset(curve); | |
630 } | |
631 | |
632 | |
633 gboolean xs_curve_realloc_data(XSCurve *curve, gint npoints) | |
634 { | |
635 if (npoints != curve->nctlpoints) { | |
636 curve->nctlpoints = npoints; | |
637 curve->ctlpoints = (t_xs_point *) g_realloc(curve->ctlpoints, | |
638 curve->nctlpoints * sizeof(*curve->ctlpoints)); | |
639 | |
640 if (curve->ctlpoints == NULL) | |
641 return FALSE; | |
642 } | |
643 | |
644 return TRUE; | |
645 } | |
646 | |
647 | |
648 void xs_curve_get_data(XSCurve *curve, t_xs_point ***points, gint **npoints) | |
649 { | |
650 *points = &(curve->ctlpoints); | |
651 *npoints = &(curve->nctlpoints); | |
652 } | |
653 | |
654 | |
655 gboolean xs_curve_set_points(XSCurve *curve, t_xs_int_point *points, gint npoints) | |
656 { | |
657 gint i; | |
658 | |
659 if (!xs_curve_realloc_data(curve, npoints + 4)) | |
660 return FALSE; | |
661 | |
662 GET_X(0) = curve->min_x; | |
663 GET_Y(0) = curve->min_y; | |
664 GET_X(1) = curve->min_x; | |
665 GET_Y(1) = curve->min_y; | |
666 | |
667 for (i = 0; i < npoints; i++) { | |
668 GET_X(i+2) = points[i].x; | |
669 GET_Y(i+2) = points[i].y; | |
670 } | |
671 | |
672 GET_X(npoints+2) = curve->max_x; | |
673 GET_Y(npoints+2) = curve->max_y; | |
674 GET_X(npoints+3) = curve->max_x; | |
675 GET_Y(npoints+3) = curve->max_y; | |
676 | |
677 xs_curve_update(curve); | |
678 return TRUE; | |
679 } | |
680 | |
681 | |
682 gboolean xs_curve_get_points(XSCurve *curve, t_xs_int_point **points, gint *npoints) | |
683 { | |
684 gint i, n; | |
685 | |
686 n = curve->nctlpoints - 4; | |
687 | |
688 *points = g_malloc(n * sizeof(t_xs_int_point)); | |
689 if (*points == NULL) | |
690 return FALSE; | |
691 | |
692 *npoints = n; | |
693 for (i = 2; i < curve->nctlpoints - 2; i++) { | |
694 (*points)[i].x = GET_X(i); | |
695 (*points)[i].y = GET_Y(i); | |
696 } | |
697 | |
698 return TRUE; | |
699 } | |
700 | |
701 | |
702 GtkWidget *xs_curve_new(void) | |
703 { | |
704 return g_object_new(XS_TYPE_CURVE, NULL); | |
705 } | |
706 | |
707 | |
708 static void xs_curve_finalize(GObject *object) | |
709 { | |
710 XSCurve *curve; | |
711 | |
712 g_return_if_fail(XS_IS_CURVE(object)); | |
713 | |
714 curve = XS_CURVE(object); | |
715 if (curve->pixmap) | |
716 g_object_unref(curve->pixmap); | |
717 if (curve->ctlpoints) | |
718 g_free(curve->ctlpoints); | |
719 | |
720 G_OBJECT_CLASS(parent_class)->finalize(object); | |
721 } |