comparison src/xs_curve.c @ 502:54d86ee98b98

Alpha/preliminary curve widget code merged.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 27 Jan 2007 02:52:02 +0000
parents 0f255a575720
children 982cec405ef0
comparison
equal deleted inserted replaced
501:d753e545f9fa 502:54d86ee98b98
1 #include <stdlib.h> 1 #include <stdlib.h>
2 #include <string.h> 2 #include <string.h>
3 #include <math.h> 3 #include <math.h>
4
5 #include <stdio.h>
4 6
5 #include "xs_curve.h" 7 #include "xs_curve.h"
6 #include <gtk/gtkdrawingarea.h> 8 #include <gtk/gtkdrawingarea.h>
7 #include <gtk/gtkmain.h> 9 #include <gtk/gtkmain.h>
8 #include <gtk/gtksignal.h> 10 #include <gtk/gtksignal.h>
9 11
10 12
13 #define GET_X(i) curve->ctlpoints[i].x
14 #define GET_Y(i) curve->ctlpoints[i].y
15
16
11 #define RADIUS 3 /* radius of the control points */ 17 #define RADIUS 3 /* radius of the control points */
18 #define RADIUS2 (RADIUS * 2)
19
12 #define MIN_DISTANCE 8 /* min distance between control points */ 20 #define MIN_DISTANCE 8 /* min distance between control points */
13 21
14 #define GRAPH_MASK (GDK_EXPOSURE_MASK | \ 22 #define GRAPH_MASK (GDK_EXPOSURE_MASK | \
15 GDK_POINTER_MOTION_MASK | \ 23 GDK_POINTER_MOTION_MASK | \
16 GDK_POINTER_MOTION_HINT_MASK | \ 24 GDK_POINTER_MOTION_HINT_MASK | \
17 GDK_ENTER_NOTIFY_MASK | \ 25 GDK_ENTER_NOTIFY_MASK | \
18 GDK_BUTTON_PRESS_MASK | \ 26 GDK_BUTTON_PRESS_MASK | \
19 GDK_BUTTON_RELEASE_MASK | \ 27 GDK_BUTTON_RELEASE_MASK | \
20 GDK_BUTTON1_MOTION_MASK) 28 GDK_BUTTON1_MOTION_MASK)
21 29
22 enum 30 enum {
23 {
24 ARG_0, 31 ARG_0,
25 ARG_CURVE_TYPE, 32 ARG_CURVE_TYPE,
26 ARG_MIN_X, 33 ARG_MIN_X,
27 ARG_MAX_X, 34 ARG_MAX_X,
28 ARG_MIN_Y, 35 ARG_MIN_Y,
29 ARG_MAX_Y 36 ARG_MAX_Y
30 }; 37 };
31 38
32 static GtkDrawingAreaClass *parent_class = NULL; 39 static GtkDrawingAreaClass *parent_class = NULL;
33 40
34
35 /* forward declarations: */
36 static void xs_curve_class_init(XSCurveClass * class); 41 static void xs_curve_class_init(XSCurveClass * class);
37 static void xs_curve_init(XSCurve * curve); 42 static void xs_curve_init(XSCurve * curve);
38 static void xs_curve_set_arg(GtkObject * object, GtkArg * arg, guint arg_id); 43 static void xs_curve_set_arg(GtkObject * object, GtkArg * arg, guint arg_id);
39 static void xs_curve_get_arg(GtkObject * object, GtkArg * arg, guint arg_id); 44 static void xs_curve_get_arg(GtkObject * object, GtkArg * arg, guint arg_id);
40 static void xs_curve_finalize(GtkObject * object); 45 static void xs_curve_finalize(GtkObject * object);
41 static gint xs_curve_graph_events(GtkWidget * widget, GdkEvent * event, XSCurve * c); 46 static gint xs_curve_graph_events(GtkWidget * widget, GdkEvent * event, XSCurve * c);
42 static void xs_curve_size_graph(XSCurve * curve); 47 static void xs_curve_size_graph(XSCurve * curve);
48
43 49
44 GtkType xs_curve_get_type(void) 50 GtkType xs_curve_get_type(void)
45 { 51 {
46 static GtkType curve_type = 0; 52 static GtkType curve_type = 0;
47 53
60 curve_type = gtk_type_unique(GTK_TYPE_DRAWING_AREA, &curve_info); 66 curve_type = gtk_type_unique(GTK_TYPE_DRAWING_AREA, &curve_info);
61 } 67 }
62 return curve_type; 68 return curve_type;
63 } 69 }
64 70
65 static void xs_curve_class_init(XSCurveClass * class) 71
72 static void xs_curve_class_init(XSCurveClass *class)
66 { 73 {
67 GtkObjectClass *object_class; 74 GtkObjectClass *object_class;
68 75
69 parent_class = gtk_type_class(GTK_TYPE_DRAWING_AREA); 76 parent_class = gtk_type_class(GTK_TYPE_DRAWING_AREA);
70 77
78 gtk_object_add_arg_type("XSCurve::max_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_X); 85 gtk_object_add_arg_type("XSCurve::max_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_X);
79 gtk_object_add_arg_type("XSCurve::min_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_Y); 86 gtk_object_add_arg_type("XSCurve::min_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_Y);
80 gtk_object_add_arg_type("XSCurve::max_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_Y); 87 gtk_object_add_arg_type("XSCurve::max_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_Y);
81 } 88 }
82 89
83 static void xs_curve_init(XSCurve * curve) 90
91 static void xs_curve_init(XSCurve *curve)
84 { 92 {
85 gint old_mask; 93 gint old_mask;
86 94
87 curve->pixmap = NULL; 95 curve->pixmap = NULL;
88 curve->height = 0; 96 curve->height = 0;
89 curve->grab_point = -1; 97 curve->grab_point = -1;
90 98
91 curve->num_points = 0;
92 curve->point = 0;
93
94 curve->num_ctlpoints = 0; 99 curve->num_ctlpoints = 0;
95 curve->ctlpoint = NULL; 100 curve->ctlpoints = NULL;
96 101
97 curve->min_x = 0.0; 102 curve->min_x = 0.0;
98 curve->max_x = 1.0; 103 curve->max_x = 2048.0;
99 curve->min_y = 0.0; 104 curve->min_y = 0.0;
100 curve->max_y = 1.0; 105 curve->max_y = 22000.0;
101 106
102 old_mask = gtk_widget_get_events(GTK_WIDGET(curve)); 107 old_mask = gtk_widget_get_events(GTK_WIDGET(curve));
103 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK); 108 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK);
104 gtk_signal_connect(GTK_OBJECT(curve), "event", (GtkSignalFunc) xs_curve_graph_events, curve); 109 gtk_signal_connect(GTK_OBJECT(curve), "event", (GtkSignalFunc) xs_curve_graph_events, curve);
105 xs_curve_size_graph(curve); 110 xs_curve_size_graph(curve);
106 } 111 }
107 112
108 static void xs_curve_set_arg(GtkObject * object, GtkArg * arg, guint arg_id) 113
114 static void xs_curve_set_arg(GtkObject *object, GtkArg *arg, guint arg_id)
109 { 115 {
110 XSCurve *curve = XS_CURVE(object); 116 XSCurve *curve = XS_CURVE(object);
111 117
112 switch (arg_id) { 118 switch (arg_id) {
113 case ARG_MIN_X: 119 case ARG_MIN_X:
123 xs_curve_set_range(curve, curve->min_x, curve->max_x, curve->min_y, GTK_VALUE_FLOAT(*arg)); 129 xs_curve_set_range(curve, curve->min_x, curve->max_x, curve->min_y, GTK_VALUE_FLOAT(*arg));
124 break; 130 break;
125 } 131 }
126 } 132 }
127 133
128 static void xs_curve_get_arg(GtkObject * object, GtkArg * arg, guint arg_id) 134
135 static void xs_curve_get_arg(GtkObject *object, GtkArg *arg, guint arg_id)
129 { 136 {
130 XSCurve *curve = XS_CURVE(object); 137 XSCurve *curve = XS_CURVE(object);
131 138
132 switch (arg_id) { 139 switch (arg_id) {
133 case ARG_MIN_X: 140 case ARG_MIN_X:
146 arg->type = GTK_TYPE_INVALID; 153 arg->type = GTK_TYPE_INVALID;
147 break; 154 break;
148 } 155 }
149 } 156 }
150 157
158
151 static int xs_project(gfloat value, gfloat min, gfloat max, int norm) 159 static int xs_project(gfloat value, gfloat min, gfloat max, int norm)
152 { 160 {
153 return (norm - 1) * ((value - min) / (max - min)) + 0.5; 161 return (norm - 1) * ((value - min) / (max - min)) + 0.5;
154 } 162 }
155 163
164
156 static gfloat xs_unproject(gint value, gfloat min, gfloat max, int norm) 165 static gfloat xs_unproject(gint value, gfloat min, gfloat max, int norm)
157 { 166 {
158 return value / (gfloat) (norm - 1) * (max - min) + min; 167 return value / (gfloat) (norm - 1) * (max - min) + min;
159 } 168 }
160 169
161 /* Solve the tridiagonal equation system that determines the second 170
162 derivatives for the interpolation points. (Based on Numerical 171 static inline void xs_cubic_coeff(gfloat x1, gfloat y1,
163 Recipies 2nd Edition.) */ 172 gfloat x2, gfloat y2,
164 static void spline_solve(int n, gfloat x[], gfloat y[], gfloat y2[]) 173 gfloat k1, gfloat k2,
165 { 174 gfloat *a, gfloat *b,
166 gfloat p, sig, *u; 175 gfloat *c, gfloat *d)
167 gint i, k; 176 {
168 177 gfloat dx = x2 - x1, dy = y2 - y1;
169 u = g_malloc((n - 1) * sizeof(u[0])); 178
170 179 *a = ((k1 + k2) - 2 * dy / dx) / (dx * dx);
171 y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */ 180 *b = ((k2 - k1) / dx - 3 * (x1 + x2) * (*a)) / 2;
172 181 *c = k1 - (3 * x1 * (*a) + 2 * (*b)) * x1;
173 for (i = 1; i < n - 1; ++i) { 182 *d = y1 - ((x1 * (*a) + (*b)) * x1 + (*c)) * x1;
174 sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); 183 }
175 p = sig * y2[i - 1] + 2.0; 184
176 y2[i] = (sig - 1.0) / p; 185 #define x(val) val->x
177 u[i] = ((y[i + 1] - y[i]) 186 #define y(val) val->y
178 / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1])); 187
179 u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; 188 static void xs_curve_draw(XSCurve *curve, gint width, gint height)
180 } 189 {
181 190 gfloat res = 10.0f;
182 y2[n - 1] = 0.0;
183 for (k = n - 2; k >= 0; --k)
184 y2[k] = y2[k] * y2[k + 1] + u[k];
185
186 g_free(u);
187 }
188
189 static gfloat spline_eval(int n, gfloat x[], gfloat y[], gfloat y2[], gfloat val)
190 {
191 gint k_lo, k_hi, k;
192 gfloat h, b, a;
193
194 /* do a binary search for the right interval: */
195 k_lo = 0;
196 k_hi = n - 1;
197 while (k_hi - k_lo > 1) {
198 k = (k_hi + k_lo) / 2;
199 if (x[k] > val)
200 k_hi = k;
201 else
202 k_lo = k;
203 }
204
205 h = x[k_hi] - x[k_lo];
206 g_assert(h > 0.0);
207
208 a = (x[k_hi] - val) / h;
209 b = (val - x[k_lo]) / h;
210 return a * y[k_lo] + b * y[k_hi] + ((a * a * a - a) * y2[k_lo] + (b * b * b - b) * y2[k_hi]) * (h * h) / 6.0;
211 }
212
213 static void xs_curve_interpolate(XSCurve * c, gint width, gint height)
214 {
215 gfloat *vector;
216 gint i;
217
218 vector = g_malloc(width * sizeof(vector[0]));
219
220 xs_curve_get_vector(c, width, vector);
221
222 c->height = height;
223 if (c->num_points != width) {
224 c->num_points = width;
225 if (c->point)
226 g_free(c->point);
227 c->point = g_malloc(c->num_points * sizeof(c->point[0]));
228 }
229
230 for (i = 0; i < width; ++i) {
231 c->point[i].x = RADIUS + i;
232 c->point[i].y = RADIUS + height - project(vector[i], c->min_y, c->max_y, height);
233 }
234
235 g_free(vector);
236 }
237
238 static void xs_curve_draw(XSCurve * c, gint width, gint height)
239 {
240 GtkStateType state; 191 GtkStateType state;
241 GtkStyle *style; 192 GtkStyle *style;
242 gint i; 193 gint i;
243 194 t_xs_point *p0, *p1, *p2, *p3;
244 if (!c->pixmap) 195
196 if (!curve->pixmap)
245 return; 197 return;
246 198
247 if (c->height != height || c->num_points != width)
248 xs_curve_interpolate(c, width, height);
249
250 state = GTK_STATE_NORMAL; 199 state = GTK_STATE_NORMAL;
251 if (!GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(c))) 200 if (!GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(curve)))
252 state = GTK_STATE_INSENSITIVE; 201 state = GTK_STATE_INSENSITIVE;
253 202
254 style = GTK_WIDGET(c)->style; 203 style = GTK_WIDGET(curve)->style;
255 204
256 /* clear the pixmap: */ 205 /* Clear the pixmap */
257 gtk_paint_flat_box(style, c->pixmap, 206 gtk_paint_flat_box(style, curve->pixmap,
258 GTK_STATE_NORMAL, GTK_SHADOW_NONE, 207 GTK_STATE_NORMAL, GTK_SHADOW_NONE,
259 NULL, GTK_WIDGET(c), "curve_bg", 208 NULL, GTK_WIDGET(curve), "curve_bg",
260 0, 0, width + RADIUS * 2, height + RADIUS * 2); 209 0, 0,
261 210 width + RADIUS2,
262 /* draw the grid lines: (XXX make more meaningful) */ 211 height + RADIUS2);
212
213
214 /* Draw the grid */
263 for (i = 0; i < 5; i++) { 215 for (i = 0; i < 5; i++) {
264 gdk_draw_line(c->pixmap, style->dark_gc[state], 216 gdk_draw_line(curve->pixmap, style->dark_gc[state],
265 RADIUS, i * (height / 4.0) + RADIUS, 217 RADIUS, i * (height / 4.0) + RADIUS,
266 width + RADIUS, i * (height / 4.0) + RADIUS); 218 width + RADIUS, i * (height / 4.0) + RADIUS);
267 219
268 gdk_draw_line(c->pixmap, style->dark_gc[state], 220 gdk_draw_line(curve->pixmap, style->dark_gc[state],
269 i * (width / 4.0) + RADIUS, RADIUS, 221 i * (width / 4.0) + RADIUS, RADIUS,
270 i * (width / 4.0) + RADIUS, height + RADIUS); 222 i * (width / 4.0) + RADIUS, height + RADIUS);
271 } 223 }
272 224
273 gdk_draw_points(c->pixmap, style->fg_gc[state], c->point, c->num_points); 225
274 226 /* Draw the spline/curve itself */
275 gdk_draw_pixmap(GTK_WIDGET(c)->window, style->fg_gc[state], c->pixmap, 227 p0 = curve->ctlpoints;
276 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2); 228 p1 = p0; p1++;
277 } 229 p2 = p1; p2++;
278 230 p3 = p2; p3++;
279 static gint xs_curve_graph_events(GtkWidget * widget, GdkEvent * event, XSCurve * c) 231
280 { 232 /* Draw each curve segment */
281 gint i, src, dst, leftbound, rightbound; 233 fprintf(stderr, "npoints = %d\n", curve->num_ctlpoints);
234 for (i = 0; i < curve->num_ctlpoints; i++, ++p0, ++p1, ++p2, ++p3) {
235 gfloat k1, k2, a, b, c, d, x;
236
237 /* p1 and p2 equal; single point */
238 if (x(p1) == x(p2))
239 continue;
240
241 /* Both end points repeated; straight line */
242 if (x(p0) == x(p1) && x(p2) == x(p3)) {
243 k1 = k2 = (y(p2) - y(p1)) / (x(p2) - x(p1));
244 }
245 /* p0 and p1 equal; use f''(x1) = 0 */
246 else if (x(p0) == x(p1)) {
247 k2 = (y(p3) - y(p1)) / (x(p3) - x(p1));
248 k1 = (3 * (y(p2) - y(p1)) / (x(p2) - x(p1)) - k2) / 2;
249 }
250 /* p2 and p3 equal; use f''(x2) = 0 */
251 else if (x(p2) == x(p3)) {
252 k1 = (y(p2) - y(p0)) / (x(p2) - x(p0));
253 k2 = (3 * (y(p2) - y(p1)) / (x(p2) - x(p1)) - k1) / 2;
254 }
255 /* Normal curve */
256 else {
257 k1 = (y(p2) - y(p0)) / (x(p2) - x(p0));
258 k2 = (y(p3) - y(p1)) / (x(p3) - x(p1));
259 }
260
261 xs_cubic_coeff(x(p1), y(p1), x(p2), y(p2), k1, k2, &a, &b, &c, &d);
262
263 fprintf(stderr, "--seg[%1.3f, %1.3f]=>[%1.3f, %1.3f]--\n",
264 x(p1), y(p1), x(p2), y(p2));
265
266 for (x = x(p1); x <= x(p2); x += res) {
267 gfloat y = ((a * x + b) * x + c) * x + d;
268 gint qx, qy;
269 qx = RADIUS + xs_project(x, curve->min_x, curve->max_x, width);
270 qy = RADIUS + xs_project(y, curve->min_y, curve->max_y, height);
271
272 fprintf(stderr, "[%1.3f, %1.3f] -> %d, %d\n", x, y, qx, qy);
273
274 gdk_draw_point(curve->pixmap, style->fg_gc[state],
275 RADIUS + xs_project(x, curve->min_x, curve->max_x, width),
276 RADIUS + xs_project(y, curve->min_y, curve->max_y, height)
277 );
278
279 }
280
281 fprintf(stderr, "-------\n");
282 }
283
284 /* Draw control points */
285 for (i = 0; i < curve->num_ctlpoints; ++i) {
286 gint x, y;
287
288 if (GET_X(i) < curve->min_x || GET_Y(i) < curve->min_y ||
289 GET_X(i) >= curve->max_x || GET_Y(i) >= curve->max_y)
290 continue;
291
292 x = xs_project(GET_X(i), curve->min_x, curve->max_x, width);
293 y = xs_project(GET_Y(i), curve->min_y, curve->max_y, height);
294
295 gdk_draw_arc(curve->pixmap, style->fg_gc[state], TRUE,
296 x, y, RADIUS2, RADIUS2, 0, 360 * 64);
297 }
298
299 /* Draw pixmap in the widget */
300 gdk_draw_pixmap(GTK_WIDGET(curve)->window,
301 style->fg_gc[state], curve->pixmap,
302 0, 0, 0, 0,
303 width + RADIUS2,
304 height + RADIUS2);
305 }
306
307 #undef x
308 #undef y
309
310
311 static gint xs_curve_graph_events(GtkWidget *widget, GdkEvent *event, XSCurve *curve)
312 {
313 GdkCursorType new_type = curve->cursor_type;
282 GdkEventButton *bevent; 314 GdkEventButton *bevent;
283 GdkEventMotion *mevent; 315 GdkEventMotion *mevent;
284 GtkWidget *w; 316 GtkWidget *w;
285 gint tx, ty; 317 gint i, width, height, x, y, tx, ty, cx, closest_point = 0, min_x;
286 gint cx, x, y, width, height;
287 gint closest_point = 0;
288 gfloat rx, ry, min_x;
289 guint distance; 318 guint distance;
290 gint x1, x2, y1, y2; 319
291 320 w = GTK_WIDGET(curve);
292 w = GTK_WIDGET(c); 321 width = w->allocation.width - RADIUS2;
293 width = w->allocation.width - RADIUS * 2; 322 height = w->allocation.height - RADIUS2;
294 height = w->allocation.height - RADIUS * 2;
295 323
296 if ((width < 0) || (height < 0)) 324 if ((width < 0) || (height < 0))
297 return FALSE; 325 return FALSE;
326
327 /* get the pointer position */
328 gdk_window_get_pointer(w->window, &tx, &ty, NULL);
329 x = CLAMP((tx - RADIUS), 0, width - 1);
330 y = CLAMP((ty - RADIUS), 0, height - 1);
331
332 min_x = curve->min_x;
333
334 distance = ~0U;
335 for (i = 0; i < curve->num_ctlpoints; ++i) {
336 cx = xs_project(GET_X(i), min_x, curve->max_x, width);
337 if ((guint) abs(x - cx) < distance) {
338 distance = abs(x - cx);
339 closest_point = i;
340 }
341 }
342
343 /* Act based on event type */
344 switch (event->type) {
345 case GDK_CONFIGURE:
346 if (curve->pixmap)
347 gdk_pixmap_unref(curve->pixmap);
348 curve->pixmap = 0;
349
350 /* fall through */
351
352 case GDK_EXPOSE:
353 if (!curve->pixmap) {
354 curve->pixmap = gdk_pixmap_new(w->window,
355 w->allocation.width, w->allocation.height, -1);
356 }
357 xs_curve_draw(curve, width, height);
358 break;
359
360 case GDK_BUTTON_PRESS:
361 gtk_grab_add(widget);
362
363 bevent = (GdkEventButton *) event;
364 new_type = GDK_TCROSS;
365
366 if (distance > MIN_DISTANCE) {
367 /* insert a new control point */
368 if (curve->num_ctlpoints > 0) {
369 cx = xs_project(GET_X(closest_point), min_x, curve->max_x, width);
370 if (x > cx) closest_point++;
371 }
372
373 curve->num_ctlpoints++;
374
375 curve->ctlpoints = g_realloc(curve->ctlpoints, curve->num_ctlpoints * sizeof(*curve->ctlpoints));
376 for (i = curve->num_ctlpoints - 1; i > closest_point; --i) {
377 memcpy(curve->ctlpoints + i, curve->ctlpoints + i - 1, sizeof(*curve->ctlpoints));
378 }
379 }
380
381 curve->grab_point = closest_point;
382 GET_X(curve->grab_point) = xs_unproject(x, min_x, curve->max_x, width);
383 GET_Y(curve->grab_point) = xs_unproject(y, curve->min_y, curve->max_y, height);
384
385 xs_curve_draw(curve, width, height);
386 break;
387
388 case GDK_BUTTON_RELEASE:
389 {
390 gint src, dst;
391
392 gtk_grab_remove(widget);
393
394 /* delete inactive points: */
395 for (src = dst = 0; src < curve->num_ctlpoints; ++src)
396 if (GET_X(src) >= min_x) {
397 memcpy(curve->ctlpoints + dst, curve->ctlpoints + src, sizeof(*curve->ctlpoints));
398 dst++;
399 }
400
401 if (dst < src) {
402 curve->num_ctlpoints -= (src - dst);
403 if (curve->num_ctlpoints <= 0) {
404 curve->num_ctlpoints = 1;
405 GET_X(0) = min_x;
406 GET_Y(0) = curve->min_y;
407 xs_curve_draw(curve, width, height);
408 }
409 curve->ctlpoints = g_realloc(curve->ctlpoints, curve->num_ctlpoints * sizeof(*curve->ctlpoints));
410 }
411
412 new_type = GDK_FLEUR;
413 curve->grab_point = -1;
414 }
415 break;
416
417 case GDK_MOTION_NOTIFY:
418 mevent = (GdkEventMotion *) event;
419
420 if (curve->grab_point == -1) {
421 /* if no point is grabbed... */
422 if (distance <= MIN_DISTANCE)
423 new_type = GDK_FLEUR;
424 else
425 new_type = GDK_TCROSS;
426 } else {
427 gint leftbound, rightbound;
428
429 /* drag the grabbed point */
430 new_type = GDK_TCROSS;
431
432 leftbound = -MIN_DISTANCE;
433 if (curve->grab_point > 0) {
434 leftbound = xs_project(
435 GET_X(curve->grab_point-1),
436 min_x, curve->max_x, width);
437 }
438
439 rightbound = width + RADIUS2 + MIN_DISTANCE;
440 if (curve->grab_point + 1 < curve->num_ctlpoints) {
441 rightbound = xs_project(
442 GET_X(curve->grab_point+1),
443 min_x, curve->max_x, width);
444 }
445
446 if ((tx <= leftbound) || (tx >= rightbound) ||
447 (ty > height + RADIUS2 + MIN_DISTANCE) || (ty < -MIN_DISTANCE)) {
448 GET_X(curve->grab_point) = min_x - 1.0;
449 } else {
450 GET_X(curve->grab_point) =
451 xs_unproject(x, min_x, curve->max_x, width);
452 GET_Y(curve->grab_point) =
453 xs_unproject(y, curve->min_y, curve->max_y, height);
454 }
455
456 xs_curve_draw(curve, width, height);
457 }
458
459 if (new_type != (GdkCursorType) curve->cursor_type) {
460 GdkCursor *cursor;
461
462 curve->cursor_type = new_type;
463
464 cursor = gdk_cursor_new(curve->cursor_type);
465 gdk_window_set_cursor(w->window, cursor);
466 gdk_cursor_destroy(cursor);
467 }
468 break;
469
470 default:
471 break;
472 }
298 473
299 return FALSE; 474 return FALSE;
300 } 475 }
301 476
302 static void xs_curve_size_graph(XSCurve * curve) 477
478 static void xs_curve_size_graph(XSCurve *curve)
303 { 479 {
304 gint width, height; 480 gint width, height;
305 gfloat aspect; 481 gfloat aspect;
306 482
307 width = (curve->max_x - curve->min_x) + 1; 483 width = (curve->max_x - curve->min_x) + 1;
308 height = (curve->max_y - curve->min_y) + 1; 484 height = (curve->max_y - curve->min_y) + 1;
309 aspect = width / (gfloat) height; 485 aspect = width / (gfloat) height;
486
310 if (width > gdk_screen_width() / 4) 487 if (width > gdk_screen_width() / 4)
311 width = gdk_screen_width() / 4; 488 width = gdk_screen_width() / 4;
489
312 if (height > gdk_screen_height() / 4) 490 if (height > gdk_screen_height() / 4)
313 height = gdk_screen_height() / 4; 491 height = gdk_screen_height() / 4;
314 492
315 if (aspect < 1.0) 493 if (aspect < 1.0)
316 width = height * aspect; 494 width = height * aspect;
317 else 495 else
318 height = width / aspect; 496 height = width / aspect;
319 497
320 gtk_drawing_area_size(GTK_DRAWING_AREA(curve), width + RADIUS * 2, height + RADIUS * 2); 498 gtk_drawing_area_size(GTK_DRAWING_AREA(curve), width + RADIUS2, height + RADIUS2);
321 } 499 }
322 500
323 static void xs_curve_reset_vector(XSCurve * curve) 501
324 { 502 void xs_curve_reset(XSCurve *curve)
325 } 503 {
326 504 if (curve->ctlpoints)
327 void xs_curve_reset(XSCurve * c) 505 g_free(curve->ctlpoints);
328 { 506
329 } 507 curve->num_ctlpoints = 4;
330 508 curve->ctlpoints = g_malloc(curve->num_ctlpoints * sizeof(curve->ctlpoints[0]));
331 509
332 void xs_curve_set_range(XSCurve * curve, gfloat min_x, gfloat max_x, gfloat min_y, gfloat max_y) 510 GET_X(0) = curve->min_x;
511 GET_Y(0) = curve->min_y;
512
513 GET_X(1) = curve->min_x;
514 GET_Y(1) = curve->min_y;
515
516 GET_X(2) = curve->max_x;
517 GET_Y(2) = curve->max_y;
518
519 GET_X(3) = curve->max_x;
520 GET_Y(3) = curve->max_y;
521
522 if (curve->pixmap) {
523 gint width, height;
524
525 width = GTK_WIDGET(curve)->allocation.width - RADIUS2;
526 height = GTK_WIDGET(curve)->allocation.height - RADIUS2;
527 xs_curve_draw(curve, width, height);
528 }
529 }
530
531
532 void xs_curve_set_range(XSCurve *curve, gfloat min_x, gfloat max_x, gfloat min_y, gfloat max_y)
333 { 533 {
334 curve->min_x = min_x; 534 curve->min_x = min_x;
335 curve->max_x = max_x; 535 curve->max_x = max_x;
336 curve->min_y = min_y; 536 curve->min_y = min_y;
337 curve->max_y = max_y; 537 curve->max_y = max_y;
338 538
339 xs_curve_size_graph(curve); 539 xs_curve_size_graph(curve);
340 xs_curve_reset_vector(curve); 540 xs_curve_reset(curve);
341 } 541 }
342 542
343 543
344 GtkWidget *xs_curve_new(void) 544 GtkWidget *xs_curve_new(void)
345 { 545 {
346 return gtk_type_new(xs_curve_get_type()); 546 return gtk_type_new(xs_curve_get_type());
347 } 547 }
348 548
349 549
350 static void xs_curve_finalize(GtkObject * object) 550 static void xs_curve_finalize(GtkObject *object)
351 { 551 {
352 XSCurve *curve; 552 XSCurve *curve;
353 553
354 g_return_if_fail(object != NULL); 554 g_return_if_fail(object != NULL);
355 g_return_if_fail(XS_IS_CURVE(object)); 555 g_return_if_fail(XS_IS_CURVE(object));
356 556
357 curve = XS_CURVE(object); 557 curve = XS_CURVE(object);
558
358 if (curve->pixmap) 559 if (curve->pixmap)
359 gdk_pixmap_unref(curve->pixmap); 560 gdk_pixmap_unref(curve->pixmap);
360 if (curve->point) 561
361 g_free(curve->point); 562 if (curve->ctlpoints)
362 if (curve->ctlpoint) 563 g_free(curve->ctlpoints);
363 g_free(curve->ctlpoint);
364 564
365 (*GTK_OBJECT_CLASS(parent_class)->finalize) (object); 565 (*GTK_OBJECT_CLASS(parent_class)->finalize) (object);
366 } 566 }
367 567
368
369 void xs_curve_get_vector(XSCurve *curve, int veclen, gfloat vector[])
370 {
371 }
372
373 void xs_curve_set_vector(XSCurve *curve, int veclen, gfloat vector[])
374 {
375 }
376