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.
31 #include <sys/types.h>
37 sv_panel_t
**_sv_panel_list
=NULL
;
38 pthread_rwlock_t panellist_m
;
40 // panel.panel_m: rwlock, protects all panel and plane heaps
41 // panel.status_m: mutex, protects status variables
43 // Plane data in the panels is protected as follows:
45 // Modifications of pointers, heap allocations, etc are protected by
46 // write-locking panel_m.
48 // Both read and write access to the contents of plane.data and
49 // plane.image are protected by read-locking panel_m; reads may happen
50 // at any time, writes are checked only that they've not been superceded
51 // by a later request. Writes are not locked against reads at all; a
52 // read from inconsistent state is temporary and cosmetic only. It will
53 // always be immediately replaced by complete/correct data when the write
54 // finishes and triggers a flush.
56 // comp_serialno is used to to verify 'freshness' of operations; anytime a
57 // thread needs to synchronize with panel/plane data before continuing
58 // (read or write), it compares the serialno that dispatched it to the
59 // current serialno. A mismatch immediately aborts the task in progress
60 // with STATUS_WORKING.
62 // map_serialno performs the same task with respect to remap requests
65 // worker thread process order:
74 // > image map render (throttleable)
78 // proceed to later steps only if there's no work immediately
79 // dispatchable from earlier steps.
81 // UI output comes first (UI is never dead, even briefly, and that
82 // includes graphs), however progressive UI work is purposely
85 // wake_workers() only explicitly needed when triggering tasks via
86 // GDK/API; it is already called implicitly in the main loop whenever
87 // a task step completes.
89 static void payload_free(sv_dim_data_t
*dd
, int dims
){
91 _sv_dim_data_clear(dd
+i
);
95 static int image_resize(sv_plane_t
*pl
,
97 return pl
->c
.image_resize(pl
, p
);
100 static int data_resize(sv_plane_t
*pl
,
102 return pl
->c
.data_resize(pl
, p
);
105 static int image_work(sv_plane_t
*pl
,
107 return pl
->c
.image_work(pl
, p
);
110 static int data_work(sv_plane_t
*pl
,
112 return pl
->c
.data_work(pl
, p
);
115 static int plane_loop(sv_panel_t
*p
, int *next
,
116 int(*function
)(_sv_plane_t
*,
120 int serialno
= p
->serialno
;
123 if(*next
>=p
->planes
)*next
=0;
124 int status
= function(p
->plane_list
[i
],p
);
125 if(status
== STATUS_WORKING
) return STATUS_WORKING
;
126 if(status
!= STATUS_IDLE
) finishedflag
=0;
134 static int done_working(sv_panel_t
*p
){
135 pthread_mutex_unlock(p
->status_m
);
136 pthread_rwlock_unlock(p
->panel_m
);
137 return STATUS_WORKING
;
140 static int done_busy(sv_panel_t
*p
){
141 pthread_mutex_unlock(p
->status_m
);
142 pthread_rwlock_unlock(p
->panel_m
);
146 static int done_idle(sv_panel_t
*p
){
147 pthread_mutex_unlock(p
->status_m
);
148 pthread_rwlock_unlock(p
->panel_m
);
152 int _sv_panel_work(sv_panel_t
*p
){
153 int i
,serialno
,status
;
154 pthread_rwlock_rdlock(p
->panel_m
);
155 pthread_mutex_lock(p
->status_m
);
159 // plane recompute calls will do nothing if recomputation is not
160 // required. Even if computation not required, may still request
161 // an image resize/resample
162 if(p
->recompute_pending
){
163 p
->recompute_pending
=0;
165 p
->legend_serialno
++;
172 p
->image_next_plane
=0;
174 bg_recompute_setup(p
);
176 for(i
=0;i
<p
->planes
;i
++)
177 p
->plane_list
[i
]->c
.recompute_setup(p
->plane_list
[i
], p
);
179 pthread_mutex_unlock(p
->status_m
);
180 pthread_rwlock_unlock(p
->panel_m
);
182 return STATUS_WORKING
;
185 if(p
->relegend_pending
){
187 p
->relegend_pending
=0;
190 serialno
= p
->comp_serialno
;
193 // image resizes assume bg resize has completed
195 status
= bg_resize(p
);
196 if(status
== STATUS_WORKING
) return done_working(p
);
197 if(status
== STATUS_BUSY
) return done_busy(p
);
203 status
= plane_loop(p
,&p
->image_next_plane
,image_resize
);
204 if(status
== STATUS_WORKING
) return done_working(p
);
205 if(status
== STATUS_IDLE
){
211 // legend regeneration
213 p
->relegend
=0; // must be unset before relegend
216 return done_working(p
);
221 p
->rescale
=0; // must be unset before rescale
224 return done_working(p
);
227 // need to join on image resizing before proceeding to background redraw
233 if(bg_render(p
) == STATUS_IDLE
){
237 return done_working(p
);
245 // wait till all these ops are done
248 // bg_expose does not reclaim loks before exit
249 return STATUS_WORKING
;
254 status
= plane_loop(p
,&p
->data_next_plane
,data_resize
);
255 if(status
== STATUS_WORKING
) return done_working(p
);
256 if(status
== STATUS_IDLE
) p
->data_resize
= 0;
259 // need to join on data resizing before proceeding to map/compute work
265 status
= plane_loop(p
,&p
->image_next_plane
,image_work
);
266 if(status
== STATUS_WORKING
) return done_working(p
);
267 if(status
== STATUS_IDLE
){
275 status
= plane_loop(p
,&p
->data_next_plane
,data_work
);
276 if(status
== STATUS_WORKING
){
278 // throttled image render
279 if(p
->map_render
==0){
280 // no render currently in progress
282 gettimeofday(&now
,NULL
);
284 if(p
->map_throttle_last
.tv_sec
==0){
285 p
->map_throttle_last
=now
;
287 long test
= (now
.tv_sec
- p
->map_throttle_last
.tv_sec
)*1000 +
288 (now
.tv_usec
- p
->map_throttle_last
.tv_usec
)/1000;
290 // first request since throttle
294 return done_working(p
);
296 if(status
== STATUS_IDLE
){
305 // looks like a cop-out but is actually the correct thing to do; the
306 // data *must* be WYSIWYG from panel display.
307 static void _sv_panel2d_print_bg(sv_panel_t
*p
, cairo_t
*c
){
308 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
312 cairo_pattern_t
*pattern
= cairo_pattern_create_for_surface(plot
->back
);
313 cairo_pattern_set_filter(pattern
, CAIRO_FILTER_NEAREST
);
314 cairo_set_source(c
,pattern
);
317 cairo_pattern_destroy(pattern
);
320 static void _sv_panel2d_print(sv_panel_t
*p
, cairo_t
*c
, int w
, int h
){
321 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
322 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
323 double pw
= p
->private->graph
->allocation
.width
;
324 double ph
= p
->private->graph
->allocation
.height
;
337 cairo_get_matrix(c
,&m
);
338 cairo_matrix_scale(&m
,scale
,scale
);
339 cairo_set_matrix(c
,&m
);
341 _sv_plot_print(plot
, c
, ph
*scale
, (void(*)(void *, cairo_t
*))_sv_panel2d_print_bg
, p
);
344 // find extents widths for objective scale labels
345 cairo_set_font_size(c
,10);
346 for(i
=0;i
<p
->objectives
;i
++){
347 cairo_text_extents_t ex
;
348 sv_obj_t
*o
= p
->objective_list
[i
].o
;
349 cairo_text_extents(c
, o
->name
, &ex
);
350 if(ex
.width
> maxlabelw
) maxlabelw
=ex
.width
;
356 for(i
=0;i
<p
->objectives
;i
++){
357 sv_obj_t
*o
= p
->objective_list
[i
].o
;
358 _sv_slider_t
*s
= p2
->range_scales
[i
];
361 double labelh
= _sv_slider_print_height(s
);
362 cairo_text_extents_t ex
;
363 cairo_text_extents (c
, o
->name
, &ex
);
365 int lx
= maxlabelw
- ex
.width
;
366 int ly
= labelh
/2 + ex
.height
/2;
368 // print objective labels
369 cairo_set_source_rgb(c
,0.,0.,0.);
370 cairo_move_to (c
, lx
,ly
+y
);
371 cairo_show_text (c
, o
->name
);
376 cairo_translate (c
, maxlabelw
+ 10, y
);
377 _sv_slider_print(s
, c
, pw
*scale
- maxlabelw
- 10, labelh
);
386 static void _sv_panel2d_update_legend(sv_panel_t
*p
){
387 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
388 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
394 _sv_plot_legend_clear(plot
);
396 // potentially add each dimension to the legend; add axis
397 // dimensions only if crosshairs are active
399 // display decimal precision relative to display scales
400 if(3-_sv_scalespace_decimal_exponent(&p2
->x
) > depth
)
401 depth
= 3-_sv_scalespace_decimal_exponent(&p2
->x
);
402 if(3-_sv_scalespace_decimal_exponent(&p2
->y
) > depth
)
403 depth
= 3-_sv_scalespace_decimal_exponent(&p2
->y
);
404 for(i
=0;i
<p
->dimensions
;i
++){
405 sv_dim_t
*d
= p
->dimension_list
[i
].d
;
406 if( (d
!=p
->private->x_d
&& d
!=p
->private->y_d
) ||
408 snprintf(buffer
,320,"%s = %+.*f",
409 p
->dimension_list
[i
].d
->legend
,
411 p
->dimension_list
[i
].d
->val
);
412 _sv_plot_legend_add(plot
,buffer
);
416 // add each active objective plane to the legend
417 // choose the value under the crosshairs
418 if(plot
->cross_active
){
420 _sv_plot_legend_add(plot
,NULL
);
422 for(i
=0;i
<p
->objectives
;i
++){
424 if(!_sv_mapping_inactive_p(p2
->mappings
+i
)){
426 _sv_panel2d_compute_point(p
,p
->objective_list
[i
].o
, plot
->selx
, plot
->sely
, &vals
);
430 snprintf(buffer
,320,"%s = %f",
431 p
->objective_list
[i
].o
->name
,
433 _sv_plot_legend_add(plot
,buffer
);
441 static void _sv_panel2d_mapchange_callback(GtkWidget
*w
,gpointer in
){
442 sv_obj_list_t
*optr
= (sv_obj_list_t
*)in
;
443 //sv_obj_t *o = optr->o;
444 sv_panel_t
*p
= optr
->p
;
445 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
446 int onum
= optr
- p
->objective_list
;
451 _sv_mapping_set_func(&p2
->mappings
[onum
],gtk_combo_box_get_active(GTK_COMBO_BOX(w
)));
453 //redraw the map slider
454 _sv_slider_set_gradient(p2
->range_scales
[onum
], &p2
->mappings
[onum
]);
456 // in the event the mapping active state changed
457 _sv_panel_dirty_legend(p
);
460 _sv_panel2d_mark_map_plane(p
,onum
,1,0,0);
461 _sv_panel_dirty_map(p
);
465 static void _sv_panel2d_map_callback(void *in
,int buttonstate
){
466 sv_obj_list_t
*optr
= (sv_obj_list_t
*)in
;
467 //sv_obj_t *o = optr->o;
468 sv_panel_t
*p
= optr
->p
;
469 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
470 int onum
= optr
- p
->objective_list
;
472 if(buttonstate
== 0){
477 // recache alpha del */
479 _sv_slider_val_to_del(p2
->range_scales
[onum
],
480 _sv_slider_get_value(p2
->range_scales
[onum
],1));
482 // redraw the plot on motion
483 if(buttonstate
== 1){
484 _sv_panel2d_mark_map_plane(p
,onum
,1,0,0);
485 _sv_panel_dirty_map(p
);
491 static void _sv_panel2d_update_xysel(sv_panel_t
*p
){
492 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
494 // update which x/y buttons are pressable */
495 // enable/disable dimension slider thumbs
497 for(i
=0;i
<p
->dimensions
;i
++){
499 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2
->dim_xb
[i
]))){
500 // make the y insensitive
502 _gtk_widget_set_sensitive_fixup(p2
->dim_yb
[i
],FALSE
);
504 // set the x dim flag
505 p
->private->x_d
= p
->dimension_list
[i
].d
;
506 p2
->x_scale
= p
->private->dim_scales
[i
];
509 // if there is a y, make it sensitive
511 _gtk_widget_set_sensitive_fixup(p2
->dim_yb
[i
],TRUE
);
514 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2
->dim_yb
[i
]))){
515 // make the x insensitive
517 _gtk_widget_set_sensitive_fixup(p2
->dim_xb
[i
],FALSE
);
520 p
->private->y_d
= p
->dimension_list
[i
].d
;
521 p2
->y_scale
= p
->private->dim_scales
[i
];
524 // if there is a x, make it sensitive
526 _gtk_widget_set_sensitive_fixup(p2
->dim_xb
[i
],TRUE
);
529 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2
->dim_xb
[i
]))) ||
531 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2
->dim_yb
[i
])))){
532 // make all thumbs visible
533 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],0,1);
534 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],2,1);
536 // make bracket thumbs invisible */
537 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],0,0);
538 _sv_dim_widget_set_thumb_active(p
->private->dim_scales
[i
],2,0);
543 static int _v_swizzle(int y
, int height
){
544 int yy
= height
>> 5;
549 yy
= (height
+16) >> 5;
554 yy
= (height
+8) >> 4;
559 yy
= (height
+4) >> 3;
564 yy
= (height
+2) >> 2;
572 static void _sv_panel2d_center_callback(sv_dim_list_t
*dptr
){
573 sv_dim_t
*d
= dptr
->d
;
574 sv_panel_t
*p
= dptr
->p
;
575 int axisp
= (d
== p
->private->x_d
|| d
== p
->private->y_d
);
578 // mid slider of a non-axis dimension changed, rerender
579 _sv_panel2d_mark_recompute(p
);
581 // mid slider of an axis dimension changed, move crosshairs
582 _sv_panel2d_update_crosshairs(p
);
586 static void _sv_panel2d_bracket_callback(sv_dim_list_t
*dptr
){
587 sv_dim_t
*d
= dptr
->d
;
588 sv_panel_t
*p
= dptr
->p
;
589 int axisp
= (d
== p
->private->x_d
|| d
== p
->private->y_d
);
592 _sv_panel2d_mark_recompute(p
);
596 static void _sv_panel2d_dimchange_callback(GtkWidget
*button
,gpointer in
){
597 sv_panel_t
*p
= (sv_panel_t
*)in
;
599 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))){
604 _sv_plot_unset_box(PLOT(p
->private->graph
));
605 _sv_panel2d_update_xysel(p
);
607 _sv_panel2d_clear_pane(p
);
608 _sv_panel2d_mark_recompute(p
);
609 _sv_panel2d_update_crosshairs(p
);
615 static void _sv_panel2d_crosshairs_callback(sv_panel_t
*p
){
616 double x
=PLOT(p
->private->graph
)->selx
;
617 double y
=PLOT(p
->private->graph
)->sely
;
623 //plot_snap_crosshairs(PLOT(p->private->graph));
625 for(i
=0;i
<p
->dimensions
;i
++){
626 sv_dim_t
*d
= p
->dimension_list
[i
].d
;
627 if(d
== p
->private->x_d
){
628 _sv_dim_widget_set_thumb(p
->private->dim_scales
[i
],1,x
);
631 if(d
== p
->private->y_d
){
632 _sv_dim_widget_set_thumb(p
->private->dim_scales
[i
],1,y
);
635 p
->private->oldbox_active
= 0;
638 // dimension setting might have enforced granularity restrictions;
639 // have the display reflect that
640 x
= p
->private->x_d
->val
;
641 y
= p
->private->y_d
->val
;
643 _sv_plot_set_crosshairs(PLOT(p
->private->graph
),x
,y
);
645 _sv_panel_dirty_legend(p
);
649 static void _sv_panel2d_box_callback(void *in
, int state
){
650 sv_panel_t
*p
= (sv_panel_t
*)in
;
651 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
652 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
657 _sv_plot_box_vals(plot
,p2
->oldbox
);
658 p
->private->oldbox_active
= plot
->box_active
;
660 case 1: // box activate
664 _sv_panel2d_crosshairs_callback(p
);
666 _sv_dim_widget_set_thumb(p2
->x_scale
,0,p2
->oldbox
[0]);
667 _sv_dim_widget_set_thumb(p2
->x_scale
,2,p2
->oldbox
[1]);
668 _sv_dim_widget_set_thumb(p2
->y_scale
,0,p2
->oldbox
[2]);
669 _sv_dim_widget_set_thumb(p2
->y_scale
,2,p2
->oldbox
[3]);
670 p
->private->oldbox_active
= 0;
674 _sv_panel_update_menus(p
);
677 // subtype entry point for legend redraws; lock held
678 static int _sv_panel2d_legend_redraw(sv_panel_t
*p
){
679 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
681 if(p
->private->legend_progress_count
)return 0;
682 p
->private->legend_progress_count
++;
683 _sv_panel2d_update_legend(p
);
684 _sv_panel_clean_legend(p
);
687 _sv_plot_draw_scales(plot
);
690 _sv_plot_expose_request(plot
);
694 // only called for resize events
695 static void _sv_panel2d_recompute_callback(void *ptr
){
696 sv_panel_t
*p
= (sv_panel_t
*)ptr
;
700 _sv_panel2d_mark_recompute(p
);
701 _sv_panel2d_compute(p
,NULL
); // initial scale setup
703 // temporary: blank background to checks
704 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
705 int pw
= plot
->x
.pixels
;
706 int ph
= plot
->y
.pixels
;
708 render_checks((_sv_ucolor_t
*)plot
->datarect
+pw
*i
, pw
, i
);
713 static void _sv_panel2d_undo_log(_sv_panel_undo_t
*u
, sv_panel_t
*p
){
714 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
717 // alloc fields as necessary
720 u
->mappings
= calloc(p
->objectives
,sizeof(*u
->mappings
));
721 if(!u
->scale_vals
[0])
722 u
->scale_vals
[0] = calloc(p
->objectives
,sizeof(**u
->scale_vals
));
723 if(!u
->scale_vals
[1])
724 u
->scale_vals
[1] = calloc(p
->objectives
,sizeof(**u
->scale_vals
));
725 if(!u
->scale_vals
[2])
726 u
->scale_vals
[2] = calloc(p
->objectives
,sizeof(**u
->scale_vals
));
729 for(i
=0;i
<p
->objectives
;i
++){
730 u
->mappings
[i
] = p2
->mappings
[i
].mapnum
;
731 u
->scale_vals
[0][i
] = _sv_slider_get_value(p2
->range_scales
[i
],0);
732 u
->scale_vals
[1][i
] = _sv_slider_get_value(p2
->range_scales
[i
],1);
733 u
->scale_vals
[2][i
] = _sv_slider_get_value(p2
->range_scales
[i
],2);
738 u
->box
[0] = p2
->oldbox
[0];
739 u
->box
[1] = p2
->oldbox
[1];
740 u
->box
[2] = p2
->oldbox
[2];
741 u
->box
[3] = p2
->oldbox
[3];
742 u
->box_active
= p
->private->oldbox_active
;
745 static void _sv_panel2d_undo_restore(_sv_panel_undo_t
*u
, sv_panel_t
*p
){
746 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
747 _sv_plot_t
*plot
= PLOT(p
->private->graph
);
750 // go in through widgets
751 for(i
=0;i
<p
->objectives
;i
++){
752 gtk_combo_box_set_active(GTK_COMBO_BOX(p2
->range_pulldowns
[i
]),u
->mappings
[i
]);
753 _sv_slider_set_value(p2
->range_scales
[i
],0,u
->scale_vals
[0][i
]);
754 _sv_slider_set_value(p2
->range_scales
[i
],1,u
->scale_vals
[1][i
]);
755 _sv_slider_set_value(p2
->range_scales
[i
],2,u
->scale_vals
[2][i
]);
758 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2
->dim_xb
[u
->x_d
]),TRUE
);
759 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2
->dim_yb
[u
->y_d
]),TRUE
);
761 _sv_panel2d_update_xysel(p
);
764 p2
->oldbox
[0] = u
->box
[0];
765 p2
->oldbox
[1] = u
->box
[1];
766 p2
->oldbox
[2] = u
->box
[2];
767 p2
->oldbox
[3] = u
->box
[3];
768 _sv_plot_box_set(plot
,u
->box
);
769 p
->private->oldbox_active
= 1;
771 _sv_plot_unset_box(plot
);
772 p
->private->oldbox_active
= 0;
776 static void _sv_panel2d_realize(sv_panel_t
*p
){
777 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
782 p
->private->toplevel
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
783 g_signal_connect_swapped (G_OBJECT (p
->private->toplevel
), "delete-event",
784 G_CALLBACK (_sv_clean_exit
), (void *)SIGINT
);
786 // add border to sides with hbox/padding
787 GtkWidget
*borderbox
= gtk_hbox_new(0,0);
788 gtk_container_add (GTK_CONTAINER (p
->private->toplevel
), borderbox
);
791 p
->private->topbox
= gtk_vbox_new(0,0);
792 gtk_box_pack_start(GTK_BOX(borderbox
), p
->private->topbox
, 1,1,4);
793 gtk_container_set_border_width (GTK_CONTAINER (p
->private->toplevel
), 1);
795 /* spinner, top bar */
797 GtkWidget
*hbox
= gtk_hbox_new(0,0);
798 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), hbox
, 0,0,0);
799 gtk_box_pack_end(GTK_BOX(hbox
),GTK_WIDGET(p
->private->spinner
),0,0,0);
804 p
->private->graph
= GTK_WIDGET(_sv_plot_new(_sv_panel2d_recompute_callback
,p
,
805 (void *)(void *)_sv_panel2d_crosshairs_callback
,p
,
806 _sv_panel2d_box_callback
,p
,0));
807 p
->private->plotbox
= p
->private->graph
;
808 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), p
->private->plotbox
, 1,1,2);
813 p2
->obj_table
= gtk_table_new(p
->objectives
, 5, 0);
814 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), p2
->obj_table
, 0,0,1);
816 /* objective sliders */
817 p2
->range_scales
= calloc(p
->objectives
,sizeof(*p2
->range_scales
));
818 p2
->range_pulldowns
= calloc(p
->objectives
,sizeof(*p2
->range_pulldowns
));
819 p2
->alphadel
= calloc(p
->objectives
,sizeof(*p2
->alphadel
));
820 p2
->mappings
= calloc(p
->objectives
,sizeof(*p2
->mappings
));
821 for(i
=0;i
<p
->objectives
;i
++){
822 GtkWidget
**sl
= calloc(3,sizeof(*sl
));
823 sv_obj_t
*o
= p
->objective_list
[i
].o
;
824 int lo
= o
->scale
->val_list
[0];
825 int hi
= o
->scale
->val_list
[o
->scale
->vals
-1];
828 GtkWidget
*label
= gtk_label_new(o
->name
);
829 gtk_misc_set_alignment(GTK_MISC(label
),1.,.5);
830 gtk_table_attach(GTK_TABLE(p2
->obj_table
),label
,0,1,i
,i
+1,
833 /* mapping pulldown */
835 GtkWidget
*menu
=_gtk_combo_box_new_markup();
837 for(j
=0;j
<_sv_mapping_names();j
++)
838 gtk_combo_box_append_text (GTK_COMBO_BOX (menu
), _sv_mapping_name(j
));
839 gtk_combo_box_set_active(GTK_COMBO_BOX(menu
),0);
840 g_signal_connect (G_OBJECT (menu
), "changed",
841 G_CALLBACK (_sv_panel2d_mapchange_callback
), p
->objective_list
+i
);
842 gtk_table_attach(GTK_TABLE(p2
->obj_table
),menu
,4,5,i
,i
+1,
843 GTK_SHRINK
,GTK_SHRINK
,0,0);
844 p2
->range_pulldowns
[i
] = menu
;
847 /* the range mapping slices/slider */
848 sl
[0] = _sv_slice_new(_sv_panel2d_map_callback
,p
->objective_list
+i
);
849 sl
[1] = _sv_slice_new(_sv_panel2d_map_callback
,p
->objective_list
+i
);
850 sl
[2] = _sv_slice_new(_sv_panel2d_map_callback
,p
->objective_list
+i
);
852 gtk_table_attach(GTK_TABLE(p2
->obj_table
),sl
[0],1,2,i
,i
+1,
853 GTK_EXPAND
|GTK_FILL
,0,0,0);
854 gtk_table_attach(GTK_TABLE(p2
->obj_table
),sl
[1],2,3,i
,i
+1,
855 GTK_EXPAND
|GTK_FILL
,0,0,0);
856 gtk_table_attach(GTK_TABLE(p2
->obj_table
),sl
[2],3,4,i
,i
+1,
857 GTK_EXPAND
|GTK_FILL
,0,0,0);
858 p2
->range_scales
[i
] = _sv_slider_new((_sv_slice_t
**)sl
,3,o
->scale
->label_list
,o
->scale
->val_list
,
859 o
->scale
->vals
,_SV_SLIDER_FLAG_INDEPENDENT_MIDDLE
);
860 gtk_table_set_col_spacing(GTK_TABLE(p2
->obj_table
),3,5);
862 _sv_slice_thumb_set((_sv_slice_t
*)sl
[0],lo
);
863 _sv_slice_thumb_set((_sv_slice_t
*)sl
[1],lo
);
864 _sv_slice_thumb_set((_sv_slice_t
*)sl
[2],hi
);
865 _sv_mapping_setup(&p2
->mappings
[i
],0.,1.,0);
866 _sv_slider_set_gradient(p2
->range_scales
[i
], &p2
->mappings
[i
]);
872 p2
->dim_table
= gtk_table_new(p
->dimensions
,4,0);
873 gtk_box_pack_start(GTK_BOX(p
->private->topbox
), p2
->dim_table
, 0,0,4);
875 GtkWidget
*first_x
= NULL
;
876 GtkWidget
*first_y
= NULL
;
877 GtkWidget
*pressed_y
= NULL
;
878 p
->private->dim_scales
= calloc(p
->dimensions
,sizeof(*p
->private->dim_scales
));
879 p2
->dim_xb
= calloc(p
->dimensions
,sizeof(*p2
->dim_xb
));
880 p2
->dim_yb
= calloc(p
->dimensions
,sizeof(*p2
->dim_yb
));
882 for(i
=0;i
<p
->dimensions
;i
++){
883 sv_dim_t
*d
= p
->dimension_list
[i
].d
;
886 GtkWidget
*label
= gtk_label_new(d
->legend
);
887 gtk_misc_set_alignment(GTK_MISC(label
),1.,.5);
888 gtk_table_attach(GTK_TABLE(p2
->dim_table
),label
,0,1,i
,i
+1,
891 /* x/y radio buttons */
892 if(!(d
->flags
& SV_DIM_NO_X
)){
894 p2
->dim_xb
[i
] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_x
),"X");
896 first_x
= p2
->dim_xb
[i
] = gtk_radio_button_new_with_label(NULL
,"X");
897 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2
->dim_xb
[i
]),TRUE
);
899 gtk_table_attach(GTK_TABLE(p2
->dim_table
),p2
->dim_xb
[i
],1,2,i
,i
+1,
903 if(!(d
->flags
& SV_DIM_NO_Y
)){
905 p2
->dim_yb
[i
] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_y
),"Y");
907 first_y
= p2
->dim_yb
[i
] = gtk_radio_button_new_with_label(NULL
,"Y");
908 if(!pressed_y
&& p2
->dim_xb
[i
]!=first_x
){
909 pressed_y
= p2
->dim_yb
[i
];
910 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2
->dim_yb
[i
]),TRUE
);
912 gtk_table_attach(GTK_TABLE(p2
->dim_table
),p2
->dim_yb
[i
],2,3,i
,i
+1,
916 p
->private->dim_scales
[i
] =
917 _sv_dim_widget_new(p
->dimension_list
+i
,_sv_panel2d_center_callback
,_sv_panel2d_bracket_callback
);
919 gtk_table_attach(GTK_TABLE(p2
->dim_table
),
920 p
->private->dim_scales
[i
]->t
,
922 GTK_EXPAND
|GTK_FILL
,0,0,0);
925 for(i
=0;i
<p
->dimensions
;i
++){
927 g_signal_connect (G_OBJECT (p2
->dim_xb
[i
]), "toggled",
928 G_CALLBACK (_sv_panel2d_dimchange_callback
), p
);
930 g_signal_connect (G_OBJECT (p2
->dim_yb
[i
]), "toggled",
931 G_CALLBACK (_sv_panel2d_dimchange_callback
), p
);
935 _sv_panel2d_update_xysel(p
);
937 gtk_widget_realize(p
->private->toplevel
);
938 gtk_widget_realize(p
->private->graph
);
939 gtk_widget_realize(GTK_WIDGET(p
->private->spinner
));
940 gtk_widget_show_all(p
->private->toplevel
);
941 _sv_panel2d_update_xysel(p
); // yes, this was already done; however,
942 // gtk clobbered the event setup on the
943 // insensitive buttons when it realized
944 // them. This call will restore them.
949 static int _sv_panel2d_save(sv_panel_t
*p
, xmlNodePtr pn
){
950 _sv_panel2d_t
*p2
= p
->subtype
->p2
;
955 xmlNewProp(pn
, (xmlChar
*)"type", (xmlChar
*)"2d");
958 if(p
->private->oldbox_active
){
959 xmlNodePtr boxn
= xmlNewChild(pn
, NULL
, (xmlChar
*) "box", NULL
);
960 _xmlNewPropF(boxn
, "x1", p2
->oldbox
[0]);
961 _xmlNewPropF(boxn
, "x2", p2
->oldbox
[1]);
962 _xmlNewPropF(boxn
, "y1", p2
->oldbox
[2]);
963 _xmlNewPropF(boxn
, "y2", p2
->oldbox
[3]);
966 // objective map settings
967 for(i
=0;i
<p
->objectives
;i
++){
968 sv_obj_t
*o
= p
->objective_list
[i
].o
;
969 xmlNodePtr on
= xmlNewChild(pn
, NULL
, (xmlChar
*) "objective", NULL
);
970 _xmlNewPropI(on
, "position", i
);
971 _xmlNewPropI(on
, "number", o
->number
);
972 _xmlNewPropS(on
, "name", o
->name
);
973 _xmlNewPropS(on
, "type", o
->output_types
);
975 // right now Y is the only type; the below is Y-specific
976 n
= xmlNewChild(on
, NULL
, (xmlChar
*) "y-map", NULL
);
977 _xmlNewPropS(n
, "color", _sv_mapping_name(p2
->mappings
[i
].mapnum
));
978 _xmlNewPropF(n
, "low-bracket", _sv_slider_get_value(p2
->range_scales
[i
],0));
979 _xmlNewPropF(n
, "alpha", _sv_slider_get_value(p2
->range_scales
[i
],1));
980 _xmlNewPropF(n
, "high-bracket", _sv_slider_get_value(p2
->range_scales
[i
],2));
984 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "axes", NULL
);
985 _xmlNewPropI(n
, "xpos", p2
->x_dnum
);
986 _xmlNewPropI(n
, "ypos", p2
->y_dnum
);
991 int _sv_panel2d_load(sv_panel_t
*p
,
998 _xmlCheckPropS(pn
,"type","2d", "Panel %d type mismatch in save file.",p
->number
,&warn
);
1002 _xmlGetChildPropFPreserve(pn
, "box", "x1", &u
->box
[0]);
1003 _xmlGetChildPropFPreserve(pn
, "box", "x2", &u
->box
[1]);
1004 _xmlGetChildPropFPreserve(pn
, "box", "y1", &u
->box
[2]);
1005 _xmlGetChildPropFPreserve(pn
, "box", "y2", &u
->box
[3]);
1007 xmlNodePtr n
= _xmlGetChildS(pn
, "box", NULL
, NULL
);
1013 // objective map settings
1014 for(i
=0;i
<p
->objectives
;i
++){
1015 sv_obj_t
*o
= p
->objective_list
[i
].o
;
1016 xmlNodePtr on
= _xmlGetChildI(pn
, "objective", "position", i
);
1018 _sv_first_load_warning(&warn
);
1019 fprintf(stderr
,"No save data found for panel %d objective \"%s\".\n",p
->number
, o
->name
);
1022 _xmlCheckPropS(on
,"name",o
->name
, "Objectve position %d name mismatch in save file.",i
,&warn
);
1023 _xmlCheckPropS(on
,"type",o
->output_types
, "Objectve position %d type mismatch in save file.",i
,&warn
);
1025 // right now Y is the only type; the below is Y-specific
1026 // load maptype, values
1027 _xmlGetChildPropFPreserve(on
, "y-map", "low-bracket", &u
->scale_vals
[0][i
]);
1028 _xmlGetChildPropFPreserve(on
, "y-map", "alpha", &u
->scale_vals
[1][i
]);
1029 _xmlGetChildPropFPreserve(on
, "y-map", "high-bracket", &u
->scale_vals
[2][i
]);
1030 _xmlGetChildMap(on
, "y-map", "color", _sv_mapping_map(), &u
->mappings
[i
],
1031 "Panel %d objective unknown mapping setting", p
->number
, &warn
);
1037 // x/y dim selection
1038 _xmlGetChildPropIPreserve(pn
, "axes", "xpos", &u
->x_d
);
1039 _xmlGetChildPropI(pn
, "axes", "ypos", &u
->y_d
);
1045 void _sv_panel_realize(sv_panel_t
*p
){
1046 if(p
&& !p
->private->realized
){
1047 p
->private->realize(p
);
1049 g_signal_connect (G_OBJECT (p
->private->toplevel
), "key-press-event",
1050 G_CALLBACK (panel_keypress
), p
);
1051 gtk_window_set_title (GTK_WINDOW (p
->private->toplevel
), p
->name
);
1053 p
->private->realized
=1;
1055 // generic things that happen in all panel realizations...
1057 // text black or white in the plot?
1059 p
->private->popmenu
= _gtk_menu_new_twocol(p
->private->toplevel
, menu
, p
);
1060 _sv_panel_update_menus(p
);
1065 int sv_panel_background(int number
,
1066 enum sv_background bg
){
1069 fprintf(stderr
,"sv_panel_background: Panel number must be >= 0\n");
1073 if(number
>_sv_panels
|| !_sv_panel_list
[number
]){
1074 fprintf(stderr
,"sv_panel_background: Panel number %d does not exist\n",number
);
1078 sv_panel_t
*p
= _sv_panel_list
[number
];
1079 return set_background(p
,bg
);
1082 sv_panel_t
*_sv_panel(char *name
){
1085 if(name
== NULL
|| name
== 0 || !strcmp(name
,"")){
1086 return (sv_panel_t
*)pthread_getspecific(_sv_panel_key
);
1089 for(i
=0;i
<_sv_panels
;i
++){
1090 sv_panel_t
*p
=_sv_panel_list
[i
];
1091 if(p
&& p
->name
&& !strcmp(name
,p
->name
)){
1092 pthread_setspecific(_sv_panel_key
, (void *)p
);
1099 int sv_panel(char *name
){
1100 sv_panel_t
*p
= _sv_panel(name
);
1105 sv_panel_t
*sv_panel_new(char *name
,
1109 sv_panel_t
*p
= NULL
;
1111 sv_token
*decl
= _sv_tokenize_declparam(name
);
1112 sv_tokenlist
*dim_tokens
= NULL
;
1113 sv_tokenlist
*obj_tokens
= NULL
;
1117 fprintf(stderr
,"sushivision: Unable to parse panel declaration \"%s\".\n",name
);
1121 // panel and panel list manipulation must be locked
1122 gdk_threads_enter();
1123 pthread_rwlock_wrlock(panellist_m
);
1125 if(_sv_panels
== 0){
1127 _sv_panel_list
= calloc (number
+1,sizeof(*_sv_panel_list
));
1130 for(number
=0;number
<_sv_panels
;number
++)
1131 if(!_sv_panel_list
[number
])break;
1132 if(number
==_sv_panels
){
1133 _sv_panels
=number
+1;
1134 _sv_panel_list
= realloc (_sv_panel_list
,_sv_panels
* sizeof(*_sv_panel_list
));
1138 p
= _sv_panel_list
[number
] = calloc(1, sizeof(**_sv_panel_list
));
1139 p
->name
= strdup(decl
->name
);
1140 p
->legend
= strdup(decl
->label
);
1142 p
->spinner
= _sv_spinner_new();
1144 // parse and sanity check the maps
1146 obj_tokens
= _sv_tokenize_namelist(objectivelist
);
1147 p
->objectives
= obj_tokens
->n
;
1148 p
->objective_list
= malloc(p
->objectives
*sizeof(*p
->objective_list
));
1149 for(i
=0;i
<p
->objectives
;i
++){
1150 char *name
= obj_tokens
->list
[i
]->name
;
1151 p
->objective_list
[i
].o
= _sv_obj(name
);
1152 p
->objective_list
[i
].p
= p
;
1156 dim_tokens
= _sv_tokenize_namelist(dimensionlist
);
1157 p
->dimensions
= dim_tokens
->n
;
1158 p
->dimension_list
= malloc(p
->dimensions
*sizeof(*p
->dimension_list
));
1159 for(i
=0;i
<p
->dimensions
;i
++){
1160 char *name
= dim_tokens
->list
[i
]->name
;
1161 sv_dim_t
*d
= sv_dim(name
);
1164 fprintf(stderr
,"Panel %d (\"%s\"): Dimension \"%s\" does not exist\n",
1165 number
,p
->name
,name
);
1172 fprintf(stderr
,"Panel %d (\"%s\"): Dimension \"%s\" has a NULL scale\n",
1173 number
,p
->name
,name
);
1179 p
->dimension_list
[i
].d
= d
;
1180 p
->dimension_list
[i
].p
= p
;
1183 _sv_tokenlist_free(obj_tokens
);
1184 _sv_tokenlist_free(dim_tokens
);
1195 _sv_panel2d_t
*p2
= calloc(1, sizeof(*p2
));
1196 int fout_offsets
[_sv_functions
];
1199 calloc(1, sizeof(*p
->subtype
)); /* the union is alloced not
1200 embedded as its internal
1201 structure must be hidden */
1202 p
->subtype
->p2
= p2
;
1203 p
->type
= SV_PANEL_2D
;
1204 p
->private->bg_type
= SV_BG_CHECKS
;
1206 // verify all the objectives have scales
1207 for(i
=0;i
<p
->objectives
;i
++){
1208 if(!p
->objective_list
[i
].o
->scale
){
1209 fprintf(stderr
,"All objectives in a 2d panel must have a scale\n");
1215 p
->private->realize
= _sv_panel2d_realize
;
1216 p
->private->map_action
= _sv_panel2d_map_redraw
;
1217 p
->private->legend_action
= _sv_panel2d_legend_redraw
;
1218 p
->private->compute_action
= _sv_panel2d_compute
;
1219 p
->private->request_compute
= _sv_panel2d_mark_recompute
;
1220 p
->private->crosshair_action
= _sv_panel2d_crosshairs_callback
;
1221 p
->private->print_action
= _sv_panel2d_print
;
1222 p
->private->undo_log
= _sv_panel2d_undo_log
;
1223 p
->private->undo_restore
= _sv_panel2d_undo_restore
;
1224 p
->private->save_action
= _sv_panel2d_save
;
1225 p
->private->load_action
= _sv_panel2d_load
;
1227 /* set up helper data structures for rendering */
1229 /* determine which functions are actually needed; if it's referenced
1230 by an objective, it's used. Precache them in dense form. */
1232 int fn
= _sv_functions
;
1233 int used
[fn
],count
=0,offcount
=0;
1234 memset(used
,0,sizeof(used
));
1235 memset(fout_offsets
,-1,sizeof(fout_offsets
));
1237 for(i
=0;i
<p
->objectives
;i
++){
1238 sv_obj_t
*o
= p
->objective_list
[i
].o
;
1239 for(j
=0;j
<o
->outputs
;j
++)
1240 used
[o
->function_map
[j
]]=1;
1245 sv_func_t
*f
= _sv_function_list
[i
];
1246 fout_offsets
[i
] = offcount
;
1247 offcount
+= f
->outputs
;
1251 p2
->used_functions
= count
;
1252 p2
->used_function_list
= calloc(count
, sizeof(*p2
->used_function_list
));
1254 for(count
=0,i
=0;i
<fn
;i
++)
1256 p2
->used_function_list
[count
]=_sv_function_list
[i
];
1261 /* set up computation/render helpers for Y planes */
1263 /* set up Y object mapping index */
1267 for(i
=0;i
<p
->objectives
;i
++){
1268 sv_obj_t
*o
= p
->objective_list
[i
].o
;
1269 if(o
->private->y_func
) yobj_count
++;
1272 p2
->y_obj_num
= yobj_count
;
1273 p2
->y_obj_list
= calloc(yobj_count
, sizeof(*p2
->y_obj_list
));
1274 p2
->y_obj_to_panel
= calloc(yobj_count
, sizeof(*p2
->y_obj_to_panel
));
1275 p2
->y_obj_from_panel
= calloc(p
->objectives
, sizeof(*p2
->y_obj_from_panel
));
1278 for(i
=0;i
<p
->objectives
;i
++){
1279 sv_obj_t
*o
= p
->objective_list
[i
].o
;
1280 if(o
->private->y_func
){
1281 p2
->y_obj_list
[yobj_count
] = o
;
1282 p2
->y_obj_to_panel
[yobj_count
] = i
;
1283 p2
->y_obj_from_panel
[i
] = yobj_count
;
1286 p2
->y_obj_from_panel
[i
] = -1;
1291 /* set up function Y output value demultiplex helper */
1293 p2
->y_fout_offset
= calloc(p2
->y_obj_num
, sizeof(*p2
->y_fout_offset
));
1294 for(i
=0;i
<p2
->y_obj_num
;i
++){
1295 sv_obj_t
*o
= p2
->y_obj_list
[i
];
1296 int funcnum
= o
->private->y_func
->number
;
1297 p2
->y_fout_offset
[i
] = fout_offsets
[funcnum
] + o
->private->y_fout
;
1301 p2
->y_map
= calloc(p2
->y_obj_num
,sizeof(*p2
->y_map
));
1302 p2
->y_planetodo
= calloc(p2
->y_obj_num
,sizeof(*p2
->y_planetodo
));
1303 p2
->y_planes
= calloc(p2
->y_obj_num
,sizeof(*p2
->y_planes
));
1311 void _sv_panel_undo_log(sv_panel_t
*p
, _sv_panel_undo_t
*u
){
1312 u
->cross_mode
= PLOT(p
->private->graph
)->cross_active
;
1313 u
->legend_mode
= PLOT(p
->private->graph
)->legend_active
;
1314 u
->grid_mode
= PLOT(p
->private->graph
)->grid_mode
;
1315 u
->text_mode
= PLOT(p
->private->graph
)->bg_inv
;
1316 u
->bg_mode
= p
->private->bg_type
;
1317 u
->menu_cursamp
= p
->private->menu_cursamp
;
1318 u
->oversample_n
= p
->private->oversample_n
;
1319 u
->oversample_d
= p
->private->oversample_d
;
1321 // panel-subtype-specific population
1322 p
->private->undo_log(u
,p
);
1325 void _sv_panel_undo_restore(sv_panel_t
*p
, _sv_panel_undo_t
*u
){
1326 // go in through setting routines
1327 _sv_plot_set_crossactive(PLOT(p
->private->graph
),u
->cross_mode
);
1328 _sv_plot_set_legendactive(PLOT(p
->private->graph
),u
->legend_mode
);
1329 set_background(p
, u
->bg_mode
); // must be first; it can frob grid and test
1330 set_text(p
, u
->text_mode
);
1331 set_grid(p
, u
->grid_mode
);
1332 p
->private->menu_cursamp
= u
->menu_cursamp
;
1333 res_set(p
, u
->oversample_n
, u
->oversample_d
);
1335 // panel-subtype-specific restore
1336 p
->private->undo_restore(u
,p
);
1338 _sv_panel_dirty_legend(p
);
1341 int _sv_panel_save(sv_panel_t
*p
, xmlNodePtr instance
){
1346 xmlNodePtr pn
= xmlNewChild(instance
, NULL
, (xmlChar
*) "panel", NULL
);
1349 _xmlNewPropI(pn
, "number", p
->number
);
1350 _xmlNewPropS(pn
, "name", p
->name
);
1352 // let the panel subtype handler fill in type
1353 // we're only saving settings independent of subtype
1356 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "background", NULL
);
1357 _xmlNewMapProp(n
, "color", bgmap
, p
->private->bg_type
);
1360 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "grid", NULL
);
1361 _xmlNewMapProp(n
, "mode", gridmap
, PLOT(p
->private->graph
)->grid_mode
);
1364 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "crosshairs", NULL
);
1365 _xmlNewMapProp(n
, "active", crossmap
, PLOT(p
->private->graph
)->cross_active
);
1368 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "legend", NULL
);
1369 _xmlNewMapProp(n
,"mode", legendmap
, PLOT(p
->private->graph
)->legend_active
);
1372 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "text", NULL
);
1373 _xmlNewMapProp(n
,"color", textmap
, PLOT(p
->private->graph
)->bg_inv
);
1376 n
= xmlNewChild(pn
, NULL
, (xmlChar
*) "sampling", NULL
);
1377 snprintf(buffer
,sizeof(buffer
),"%d:%d",
1378 p
->private->oversample_n
, p
->private->oversample_d
);
1379 xmlNewProp(n
, (xmlChar
*)"ratio", (xmlChar
*)buffer
);
1382 if(p
->private->save_action
)
1383 ret
|= p
->private->save_action(p
, pn
);
1388 int _sv_panel_load(sv_panel_t
*p
,
1389 _sv_panel_undo_t
*u
,
1394 _xmlCheckPropS(pn
,"name",p
->name
,"Panel %d name mismatch in save file.",p
->number
,&warn
);
1397 _xmlGetChildMap(pn
, "background", "color", bgmap
, &u
->bg_mode
,
1398 "Panel %d unknown background setting", p
->number
, &warn
);
1400 _xmlGetChildMap(pn
, "grid", "mode", gridmap
, &u
->grid_mode
,
1401 "Panel %d unknown grid mode setting", p
->number
, &warn
);
1403 _xmlGetChildMap(pn
, "crosshairs", "active", crossmap
, &u
->cross_mode
,
1404 "Panel %d unknown crosshair setting", p
->number
, &warn
);
1406 _xmlGetChildMap(pn
, "legend", "mode", legendmap
, &u
->legend_mode
,
1407 "Panel %d unknown legend setting", p
->number
, &warn
);
1409 _xmlGetChildMap(pn
, "text", "color", textmap
, &u
->text_mode
,
1410 "Panel %d unknown text color setting", p
->number
, &warn
);
1413 _xmlGetChildPropS(pn
, "sampling", "ratio", &prop
);
1415 int res
= sscanf(prop
,"%d:%d", &u
->oversample_n
, &u
->oversample_d
);
1417 fprintf(stderr
,"Unable to parse sample setting (%s) for panel %d.\n",prop
,p
->number
);
1418 u
->oversample_n
= p
->private->def_oversample_n
;
1419 u
->oversample_d
= p
->private->def_oversample_d
;
1421 if(u
->oversample_d
== 0) u
->oversample_d
= 1;
1426 if(p
->private->load_action
)
1427 warn
= p
->private->load_action(p
, u
, pn
, warn
);
1429 // any unparsed elements?
1430 xmlNodePtr n
= pn
->xmlChildrenNode
;
1433 if (n
->type
== XML_ELEMENT_NODE
) {
1434 _sv_first_load_warning(&warn
);
1435 fprintf(stderr
,"Unknown option (%s) set for panel %d.\n",n
->name
,p
->number
);
1443 int sv_panel_callback_recompute (sv_panel_t
*p
,
1444 int (*callback
)(sv_panel_t
*p
,void *data
),
1447 p
->private->callback_precompute
= callback
;
1448 p
->private->callback_precompute_data
= data
;