comparison src/xs_curve.c @ 359:b1a858b8cb1a

Re-indentation all (non-generated) code.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 07 Nov 2005 09:50:04 +0000
parents 4f247b19c9ea
children df6f12a00305
comparison
equal deleted inserted replaced
358:4f247b19c9ea 359:b1a858b8cb1a
46 GDK_ENTER_NOTIFY_MASK | \ 46 GDK_ENTER_NOTIFY_MASK | \
47 GDK_BUTTON_PRESS_MASK | \ 47 GDK_BUTTON_PRESS_MASK | \
48 GDK_BUTTON_RELEASE_MASK | \ 48 GDK_BUTTON_RELEASE_MASK | \
49 GDK_BUTTON1_MOTION_MASK) 49 GDK_BUTTON1_MOTION_MASK)
50 50
51 enum { 51 enum
52 ARG_0, 52 {
53 ARG_CURVE_TYPE, 53 ARG_0,
54 ARG_MIN_X, 54 ARG_CURVE_TYPE,
55 ARG_MAX_X, 55 ARG_MIN_X,
56 ARG_MIN_Y, 56 ARG_MAX_X,
57 ARG_MAX_Y 57 ARG_MIN_Y,
58 ARG_MAX_Y
58 }; 59 };
59 60
60 static GtkDrawingAreaClass *parent_class = NULL; 61 static GtkDrawingAreaClass *parent_class = NULL;
61 static guint curve_type_changed_signal = 0; 62 static guint curve_type_changed_signal = 0;
62 63
63 64
64 /* forward declarations: */ 65 /* forward declarations: */
65 static void gtk_curve_class_init (GtkCurveClass *class); 66 static void gtk_curve_class_init(GtkCurveClass * class);
66 static void gtk_curve_init (GtkCurve *curve); 67 static void gtk_curve_init(GtkCurve * curve);
67 static void gtk_curve_set_arg (GtkObject *object, 68 static void gtk_curve_set_arg(GtkObject * object, GtkArg * arg, guint arg_id);
68 GtkArg *arg, 69 static void gtk_curve_get_arg(GtkObject * object, GtkArg * arg, guint arg_id);
69 guint arg_id); 70 static void gtk_curve_finalize(GtkObject * object);
70 static void gtk_curve_get_arg (GtkObject *object, 71 static gint gtk_curve_graph_events(GtkWidget * widget, GdkEvent * event, GtkCurve * c);
71 GtkArg *arg, 72 static void gtk_curve_size_graph(GtkCurve * curve);
72 guint arg_id); 73
73 static void gtk_curve_finalize (GtkObject *object); 74 GtkType gtk_curve_get_type(void)
74 static gint gtk_curve_graph_events (GtkWidget *widget, 75 {
75 GdkEvent *event, 76 static GtkType curve_type = 0;
76 GtkCurve *c); 77
77 static void gtk_curve_size_graph (GtkCurve *curve); 78 if (!curve_type) {
78 79 static const GtkTypeInfo curve_info = {
79 GtkType 80 "GtkCurve",
80 gtk_curve_get_type (void) 81 sizeof(GtkCurve),
81 { 82 sizeof(GtkCurveClass),
82 static GtkType curve_type = 0; 83 (GtkClassInitFunc) gtk_curve_class_init,
83 84 (GtkObjectInitFunc) gtk_curve_init,
84 if (!curve_type) 85 /* reserved_1 */ NULL,
85 { 86 /* reserved_2 */ NULL,
86 static const GtkTypeInfo curve_info = 87 (GtkClassInitFunc) NULL,
87 { 88 };
88 "GtkCurve", 89
89 sizeof (GtkCurve), 90 curve_type = gtk_type_unique(GTK_TYPE_DRAWING_AREA, &curve_info);
90 sizeof (GtkCurveClass), 91 }
91 (GtkClassInitFunc) gtk_curve_class_init, 92 return curve_type;
92 (GtkObjectInitFunc) gtk_curve_init, 93 }
93 /* reserved_1 */ NULL, 94
94 /* reserved_2 */ NULL, 95 static void gtk_curve_class_init(GtkCurveClass * class)
95 (GtkClassInitFunc) NULL, 96 {
96 }; 97 GtkObjectClass *object_class;
97 98
98 curve_type = gtk_type_unique (GTK_TYPE_DRAWING_AREA, &curve_info); 99 parent_class = gtk_type_class(GTK_TYPE_DRAWING_AREA);
99 } 100
100 return curve_type; 101 object_class = (GtkObjectClass *) class;
101 } 102
102 103 object_class->set_arg = gtk_curve_set_arg;
103 static void 104 object_class->get_arg = gtk_curve_get_arg;
104 gtk_curve_class_init (GtkCurveClass *class) 105 object_class->finalize = gtk_curve_finalize;
105 { 106
106 GtkObjectClass *object_class; 107 curve_type_changed_signal =
107 108 gtk_signal_new("curve_type_changed", GTK_RUN_FIRST, object_class->type,
108 parent_class = gtk_type_class (GTK_TYPE_DRAWING_AREA); 109 GTK_SIGNAL_OFFSET(GtkCurveClass, curve_type_changed),
109 110 gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
110 object_class = (GtkObjectClass *) class; 111 gtk_object_class_add_signals(object_class, &curve_type_changed_signal, 1);
111 112
112 object_class->set_arg = gtk_curve_set_arg; 113 gtk_object_add_arg_type("GtkCurve::curve_type", GTK_TYPE_CURVE_TYPE, GTK_ARG_READWRITE, ARG_CURVE_TYPE);
113 object_class->get_arg = gtk_curve_get_arg; 114 gtk_object_add_arg_type("GtkCurve::min_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_X);
114 object_class->finalize = gtk_curve_finalize; 115 gtk_object_add_arg_type("GtkCurve::max_x", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_X);
115 116 gtk_object_add_arg_type("GtkCurve::min_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MIN_Y);
116 curve_type_changed_signal = 117 gtk_object_add_arg_type("GtkCurve::max_y", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_MAX_Y);
117 gtk_signal_new ("curve_type_changed", GTK_RUN_FIRST, object_class->type, 118 }
118 GTK_SIGNAL_OFFSET (GtkCurveClass, curve_type_changed), 119
119 gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); 120 static void gtk_curve_init(GtkCurve * curve)
120 gtk_object_class_add_signals (object_class, &curve_type_changed_signal, 1); 121 {
121 122 gint old_mask;
122 gtk_object_add_arg_type ("GtkCurve::curve_type", GTK_TYPE_CURVE_TYPE, 123
123 GTK_ARG_READWRITE, ARG_CURVE_TYPE); 124 curve->cursor_type = GDK_TOP_LEFT_ARROW;
124 gtk_object_add_arg_type ("GtkCurve::min_x", GTK_TYPE_FLOAT, 125 curve->pixmap = NULL;
125 GTK_ARG_READWRITE, ARG_MIN_X); 126 curve->curve_type = GTK_CURVE_TYPE_SPLINE;
126 gtk_object_add_arg_type ("GtkCurve::max_x", GTK_TYPE_FLOAT, 127 curve->height = 0;
127 GTK_ARG_READWRITE, ARG_MAX_X); 128 curve->grab_point = -1;
128 gtk_object_add_arg_type ("GtkCurve::min_y", GTK_TYPE_FLOAT, 129
129 GTK_ARG_READWRITE, ARG_MIN_Y); 130 curve->num_points = 0;
130 gtk_object_add_arg_type ("GtkCurve::max_y", GTK_TYPE_FLOAT, 131 curve->point = 0;
131 GTK_ARG_READWRITE, ARG_MAX_Y); 132
132 } 133 curve->num_ctlpoints = 0;
133 134 curve->ctlpoint = NULL;
134 static void 135
135 gtk_curve_init (GtkCurve *curve) 136 curve->min_x = 0.0;
136 { 137 curve->max_x = 1.0;
137 gint old_mask; 138 curve->min_y = 0.0;
138 139 curve->max_y = 1.0;
139 curve->cursor_type = GDK_TOP_LEFT_ARROW; 140
140 curve->pixmap = NULL; 141 old_mask = gtk_widget_get_events(GTK_WIDGET(curve));
141 curve->curve_type = GTK_CURVE_TYPE_SPLINE; 142 gtk_widget_set_events(GTK_WIDGET(curve), old_mask | GRAPH_MASK);
142 curve->height = 0; 143 gtk_signal_connect(GTK_OBJECT(curve), "event", (GtkSignalFunc) gtk_curve_graph_events, curve);
143 curve->grab_point = -1; 144 gtk_curve_size_graph(curve);
144 145 }
145 curve->num_points = 0; 146
146 curve->point = 0; 147 static void gtk_curve_set_arg(GtkObject * object, GtkArg * arg, guint arg_id)
147 148 {
148 curve->num_ctlpoints = 0; 149 GtkCurve *curve = GTK_CURVE(object);
149 curve->ctlpoint = NULL; 150
150 151 switch (arg_id) {
151 curve->min_x = 0.0; 152 case ARG_CURVE_TYPE:
152 curve->max_x = 1.0; 153 gtk_curve_set_curve_type(curve, GTK_VALUE_ENUM(*arg));
153 curve->min_y = 0.0; 154 break;
154 curve->max_y = 1.0; 155 case ARG_MIN_X:
155 156 gtk_curve_set_range(curve, GTK_VALUE_FLOAT(*arg), curve->max_x, curve->min_y, curve->max_y);
156 old_mask = gtk_widget_get_events (GTK_WIDGET (curve)); 157 break;
157 gtk_widget_set_events (GTK_WIDGET (curve), old_mask | GRAPH_MASK); 158 case ARG_MAX_X:
158 gtk_signal_connect (GTK_OBJECT (curve), "event", 159 gtk_curve_set_range(curve, curve->min_x, GTK_VALUE_FLOAT(*arg), curve->min_y, curve->max_y);
159 (GtkSignalFunc) gtk_curve_graph_events, curve); 160 break;
160 gtk_curve_size_graph (curve); 161 case ARG_MIN_Y:
161 } 162 gtk_curve_set_range(curve, curve->min_x, curve->max_x, GTK_VALUE_FLOAT(*arg), curve->max_y);
162 163 break;
163 static void 164 case ARG_MAX_Y:
164 gtk_curve_set_arg (GtkObject *object, 165 gtk_curve_set_range(curve, curve->min_x, curve->max_x, curve->min_y, GTK_VALUE_FLOAT(*arg));
165 GtkArg *arg, 166 break;
166 guint arg_id) 167 }
167 { 168 }
168 GtkCurve *curve = GTK_CURVE (object); 169
169 170 static void gtk_curve_get_arg(GtkObject * object, GtkArg * arg, guint arg_id)
170 switch (arg_id) 171 {
171 { 172 GtkCurve *curve = GTK_CURVE(object);
172 case ARG_CURVE_TYPE: 173
173 gtk_curve_set_curve_type (curve, GTK_VALUE_ENUM (*arg)); 174 switch (arg_id) {
174 break; 175 case ARG_CURVE_TYPE:
175 case ARG_MIN_X: 176 GTK_VALUE_ENUM(*arg) = curve->curve_type;
176 gtk_curve_set_range (curve, GTK_VALUE_FLOAT (*arg), curve->max_x, 177 break;
177 curve->min_y, curve->max_y); 178 case ARG_MIN_X:
178 break; 179 GTK_VALUE_FLOAT(*arg) = curve->min_x;
179 case ARG_MAX_X: 180 break;
180 gtk_curve_set_range (curve, curve->min_x, GTK_VALUE_FLOAT (*arg), 181 case ARG_MAX_X:
181 curve->min_y, curve->max_y); 182 GTK_VALUE_FLOAT(*arg) = curve->max_x;
182 break; 183 break;
183 case ARG_MIN_Y: 184 case ARG_MIN_Y:
184 gtk_curve_set_range (curve, curve->min_x, curve->max_x, 185 GTK_VALUE_FLOAT(*arg) = curve->min_y;
185 GTK_VALUE_FLOAT (*arg), curve->max_y); 186 break;
186 break; 187 case ARG_MAX_Y:
187 case ARG_MAX_Y: 188 GTK_VALUE_FLOAT(*arg) = curve->max_y;
188 gtk_curve_set_range (curve, curve->min_x, curve->max_x, 189 break;
189 curve->min_y, GTK_VALUE_FLOAT (*arg)); 190 default:
190 break; 191 arg->type = GTK_TYPE_INVALID;
191 } 192 break;
192 } 193 }
193 194 }
194 static void 195
195 gtk_curve_get_arg (GtkObject *object, 196 static int project(gfloat value, gfloat min, gfloat max, int norm)
196 GtkArg *arg, 197 {
197 guint arg_id) 198 return (norm - 1) * ((value - min) / (max - min)) + 0.5;
198 { 199 }
199 GtkCurve *curve = GTK_CURVE (object); 200
200 201 static gfloat unproject(gint value, gfloat min, gfloat max, int norm)
201 switch (arg_id) 202 {
202 { 203 return value / (gfloat) (norm - 1) * (max - min) + min;
203 case ARG_CURVE_TYPE:
204 GTK_VALUE_ENUM (*arg) = curve->curve_type;
205 break;
206 case ARG_MIN_X:
207 GTK_VALUE_FLOAT (*arg) = curve->min_x;
208 break;
209 case ARG_MAX_X:
210 GTK_VALUE_FLOAT (*arg) = curve->max_x;
211 break;
212 case ARG_MIN_Y:
213 GTK_VALUE_FLOAT (*arg) = curve->min_y;
214 break;
215 case ARG_MAX_Y:
216 GTK_VALUE_FLOAT (*arg) = curve->max_y;
217 break;
218 default:
219 arg->type = GTK_TYPE_INVALID;
220 break;
221 }
222 }
223
224 static int
225 project (gfloat value, gfloat min, gfloat max, int norm)
226 {
227 return (norm - 1) * ((value - min) / (max - min)) + 0.5;
228 }
229
230 static gfloat
231 unproject (gint value, gfloat min, gfloat max, int norm)
232 {
233 return value / (gfloat) (norm - 1) * (max - min) + min;
234 } 204 }
235 205
236 /* Solve the tridiagonal equation system that determines the second 206 /* Solve the tridiagonal equation system that determines the second
237 derivatives for the interpolation points. (Based on Numerical 207 derivatives for the interpolation points. (Based on Numerical
238 Recipies 2nd Edition.) */ 208 Recipies 2nd Edition.) */
239 static void 209 static void spline_solve(int n, gfloat x[], gfloat y[], gfloat y2[])
240 spline_solve (int n, gfloat x[], gfloat y[], gfloat y2[]) 210 {
241 { 211 gfloat p, sig, *u;
242 gfloat p, sig, *u; 212 gint i, k;
243 gint i, k; 213
244 214 u = g_malloc((n - 1) * sizeof(u[0]));
245 u = g_malloc ((n - 1) * sizeof (u[0])); 215
246 216 y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */
247 y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */ 217
248 218 for (i = 1; i < n - 1; ++i) {
249 for (i = 1; i < n - 1; ++i) 219 sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
250 { 220 p = sig * y2[i - 1] + 2.0;
251 sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); 221 y2[i] = (sig - 1.0) / p;
252 p = sig * y2[i - 1] + 2.0; 222 u[i] = ((y[i + 1] - y[i])
253 y2[i] = (sig - 1.0) / p; 223 / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]));
254 u[i] = ((y[i + 1] - y[i]) 224 u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
255 / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1])); 225 }
256 u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; 226
257 } 227 y2[n - 1] = 0.0;
258 228 for (k = n - 2; k >= 0; --k)
259 y2[n - 1] = 0.0; 229 y2[k] = y2[k] * y2[k + 1] + u[k];
260 for (k = n - 2; k >= 0; --k) 230
261 y2[k] = y2[k] * y2[k + 1] + u[k]; 231 g_free(u);
262 232 }
263 g_free (u); 233
264 } 234 static gfloat spline_eval(int n, gfloat x[], gfloat y[], gfloat y2[], gfloat val)
265 235 {
266 static gfloat 236 gint k_lo, k_hi, k;
267 spline_eval (int n, gfloat x[], gfloat y[], gfloat y2[], gfloat val) 237 gfloat h, b, a;
268 { 238
269 gint k_lo, k_hi, k; 239 /* do a binary search for the right interval: */
270 gfloat h, b, a; 240 k_lo = 0;
271 241 k_hi = n - 1;
272 /* do a binary search for the right interval: */ 242 while (k_hi - k_lo > 1) {
273 k_lo = 0; k_hi = n - 1; 243 k = (k_hi + k_lo) / 2;
274 while (k_hi - k_lo > 1) 244 if (x[k] > val)
275 { 245 k_hi = k;
276 k = (k_hi + k_lo) / 2; 246 else
277 if (x[k] > val) 247 k_lo = k;
278 k_hi = k; 248 }
279 else 249
280 k_lo = k; 250 h = x[k_hi] - x[k_lo];
281 } 251 g_assert(h > 0.0);
282 252
283 h = x[k_hi] - x[k_lo]; 253 a = (x[k_hi] - val) / h;
284 g_assert (h > 0.0); 254 b = (val - x[k_lo]) / h;
285 255 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;
286 a = (x[k_hi] - val) / h; 256 }
287 b = (val - x[k_lo]) / h; 257
288 return a*y[k_lo] + b*y[k_hi] + 258 static void gtk_curve_interpolate(GtkCurve * c, gint width, gint height)
289 ((a*a*a - a)*y2[k_lo] + (b*b*b - b)*y2[k_hi]) * (h*h)/6.0; 259 {
290 } 260 gfloat *vector;
291 261 int i;
292 static void 262
293 gtk_curve_interpolate (GtkCurve *c, gint width, gint height) 263 vector = g_malloc(width * sizeof(vector[0]));
294 { 264
295 gfloat *vector; 265 gtk_curve_get_vector(c, width, vector);
296 int i; 266
297 267 c->height = height;
298 vector = g_malloc (width * sizeof (vector[0])); 268 if (c->num_points != width) {
299 269 c->num_points = width;
300 gtk_curve_get_vector (c, width, vector); 270 if (c->point)
301 271 g_free(c->point);
302 c->height = height; 272 c->point = g_malloc(c->num_points * sizeof(c->point[0]));
303 if (c->num_points != width) 273 }
304 { 274
305 c->num_points = width; 275 for (i = 0; i < width; ++i) {
306 if (c->point) 276 c->point[i].x = RADIUS + i;
307 g_free (c->point); 277 c->point[i].y = RADIUS + height - project(vector[i], c->min_y, c->max_y, height);
308 c->point = g_malloc (c->num_points * sizeof (c->point[0])); 278 }
309 } 279
310 280 g_free(vector);
311 for (i = 0; i < width; ++i) 281 }
312 { 282
313 c->point[i].x = RADIUS + i; 283 static void gtk_curve_draw(GtkCurve * c, gint width, gint height)
314 c->point[i].y = RADIUS + height 284 {
315 - project (vector[i], c->min_y, c->max_y, height); 285 GtkStateType state;
316 } 286 GtkStyle *style;
317 287 gint i;
318 g_free (vector); 288
319 } 289 if (!c->pixmap)
320 290 return;
321 static void 291
322 gtk_curve_draw (GtkCurve *c, gint width, gint height) 292 if (c->height != height || c->num_points != width)
323 { 293 gtk_curve_interpolate(c, width, height);
324 GtkStateType state; 294
325 GtkStyle *style; 295 state = GTK_STATE_NORMAL;
326 gint i; 296 if (!GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(c)))
327 297 state = GTK_STATE_INSENSITIVE;
328 if (!c->pixmap) 298
329 return; 299 style = GTK_WIDGET(c)->style;
330 300
331 if (c->height != height || c->num_points != width) 301 /* clear the pixmap: */
332 gtk_curve_interpolate (c, width, height); 302 gtk_paint_flat_box(style, c->pixmap, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
333 303 NULL, GTK_WIDGET(c), "curve_bg", 0, 0, width + RADIUS * 2, height + RADIUS * 2);
334 state = GTK_STATE_NORMAL; 304 /* draw the grid lines: (XXX make more meaningful) */
335 if (!GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (c))) 305 for (i = 0; i < 5; i++) {
336 state = GTK_STATE_INSENSITIVE; 306 gdk_draw_line(c->pixmap, style->dark_gc[state],
337 307 RADIUS, i * (height / 4.0) + RADIUS, width + RADIUS, i * (height / 4.0) + RADIUS);
338 style = GTK_WIDGET (c)->style; 308 gdk_draw_line(c->pixmap, style->dark_gc[state],
339 309 i * (width / 4.0) + RADIUS, RADIUS, i * (width / 4.0) + RADIUS, height + RADIUS);
340 /* clear the pixmap: */ 310 }
341 gtk_paint_flat_box (style, c->pixmap, GTK_STATE_NORMAL, GTK_SHADOW_NONE, 311
342 NULL, GTK_WIDGET(c), "curve_bg", 312 gdk_draw_points(c->pixmap, style->fg_gc[state], c->point, c->num_points);
343 0, 0, width + RADIUS * 2, height + RADIUS * 2); 313 if (c->curve_type != GTK_CURVE_TYPE_FREE)
344 /* draw the grid lines: (XXX make more meaningful) */ 314 for (i = 0; i < c->num_ctlpoints; ++i) {
345 for (i = 0; i < 5; i++) 315 gint x, y;
346 { 316
347 gdk_draw_line (c->pixmap, style->dark_gc[state], 317 if (c->ctlpoint[i][0] < c->min_x)
348 RADIUS, i * (height / 4.0) + RADIUS, 318 continue;
349 width + RADIUS, i * (height / 4.0) + RADIUS); 319
350 gdk_draw_line (c->pixmap, style->dark_gc[state], 320 x = project(c->ctlpoint[i][0], c->min_x, c->max_x, width);
351 i * (width / 4.0) + RADIUS, RADIUS, 321 y = height - project(c->ctlpoint[i][1], c->min_y, c->max_y, height);
352 i * (width / 4.0) + RADIUS, height + RADIUS); 322
353 } 323 /* draw a bullet: */
354 324 gdk_draw_arc(c->pixmap, style->fg_gc[state], TRUE, x, y, RADIUS * 2, RADIUS * 2, 0, 360 * 64);
355 gdk_draw_points (c->pixmap, style->fg_gc[state], c->point, c->num_points); 325 }
356 if (c->curve_type != GTK_CURVE_TYPE_FREE) 326 gdk_draw_pixmap(GTK_WIDGET(c)->window, style->fg_gc[state], c->pixmap,
357 for (i = 0; i < c->num_ctlpoints; ++i) 327 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2);
358 { 328 }
359 gint x, y; 329
360 330 static gint gtk_curve_graph_events(GtkWidget * widget, GdkEvent * event, GtkCurve * c)
361 if (c->ctlpoint[i][0] < c->min_x) 331 {
362 continue; 332 GdkCursorType new_type = c->cursor_type;
363 333 gint i, src, dst, leftbound, rightbound;
364 x = project (c->ctlpoint[i][0], c->min_x, c->max_x, 334 GdkEventButton *bevent;
365 width); 335 GdkEventMotion *mevent;
366 y = height - 336 GtkWidget *w;
367 project (c->ctlpoint[i][1], c->min_y, c->max_y, 337 gint tx, ty;
368 height); 338 gint cx, x, y, width, height;
369 339 gint closest_point = 0;
370 /* draw a bullet: */ 340 gfloat rx, ry, min_x;
371 gdk_draw_arc (c->pixmap, style->fg_gc[state], TRUE, x, y, 341 guint distance;
372 RADIUS * 2, RADIUS*2, 0, 360*64); 342 gint x1, x2, y1, y2;
373 } 343
374 gdk_draw_pixmap (GTK_WIDGET (c)->window, style->fg_gc[state], c->pixmap, 344 w = GTK_WIDGET(c);
375 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2); 345 width = w->allocation.width - RADIUS * 2;
376 } 346 height = w->allocation.height - RADIUS * 2;
377 347
378 static gint 348 if ((width < 0) || (height < 0))
379 gtk_curve_graph_events (GtkWidget *widget, GdkEvent *event, GtkCurve *c) 349 return FALSE;
380 { 350
381 GdkCursorType new_type = c->cursor_type; 351 /* get the pointer position */
382 gint i, src, dst, leftbound, rightbound; 352 gdk_window_get_pointer(w->window, &tx, &ty, NULL);
383 GdkEventButton *bevent; 353 x = CLAMP((tx - RADIUS), 0, width - 1);
384 GdkEventMotion *mevent; 354 y = CLAMP((ty - RADIUS), 0, height - 1);
385 GtkWidget *w; 355
386 gint tx, ty; 356 min_x = c->min_x;
387 gint cx, x, y, width, height; 357
388 gint closest_point = 0; 358 distance = ~0U;
389 gfloat rx, ry, min_x; 359 for (i = 0; i < c->num_ctlpoints; ++i) {
390 guint distance; 360 cx = project(c->ctlpoint[i][0], min_x, c->max_x, width);
391 gint x1, x2, y1, y2; 361 if ((guint) abs(x - cx) < distance) {
392 362 distance = abs(x - cx);
393 w = GTK_WIDGET (c); 363 closest_point = i;
394 width = w->allocation.width - RADIUS * 2; 364 }
395 height = w->allocation.height - RADIUS * 2; 365 }
396 366
397 if ((width < 0) || (height < 0)) 367 switch (event->type) {
398 return FALSE; 368 case GDK_CONFIGURE:
399 369 if (c->pixmap)
400 /* get the pointer position */ 370 gdk_pixmap_unref(c->pixmap);
401 gdk_window_get_pointer (w->window, &tx, &ty, NULL); 371 c->pixmap = 0;
402 x = CLAMP ((tx - RADIUS), 0, width-1); 372 /* fall through */
403 y = CLAMP ((ty - RADIUS), 0, height-1); 373 case GDK_EXPOSE:
404 374 if (!c->pixmap)
405 min_x = c->min_x; 375 c->pixmap = gdk_pixmap_new(w->window, w->allocation.width, w->allocation.height, -1);
406 376 gtk_curve_draw(c, width, height);
407 distance = ~0U; 377 break;
408 for (i = 0; i < c->num_ctlpoints; ++i) 378
409 { 379 case GDK_BUTTON_PRESS:
410 cx = project (c->ctlpoint[i][0], min_x, c->max_x, width); 380 gtk_grab_add(widget);
411 if ((guint) abs (x - cx) < distance) 381
412 { 382 bevent = (GdkEventButton *) event;
413 distance = abs (x - cx); 383 new_type = GDK_TCROSS;
414 closest_point = i; 384
415 } 385 switch (c->curve_type) {
416 } 386 case GTK_CURVE_TYPE_LINEAR:
417 387 case GTK_CURVE_TYPE_SPLINE:
418 switch (event->type) 388 if (distance > MIN_DISTANCE) {
419 { 389 /* insert a new control point */
420 case GDK_CONFIGURE: 390 if (c->num_ctlpoints > 0) {
421 if (c->pixmap) 391 cx = project(c->ctlpoint[closest_point][0], min_x, c->max_x, width);
422 gdk_pixmap_unref (c->pixmap); 392 if (x > cx)
423 c->pixmap = 0; 393 ++closest_point;
424 /* fall through */ 394 }
425 case GDK_EXPOSE: 395 ++c->num_ctlpoints;
426 if (!c->pixmap) 396 c->ctlpoint = g_realloc(c->ctlpoint, c->num_ctlpoints * sizeof(*c->ctlpoint));
427 c->pixmap = gdk_pixmap_new (w->window, 397 for (i = c->num_ctlpoints - 1; i > closest_point; --i)
428 w->allocation.width, 398 memcpy(c->ctlpoint + i, c->ctlpoint + i - 1, sizeof(*c->ctlpoint));
429 w->allocation.height, -1); 399 }
430 gtk_curve_draw (c, width, height); 400 c->grab_point = closest_point;
431 break; 401 c->ctlpoint[c->grab_point][0] = unproject(x, min_x, c->max_x, width);
432 402 c->ctlpoint[c->grab_point][1] = unproject(height - y, c->min_y, c->max_y, height);
433 case GDK_BUTTON_PRESS: 403
434 gtk_grab_add (widget); 404 gtk_curve_interpolate(c, width, height);
435 405 break;
436 bevent = (GdkEventButton *) event; 406
437 new_type = GDK_TCROSS; 407 case GTK_CURVE_TYPE_FREE:
438 408 c->point[x].x = RADIUS + x;
439 switch (c->curve_type) 409 c->point[x].y = RADIUS + y;
440 { 410 c->grab_point = x;
411 c->last = y;
412 break;
413 }
414 gtk_curve_draw(c, width, height);
415 break;
416
417 case GDK_BUTTON_RELEASE:
418 gtk_grab_remove(widget);
419
420 /* delete inactive points: */
421 if (c->curve_type != GTK_CURVE_TYPE_FREE) {
422 for (src = dst = 0; src < c->num_ctlpoints; ++src) {
423 if (c->ctlpoint[src][0] >= min_x) {
424 memcpy(c->ctlpoint + dst, c->ctlpoint + src, sizeof(*c->ctlpoint));
425 ++dst;
426 }
427 }
428 if (dst < src) {
429 c->num_ctlpoints -= (src - dst);
430 if (c->num_ctlpoints <= 0) {
431 c->num_ctlpoints = 1;
432 c->ctlpoint[0][0] = min_x;
433 c->ctlpoint[0][1] = c->min_y;
434 gtk_curve_interpolate(c, width, height);
435 gtk_curve_draw(c, width, height);
436 }
437 c->ctlpoint = g_realloc(c->ctlpoint, c->num_ctlpoints * sizeof(*c->ctlpoint));
438 }
439 }
440 new_type = GDK_FLEUR;
441 c->grab_point = -1;
442 break;
443
444 case GDK_MOTION_NOTIFY:
445 mevent = (GdkEventMotion *) event;
446
447 switch (c->curve_type) {
448 case GTK_CURVE_TYPE_LINEAR:
449 case GTK_CURVE_TYPE_SPLINE:
450 if (c->grab_point == -1) {
451 /* if no point is grabbed... */
452 if (distance <= MIN_DISTANCE)
453 new_type = GDK_FLEUR;
454 else
455 new_type = GDK_TCROSS;
456 } else {
457 /* drag the grabbed point */
458 new_type = GDK_TCROSS;
459
460 leftbound = -MIN_DISTANCE;
461 if (c->grab_point > 0)
462 leftbound = project(c->ctlpoint[c->grab_point - 1][0], min_x, c->max_x, width);
463
464 rightbound = width + RADIUS * 2 + MIN_DISTANCE;
465 if (c->grab_point + 1 < c->num_ctlpoints)
466 rightbound = project(c->ctlpoint[c->grab_point + 1][0], min_x, c->max_x, width);
467
468 if (tx <= leftbound || tx >= rightbound
469 || ty > height + RADIUS * 2 + MIN_DISTANCE || ty < -MIN_DISTANCE)
470 c->ctlpoint[c->grab_point][0] = min_x - 1.0;
471 else {
472 rx = unproject(x, min_x, c->max_x, width);
473 ry = unproject(height - y, c->min_y, c->max_y, height);
474 c->ctlpoint[c->grab_point][0] = rx;
475 c->ctlpoint[c->grab_point][1] = ry;
476 }
477 gtk_curve_interpolate(c, width, height);
478 gtk_curve_draw(c, width, height);
479 }
480 break;
481
482 case GTK_CURVE_TYPE_FREE:
483 if (c->grab_point != -1) {
484 if (c->grab_point > x) {
485 x1 = x;
486 x2 = c->grab_point;
487 y1 = y;
488 y2 = c->last;
489 } else {
490 x1 = c->grab_point;
491 x2 = x;
492 y1 = c->last;
493 y2 = y;
494 }
495
496 if (x2 != x1)
497 for (i = x1; i <= x2; i++) {
498 c->point[i].x = RADIUS + i;
499 c->point[i].y = RADIUS + (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1));
500 } else {
501 c->point[x].x = RADIUS + x;
502 c->point[x].y = RADIUS + y;
503 }
504 c->grab_point = x;
505 c->last = y;
506 gtk_curve_draw(c, width, height);
507 }
508 if (mevent->state & GDK_BUTTON1_MASK)
509 new_type = GDK_TCROSS;
510 else
511 new_type = GDK_PENCIL;
512 break;
513 }
514 if (new_type != (GdkCursorType) c->cursor_type) {
515 GdkCursor *cursor;
516
517 c->cursor_type = new_type;
518
519 cursor = gdk_cursor_new(c->cursor_type);
520 gdk_window_set_cursor(w->window, cursor);
521 gdk_cursor_destroy(cursor);
522 }
523 break;
524
525 default:
526 break;
527 }
528 return FALSE;
529 }
530
531 void gtk_curve_set_curve_type(GtkCurve * c, GtkCurveType new_type)
532 {
533 gfloat rx, dx;
534 gint x, i;
535
536 if (new_type != c->curve_type) {
537 gint width, height;
538
539 width = GTK_WIDGET(c)->allocation.width - RADIUS * 2;
540 height = GTK_WIDGET(c)->allocation.height - RADIUS * 2;
541
542 if (new_type == GTK_CURVE_TYPE_FREE) {
543 gtk_curve_interpolate(c, width, height);
544 c->curve_type = new_type;
545 } else if (c->curve_type == GTK_CURVE_TYPE_FREE) {
546 if (c->ctlpoint)
547 g_free(c->ctlpoint);
548 c->num_ctlpoints = 9;
549 c->ctlpoint = g_malloc(c->num_ctlpoints * sizeof(*c->ctlpoint));
550
551 rx = 0.0;
552 dx = (width - 1) / (gfloat) (c->num_ctlpoints - 1);
553
554 for (i = 0; i < c->num_ctlpoints; ++i, rx += dx) {
555 x = (int) (rx + 0.5);
556 c->ctlpoint[i][0] = unproject(x, c->min_x, c->max_x, width);
557 c->ctlpoint[i][1] =
558 unproject(RADIUS + height - c->point[x].y, c->min_y, c->max_y, height);
559 }
560 c->curve_type = new_type;
561 gtk_curve_interpolate(c, width, height);
562 } else {
563 c->curve_type = new_type;
564 gtk_curve_interpolate(c, width, height);
565 }
566 gtk_signal_emit(GTK_OBJECT(c), curve_type_changed_signal);
567 gtk_curve_draw(c, width, height);
568 }
569 }
570
571 static void gtk_curve_size_graph(GtkCurve * curve)
572 {
573 gint width, height;
574 gfloat aspect;
575
576 width = (curve->max_x - curve->min_x) + 1;
577 height = (curve->max_y - curve->min_y) + 1;
578 aspect = width / (gfloat) height;
579 if (width > gdk_screen_width() / 4)
580 width = gdk_screen_width() / 4;
581 if (height > gdk_screen_height() / 4)
582 height = gdk_screen_height() / 4;
583
584 if (aspect < 1.0)
585 width = height * aspect;
586 else
587 height = width / aspect;
588
589 gtk_drawing_area_size(GTK_DRAWING_AREA(curve), width + RADIUS * 2, height + RADIUS * 2);
590 }
591
592 static void gtk_curve_reset_vector(GtkCurve * curve)
593 {
594 if (curve->ctlpoint)
595 g_free(curve->ctlpoint);
596
597 curve->num_ctlpoints = 2;
598 curve->ctlpoint = g_malloc(2 * sizeof(curve->ctlpoint[0]));
599 curve->ctlpoint[0][0] = curve->min_x;
600 curve->ctlpoint[0][1] = curve->min_y;
601 curve->ctlpoint[1][0] = curve->max_x;
602 curve->ctlpoint[1][1] = curve->max_y;
603
604 if (curve->pixmap) {
605 gint width, height;
606
607 width = GTK_WIDGET(curve)->allocation.width - RADIUS * 2;
608 height = GTK_WIDGET(curve)->allocation.height - RADIUS * 2;
609
610 if (curve->curve_type == GTK_CURVE_TYPE_FREE) {
611 curve->curve_type = GTK_CURVE_TYPE_LINEAR;
612 gtk_curve_interpolate(curve, width, height);
613 curve->curve_type = GTK_CURVE_TYPE_FREE;
614 } else
615 gtk_curve_interpolate(curve, width, height);
616 gtk_curve_draw(curve, width, height);
617 }
618 }
619
620 void gtk_curve_reset(GtkCurve * c)
621 {
622 GtkCurveType old_type;
623
624 old_type = c->curve_type;
625 c->curve_type = GTK_CURVE_TYPE_SPLINE;
626 gtk_curve_reset_vector(c);
627
628 if (old_type != GTK_CURVE_TYPE_SPLINE)
629 gtk_signal_emit(GTK_OBJECT(c), curve_type_changed_signal);
630 }
631
632 void gtk_curve_set_gamma(GtkCurve * c, gfloat gamma)
633 {
634 gfloat x, one_over_gamma, height, one_over_width;
635 GtkCurveType old_type;
636 gint i;
637
638 if (c->num_points < 2)
639 return;
640
641 old_type = c->curve_type;
642 c->curve_type = GTK_CURVE_TYPE_FREE;
643
644 if (gamma <= 0)
645 one_over_gamma = 1.0;
646 else
647 one_over_gamma = 1.0 / gamma;
648 one_over_width = 1.0 / (c->num_points - 1);
649 height = c->height;
650 for (i = 0; i < c->num_points; ++i) {
651 x = (gfloat) i / (c->num_points - 1);
652 c->point[i].x = RADIUS + i;
653 c->point[i].y = RADIUS + (height * (1.0 - pow(x, one_over_gamma)) + 0.5);
654 }
655
656 if (old_type != GTK_CURVE_TYPE_FREE)
657 gtk_signal_emit(GTK_OBJECT(c), curve_type_changed_signal);
658
659 gtk_curve_draw(c, c->num_points, c->height);
660 }
661
662 void gtk_curve_set_range(GtkCurve * curve, gfloat min_x, gfloat max_x, gfloat min_y, gfloat max_y)
663 {
664 curve->min_x = min_x;
665 curve->max_x = max_x;
666 curve->min_y = min_y;
667 curve->max_y = max_y;
668
669 gtk_curve_size_graph(curve);
670 gtk_curve_reset_vector(curve);
671 }
672
673 void gtk_curve_set_vector(GtkCurve * c, int veclen, gfloat vector[])
674 {
675 GtkCurveType old_type;
676 gfloat rx, dx, ry;
677 gint i, height;
678
679 old_type = c->curve_type;
680 c->curve_type = GTK_CURVE_TYPE_FREE;
681
682 if (c->point)
683 height = GTK_WIDGET(c)->allocation.height - RADIUS * 2;
684 else {
685 height = (c->max_y - c->min_y);
686 if (height > gdk_screen_height() / 4)
687 height = gdk_screen_height() / 4;
688
689 c->height = height;
690 c->num_points = veclen;
691 c->point = g_malloc(c->num_points * sizeof(c->point[0]));
692 }
693 rx = 0;
694 dx = (veclen - 1.0) / (c->num_points - 1.0);
695
696 for (i = 0; i < c->num_points; ++i, rx += dx) {
697 ry = vector[(int) (rx + 0.5)];
698 if (ry > c->max_y)
699 ry = c->max_y;
700 if (ry < c->min_y)
701 ry = c->min_y;
702 c->point[i].x = RADIUS + i;
703 c->point[i].y = RADIUS + height - project(ry, c->min_y, c->max_y, height);
704 }
705 if (old_type != GTK_CURVE_TYPE_FREE)
706 gtk_signal_emit(GTK_OBJECT(c), curve_type_changed_signal);
707
708 gtk_curve_draw(c, c->num_points, height);
709 }
710
711 void gtk_curve_get_vector(GtkCurve * c, int veclen, gfloat vector[])
712 {
713 gfloat rx, ry, dx, dy, min_x, delta_x, *mem, *xv, *yv, *y2v, prev;
714 gint dst, i, x, next, num_active_ctlpoints = 0, first_active = -1;
715
716 min_x = c->min_x;
717
718 if (c->curve_type != GTK_CURVE_TYPE_FREE) {
719 /* count active points: */
720 prev = min_x - 1.0;
721 for (i = num_active_ctlpoints = 0; i < c->num_ctlpoints; ++i)
722 if (c->ctlpoint[i][0] > prev) {
723 if (first_active < 0)
724 first_active = i;
725 prev = c->ctlpoint[i][0];
726 ++num_active_ctlpoints;
727 }
728
729 /* handle degenerate case: */
730 if (num_active_ctlpoints < 2) {
731 if (num_active_ctlpoints > 0)
732 ry = c->ctlpoint[first_active][1];
733 else
734 ry = c->min_y;
735 if (ry < c->min_y)
736 ry = c->min_y;
737 if (ry > c->max_y)
738 ry = c->max_y;
739 for (x = 0; x < veclen; ++x)
740 vector[x] = ry;
741 return;
742 }
743 }
744
745 switch (c->curve_type) {
746 case GTK_CURVE_TYPE_SPLINE:
747 mem = g_malloc(3 * num_active_ctlpoints * sizeof(gfloat));
748 xv = mem;
749 yv = mem + num_active_ctlpoints;
750 y2v = mem + 2 * num_active_ctlpoints;
751
752 prev = min_x - 1.0;
753 for (i = dst = 0; i < c->num_ctlpoints; ++i)
754 if (c->ctlpoint[i][0] > prev) {
755 prev = c->ctlpoint[i][0];
756 xv[dst] = c->ctlpoint[i][0];
757 yv[dst] = c->ctlpoint[i][1];
758 ++dst;
759 }
760
761 spline_solve(num_active_ctlpoints, xv, yv, y2v);
762
763 rx = min_x;
764 dx = (c->max_x - min_x) / (veclen - 1);
765 for (x = 0; x < veclen; ++x, rx += dx) {
766 ry = spline_eval(num_active_ctlpoints, xv, yv, y2v, rx);
767 if (ry < c->min_y)
768 ry = c->min_y;
769 if (ry > c->max_y)
770 ry = c->max_y;
771 vector[x] = ry;
772 }
773
774 g_free(mem);
775 break;
776
441 case GTK_CURVE_TYPE_LINEAR: 777 case GTK_CURVE_TYPE_LINEAR:
442 case GTK_CURVE_TYPE_SPLINE: 778 dx = (c->max_x - min_x) / (veclen - 1);
443 if (distance > MIN_DISTANCE) 779 rx = min_x;
444 { 780 ry = c->min_y;
445 /* insert a new control point */ 781 dy = 0.0;
446 if (c->num_ctlpoints > 0) 782 i = first_active;
447 { 783 for (x = 0; x < veclen; ++x, rx += dx) {
448 cx = project (c->ctlpoint[closest_point][0], min_x, 784 if (rx >= c->ctlpoint[i][0]) {
449 c->max_x, width); 785 if (rx > c->ctlpoint[i][0])
450 if (x > cx) 786 ry = c->min_y;
451 ++closest_point; 787 dy = 0.0;
452 } 788 next = i + 1;
453 ++c->num_ctlpoints; 789 while (next < c->num_ctlpoints && c->ctlpoint[next][0] <= c->ctlpoint[i][0])
454 c->ctlpoint = 790 ++next;
455 g_realloc (c->ctlpoint, 791 if (next < c->num_ctlpoints) {
456 c->num_ctlpoints * sizeof (*c->ctlpoint)); 792 delta_x = c->ctlpoint[next][0] - c->ctlpoint[i][0];
457 for (i = c->num_ctlpoints - 1; i > closest_point; --i) 793 dy = ((c->ctlpoint[next][1] - c->ctlpoint[i][1])
458 memcpy (c->ctlpoint + i, c->ctlpoint + i - 1, 794 / delta_x);
459 sizeof (*c->ctlpoint)); 795 dy *= dx;
460 } 796 ry = c->ctlpoint[i][1];
461 c->grab_point = closest_point; 797 i = next;
462 c->ctlpoint[c->grab_point][0] = 798 }
463 unproject (x, min_x, c->max_x, width); 799 }
464 c->ctlpoint[c->grab_point][1] = 800 vector[x] = ry;
465 unproject (height - y, c->min_y, c->max_y, height); 801 ry += dy;
466 802 }
467 gtk_curve_interpolate (c, width, height); 803 break;
468 break;
469 804
470 case GTK_CURVE_TYPE_FREE: 805 case GTK_CURVE_TYPE_FREE:
471 c->point[x].x = RADIUS + x; 806 if (c->point) {
472 c->point[x].y = RADIUS + y; 807 rx = 0.0;
473 c->grab_point = x; 808 dx = c->num_points / (double) veclen;
474 c->last = y; 809 for (x = 0; x < veclen; ++x, rx += dx)
475 break; 810 vector[x] = unproject(RADIUS + c->height - c->point[(int) rx].y,
476 } 811 c->min_y, c->max_y, c->height);
477 gtk_curve_draw (c, width, height); 812 } else
478 break; 813 memset(vector, 0, veclen * sizeof(vector[0]));
479 814 break;
480 case GDK_BUTTON_RELEASE: 815 }
481 gtk_grab_remove (widget); 816 }
482 817
483 /* delete inactive points: */ 818 GtkWidget *gtk_curve_new(void)
484 if (c->curve_type != GTK_CURVE_TYPE_FREE) 819 {
485 { 820 return gtk_type_new(gtk_curve_get_type());
486 for (src = dst = 0; src < c->num_ctlpoints; ++src) 821 }
487 { 822
488 if (c->ctlpoint[src][0] >= min_x) 823 static void gtk_curve_finalize(GtkObject * object)
489 { 824 {
490 memcpy (c->ctlpoint + dst, c->ctlpoint + src, 825 GtkCurve *curve;
491 sizeof (*c->ctlpoint)); 826
492 ++dst; 827 g_return_if_fail(object != NULL);
493 } 828 g_return_if_fail(GTK_IS_CURVE(object));
494 } 829
495 if (dst < src) 830 curve = GTK_CURVE(object);
496 { 831 if (curve->pixmap)
497 c->num_ctlpoints -= (src - dst); 832 gdk_pixmap_unref(curve->pixmap);
498 if (c->num_ctlpoints <= 0) 833 if (curve->point)
499 { 834 g_free(curve->point);
500 c->num_ctlpoints = 1; 835 if (curve->ctlpoint)
501 c->ctlpoint[0][0] = min_x; 836 g_free(curve->ctlpoint);
502 c->ctlpoint[0][1] = c->min_y; 837
503 gtk_curve_interpolate (c, width, height); 838 (*GTK_OBJECT_CLASS(parent_class)->finalize) (object);
504 gtk_curve_draw (c, width, height); 839 }
505 }
506 c->ctlpoint =
507 g_realloc (c->ctlpoint,
508 c->num_ctlpoints * sizeof (*c->ctlpoint));
509 }
510 }
511 new_type = GDK_FLEUR;
512 c->grab_point = -1;
513 break;
514
515 case GDK_MOTION_NOTIFY:
516 mevent = (GdkEventMotion *) event;
517
518 switch (c->curve_type)
519 {
520 case GTK_CURVE_TYPE_LINEAR:
521 case GTK_CURVE_TYPE_SPLINE:
522 if (c->grab_point == -1)
523 {
524 /* if no point is grabbed... */
525 if (distance <= MIN_DISTANCE)
526 new_type = GDK_FLEUR;
527 else
528 new_type = GDK_TCROSS;
529 }
530 else
531 {
532 /* drag the grabbed point */
533 new_type = GDK_TCROSS;
534
535 leftbound = -MIN_DISTANCE;
536 if (c->grab_point > 0)
537 leftbound = project (c->ctlpoint[c->grab_point - 1][0],
538 min_x, c->max_x, width);
539
540 rightbound = width + RADIUS * 2 + MIN_DISTANCE;
541 if (c->grab_point + 1 < c->num_ctlpoints)
542 rightbound = project (c->ctlpoint[c->grab_point + 1][0],
543 min_x, c->max_x, width);
544
545 if (tx <= leftbound || tx >= rightbound
546 || ty > height + RADIUS * 2 + MIN_DISTANCE
547 || ty < -MIN_DISTANCE)
548 c->ctlpoint[c->grab_point][0] = min_x - 1.0;
549 else
550 {
551 rx = unproject (x, min_x, c->max_x, width);
552 ry = unproject (height - y, c->min_y, c->max_y, height);
553 c->ctlpoint[c->grab_point][0] = rx;
554 c->ctlpoint[c->grab_point][1] = ry;
555 }
556 gtk_curve_interpolate (c, width, height);
557 gtk_curve_draw (c, width, height);
558 }
559 break;
560
561 case GTK_CURVE_TYPE_FREE:
562 if (c->grab_point != -1)
563 {
564 if (c->grab_point > x)
565 {
566 x1 = x;
567 x2 = c->grab_point;
568 y1 = y;
569 y2 = c->last;
570 }
571 else
572 {
573 x1 = c->grab_point;
574 x2 = x;
575 y1 = c->last;
576 y2 = y;
577 }
578
579 if (x2 != x1)
580 for (i = x1; i <= x2; i++)
581 {
582 c->point[i].x = RADIUS + i;
583 c->point[i].y = RADIUS +
584 (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1));
585 }
586 else
587 {
588 c->point[x].x = RADIUS + x;
589 c->point[x].y = RADIUS + y;
590 }
591 c->grab_point = x;
592 c->last = y;
593 gtk_curve_draw (c, width, height);
594 }
595 if (mevent->state & GDK_BUTTON1_MASK)
596 new_type = GDK_TCROSS;
597 else
598 new_type = GDK_PENCIL;
599 break;
600 }
601 if (new_type != (GdkCursorType) c->cursor_type)
602 {
603 GdkCursor *cursor;
604
605 c->cursor_type = new_type;
606
607 cursor = gdk_cursor_new (c->cursor_type);
608 gdk_window_set_cursor (w->window, cursor);
609 gdk_cursor_destroy (cursor);
610 }
611 break;
612
613 default:
614 break;
615 }
616 return FALSE;
617 }
618
619 void
620 gtk_curve_set_curve_type (GtkCurve *c, GtkCurveType new_type)
621 {
622 gfloat rx, dx;
623 gint x, i;
624
625 if (new_type != c->curve_type)
626 {
627 gint width, height;
628
629 width = GTK_WIDGET(c)->allocation.width - RADIUS * 2;
630 height = GTK_WIDGET(c)->allocation.height - RADIUS * 2;
631
632 if (new_type == GTK_CURVE_TYPE_FREE)
633 {
634 gtk_curve_interpolate (c, width, height);
635 c->curve_type = new_type;
636 }
637 else if (c->curve_type == GTK_CURVE_TYPE_FREE)
638 {
639 if (c->ctlpoint)
640 g_free (c->ctlpoint);
641 c->num_ctlpoints = 9;
642 c->ctlpoint = g_malloc (c->num_ctlpoints * sizeof (*c->ctlpoint));
643
644 rx = 0.0;
645 dx = (width - 1) / (gfloat) (c->num_ctlpoints - 1);
646
647 for (i = 0; i < c->num_ctlpoints; ++i, rx += dx)
648 {
649 x = (int) (rx + 0.5);
650 c->ctlpoint[i][0] =
651 unproject (x, c->min_x, c->max_x, width);
652 c->ctlpoint[i][1] =
653 unproject (RADIUS + height - c->point[x].y,
654 c->min_y, c->max_y, height);
655 }
656 c->curve_type = new_type;
657 gtk_curve_interpolate (c, width, height);
658 }
659 else
660 {
661 c->curve_type = new_type;
662 gtk_curve_interpolate (c, width, height);
663 }
664 gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal);
665 gtk_curve_draw (c, width, height);
666 }
667 }
668
669 static void
670 gtk_curve_size_graph (GtkCurve *curve)
671 {
672 gint width, height;
673 gfloat aspect;
674
675 width = (curve->max_x - curve->min_x) + 1;
676 height = (curve->max_y - curve->min_y) + 1;
677 aspect = width / (gfloat) height;
678 if (width > gdk_screen_width () / 4)
679 width = gdk_screen_width () / 4;
680 if (height > gdk_screen_height () / 4)
681 height = gdk_screen_height () / 4;
682
683 if (aspect < 1.0)
684 width = height * aspect;
685 else
686 height = width / aspect;
687
688 gtk_drawing_area_size (GTK_DRAWING_AREA (curve),
689 width + RADIUS * 2, height + RADIUS * 2);
690 }
691
692 static void
693 gtk_curve_reset_vector (GtkCurve *curve)
694 {
695 if (curve->ctlpoint)
696 g_free (curve->ctlpoint);
697
698 curve->num_ctlpoints = 2;
699 curve->ctlpoint = g_malloc (2 * sizeof (curve->ctlpoint[0]));
700 curve->ctlpoint[0][0] = curve->min_x;
701 curve->ctlpoint[0][1] = curve->min_y;
702 curve->ctlpoint[1][0] = curve->max_x;
703 curve->ctlpoint[1][1] = curve->max_y;
704
705 if (curve->pixmap)
706 {
707 gint width, height;
708
709 width = GTK_WIDGET (curve)->allocation.width - RADIUS * 2;
710 height = GTK_WIDGET (curve)->allocation.height - RADIUS * 2;
711
712 if (curve->curve_type == GTK_CURVE_TYPE_FREE)
713 {
714 curve->curve_type = GTK_CURVE_TYPE_LINEAR;
715 gtk_curve_interpolate (curve, width, height);
716 curve->curve_type = GTK_CURVE_TYPE_FREE;
717 }
718 else
719 gtk_curve_interpolate (curve, width, height);
720 gtk_curve_draw (curve, width, height);
721 }
722 }
723
724 void
725 gtk_curve_reset (GtkCurve *c)
726 {
727 GtkCurveType old_type;
728
729 old_type = c->curve_type;
730 c->curve_type = GTK_CURVE_TYPE_SPLINE;
731 gtk_curve_reset_vector (c);
732
733 if (old_type != GTK_CURVE_TYPE_SPLINE)
734 gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal);
735 }
736
737 void
738 gtk_curve_set_gamma (GtkCurve *c, gfloat gamma)
739 {
740 gfloat x, one_over_gamma, height, one_over_width;
741 GtkCurveType old_type;
742 gint i;
743
744 if (c->num_points < 2)
745 return;
746
747 old_type = c->curve_type;
748 c->curve_type = GTK_CURVE_TYPE_FREE;
749
750 if (gamma <= 0)
751 one_over_gamma = 1.0;
752 else
753 one_over_gamma = 1.0 / gamma;
754 one_over_width = 1.0 / (c->num_points - 1);
755 height = c->height;
756 for (i = 0; i < c->num_points; ++i)
757 {
758 x = (gfloat) i / (c->num_points - 1);
759 c->point[i].x = RADIUS + i;
760 c->point[i].y =
761 RADIUS + (height * (1.0 - pow (x, one_over_gamma)) + 0.5);
762 }
763
764 if (old_type != GTK_CURVE_TYPE_FREE)
765 gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal);
766
767 gtk_curve_draw (c, c->num_points, c->height);
768 }
769
770 void
771 gtk_curve_set_range (GtkCurve *curve,
772 gfloat min_x, gfloat max_x, gfloat min_y, gfloat max_y)
773 {
774 curve->min_x = min_x;
775 curve->max_x = max_x;
776 curve->min_y = min_y;
777 curve->max_y = max_y;
778
779 gtk_curve_size_graph (curve);
780 gtk_curve_reset_vector (curve);
781 }
782
783 void
784 gtk_curve_set_vector (GtkCurve *c, int veclen, gfloat vector[])
785 {
786 GtkCurveType old_type;
787 gfloat rx, dx, ry;
788 gint i, height;
789
790 old_type = c->curve_type;
791 c->curve_type = GTK_CURVE_TYPE_FREE;
792
793 if (c->point)
794 height = GTK_WIDGET (c)->allocation.height - RADIUS * 2;
795 else
796 {
797 height = (c->max_y - c->min_y);
798 if (height > gdk_screen_height () / 4)
799 height = gdk_screen_height () / 4;
800
801 c->height = height;
802 c->num_points = veclen;
803 c->point = g_malloc (c->num_points * sizeof (c->point[0]));
804 }
805 rx = 0;
806 dx = (veclen - 1.0) / (c->num_points - 1.0);
807
808 for (i = 0; i < c->num_points; ++i, rx += dx)
809 {
810 ry = vector[(int) (rx + 0.5)];
811 if (ry > c->max_y) ry = c->max_y;
812 if (ry < c->min_y) ry = c->min_y;
813 c->point[i].x = RADIUS + i;
814 c->point[i].y =
815 RADIUS + height - project (ry, c->min_y, c->max_y, height);
816 }
817 if (old_type != GTK_CURVE_TYPE_FREE)
818 gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal);
819
820 gtk_curve_draw (c, c->num_points, height);
821 }
822
823 void
824 gtk_curve_get_vector (GtkCurve *c, int veclen, gfloat vector[])
825 {
826 gfloat rx, ry, dx, dy, min_x, delta_x, *mem, *xv, *yv, *y2v, prev;
827 gint dst, i, x, next, num_active_ctlpoints = 0, first_active = -1;
828
829 min_x = c->min_x;
830
831 if (c->curve_type != GTK_CURVE_TYPE_FREE)
832 {
833 /* count active points: */
834 prev = min_x - 1.0;
835 for (i = num_active_ctlpoints = 0; i < c->num_ctlpoints; ++i)
836 if (c->ctlpoint[i][0] > prev)
837 {
838 if (first_active < 0)
839 first_active = i;
840 prev = c->ctlpoint[i][0];
841 ++num_active_ctlpoints;
842 }
843
844 /* handle degenerate case: */
845 if (num_active_ctlpoints < 2)
846 {
847 if (num_active_ctlpoints > 0)
848 ry = c->ctlpoint[first_active][1];
849 else
850 ry = c->min_y;
851 if (ry < c->min_y) ry = c->min_y;
852 if (ry > c->max_y) ry = c->max_y;
853 for (x = 0; x < veclen; ++x)
854 vector[x] = ry;
855 return;
856 }
857 }
858
859 switch (c->curve_type)
860 {
861 case GTK_CURVE_TYPE_SPLINE:
862 mem = g_malloc (3 * num_active_ctlpoints * sizeof (gfloat));
863 xv = mem;
864 yv = mem + num_active_ctlpoints;
865 y2v = mem + 2*num_active_ctlpoints;
866
867 prev = min_x - 1.0;
868 for (i = dst = 0; i < c->num_ctlpoints; ++i)
869 if (c->ctlpoint[i][0] > prev)
870 {
871 prev = c->ctlpoint[i][0];
872 xv[dst] = c->ctlpoint[i][0];
873 yv[dst] = c->ctlpoint[i][1];
874 ++dst;
875 }
876
877 spline_solve (num_active_ctlpoints, xv, yv, y2v);
878
879 rx = min_x;
880 dx = (c->max_x - min_x) / (veclen - 1);
881 for (x = 0; x < veclen; ++x, rx += dx)
882 {
883 ry = spline_eval (num_active_ctlpoints, xv, yv, y2v, rx);
884 if (ry < c->min_y) ry = c->min_y;
885 if (ry > c->max_y) ry = c->max_y;
886 vector[x] = ry;
887 }
888
889 g_free (mem);
890 break;
891
892 case GTK_CURVE_TYPE_LINEAR:
893 dx = (c->max_x - min_x) / (veclen - 1);
894 rx = min_x;
895 ry = c->min_y;
896 dy = 0.0;
897 i = first_active;
898 for (x = 0; x < veclen; ++x, rx += dx)
899 {
900 if (rx >= c->ctlpoint[i][0])
901 {
902 if (rx > c->ctlpoint[i][0])
903 ry = c->min_y;
904 dy = 0.0;
905 next = i + 1;
906 while (next < c->num_ctlpoints
907 && c->ctlpoint[next][0] <= c->ctlpoint[i][0])
908 ++next;
909 if (next < c->num_ctlpoints)
910 {
911 delta_x = c->ctlpoint[next][0] - c->ctlpoint[i][0];
912 dy = ((c->ctlpoint[next][1] - c->ctlpoint[i][1])
913 / delta_x);
914 dy *= dx;
915 ry = c->ctlpoint[i][1];
916 i = next;
917 }
918 }
919 vector[x] = ry;
920 ry += dy;
921 }
922 break;
923
924 case GTK_CURVE_TYPE_FREE:
925 if (c->point)
926 {
927 rx = 0.0;
928 dx = c->num_points / (double) veclen;
929 for (x = 0; x < veclen; ++x, rx += dx)
930 vector[x] = unproject (RADIUS + c->height - c->point[(int) rx].y,
931 c->min_y, c->max_y,
932 c->height);
933 }
934 else
935 memset (vector, 0, veclen * sizeof (vector[0]));
936 break;
937 }
938 }
939
940 GtkWidget*
941 gtk_curve_new (void)
942 {
943 return gtk_type_new (gtk_curve_get_type ());
944 }
945
946 static void
947 gtk_curve_finalize (GtkObject *object)
948 {
949 GtkCurve *curve;
950
951 g_return_if_fail (object != NULL);
952 g_return_if_fail (GTK_IS_CURVE (object));
953
954 curve = GTK_CURVE (object);
955 if (curve->pixmap)
956 gdk_pixmap_unref (curve->pixmap);
957 if (curve->point)
958 g_free (curve->point);
959 if (curve->ctlpoint)
960 g_free (curve->ctlpoint);
961
962 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
963 }