Don't forget the new file
[xiph/unicode.git] / sushivision / panel-1d.c
blob6523cbb136d27251b44e3ef4b46fe04c9d5e640b
1 /*
3 * sushivision copyright (C) 2006-2007 Monty <monty@xiph.org>
5 * sushivision 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 * sushivision 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.
15 * You should have received a copy of the GNU General Public License
16 * along with sushivision; see the file COPYING. If not, write to the
17 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define _GNU_SOURCE
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <math.h>
28 #include <signal.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <gtk/gtk.h>
32 #include <cairo-ft.h>
33 #include "internal.h"
35 #define LINETYPES 6
36 static _sv_propmap_t *line_name[LINETYPES+1] = {
37 &(_sv_propmap_t){"line", 0, NULL,NULL,NULL},
38 &(_sv_propmap_t){"fat line", 1, NULL,NULL,NULL},
39 &(_sv_propmap_t){"fill above", 2, NULL,NULL,NULL},
40 &(_sv_propmap_t){"fill below", 3, NULL,NULL,NULL},
41 &(_sv_propmap_t){"fill to zero", 4, NULL,NULL,NULL},
42 &(_sv_propmap_t){"no line", 5, NULL,NULL,NULL},
43 NULL
46 #define POINTTYPES 9
47 static _sv_propmap_t *point_name[POINTTYPES+1] = {
48 &(_sv_propmap_t){"dot", 0, NULL,NULL,NULL},
49 &(_sv_propmap_t){"cross", 1, NULL,NULL,NULL},
50 &(_sv_propmap_t){"plus", 2, NULL,NULL,NULL},
51 &(_sv_propmap_t){"open circle", 3, NULL,NULL,NULL},
52 &(_sv_propmap_t){"open square", 4, NULL,NULL,NULL},
53 &(_sv_propmap_t){"open triangle", 5, NULL,NULL,NULL},
54 &(_sv_propmap_t){"solid circle", 6, NULL,NULL,NULL},
55 &(_sv_propmap_t){"solid square", 7, NULL,NULL,NULL},
56 &(_sv_propmap_t){"solid triangle", 8, NULL,NULL,NULL},
57 NULL
60 static void render_checks(cairo_t *c, int w, int h){
61 /* default checked background */
62 /* 16x16 'mid-checks' */
63 int x,y;
65 cairo_set_source_rgb (c, .5,.5,.5);
66 cairo_paint(c);
67 cairo_set_source_rgb (c, .314,.314,.314);
69 for(y=0;y<h;y+=16){
70 int phase = (y>>4)&1;
71 for(x=0;x<w;x+=16){
72 if(phase){
73 cairo_rectangle(c,x,y,16.,16.);
74 cairo_fill(c);
76 phase=!phase;
81 // called internally, assumes we hold lock
82 // redraws the data, does not compute the data
83 static int _sv_panel1d_remap(sv_panel_t *p, cairo_t *c){
84 _sv_panel1d_t *p1 = p->subtype->p1;
85 _sv_plot_t *plot = PLOT(p->private->graph);
87 int plot_serialno = p->private->plot_serialno;
88 int map_serialno = p->private->map_serialno;
89 int xi,i,j;
90 int pw = plot->x.pixels;
91 int ph = plot->y.pixels;
92 int dw = p1->data_size;
93 double r = (p1->flip?p1->panel_w:p1->panel_h);
95 _sv_scalespace_t rx = (p1->flip?p1->y:p1->x);
96 _sv_scalespace_t ry = (p1->flip?p1->x:p1->y);
97 _sv_scalespace_t sx = p1->x;
98 _sv_scalespace_t sy = p1->y;
99 _sv_scalespace_t sx_v = p1->x_v;
100 _sv_scalespace_t px = plot->x;
101 _sv_scalespace_t py = plot->y;
103 /* do the panel and plot scales match? If not, redraw the plot
104 scales */
106 if(memcmp(&rx,&px,sizeof(rx)) ||
107 memcmp(&ry,&py,sizeof(ry))){
109 plot->x = rx;
110 plot->y = ry;
112 gdk_threads_leave();
113 _sv_plot_draw_scales(plot);
114 }else
115 gdk_threads_leave();
117 /* blank frame to selected bg */
118 switch(p->private->bg_type){
119 case SV_BG_WHITE:
120 cairo_set_source_rgb (c, 1.,1.,1.);
121 cairo_paint(c);
122 break;
123 case SV_BG_BLACK:
124 cairo_set_source_rgb (c, 0,0,0);
125 cairo_paint(c);
126 break;
127 case SV_BG_CHECKS:
128 render_checks(c,pw,ph);
129 break;
132 gdk_threads_enter();
133 if(plot_serialno != p->private->plot_serialno ||
134 map_serialno != p->private->map_serialno) return -1;
136 if(p1->data_vec){
138 /* by objective */
139 for(j=0;j<p->objectives;j++){
140 if(p1->data_vec[j] && !_sv_mapping_inactive_p(p1->mappings+j)){
142 double alpha = _sv_slider_get_value(p1->alpha_scale[j],0);
143 int linetype = p1->linetype[j];
144 int pointtype = p1->pointtype[j];
145 u_int32_t color = _sv_mapping_calc(p1->mappings+j,1.,0);
147 double *xv = calloc(dw,sizeof(*xv));
148 double *yv = calloc(dw,sizeof(*yv));
149 double *data_vec = calloc(dw,sizeof(*data_vec));
151 memcpy(data_vec,p1->data_vec[j],sizeof(*data_vec)*dw);
152 gdk_threads_leave();
154 /* by x */
155 for(xi=0;xi<dw;xi++){
156 double val = data_vec[xi];
157 double xpixel = xi;
158 double ypixel = NAN;
160 /* map data vector bin to x pixel location in the plot */
161 xpixel = _sv_scalespace_pixel(&sx,_sv_scalespace_value(&sx_v,xpixel))+.5;
163 /* map/render result */
164 if(!isnan(val))
165 ypixel = _sv_scalespace_pixel(&sy,val)+.5;
167 xv[xi] = xpixel;
168 yv[xi] = ypixel;
171 /* draw areas, if any */
172 if(linetype>1 && linetype < 5){
173 double yA=-1;
174 if(linetype == 2) /* fill above */
175 yA= (p1->flip?r:-1);
176 if(linetype == 3) /* fill below */
177 yA = (p1->flip?-1:r);
178 if(linetype == 4) /* fill to zero */
179 yA = _sv_scalespace_pixel(&sy,0.)+.5;
181 cairo_set_source_rgba(c,
182 ((color>>16)&0xff)/255.,
183 ((color>>8)&0xff)/255.,
184 ((color)&0xff)/255.,
185 alpha*.75);
187 if(!isnan(yv[0])){
188 if(p1->flip){
189 cairo_move_to(c,yA,xv[0]+.5);
190 cairo_line_to(c,yv[0],xv[0]+.5);
191 }else{
192 cairo_move_to(c,xv[0]-.5,yA);
193 cairo_line_to(c,xv[0]-.5,yv[0]);
197 for(i=1;i<dw;i++){
199 if(isnan(yv[i])){
200 if(!isnan(yv[i-1])){
201 /* close off the area */
202 if(p1->flip){
203 cairo_line_to(c,yv[i-1],xv[i-1]-.5);
204 cairo_line_to(c,yA,xv[i-1]-.5);
205 }else{
206 cairo_line_to(c,xv[i-1]+.5,yv[i-1]);
207 cairo_line_to(c,xv[i-1]+.5,yA);
209 cairo_close_path(c);
211 }else{
212 if(isnan(yv[i-1])){
213 if(p1->flip){
214 cairo_move_to(c,yA,xv[i]+.5);
215 cairo_line_to(c,yv[i],xv[i]+.5);
216 }else{
217 cairo_move_to(c,xv[i]-.5,yA);
218 cairo_line_to(c,xv[i]-.5,yv[i]);
220 }else{
221 if(p1->flip){
222 cairo_line_to(c,yv[i],xv[i]);
223 }else{
224 cairo_line_to(c,xv[i],yv[i]);
230 if(!isnan(yv[i-1])){
231 /* close off the area */
232 if(p1->flip){
233 cairo_line_to(c,yv[i-1],xv[i-1]-.5);
234 cairo_line_to(c,yA,xv[i-1]-.5);
235 }else{
236 cairo_line_to(c,xv[i-1]+.5,yv[i-1]);
237 cairo_line_to(c,xv[i-1]+.5,yA);
239 cairo_close_path(c);
242 cairo_fill(c);
245 /* now draw the lines */
246 if(linetype != 5){
247 cairo_set_source_rgba(c,
248 ((color>>16)&0xff)/255.,
249 ((color>>8)&0xff)/255.,
250 ((color)&0xff)/255.,
251 alpha);
252 if(linetype == 1)
253 cairo_set_line_width(c,2.);
254 else
255 cairo_set_line_width(c,1.);
257 for(i=1;i<dw;i++){
259 if(!isnan(yv[i-1]) && !isnan(yv[i])){
261 if(p1->flip){
262 cairo_move_to(c,yv[i-1],xv[i-1]);
263 cairo_line_to(c,yv[i],xv[i]);
264 }else{
265 cairo_move_to(c,xv[i-1],yv[i-1]);
266 cairo_line_to(c,xv[i],yv[i]);
268 cairo_stroke(c);
273 /* now draw the points */
274 if(pointtype > 0 || linetype == 5){
275 cairo_set_line_width(c,1.);
277 for(i=0;i<dw;i++){
278 if(!isnan(yv[i])){
279 double xx,yy;
280 if(p1->flip){
281 xx = yv[i];
282 yy = xv[i];
283 }else{
284 xx = xv[i];
285 yy = yv[i];
288 cairo_set_source_rgba(c,
289 ((color>>16)&0xff)/255.,
290 ((color>>8)&0xff)/255.,
291 ((color)&0xff)/255.,
292 alpha);
294 switch(pointtype){
295 case 0: /* pixeldots */
296 cairo_rectangle(c, xx-.5,yy-.5,1,1);
297 cairo_fill(c);
298 break;
299 case 1: /* X */
300 cairo_move_to(c,xx-4,yy-4);
301 cairo_line_to(c,xx+4,yy+4);
302 cairo_move_to(c,xx+4,yy-4);
303 cairo_line_to(c,xx-4,yy+4);
304 break;
305 case 2: /* + */
306 cairo_move_to(c,xx-4,yy);
307 cairo_line_to(c,xx+4,yy);
308 cairo_move_to(c,xx,yy-4);
309 cairo_line_to(c,xx,yy+4);
310 break;
311 case 3: case 6: /* circle */
312 cairo_arc(c,xx,yy,4,0,2.*M_PI);
313 break;
314 case 4: case 7: /* square */
315 cairo_rectangle(c,xx-4,yy-4,8,8);
316 break;
317 case 5: case 8: /* triangle */
318 cairo_move_to(c,xx,yy-5);
319 cairo_line_to(c,xx-4,yy+3);
320 cairo_line_to(c,xx+4,yy+3);
321 cairo_close_path(c);
322 break;
325 if(pointtype>5){
326 cairo_fill_preserve(c);
329 if(pointtype>0){
330 if(p->private->bg_type == SV_BG_WHITE)
331 cairo_set_source_rgba(c,0.,0.,0.,alpha);
332 else
333 cairo_set_source_rgba(c,1.,1.,1.,alpha);
334 cairo_stroke(c);
340 free(data_vec);
341 free(xv);
342 free(yv);
344 gdk_threads_enter();
345 if(plot_serialno != p->private->plot_serialno ||
346 map_serialno != p->private->map_serialno) return -1;
353 return 1;
356 static void _sv_panel1d_print(sv_panel_t *p, cairo_t *c, int w, int h){
357 _sv_plot_t *plot = PLOT(p->private->graph);
358 double pw = p->private->graph->allocation.width;
359 double ph = p->private->graph->allocation.height;
360 double scale;
362 if(w/pw < h/ph)
363 scale = w/pw;
364 else
365 scale = h/ph;
367 cairo_matrix_t m;
368 cairo_get_matrix(c,&m);
369 cairo_matrix_scale(&m,scale,scale);
370 cairo_set_matrix(c,&m);
372 _sv_plot_print(plot, c, ph*scale, (void(*)(void *, cairo_t *))_sv_panel1d_remap, p);
375 static void _sv_panel1d_update_legend(sv_panel_t *p){
376 _sv_panel1d_t *p1 = p->subtype->p1;
377 _sv_plot_t *plot = PLOT(p->private->graph);
379 gdk_threads_enter ();
381 if(plot){
382 int i,depth=0;
383 char buffer[320];
384 _sv_plot_legend_clear(plot);
386 if(3-_sv_scalespace_decimal_exponent(&p1->x_v) > depth)
387 depth = 3-_sv_scalespace_decimal_exponent(&p1->x_v);
389 // add each dimension to the legend
390 for(i=0;i<p->dimensions;i++){
391 sv_dim_t *d = p->dimension_list[i].d;
392 // display decimal precision relative to bracket
393 //int depth = del_depth(p->dimension_list[i].d->bracket[0],
394 // p->dimension_list[i].d->bracket[1]) + offset;
395 if( d!=p->private->x_d ||
396 plot->cross_active){
398 snprintf(buffer,320,"%s = %+.*f",
399 p->dimension_list[i].d->name,
400 depth,
401 p->dimension_list[i].d->val);
402 _sv_plot_legend_add(plot,buffer);
406 // one space
407 _sv_plot_legend_add(plot,NULL);
409 // add each active objective to the legend
410 // choose the value under the crosshairs
411 if(plot->cross_active){
412 double val = (p1->flip?plot->sely:plot->selx);
413 int bin = rint(_sv_scalespace_pixel(&p1->x_v, val));
415 for(i=0;i<p->objectives;i++){
416 if(!_sv_mapping_inactive_p(p1->mappings+i)){
417 u_int32_t color = _sv_mapping_calc(p1->mappings+i,1.,0);
419 snprintf(buffer,320,"%s",
420 p->objective_list[i].o->name);
422 if(bin>=0 && bin<p1->data_size){
424 float val = p1->data_vec[i][bin];
426 if(!isnan(val)){
427 snprintf(buffer,320,"%s = %f",
428 p->objective_list[i].o->name,
429 val);
433 _sv_plot_legend_add_with_color(plot,buffer,color | 0xff000000);
437 gdk_threads_leave ();
441 static void _sv_panel1d_mapchange_callback(GtkWidget *w,gpointer in){
442 sv_obj_list_t *optr = (sv_obj_list_t *)in;
443 sv_panel_t *p = optr->p;
444 _sv_panel1d_t *p1 = p->subtype->p1;
445 int onum = optr - p->objective_list;
447 _sv_undo_push();
448 _sv_undo_suspend();
450 // update colormap
451 // oh, the wasteful
452 _sv_solid_set_func(&p1->mappings[onum],
453 gtk_combo_box_get_active(GTK_COMBO_BOX(w)));
454 _sv_slider_set_gradient(p1->alpha_scale[onum], &p1->mappings[onum]);
456 _sv_panel_dirty_map(p);
457 _sv_panel_dirty_legend(p);
458 _sv_undo_resume();
461 static void _sv_panel1d_alpha_callback(void * in, int buttonstate){
462 sv_obj_list_t *optr = (sv_obj_list_t *)in;
463 sv_panel_t *p = optr->p;
464 // _sv_panel1d_t *p1 = p->subtype->p1;
465 // int onum = optr - p->objective_list;
467 if(buttonstate == 0){
468 _sv_undo_push();
469 _sv_undo_suspend();
472 _sv_panel_dirty_map(p);
473 _sv_panel_dirty_legend(p);
475 if(buttonstate == 2)
476 _sv_undo_resume();
479 static void _sv_panel1d_linetype_callback(GtkWidget *w,gpointer in){
480 sv_obj_list_t *optr = (sv_obj_list_t *)in;
481 sv_panel_t *p = optr->p;
482 _sv_panel1d_t *p1 = p->subtype->p1;
483 int onum = optr - p->objective_list;
485 _sv_undo_push();
486 _sv_undo_suspend();
488 // update colormap
489 int pos = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
490 p1->linetype[onum] = line_name[pos]->value;
492 _sv_panel_dirty_map(p);
493 _sv_undo_resume();
496 static void _sv_panel1d_pointtype_callback(GtkWidget *w,gpointer in){
497 sv_obj_list_t *optr = (sv_obj_list_t *)in;
498 sv_panel_t *p = optr->p;
499 _sv_panel1d_t *p1 = p->subtype->p1;
500 int onum = optr - p->objective_list;
502 _sv_undo_push();
503 _sv_undo_suspend();
505 // update colormap
506 int pos = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
507 p1->pointtype[onum] = point_name[pos]->value;
509 _sv_panel_dirty_map(p);
510 _sv_undo_resume();
513 static void _sv_panel1d_map_callback(void *in,int buttonstate){
514 sv_panel_t *p = (sv_panel_t *)in;
515 _sv_panel1d_t *p1 = p->subtype->p1;
516 _sv_plot_t *plot = PLOT(p->private->graph);
518 if(buttonstate == 0){
519 _sv_undo_push();
520 _sv_undo_suspend();
523 // has new bracketing changed the plot range scale?
524 if(p1->range_bracket[0] != _sv_slider_get_value(p1->range_slider,0) ||
525 p1->range_bracket[1] != _sv_slider_get_value(p1->range_slider,1)){
527 int w = plot->w.allocation.width;
528 int h = plot->w.allocation.height;
530 p1->range_bracket[0] = _sv_slider_get_value(p1->range_slider,0);
531 p1->range_bracket[1] = _sv_slider_get_value(p1->range_slider,1);
533 if(p1->flip)
534 p1->y = _sv_scalespace_linear(p1->range_bracket[0],
535 p1->range_bracket[1],
537 plot->scalespacing,
538 p1->range_scale->legend);
540 else
541 p1->y = _sv_scalespace_linear(p1->range_bracket[1],
542 p1->range_bracket[0],
544 plot->scalespacing,
545 p1->range_scale->legend);
549 //redraw the plot
550 _sv_panel_dirty_map(p);
551 if(buttonstate == 2)
552 _sv_undo_resume();
555 static void _sv_panel1d_update_xsel(sv_panel_t *p){
556 _sv_panel1d_t *p1 = p->subtype->p1;
557 int i;
559 // enable/disable dimension slider thumbs
560 // enable/disable objective 'point' dropdowns
561 for(i=0;i<p->dimensions;i++){
563 if(p1->dim_xb[i] &&
564 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p1->dim_xb[i]))){
566 // set the x dim flag
567 p->private->x_d = p->dimension_list[i].d;
568 p1->x_scale = p->private->dim_scales[i];
569 p1->x_dnum = i;
571 if(p1->dim_xb[i] &&
572 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p1->dim_xb[i]))){
573 // make all thumbs visible
574 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],0,1);
575 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],2,1);
576 }else{
577 // make bracket thumbs invisible */
578 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],0,0);
579 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],2,0);
584 static void _sv_panel1d_compute_line(sv_panel_t *p,
585 int serialno,
586 int x_d,
587 _sv_scalespace_t sxi,
588 int w,
589 double *dim_vals,
590 _sv_bythread_cache_1d_t *c){
591 _sv_panel1d_t *p1 = p->subtype->p1;
592 double work[w];
593 int i,j,fn=_sv_functions;
595 /* by function */
596 for(i=0;i<fn;i++){
597 if(c->call[i]){
598 sv_func_t *f = _sv_function_list[i];
599 int step = f->outputs;
600 double *fout = c->fout[i];
602 /* by x */
603 for(j=0;j<w;j++){
604 dim_vals[x_d] = _sv_scalespace_value(&sxi,j);
605 c->call[i](dim_vals,fout);
606 fout+=step;
611 /* process function output by objective */
612 /* 1d panels currently only care about the Y output value; in the
613 future, Z may also be relevant */
614 for(i=0;i<p->objectives;i++){
615 sv_obj_t *o = p->objective_list[i].o;
616 int offset = o->private->y_fout;
617 sv_func_t *f = o->private->y_func;
618 if(f){
619 int step = f->outputs;
620 double *fout = c->fout[f->number]+offset;
622 /* map result from function output to objective output */
623 for(j=0;j<w;j++){
624 work[j] = *fout;
625 fout+=step;
628 gdk_threads_enter (); // misuse me as a global mutex
629 if(p->private->plot_serialno == serialno){
630 /* store result in panel */
631 memcpy(p1->data_vec[i],work,w*sizeof(*work));
632 gdk_threads_leave (); // misuse me as a global mutex
633 }else{
634 gdk_threads_leave (); // misuse me as a global mutex
635 break;
641 // subtype entry point for plot remaps; lock held
642 int _sv_panel1d_map_redraw(sv_panel_t *p, _sv_bythread_cache_t *c){
643 if(p->private->map_progress_count)return 0;
644 p->private->map_progress_count++;
646 // render to a temp surface so that we can release the lock occasionally
647 _sv_plot_t *plot = PLOT(p->private->graph);
648 cairo_surface_t *back = plot->back;
649 cairo_surface_t *cs = cairo_surface_create_similar(back,CAIRO_CONTENT_COLOR,
650 cairo_image_surface_get_width(back),
651 cairo_image_surface_get_height(back));
652 cairo_t *ct = cairo_create(cs);
654 if(_sv_panel1d_remap(p,ct) == -1){ // returns -1 on abort
655 cairo_destroy(ct);
656 cairo_surface_destroy(cs);
657 }else{
658 // else complete
659 cairo_surface_destroy(plot->back);
660 plot->back = cs;
661 cairo_destroy(ct);
663 _sv_panel_clean_map(p);
664 _sv_plot_expose_request(plot);
667 return 1;
670 // call only from main gtk thread
671 void _sv_panel1d_mark_recompute(sv_panel_t *p){
672 if(!p->private->realized) return;
673 _sv_panel1d_t *p1 = p->subtype->p1;
674 _sv_plot_t *plot = PLOT(p->private->graph);
675 int w = plot->w.allocation.width;
676 int h = plot->w.allocation.height;
677 int dw = w;
678 int i,j;
680 if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
681 if(p1->flip){
682 dw = _sv_dim_scales(p->private->x_d,
683 p->private->x_d->bracket[1],
684 p->private->x_d->bracket[0],
685 h,dw * p->private->oversample_n / p->private->oversample_d,
686 plot->scalespacing,
687 p->private->x_d->name,
688 &p1->x,
689 &p1->x_v,
690 &p1->x_i);
692 p1->y = _sv_scalespace_linear(p1->range_bracket[0],
693 p1->range_bracket[1],
695 plot->scalespacing,
696 p1->range_scale->legend);
698 }else{
699 dw = _sv_dim_scales(p->private->x_d,
700 p->private->x_d->bracket[0],
701 p->private->x_d->bracket[1],
702 w,dw * p->private->oversample_n / p->private->oversample_d,
703 plot->scalespacing,
704 p->private->x_d->name,
705 &p1->x,
706 &p1->x_v,
707 &p1->x_i);
709 p1->y = _sv_scalespace_linear(p1->range_bracket[1],
710 p1->range_bracket[0],
712 plot->scalespacing,
713 p1->range_scale->legend);
716 if(p1->data_size != dw){
717 if(p1->data_vec){
719 // make new vec
720 int i;
721 for(i=0;i<p->objectives;i++){
722 double *new_vec = malloc(dw * sizeof(**p1->data_vec));
724 free(p1->data_vec[i]);
725 p1->data_vec[i] = new_vec;
730 p1->data_size = dw;
732 if(!p1->data_vec){
733 // allocate it
735 p1->data_vec = calloc(p->objectives,sizeof(*p1->data_vec));
736 for(i=0;i<p->objectives;i++)
737 p1->data_vec[i] = malloc(dw*sizeof(**p1->data_vec));
741 // blank it
742 for(i=0;i<p->objectives;i++)
743 for(j=0;j<dw;j++)
744 p1->data_vec[i][j]=NAN;
746 if(p1->panel_w != w || p1->panel_h != h){
747 p->private->map_progress_count=0;
748 _sv_panel1d_map_redraw(p, NULL);
751 p1->panel_w = w;
752 p1->panel_h = h;
754 _sv_panel_dirty_plot(p);
758 static void _sv_panel1d_recompute_callback(void *ptr){
759 sv_panel_t *p = (sv_panel_t *)ptr;
760 _sv_panel1d_mark_recompute(p);
763 static void _sv_panel1d_update_crosshair(sv_panel_t *p){
764 _sv_panel1d_t *p1 = p->subtype->p1;
765 _sv_plot_t *plot = PLOT(p->private->graph);
766 double x=0;
767 int i;
769 if(!p->private->realized)return;
771 for(i=0;i<p->dimensions;i++){
772 sv_dim_t *d = p->dimension_list[i].d;
773 if(d == p->private->x_d)
774 x = p->dimension_list[i].d->val;
777 if(p1->flip)
778 _sv_plot_set_crosshairs(plot,0,x);
779 else
780 _sv_plot_set_crosshairs(plot,x,0);
782 // crosshairs snap to a pixel position; the
783 // cached dimension value should be accurate with respect to the
784 // crosshairs.
785 for(i=0;i<p->dimensions;i++){
786 sv_dim_t *d = p->dimension_list[i].d;
787 _sv_panel1d_t *p1 = p->subtype->p1;
788 if(d == p->private->x_d){
789 if(p1->flip)
790 d->val = _sv_scalespace_value(&plot->x,_sv_plot_get_crosshair_ypixel(plot));
791 else
792 d->val = _sv_scalespace_value(&plot->x,_sv_plot_get_crosshair_xpixel(plot));
795 _sv_panel_dirty_legend(p);
798 static void _sv_panel1d_center_callback(sv_dim_list_t *dptr){
799 sv_dim_t *d = dptr->d;
800 sv_panel_t *p = dptr->p;
801 int axisp = (d == p->private->x_d);
803 if(!axisp){
804 // mid slider of a non-axis dimension changed, rerender
805 _sv_panel1d_mark_recompute(p);
806 }else{
807 // mid slider of an axis dimension changed, move crosshairs
808 _sv_panel1d_update_crosshair(p);
812 static void _sv_panel1d_bracket_callback(sv_dim_list_t *dptr){
813 sv_dim_t *d = dptr->d;
814 sv_panel_t *p = dptr->p;
815 int axisp = d == p->private->x_d;
817 if(axisp)
818 _sv_panel1d_mark_recompute(p);
822 static void _sv_panel1d_dimchange_callback(GtkWidget *button,gpointer in){
823 sv_panel_t *p = (sv_panel_t *)in;
825 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))){
827 _sv_undo_push();
828 _sv_undo_suspend();
830 _sv_panel1d_update_xsel(p);
831 _sv_panel1d_update_crosshair(p);
832 _sv_plot_unset_box(PLOT(p->private->graph));
833 _sv_panel1d_mark_recompute(p);
835 _sv_undo_resume();
839 static void _sv_panel1d_crosshair_callback(sv_panel_t *p){
840 _sv_panel1d_t *p1 = p->subtype->p1;
841 double x=PLOT(p->private->graph)->selx;
842 int i;
844 if(p1->flip)
845 x=PLOT(p->private->graph)->sely;
847 _sv_panel_dirty_legend(p);
849 _sv_undo_push();
850 _sv_undo_suspend();
852 for(i=0;i<p->dimensions;i++){
853 sv_dim_t *d = p->dimension_list[i].d;
854 if(d == p->private->x_d)
855 _sv_dim_widget_set_thumb(p->private->dim_scales[i],1,x);
857 p->private->oldbox_active = 0;
861 static void _sv_panel1d_box_callback(void *in, int state){
862 sv_panel_t *p = (sv_panel_t *)in;
863 _sv_panel1d_t *p1 = p->subtype->p1;
864 _sv_plot_t *plot = PLOT(p->private->graph);
866 switch(state){
867 case 0: // box set
868 _sv_undo_push();
869 _sv_plot_box_vals(plot,p1->oldbox);
870 p->private->oldbox_active = plot->box_active;
871 break;
872 case 1: // box activate
873 _sv_undo_push();
874 _sv_undo_suspend();
876 _sv_panel1d_crosshair_callback(p);
878 _sv_dim_widget_set_thumb(p1->x_scale,0,p1->oldbox[0]);
879 _sv_dim_widget_set_thumb(p1->x_scale,2,p1->oldbox[1]);
880 p->private->oldbox_active = 0;
881 _sv_undo_resume();
882 break;
884 _sv_panel_update_menus(p);
887 void _sv_panel1d_maintain_cache(sv_panel_t *p, _sv_bythread_cache_1d_t *c, int w){
889 /* toplevel initialization */
890 if(c->fout == 0){
891 int i,j;
893 /* determine which functions are actually needed */
894 c->call = calloc(_sv_functions,sizeof(*c->call));
895 c->fout = calloc(_sv_functions,sizeof(*c->fout));
896 for(i=0;i<p->objectives;i++){
897 sv_obj_t *o = p->objective_list[i].o;
898 for(j=0;j<o->outputs;j++)
899 c->call[o->function_map[j]]=
900 _sv_function_list[o->function_map[j]]->callback;
904 /* once to begin, as well as anytime the data width changes */
905 if(c->storage_width < w){
906 int i;
907 c->storage_width = w;
909 for(i=0;i<_sv_functions;i++){
910 if(c->call[i]){
911 if(c->fout[i])free(c->fout[i]);
912 c->fout[i] = malloc(w * _sv_function_list[i]->outputs *
913 sizeof(**c->fout));
919 // subtype entry point for legend redraws; lock held
920 int _sv_panel1d_legend_redraw(sv_panel_t *p){
921 _sv_plot_t *plot = PLOT(p->private->graph);
923 if(p->private->legend_progress_count)return 0;
924 p->private->legend_progress_count++;
925 _sv_panel1d_update_legend(p);
926 _sv_panel_clean_legend(p);
928 gdk_threads_leave();
929 _sv_plot_draw_scales(plot);
930 gdk_threads_enter();
932 _sv_plot_expose_request(plot);
933 return 1;
936 // subtype entry point for recomputation; lock held
937 int _sv_panel1d_compute(sv_panel_t *p,
938 _sv_bythread_cache_t *c){
939 _sv_panel1d_t *p1 = p->subtype->p1;
940 _sv_plot_t *plot;
942 int dw,w,h,i,d;
943 int serialno;
944 int x_d=-1;
945 _sv_scalespace_t sy;
947 _sv_scalespace_t sx;
948 _sv_scalespace_t sxv;
949 _sv_scalespace_t sxi;
951 dw = p1->data_size;
952 w = p1->panel_w;
953 h = p1->panel_h;
955 sy = p1->y;
957 sx = p1->x;
958 sxv = p1->x_v;
959 sxi = p1->x_i;
961 if(p->private->plot_progress_count)
962 return 0;
964 serialno = p->private->plot_serialno;
965 p->private->plot_progress_count++;
966 d = p->dimensions;
967 plot = PLOT(p->private->graph);
969 /* render using local dimension array; several threads will be
970 computing objectives */
971 double dim_vals[_sv_dimensions];
973 /* get iterator bounds, use iterator scale */
974 x_d = p->private->x_d->number;
976 if(p1->flip){
977 plot->x = sy;
978 plot->y = sx;
979 plot->x_v = sy;
980 plot->y_v = sxv;
981 }else{
982 plot->x = sx;
983 plot->y = sy;
984 plot->x_v = sxv;
985 plot->y_v = sy;
988 // Initialize local dimension value array
989 for(i=0;i<_sv_dimensions;i++){
990 sv_dim_t *dim = _sv_dimension_list[i];
991 dim_vals[i]=dim->val;
994 _sv_panel1d_maintain_cache(p,&c->p1,dw);
996 /* unlock for computation */
997 gdk_threads_leave ();
999 _sv_panel1d_compute_line(p, serialno, x_d, sxi, dw, dim_vals, &c->p1);
1001 gdk_threads_enter ();
1003 if(serialno == p->private->plot_serialno){
1004 _sv_panel_dirty_map(p);
1005 _sv_panel_dirty_legend(p);
1006 _sv_panel_clean_plot(p);
1008 return 1;
1011 static void _sv_panel1d_undo_log(_sv_panel_undo_t *u, sv_panel_t *p){
1012 _sv_panel1d_t *p1 = p->subtype->p1;
1013 int i;
1015 // alloc fields as necessary
1016 if(!u->mappings)
1017 u->mappings = calloc(p->objectives,sizeof(*u->mappings));
1018 if(!u->scale_vals[0])
1019 u->scale_vals[0] = calloc(1,sizeof(**u->scale_vals));
1020 if(!u->scale_vals[1])
1021 u->scale_vals[1] = calloc(1,sizeof(**u->scale_vals));
1022 if(!u->scale_vals[2])
1023 u->scale_vals[2] = calloc(p->objectives,sizeof(**u->scale_vals));
1025 // populate undo
1026 u->scale_vals[0][0] = _sv_slider_get_value(p1->range_slider,0);
1027 u->scale_vals[1][0] = _sv_slider_get_value(p1->range_slider,1);
1029 for(i=0;i<p->objectives;i++){
1030 u->mappings[i] =
1031 (p1->mappings[i].mapnum<<24) |
1032 (p1->linetype[i]<<16) |
1033 (p1->pointtype[i]<<8);
1034 u->scale_vals[2][i] = _sv_slider_get_value(p1->alpha_scale[i],0);
1037 u->x_d = p1->x_dnum;
1038 u->box[0] = p1->oldbox[0];
1039 u->box[1] = p1->oldbox[1];
1041 u->box_active = p->private->oldbox_active;
1045 static void _sv_panel1d_undo_restore(_sv_panel_undo_t *u, sv_panel_t *p){
1046 _sv_panel1d_t *p1 = p->subtype->p1;
1047 _sv_plot_t *plot = PLOT(p->private->graph);
1049 int i;
1051 // go in through widgets
1053 _sv_slider_set_value(p1->range_slider,0,u->scale_vals[0][0]);
1054 _sv_slider_set_value(p1->range_slider,1,u->scale_vals[1][0]);
1056 for(i=0;i<p->objectives;i++){
1057 gtk_combo_box_set_active(GTK_COMBO_BOX(p1->map_pulldowns[i]), (u->mappings[i]>>24)&0xff );
1058 gtk_combo_box_set_active(GTK_COMBO_BOX(p1->line_pulldowns[i]), (u->mappings[i]>>16)&0xff );
1059 gtk_combo_box_set_active(GTK_COMBO_BOX(p1->point_pulldowns[i]), (u->mappings[i]>>8)&0xff );
1060 _sv_slider_set_value(p1->alpha_scale[i],0,u->scale_vals[2][i]);
1063 if(p1->dim_xb && u->x_d<p->dimensions && p1->dim_xb[u->x_d])
1064 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p1->dim_xb[u->x_d]),TRUE);
1066 _sv_panel1d_update_xsel(p);
1068 if(u->box_active){
1069 p1->oldbox[0] = u->box[0];
1070 p1->oldbox[1] = u->box[1];
1071 _sv_plot_box_set(plot,u->box);
1072 p->private->oldbox_active = 1;
1073 }else{
1074 _sv_plot_unset_box(plot);
1075 p->private->oldbox_active = 0;
1079 void _sv_panel1d_realize(sv_panel_t *p){
1080 _sv_panel1d_t *p1 = p->subtype->p1;
1081 char buffer[160];
1082 int i;
1083 _sv_undo_suspend();
1085 p->private->toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1086 g_signal_connect_swapped (G_OBJECT (p->private->toplevel), "delete-event",
1087 G_CALLBACK (_sv_clean_exit), (void *)SIGINT);
1089 // add border to sides with hbox/padding
1090 GtkWidget *borderbox = gtk_hbox_new(0,0);
1091 gtk_container_add (GTK_CONTAINER (p->private->toplevel), borderbox);
1093 // main layout vbox
1094 p->private->topbox = gtk_vbox_new(0,0);
1095 gtk_box_pack_start(GTK_BOX(borderbox), p->private->topbox, 1,1,4);
1096 gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 1);
1098 /* spinner, top bar */
1100 GtkWidget *hbox = gtk_hbox_new(0,0);
1101 gtk_box_pack_start(GTK_BOX(p->private->topbox), hbox, 0,0,0);
1102 gtk_box_pack_end(GTK_BOX(hbox),GTK_WIDGET(p->private->spinner),0,0,0);
1105 /* plotbox, graph */
1107 unsigned flags = 0;
1108 if(p1->flip)
1109 flags |= _SV_PLOT_NO_X_CROSS;
1110 else
1111 flags |= _SV_PLOT_NO_Y_CROSS;
1113 p1->graph_table = gtk_table_new(2,2,0);
1114 p->private->plotbox = p1->graph_table;
1115 gtk_box_pack_start(GTK_BOX(p->private->topbox), p->private->plotbox, 1,1,2);
1117 p->private->graph = GTK_WIDGET(_sv_plot_new(_sv_panel1d_recompute_callback,p,
1118 (void *)(void *)_sv_panel1d_crosshair_callback,p,
1119 _sv_panel1d_box_callback,p,flags));
1120 if(p1->flip){
1121 gtk_table_attach(GTK_TABLE(p1->graph_table),p->private->graph,0,2,0,1,
1122 GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,1);
1123 }else{
1124 gtk_table_attach(GTK_TABLE(p1->graph_table),p->private->graph,1,2,0,2,
1125 GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,1);
1129 /* range slider, goes in the plotbox table */
1130 /* may be vertical to the left of the plot or along the bottom if the plot is flipped */
1132 GtkWidget **sl = calloc(2,sizeof(*sl));
1133 int lo = p1->range_scale->val_list[0];
1134 int hi = p1->range_scale->val_list[p1->range_scale->vals-1];
1136 /* the range slices/slider */
1137 sl[0] = _sv_slice_new(_sv_panel1d_map_callback,p);
1138 sl[1] = _sv_slice_new(_sv_panel1d_map_callback,p);
1140 if(p1->flip){
1141 gtk_table_attach(GTK_TABLE(p1->graph_table),sl[0],0,1,1,2,
1142 GTK_EXPAND|GTK_FILL,0,0,0);
1143 gtk_table_attach(GTK_TABLE(p1->graph_table),sl[1],1,2,1,2,
1144 GTK_EXPAND|GTK_FILL,0,0,0);
1145 }else{
1146 gtk_table_attach(GTK_TABLE(p1->graph_table),sl[0],0,1,1,2,
1147 GTK_SHRINK,GTK_EXPAND|GTK_FILL,0,0);
1148 gtk_table_attach(GTK_TABLE(p1->graph_table),sl[1],0,1,0,1,
1149 GTK_SHRINK,GTK_EXPAND|GTK_FILL,0,0);
1150 gtk_table_set_col_spacing(GTK_TABLE(p1->graph_table),0,4);
1153 p1->range_slider = _sv_slider_new((_sv_slice_t **)sl,2,
1154 p1->range_scale->label_list,
1155 p1->range_scale->val_list,
1156 p1->range_scale->vals,
1157 (p1->flip?0:_SV_SLIDER_FLAG_VERTICAL));
1159 _sv_slice_thumb_set((_sv_slice_t *)sl[0],lo);
1160 _sv_slice_thumb_set((_sv_slice_t *)sl[1],hi);
1163 /* obj box */
1165 p1->obj_table = gtk_table_new(p->objectives,5,0);
1166 gtk_box_pack_start(GTK_BOX(p->private->topbox), p1->obj_table, 0,0,1);
1168 /* pulldowns */
1169 p1->pointtype = calloc(p->objectives,sizeof(*p1->pointtype));
1170 p1->linetype = calloc(p->objectives,sizeof(*p1->linetype));
1171 p1->mappings = calloc(p->objectives,sizeof(*p1->mappings));
1172 p1->map_pulldowns = calloc(p->objectives,sizeof(*p1->map_pulldowns));
1173 p1->line_pulldowns = calloc(p->objectives,sizeof(*p1->line_pulldowns));
1174 p1->point_pulldowns = calloc(p->objectives,sizeof(*p1->point_pulldowns));
1175 p1->alpha_scale = calloc(p->objectives,sizeof(*p1->alpha_scale));
1177 for(i=0;i<p->objectives;i++){
1178 sv_obj_t *o = p->objective_list[i].o;
1180 /* label */
1181 GtkWidget *label = gtk_label_new(o->name);
1182 gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
1183 gtk_table_attach(GTK_TABLE(p1->obj_table),label,0,1,i,i+1,
1184 GTK_FILL,0,5,0);
1186 /* mapping pulldown */
1188 GtkWidget *menu=_gtk_combo_box_new_markup();
1189 int j;
1190 for(j=0;j<_sv_solid_names();j++){
1191 if(strcmp(_sv_solid_name(j),"inactive"))
1192 snprintf(buffer,sizeof(buffer),"<span foreground=\"%s\">%s</span>",
1193 _sv_solid_name(j),_sv_solid_name(j));
1194 else
1195 snprintf(buffer,sizeof(buffer),"%s",_sv_solid_name(j));
1197 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), buffer);
1199 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
1200 g_signal_connect (G_OBJECT (menu), "changed",
1201 G_CALLBACK (_sv_panel1d_mapchange_callback), p->objective_list+i);
1202 gtk_table_attach(GTK_TABLE(p1->obj_table),menu,1,2,i,i+1,
1203 GTK_SHRINK,GTK_SHRINK,5,0);
1204 p1->map_pulldowns[i] = menu;
1205 _sv_solid_setup(&p1->mappings[i],0.,1.,0);
1208 /* line pulldown */
1210 GtkWidget *menu=gtk_combo_box_new_text();
1211 int j;
1212 for(j=0;j<LINETYPES;j++)
1213 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), line_name[j]->left);
1214 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
1215 g_signal_connect (G_OBJECT (menu), "changed",
1216 G_CALLBACK (_sv_panel1d_linetype_callback), p->objective_list+i);
1217 gtk_table_attach(GTK_TABLE(p1->obj_table),menu,2,3,i,i+1,
1218 GTK_SHRINK,GTK_SHRINK,5,0);
1219 p1->line_pulldowns[i] = menu;
1222 /* point pulldown */
1224 GtkWidget *menu=gtk_combo_box_new_text();
1225 int j;
1226 for(j=0;j<POINTTYPES;j++)
1227 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), point_name[j]->left);
1228 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
1229 g_signal_connect (G_OBJECT (menu), "changed",
1230 G_CALLBACK (_sv_panel1d_pointtype_callback), p->objective_list+i);
1231 gtk_table_attach(GTK_TABLE(p1->obj_table),menu,3,4,i,i+1,
1232 GTK_SHRINK,GTK_SHRINK,5,0);
1233 p1->point_pulldowns[i] = menu;
1236 /* alpha slider */
1238 GtkWidget **sl = calloc(1, sizeof(*sl));
1239 sl[0] = _sv_slice_new(_sv_panel1d_alpha_callback,p->objective_list+i);
1241 gtk_table_attach(GTK_TABLE(p1->obj_table),sl[0],4,5,i,i+1,
1242 GTK_EXPAND|GTK_FILL,0,0,0);
1244 p1->alpha_scale[i] = _sv_slider_new((_sv_slice_t **)sl,1,
1245 (char *[]){"transparent","solid"},
1246 (double []){0.,1.},
1247 2,0);
1249 _sv_slider_set_gradient(p1->alpha_scale[i], &p1->mappings[i]);
1250 _sv_slice_thumb_set((_sv_slice_t *)sl[0],1.);
1256 /* dim box */
1257 if(p->dimensions){
1258 p1->dim_table = gtk_table_new(p->dimensions,3,0);
1259 gtk_box_pack_start(GTK_BOX(p->private->topbox), p1->dim_table, 0,0,4);
1261 p->private->dim_scales = calloc(p->dimensions,sizeof(*p->private->dim_scales));
1262 p1->dim_xb = calloc(p->dimensions,sizeof(*p1->dim_xb));
1263 GtkWidget *first_x = NULL;
1265 for(i=0;i<p->dimensions;i++){
1266 sv_dim_t *d = p->dimension_list[i].d;
1268 /* label */
1269 GtkWidget *label = gtk_label_new(d->name);
1270 gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
1271 gtk_table_attach(GTK_TABLE(p1->dim_table),label,0,1,i,i+1,
1272 GTK_FILL,0,5,0);
1274 /* x radio buttons */
1275 if(!(d->flags & SV_DIM_NO_X)){
1276 if(first_x)
1277 p1->dim_xb[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_x),"X");
1278 else{
1279 first_x = p1->dim_xb[i] = gtk_radio_button_new_with_label(NULL,"X");
1280 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p1->dim_xb[i]),TRUE);
1282 gtk_table_attach(GTK_TABLE(p1->dim_table),p1->dim_xb[i],1,2,i,i+1,
1283 0,0,3,0);
1286 p->private->dim_scales[i] =
1287 _sv_dim_widget_new(p->dimension_list+i,_sv_panel1d_center_callback,_sv_panel1d_bracket_callback);
1289 gtk_table_attach(GTK_TABLE(p1->dim_table),
1290 GTK_WIDGET(p->private->dim_scales[i]->t),
1291 2,3,i,i+1,
1292 GTK_EXPAND|GTK_FILL,0,0,0);
1296 for(i=0;i<p->dimensions;i++)
1297 if(p1->dim_xb[i])
1298 g_signal_connect (G_OBJECT (p1->dim_xb[i]), "toggled",
1299 G_CALLBACK (_sv_panel1d_dimchange_callback), p);
1301 _sv_panel1d_update_xsel(p);
1304 gtk_widget_realize(p->private->toplevel);
1305 gtk_widget_realize(p->private->graph);
1306 gtk_widget_realize(GTK_WIDGET(p->private->spinner));
1307 gtk_widget_show_all(p->private->toplevel);
1309 _sv_undo_resume();
1313 static int _sv_panel1d_save(sv_panel_t *p, xmlNodePtr pn){
1314 _sv_panel1d_t *p1 = p->subtype->p1;
1315 int ret=0,i;
1317 xmlNodePtr n;
1319 xmlNewProp(pn, (xmlChar *)"type", (xmlChar *)"1d");
1321 // box
1322 if(p->private->oldbox_active){
1323 xmlNodePtr boxn = xmlNewChild(pn, NULL, (xmlChar *) "box", NULL);
1324 _xmlNewPropF(boxn, "x1", p1->oldbox[0]);
1325 _xmlNewPropF(boxn, "x2", p1->oldbox[1]);
1328 // objective map settings
1329 for(i=0;i<p->objectives;i++){
1330 sv_obj_t *o = p->objective_list[i].o;
1332 xmlNodePtr on = xmlNewChild(pn, NULL, (xmlChar *) "objective", NULL);
1333 _xmlNewPropI(on, "position", i);
1334 _xmlNewPropI(on, "number", o->number);
1335 _xmlNewPropS(on, "name", o->name);
1336 _xmlNewPropS(on, "type", o->output_types);
1338 // right now Y is the only type; the below is Y-specific
1340 n = xmlNewChild(on, NULL, (xmlChar *) "y-map", NULL);
1341 _xmlNewMapProp(n, "color", _sv_solid_map(), p1->mappings[i].mapnum);
1342 _xmlNewMapProp(n, "line", line_name, p1->linetype[i]);
1343 _xmlNewMapProp(n, "point", point_name, p1->pointtype[i]);
1344 _xmlNewPropF(n, "alpha", _sv_slider_get_value(p1->alpha_scale[i],0));
1347 // y scale
1348 n = xmlNewChild(pn, NULL, (xmlChar *) "range", NULL);
1349 _xmlNewPropF(n, "low-bracket", _sv_slider_get_value(p1->range_slider,0));
1350 _xmlNewPropF(n, "high-bracket", _sv_slider_get_value(p1->range_slider,1));
1352 // x/y dim selection
1353 n = xmlNewChild(pn, NULL, (xmlChar *) "axes", NULL);
1354 _xmlNewPropI(n, "xpos", p1->x_dnum);
1356 return ret;
1359 int _sv_panel1d_load(sv_panel_t *p,
1360 _sv_panel_undo_t *u,
1361 xmlNodePtr pn,
1362 int warn){
1363 int i;
1365 // check type
1366 _xmlCheckPropS(pn,"type","1d", "Panel %d type mismatch in save file.",p->number,&warn);
1368 // box
1369 u->box_active = 0;
1370 _xmlGetChildPropFPreserve(pn, "box", "x1", &u->box[0]);
1371 _xmlGetChildPropFPreserve(pn, "box", "x2", &u->box[1]);
1373 xmlNodePtr n = _xmlGetChildS(pn, "box", NULL, NULL);
1374 if(n){
1375 u->box_active = 1;
1376 xmlFree(n);
1379 // objective map settings
1380 for(i=0;i<p->objectives;i++){
1381 sv_obj_t *o = p->objective_list[i].o;
1382 xmlNodePtr on = _xmlGetChildI(pn, "objective", "position", i);
1383 if(!on){
1384 _sv_first_load_warning(&warn);
1385 fprintf(stderr,"No save data found for panel %d objective \"%s\".\n",p->number, o->name);
1386 }else{
1387 // check name, type
1388 _xmlCheckPropS(on,"name",o->name, "Objectve position %d name mismatch in save file.",i,&warn);
1389 _xmlCheckPropS(on,"type",o->output_types, "Objectve position %d type mismatch in save file.",i,&warn);
1391 // right now Y is the only type; the below is Y-specific
1392 // load maptype, values
1393 int color = (u->mappings[i]>>24)&0xff;
1394 int line = (u->mappings[i]>>16)&0xff;
1395 int point = (u->mappings[i]>>8)&0xff;
1397 _xmlGetChildMapPreserve(on, "y-map", "color", _sv_solid_map(), &color,
1398 "Panel %d objective unknown mapping setting", p->number, &warn);
1399 _xmlGetChildMapPreserve(on, "y-map", "line", line_name, &line,
1400 "Panel %d objective unknown mapping setting", p->number, &warn);
1401 _xmlGetChildMapPreserve(on, "y-map", "point", point_name, &point,
1402 "Panel %d objective unknown mapping setting", p->number, &warn);
1403 _xmlGetChildPropF(on, "y-map", "alpha", &u->scale_vals[2][i]);
1405 u->mappings[i] = (color<<24) | (line<<16) | (point<<8);
1407 xmlFreeNode(on);
1411 // y scale
1412 _xmlGetChildPropFPreserve(pn, "range", "low-bracket", &u->scale_vals[0][0]);
1413 _xmlGetChildPropF(pn, "range", "high-bracket", &u->scale_vals[1][0]);
1415 // x/y dim selection
1416 _xmlGetChildPropI(pn, "axes", "xpos", &u->x_d);
1418 return warn;
1421 sv_panel_t *sv_panel_new_1d(int number,
1422 char *name,
1423 sv_scale_t *scale,
1424 char *objectivelist,
1425 char *dimensionlist,
1426 unsigned flags){
1428 sv_panel_t *p = _sv_panel_new(number,name,objectivelist,dimensionlist,flags);
1429 _sv_panel1d_t *p1;
1431 if(!p)return p;
1432 p1 = calloc(1, sizeof(*p1));
1433 p->subtype = calloc(1, sizeof(*p->subtype));
1435 p->subtype->p1 = p1;
1436 p->type = SV_PANEL_1D;
1437 p1->range_scale = (sv_scale_t *)scale;
1438 p->private->bg_type = SV_BG_WHITE;
1440 if(p->flags && SV_PANEL_FLIP)
1441 p1->flip=1;
1443 p->private->realize = _sv_panel1d_realize;
1444 p->private->map_action = _sv_panel1d_map_redraw;
1445 p->private->legend_action = _sv_panel1d_legend_redraw;
1446 p->private->compute_action = _sv_panel1d_compute;
1447 p->private->request_compute = _sv_panel1d_mark_recompute;
1448 p->private->crosshair_action = _sv_panel1d_crosshair_callback;
1449 p->private->print_action = _sv_panel1d_print;
1450 p->private->save_action = _sv_panel1d_save;
1451 p->private->load_action = _sv_panel1d_load;
1453 p->private->undo_log = _sv_panel1d_undo_log;
1454 p->private->undo_restore = _sv_panel1d_undo_restore;
1455 p->private->def_oversample_n = p->private->oversample_n = 1;
1456 p->private->def_oversample_d = p->private->oversample_d = 8;
1458 return p;