1 /* scale/slider widget
2 *
3 * Copyright (C) 2013-2016 Robin Gareus <robin@gareus.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #ifndef _ROB_TK_SCALE_H_
21 #define _ROB_TK_SCALE_H_
22
23 /* default values used by robtk_scale_new()
24 * for calling robtk_scale_new_with_size()
25 */
26 #define GSC_LENGTH 250
27 #define GSC_GIRTH 18
28
29 typedef struct {
30 RobWidget *rw;
31
32 float min;
33 float max;
34 float acc;
35 float cur;
36 float dfl;
37
38 float drag_x, drag_y, drag_c;
39 bool sensitive;
40 bool prelight;
41
42 bool (*cb) (RobWidget* w, void* handle);
43 void* handle;
44
45 void (*touch_cb) (void*, uint32_t, bool);
46 void* touch_hd;
47 uint32_t touch_id;
48 bool touching;
49
50 cairo_pattern_t* dpat;
51 cairo_pattern_t* fpat;
52 cairo_surface_t* bg;
53
54 float w_width, w_height;
55 bool horiz;
56
57 char **mark_txt;
58 float *mark_val;
59 int mark_cnt;
60 bool mark_expose;
61 PangoFontDescription *mark_font;
62 float c_txt[4];
63 float mark_space;
64
65 pthread_mutex_t _mutex;
66
67 } RobTkScale;
68
69
robtk_scale_round_length(RobTkScale * d,float val)70 static int robtk_scale_round_length(RobTkScale * d, float val) {
71 if (d->horiz) {
72 return rint((d->w_width - 8) * (val - d->min) / (d->max - d->min));
73 } else {
74 return rint((d->w_height - 8) * (1.0 - (val - d->min) / (d->max - d->min)));
75 }
76 }
77
robtk_scale_update_value(RobTkScale * d,float val)78 static void robtk_scale_update_value(RobTkScale * d, float val) {
79 if (val < d->min) val = d->min;
80 if (val > d->max) val = d->max;
81 if (val != d->cur) {
82 float oldval = d->cur;
83 d->cur = val;
84 if (d->cb) d->cb(d->rw, d->handle);
85 if (robtk_scale_round_length(d, oldval) != robtk_scale_round_length(d, val)) {
86 val = robtk_scale_round_length(d, val);
87 oldval = robtk_scale_round_length(d, oldval);
88 cairo_rectangle_t rect;
89 if (oldval > val) {
90
91 if (d->horiz) {
92 rect.x = 1 + val;
93 rect.width = 9 + oldval - val;
94 rect.y = d->rw->widget_scale * d->mark_space + 5;
95 rect.height = d->w_height - 9 - d->mark_space * d->rw->widget_scale;
96 } else {
97 rect.x = 5;
98 rect.width = d->w_width - 9 - d->mark_space * d->rw->widget_scale;
99 rect.y = 1 + val;
100 rect.height = 9 + oldval - val;
101 }
102 } else {
103 if (d->horiz) {
104 rect.x = 1 + oldval;
105 rect.width = 9 + val - oldval;
106 rect.y = d->rw->widget_scale * d->mark_space + 5;
107 rect.height = d->w_height - 9 - d->mark_space * d->rw->widget_scale;
108 } else {
109 rect.x = 5;
110 rect.width = d->w_width - 9 - d->mark_space * d->rw->widget_scale;
111 rect.y = 1 + oldval;
112 rect.height = 9 + val - oldval;
113 }
114 }
115 #ifdef GTK_BACKEND
116 if (1 /* XXX is visible */) {
117 queue_tiny_area(d->rw, rect.x, rect.y, rect.width, rect.height);
118 }
119 #else
120 if (d->rw->cached_position) {
121 queue_tiny_area(d->rw, rect.x, rect.y, rect.width, rect.height);
122 }
123 #endif
124 }
125 }
126 }
127
robtk_scale_mousedown(RobWidget * handle,RobTkBtnEvent * event)128 static RobWidget* robtk_scale_mousedown(RobWidget *handle, RobTkBtnEvent *event) {
129 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
130 if (!d->sensitive) { return NULL; }
131 if (d->touch_cb) {
132 d->touch_cb (d->touch_hd, d->touch_id, true);
133 }
134 if (event->state & ROBTK_MOD_SHIFT) {
135 robtk_scale_update_value(d, d->dfl);
136 } else {
137 d->drag_x = event->x;
138 d->drag_y = event->y;
139 d->drag_c = d->cur;
140 }
141 queue_draw(d->rw);
142 return handle;
143 }
144
robtk_scale_mouseup(RobWidget * handle,RobTkBtnEvent * event)145 static RobWidget* robtk_scale_mouseup(RobWidget *handle, RobTkBtnEvent *event) {
146 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
147 if (!d->sensitive) { return NULL; }
148 d->drag_x = d->drag_y = -1;
149 if (d->touch_cb) {
150 d->touch_cb (d->touch_hd, d->touch_id, false);
151 }
152 queue_draw(d->rw);
153 return NULL;
154 }
155
robtk_scale_mousemove(RobWidget * handle,RobTkBtnEvent * event)156 static RobWidget* robtk_scale_mousemove(RobWidget *handle, RobTkBtnEvent *event) {
157 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
158 if (d->drag_x < 0 || d->drag_y < 0) return NULL;
159
160 if (!d->sensitive) {
161 d->drag_x = d->drag_y = -1;
162 queue_draw(d->rw);
163 return NULL;
164 }
165 float len;
166 float diff;
167 if (d->horiz) {
168 len = d->w_width - 8;
169 diff = (event->x - d->drag_x) / len;
170 } else {
171 len = d->w_height - 8;
172 diff = (d->drag_y - event->y) / len;
173 }
174 diff = rint(diff * (d->max - d->min) / d->acc ) * d->acc;
175 float val = d->drag_c + diff;
176
177 /* snap to mark */
178 const int snc = robtk_scale_round_length(d, val);
179 // lock ?!
180 for (int i = 0; i < d->mark_cnt; ++i) {
181 int sn = robtk_scale_round_length(d, d->mark_val[i]);
182 if (abs(sn-snc) < 3) {
183 val = d->mark_val[i];
184 break;
185 }
186 }
187
188 robtk_scale_update_value(d, val);
189 return handle;
190 }
191
robtk_scale_enter_notify(RobWidget * handle)192 static void robtk_scale_enter_notify(RobWidget *handle) {
193 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
194 if (!d->prelight) {
195 d->prelight = TRUE;
196 queue_draw(d->rw);
197 }
198 }
199
robtk_scale_leave_notify(RobWidget * handle)200 static void robtk_scale_leave_notify(RobWidget *handle) {
201 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
202 if (d->touch_cb && d->touching) {
203 d->touch_cb (d->touch_hd, d->touch_id, false);
204 d->touching = FALSE;
205 }
206 if (d->prelight) {
207 d->prelight = FALSE;
208 queue_draw(d->rw);
209 }
210 }
211
212 static void
robtk_scale_size_request(RobWidget * handle,int * w,int * h)213 robtk_scale_size_request(RobWidget* handle, int *w, int *h) {
214 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
215 int rw, rh;
216 if (d->horiz) {
217 rh = GSC_GIRTH + (d->mark_cnt > 0 ? d->mark_space : 0);
218 rh *= d->rw->widget_scale;
219 rw = 250;
220 } else {
221 rw = GSC_GIRTH + (d->mark_cnt > 0 ? d->mark_space : 0);
222 rw *= d->rw->widget_scale;
223 rh = 250;
224 }
225
226 *w = d->w_width = rw;
227 *h = d->w_height = rh;
228 }
229
230 static void
robtk_scale_size_allocate(RobWidget * handle,int w,int h)231 robtk_scale_size_allocate(RobWidget* handle, int w, int h) {
232 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
233 if (d->horiz) {
234 d->w_width = w;
235 d->w_height = d->rw->widget_scale * (GSC_GIRTH * + (d->mark_cnt > 0 ? d->mark_space : 0));
236 if (d->w_height > h) {
237 d->w_height = h;
238 }
239 } else {
240 d->w_height = h;
241 d->w_width = d->rw->widget_scale * (GSC_GIRTH + (d->mark_cnt > 0 ? d->mark_space : 0));
242 if (d->w_width > w) {
243 d->w_width = w;
244 }
245 }
246 robwidget_set_size(handle, d->w_width, d->w_height);
247 if (d->mark_cnt > 0) { d->mark_expose = TRUE; }
248 }
249
robtk_scale_scroll(RobWidget * handle,RobTkBtnEvent * ev)250 static RobWidget* robtk_scale_scroll(RobWidget *handle, RobTkBtnEvent *ev) {
251 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
252 if (!d->sensitive) { return NULL; }
253
254 if (!(d->drag_x < 0 || d->drag_y < 0)) {
255 d->drag_x = d->drag_y = -1;
256 }
257
258 float val = d->cur;
259 switch (ev->direction) {
260 case ROBTK_SCROLL_RIGHT:
261 case ROBTK_SCROLL_UP:
262 val += d->acc;
263 break;
264 case ROBTK_SCROLL_LEFT:
265 case ROBTK_SCROLL_DOWN:
266 val -= d->acc;
267 break;
268 default:
269 break;
270 }
271
272 if (d->touch_cb && !d->touching) {
273 d->touch_cb (d->touch_hd, d->touch_id, true);
274 d->touching = TRUE;
275 }
276
277 robtk_scale_update_value(d, val);
278 return NULL;
279 }
280
create_scale_pattern(RobTkScale * d)281 static void create_scale_pattern(RobTkScale * d) {
282 if (d->horiz) {
283 d->dpat = cairo_pattern_create_linear (0.0, 0.0, 0.0, GSC_GIRTH);
284 } else {
285 d->dpat = cairo_pattern_create_linear (0.0, 0.0, GSC_GIRTH, 0);
286 }
287 cairo_pattern_add_color_stop_rgb (d->dpat, 0.0, .3, .3, .33);
288 cairo_pattern_add_color_stop_rgb (d->dpat, 0.4, .5, .5, .55);
289 cairo_pattern_add_color_stop_rgb (d->dpat, 1.0, .2, .2, .22);
290
291 if (d->horiz) {
292 d->fpat = cairo_pattern_create_linear (0.0, 0.0, 0.0, GSC_GIRTH);
293 } else {
294 d->fpat = cairo_pattern_create_linear (0.0, 0.0, GSC_GIRTH, 0);
295 }
296 cairo_pattern_add_color_stop_rgb (d->fpat, 0.0, .0, .0, .0);
297 cairo_pattern_add_color_stop_rgb (d->fpat, 0.4, 1, 1, 1);
298 cairo_pattern_add_color_stop_rgb (d->fpat, 1.0, .1, .1, .1);
299 }
300
301 #define SXX_W(minus) (d->w_width + minus - d->rw->widget_scale * ((d->bg && !d->horiz) ? d->mark_space : 0))
302 #define SXX_H(minus) (d->w_height + minus - d->rw->widget_scale * ((d->bg && d->horiz) ? d->mark_space : 0))
303 #define SXX_T(plus) (plus + d->rw->widget_scale * ((d->bg && d->horiz) ? d->mark_space : 0))
304
robtk_scale_render_metrics(RobTkScale * d)305 static void robtk_scale_render_metrics(RobTkScale* d) {
306 if (d->bg) {
307 cairo_surface_destroy(d->bg);
308 }
309 d->bg = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, d->w_width, d->w_height);
310 cairo_t *cr = cairo_create (d->bg);
311 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
312 cairo_set_source_rgba (cr, .0, .0, .0, 0);
313 cairo_rectangle (cr, 0, 0, d->w_width, d->w_height);
314 cairo_fill (cr);
315 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
316 cairo_set_source_rgba (cr, .7, .7, .7, 1.0);
317 cairo_set_line_width (cr, 1.0);
318
319 for (int i = 0; i < d->mark_cnt; ++i) {
320 float v = 4.0 + robtk_scale_round_length(d, d->mark_val[i]);
321 if (d->horiz) {
322 if (d->mark_txt[i]) {
323 cairo_save (cr);
324 cairo_scale (cr, d->rw->widget_scale, d->rw->widget_scale);
325 write_text_full(cr, d->mark_txt[i], d->mark_font, v / d->rw->widget_scale, d->rw->widget_scale, -M_PI/2, 1, d->c_txt);
326 cairo_restore (cr);
327 }
328 cairo_move_to(cr, v+.5, SXX_T(1.5));
329 cairo_line_to(cr, v+.5, SXX_T(0) + SXX_H(-.5));
330 } else {
331 if (d->mark_txt[i]) {
332 cairo_save (cr);
333 cairo_scale (cr, d->rw->widget_scale, d->rw->widget_scale);
334 write_text_full(cr, d->mark_txt[i], d->mark_font, (d->w_width -2) / d->rw->widget_scale, v / d->rw->widget_scale, 0, 1, d->c_txt);
335 cairo_restore (cr);
336 }
337 cairo_move_to(cr, 1.5, v+.5);
338 cairo_line_to(cr, SXX_W(-.5) , v+.5);
339 }
340 cairo_stroke(cr);
341 }
342 cairo_destroy(cr);
343 }
344
robtk_scale_expose_event(RobWidget * handle,cairo_t * cr,cairo_rectangle_t * ev)345 static bool robtk_scale_expose_event (RobWidget* handle, cairo_t* cr, cairo_rectangle_t* ev) {
346 RobTkScale * d = (RobTkScale *)GET_HANDLE(handle);
347 cairo_rectangle (cr, ev->x, ev->y, ev->width, ev->height);
348 cairo_clip (cr);
349
350 float c[4];
351 get_color_from_theme(1, c);
352 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
353 cairo_set_source_rgb (cr, c[0], c[1], c[2]);
354 cairo_rectangle (cr, 0, 0, d->w_width, d->w_height);
355 cairo_fill(cr);
356
357 /* prepare tick mark surfaces */
358 if (d->mark_cnt > 0 && d->mark_expose) {
359 pthread_mutex_lock (&d->_mutex);
360 d->mark_expose = FALSE;
361 robtk_scale_render_metrics(d);
362 pthread_mutex_unlock (&d->_mutex);
363 }
364
365 /* tick marks */
366 if (d->bg) {
367 if (!d->sensitive) {
368 //cairo_set_operator (cr, CAIRO_OPERATOR_OVERLAY);
369 cairo_set_operator (cr, CAIRO_OPERATOR_SOFT_LIGHT);
370 } else {
371 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
372 }
373 cairo_set_source_surface(cr, d->bg, 0, 0);
374 cairo_paint (cr);
375 }
376
377 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
378
379 /* solid background */
380 if (d->sensitive) {
381 cairo_matrix_t matrix;
382 cairo_matrix_init_translate(&matrix, 0.0, -SXX_T(0));
383 cairo_pattern_set_matrix (d->dpat, &matrix);
384 cairo_set_source(cr, d->dpat);
385 } else {
386 cairo_set_source_rgba (cr, .5, .5, .5, 1.0);
387 }
388 rounded_rectangle(cr, 4.5, SXX_T(4.5), SXX_W(-8), SXX_H(-8), C_RAD);
389 cairo_fill_preserve(cr);
390
391 if (d->sensitive) {
392 cairo_set_source_rgba (cr, .0, .0, .0, 1.0);
393 } else {
394 cairo_set_source_rgba (cr, .5, .5, .5, 1.0);
395 }
396 cairo_set_line_width(cr, .75);
397 cairo_stroke_preserve (cr);
398 cairo_clip (cr);
399
400
401 float val = robtk_scale_round_length(d, d->cur);
402
403 /* red area, left | top */
404 if (d->sensitive) {
405 cairo_set_source_rgba (cr, .5, .0, .0, .3);
406 } else {
407 cairo_set_source_rgba (cr, .5, .2, .2, .3);
408 }
409 if (d->horiz) {
410 cairo_rectangle(cr, 3.0, SXX_T(5), val, SXX_H(-9));
411 } else {
412 cairo_rectangle(cr, 5, SXX_T(3) + val, SXX_W(-9), SXX_H(-7) - val);
413 }
414 cairo_fill(cr);
415
416 /* green area, botom | right */
417 if (d->sensitive) {
418 cairo_set_source_rgba (cr, .0, .5, .0, .3);
419 } else {
420 cairo_set_source_rgba (cr, .2, .5, .2, .3);
421 }
422 if (d->horiz) {
423 cairo_rectangle(cr, 3.0 + val, SXX_T(5), SXX_W(-7) - val, SXX_H(-9));
424 } else {
425 cairo_rectangle(cr, 5, SXX_T(3), SXX_W(-9), val);
426 }
427 cairo_fill(cr);
428
429 /* value ring */
430 if (d->sensitive) {
431 cairo_matrix_t matrix;
432 cairo_matrix_init_translate(&matrix, 0, -SXX_T(0));
433 cairo_pattern_set_matrix (d->fpat, &matrix);
434 cairo_set_source(cr, d->fpat);
435 } else {
436 cairo_set_source_rgba (cr, .7, .7, .7, .7);
437 }
438 if (d->horiz) {
439 cairo_rectangle(cr, 3.0 + val, SXX_T(5), 3, SXX_H(-9));
440 } else {
441 cairo_rectangle(cr, 5, SXX_T(3) + val, SXX_W(-9), 3);
442 }
443 cairo_fill(cr);
444
445
446 if (d->sensitive && (d->prelight || d->drag_x > 0)) {
447 cairo_reset_clip (cr);
448 cairo_rectangle (cr, ev->x, ev->y, ev->width, ev->height);
449 cairo_clip (cr);
450 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, .1);
451 rounded_rectangle(cr, 4.5, SXX_T(4.5), SXX_W(-8), SXX_H(-8), C_RAD);
452 cairo_fill_preserve(cr);
453 cairo_set_line_width(cr, .75);
454 cairo_set_source_rgba (cr, .0, .0, .0, 1.0);
455 cairo_stroke(cr);
456 }
457 return TRUE;
458 }
459
460
461
462 /******************************************************************************
463 * public functions
464 */
465
robtk_scale_new_with_size(float min,float max,float step,int girth,int length,bool horiz)466 static RobTkScale * robtk_scale_new_with_size(float min, float max, float step,
467 int girth, int length, bool horiz) {
468
469 assert(max > min);
470 assert(step > 0);
471 assert( (max - min) / step >= 1.0);
472
473 RobTkScale *d = (RobTkScale *) malloc(sizeof(RobTkScale));
474
475 d->mark_font = get_font_from_theme();
476 get_color_from_theme(0, d->c_txt);
477
478 pthread_mutex_init (&d->_mutex, 0);
479 d->mark_space = 0.0; // XXX longest annotation text
480
481 d->horiz = horiz;
482 if (horiz) {
483 d->w_width = length; d->w_height = girth;
484 } else {
485 d->w_width = girth; d->w_height = length;
486 }
487
488 d->rw = robwidget_new(d);
489 ROBWIDGET_SETNAME(d->rw, "scale");
490
491 d->mark_expose = FALSE;
492 d->cb = NULL;
493 d->handle = NULL;
494 d->touch_cb = NULL;
495 d->touch_hd = NULL;
496 d->touch_id = 0;
497 d->touching = FALSE;
498 d->min = min;
499 d->max = max;
500 d->acc = step;
501 d->cur = min;
502 d->dfl = min;
503 d->sensitive = TRUE;
504 d->prelight = FALSE;
505 d->drag_x = d->drag_y = -1;
506 d->bg = NULL;
507 create_scale_pattern(d);
508
509 d->mark_cnt = 0;
510 d->mark_val = NULL;
511 d->mark_txt = NULL;
512
513 robwidget_set_size_request(d->rw, robtk_scale_size_request);
514 robwidget_set_size_allocate(d->rw, robtk_scale_size_allocate);
515
516 robwidget_set_expose_event(d->rw, robtk_scale_expose_event);
517 robwidget_set_mouseup(d->rw, robtk_scale_mouseup);
518 robwidget_set_mousedown(d->rw, robtk_scale_mousedown);
519 robwidget_set_mousemove(d->rw, robtk_scale_mousemove);
520 robwidget_set_mousescroll(d->rw, robtk_scale_scroll);
521 robwidget_set_enter_notify(d->rw, robtk_scale_enter_notify);
522 robwidget_set_leave_notify(d->rw, robtk_scale_leave_notify);
523
524 return d;
525 }
526
robtk_scale_new(float min,float max,float step,bool horiz)527 static RobTkScale * robtk_scale_new(float min, float max, float step, bool horiz) {
528 return robtk_scale_new_with_size(min, max, step, GSC_GIRTH, GSC_LENGTH, horiz);
529 }
530
robtk_scale_destroy(RobTkScale * d)531 static void robtk_scale_destroy(RobTkScale *d) {
532 robwidget_destroy(d->rw);
533 cairo_pattern_destroy(d->dpat);
534 cairo_pattern_destroy(d->fpat);
535 pthread_mutex_destroy(&d->_mutex);
536 for (int i = 0; i < d->mark_cnt; ++i) {
537 free(d->mark_txt[i]);
538 }
539 free(d->mark_txt);
540 free(d->mark_val);
541 pango_font_description_free(d->mark_font);
542 free(d);
543 }
544
robtk_scale_widget(RobTkScale * d)545 static RobWidget * robtk_scale_widget(RobTkScale *d) {
546 return d->rw;
547 }
548
robtk_scale_set_callback(RobTkScale * d,bool (* cb)(RobWidget * w,void * handle),void * handle)549 static void robtk_scale_set_callback(RobTkScale *d, bool (*cb) (RobWidget* w, void* handle), void* handle) {
550 d->cb = cb;
551 d->handle = handle;
552 }
553
robtk_scale_set_touch(RobTkScale * d,void (* cb)(void *,uint32_t,bool),void * handle,uint32_t id)554 static void robtk_scale_set_touch(RobTkScale *d, void (*cb) (void*, uint32_t, bool), void* handle, uint32_t id) {
555 d->touch_cb = cb;
556 d->touch_hd = handle;
557 d->touch_id = id;
558 }
559
robtk_scale_set_value(RobTkScale * d,float v)560 static void robtk_scale_set_value(RobTkScale *d, float v) {
561 v = d->min + rint((v-d->min) / d->acc ) * d->acc;
562 robtk_scale_update_value(d, v);
563 }
564
robtk_scale_set_sensitive(RobTkScale * d,bool s)565 static void robtk_scale_set_sensitive(RobTkScale *d, bool s) {
566 if (d->sensitive != s) {
567 d->sensitive = s;
568 queue_draw(d->rw);
569 }
570 }
571
robtk_scale_get_value(RobTkScale * d)572 static float robtk_scale_get_value(RobTkScale *d) {
573 return (d->cur);
574 }
575
robtk_scale_set_default(RobTkScale * d,float v)576 static void robtk_scale_set_default(RobTkScale *d, float v) {
577 assert(v >= d->min);
578 assert(v <= d->max);
579 d->dfl = v;
580 }
581
robtk_scale_add_mark(RobTkScale * d,float v,const char * txt)582 static void robtk_scale_add_mark(RobTkScale *d, float v, const char *txt) {
583 int tw = 0;
584 int th = 0;
585 if (txt && strlen(txt)) {
586 get_text_geometry(txt, d->mark_font, &tw, &th);
587 }
588 pthread_mutex_lock (&d->_mutex);
589 if ((tw + 3) > d->mark_space) {
590 d->mark_space = tw + 3;
591 }
592 d->mark_val = (float *) realloc(d->mark_val, sizeof(float) * (d->mark_cnt+1));
593 d->mark_txt = (char **) realloc(d->mark_txt, sizeof(char*) * (d->mark_cnt+1));
594 d->mark_val[d->mark_cnt] = v;
595 d->mark_txt[d->mark_cnt] = txt ? strdup(txt): NULL;
596 d->mark_cnt++;
597 d->mark_expose = TRUE;
598 pthread_mutex_unlock (&d->_mutex);
599 }
600 #endif
601