[xiph-commits] r12753 - trunk/sushivision
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Tue Mar 13 19:14:00 PDT 2007
Author: xiphmont
Date: 2007-03-13 19:13:57 -0700 (Tue, 13 Mar 2007)
New Revision: 12753
Added:
trunk/sushivision/panel-xy.c
trunk/sushivision/panel-xy.h
Modified:
trunk/sushivision/internal.h
trunk/sushivision/panel-1d.c
trunk/sushivision/panel-2d.c
Log:
Incremental commit to get new source in SVN. Module is not complete (and not yet part of build)
Modified: trunk/sushivision/internal.h
===================================================================
--- trunk/sushivision/internal.h 2007-03-13 20:29:15 UTC (rev 12752)
+++ trunk/sushivision/internal.h 2007-03-14 02:13:57 UTC (rev 12753)
@@ -47,11 +47,13 @@
#include "dimension.h"
#include "objective.h"
#include "panel-1d.h"
+#include "panel-xy.h"
#include "panel-2d.h"
#include "xml.h"
#include "gtksucks.h"
union sushiv_panel_subtype {
+ sushiv_panelxy_t *pxy;
sushiv_panel1d_t *p1;
sushiv_panel2d_t *p2;
};
Modified: trunk/sushivision/panel-1d.c
===================================================================
--- trunk/sushivision/panel-1d.c 2007-03-13 20:29:15 UTC (rev 12752)
+++ trunk/sushivision/panel-1d.c 2007-03-14 02:13:57 UTC (rev 12753)
@@ -379,7 +379,7 @@
char buffer[320];
plot_legend_clear(plot);
- if(-p1->x_v.decimal_exponent > depth) depth = 3-p1->x_v.decimal_exponent;
+ if(3-p1->x_v.decimal_exponent > depth) depth = 3-p1->x_v.decimal_exponent;
// add each dimension to the legend
for(i=0;i<p->dimensions;i++){
@@ -500,7 +500,8 @@
_sushiv_undo_suspend(p->sushi);
// update colormap
- p1->linetype[onum]=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+ int pos = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+ p1->linetype[onum] = line_name[pos].value;
_sushiv_panel_dirty_map(p);
_sushiv_undo_resume(p->sushi);
@@ -516,7 +517,8 @@
_sushiv_undo_suspend(p->sushi);
// update colormap
- p1->pointtype[onum]=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+ int pos = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+ p1->pointtype[onum] = point_name[pos].value;
_sushiv_panel_dirty_map(p);
_sushiv_undo_resume(p->sushi);
Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c 2007-03-13 20:29:15 UTC (rev 12752)
+++ trunk/sushivision/panel-2d.c 2007-03-14 02:13:57 UTC (rev 12753)
@@ -901,12 +901,12 @@
}
}
- // one space
- plot_legend_add(plot,NULL);
-
// add each active objective plane to the legend
// choose the value under the crosshairs
if(plot->cross_active){
+ // one space
+ plot_legend_add(plot,NULL);
+
for(i=0;i<p->objectives;i++){
if(!mapping_inactive_p(p2->mappings+i)){
Added: trunk/sushivision/panel-xy.c
===================================================================
--- trunk/sushivision/panel-xy.c 2007-03-13 20:29:15 UTC (rev 12752)
+++ trunk/sushivision/panel-xy.c 2007-03-14 02:13:57 UTC (rev 12753)
@@ -0,0 +1,1526 @@
+/*
+ *
+ * sushivision copyright (C) 2006-2007 Monty <monty at xiph.org>
+ *
+ * sushivision is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * sushivision is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with sushivision; see the file COPYING. If not, write to the
+ * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <gtk/gtk.h>
+#include <cairo-ft.h>
+#include "internal.h"
+
+#define LINETYPES 6
+static propmap *line_name[LINETYPES+1] = {
+ &(propmap){"line", 0, NULL,NULL,NULL},
+ &(propmap){"fat line", 1, NULL,NULL,NULL},
+ &(propmap){"no line", 5, NULL,NULL,NULL},
+ NULL
+};
+
+#define POINTTYPES 9
+static propmap *point_name[POINTTYPES+1] = {
+ &(propmap){"dot", 0, NULL,NULL,NULL},
+ &(propmap){"cross", 1, NULL,NULL,NULL},
+ &(propmap){"plus", 2, NULL,NULL,NULL},
+ &(propmap){"open circle", 3, NULL,NULL,NULL},
+ &(propmap){"open square", 4, NULL,NULL,NULL},
+ &(propmap){"open triangle", 5, NULL,NULL,NULL},
+ &(propmap){"solid circle", 6, NULL,NULL,NULL},
+ &(propmap){"solid square", 7, NULL,NULL,NULL},
+ &(propmap){"solid triangle", 8, NULL,NULL,NULL},
+ NULL
+};
+
+static void render_checks(cairo_t *c, int w, int h){
+ /* default checked background */
+ /* 16x16 'mid-checks' */
+ int x,y;
+
+ cairo_set_source_rgb (c, .5,.5,.5);
+ cairo_paint(c);
+ cairo_set_source_rgb (c, .314,.314,.314);
+
+ for(y=0;y<h;y+=16){
+ int phase = (y>>4)&1;
+ for(x=0;x<w;x+=16){
+ if(phase){
+ cairo_rectangle(c,x,y,16.,16.);
+ cairo_fill(c);
+ }
+ phase=!phase;
+ }
+ }
+}
+
+// called internally, assumes we hold lock
+// redraws the data, does not compute the data
+static int _sushiv_panelxy_remap(sushiv_panel_t *p, cairo_t *c){
+ sushiv_panelxy_t *xy = p->subtype->pxy;
+ Plot *plot = PLOT(p->private->graph);
+
+ int plot_serialno = p->private->plot_serialno;
+ int map_serialno = p->private->map_serialno;
+ int xi,i,j;
+ int pw = plot->x.pixels;
+ int ph = plot->y.pixels;
+
+ scalespace sx = p1->x;
+ scalespace sy = p1->y;
+ scalespace data_v = p1->data_v;
+ scalespace px = plot->x;
+ scalespace py = plot->y;
+
+ /* do the panel and plot scales match? If not, redraw the plot
+ scales */
+
+ if(memcmp(&sx,&px,sizeof(sx)) ||
+ memcmp(&sy,&py,sizeof(sy))){
+
+ plot->x = sx;
+ plot->y = sy;
+
+ gdk_threads_leave();
+ plot_draw_scales(plot);
+ }else
+ gdk_threads_leave();
+
+ /* blank frame to selected bg */
+ switch(p->private->bg_type){
+ case SUSHIV_BG_WHITE:
+ cairo_set_source_rgb (c, 1.,1.,1.);
+ cairo_paint(c);
+ break;
+ case SUSHIV_BG_BLACK:
+ cairo_set_source_rgb (c, 0,0,0);
+ cairo_paint(c);
+ break;
+ case SUSHIV_BG_CHECKS:
+ render_checks(c,pw,ph);
+ break;
+ }
+
+ gdk_threads_enter();
+ if(plot_serialno != p->private->plot_serialno ||
+ map_serialno != p->private->map_serialno) return -1;
+
+ if(xy->data_head){
+
+ /* by objective */
+ for(j=0;j<p->objectives;j++){
+ if(xy->data_head[j] && xy->data_length[j] && !mapping_inactive_p(xy->mappings+j)){
+
+ int dw = xy->data_length[j];
+ double alpha = slider_get_value(xy->alpha_scale[j],0);
+ int linetype = xy->linetype[j];
+ int pointtype = xy->pointtype[j];
+ u_int32_t color = mapping_calc(xy->mappings+j,1.,0);
+
+ double xv[dw];
+ double yv[dw];
+
+ // copy the list data over
+ xy_data_t *d = xy->data_head[j];
+ i=0;
+ while(d){
+ xv[i] = d->xval;
+ yv[i] = d->yval;
+ d=d->next;
+ }
+ gdk_threads_leave();
+
+ /* by x */
+ for(xi=0;xi<dw;xi++){
+ double xpixel = xv[xi];
+ double ypixel = yv[xi];
+
+ /* map data vector bin to x pixel location in the plot */
+ if(!isnan(xpixel))
+ xpixel = scalespace_pixel(&sx,xpixel)+.5;
+
+ if(!isnan(ypixel))
+ ypixel = scalespace_pixel(&sy,ypixel)+.5;
+
+ xv[xi] = xpixel;
+ yv[xi] = ypixel;
+ }
+
+ /* draw lines, if any */
+ if(linetype != 5){
+ cairo_set_source_rgba(c,
+ ((color>>16)&0xff)/255.,
+ ((color>>8)&0xff)/255.,
+ ((color)&0xff)/255.,
+ alpha);
+ if(linetype == 1)
+ cairo_set_line_width(c,2.);
+ else
+ cairo_set_line_width(c,1.);
+
+ for(i=1;i<dw;i++){
+
+ if(!isnan(yv[i-1]) && !isnan(yv[i])){
+ cairo_move_to(c,xv[i-1],yv[i-1]);
+ cairo_line_to(c,xv[i],yv[i]);
+ cairo_stroke(c);
+ }
+ }
+ }
+
+ /* now draw the points */
+ if(pointtype > 0 || linetype == 5){
+ cairo_set_line_width(c,1.);
+
+ for(i=0;i<dw;i++){
+ if(!isnan(yv[i])){
+ double xx,yy;
+ xx = xv[i];
+ yy = yv[i];
+
+ cairo_set_source_rgba(c,
+ ((color>>16)&0xff)/255.,
+ ((color>>8)&0xff)/255.,
+ ((color)&0xff)/255.,
+ alpha);
+
+ switch(pointtype){
+ case 0: /* pixeldots */
+ cairo_rectangle(c, xx-.5,yy-.5,1,1);
+ cairo_fill(c);
+ break;
+ case 1: /* X */
+ cairo_move_to(c,xx-4,yy-4);
+ cairo_line_to(c,xx+4,yy+4);
+ cairo_move_to(c,xx+4,yy-4);
+ cairo_line_to(c,xx-4,yy+4);
+ break;
+ case 2: /* + */
+ cairo_move_to(c,xx-4,yy);
+ cairo_line_to(c,xx+4,yy);
+ cairo_move_to(c,xx,yy-4);
+ cairo_line_to(c,xx,yy+4);
+ break;
+ case 3: case 6: /* circle */
+ cairo_arc(c,xx,yy,4,0,2.*M_PI);
+ break;
+ case 4: case 7: /* square */
+ cairo_rectangle(c,xx-4,yy-4,8,8);
+ break;
+ case 5: case 8: /* triangle */
+ cairo_move_to(c,xx,yy-5);
+ cairo_line_to(c,xx-4,yy+3);
+ cairo_line_to(c,xx+4,yy+3);
+ cairo_close_path(c);
+ break;
+ }
+
+ if(pointtype>5){
+ cairo_fill_preserve(c);
+ }
+
+ if(pointtype>0){
+ if(p->private->bg_type == SUSHIV_BG_WHITE)
+ cairo_set_source_rgba(c,0.,0.,0.,alpha);
+ else
+ cairo_set_source_rgba(c,1.,1.,1.,alpha);
+ cairo_stroke(c);
+ }
+ }
+ }
+ }
+
+ gdk_threads_enter();
+ if(plot_serialno != p->private->plot_serialno ||
+ map_serialno != p->private->map_serialno) return -1;
+
+
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void sushiv_panelxy_print(sushiv_panel_t *p, cairo_t *c, int w, int h){
+ Plot *plot = PLOT(p->private->graph);
+ double pw = p->private->graph->allocation.width;
+ double ph = p->private->graph->allocation.height;
+ double scale;
+
+ if(w/pw < h/ph)
+ scale = w/pw;
+ else
+ scale = h/ph;
+
+ cairo_matrix_t m;
+ cairo_get_matrix(c,&m);
+ cairo_matrix_scale(&m,scale,scale);
+ cairo_set_matrix(c,&m);
+
+ plot_print(plot, c, ph*scale, (void(*)(void *, cairo_t *))_sushiv_panelxy_remap, p);
+}
+
+static void update_legend(sushiv_panel_t *p){
+ sushiv_panelxy_t *xy = p->subtype->xy;
+ Plot *plot = PLOT(p->private->graph);
+
+ gdk_threads_enter ();
+
+ if(plot){
+ int i,depth=0;
+ char buffer[320];
+ plot_legend_clear(plot);
+
+ if(3-xy->data_v.decimal_exponent > depth) depth = 3-xy->data_v.decimal_exponent;
+ if(3-xy->x.decimal_exponent > depth) depth = 3-xy->x.decimal_exponent;
+ if(3-xy->y.decimal_exponent > depth) depth = 3-xy->y.decimal_exponent;
+
+ // if crosshairs are active, add them to the fun
+ if( plot->cross_active){
+ snprintf(buffer,320,"%s = %+.*f",
+ xy->x_scale.name,
+ depth,
+ xy->x_val);
+ plot_legend_add(plot,buffer);
+ snprintf(buffer,320,"%s = %+.*f",
+ xy->y_scale.name,
+ depth,
+ xy->y_val);
+ plot_legend_add(plot,buffer);
+
+ if(p->dimensions)
+ plot_legend_add(plot,NULL);
+ }
+
+ // add each dimension to the legend
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = p->dimension_list[i].d;
+
+ if(d != xy->x_d ||
+ plot->cross_active){
+
+ snprintf(buffer,320,"%s = %+.*f",
+ p->dimension_list[i].d->name,
+ depth,
+ p->dimension_list[i].d->val);
+ plot_legend_add(plot,buffer);
+ }
+ }
+
+ gdk_threads_leave ();
+ }
+}
+
+static void mapchange_callback_xy(GtkWidget *w,gpointer in){
+ sushiv_objective_list_t *optr = (sushiv_objective_list_t *)in;
+ sushiv_panel_t *p = optr->p;
+ sushiv_panelxy_t *xy = p->subtype->xy;
+ int onum = optr - p->objective_list;
+
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+
+ // update colormap
+ // oh, the wasteful
+ int pos = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+ solid_set_func(&xy->mappings[onum],pos);
+ slider_set_gradient(xy->alpha_scale[onum], &xy->mappings[onum]);
+
+ _sushiv_panel_dirty_map(p);
+ _sushiv_panel_dirty_legend(p);
+ _sushiv_undo_resume(p->sushi);
+}
+
+static void alpha_callback_xy(void * in, int buttonstate){
+ sushiv_objective_list_t *optr = (sushiv_objective_list_t *)in;
+ sushiv_panel_t *p = optr->p;
+
+ if(buttonstate == 0){
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+ }
+
+ _sushiv_panel_dirty_map(p);
+ _sushiv_panel_dirty_legend(p);
+
+ if(buttonstate == 2)
+ _sushiv_undo_resume(p->sushi);
+}
+
+static void linetype_callback_xy(GtkWidget *w,gpointer in){
+ sushiv_objective_list_t *optr = (sushiv_objective_list_t *)in;
+ sushiv_panel_t *p = optr->p;
+ sushiv_panelxy_t *xy = p->subtype->xy;
+ int onum = optr - p->objective_list;
+
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+
+ // update colormap
+ int pos = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+ xy->linetype[onum] = line_name[pos].value;
+
+ _sushiv_panel_dirty_map(p);
+ _sushiv_undo_resume(p->sushi);
+}
+
+static void pointtype_callback_xy(GtkWidget *w,gpointer in){
+ sushiv_objective_list_t *optr = (sushiv_objective_list_t *)in;
+ sushiv_panel_t *p = optr->p;
+ sushiv_panelxy_t *xy = p->subtype->xy;
+ int onum = optr - p->objective_list;
+
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+
+ // update colormap
+ int pos = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+ xy->pointtype[onum] = point_name[pos].value;
+
+ _sushiv_panel_dirty_map(p);
+ _sushiv_undo_resume(p->sushi);
+}
+
+static void map_callback_xy(void *in,int buttonstate){
+ sushiv_panel_t *p = (sushiv_panel_t *)in;
+ sushiv_panel1d_t *xy = p->subtype->xy;
+ Plot *plot = PLOT(p->private->graph);
+
+ if(buttonstate == 0){
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+ }
+
+ // has new bracketing changed the plot range scale?
+ if(xy->x_bracket[0] != slider_get_value(xy->x_slider,0) ||
+ xy->x_bracket[1] != slider_get_value(xy->x_slider,1) ||
+ xy->y_bracket[0] != slider_get_value(xy->y_slider,0) ||
+ xy->y_bracket[1] != slider_get_value(xy->y_slider,1)){
+
+ int w = plot->w.allocation.width;
+ int h = plot->w.allocation.height;
+
+ xy->x_bracket[0] = slider_get_value(xy->x_slider,0);
+ xy->x_bracket[1] = slider_get_value(xy->x_slider,1);
+ xy->y_bracket[0] = slider_get_value(xy->y_slider,0);
+ xy->y_bracket[1] = slider_get_value(xy->y_slider,1);
+
+ xy->x = scalespace_linear(xy->x_bracket[1],
+ xy->x_bracket[0],
+ w,
+ plot->scalespacing,
+ xy->x_scale->legend);
+ xy->y = scalespace_linear(xy->y_bracket[1],
+ xy->y_bracket[0],
+ h,
+ plot->scalespacing,
+ xy->y_scale->legend);
+
+ }
+
+ //redraw the plot
+ _sushiv_panel_dirty_map(p);
+ if(buttonstate == 2)
+ _sushiv_undo_resume(p->sushi);
+}
+
+static void update_dim_sel(sushiv_panel_t *p){
+ sushiv_panelxy_t *xy = p->subtype->xy;
+ int i;
+
+ // enable/disable dimension slider thumbs
+ for(i=0;i<p->dimensions;i++){
+
+ if(xy->dim_xb[i] &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xy->dim_xb[i]))){
+
+ // set the x dim flag
+ xy->x_d = p->dimension_list[i].d;
+ xy->x_widget = p->private->dim_scales[i];
+ xy->x_dnum = i;
+ }
+ if(xy->dim_xb[i] &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xy->dim_xb[i]))){
+ // make all thumbs visible
+ _sushiv_dim_widget_set_thumb_active(p->private->dim_scales[i],0,1);
+ _sushiv_dim_widget_set_thumb_active(p->private->dim_scales[i],2,1);
+ }else{
+ // make bracket thumbs invisible */
+ _sushiv_dim_widget_set_thumb_active(p->private->dim_scales[i],0,0);
+ _sushiv_dim_widget_set_thumb_active(p->private->dim_scales[i],2,0);
+ }
+ }
+}
+
+static void compute_xy_one(sushiv_panel_t *p,
+ double *dim_vals,
+ xy_data_t **out,
+ _sushiv_bythread_cache_xy *c){
+ sushiv_panelxy_t *xy = p->subtype->xy;
+ double work[w];
+ int i,j,fn=p->sushi->functions;
+
+ /* by function */
+ for(i=0;i<fn;i++){
+ if(c->call[i]){
+ sushiv_function_t *f = p->sushi->function_list[i];
+ int step = f->outputs;
+ double *fout = c->fout[i];
+
+ c->call[i](dim_vals,fout);
+ }
+ }
+
+ /* process function output by objective */
+ /* XY panels currently only care about the X and Y output value; in the
+ future, Z, etc may also be relevant */
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ int xoff = o->private->x_fout;
+ int yoff = o->private->y_fout;
+ sushiv_function_t *xf = o->private->x_func;
+ sushiv_function_t *yf = o->private->y_func;
+XXXX
+ if(xf && yf){
+ int step = f->outputs;
+ double *fout = c->fout[f->number]+offset;
+
+ /* map result from function output to objective output */
+ for(j=0;j<w;j++){
+ work[j] = *fout;
+ fout+=step;
+ }
+
+ gdk_threads_enter (); // misuse me as a global mutex
+ if(p->private->plot_serialno == serialno){
+ /* store result in panel */
+ memcpy(p1->data_vec[i],work,w*sizeof(*work));
+ gdk_threads_leave (); // misuse me as a global mutex
+ }else{
+ gdk_threads_leave (); // misuse me as a global mutex
+ break;
+ }
+ }
+ }
+}
+
+static void compute_xy(sushiv_panel_t *p,
+ int serialno,
+ int x_d,
+ scalespace sxi,
+ int w,
+ double *dim_vals,
+ _sushiv_bythread_cache_1d *c){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ double work[w];
+ int i,j,fn=p->sushi->functions;
+
+ /* by function */
+ for(i=0;i<fn;i++){
+ if(c->call[i]){
+ sushiv_function_t *f = p->sushi->function_list[i];
+ int step = f->outputs;
+ double *fout = c->fout[i];
+
+ /* by x */
+ for(j=0;j<w;j++){
+ dim_vals[x_d] = scalespace_value(&sxi,j);
+ c->call[i](dim_vals,fout);
+ fout+=step;
+ }
+ }
+ }
+
+ /* process function output by objective */
+ /* 1d panels currently only care about the Y output value; in the
+ future, Z may also be relevant */
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ int offset = o->private->y_fout;
+ sushiv_function_t *f = o->private->y_func;
+ if(f){
+ int step = f->outputs;
+ double *fout = c->fout[f->number]+offset;
+
+ /* map result from function output to objective output */
+ for(j=0;j<w;j++){
+ work[j] = *fout;
+ fout+=step;
+ }
+
+ gdk_threads_enter (); // misuse me as a global mutex
+ if(p->private->plot_serialno == serialno){
+ /* store result in panel */
+ memcpy(p1->data_vec[i],work,w*sizeof(*work));
+ gdk_threads_leave (); // misuse me as a global mutex
+ }else{
+ gdk_threads_leave (); // misuse me as a global mutex
+ break;
+ }
+ }
+ }
+}
+
+// call only from main gtk thread
+void _mark_recompute_1d(sushiv_panel_t *p){
+ if(!p->private->realized) return;
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ Plot *plot = PLOT(p->private->graph);
+ int w = plot->w.allocation.width;
+ int h = plot->w.allocation.height;
+ int dw = w;
+ sushiv_panel_t *link = (p1->link_x ? p1->link_x : p1->link_y);
+ sushiv_panel2d_t *p2 = (link?link->subtype->p2:NULL);
+ int i,j;
+
+ if(p1->link_x){
+ dw = p2->x_v.pixels;
+ p1->x_d = p2->x_d;
+ p1->x_scale = p2->x_scale;
+ }
+ if(p1->link_y){
+ dw = p2->y_v.pixels;
+ p1->x_d = p2->y_d;
+ p1->x_scale = p2->y_scale;
+ }
+
+ if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
+ if(p1->flip){
+ dw = _sushiv_dimension_scales(p1->x_d,
+ p1->x_d->bracket[1],
+ p1->x_d->bracket[0],
+ h,dw * p->private->oversample_n / p->private->oversample_d,
+ plot->scalespacing,
+ p1->x_d->name,
+ &p1->x,
+ &p1->x_v,
+ &p1->x_i);
+
+ p1->y = scalespace_linear(p1->range_bracket[0],
+ p1->range_bracket[1],
+ w,
+ plot->scalespacing,
+ p1->range_scale->legend);
+
+ }else{
+ dw = _sushiv_dimension_scales(p1->x_d,
+ p1->x_d->bracket[0],
+ p1->x_d->bracket[1],
+ w,dw * p->private->oversample_n / p->private->oversample_d,
+ plot->scalespacing,
+ p1->x_d->name,
+ &p1->x,
+ &p1->x_v,
+ &p1->x_i);
+
+ p1->y = scalespace_linear(p1->range_bracket[1],
+ p1->range_bracket[0],
+ h,
+ plot->scalespacing,
+ p1->range_scale->legend);
+ }
+
+ if(p1->data_size != dw){
+ if(p1->data_vec){
+
+ // make new vec
+ int i;
+ for(i=0;i<p->objectives;i++){
+ double *new_vec = malloc(dw * sizeof(**p1->data_vec));
+
+ free(p1->data_vec[i]);
+ p1->data_vec[i] = new_vec;
+ }
+ }
+ }
+
+ p1->data_size = dw;
+ p1->panel_w = w;
+ p1->panel_h = h;
+
+ if(!p1->data_vec){
+ // allocate it
+
+ p1->data_vec = calloc(p->objectives,sizeof(*p1->data_vec));
+ for(i=0;i<p->objectives;i++)
+ p1->data_vec[i] = malloc(dw*sizeof(**p1->data_vec));
+
+ }
+
+ // blank it
+ for(i=0;i<p->objectives;i++)
+ for(j=0;j<dw;j++)
+ p1->data_vec[i][j]=NAN;
+
+ _sushiv_panel_dirty_plot(p);
+ }
+}
+
+static void recompute_callback_1d(void *ptr){
+ sushiv_panel_t *p = (sushiv_panel_t *)ptr;
+ _mark_recompute_1d(p);
+}
+
+void _sushiv_panel1d_mark_recompute_linked(sushiv_panel_t *p){
+ int i;
+
+ /* look to see if any 1d panels link to passed in panel */
+ sushiv_instance_t *s = p->sushi;
+ for(i=0;i<s->panels;i++){
+ sushiv_panel_t *q = s->panel_list[i];
+ if(q != p && q->type == SUSHIV_PANEL_1D){
+ sushiv_panel1d_t *q1 = q->subtype->p1;
+ if(q1->link_x == p)
+ _mark_recompute_1d(q);
+ else{
+ if(q1->link_y == p)
+ _mark_recompute_1d(q);
+ }
+ }
+ }
+}
+
+static void update_crosshair(sushiv_panel_t *p){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ sushiv_panel_t *link=p1->link_x;
+ Plot *plot = PLOT(p->private->graph);
+ double x=0;
+ int i;
+
+ if(!p->private->realized)return;
+
+ if(p1->link_y)link=p1->link_y;
+
+ if(link){
+ for(i=0;i<link->dimensions;i++){
+ sushiv_dimension_t *d = link->dimension_list[i].d;
+ if(d == p1->x_d)
+ x = link->dimension_list[i].d->val;
+ }
+ }else{
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = p->dimension_list[i].d;
+ if(d == p1->x_d)
+ x = p->dimension_list[i].d->val;
+ }
+ }
+
+ if(p1->flip)
+ plot_set_crosshairs(plot,0,x);
+ else
+ plot_set_crosshairs(plot,x,0);
+
+ // in independent panels, crosshairs snap to a pixel position; the
+ // cached dimension value should be accurate with respect to the
+ // crosshairs. in linked panels, the crosshairs snap to a pixel
+ // position in the master panel; that is handled in the master, not
+ // here.
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = p->dimension_list[i].d;
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ if(d == p1->x_d){
+ if(p1->flip)
+ d->val = scalespace_value(&plot->x,plot_get_crosshair_ypixel(plot));
+ else
+ d->val = scalespace_value(&plot->x,plot_get_crosshair_xpixel(plot));
+ }
+ }
+ _sushiv_panel_dirty_legend(p);
+}
+
+void _sushiv_panel1d_update_linked_crosshairs(sushiv_panel_t *p, int xflag, int yflag){
+ int i;
+
+ /* look to see if any 1d panels link to passed in panel */
+ sushiv_instance_t *s = p->sushi;
+ for(i=0;i<s->panels;i++){
+ sushiv_panel_t *q = s->panel_list[i];
+ if(q != p && q->type == SUSHIV_PANEL_1D){
+ sushiv_panel1d_t *q1 = q->subtype->p1;
+ if(q1->link_x == p){
+ update_crosshair(q);
+ if(yflag)
+ q->private->request_compute(q);
+ }else{
+ if(q1->link_y == p){
+ update_crosshair(q);
+ if(xflag)
+ q->private->request_compute(q);
+ }
+ }
+ }
+ }
+}
+
+static void center_callback_1d(sushiv_dimension_list_t *dptr){
+ sushiv_dimension_t *d = dptr->d;
+ sushiv_panel_t *p = dptr->p;
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ int axisp = (d == p1->x_d);
+
+ if(!axisp){
+ // mid slider of a non-axis dimension changed, rerender
+ _mark_recompute_1d(p);
+ }else{
+ // mid slider of an axis dimension changed, move crosshairs
+ update_crosshair(p);
+ }
+}
+
+static void bracket_callback_1d(sushiv_dimension_list_t *dptr){
+ sushiv_dimension_t *d = dptr->d;
+ sushiv_panel_t *p = dptr->p;
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ int axisp = d == p1->x_d;
+
+ if(axisp)
+ _mark_recompute_1d(p);
+
+}
+
+static void dimchange_callback_1d(GtkWidget *button,gpointer in){
+ sushiv_panel_t *p = (sushiv_panel_t *)in;
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))){
+
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+
+ update_x_sel(p);
+ update_crosshair(p);
+ plot_unset_box(PLOT(p->private->graph));
+ _mark_recompute_1d(p);
+
+ _sushiv_undo_resume(p->sushi);
+ }
+}
+
+static void crosshair_callback(sushiv_panel_t *p){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ sushiv_panel_t *link = p1->link_x;
+ double x=PLOT(p->private->graph)->selx;
+ int i;
+
+ if(p1->flip)
+ x=PLOT(p->private->graph)->sely;
+ if(p1->link_y)
+ link=p1->link_y;
+
+ _sushiv_panel_dirty_legend(p);
+
+ if(p1->link_x){
+ // make it the master panel's problem.
+ plot_set_crosshairs_snap(PLOT(link->private->graph),
+ x,
+ PLOT(link->private->graph)->sely);
+ link->private->crosshair_action(link);
+ }else if (p1->link_y){
+ // make it the master panel's problem.
+ plot_set_crosshairs_snap(PLOT(link->private->graph),
+ PLOT(link->private->graph)->selx,
+ x);
+ link->private->crosshair_action(link);
+ }else{
+
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = p->dimension_list[i].d;
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ if(d == p1->x_d)
+ _sushiv_dimension_set_value(p->private->dim_scales[i],1,x);
+
+ p->private->oldbox_active = 0;
+ }
+ _sushiv_undo_resume(p->sushi);
+ }
+}
+
+static void box_callback(void *in, int state){
+ sushiv_panel_t *p = (sushiv_panel_t *)in;
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ Plot *plot = PLOT(p->private->graph);
+
+ switch(state){
+ case 0: // box set
+ _sushiv_undo_push(p->sushi);
+ plot_box_vals(plot,p1->oldbox);
+ p->private->oldbox_active = plot->box_active;
+ break;
+ case 1: // box activate
+ _sushiv_undo_push(p->sushi);
+ _sushiv_undo_suspend(p->sushi);
+
+ crosshair_callback(p);
+
+ _sushiv_dimension_set_value(p1->x_scale,0,p1->oldbox[0]);
+ _sushiv_dimension_set_value(p1->x_scale,2,p1->oldbox[1]);
+ p->private->oldbox_active = 0;
+ _sushiv_undo_resume(p->sushi);
+ break;
+ }
+ _sushiv_panel_update_menus(p);
+}
+
+void _maintain_cache_1d(sushiv_panel_t *p, _sushiv_bythread_cache_1d *c, int w){
+
+ /* toplevel initialization */
+ if(c->fout == 0){
+ int i,j;
+
+ /* determine which functions are actually needed */
+ c->call = calloc(p->sushi->functions,sizeof(*c->call));
+ c->fout = calloc(p->sushi->functions,sizeof(*c->fout));
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ for(j=0;j<o->outputs;j++)
+ c->call[o->function_map[j]]=
+ p->sushi->function_list[o->function_map[j]]->callback;
+ }
+ }
+
+ /* once to begin, as well as anytime the data width changes */
+ if(c->storage_width < w){
+ int i;
+ c->storage_width = w;
+
+ for(i=0;i<p->sushi->functions;i++){
+ if(c->call[i]){
+ if(c->fout[i])free(c->fout[i]);
+ c->fout[i] = malloc(w * p->sushi->function_list[i]->outputs *
+ sizeof(**c->fout));
+ }
+ }
+ }
+}
+
+// subtype entry point for plot remaps; lock held
+int _sushiv_panel1d_map_redraw(sushiv_panel_t *p, _sushiv_bythread_cache *c){
+ if(p->private->map_progress_count)return 0;
+ p->private->map_progress_count++;
+
+ // render to a temp surface so that we can release the lock occasionally
+ Plot *plot = PLOT(p->private->graph);
+ cairo_surface_t *back = plot->back;
+ cairo_surface_t *cs = cairo_surface_create_similar(back,CAIRO_CONTENT_COLOR,
+ cairo_image_surface_get_width(back),
+ cairo_image_surface_get_height(back));
+ cairo_t *ct = cairo_create(cs);
+
+ if(_sushiv_panel1d_remap(p,ct) == -1){ // returns -1 on abort
+ cairo_destroy(ct);
+ cairo_surface_destroy(cs);
+ }else{
+ // else complete
+ cairo_surface_destroy(plot->back);
+ plot->back = cs;
+ cairo_destroy(ct);
+
+ _sushiv_panel_clean_map(p);
+ plot_expose_request(plot);
+ }
+
+ return 1;
+}
+
+// subtype entry point for legend redraws; lock held
+int _sushiv_panel1d_legend_redraw(sushiv_panel_t *p){
+ Plot *plot = PLOT(p->private->graph);
+
+ if(p->private->legend_progress_count)return 0;
+ p->private->legend_progress_count++;
+ update_legend(p);
+ _sushiv_panel_clean_legend(p);
+
+ gdk_threads_leave();
+ plot_draw_scales(plot);
+ gdk_threads_enter();
+
+ plot_expose_request(plot);
+ return 1;
+}
+
+// subtype entry point for recomputation; lock held
+int _sushiv_panel1d_compute(sushiv_panel_t *p,
+ _sushiv_bythread_cache *c){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ Plot *plot;
+
+ int dw,w,h,i,d;
+ int serialno;
+ int x_d=-1;
+ scalespace sy;
+
+ scalespace sx;
+ scalespace sxv;
+ scalespace sxi;
+
+ dw = p1->data_size;
+ w = p1->panel_w;
+ h = p1->panel_h;
+
+ sy = p1->y;
+
+ sx = p1->x;
+ sxv = p1->x_v;
+ sxi = p1->x_i;
+
+ if(p->private->plot_progress_count)
+ return 0;
+
+ serialno = p->private->plot_serialno;
+ p->private->plot_progress_count++;
+ d = p->dimensions;
+ plot = PLOT(p->private->graph);
+
+ /* render using local dimension array; several threads will be
+ computing objectives */
+ double dim_vals[p->sushi->dimensions];
+
+ /* get iterator bounds, use iterator scale */
+ x_d = p1->x_d->number;
+
+ if(p1->flip){
+ plot->x = sy;
+ plot->y = sx;
+ plot->x_v = sy;
+ plot->y_v = sxv;
+ }else{
+ plot->x = sx;
+ plot->y = sy;
+ plot->x_v = sxv;
+ plot->y_v = sy;
+ }
+
+ // Initialize local dimension value array
+ for(i=0;i<p->sushi->dimensions;i++){
+ sushiv_dimension_t *dim = p->sushi->dimension_list[i];
+ dim_vals[i]=dim->val;
+ }
+
+ _maintain_cache_1d(p,&c->p1,dw);
+
+ /* unlock for computation */
+ gdk_threads_leave ();
+
+ plot_draw_scales(plot);
+ compute_1d(p, serialno, x_d, sxi, dw, dim_vals, &c->p1);
+
+ gdk_threads_enter ();
+
+ if(serialno == p->private->plot_serialno){
+ _sushiv_panel_dirty_map(p);
+ _sushiv_panel_dirty_legend(p);
+ _sushiv_panel_clean_plot(p);
+ }
+ return 1;
+}
+
+static void panel1d_undo_log(sushiv_panel_undo_t *u, sushiv_panel_t *p){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ int i;
+
+ // alloc fields as necessary
+ if(!u->mappings)
+ u->mappings = calloc(p->objectives,sizeof(*u->mappings));
+ if(!u->scale_vals[0])
+ u->scale_vals[0] = calloc(1,sizeof(**u->scale_vals));
+ if(!u->scale_vals[1])
+ u->scale_vals[1] = calloc(1,sizeof(**u->scale_vals));
+ if(!u->scale_vals[2])
+ u->scale_vals[2] = calloc(p->objectives,sizeof(**u->scale_vals));
+
+ // populate undo
+ u->scale_vals[0][0] = slider_get_value(p1->range_slider,0);
+ u->scale_vals[1][0] = slider_get_value(p1->range_slider,1);
+
+ for(i=0;i<p->objectives;i++){
+ u->mappings[i] =
+ (p1->mappings[i].mapnum<<24) |
+ (p1->linetype[i]<<16) |
+ (p1->pointtype[i]<<8);
+ u->scale_vals[2][i] = slider_get_value(p1->alpha_scale[i],0);
+ }
+
+ u->x_d = p1->x_dnum;
+ u->box[0] = p1->oldbox[0];
+ u->box[1] = p1->oldbox[1];
+
+ u->box_active = p->private->oldbox_active;
+
+}
+
+static void panel1d_undo_restore(sushiv_panel_undo_t *u, sushiv_panel_t *p){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ Plot *plot = PLOT(p->private->graph);
+
+ int i;
+
+ // go in through widgets
+
+ slider_set_value(p1->range_slider,0,u->scale_vals[0][0]);
+ slider_set_value(p1->range_slider,1,u->scale_vals[1][0]);
+
+ for(i=0;i<p->objectives;i++){
+ gtk_combo_box_set_active(GTK_COMBO_BOX(p1->map_pulldowns[i]), (u->mappings[i]>>24)&0xff );
+ gtk_combo_box_set_active(GTK_COMBO_BOX(p1->line_pulldowns[i]), (u->mappings[i]>>16)&0xff );
+ gtk_combo_box_set_active(GTK_COMBO_BOX(p1->point_pulldowns[i]), (u->mappings[i]>>8)&0xff );
+ slider_set_value(p1->alpha_scale[i],0,u->scale_vals[2][i]);
+ }
+
+ if(p1->dim_xb && u->x_d<p->dimensions && p1->dim_xb[u->x_d])
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p1->dim_xb[u->x_d]),TRUE);
+
+ update_x_sel(p);
+
+ if(u->box_active){
+ p1->oldbox[0] = u->box[0];
+ p1->oldbox[1] = u->box[1];
+ plot_box_set(plot,u->box);
+ p->private->oldbox_active = 1;
+ }else{
+ plot_unset_box(plot);
+ p->private->oldbox_active = 0;
+ }
+}
+
+void _sushiv_realize_panel1d(sushiv_panel_t *p){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ char buffer[160];
+ int i;
+ _sushiv_undo_suspend(p->sushi);
+
+ p->private->toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect_swapped (G_OBJECT (p->private->toplevel), "delete-event",
+ G_CALLBACK (_sushiv_clean_exit), (void *)SIGINT);
+
+ // add border to sides with hbox/padding
+ GtkWidget *borderbox = gtk_hbox_new(0,0);
+ gtk_container_add (GTK_CONTAINER (p->private->toplevel), borderbox);
+
+ // main layout vbox
+ p->private->topbox = gtk_vbox_new(0,0);
+ gtk_box_pack_start(GTK_BOX(borderbox), p->private->topbox, 1,1,4);
+ gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 1);
+
+ /* spinner, top bar */
+ {
+ GtkWidget *hbox = gtk_hbox_new(0,0);
+ gtk_box_pack_start(GTK_BOX(p->private->topbox), hbox, 0,0,0);
+ gtk_box_pack_end(GTK_BOX(hbox),GTK_WIDGET(p->private->spinner),0,0,0);
+ }
+
+ /* plotbox, graph */
+ {
+ unsigned flags = 0;
+ if(p1->flip)
+ flags |= PLOT_NO_X_CROSS;
+ else
+ flags |= PLOT_NO_Y_CROSS;
+
+ p1->graph_table = gtk_table_new(2,2,0);
+ p->private->plotbox = p1->graph_table;
+ gtk_box_pack_start(GTK_BOX(p->private->topbox), p->private->plotbox, 1,1,2);
+
+ p->private->graph = GTK_WIDGET(plot_new(recompute_callback_1d,p,
+ (void *)(void *)crosshair_callback,p,
+ box_callback,p,flags));
+ if(p1->flip){
+ gtk_table_attach(GTK_TABLE(p1->graph_table),p->private->graph,0,2,0,1,
+ GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,1);
+ }else{
+ gtk_table_attach(GTK_TABLE(p1->graph_table),p->private->graph,1,2,0,2,
+ GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,1);
+ }
+ }
+
+ /* range slider, goes in the plotbox table */
+ /* may be vertical to the left of the plot or along the bottom if the plot is flipped */
+ {
+ GtkWidget **sl = calloc(2,sizeof(*sl));
+ int lo = p1->range_scale->val_list[0];
+ int hi = p1->range_scale->val_list[p1->range_scale->vals-1];
+
+ /* the range slices/slider */
+ sl[0] = slice_new(map_callback_1d,p);
+ sl[1] = slice_new(map_callback_1d,p);
+
+ if(p1->flip){
+ gtk_table_attach(GTK_TABLE(p1->graph_table),sl[0],0,1,1,2,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+ gtk_table_attach(GTK_TABLE(p1->graph_table),sl[1],1,2,1,2,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+ }else{
+ gtk_table_attach(GTK_TABLE(p1->graph_table),sl[0],0,1,1,2,
+ GTK_SHRINK,GTK_EXPAND|GTK_FILL,0,0);
+ gtk_table_attach(GTK_TABLE(p1->graph_table),sl[1],0,1,0,1,
+ GTK_SHRINK,GTK_EXPAND|GTK_FILL,0,0);
+ gtk_table_set_col_spacing(GTK_TABLE(p1->graph_table),0,4);
+ }
+
+ p1->range_slider = slider_new((Slice **)sl,2,
+ p1->range_scale->label_list,
+ p1->range_scale->val_list,
+ p1->range_scale->vals,
+ (p1->flip?0:SLIDER_FLAG_VERTICAL));
+
+ slice_thumb_set((Slice *)sl[0],lo);
+ slice_thumb_set((Slice *)sl[1],hi);
+ }
+
+ /* obj box */
+ {
+ p1->obj_table = gtk_table_new(p->objectives,5,0);
+ gtk_box_pack_start(GTK_BOX(p->private->topbox), p1->obj_table, 0,0,1);
+
+ /* pulldowns */
+ p1->pointtype = calloc(p->objectives,sizeof(*p1->pointtype));
+ p1->linetype = calloc(p->objectives,sizeof(*p1->linetype));
+ p1->mappings = calloc(p->objectives,sizeof(*p1->mappings));
+ p1->map_pulldowns = calloc(p->objectives,sizeof(*p1->map_pulldowns));
+ p1->line_pulldowns = calloc(p->objectives,sizeof(*p1->line_pulldowns));
+ p1->point_pulldowns = calloc(p->objectives,sizeof(*p1->point_pulldowns));
+ p1->alpha_scale = calloc(p->objectives,sizeof(*p1->alpha_scale));
+
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+
+ /* label */
+ GtkWidget *label = gtk_label_new(o->name);
+ gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
+ gtk_table_attach(GTK_TABLE(p1->obj_table),label,0,1,i,i+1,
+ GTK_FILL,0,5,0);
+
+ /* mapping pulldown */
+ {
+ GtkWidget *menu=gtk_combo_box_new_markup();
+ int j;
+ for(j=0;j<num_solids();j++){
+ if(strcmp(solid_name(j),"inactive"))
+ snprintf(buffer,sizeof(buffer),"<span foreground=\"%s\">%s</span>",solid_name(j),solid_name(j));
+ else
+ snprintf(buffer,sizeof(buffer),"%s",solid_name(j));
+
+ gtk_combo_box_append_text (GTK_COMBO_BOX (menu), buffer);
+ }
+ gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
+ g_signal_connect (G_OBJECT (menu), "changed",
+ G_CALLBACK (mapchange_callback_1d), p->objective_list+i);
+ gtk_table_attach(GTK_TABLE(p1->obj_table),menu,1,2,i,i+1,
+ GTK_SHRINK,GTK_SHRINK,5,0);
+ p1->map_pulldowns[i] = menu;
+ solid_setup(&p1->mappings[i],0.,1.,0);
+ }
+
+ /* line pulldown */
+ {
+ GtkWidget *menu=gtk_combo_box_new_text();
+ int j;
+ for(j=0;j<LINETYPES;j++)
+ gtk_combo_box_append_text (GTK_COMBO_BOX (menu), line_name[j]->left);
+ gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
+ g_signal_connect (G_OBJECT (menu), "changed",
+ G_CALLBACK (linetype_callback_1d), p->objective_list+i);
+ gtk_table_attach(GTK_TABLE(p1->obj_table),menu,2,3,i,i+1,
+ GTK_SHRINK,GTK_SHRINK,5,0);
+ p1->line_pulldowns[i] = menu;
+ }
+
+ /* point pulldown */
+ {
+ GtkWidget *menu=gtk_combo_box_new_text();
+ int j;
+ for(j=0;j<POINTTYPES;j++)
+ gtk_combo_box_append_text (GTK_COMBO_BOX (menu), point_name[j]->left);
+ gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
+ g_signal_connect (G_OBJECT (menu), "changed",
+ G_CALLBACK (pointtype_callback_1d), p->objective_list+i);
+ gtk_table_attach(GTK_TABLE(p1->obj_table),menu,3,4,i,i+1,
+ GTK_SHRINK,GTK_SHRINK,5,0);
+ p1->point_pulldowns[i] = menu;
+ }
+
+ /* alpha slider */
+ {
+ GtkWidget **sl = calloc(1, sizeof(*sl));
+ sl[0] = slice_new(alpha_callback_1d,p->objective_list+i);
+
+ gtk_table_attach(GTK_TABLE(p1->obj_table),sl[0],4,5,i,i+1,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+
+ p1->alpha_scale[i] = slider_new((Slice **)sl,1,
+ (char *[]){"transparent","solid"},
+ (double []){0.,1.},
+ 2,0);
+
+ slider_set_gradient(p1->alpha_scale[i], &p1->mappings[i]);
+ slice_thumb_set((Slice *)sl[0],1.);
+
+ }
+ }
+ }
+
+ /* dim box */
+ if(p->dimensions){
+ p1->dim_table = gtk_table_new(p->dimensions,3,0);
+ gtk_box_pack_start(GTK_BOX(p->private->topbox), p1->dim_table, 0,0,4);
+
+ p->private->dim_scales = calloc(p->dimensions,sizeof(*p->private->dim_scales));
+ p1->dim_xb = calloc(p->dimensions,sizeof(*p1->dim_xb));
+ GtkWidget *first_x = NULL;
+
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = p->dimension_list[i].d;
+
+ /* label */
+ GtkWidget *label = gtk_label_new(d->name);
+ gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
+ gtk_table_attach(GTK_TABLE(p1->dim_table),label,0,1,i,i+1,
+ GTK_FILL,0,5,0);
+
+ /* x radio buttons */
+ if(!(d->flags & SUSHIV_DIM_NO_X) && !p1->link_x && !p1->link_y){
+ if(first_x)
+ p1->dim_xb[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_x),"X");
+ else{
+ first_x = p1->dim_xb[i] = gtk_radio_button_new_with_label(NULL,"X");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p1->dim_xb[i]),TRUE);
+ }
+ gtk_table_attach(GTK_TABLE(p1->dim_table),p1->dim_xb[i],1,2,i,i+1,
+ 0,0,3,0);
+ }
+
+ p->private->dim_scales[i] =
+ _sushiv_new_dimension_widget(p->dimension_list+i,center_callback_1d,bracket_callback_1d);
+
+ gtk_table_attach(GTK_TABLE(p1->dim_table),
+ GTK_WIDGET(p->private->dim_scales[i]->t),
+ 2,3,i,i+1,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+
+ }
+
+ for(i=0;i<p->dimensions;i++)
+ if(p1->dim_xb[i])
+ g_signal_connect (G_OBJECT (p1->dim_xb[i]), "toggled",
+ G_CALLBACK (dimchange_callback_1d), p);
+
+ update_x_sel(p);
+ }
+
+ gtk_widget_realize(p->private->toplevel);
+ gtk_widget_realize(p->private->graph);
+ gtk_widget_realize(GTK_WIDGET(p->private->spinner));
+ gtk_widget_show_all(p->private->toplevel);
+
+ _sushiv_undo_resume(p->sushi);
+}
+
+
+static int _save_panel1d(sushiv_panel_t *p, xmlNodePtr pn){
+ sushiv_panel1d_t *p1 = p->subtype->p1;
+ int ret=0,i;
+
+ xmlNodePtr n;
+
+ xmlNewProp(pn, (xmlChar *)"type", (xmlChar *)"1d");
+
+ // box
+ if(p->private->oldbox_active){
+ xmlNodePtr boxn = xmlNewChild(pn, NULL, (xmlChar *) "box", NULL);
+ xmlNewPropF(boxn, "x1", p1->oldbox[0]);
+ xmlNewPropF(boxn, "x2", p1->oldbox[1]);
+ }
+
+ // objective map settings
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+
+ xmlNodePtr on = xmlNewChild(pn, NULL, (xmlChar *) "objective", NULL);
+ xmlNewPropI(on, "position", i);
+ xmlNewPropI(on, "number", o->number);
+ xmlNewPropS(on, "name", o->name);
+ xmlNewPropS(on, "type", o->output_types);
+
+ // right now Y is the only type; the below is Y-specific
+
+ n = xmlNewChild(on, NULL, (xmlChar *) "y-map", NULL);
+ xmlNewMapProp(n, "color", solid_map(), p1->mappings[i].mapnum);
+ xmlNewMapProp(n, "line", line_name, p1->linetype[i]);
+ xmlNewMapProp(n, "point", point_name, p1->pointtype[i]);
+ xmlNewPropF(n, "alpha", slider_get_value(p1->alpha_scale[i],0));
+ }
+
+ // y scale
+ n = xmlNewChild(pn, NULL, (xmlChar *) "range", NULL);
+ xmlNewPropF(n, "low-bracket", slider_get_value(p1->range_slider,0));
+ xmlNewPropF(n, "high-bracket", slider_get_value(p1->range_slider,1));
+
+ // x/y dim selection
+ n = xmlNewChild(pn, NULL, (xmlChar *) "axes", NULL);
+ xmlNewPropI(n, "xpos", p1->x_dnum);
+
+ return ret;
+}
+
+int _load_panel1d(sushiv_panel_t *p,
+ sushiv_panel_undo_t *u,
+ xmlNodePtr pn,
+ int warn){
+ int i;
+
+ // check type
+ xmlCheckPropS(pn,"type","1d", "Panel %d type mismatch in save file.",p->number,&warn);
+
+ // box
+ u->box_active = 0;
+ xmlGetChildPropFPreserve(pn, "box", "x1", &u->box[0]);
+ xmlGetChildPropFPreserve(pn, "box", "x2", &u->box[1]);
+
+ xmlNodePtr n = xmlGetChildS(pn, "box", NULL, NULL);
+ if(n){
+ u->box_active = 1;
+ xmlFree(n);
+ }
+
+ // objective map settings
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ xmlNodePtr on = xmlGetChildI(pn, "objective", "position", i);
+ if(!on){
+ first_load_warning(&warn);
+ fprintf(stderr,"No save data found for panel %d objective \"%s\".\n",p->number, o->name);
+ }else{
+ // check name, type
+ xmlCheckPropS(on,"name",o->name, "Objectve position %d name mismatch in save file.",i,&warn);
+ xmlCheckPropS(on,"type",o->output_types, "Objectve position %d type mismatch in save file.",i,&warn);
+
+ // right now Y is the only type; the below is Y-specific
+ // load maptype, values
+ int color = (u->mappings[i]>>24)&0xff;
+ int line = (u->mappings[i]>>16)&0xff;
+ int point = (u->mappings[i]>>8)&0xff;
+
+ xmlGetChildMapPreserve(on, "y-map", "color", solid_map(), &color,
+ "Panel %d objective unknown mapping setting", p->number, &warn);
+ xmlGetChildMapPreserve(on, "y-map", "line", line_name, &line,
+ "Panel %d objective unknown mapping setting", p->number, &warn);
+ xmlGetChildMapPreserve(on, "y-map", "point", point_name, &point,
+ "Panel %d objective unknown mapping setting", p->number, &warn);
+ xmlGetChildPropF(on, "y-map", "alpha", &u->scale_vals[2][i]);
+
+ u->mappings[i] = (color<<24) | (line<<16) | (point<<8);
+
+ xmlFreeNode(on);
+ }
+ }
+
+ // y scale
+ xmlGetChildPropFPreserve(pn, "range", "low-bracket", &u->scale_vals[0][0]);
+ xmlGetChildPropF(pn, "range", "high-bracket", &u->scale_vals[1][0]);
+
+ // x/y dim selection
+ xmlGetChildPropI(pn, "axes", "xpos", &u->x_d);
+
+ return warn;
+}
+
+int sushiv_new_panel_1d(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ sushiv_scale_t *scale,
+ int *objectives,
+ int *dimensions,
+ unsigned flags){
+
+ int ret = _sushiv_new_panel(s,number,name,objectives,dimensions,flags);
+ sushiv_panel_t *p;
+ sushiv_panel1d_t *p1;
+
+ if(ret<0)return ret;
+ p = s->panel_list[number];
+ p1 = calloc(1, sizeof(*p1));
+ p->subtype = calloc(1, sizeof(*p->subtype));
+
+ p->subtype->p1 = p1;
+ p->type = SUSHIV_PANEL_1D;
+ p1->range_scale = scale;
+ p->private->bg_type = SUSHIV_BG_WHITE;
+
+ if(p->flags && SUSHIV_PANEL_FLIP)
+ p1->flip=1;
+
+ p->private->realize = _sushiv_realize_panel1d;
+ p->private->map_action = _sushiv_panel1d_map_redraw;
+ p->private->legend_action = _sushiv_panel1d_legend_redraw;
+ p->private->compute_action = _sushiv_panel1d_compute;
+ p->private->request_compute = _mark_recompute_1d;
+ p->private->crosshair_action = crosshair_callback;
+ p->private->print_action = sushiv_panel1d_print;
+ p->private->save_action = _save_panel1d;
+ p->private->load_action = _load_panel1d;
+
+ p->private->undo_log = panel1d_undo_log;
+ p->private->undo_restore = panel1d_undo_restore;
+ p->private->def_oversample_n = p->private->oversample_n = 1;
+ p->private->def_oversample_d = p->private->oversample_d = 8;
+
+ return 0;
+}
+
+int sushiv_new_panel_1d_linked(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ sushiv_scale_t *scale,
+ int *objectives,
+ int link,
+ unsigned flags){
+
+ if(link < 0 ||
+ link >= s->panels ||
+ s->panel_list[link]==NULL ||
+ s->panel_list[link]->type != SUSHIV_PANEL_2D){
+ fprintf(stderr,"1d linked panel must be linked to preexisting 2d panel.\n");
+ return -EINVAL;
+ }
+
+ int ret = sushiv_new_panel_1d(s,number,name,scale,objectives,(int []){-1},flags);
+
+ sushiv_panel_t *p;
+ sushiv_panel1d_t *p1;
+ sushiv_panel_t *p2 = s->panel_list[link];
+
+ if(ret<0)return ret;
+ p = s->panel_list[number];
+ p1 = p->subtype->p1;
+
+ if(flags && SUSHIV_PANEL_LINK_Y)
+ p1->link_y = p2;
+ else
+ p1->link_x = p2;
+
+ return 0;
+}
Added: trunk/sushivision/panel-xy.h
===================================================================
--- trunk/sushivision/panel-xy.h 2007-03-13 20:29:15 UTC (rev 12752)
+++ trunk/sushivision/panel-xy.h 2007-03-14 02:13:57 UTC (rev 12753)
@@ -0,0 +1,80 @@
+/*
+ *
+ * sushivision copyright (C) 2006-2007 Monty <monty at xiph.org>
+ *
+ * sushivision is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * sushivision is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with sushivision; see the file COPYING. If not, write to the
+ * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+tyedef xy_data_t struct xy_data;
+
+struct xy_data{
+ xy_data_t *p;
+ xy_data_t *n;
+
+ double dimx;
+ double xval;
+ double yval;
+};
+
+typedef struct sushiv_panelxy {
+ GtkWidget *graph_table;
+ GtkWidget *obj_table;
+ GtkWidget *dim_table;
+
+ int panel_w;
+ int panel_h;
+
+ xy_data_t **data_head;
+ int *data_length;
+
+ // panel x/y don't correspond to dimensions like on other panels
+ scalespace x;
+ scalespace y;
+ double oldbox[4];
+ sushiv_scale_t x_scale;
+ sushiv_scale_t y_scale;
+ Slider x_slider;
+ Slider y_slider;
+ double x_bracket[2];
+ double y_bracket[2];
+ double x_val;
+ double y_val;
+
+
+ scalespace data_v; // the x scale aligned to data vector's bins
+ scalespace data_i; // the 'counting' scale used to iterate for compute
+
+ mapping *mappings;
+ int *linetype;
+ int *pointtype;
+ GtkWidget **map_pulldowns;
+ GtkWidget **line_pulldowns;
+ GtkWidget **point_pulldowns;
+ Slider **alpha_scale;
+
+ GtkWidget **dim_xb;
+
+ sushiv_dimension_t *x_d;
+ sushiv_dim_widget_t *x_widget;
+ int x_dnum; // number of dimension within panel, not global instance
+} sushiv_panelxy_t;
+
+typedef struct {
+ void (**call)(double *, double *);
+ double **fout; // [function number][outval_number]
+
+} _sushiv_bythread_cache_xy;
+
More information about the commits
mailing list