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)
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.
30 #include <sys/types.h>
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
){"no line", 5, NULL
,NULL
,NULL
},
44 static _sv_propmap_t
*point_name
[POINTTYPES
+1] = {
45 &(_sv_propmap_t
){"dot", 0, NULL
,NULL
,NULL
},
46 &(_sv_propmap_t
){"cross", 1, NULL
,NULL
,NULL
},
47 &(_sv_propmap_t
){"plus", 2, NULL
,NULL
,NULL
},
48 &(_sv_propmap_t
){"open circle", 3, NULL
,NULL
,NULL
},
49 &(_sv_propmap_t
){"open square", 4, NULL
,NULL
,NULL
},
50 &(_sv_propmap_t
){"open triangle", 5, NULL
,NULL
,NULL
},
51 &(_sv_propmap_t
){"solid circle", 6, NULL
,NULL
,NULL
},
52 &(_sv_propmap_t
){"solid square", 7, NULL
,NULL
,NULL
},
53 &(_sv_propmap_t
){"solid triangle", 8, NULL
,NULL
,NULL
},
57 static void _sv_panelxy_clear_data(sv_panel_t
*p
){
58 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
62 for(i
=0;i
<p
->objectives
;i
++){
71 for(i
=0;i
<p
->objectives
;i
++){
80 static void render_checks(cairo_t
*c
, int w
, int h
){
81 /* default checked background */
82 /* 16x16 'mid-checks' */
85 cairo_set_source_rgb (c
, .5,.5,.5);
87 cairo_set_source_rgb (c
, .314,.314,.314);
93 cairo_rectangle(c
,x
,y
,16.,16.);
101 // called internally, assumes we hold lock
102 // redraws the data, does not compute the data
103 static int _sv_panelxy_remap(sv_panel_t
*p
, cairo_t
*c
){
104 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
105 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
107 int plot_serialno
= p
->private->plot_serialno
;
108 int map_serialno
= p
->private->map_serialno
;
110 int pw
= plot
->x
.pixels
;
111 int ph
= plot
->y
.pixels
;
114 _sv_scalespace_t sx
= xy
->x
;
115 _sv_scalespace_t sy
= xy
->y
;
116 _sv_scalespace_t data_v
= xy
->data_v
;
117 _sv_scalespace_t px
= plot
->x
;
118 _sv_scalespace_t py
= plot
->y
;
120 /* do the panel and plot scales match? If not, redraw the plot
123 if(memcmp(&sx
,&px
,sizeof(sx
)) ||
124 memcmp(&sy
,&py
,sizeof(sy
))){
130 _sv_plot_draw_scales(plot
);
134 /* blank frame to selected bg */
135 switch(p
->private->bg_type
){
137 cairo_set_source_rgb (c
, 1.,1.,1.);
141 cairo_set_source_rgb (c
, 0,0,0);
145 render_checks(c
,pw
,ph
);
150 if(plot_serialno
!= p
->private->plot_serialno
||
151 map_serialno
!= p
->private->map_serialno
) return -1;
153 if(xy
->x_vec
&& xy
->y_vec
){
154 int dw
= data_v
.pixels
;
155 double *xv
= calloc(dw
,sizeof(*xv
));
156 double *yv
= calloc(dw
,sizeof(*yv
));
159 for(j
=0;j
<p
->objectives
;j
++){
160 if(xy
->x_vec
[j
] && xy
->y_vec
[j
] && !_sv_mapping_inactive_p(xy
->mappings
+j
)){
162 double alpha
= _sv_slider_get_value(xy
->alpha_scale
[j
],0);
163 int linetype
= xy
->linetype
[j
];
164 int pointtype
= xy
->pointtype
[j
];
165 u_int32_t color
= _sv_mapping_calc(xy
->mappings
+j
,1.,0);
167 // copy the list data over
168 memcpy(xv
,xy
->x_vec
[j
],dw
*sizeof(*xv
));
169 memcpy(yv
,xy
->y_vec
[j
],dw
*sizeof(*yv
));
173 for(xi
=0;xi
<dw
;xi
++){
174 double xpixel
= xv
[xi
];
175 double ypixel
= yv
[xi
];
177 /* map data vector bin to x pixel location in the plot */
179 xpixel
= _sv_scalespace_pixel(&sx
,xpixel
)+.5;
182 ypixel
= _sv_scalespace_pixel(&sy
,ypixel
)+.5;
188 /* draw lines, if any */
190 cairo_set_source_rgba(c
,
191 ((color
>>16)&0xff)/255.,
192 ((color
>>8)&0xff)/255.,
196 cairo_set_line_width(c
,2.);
198 cairo_set_line_width(c
,1.);
202 if(!isnan(yv
[i
-1]) && !isnan(yv
[i
]) &&
203 !isnan(xv
[i
-1]) && !isnan(xv
[i
]) &&
204 !(xv
[i
-1] < 0 && xv
[i
] < 0) &&
205 !(yv
[i
-1] < 0 && yv
[i
] < 0) &&
206 !(xv
[i
-1] > pw
&& xv
[i
] > pw
) &&
207 !(yv
[i
-1] > ph
&& yv
[i
] > ph
)){
209 cairo_move_to(c
,xv
[i
-1],yv
[i
-1]);
210 cairo_line_to(c
,xv
[i
],yv
[i
]);
216 /* now draw the points */
217 if(pointtype
> 0 || linetype
== 5){
218 cairo_set_line_width(c
,1.);
232 cairo_set_source_rgba(c
,
233 ((color
>>16)&0xff)/255.,
234 ((color
>>8)&0xff)/255.,
239 case 0: /* pixeldots */
240 cairo_rectangle(c
, xx
-.5,yy
-.5,1,1);
244 cairo_move_to(c
,xx
-4,yy
-4);
245 cairo_line_to(c
,xx
+4,yy
+4);
246 cairo_move_to(c
,xx
+4,yy
-4);
247 cairo_line_to(c
,xx
-4,yy
+4);
250 cairo_move_to(c
,xx
-4,yy
);
251 cairo_line_to(c
,xx
+4,yy
);
252 cairo_move_to(c
,xx
,yy
-4);
253 cairo_line_to(c
,xx
,yy
+4);
255 case 3: case 6: /* circle */
256 cairo_arc(c
,xx
,yy
,4,0,2.*M_PI
);
258 case 4: case 7: /* square */
259 cairo_rectangle(c
,xx
-4,yy
-4,8,8);
261 case 5: case 8: /* triangle */
262 cairo_move_to(c
,xx
,yy
-5);
263 cairo_line_to(c
,xx
-4,yy
+3);
264 cairo_line_to(c
,xx
+4,yy
+3);
270 cairo_fill_preserve(c
);
274 if(p
->private->bg_type
== SV_BG_WHITE
)
275 cairo_set_source_rgba(c
,0.,0.,0.,alpha
);
277 cairo_set_source_rgba(c
,1.,1.,1.,alpha
);
285 if(plot_serialno
!= p
->private->plot_serialno
||
286 map_serialno
!= p
->private->map_serialno
){
300 static void _sv_panelxy_print(sv_panel_t
*p
, cairo_t
*c
, int w
, int h
){
301 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
302 double pw
= p
->private->graph
->allocation
.width
;
303 double ph
= p
->private->graph
->allocation
.height
;
312 cairo_get_matrix(c
,&m
);
313 cairo_matrix_scale(&m
,scale
,scale
);
314 cairo_set_matrix(c
,&m
);
316 _sv_plot_print(plot
, c
, ph
*scale
, (void(*)(void *, cairo_t
*))_sv_panelxy_remap
, p
);
319 static void _sv_panelxy_update_legend(sv_panel_t
*p
){
320 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
321 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
323 gdk_threads_enter ();
328 _sv_plot_legend_clear(plot
);
330 if(3-_sv_scalespace_decimal_exponent(&xy
->x
) > depth
)
331 depth
= 3-_sv_scalespace_decimal_exponent(&xy
->x
);
332 if(3-_sv_scalespace_decimal_exponent(&xy
->y
) > depth
)
333 depth
= 3-_sv_scalespace_decimal_exponent(&xy
->y
);
335 // if crosshairs are active, add them to the fun
336 if( plot
->cross_active
){
337 char *legend
= xy
->x_scale
->legend
;
338 if(!strcmp(legend
,""))legend
= "X";
339 snprintf(buffer
,320,"%s = %+.*f",
343 _sv_plot_legend_add(plot
,buffer
);
345 legend
= xy
->y_scale
->legend
;
346 if(!strcmp(legend
,""))legend
= "Y";
347 snprintf(buffer
,320,"%s = %+.*f",
351 _sv_plot_legend_add(plot
,buffer
);
354 _sv_plot_legend_add(plot
,NULL
);
357 // add each dimension to the legend
358 if(-_sv_scalespace_decimal_exponent(&xy
->y
) > depth
)
359 depth
= -_sv_scalespace_decimal_exponent(&xy
->y
);
361 for(i
=0;i
<p
->dimensions
;i
++){
362 sv_dim_t
*d
= p
->dimension_list
[i
].d
;
364 if(d
!= p
->private->x_d
||
367 snprintf(buffer
,320,"%s = %+.*f",
368 p
->dimension_list
[i
].d
->name
,
370 p
->dimension_list
[i
].d
->val
);
371 _sv_plot_legend_add(plot
,buffer
);
375 gdk_threads_leave ();
380 static double _sv_panelxy_zoom_metric(sv_panel_t
*p
, int off
){
381 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
382 int on
= p
->objectives
;
383 double pw
= p
->private->graph
->allocation
.width
;
384 double ph
= p
->private->graph
->allocation
.height
;
385 int dw
= xy
->data_v
.pixels
;
387 // if this is a discrete data set, size/view changes cannot affect
388 // the data spacing; that's set by the discrete scale
389 if(p
->private->x_d
->type
!= SV_DIM_CONTINUOUS
) return -1;
391 double xscale
= _sv_scalespace_pixel(&xy
->x
,1.) - _sv_scalespace_pixel(&xy
->x
,0.);
392 double yscale
= _sv_scalespace_pixel(&xy
->y
,1.) - _sv_scalespace_pixel(&xy
->y
,0.);
393 double lox
= _sv_scalespace_value(&xy
->x
,0.);
394 double loy
= _sv_scalespace_value(&xy
->y
,ph
);
395 double hix
= _sv_scalespace_value(&xy
->x
,pw
);
396 double hiy
= _sv_scalespace_value(&xy
->y
,0.);
398 // by plane, look at the spacing between visible x/y points
403 if(xy
->x_vec
[i
] && xy
->y_vec
[i
]){
407 double *x
= xy
->x_vec
[i
];
408 double *y
= xy
->y_vec
[i
];
410 for(j
= off
; j
<dw
; j
++){
411 if(!isnan(x
[j
-off
]) &&
415 !(x
[j
-off
] < lox
&& x
[j
] < lox
) &&
416 !(y
[j
-off
] < loy
&& y
[j
] < loy
) &&
417 !(x
[j
-off
] > hix
&& x
[j
] > hix
) &&
418 !(y
[j
-off
] > hiy
&& y
[j
] > hiy
)){
420 xacc
+= (x
[j
-off
]-x
[j
]) * (x
[j
-off
]-x
[j
]);
421 yacc
+= (y
[j
-off
]-y
[j
]) * (y
[j
-off
]-y
[j
]);
427 double acc
= sqrt((xacc
*xscale
*xscale
+ yacc
*yscale
*yscale
)/count
);
428 if(acc
> max
) max
= acc
;
438 static int _sv_panelxy_mark_recompute_by_metric(sv_panel_t
*p
, int recursing
){
439 if(!p
->private->realized
) return 0;
441 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
443 // discrete val dimensions are immune to rerender by metric changes
444 if(p
->private->x_d
->type
!= SV_DIM_CONTINUOUS
) return 0;
446 double target
= (double) p
->private->oversample_d
/ p
->private->oversample_n
;
447 double full
= _sv_panelxy_zoom_metric(p
, 1);
450 // we want to halve the sample spacing. But first make sure we're
451 // not looping due to uncertainties in the metric.
452 if(recursing
&& xy
->prev_zoom
> xy
->curr_zoom
) return 0;
454 // also make sure our zoom level doesn't underflow
455 if(xy
->data_v
.massaged
|| xy
->curr_zoom
>48) return 0;
457 xy
->req_zoom
= xy
->curr_zoom
+1;
459 _sv_panel_dirty_plot(p
); // trigger recompute
463 double half
= _sv_panelxy_zoom_metric(p
, 2);
465 // we want to double the sample spacing. But first make sure we're
466 // not looping due to uncertainties in the metric.
467 if(recursing
&& xy
->prev_zoom
< xy
->curr_zoom
) return 0;
469 // also make sure our zoom level doesn't overrflow
470 if(xy
->curr_zoom
== 0) return 0;
472 xy
->req_zoom
= xy
->curr_zoom
-1;
474 _sv_panel_dirty_plot(p
); // trigger recompute
480 xy
->req_zoom
= xy
->prev_zoom
= xy
->curr_zoom
;
484 static void _sv_panelxy_mapchange_callback(GtkWidget
*w
,gpointer in
){
485 sv_obj_list_t
*optr
= (sv_obj_list_t
*)in
;
486 sv_panel_t
*p
= optr
->p
;
487 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
488 int onum
= optr
- p
->objective_list
;
489 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
496 int pos
= gtk_combo_box_get_active(GTK_COMBO_BOX(w
));
497 _sv_solid_set_func(&xy
->mappings
[onum
],pos
);
498 _sv_slider_set_gradient(xy
->alpha_scale
[onum
], &xy
->mappings
[onum
]);
500 // if the mapping has become inactive and the crosshairs point to
501 // this objective, inactivate the crosshairs.
502 if(xy
->cross_objnum
== onum
)
503 plot
->cross_active
= 0;
505 _sv_panel_dirty_map(p
);
506 _sv_panel_dirty_legend(p
);
511 static void _sv_panelxy_alpha_callback(void * in
, int buttonstate
){
512 sv_obj_list_t
*optr
= (sv_obj_list_t
*)in
;
513 sv_panel_t
*p
= optr
->p
;
515 if(buttonstate
== 0){
520 _sv_panel_dirty_map(p
);
521 _sv_panel_dirty_legend(p
);
527 static void _sv_panelxy_linetype_callback(GtkWidget
*w
,gpointer in
){
528 sv_obj_list_t
*optr
= (sv_obj_list_t
*)in
;
529 sv_panel_t
*p
= optr
->p
;
530 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
531 int onum
= optr
- p
->objective_list
;
537 int pos
= gtk_combo_box_get_active(GTK_COMBO_BOX(w
));
538 xy
->linetype
[onum
] = line_name
[pos
]->value
;
540 _sv_panel_dirty_map(p
);
544 static void _sv_panelxy_pointtype_callback(GtkWidget
*w
,gpointer in
){
545 sv_obj_list_t
*optr
= (sv_obj_list_t
*)in
;
546 sv_panel_t
*p
= optr
->p
;
547 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
548 int onum
= optr
- p
->objective_list
;
554 int pos
= gtk_combo_box_get_active(GTK_COMBO_BOX(w
));
555 xy
->pointtype
[onum
] = point_name
[pos
]->value
;
557 _sv_panel_dirty_map(p
);
561 static void _sv_panelxy_map_callback(void *in
,int buttonstate
){
562 sv_panel_t
*p
= (sv_panel_t
*)in
;
563 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
564 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
566 if(buttonstate
== 0){
571 // has new bracketing changed the plot range scale?
572 if(xy
->x_bracket
[0] != _sv_slider_get_value(xy
->x_slider
,0) ||
573 xy
->x_bracket
[1] != _sv_slider_get_value(xy
->x_slider
,1) ||
574 xy
->y_bracket
[0] != _sv_slider_get_value(xy
->y_slider
,0) ||
575 xy
->y_bracket
[1] != _sv_slider_get_value(xy
->y_slider
,1)){
577 int w
= plot
->w
.allocation
.width
;
578 int h
= plot
->w
.allocation
.height
;
580 xy
->x_bracket
[0] = _sv_slider_get_value(xy
->x_slider
,0);
581 xy
->x_bracket
[1] = _sv_slider_get_value(xy
->x_slider
,1);
582 xy
->y_bracket
[0] = _sv_slider_get_value(xy
->y_slider
,0);
583 xy
->y_bracket
[1] = _sv_slider_get_value(xy
->y_slider
,1);
586 xy
->x
= _sv_scalespace_linear(xy
->x_bracket
[0],
590 xy
->x_scale
->legend
);
591 xy
->y
= _sv_scalespace_linear(xy
->y_bracket
[1],
595 xy
->y_scale
->legend
);
597 // a map view size change may trigger a progressive up/down render,
598 // but will at least cause a remap
599 _sv_panelxy_mark_recompute_by_metric(p
,0);
600 _sv_panel_dirty_map(p
);
608 static void _sv_panelxy_update_xsel(sv_panel_t
*p
){
609 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
612 // enable/disable dimension slider thumbs
613 for(i
=0;i
<p
->dimensions
;i
++){
616 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xy
->dim_xb
[i
]))){
618 // set the x dim flag
619 p
->private->x_d
= p
->dimension_list
[i
].d
;
620 xy
->x_widget
= p
->private->dim_scales
[i
];
624 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xy
->dim_xb
[i
]))){
625 // make all thumbs visible
626 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],0,1);
627 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],2,1);
629 // make bracket thumbs invisible */
630 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],0,0);
631 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],2,0);
636 static void _sv_panelxy_compute_line(sv_panel_t
*p
,
639 _sv_scalespace_t sxi
,
644 _sv_bythread_cache_xy_t
*c
){
646 int i
,j
,fn
=_sv_functions
;
653 dim_vals
[x_d
] = _sv_scalespace_value(&sxi
,j
);
658 double *fout
= c
->fout
[i
];
659 c
->call
[i
](dim_vals
,fout
);
663 /* process function output by objective */
664 /* xy panels currently only care about the XY output values; in the
665 future, Z and others may also be relevant */
666 for(i
=0;i
<p
->objectives
;i
++){
667 sv_obj_t
*o
= p
->objective_list
[i
].o
;
668 int xoff
= o
->private->x_fout
;
669 int yoff
= o
->private->y_fout
;
670 sv_func_t
*xf
= o
->private->x_func
;
671 sv_func_t
*yf
= o
->private->y_func
;
672 x_vec
[i
][j
] = c
->fout
[xf
->number
][xoff
];
673 y_vec
[i
][j
] = c
->fout
[yf
->number
][yoff
];
680 if(serialno
!= p
->private->plot_serialno
){
685 _sv_spinner_set_busy(p
->private->spinner
);
692 void _sv_panelxy_mark_recompute(sv_panel_t
*p
){
693 if(!p
->private->realized
) return;
695 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
696 xy
->req_zoom
= xy
->prev_zoom
= xy
->curr_zoom
;
697 _sv_panel_dirty_plot(p
);
700 // subtype entry point for plot remaps; lock held
701 int _sv_panelxy_map_redraw(sv_panel_t
*p
, _sv_bythread_cache_t
*c
){
702 if(p
->private->map_progress_count
)return 0;
703 p
->private->map_progress_count
++;
705 // render to a temp surface so that we can release the lock occasionally
706 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
707 cairo_surface_t
*back
= plot
->back
;
708 cairo_surface_t
*cs
= cairo_surface_create_similar(back
,CAIRO_CONTENT_COLOR
,
709 cairo_image_surface_get_width(back
),
710 cairo_image_surface_get_height(back
));
711 cairo_t
*ct
= cairo_create(cs
);
713 if(_sv_panelxy_remap(p
,ct
) == -1){ // returns -1 on abort
715 cairo_surface_destroy(cs
);
718 cairo_surface_destroy(plot
->back
);
722 _sv_panel_clean_map(p
);
723 _sv_plot_expose_request(plot
);
729 static void _sv_panelxy_recompute_callback(void *ptr
){
730 sv_panel_t
*p
= (sv_panel_t
*)ptr
;
731 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
732 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
733 int w
= plot
->w
.allocation
.width
;
734 int h
= plot
->w
.allocation
.height
;
736 plot
->x
= xy
->x
= _sv_scalespace_linear(xy
->x_bracket
[0],
740 xy
->x_scale
->legend
);
741 plot
->y
= xy
->y
= _sv_scalespace_linear(xy
->y_bracket
[1],
745 xy
->y_scale
->legend
);
747 if(xy
->panel_w
!= w
|| xy
->panel_h
!= h
){
748 p
->private->map_progress_count
=0;
749 _sv_panelxy_map_redraw(p
, NULL
);
755 // always recompute, but also update zoom
756 if(!_sv_panelxy_mark_recompute_by_metric(p
,0))
757 _sv_panelxy_mark_recompute(p
);
760 static void _sv_panelxy_update_crosshair(sv_panel_t
*p
){
761 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
762 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
765 if(!p
->private->realized
)return;
767 // crosshairs snap to the x/y location of a point; however, with
768 // multiple objectives, there are probably multiple possible points.
769 // So, if we're currently pointing to a point for a given objective,
770 // update to a point on the same objective. Otherwise if crosshairs
771 // are inactive, do nothing.
773 if(!plot
->cross_active
)return;
774 if(xy
->cross_objnum
<0 || xy
->cross_objnum
>= p
->objectives
)return;
775 if(!xy
->x_vec
|| !xy
->y_vec
)return;
776 if(!xy
->x_vec
[xy
->cross_objnum
] || !xy
->y_vec
[xy
->cross_objnum
])return;
778 // get bin number of dim value
779 int x_bin
= rint(_sv_scalespace_pixel(&xy
->data_v
, p
->private->x_d
->val
));
780 double x
= xy
->x_vec
[xy
->cross_objnum
][x_bin
];
781 double y
= xy
->y_vec
[xy
->cross_objnum
][x_bin
];
783 _sv_plot_set_crosshairs(plot
,x
,y
);
784 _sv_dim_set_thumb(p
->private->x_d
,1,_sv_scalespace_value(&xy
->data_v
, x_bin
));
786 _sv_panel_dirty_legend(p
);
789 static void _sv_panelxy_center_callback(sv_dim_list_t
*dptr
){
790 sv_dim_t
*d
= dptr
->d
;
791 sv_panel_t
*p
= dptr
->p
;
792 int axisp
= (d
== p
->private->x_d
);
795 // mid slider of a non-axis dimension changed, rerender
796 _sv_panelxy_clear_data(p
);
797 _sv_panelxy_mark_recompute(p
);
799 // mid slider of an axis dimension changed, move crosshairs
800 _sv_panelxy_update_crosshair(p
);
804 static void _sv_panelxy_bracket_callback(sv_dim_list_t
*dptr
){
805 sv_dim_t
*d
= dptr
->d
;
806 sv_panel_t
*p
= dptr
->p
;
807 int axisp
= (d
== p
->private->x_d
);
809 // always need to recompute, may also need to update zoom
812 if(!_sv_panelxy_mark_recompute_by_metric(p
,0))
813 _sv_panelxy_mark_recompute(p
);
817 static void _sv_panelxy_dimchange_callback(GtkWidget
*button
,gpointer in
){
818 sv_panel_t
*p
= (sv_panel_t
*)in
;
819 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
821 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))){
826 _sv_panelxy_update_xsel(p
);
828 // clear data vectors so that none of the data is reused.
829 _sv_panelxy_clear_data(p
);
831 _sv_panelxy_update_crosshair(p
); // which is to say, deactivate it
832 _sv_plot_unset_box(PLOT(p
->private->graph
));
834 xy
->curr_zoom
= xy
->prev_zoom
= xy
->req_zoom
= 0;
835 _sv_panelxy_mark_recompute(p
);
841 static void _sv_panelxy_crosshair_callback(sv_panel_t
*p
){
842 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
843 double x
=PLOT(p
->private->graph
)->selx
;
844 double y
=PLOT(p
->private->graph
)->sely
;
850 // snap crosshairs to the closest plotted x/y point
855 if(xy
->x_vec
&& xy
->y_vec
){
856 for(i
=0;i
<p
->objectives
;i
++){
857 if(xy
->x_vec
[i
] && xy
->y_vec
[i
] && !_sv_mapping_inactive_p(xy
->mappings
+i
)){
858 for(j
=0;j
<xy
->data_v
.pixels
;j
++){
859 double xd
= x
- xy
->x_vec
[i
][j
];
860 double yd
= y
- xy
->y_vec
[i
][j
];
861 double dist
= xd
*xd
+ yd
*yd
;
862 if(besto
==-1 || dist
<bestdist
){
873 x
= xy
->x_vec
[besto
][bestbin
];
874 y
= xy
->y_vec
[besto
][bestbin
];
876 xy
->cross_objnum
= besto
;
878 double dimval
= _sv_scalespace_value(&xy
->data_v
, bestbin
);
879 _sv_dim_set_thumb(p
->private->x_d
,1,dimval
);
883 PLOT(p
->private->graph
)->selx
= x
;
884 PLOT(p
->private->graph
)->sely
= y
;
886 p
->private->oldbox_active
= 0;
888 _sv_panel_dirty_legend(p
);
892 static void _sv_panelxy_box_callback(void *in
, int state
){
893 sv_panel_t
*p
= (sv_panel_t
*)in
;
894 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
895 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
900 _sv_plot_box_vals(plot
,xy
->oldbox
);
901 p
->private->oldbox_active
= plot
->box_active
;
903 case 1: // box activate
907 _sv_panelxy_crosshair_callback(p
);
909 _sv_slider_set_value(xy
->x_slider
,0,xy
->oldbox
[0]);
910 _sv_slider_set_value(xy
->x_slider
,1,xy
->oldbox
[1]);
911 _sv_slider_set_value(xy
->y_slider
,0,xy
->oldbox
[2]);
912 _sv_slider_set_value(xy
->y_slider
,1,xy
->oldbox
[3]);
914 p
->private->oldbox_active
= 0;
918 _sv_panel_update_menus(p
);
921 void _sv_panelxy_maintain_cache(sv_panel_t
*p
, _sv_bythread_cache_xy_t
*c
, int w
){
923 /* toplevel initialization */
927 /* determine which functions are actually needed */
928 c
->call
= calloc(_sv_functions
,sizeof(*c
->call
));
929 c
->fout
= calloc(_sv_functions
,sizeof(*c
->fout
));
930 for(i
=0;i
<p
->objectives
;i
++){
931 sv_obj_t
*o
= p
->objective_list
[i
].o
;
932 for(j
=0;j
<o
->outputs
;j
++)
933 c
->call
[o
->function_map
[j
]]=
934 _sv_function_list
[o
->function_map
[j
]]->callback
;
937 for(i
=0;i
<_sv_functions
;i
++){
939 c
->fout
[i
] = malloc(_sv_function_list
[i
]->outputs
*
946 // subtype entry point for legend redraws; lock held
947 int _sv_panelxy_legend_redraw(sv_panel_t
*p
){
948 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
950 if(p
->private->legend_progress_count
)return 0;
951 p
->private->legend_progress_count
++;
952 _sv_panelxy_update_legend(p
);
953 _sv_panel_clean_legend(p
);
956 _sv_plot_draw_scales(plot
);
959 _sv_plot_expose_request(plot
);
963 // dim scales are autozoomed; we want the initial values to quantize
964 // to the same grid regardless of zoom level or starting bracket as
965 // well as only encompass the desired range
966 static int _sv_panelxy_generate_dimscale(sv_dim_t
*d
, int zoom
, _sv_scalespace_t
*v
, _sv_scalespace_t
*i
){
968 if(d
->type
!= SV_DIM_CONTINUOUS
){
969 // non-continuous is unaffected by zoom
970 _sv_dim_scales(d
, d
->bracket
[0], d
->bracket
[1], 2, 2, 1, d
->name
, NULL
, v
, i
);
974 // continuous dimensions are, in some ways, handled like a discrete dim.
975 double lo
= d
->scale
->val_list
[0];
976 double hi
= d
->scale
->val_list
[d
->scale
->vals
-1];
977 _sv_dim_scales(d
, lo
, hi
, 2, 2, 1, d
->name
, NULL
, v
, i
);
979 // this is iterative, not direct computation, so that at each level
980 // we have a small adjustment (as opposed to one huge adjustment at
983 int neg
= (lo
<hi
?1:-1);
986 // double scale resolution
987 _sv_scalespace_double(v
);
988 _sv_scalespace_double(i
);
990 if(v
->massaged
)return 1;
992 // clip scales down the the desired part of the range
993 // an assumption: v->step_pixel == 1 because spacing is 1. We can
994 // increment first_val instead of first_pixel.
995 while(_sv_scalespace_value(v
,1)*neg
< d
->bracket
[0]*neg
){
996 v
->first_val
+= v
->neg
;
997 i
->first_val
+= v
->neg
;
1002 while(v
->pixels
>2 && _sv_scalespace_value(v
,v
->pixels
-1)*neg
> d
->bracket
[1]*neg
){
1007 while(_sv_scalespace_value(v
,v
->pixels
-1)*neg
< d
->bracket
[1]*neg
){
1018 static void _sv_panelxy_rescale(_sv_scalespace_t
*old
, double **oldx
, double **oldy
,
1019 _sv_scalespace_t
*new, double **newx
, double **newy
,
1020 char *prefilled
, int objectives
){
1022 if(!oldx
|| !oldy
)return;
1028 for(j
=0;j
<objectives
;j
++)
1029 if(!oldx
[j
] || !oldy
[j
])
1032 long num
= _sv_scalespace_scalenum(new,old
);
1033 long den
= _sv_scalespace_scaleden(new,old
);
1034 long oldpos
= -_sv_scalespace_scalebin(new,old
);
1037 while(newi
< new->pixels
&& oldi
< old
->pixels
){
1039 if(oldpos
== newpos
&&
1041 prefilled
[newi
] = 1;
1042 for(j
=0;j
<objectives
;j
++){
1043 newx
[j
][newi
] = oldx
[j
][oldi
];
1044 newy
[j
][newi
] = oldy
[j
][oldi
];
1053 while(newi
< new->pixels
&& newpos
< oldpos
){
1057 while(oldi
< old
->pixels
&& oldpos
< newpos
){
1064 // subtype entry point for recomputation; lock held
1065 int _sv_panelxy_compute(sv_panel_t
*p
,
1066 _sv_bythread_cache_t
*c
){
1067 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
1073 int prev_zoom
= xy
->curr_zoom
;
1074 int zoom
= xy
->req_zoom
;
1076 _sv_scalespace_t sxv
= xy
->data_v
;
1077 plot
= PLOT(p
->private->graph
);
1080 w
= plot
->w
.allocation
.width
;
1081 h
= plot
->w
.allocation
.height
;
1083 // this computation is single-threaded for now
1084 if(p
->private->plot_progress_count
)
1087 serialno
= p
->private->plot_serialno
;
1088 p
->private->plot_progress_count
++;
1091 /* render using local dimension array; several threads will be
1092 computing objectives */
1093 double dim_vals
[_sv_dimensions
];
1095 /* get iterator bounds, use iterator scale */
1096 x_d
= p
->private->x_d
->number
;
1098 /* generate a new data_v/data_i */
1099 _sv_scalespace_t newv
;
1100 _sv_scalespace_t newi
;
1101 _sv_panelxy_generate_dimscale(p
->private->x_d
, zoom
, &newv
, &newi
);
1104 /* compare new/old data scales; pre-fill the data vec with values
1105 from old data vector if it can be reused */
1106 double *new_x_vec
[p
->objectives
];
1107 double *new_y_vec
[p
->objectives
];
1108 char *prefilled
= calloc(dw
,sizeof(*prefilled
));
1109 for(i
=0;i
<p
->objectives
;i
++){
1110 new_x_vec
[i
] = calloc(dw
,sizeof(**new_x_vec
));
1111 new_y_vec
[i
] = calloc(dw
,sizeof(**new_y_vec
));
1113 _sv_panelxy_rescale(&sxv
,xy
->x_vec
,xy
->y_vec
,
1114 &newv
,new_x_vec
,new_y_vec
,prefilled
, p
->objectives
);
1116 // Initialize local dimension value array
1117 for(i
=0;i
<_sv_dimensions
;i
++){
1118 sv_dim_t
*dim
= _sv_dimension_list
[i
];
1119 dim_vals
[i
]=dim
->val
;
1122 _sv_panelxy_maintain_cache(p
,&c
->xy
,dw
);
1127 /* unlock for computation */
1128 gdk_threads_leave ();
1130 _sv_panelxy_compute_line(p
, serialno
, x_d
, newi
, dim_vals
, prefilled
, new_x_vec
, new_y_vec
, &c
->xy
);
1132 gdk_threads_enter ();
1134 if(serialno
== p
->private->plot_serialno
){
1135 // replace data vectors
1136 p
->private->plot_serialno
++;
1137 _sv_panelxy_clear_data(p
);
1139 xy
->x_vec
= calloc(p
->objectives
, sizeof(*xy
->x_vec
));
1141 xy
->y_vec
= calloc(p
->objectives
, sizeof(*xy
->y_vec
));
1142 for(i
=0;i
<p
->objectives
;i
++){
1143 xy
->x_vec
[i
] = new_x_vec
[i
];
1144 xy
->y_vec
[i
] = new_y_vec
[i
];
1151 xy
->prev_zoom
= prev_zoom
;
1152 xy
->curr_zoom
= zoom
;
1154 _sv_panel_clean_plot(p
);
1155 if(!_sv_panelxy_mark_recompute_by_metric(p
, 1)){
1156 _sv_panel_dirty_legend(p
);
1157 _sv_panel_dirty_map(p
);
1159 _sv_panel_dirty_map_throttled(p
);
1163 for(i
=0;i
<p
->objectives
;i
++){
1173 static void _sv_panelxy_undo_log(_sv_panel_undo_t
*u
, sv_panel_t
*p
){
1174 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
1175 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
1178 // alloc fields as necessary
1180 u
->mappings
= calloc(p
->objectives
,sizeof(*u
->mappings
));
1181 if(!u
->scale_vals
[0])
1182 u
->scale_vals
[0] = calloc(3,sizeof(**u
->scale_vals
));
1183 if(!u
->scale_vals
[1])
1184 u
->scale_vals
[1] = calloc(3,sizeof(**u
->scale_vals
));
1185 if(!u
->scale_vals
[2])
1186 u
->scale_vals
[2] = calloc(p
->objectives
,sizeof(**u
->scale_vals
));
1189 u
->scale_vals
[0][0] = _sv_slider_get_value(xy
->x_slider
,0);
1190 u
->scale_vals
[1][0] = _sv_slider_get_value(xy
->x_slider
,1);
1191 u
->scale_vals
[0][1] = plot
->selx
;
1192 u
->scale_vals
[1][1] = plot
->sely
;
1193 u
->scale_vals
[0][2] = _sv_slider_get_value(xy
->y_slider
,0);
1194 u
->scale_vals
[1][2] = _sv_slider_get_value(xy
->y_slider
,1);
1196 for(i
=0;i
<p
->objectives
;i
++){
1198 (xy
->mappings
[i
].mapnum
<<24) |
1199 (xy
->linetype
[i
]<<16) |
1200 (xy
->pointtype
[i
]<<8);
1201 u
->scale_vals
[2][i
] = _sv_slider_get_value(xy
->alpha_scale
[i
],0);
1204 u
->x_d
= xy
->x_dnum
;
1205 u
->box
[0] = xy
->oldbox
[0];
1206 u
->box
[1] = xy
->oldbox
[1];
1207 u
->box
[2] = xy
->oldbox
[2];
1208 u
->box
[3] = xy
->oldbox
[3];
1210 u
->box_active
= p
->private->oldbox_active
;
1214 static void _sv_panelxy_undo_restore(_sv_panel_undo_t
*u
, sv_panel_t
*p
){
1215 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
1216 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
1220 // go in through widgets
1222 _sv_slider_set_value(xy
->x_slider
,0,u
->scale_vals
[0][0]);
1223 _sv_slider_set_value(xy
->x_slider
,1,u
->scale_vals
[1][0]);
1224 plot
->selx
= u
->scale_vals
[0][1];
1225 plot
->sely
= u
->scale_vals
[1][1];
1226 _sv_slider_set_value(xy
->y_slider
,0,u
->scale_vals
[0][2]);
1227 _sv_slider_set_value(xy
->y_slider
,1,u
->scale_vals
[1][2]);
1229 for(i
=0;i
<p
->objectives
;i
++){
1230 gtk_combo_box_set_active(GTK_COMBO_BOX(xy
->map_pulldowns
[i
]), (u
->mappings
[i
]>>24)&0xff );
1231 gtk_combo_box_set_active(GTK_COMBO_BOX(xy
->line_pulldowns
[i
]), (u
->mappings
[i
]>>16)&0xff );
1232 gtk_combo_box_set_active(GTK_COMBO_BOX(xy
->point_pulldowns
[i
]), (u
->mappings
[i
]>>8)&0xff );
1233 _sv_slider_set_value(xy
->alpha_scale
[i
],0,u
->scale_vals
[2][i
]);
1236 if(xy
->dim_xb
&& u
->x_d
<p
->dimensions
&& xy
->dim_xb
[u
->x_d
])
1237 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xy
->dim_xb
[u
->x_d
]),TRUE
);
1239 _sv_panelxy_update_xsel(p
);
1240 _sv_panelxy_crosshair_callback(p
);
1243 xy
->oldbox
[0] = u
->box
[0];
1244 xy
->oldbox
[1] = u
->box
[1];
1245 xy
->oldbox
[2] = u
->box
[2];
1246 xy
->oldbox
[3] = u
->box
[3];
1247 _sv_plot_box_set(plot
,u
->box
);
1248 p
->private->oldbox_active
= 1;
1250 _sv_plot_unset_box(plot
);
1251 p
->private->oldbox_active
= 0;
1255 static void _sv_panelxy_realize(sv_panel_t
*p
){
1256 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
1261 p
->private->toplevel
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1262 g_signal_connect_swapped (G_OBJECT (p
->private->toplevel
), "delete-event",
1263 G_CALLBACK (_sv_clean_exit
), (void *)SIGINT
);
1265 // add border to sides with hbox/padding
1266 GtkWidget
*borderbox
= gtk_hbox_new(0,0);
1267 gtk_container_add (GTK_CONTAINER (p
->private->toplevel
), borderbox
);
1270 p
->private->topbox
= gtk_vbox_new(0,0);
1271 gtk_box_pack_start(GTK_BOX(borderbox
), p
->private->topbox
, 1,1,4);
1272 gtk_container_set_border_width (GTK_CONTAINER (p
->private->toplevel
), 1);
1274 /* spinner, top bar */
1276 GtkWidget
*hbox
= gtk_hbox_new(0,0);
1277 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), hbox
, 0,0,0);
1278 gtk_box_pack_end(GTK_BOX(hbox
),GTK_WIDGET(p
->private->spinner
),0,0,0);
1281 /* plotbox, graph */
1283 xy
->graph_table
= gtk_table_new(3,3,0);
1284 p
->private->plotbox
= xy
->graph_table
;
1285 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), p
->private->plotbox
, 1,1,2);
1287 p
->private->graph
= GTK_WIDGET(_sv_plot_new(_sv_panelxy_recompute_callback
,p
,
1288 (void *)(void *)_sv_panelxy_crosshair_callback
,p
,
1289 _sv_panelxy_box_callback
,p
,0));
1291 gtk_table_attach(GTK_TABLE(xy
->graph_table
),p
->private->graph
,1,3,0,2,
1292 GTK_EXPAND
|GTK_FILL
,GTK_EXPAND
|GTK_FILL
,0,1);
1295 /* X range slider */
1296 /* Y range slider */
1298 GtkWidget
**slx
= calloc(2,sizeof(*slx
));
1299 GtkWidget
**sly
= calloc(2,sizeof(*sly
));
1301 /* the range slices/slider */
1302 slx
[0] = _sv_slice_new(_sv_panelxy_map_callback
,p
);
1303 slx
[1] = _sv_slice_new(_sv_panelxy_map_callback
,p
);
1304 sly
[0] = _sv_slice_new(_sv_panelxy_map_callback
,p
);
1305 sly
[1] = _sv_slice_new(_sv_panelxy_map_callback
,p
);
1307 gtk_table_attach(GTK_TABLE(xy
->graph_table
),slx
[0],1,2,2,3,
1308 GTK_EXPAND
|GTK_FILL
,0,0,0);
1309 gtk_table_attach(GTK_TABLE(xy
->graph_table
),slx
[1],2,3,2,3,
1310 GTK_EXPAND
|GTK_FILL
,0,0,0);
1311 gtk_table_attach(GTK_TABLE(xy
->graph_table
),sly
[0],0,1,1,2,
1312 GTK_SHRINK
,GTK_EXPAND
|GTK_FILL
,0,0);
1313 gtk_table_attach(GTK_TABLE(xy
->graph_table
),sly
[1],0,1,0,1,
1314 GTK_SHRINK
,GTK_EXPAND
|GTK_FILL
,0,0);
1315 gtk_table_set_col_spacing(GTK_TABLE(xy
->graph_table
),0,4);
1317 xy
->x_slider
= _sv_slider_new((_sv_slice_t
**)slx
,2,
1318 xy
->x_scale
->label_list
,
1319 xy
->x_scale
->val_list
,
1320 xy
->x_scale
->vals
,0);
1321 xy
->y_slider
= _sv_slider_new((_sv_slice_t
**)sly
,2,
1322 xy
->y_scale
->label_list
,
1323 xy
->y_scale
->val_list
,
1325 _SV_SLIDER_FLAG_VERTICAL
);
1327 int lo
= xy
->x_scale
->val_list
[0];
1328 int hi
= xy
->x_scale
->val_list
[xy
->x_scale
->vals
-1];
1329 _sv_slice_thumb_set((_sv_slice_t
*)slx
[0],lo
);
1330 _sv_slice_thumb_set((_sv_slice_t
*)slx
[1],hi
);
1332 lo
= xy
->y_scale
->val_list
[0];
1333 hi
= xy
->y_scale
->val_list
[xy
->y_scale
->vals
-1];
1334 _sv_slice_thumb_set((_sv_slice_t
*)sly
[0],lo
);
1335 _sv_slice_thumb_set((_sv_slice_t
*)sly
[1],hi
);
1340 xy
->obj_table
= gtk_table_new(p
->objectives
,5,0);
1341 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), xy
->obj_table
, 0,0,1);
1344 xy
->pointtype
= calloc(p
->objectives
,sizeof(*xy
->pointtype
));
1345 xy
->linetype
= calloc(p
->objectives
,sizeof(*xy
->linetype
));
1346 xy
->mappings
= calloc(p
->objectives
,sizeof(*xy
->mappings
));
1347 xy
->map_pulldowns
= calloc(p
->objectives
,sizeof(*xy
->map_pulldowns
));
1348 xy
->line_pulldowns
= calloc(p
->objectives
,sizeof(*xy
->line_pulldowns
));
1349 xy
->point_pulldowns
= calloc(p
->objectives
,sizeof(*xy
->point_pulldowns
));
1350 xy
->alpha_scale
= calloc(p
->objectives
,sizeof(*xy
->alpha_scale
));
1352 for(i
=0;i
<p
->objectives
;i
++){
1353 sv_obj_t
*o
= p
->objective_list
[i
].o
;
1356 GtkWidget
*label
= gtk_label_new(o
->name
);
1357 gtk_misc_set_alignment(GTK_MISC(label
),1.,.5);
1358 gtk_table_attach(GTK_TABLE(xy
->obj_table
),label
,0,1,i
,i
+1,
1361 /* mapping pulldown */
1363 GtkWidget
*menu
=_gtk_combo_box_new_markup();
1365 for(j
=0;j
<_sv_solid_names();j
++){
1366 if(strcmp(_sv_solid_name(j
),"inactive"))
1367 snprintf(buffer
,sizeof(buffer
),"<span foreground=\"%s\">%s</span>",_sv_solid_name(j
),_sv_solid_name(j
));
1369 snprintf(buffer
,sizeof(buffer
),"%s",_sv_solid_name(j
));
1371 gtk_combo_box_append_text (GTK_COMBO_BOX (menu
), buffer
);
1373 gtk_combo_box_set_active(GTK_COMBO_BOX(menu
),0);
1374 g_signal_connect (G_OBJECT (menu
), "changed",
1375 G_CALLBACK (_sv_panelxy_mapchange_callback
), p
->objective_list
+i
);
1376 gtk_table_attach(GTK_TABLE(xy
->obj_table
),menu
,1,2,i
,i
+1,
1377 GTK_SHRINK
,GTK_SHRINK
,5,0);
1378 xy
->map_pulldowns
[i
] = menu
;
1379 _sv_solid_setup(&xy
->mappings
[i
],0.,1.,0);
1384 GtkWidget
*menu
=gtk_combo_box_new_text();
1386 for(j
=0;j
<LINETYPES
;j
++)
1387 gtk_combo_box_append_text (GTK_COMBO_BOX (menu
), line_name
[j
]->left
);
1388 gtk_combo_box_set_active(GTK_COMBO_BOX(menu
),0);
1389 g_signal_connect (G_OBJECT (menu
), "changed",
1390 G_CALLBACK (_sv_panelxy_linetype_callback
), p
->objective_list
+i
);
1391 gtk_table_attach(GTK_TABLE(xy
->obj_table
),menu
,2,3,i
,i
+1,
1392 GTK_SHRINK
,GTK_SHRINK
,5,0);
1393 xy
->line_pulldowns
[i
] = menu
;
1396 /* point pulldown */
1398 GtkWidget
*menu
=gtk_combo_box_new_text();
1400 for(j
=0;j
<POINTTYPES
;j
++)
1401 gtk_combo_box_append_text (GTK_COMBO_BOX (menu
), point_name
[j
]->left
);
1402 gtk_combo_box_set_active(GTK_COMBO_BOX(menu
),0);
1403 g_signal_connect (G_OBJECT (menu
), "changed",
1404 G_CALLBACK (_sv_panelxy_pointtype_callback
), p
->objective_list
+i
);
1405 gtk_table_attach(GTK_TABLE(xy
->obj_table
),menu
,3,4,i
,i
+1,
1406 GTK_SHRINK
,GTK_SHRINK
,5,0);
1407 xy
->point_pulldowns
[i
] = menu
;
1412 GtkWidget
**sl
= calloc(1, sizeof(*sl
));
1413 sl
[0] = _sv_slice_new(_sv_panelxy_alpha_callback
,p
->objective_list
+i
);
1415 gtk_table_attach(GTK_TABLE(xy
->obj_table
),sl
[0],4,5,i
,i
+1,
1416 GTK_EXPAND
|GTK_FILL
,0,0,0);
1418 xy
->alpha_scale
[i
] = _sv_slider_new((_sv_slice_t
**)sl
,1,
1419 (char *[]){"transparent","solid"},
1423 _sv_slider_set_gradient(xy
->alpha_scale
[i
], &xy
->mappings
[i
]);
1424 _sv_slice_thumb_set((_sv_slice_t
*)sl
[0],1.);
1432 xy
->dim_table
= gtk_table_new(p
->dimensions
,3,0);
1433 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), xy
->dim_table
, 0,0,4);
1435 p
->private->dim_scales
= calloc(p
->dimensions
,sizeof(*p
->private->dim_scales
));
1436 xy
->dim_xb
= calloc(p
->dimensions
,sizeof(*xy
->dim_xb
));
1437 GtkWidget
*first_x
= NULL
;
1439 for(i
=0;i
<p
->dimensions
;i
++){
1440 sv_dim_t
*d
= p
->dimension_list
[i
].d
;
1443 GtkWidget
*label
= gtk_label_new(d
->name
);
1444 gtk_misc_set_alignment(GTK_MISC(label
),1.,.5);
1445 gtk_table_attach(GTK_TABLE(xy
->dim_table
),label
,0,1,i
,i
+1,
1448 /* x radio buttons */
1449 if(!(d
->flags
& SV_DIM_NO_X
)){
1451 xy
->dim_xb
[i
] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_x
),"X");
1453 first_x
= xy
->dim_xb
[i
] = gtk_radio_button_new_with_label(NULL
,"X");
1454 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xy
->dim_xb
[i
]),TRUE
);
1456 gtk_table_attach(GTK_TABLE(xy
->dim_table
),xy
->dim_xb
[i
],1,2,i
,i
+1,
1460 p
->private->dim_scales
[i
] =
1461 _sv_dim_widget_new(p
->dimension_list
+i
,_sv_panelxy_center_callback
,_sv_panelxy_bracket_callback
);
1463 gtk_table_attach(GTK_TABLE(xy
->dim_table
),
1464 GTK_WIDGET(p
->private->dim_scales
[i
]->t
),
1466 GTK_EXPAND
|GTK_FILL
,0,0,0);
1470 for(i
=0;i
<p
->dimensions
;i
++)
1472 g_signal_connect (G_OBJECT (xy
->dim_xb
[i
]), "toggled",
1473 G_CALLBACK (_sv_panelxy_dimchange_callback
), p
);
1475 _sv_panelxy_update_xsel(p
);
1478 gtk_widget_realize(p
->private->toplevel
);
1479 gtk_widget_realize(p
->private->graph
);
1480 gtk_widget_realize(GTK_WIDGET(p
->private->spinner
));
1481 gtk_widget_show_all(p
->private->toplevel
);
1487 static int _sv_panelxy_save(sv_panel_t
*p
, xmlNodePtr pn
){
1488 _sv_panelxy_t
*xy
= p
->subtype
->xy
;
1489 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
1494 xmlNewProp(pn
, (xmlChar
*)"type", (xmlChar
*)"xy");
1497 if(p
->private->oldbox_active
){
1498 xmlNodePtr boxn
= xmlNewChild(pn
, NULL
, (xmlChar
*) "box", NULL
);
1499 _xmlNewPropF(boxn
, "x1", xy
->oldbox
[0]);
1500 _xmlNewPropF(boxn
, "x2", xy
->oldbox
[1]);
1501 _xmlNewPropF(boxn
, "y1", xy
->oldbox
[2]);
1502 _xmlNewPropF(boxn
, "y2", xy
->oldbox
[3]);
1505 // objective map settings
1506 for(i
=0;i
<p
->objectives
;i
++){
1507 sv_obj_t
*o
= p
->objective_list
[i
].o
;
1509 xmlNodePtr on
= xmlNewChild(pn
, NULL
, (xmlChar
*) "objective", NULL
);
1510 _xmlNewPropI(on
, "position", i
);
1511 _xmlNewPropI(on
, "number", o
->number
);
1512 _xmlNewPropS(on
, "name", o
->name
);
1513 _xmlNewPropS(on
, "type", o
->output_types
);
1515 // right now Y is the only type; the below is Y-specific
1517 n
= xmlNewChild(on
, NULL
, (xmlChar
*) "y-map", NULL
);
1518 _xmlNewMapProp(n
, "color", _sv_solid_map(), xy
->mappings
[i
].mapnum
);
1519 _xmlNewMapProp(n
, "line", line_name
, xy
->linetype
[i
]);
1520 _xmlNewMapProp(n
, "point", point_name
, xy
->pointtype
[i
]);
1521 _xmlNewPropF(n
, "alpha", _sv_slider_get_value(xy
->alpha_scale
[i
],0));
1525 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "range", NULL
);
1526 _xmlNewPropF(n
, "x-low-bracket", _sv_slider_get_value(xy
->x_slider
,0));
1527 _xmlNewPropF(n
, "x-high-bracket", _sv_slider_get_value(xy
->x_slider
,1));
1528 _xmlNewPropF(n
, "y-low-bracket", _sv_slider_get_value(xy
->y_slider
,0));
1529 _xmlNewPropF(n
, "y-high-bracket", _sv_slider_get_value(xy
->y_slider
,1));
1530 _xmlNewPropF(n
, "x-cross", plot
->selx
);
1531 _xmlNewPropF(n
, "y-cross", plot
->sely
);
1533 // x/y dim selection
1534 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "axes", NULL
);
1535 _xmlNewPropI(n
, "xpos", xy
->x_dnum
);
1540 int _sv_panelxy_load(sv_panel_t
*p
,
1541 _sv_panel_undo_t
*u
,
1547 _xmlCheckPropS(pn
,"type","xy", "Panel %d type mismatch in save file.",p
->number
,&warn
);
1551 _xmlGetChildPropFPreserve(pn
, "box", "x1", &u
->box
[0]);
1552 _xmlGetChildPropFPreserve(pn
, "box", "x2", &u
->box
[1]);
1553 _xmlGetChildPropFPreserve(pn
, "box", "y1", &u
->box
[2]);
1554 _xmlGetChildPropFPreserve(pn
, "box", "y2", &u
->box
[3]);
1556 xmlNodePtr n
= _xmlGetChildS(pn
, "box", NULL
, NULL
);
1562 // objective map settings
1563 for(i
=0;i
<p
->objectives
;i
++){
1564 sv_obj_t
*o
= p
->objective_list
[i
].o
;
1565 xmlNodePtr on
= _xmlGetChildI(pn
, "objective", "position", i
);
1567 _sv_first_load_warning(&warn
);
1568 fprintf(stderr
,"No save data found for panel %d objective \"%s\".\n",p
->number
, o
->name
);
1571 _xmlCheckPropS(on
,"name",o
->name
, "Objectve position %d name mismatch in save file.",i
,&warn
);
1572 _xmlCheckPropS(on
,"type",o
->output_types
, "Objectve position %d type mismatch in save file.",i
,&warn
);
1574 // right now Y is the only type; the below is Y-specific
1575 // load maptype, values
1576 int color
= (u
->mappings
[i
]>>24)&0xff;
1577 int line
= (u
->mappings
[i
]>>16)&0xff;
1578 int point
= (u
->mappings
[i
]>>8)&0xff;
1580 _xmlGetChildMapPreserve(on
, "y-map", "color", _sv_solid_map(), &color
,
1581 "Panel %d objective unknown mapping setting", p
->number
, &warn
);
1582 _xmlGetChildMapPreserve(on
, "y-map", "line", line_name
, &line
,
1583 "Panel %d objective unknown mapping setting", p
->number
, &warn
);
1584 _xmlGetChildMapPreserve(on
, "y-map", "point", point_name
, &point
,
1585 "Panel %d objective unknown mapping setting", p
->number
, &warn
);
1586 _xmlGetChildPropF(on
, "y-map", "alpha", &u
->scale_vals
[2][i
]);
1588 u
->mappings
[i
] = (color
<<24) | (line
<<16) | (point
<<8);
1594 _xmlGetChildPropFPreserve(pn
, "range", "x-low-bracket", &u
->scale_vals
[0][0]);
1595 _xmlGetChildPropFPreserve(pn
, "range", "x-high-bracket", &u
->scale_vals
[1][0]);
1596 _xmlGetChildPropFPreserve(pn
, "range", "y-low-bracket", &u
->scale_vals
[0][2]);
1597 _xmlGetChildPropFPreserve(pn
, "range", "y-high-bracket", &u
->scale_vals
[1][2]);
1598 _xmlGetChildPropFPreserve(pn
, "range", "x-cross", &u
->scale_vals
[0][1]);
1599 _xmlGetChildPropF(pn
, "range", "y-cross", &u
->scale_vals
[1][1]);
1601 // x/y dim selection
1602 _xmlGetChildPropI(pn
, "axes", "xpos", &u
->x_d
);
1607 sv_panel_t
*sv_panel_new_xy(int number
,
1611 char *objectivelist
,
1612 char *dimensionlist
,
1615 sv_panel_t
*p
= _sv_panel_new(number
,name
,objectivelist
,dimensionlist
,flags
);
1619 xy
= calloc(1, sizeof(*xy
));
1620 p
->subtype
= calloc(1, sizeof(*p
->subtype
));
1622 p
->subtype
->xy
= xy
;
1623 p
->type
= SV_PANEL_XY
;
1624 xy
->x_scale
= (sv_scale_t
*)xscale
;
1625 xy
->y_scale
= (sv_scale_t
*)yscale
;
1626 p
->private->bg_type
= SV_BG_WHITE
;
1628 p
->private->realize
= _sv_panelxy_realize
;
1629 p
->private->map_action
= _sv_panelxy_map_redraw
;
1630 p
->private->legend_action
= _sv_panelxy_legend_redraw
;
1631 p
->private->compute_action
= _sv_panelxy_compute
;
1632 p
->private->request_compute
= _sv_panelxy_mark_recompute
;
1633 p
->private->crosshair_action
= _sv_panelxy_crosshair_callback
;
1634 p
->private->print_action
= _sv_panelxy_print
;
1635 p
->private->save_action
= _sv_panelxy_save
;
1636 p
->private->load_action
= _sv_panelxy_load
;
1638 p
->private->undo_log
= _sv_panelxy_undo_log
;
1639 p
->private->undo_restore
= _sv_panelxy_undo_restore
;
1640 p
->private->def_oversample_n
= p
->private->oversample_n
= 1;
1641 p
->private->def_oversample_d
= p
->private->oversample_d
= 8;