comparison src/sid/xs_curve.c @ 2509:1223e8510d8a

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