3 * sushivision copyright (C) 2006 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>
33 #include <gdk/gdkkeysyms.h>
37 static char *line_name
[LINETYPES
+1] = {
51 static void update_context_menus(sushiv_panel_t
*p
);
53 // called internally, assumes we hold lock
54 // redraws the data, does not compute the data
55 static void _sushiv_panel1d_remap(sushiv_panel_t
*p
){
56 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
57 Plot
*plot
= PLOT(p
->private->graph
);
58 cairo_surface_t
*cs
= plot
->back
;
59 cairo_t
*c
= cairo_create(cs
);
61 cairo_set_line_width(c
,1.);
65 int dw
= p1
->data_size
;
66 double h
= p1
->panel_h
;
68 /* blank frame to black */
69 cairo_set_source_rgb (c
, 0,0,0);
74 /* do the panel and plot scales match? If not, redraw the plot
77 scalespace sx
= (p1
->flip
?p1
->y
:p1
->x
);
78 scalespace sy
= (p1
->flip
?p1
->x
:p1
->y
);
80 if(memcmp(&sx
,&plot
->x
,sizeof(sx
)) ||
81 memcmp(&sy
,&plot
->y
,sizeof(sy
))){
85 plot_draw_scales(plot
);
89 for(i
=0;i
<p
->objectives
;i
++){
90 double *data_vec
= p1
->data_vec
[i
];
92 double yprev
=NAN
,xprev
=NAN
;
94 u_int32_t color
= mapping_calc(p1
->mappings
+i
,0,0);
96 cairo_set_source_rgb(c
,
97 ((color
>>16)&0xff)/255.,
98 ((color
>>8)&0xff)/255.,
102 for(xi
=0;xi
<dw
;xi
++){
103 double val
= data_vec
[xi
];
107 /* in linked panels, the data vector doesn't match the graph width; map */
108 if(p1
->link_x
|| p1
->link_y
)
109 xpixel
= scalespace_pixel(&p1
->x
,scalespace_value(&p1
->vs
,xpixel
))+.5;
111 /* map/render result */
113 ypixel
= scalespace_pixel(&p1
->y
,val
)+.5;
115 if(!isnan(ypixel
) && !isnan(yprev
)){
117 cairo_move_to(c
,yprev
,h
-xprev
);
118 cairo_line_to(c
,ypixel
,h
-xpixel
);
120 cairo_move_to(c
,xprev
,h
-yprev
);
121 cairo_line_to(c
,xpixel
,h
-ypixel
);
135 static void update_legend(sushiv_panel_t
*p
){
136 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
137 Plot
*plot
= PLOT(p
->private->graph
);
139 gdk_threads_enter ();
144 plot_legend_clear(plot
);
146 if(-p1
->vs
.decimal_exponent
> depth
) depth
= 3-p1
->vs
.decimal_exponent
;
148 // add each dimension to the legend
149 for(i
=0;i
<p
->dimensions
;i
++){
150 // display decimal precision relative to bracket
151 //int depth = del_depth(p->dimension_list[i].d->bracket[0],
152 // p->dimension_list[i].d->bracket[1]) + offset;
153 snprintf(buffer
,320,"%s = %+.*f",
154 p
->dimension_list
[i
].d
->name
,
156 p
->dimension_list
[i
].d
->val
);
157 plot_legend_add(plot
,buffer
);
160 // linked? add the linked dimension value to the legend
161 if(p1
->link_x
|| p1
->link_y
){
162 sushiv_dimension_t
*d
;
165 d
= p1
->link_x
->subtype
->p2
->x_d
;
167 d
= p1
->link_y
->subtype
->p2
->y_d
;
170 // add each dimension to the legend
171 // display decimal precision relative to display scales
172 if(3-p1
->vs
.decimal_exponent
> depth
) depth
= 3-p1
->vs
.decimal_exponent
;
173 snprintf(buffer
,320,"%s = %+.*f",
177 plot_legend_add(plot
,buffer
);
181 plot_legend_add(plot
,NULL
);
183 // add each active objective to the legend
184 // choose the value under the crosshairs
186 double val
= (p1
->flip
?plot
->sely
:plot
->selx
);
187 int bin
= scalespace_pixel(&p1
->vs
, val
);
188 u_int32_t color
= mapping_calc(p1
->mappings
+i
,0,0);
190 for(i
=0;i
<p
->objectives
;i
++){
192 snprintf(buffer
,320,"%s",
193 p
->objective_list
[i
].o
->name
);
195 if(bin
>=0 && bin
<p1
->data_size
){
197 float val
= p1
->data_vec
[i
][bin
];
200 snprintf(buffer
,320,"%s = %f",
201 p
->objective_list
[i
].o
->name
,
206 plot_legend_add_with_color(plot
,buffer
,color
);
210 gdk_threads_leave ();
214 void _sushiv_panel1d_map_redraw(sushiv_panel_t
*p
){
215 Plot
*plot
= PLOT(p
->private->graph
);
217 gdk_threads_enter (); // misuse me as a global mutex
219 _sushiv_panel1d_remap(p
);
221 plot_expose_request(plot
);
223 gdk_threads_leave (); // misuse me as a global mutex
226 void _sushiv_panel1d_legend_redraw(sushiv_panel_t
*p
){
227 Plot
*plot
= PLOT(p
->private->graph
);
229 gdk_threads_enter (); // misuse me as a global mutex
232 plot_draw_scales(plot
);
233 gdk_threads_leave (); // misuse me as a global mutex
236 static void mapchange_callback_1d(GtkWidget
*w
,gpointer in
){
237 sushiv_objective_list_t
*optr
= (sushiv_objective_list_t
*)in
;
238 sushiv_panel_t
*p
= optr
->p
;
239 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
240 int onum
= optr
- p
->objective_list
;
242 _sushiv_panel_undo_push(p
);
243 _sushiv_panel_undo_suspend(p
);
247 solid_set_func(&p1
->mappings
[onum
],
248 gtk_combo_box_get_active(GTK_COMBO_BOX(w
)));
250 _sushiv_panel_dirty_map(p
);
251 _sushiv_panel_dirty_legend(p
);
252 _sushiv_panel_undo_resume(p
);
255 static void linetype_callback_1d(GtkWidget
*w
,gpointer in
){
256 sushiv_objective_list_t
*optr
= (sushiv_objective_list_t
*)in
;
257 sushiv_panel_t
*p
= optr
->p
;
258 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
259 int onum
= optr
- p
->objective_list
;
261 _sushiv_panel_undo_push(p
);
262 _sushiv_panel_undo_suspend(p
);
265 p1
->linetype
[onum
]=gtk_combo_box_get_active(GTK_COMBO_BOX(w
));
267 _sushiv_panel_dirty_map(p
);
268 _sushiv_panel_undo_resume(p
);
271 static void map_callback_1d(void *in
,int buttonstate
){
272 sushiv_panel_t
*p
= (sushiv_panel_t
*)in
;
273 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
274 Plot
*plot
= PLOT(p
->private->graph
);
276 if(buttonstate
== 0){
277 _sushiv_panel_undo_push(p
);
278 _sushiv_panel_undo_suspend(p
);
281 // has new bracketing changed the plot range scale?
282 if(p1
->range_bracket
[0] != slider_get_value(p1
->range_slider
,0) ||
283 p1
->range_bracket
[1] != slider_get_value(p1
->range_slider
,1)){
285 int w
= plot
->w
.allocation
.width
;
286 int h
= plot
->w
.allocation
.height
;
288 p1
->range_bracket
[0] = slider_get_value(p1
->range_slider
,0);
289 p1
->range_bracket
[1] = slider_get_value(p1
->range_slider
,1);
291 p1
->y
= scalespace_linear(p1
->range_bracket
[0],
292 p1
->range_bracket
[1],
294 PLOT(p
->private->graph
)->scalespacing
,
295 p1
->range_scale
->legend
);
299 _sushiv_panel_dirty_map(p
);
301 _sushiv_panel_undo_resume(p
);
304 static void update_x_sel(sushiv_panel_t
*p
){
305 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
308 // enable/disable dimension slider thumbs
310 for(i
=0;i
<p
->dimensions
;i
++){
313 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p1
->dim_xb
[i
]))){
315 // set the x dim flag
316 p1
->x_d
= p
->dimension_list
[i
].d
;
317 p1
->x_scale
= p
->private->dim_scales
[i
];
320 // set panel x scale to this dim
321 p1
->x
= p1
->vs
= scalespace_linear(p1
->x_d
->bracket
[0],
324 PLOT(p
->private->graph
)->scalespacing
,
329 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p1
->dim_xb
[i
]))){
330 // make all thumbs visible
331 _sushiv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],0,1);
332 _sushiv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],2,1);
334 // make bracket thumbs invisible */
335 _sushiv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],0,0);
336 _sushiv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],2,0);
341 static void compute_1d(sushiv_panel_t
*p
,
348 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
354 for(i
=0;i
<p
->objectives
;i
++){
355 sushiv_objective_t
*o
= p
->objective_list
[i
].o
;
360 /* compute value for this objective for this pixel */
361 dim_vals
[x_d
] = (x_max
-x_min
) * inv_w
* j
+ x_min
;
362 o
->callback(dim_vals
,work
+j
);
366 gdk_threads_enter (); // misuse me as a global mutex
367 if(p1
->serialno
== serialno
){
368 /* store result in panel */
369 memcpy(p1
->data_vec
[i
],work
,w
*sizeof(*work
));
370 gdk_threads_leave (); // misuse me as a global mutex
372 gdk_threads_leave (); // misuse me as a global mutex
378 // call only from main gtk thread
379 void _mark_recompute_1d(sushiv_panel_t
*p
){
380 if(!p
->private->realized
) return;
381 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
382 Plot
*plot
= PLOT(p
->private->graph
);
383 int w
= plot
->w
.allocation
.width
;
384 int h
= plot
->w
.allocation
.height
;
386 sushiv_panel_t
*link
= (p1
->link_x
? p1
->link_x
: p1
->link_y
);
387 sushiv_panel2d_t
*p2
= (link
?link
->subtype
->p2
:NULL
);
393 p1
->x_scale
= p2
->x_scale
;
398 p1
->x_scale
= p2
->y_scale
;
401 if(plot
&& GTK_WIDGET_REALIZED(GTK_WIDGET(plot
))){
402 p1
->x
= scalespace_linear(p1
->x_d
->bracket
[0],
405 PLOT(p
->private->graph
)->scalespacing
,
408 p1
->y
= scalespace_linear(p1
->range_bracket
[0],
409 p1
->range_bracket
[1],
411 PLOT(p
->private->graph
)->scalespacing
,
412 p1
->range_scale
->legend
);
415 // handle the possibility that our data scale is from a link.
416 // 2d panels do not necessarily update their scales until
417 // recompute time, and 1d panels may be recomputed first,
418 // thus duplicate the scale computaiton here
419 p1
->vs
= scalespace_linear(p1
->x_d
->bracket
[0],
422 PLOT(p
->private->graph
)->scalespacing
,
425 // the data iterator may need to be mapped to the dimension type
426 p1
->vs
= _sushiv_dimension_datascale(p1
->x_d
, p1
->vs
);
428 if(p1
->data_size
!= dw
){
433 for(i
=0;i
<p
->objectives
;i
++){
434 double *new_vec
= malloc(dw
* sizeof(**p1
->data_vec
));
436 free(p1
->data_vec
[i
]);
437 p1
->data_vec
[i
] = new_vec
;
449 p1
->data_vec
= calloc(p
->objectives
,sizeof(*p1
->data_vec
));
450 for(i
=0;i
<p
->objectives
;i
++)
451 p1
->data_vec
[i
] = malloc(dw
*sizeof(**p1
->data_vec
));
456 for(i
=0;i
<p
->objectives
;i
++)
458 p1
->data_vec
[i
][j
]=NAN
;
462 _sushiv_wake_workers();
466 static void recompute_callback_1d(void *ptr
){
467 sushiv_panel_t
*p
= (sushiv_panel_t
*)ptr
;
468 _mark_recompute_1d(p
);
471 void _sushiv_panel1d_mark_recompute_linked(sushiv_panel_t
*p
){
474 /* look to see if any 1d panels link to passed in panel */
475 sushiv_instance_t
*s
= p
->sushi
;
476 for(i
=0;i
<s
->panels
;i
++){
477 sushiv_panel_t
*q
= s
->panel_list
[i
];
478 if(q
!= p
&& q
->type
== SUSHIV_PANEL_1D
){
479 sushiv_panel1d_t
*q1
= q
->subtype
->p1
;
481 _mark_recompute_1d(q
);
484 _mark_recompute_1d(q
);
490 static void update_crosshair(sushiv_panel_t
*p
){
491 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
492 sushiv_panel_t
*link
=p1
->link_x
;
493 Plot
*plot
= PLOT(p
->private->graph
);
497 if(!p
->private->realized
)return;
499 if(p1
->link_y
)link
=p1
->link_y
;
502 for(i
=0;i
<link
->dimensions
;i
++){
503 sushiv_dimension_t
*d
= link
->dimension_list
[i
].d
;
505 x
= link
->dimension_list
[i
].d
->val
;
508 for(i
=0;i
<p
->dimensions
;i
++){
509 sushiv_dimension_t
*d
= p
->dimension_list
[i
].d
;
511 x
= p
->dimension_list
[i
].d
->val
;
516 plot_set_crosshairs(plot
,0,x
);
518 plot_set_crosshairs(plot
,x
,0);
520 // in independent panels, crosshairs snap to a pixel position; the
521 // cached dimension value should be accurate with respect to the
522 // crosshairs. in linked panels, the crosshairs snap to a pixel
523 // position in the master panel; that is handled in the master, not
525 for(i
=0;i
<p
->dimensions
;i
++){
526 sushiv_dimension_t
*d
= p
->dimension_list
[i
].d
;
527 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
530 d
->val
= scalespace_value(&plot
->x
,plot_get_crosshair_ypixel(plot
));
532 d
->val
= scalespace_value(&plot
->x
,plot_get_crosshair_xpixel(plot
));
535 _sushiv_panel_dirty_legend(p
);
538 void _sushiv_panel1d_update_linked_crosshairs(sushiv_panel_t
*p
, int xflag
, int yflag
){
541 /* look to see if any 1d panels link to passed in panel */
542 sushiv_instance_t
*s
= p
->sushi
;
543 for(i
=0;i
<s
->panels
;i
++){
544 sushiv_panel_t
*q
= s
->panel_list
[i
];
545 if(q
!= p
&& q
->type
== SUSHIV_PANEL_1D
){
546 sushiv_panel1d_t
*q1
= q
->subtype
->p1
;
550 q
->private->request_compute(q
);
555 q
->private->request_compute(q
);
562 static void center_callback_1d(sushiv_dimension_list_t
*dptr
){
563 sushiv_dimension_t
*d
= dptr
->d
;
564 sushiv_panel_t
*p
= dptr
->p
;
565 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
566 int axisp
= (d
== p1
->x_d
);
569 // mid slider of a non-axis dimension changed, rerender
570 _mark_recompute_1d(p
);
572 // mid slider of an axis dimension changed, move crosshairs
577 static void bracket_callback_1d(sushiv_dimension_list_t
*dptr
){
578 sushiv_dimension_t
*d
= dptr
->d
;
579 sushiv_panel_t
*p
= dptr
->p
;
580 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
581 int axisp
= d
== p1
->x_d
;
584 _mark_recompute_1d(p
);
588 static void dimchange_callback_1d(GtkWidget
*button
,gpointer in
){
589 sushiv_panel_t
*p
= (sushiv_panel_t
*)in
;
591 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))){
593 _sushiv_panel_undo_push(p
);
594 _sushiv_panel_undo_suspend(p
);
598 plot_unset_box(PLOT(p
->private->graph
));
599 _mark_recompute_1d(p
);
601 _sushiv_panel_undo_resume(p
);
605 static void crosshair_callback(sushiv_panel_t
*p
){
606 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
607 sushiv_panel_t
*link
= p1
->link_x
;
608 double x
=PLOT(p
->private->graph
)->selx
;
612 x
=PLOT(p
->private->graph
)->sely
;
617 // make it the master panel's problem.
618 plot_set_crosshairs_snap(PLOT(link
->private->graph
),
620 PLOT(link
->private->graph
)->sely
);
621 link
->private->crosshair_action(link
);
622 }else if (p1
->link_y
){
623 // make it the master panel's problem.
624 plot_set_crosshairs_snap(PLOT(link
->private->graph
),
625 PLOT(link
->private->graph
)->selx
,
627 link
->private->crosshair_action(link
);
630 _sushiv_panel_undo_push(p
);
631 _sushiv_panel_undo_suspend(p
);
633 for(i
=0;i
<p
->dimensions
;i
++){
634 sushiv_dimension_t
*d
= p
->dimension_list
[i
].d
;
635 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
637 _sushiv_dimension_set_value(p
->private->dim_scales
[i
],1,x
);
639 p1
->oldbox_active
= 0;
641 _sushiv_panel_undo_resume(p
);
645 static void box_callback(void *in
, int state
){
646 sushiv_panel_t
*p
= (sushiv_panel_t
*)in
;
647 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
648 Plot
*plot
= PLOT(p
->private->graph
);
652 _sushiv_panel_undo_push(p
);
653 plot_box_vals(plot
,p1
->oldbox
);
654 p1
->oldbox_active
= plot
->box_active
;
656 case 1: // box activate
657 _sushiv_panel_undo_push(p
);
658 _sushiv_panel_undo_suspend(p
);
660 crosshair_callback(p
);
662 _sushiv_dimension_set_value(p1
->x_scale
,0,p1
->oldbox
[0]);
663 _sushiv_dimension_set_value(p1
->x_scale
,2,p1
->oldbox
[1]);
664 p1
->oldbox_active
= 0;
665 _sushiv_panel_undo_resume(p
);
668 update_context_menus(p
);
671 int _sushiv_panel_cooperative_compute_1d(sushiv_panel_t
*p
){
672 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
679 int render_scale_flag
= 0;
685 gdk_threads_enter ();
695 gdk_threads_leave ();
699 plot
= PLOT(p
->private->graph
);
701 serialno
= p1
->serialno
;
704 /* render using local dimension array; several threads will be
705 computing objectives */
706 double dim_vals
[p
->sushi
->dimensions
];
708 x_min
= scalespace_value(&sv
,0);
709 x_max
= scalespace_value(&sv
,dw
);
710 x_d
= p1
->x_d
->number
;
720 // Bulletproofing; shouldn't ever come up
722 gdk_threads_leave ();
723 fprintf(stderr
,"Invalid/missing x dimension setting in 1d panel x_d\n");
727 // Initialize local dimension value array
728 for(i
=0;i
<p
->sushi
->dimensions
;i
++){
729 sushiv_dimension_t
*dim
= p
->sushi
->dimension_list
[i
];
730 dim_vals
[i
]=dim
->val
;
733 // update scales if we're just starting
734 if(p1
->last_line
==0) render_scale_flag
= 1;
736 if(plot
->w
.allocation
.height
== h
&&
737 serialno
== p1
->serialno
){
740 /* unlock for computation */
741 gdk_threads_leave ();
743 if(render_scale_flag
){
744 plot_draw_scales(plot
);
745 render_scale_flag
= 0;
749 compute_1d(p
, serialno
, x_d
, x_min
, x_max
, dw
, dim_vals
);
750 gdk_threads_enter ();
751 _sushiv_panel_dirty_map(p
);
752 _sushiv_panel_dirty_legend(p
);
753 gdk_threads_leave ();
756 gdk_threads_leave ();
761 static void panel1d_undo_log(sushiv_panel_undo_t
*u
, sushiv_panel_t
*p
){
762 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
765 // alloc fields as necessary
767 u
->mappings
= calloc(p
->objectives
,sizeof(*u
->mappings
));
769 u
->submappings
= calloc(p
->objectives
,sizeof(*u
->submappings
));
770 if(!u
->scale_vals
[0])
771 u
->scale_vals
[0] = calloc(1,sizeof(**u
->scale_vals
));
772 if(!u
->scale_vals
[1])
773 u
->scale_vals
[1] = calloc(1,sizeof(**u
->scale_vals
));
774 if(!u
->scale_vals
[2])
775 u
->scale_vals
[2] = calloc(1,sizeof(**u
->scale_vals
));
777 u
->dim_vals
[0] = calloc(p
->dimensions
+1,sizeof(**u
->dim_vals
)); // +1 for possible linked dim
779 u
->dim_vals
[1] = calloc(p
->dimensions
+1,sizeof(**u
->dim_vals
)); // +1 for possible linked dim
781 u
->dim_vals
[2] = calloc(p
->dimensions
+1,sizeof(**u
->dim_vals
)); // +1 for possible linked dim
784 u
->scale_vals
[0][0] = slider_get_value(p1
->range_slider
,0);
785 u
->scale_vals
[1][0] = slider_get_value(p1
->range_slider
,1);
787 for(i
=0;i
<p
->objectives
;i
++){
788 u
->mappings
[i
] = p1
->mappings
[i
].mapnum
;
789 u
->submappings
[i
] = p1
->linetype
[i
];
792 for(i
=0;i
<p
->dimensions
;i
++){
793 u
->dim_vals
[0][i
] = p
->dimension_list
[i
].d
->bracket
[0];
794 u
->dim_vals
[1][i
] = p
->dimension_list
[i
].d
->val
;
795 u
->dim_vals
[2][i
] = p
->dimension_list
[i
].d
->bracket
[1];
798 u
->dim_vals
[0][i
] = p1
->x_d
->bracket
[0];
799 u
->dim_vals
[1][i
] = p1
->x_d
->val
;
800 u
->dim_vals
[2][i
] = p1
->x_d
->bracket
[1];
803 u
->box
[0] = p1
->oldbox
[0];
804 u
->box
[1] = p1
->oldbox
[1];
805 u
->box_active
= p1
->oldbox_active
;
809 static void panel1d_undo_restore(sushiv_panel_undo_t
*u
, sushiv_panel_t
*p
){
810 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
811 Plot
*plot
= PLOT(p
->private->graph
);
812 sushiv_panel_t
*link
= (p1
->link_x
?p1
->link_x
:p1
->link_y
);
816 // go in through widgets
818 slider_set_value(p1
->range_slider
,0,u
->scale_vals
[0][0]);
819 slider_set_value(p1
->range_slider
,1,u
->scale_vals
[1][0]);
821 for(i
=0;i
<p
->objectives
;i
++){
822 gtk_combo_box_set_active(GTK_COMBO_BOX(p1
->map_pulldowns
[i
]),u
->mappings
[i
]);
823 gtk_combo_box_set_active(GTK_COMBO_BOX(p1
->line_pulldowns
[i
]),u
->submappings
[i
]);
826 for(i
=0;i
<p
->dimensions
;i
++){
827 _sushiv_dimension_set_value(p
->private->dim_scales
[i
],0,u
->dim_vals
[0][i
]);
828 _sushiv_dimension_set_value(p
->private->dim_scales
[i
],1,u
->dim_vals
[1][i
]);
829 _sushiv_dimension_set_value(p
->private->dim_scales
[i
],2,u
->dim_vals
[2][i
]);
832 if(p1
->dim_xb
&& u
->x_d
<p
->dimensions
&& p1
->dim_xb
[u
->x_d
])
833 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p1
->dim_xb
[u
->x_d
]),TRUE
);
835 /* make sure x_d is set before updating the x_d sliders! */
839 /* doesn't matter which widget belonging to the dimension is the one that gets set */
840 _sushiv_dimension_set_value(p1
->x_d
->private->widget_list
[0],0,u
->dim_vals
[0][p
->dimensions
]);
841 _sushiv_dimension_set_value(p1
->x_d
->private->widget_list
[0],1,u
->dim_vals
[1][p
->dimensions
]);
842 _sushiv_dimension_set_value(p1
->x_d
->private->widget_list
[0],2,u
->dim_vals
[2][p
->dimensions
]);
846 plot_box_set(plot
,u
->box
);
847 p1
->oldbox_active
= 1;
849 plot_unset_box(plot
);
850 p1
->oldbox_active
= 0;
855 static void panel1d_find_peak(sushiv_panel_t
*p
){
856 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
857 Plot
*plot
= PLOT(p
->private->graph
);
859 int dw
= p1
->data_size
;
862 // finds in order each peak (in the event there's more than one) of
863 // each active objective
866 for(i
=0;i
<p
->objectives
;i
++){
867 if(p1
->data_vec
&& p1
->data_vec
[i
] && !mapping_inactive_p(p1
->mappings
+i
)){
868 double *data
=p1
->data_vec
[i
];
869 double best_val
= data
[0];
871 int inner_count
= count
+1;
875 if(data
[j
]>best_val
){
876 inner_count
= count
+1;
879 }else if (data
[j
]==best_val
){
880 if(inner_count
<= p1
->peak_count
){
890 if(count
>p1
->peak_count
){
891 double xv
= scalespace_value(&p1
->vs
,best_j
);
894 plot_set_crosshairs(plot
,0,xv
);
896 plot_set_crosshairs(plot
,xv
,0);
897 crosshair_callback(p
);
906 if(p1
->peak_count
==0)
907 return; // must be all inactive
913 static gboolean
panel1d_keypress(GtkWidget
*widget
,
916 sushiv_panel_t
*p
= (sushiv_panel_t
*)in
;
918 if(event
->state
&GDK_MOD1_MASK
) return FALSE
;
919 if(event
->state
&GDK_CONTROL_MASK
)return FALSE
;
921 /* non-control keypresses */
922 switch(event
->keyval
){
927 _sushiv_clean_exit(SIGINT
);
932 _sushiv_panel_undo_down(p
);
938 _sushiv_panel_undo_up(p
);
943 panel1d_find_peak(p
);
950 static void update_context_menus(sushiv_panel_t
*p
){
951 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
954 if(!p
->sushi
->private->undo_stack
||
955 !p
->sushi
->private->undo_level
){
956 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->popmenu
),0),FALSE
);
957 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->graphmenu
),0),FALSE
);
959 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->popmenu
),0),TRUE
);
960 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->graphmenu
),0),TRUE
);
964 if(!p
->sushi
->private->undo_stack
||
965 !p
->sushi
->private->undo_stack
[p
->sushi
->private->undo_level
] ||
966 !p
->sushi
->private->undo_stack
[p
->sushi
->private->undo_level
+1]){
967 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->popmenu
),1),FALSE
);
968 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->graphmenu
),1),FALSE
);
970 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->popmenu
),1),TRUE
);
971 gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1
->graphmenu
),1),TRUE
);
974 // are we starting or enacting a zoom box?
975 if(p1
->oldbox_active
){
976 gtk_menu_alter_item_label(GTK_MENU(p1
->graphmenu
),3,"Zoom to selection");
978 gtk_menu_alter_item_label(GTK_MENU(p1
->graphmenu
),3,"Start zoom selection");
983 void wrap_exit(sushiv_panel_t
*dummy
){
984 _sushiv_clean_exit(SIGINT
);
987 static char *panel_menulist
[]={
995 static char *panel_shortlist
[]={
1003 static void (*panel_calllist
[])(sushiv_panel_t
*)={
1004 &_sushiv_panel_undo_down
,
1005 &_sushiv_panel_undo_up
,
1011 void wrap_enter(sushiv_panel_t
*p
){
1012 plot_do_enter(PLOT(p
->private->graph
));
1015 void wrap_escape(sushiv_panel_t
*p
){
1016 plot_do_escape(PLOT(p
->private->graph
));
1019 static char *graph_menulist
[]={
1023 "Start zoom selection",
1031 static char *graph_shortlist
[]={
1043 static void (*graph_calllist
[])(sushiv_panel_t
*)={
1044 &_sushiv_panel_undo_down
,
1045 &_sushiv_panel_undo_up
,
1056 void _sushiv_realize_panel1d(sushiv_panel_t
*p
){
1057 sushiv_panel1d_t
*p1
= p
->subtype
->p1
;
1060 _sushiv_panel_undo_suspend(p
);
1062 p
->private->toplevel
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1063 g_signal_connect_swapped (G_OBJECT (p
->private->toplevel
), "delete-event",
1064 G_CALLBACK (_sushiv_clean_exit
), (void *)SIGINT
);
1066 p1
->top_table
= gtk_table_new(3,4,0);
1068 gtk_container_add (GTK_CONTAINER (p
->private->toplevel
), p1
->top_table
);
1069 gtk_container_set_border_width (GTK_CONTAINER (p
->private->toplevel
), 5);
1071 p1
->obj_table
= gtk_table_new(p
->objectives
,3,0);
1072 gtk_table_attach(GTK_TABLE(p1
->top_table
),p1
->obj_table
,0,4,2,3,
1073 GTK_EXPAND
|GTK_FILL
,0,0,5);
1075 p1
->dim_table
= gtk_table_new(p
->dimensions
,3,0);
1076 gtk_table_attach(GTK_TABLE(p1
->top_table
),p1
->dim_table
,0,4,3,4,
1077 GTK_EXPAND
|GTK_FILL
,0,0,5);
1083 flags
|= PLOT_NO_X_CROSS
;
1085 flags
|= PLOT_NO_Y_CROSS
;
1086 p
->private->graph
= GTK_WIDGET(plot_new(recompute_callback_1d
,p
,
1087 (void *)(void *)crosshair_callback
,p
,
1088 box_callback
,p
,flags
));
1089 gtk_table_attach(GTK_TABLE(p1
->top_table
),p
->private->graph
,0,4,0,1,
1090 GTK_EXPAND
|GTK_FILL
,GTK_EXPAND
|GTK_FILL
,0,5);
1095 GtkWidget
**sl
= calloc(2,sizeof(*sl
));
1097 int lo
= p1
->range_scale
->val_list
[0];
1098 int hi
= p1
->range_scale
->val_list
[p1
->range_scale
->vals
-1];
1103 asprintf(&buf
,"%s range",p1
->range_scale
->legend
);
1104 GtkWidget
*label
= gtk_label_new(buf
);
1105 gtk_table_attach(GTK_TABLE(p1
->top_table
),label
,0,1,1,2,
1110 /* the range slices/slider */
1111 sl
[0] = slice_new(map_callback_1d
,p
);
1112 sl
[1] = slice_new(map_callback_1d
,p
);
1114 gtk_table_attach(GTK_TABLE(p1
->top_table
),sl
[0],1,2,1,2,
1115 GTK_EXPAND
|GTK_FILL
,0,0,0);
1116 gtk_table_attach(GTK_TABLE(p1
->top_table
),sl
[1],2,3,1,2,
1117 GTK_EXPAND
|GTK_FILL
,0,0,0);
1118 p1
->range_slider
= slider_new((Slice
**)sl
,2,
1119 p1
->range_scale
->label_list
,
1120 p1
->range_scale
->val_list
,
1121 p1
->range_scale
->vals
,
1122 SLIDER_FLAG_INDEPENDENT_MIDDLE
);
1124 slice_thumb_set((Slice
*)sl
[0],lo
);
1125 slice_thumb_set((Slice
*)sl
[1],hi
);
1128 /* objective pulldowns */
1129 p1
->linetype
= calloc(p
->objectives
,sizeof(*p1
->linetype
));
1130 p1
->mappings
= calloc(p
->objectives
,sizeof(*p1
->mappings
));
1131 p1
->map_pulldowns
= calloc(p
->objectives
,sizeof(*p1
->map_pulldowns
));
1132 p1
->line_pulldowns
= calloc(p
->objectives
,sizeof(*p1
->line_pulldowns
));
1134 for(i
=0;i
<p
->objectives
;i
++){
1135 sushiv_objective_t
*o
= p
->objective_list
[i
].o
;
1138 GtkWidget
*label
= gtk_label_new(o
->name
);
1139 gtk_table_attach(GTK_TABLE(p1
->obj_table
),label
,0,1,i
,i
+1,
1142 /* mapping pulldown */
1144 GtkWidget
*menu
=gtk_combo_box_new_markup();
1146 for(j
=0;j
<num_solids();j
++)
1147 gtk_combo_box_append_text (GTK_COMBO_BOX (menu
), solid_name(j
));
1148 gtk_combo_box_set_active(GTK_COMBO_BOX(menu
),0);
1149 g_signal_connect (G_OBJECT (menu
), "changed",
1150 G_CALLBACK (mapchange_callback_1d
), p
->objective_list
+i
);
1151 gtk_table_attach(GTK_TABLE(p1
->obj_table
),menu
,1,2,i
,i
+1,
1152 GTK_SHRINK
,GTK_SHRINK
,5,0);
1153 p1
->map_pulldowns
[i
] = menu
;
1154 solid_setup(&p1
->mappings
[i
],0.,1.,0);
1159 GtkWidget
*menu
=gtk_combo_box_new_text();
1161 for(j
=0;j
<LINETYPES
;j
++)
1162 gtk_combo_box_append_text (GTK_COMBO_BOX (menu
), line_name
[j
]);
1163 gtk_combo_box_set_active(GTK_COMBO_BOX(menu
),0);
1164 g_signal_connect (G_OBJECT (menu
), "changed",
1165 G_CALLBACK (linetype_callback_1d
), p
->objective_list
+i
);
1166 gtk_table_attach(GTK_TABLE(p1
->obj_table
),menu
,2,3,i
,i
+1,
1167 GTK_SHRINK
,GTK_SHRINK
,5,0);
1168 p1
->line_pulldowns
[i
] = menu
;
1173 p
->private->dim_scales
= calloc(p
->dimensions
,sizeof(*p
->private->dim_scales
));
1174 p1
->dim_xb
= calloc(p
->dimensions
,sizeof(*p1
->dim_xb
));
1175 GtkWidget
*first_x
= NULL
;
1177 for(i
=0;i
<p
->dimensions
;i
++){
1178 sushiv_dimension_t
*d
= p
->dimension_list
[i
].d
;
1181 GtkWidget
*label
= gtk_label_new(d
->name
);
1182 gtk_table_attach(GTK_TABLE(p1
->dim_table
),label
,0,1,i
,i
+1,
1185 /* x radio buttons */
1186 if(!(d
->flags
& SUSHIV_DIM_NO_X
) && !p1
->link_x
&& !p1
->link_y
){
1188 p1
->dim_xb
[i
] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_x
),"X");
1190 first_x
= p1
->dim_xb
[i
] = gtk_radio_button_new_with_label(NULL
,"X");
1191 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p1
->dim_xb
[i
]),TRUE
);
1193 gtk_table_attach(GTK_TABLE(p1
->dim_table
),p1
->dim_xb
[i
],1,2,i
,i
+1,
1197 p
->private->dim_scales
[i
] =
1198 _sushiv_new_dimension_widget(p
->dimension_list
+i
,center_callback_1d
,bracket_callback_1d
);
1200 gtk_table_attach(GTK_TABLE(p1
->dim_table
),
1201 GTK_WIDGET(p
->private->dim_scales
[i
]->t
),
1203 GTK_EXPAND
|GTK_FILL
,0,0,0);
1207 for(i
=0;i
<p
->dimensions
;i
++)
1209 g_signal_connect (G_OBJECT (p1
->dim_xb
[i
]), "toggled",
1210 G_CALLBACK (dimchange_callback_1d
), p
);
1215 p1
->popmenu
= gtk_menu_new_twocol(p
->private->toplevel
,
1218 (void *)(void *)panel_calllist
,
1220 p1
->graphmenu
= gtk_menu_new_twocol(p
->private->graph
,
1223 (void *)(void *)graph_calllist
,
1226 update_context_menus(p
);
1228 g_signal_connect (G_OBJECT (p
->private->toplevel
), "key-press-event",
1229 G_CALLBACK (panel1d_keypress
), p
);
1230 gtk_window_set_title (GTK_WINDOW (p
->private->toplevel
), p
->name
);
1232 gtk_widget_realize(p
->private->toplevel
);
1233 gtk_widget_realize(p
->private->graph
);
1234 gtk_widget_show_all(p
->private->toplevel
);
1236 _sushiv_panel_undo_resume(p
);
1239 int sushiv_new_panel_1d_linked(sushiv_instance_t
*s
,
1242 sushiv_scale_t
*scale
,
1248 link
>= s
->panels
||
1249 s
->panel_list
[link
]==NULL
||
1250 s
->panel_list
[link
]->type
!= SUSHIV_PANEL_2D
){
1251 fprintf(stderr
,"1d linked panel must be linked to preexisting 2d panel.\n");
1255 int ret
= _sushiv_new_panel(s
,number
,name
,objectives
,(int []){-1},flags
);
1257 sushiv_panel1d_t
*p1
;
1258 sushiv_panel_t
*p2
= s
->panel_list
[link
];
1260 if(ret
<0)return ret
;
1261 p
= s
->panel_list
[number
];
1262 p1
= calloc(1, sizeof(*p1
));
1264 calloc(1, sizeof(*p
->subtype
)); /* the union is alloced not
1265 embedded as its internal
1266 structure must be hidden */
1267 p
->subtype
->p1
= p1
;
1268 p
->type
= SUSHIV_PANEL_1D
;
1270 p1
->range_scale
= scale
;
1272 if(flags
&& SUSHIV_PANEL_LINK_Y
)
1277 if(p
->flags
&& SUSHIV_PANEL_FLIP
)
1280 p
->private->realize
= _sushiv_realize_panel1d
;
1281 p
->private->map_redraw
= _sushiv_panel1d_map_redraw
;
1282 p
->private->legend_redraw
= _sushiv_panel1d_legend_redraw
;
1283 p
->private->compute_action
= _sushiv_panel_cooperative_compute_1d
;
1284 p
->private->request_compute
= _mark_recompute_1d
;
1285 p
->private->crosshair_action
= crosshair_callback
;
1287 p
->private->undo_log
= panel1d_undo_log
;
1288 p
->private->undo_restore
= panel1d_undo_restore
;
1289 p
->private->update_menus
= update_context_menus
;