[xiph-commits] r12248 - trunk/sushivision

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Wed Dec 27 22:06:30 PST 2006


Author: xiphmont
Date: 2006-12-27 22:06:26 -0800 (Wed, 27 Dec 2006)
New Revision: 12248

Added:
   trunk/sushivision/panel-1d.c
   trunk/sushivision/panel-1d.h
Modified:
   trunk/sushivision/Makefile
   trunk/sushivision/dimension.c
   trunk/sushivision/internal.h
   trunk/sushivision/mapping.c
   trunk/sushivision/objective.c
   trunk/sushivision/panel-2d.c
   trunk/sushivision/plot.c
   trunk/sushivision/plot.h
   trunk/sushivision/scale.c
   trunk/sushivision/sushivision.h
Log:
Add first cut of 1d panel implementation.  Builds but certainly does
not run.  Currently only has constructor for linked panels.



Modified: trunk/sushivision/Makefile
===================================================================
--- trunk/sushivision/Makefile	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/Makefile	2006-12-28 06:06:26 UTC (rev 12248)
@@ -14,10 +14,10 @@
 SOCFLAGS  = -fPIC
 SOLDFLAGS = -shared -nostdlib
 
-SRC  = main.c scale.c plot.c slider.c slice.c panel.c panel-2d.c mapping.c dimension.c objective.c undo.c gtksucks.c example_submain.c example_fractal.c
-OBJ  = main.o scale.o plot.o slider.o slice.o panel.o panel-2d.o mapping.o dimension.o objective.o undo.o gtksucks.o
-OBJ_EX1  = main.o scale.o plot.o slider.o slice.o panel.o panel-2d.o mapping.o dimension.o objective.o undo.o gtksucks.o example_submain.o
-OBJ_EX2  = main.o scale.o plot.o slider.o slice.o panel.o panel-2d.o mapping.o dimension.o objective.o undo.o gtksucks.o example_fractal.o
+SRC  = main.c scale.c plot.c slider.c slice.c panel.c panel-1d.c panel-2d.c mapping.c dimension.c objective.c undo.c gtksucks.c example_submain.c example_fractal.c
+OBJ  = main.o scale.o plot.o slider.o slice.o panel.o panel-1d.o panel-2d.o mapping.o dimension.o objective.o undo.o gtksucks.o
+OBJ_EX1  = main.o scale.o plot.o slider.o slice.o panel.o panel-1d.o panel-2d.o mapping.o dimension.o objective.o undo.o gtksucks.o example_submain.o
+OBJ_EX2  = main.o scale.o plot.o slider.o slice.o panel.o panel-1d.o panel-2d.o mapping.o dimension.o objective.o undo.o gtksucks.o example_fractal.o
 INC  = sushivision.h
 LIBS = -lpthread -ldl
 CAIROVER =  >= 1.0.0

Modified: trunk/sushivision/dimension.c
===================================================================
--- trunk/sushivision/dimension.c	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/dimension.c	2006-12-28 06:06:26 UTC (rev 12248)
@@ -60,6 +60,6 @@
   d->flags = flags;
   d->sushi = s;
   d->callback = callback;
-  d->scale = scale_new(scalevals, scaleval_list);
+  d->scale = scale_new(scalevals, scaleval_list, name);
   return 0;
 }

Modified: trunk/sushivision/internal.h
===================================================================
--- trunk/sushivision/internal.h	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/internal.h	2006-12-28 06:06:26 UTC (rev 12248)
@@ -26,12 +26,13 @@
 #include "slice.h"
 #include "slider.h"
 #include "scale.h"
+#include "panel-1d.h"
 #include "panel-2d.h"
 #include "gtksucks.h"
 #include "plot.h"
 
 union sushiv_panel_subtype {
-  //sushiv_panel1d_t *p1;
+  sushiv_panel1d_t *p1;
   sushiv_panel2d_t *p2;
 };
 
@@ -108,5 +109,7 @@
 extern void _sushiv_panel_update_shared_dimension(sushiv_dimension_t *d,
 						  double val);
 
+extern void _sushiv_panel1d_mark_recompute_linked(sushiv_panel_t *p); 
+extern void _sushiv_panel1d_update_linked_crosshairs(sushiv_panel_t *p); 
 
 extern sig_atomic_t _sushiv_exiting;

Modified: trunk/sushivision/mapping.c
===================================================================
--- trunk/sushivision/mapping.c	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/mapping.c	2006-12-28 06:06:26 UTC (rev 12248)
@@ -362,14 +362,14 @@
 };
 
 static char *solidnames[]={
-  "white",
-  "red",
-  "green",
-  "blue",
-  "yellow",
-  "cyan",
-  "purple",
-  "gray",
+  "<span foreground=\"white\">white</span>",
+  "<span foreground=\"red\">white</span>",
+  "<span foreground=\"green\">white</span>",
+  "<span foreground=\"blue\">white</span>",
+  "<span foreground=\"yellow\">white</span>",
+  "<span foreground=\"cyan\">white</span>",
+  "<span foreground=\"purple\">white</span>",
+  "<span foreground=\"gray\">white</span>",
   "inactive",
   0
 };

Modified: trunk/sushivision/objective.c
===================================================================
--- trunk/sushivision/objective.c	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/objective.c	2006-12-28 06:06:26 UTC (rev 12248)
@@ -62,7 +62,7 @@
   o->callback = callback;
 
   if(scalevals>0 && scaleval_list)
-    o->scale=scale_new(scalevals, scaleval_list);
+    o->scale=scale_new(scalevals, scaleval_list, name);
 
   return 0;
 }

Added: trunk/sushivision/panel-1d.c
===================================================================
--- trunk/sushivision/panel-1d.c	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/panel-1d.c	2006-12-28 06:06:26 UTC (rev 12248)
@@ -0,0 +1,1347 @@
+/*
+ *
+ *     sushivision copyright (C) 2006 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 <gdk/gdkkeysyms.h>
+#include "internal.h"
+
+#define LINETYPES 10
+static char *line_name[LINETYPES+1] = {
+  "line",
+  "dot",
+  "circle",
+  "square",
+  "cross",
+  "triangle",
+  "line and circle",
+  "line and square",
+  "line and cross",
+  "line and triangle",
+  NULL
+};
+
+static void update_context_menus(sushiv_panel_t *p);
+
+// called internally, assumes we hold lock
+// redraws the data, does not compute the data
+static void _sushiv_panel1d_remap(sushiv_panel_t *p){
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  Plot *plot = PLOT(p->private->graph);
+  cairo_surface_t *cs = plot->back;
+  cairo_t *c = cairo_create(cs);
+
+  cairo_set_line_width(c,1.);
+
+  if(plot){
+    int xi,i;
+    int dw = p1->data_size;
+    double r = (p1->flip?p1->panel_w:p1->panel_h);
+    double alpha = p1->alphaval;
+    double neg = p1->y.neg;
+
+    scalespace sx = (p1->flip?p1->y:p1->x);
+    scalespace sy = (p1->flip?p1->x:p1->y);
+    
+    /* blank frame to black */
+    cairo_set_source_rgb (c, 0,0,0);
+    cairo_paint(c);
+
+    /* do the panel and plot scales match?  If not, redraw the plot
+       scales */
+    if(memcmp(&sx,&plot->x,sizeof(sx)) |
+       memcmp(&sy,&plot->y,sizeof(sy))){
+      plot->x = sx;
+      plot->y = sy;
+
+      plot_draw_scales(plot);
+    }
+
+    /* by objective */
+    for(i=0;i<p->objectives;i++){
+      double *data_vec = p1->data_vec[i];
+      double yprev=NAN,xprev=NAN;
+      
+      u_int32_t color = mapping_calc(p1->mappings+i,0,0);
+      cairo_set_source_rgb(c,
+			   ((color>>16)&0xff)/255.,
+			   ((color>>8)&0xff)/255.,
+			   ((color)&0xff)/255.);
+      
+      /* by x */
+      for(xi=0;xi<dw;xi++){
+	double val = data_vec[xi];
+	double xpixel = xi;
+	double ypixel = NAN;
+	
+	/* in linked panels, the data vector doesn't match the graph width; map */
+	if(p1->link_x || p1->link_y)
+	  xpixel = scalespace_pixel(&p1->x,scalespace_value(&p1->vs,xpixel))+.5;
+
+	/* map/render result */
+	if(!isnan(val) && val*neg > alpha*neg)
+	  ypixel = scalespace_pixel(&p1->y,val)+.5;
+	
+	if(!isnan(ypixel) && !isnan(yprev)){
+	  if(p1->flip){
+	    cairo_move_to(c,yprev,r-xprev);
+	    cairo_line_to(c,ypixel,r-xpixel);
+	  }else{
+	    cairo_move_to(c,xprev,r-yprev);
+	    cairo_line_to(c,xpixel,r-ypixel);
+	  }
+	}
+
+	yprev=ypixel;
+	xprev=xpixel;
+      }
+    }
+  }
+}
+
+void _sushiv_panel1d_map_redraw(sushiv_panel_t *p){
+  Plot *plot = PLOT(p->private->graph);
+
+  gdk_threads_enter (); // misuse me as a global mutex
+  
+  _sushiv_panel1d_remap(p);
+  if(plot)
+    plot_expose_request(plot);
+ 
+  gdk_threads_leave (); // misuse me as a global mutex
+}
+
+void _sushiv_panel1d_legend_redraw(sushiv_panel_t *p){
+  Plot *plot = PLOT(p->private->graph);
+
+  if(plot)
+    plot_draw_scales(plot);
+}
+
+static int ilog10(int x){
+  int count=0;
+  if(x<0)x=-x;
+  while(x){
+    count++;
+    x/=10;
+  }
+  return count;
+}
+
+static void update_legend(sushiv_panel_t *p){  
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  Plot *plot = PLOT(p->private->graph);
+
+  gdk_threads_enter ();
+  int w = p1->panel_w;
+  int h = p1->panel_h;
+  int offset = ilog10(w>h?w:h);
+
+  if(plot){
+    int i;
+    char buffer[320];
+    plot_legend_clear(plot);
+
+    // add each dimension to the legend
+    for(i=0;i<p->dimensions;i++){
+      // display decimal precision relative to bracket
+      int depth = del_depth(p->dimension_list[i].d->bracket[0],
+			    p->dimension_list[i].d->bracket[1]) + offset;
+      snprintf(buffer,320,"%s = %.*f",
+	       p->dimension_list[i].d->name,
+	       depth,
+	       p->dimension_list[i].d->val);
+      plot_legend_add(plot,buffer);
+    }
+
+    // linked? add the linked dimension value to the legend
+    if(p1->link_x || p1->link_y){
+      sushiv_dimension_t *d;
+      int depth;
+      if(p1->link_x)
+	d = p1->link_x->subtype->p2->x_d;
+      else
+	d = p1->link_y->subtype->p2->y_d;
+
+      // display decimal precision relative to bracket
+      depth = del_depth(d->bracket[0],
+			d->bracket[1]) + offset;
+      snprintf(buffer,320,"%s = %.*f",
+	       d->name,
+	       depth,
+	       d->val);
+      plot_legend_add(plot,buffer);
+    }
+
+    // one space 
+    plot_legend_add(plot,NULL);
+
+    // add each active objective to the legend
+    // choose the value under the crosshairs 
+    {
+      double val = (p1->flip?plot->sely:plot->selx);
+      int bin = scalespace_pixel(&p1->vs, val);
+
+      if(bin>=0 && bin<p1->data_size){
+	
+	for(i=0;i<p->objectives;i++){
+	  float val = p1->data_vec[i][bin];
+
+	  if(!isnan(val)){
+	    snprintf(buffer,320,"%s = %f",
+		     p->objective_list[i].o->name,
+		     val);
+	    plot_legend_add(plot,buffer);
+	  }
+	}
+      }
+    }
+    gdk_threads_leave ();
+    
+    _sushiv_panel_dirty_legend(p);
+    
+  }
+}
+
+static void mapchange_callback_1d(GtkWidget *w,gpointer in){
+  sushiv_objective_list_t *optr = (sushiv_objective_list_t *)in;
+  sushiv_panel_t *p = optr->p;
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  int onum = optr - p->objective_list;
+  
+  _sushiv_panel_undo_push(p);
+  _sushiv_panel_undo_suspend(p);
+
+  // update colormap
+  // oh, the wasteful
+  solid_set_func(&p1->mappings[onum],
+		 gtk_combo_box_get_active(GTK_COMBO_BOX(w)));
+
+  update_legend(p);
+  _sushiv_panel_dirty_map(p);
+  _sushiv_panel_undo_resume(p);
+}
+
+static void linetype_callback_1d(GtkWidget *w,gpointer in){
+  sushiv_objective_list_t *optr = (sushiv_objective_list_t *)in;
+  sushiv_panel_t *p = optr->p;
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  int onum = optr - p->objective_list;
+  
+  _sushiv_panel_undo_push(p);
+  _sushiv_panel_undo_suspend(p);
+
+  // update colormap
+  p1->linetype[onum]=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
+
+  //update_legend(p);
+  _sushiv_panel_dirty_map(p);
+  _sushiv_panel_undo_resume(p);
+}
+
+static void map_callback_1d(void *in,int buttonstate){
+  sushiv_panel_t *p = (sushiv_panel_t *)in;
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  Plot *plot = PLOT(p->private->graph);
+  
+  if(buttonstate == 0){
+    _sushiv_panel_undo_push(p);
+    _sushiv_panel_undo_suspend(p);
+  }
+
+  // recache alpha vals 
+  p1->alphaval = slider_get_value(p1->range_slider,1);
+
+  // has new bracketing changed the plot range scale?
+  if(p1->range_bracket[0] != slider_get_value(p1->range_slider,0) ||
+     p1->range_bracket[1] != slider_get_value(p1->range_slider,2)){
+
+    int w = plot->w.allocation.width;
+    int h = plot->w.allocation.height;
+
+    p1->range_bracket[0] = slider_get_value(p1->range_slider,0);
+    p1->range_bracket[1] = slider_get_value(p1->range_slider,2);
+    
+    p1->y = scalespace_linear(p1->range_bracket[0],
+			      p1->range_bracket[1],
+			      (p1->flip?h:w),
+			      PLOT(p->private->graph)->scalespacing,
+			      p1->range_scale->legend);
+  }
+
+  //redraw the plot
+  _sushiv_panel_dirty_map(p);
+  if(buttonstate == 2)
+    _sushiv_panel_undo_resume(p);
+}
+
+static void update_x_sel(sushiv_panel_t *p){
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  int i;
+
+  // enable/disable dimension slider thumbs
+  
+  for(i=0;i<p->dimensions;i++){
+    
+    if(p1->dim_xb[i] &&
+       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p1->dim_xb[i]))){
+
+      // set the x dim flag
+      p1->x_d = p->dimension_list[i].d;
+      p1->x_scale = p->private->dim_scales[i];
+      p1->x_dnum = i;
+
+      // set panel x scale to this dim
+      p1->x = p1->vs = scalespace_linear(p1->x_d->bracket[0],
+					 p1->x_d->bracket[1],
+					 p1->data_size,
+					 PLOT(p->private->graph)->scalespacing,
+					 p1->x_d->name);
+
+    }
+    if(p1->dim_xb[i] &&
+       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p1->dim_xb[i]))){
+      // make all thumbs visible 
+      slider_set_thumb_active(p->private->dim_scales[i],0,1);
+      slider_set_thumb_active(p->private->dim_scales[i],2,1);
+    }else{
+      // make bracket thumbs invisible */
+      slider_set_thumb_active(p->private->dim_scales[i],0,0);
+      slider_set_thumb_active(p->private->dim_scales[i],2,0);
+    }
+  } 
+}
+
+static void compute_1d(sushiv_panel_t *p, 
+		       int serialno,
+		       int x_d, 
+		       double x_min, 
+		       double x_max, 
+		       int w, 
+		       double *dim_vals){
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  double work[w];
+  double inv_w = 1./w;
+  int i,j;
+
+  /* by objective */
+  for(i=0;i<p->objectives;i++){
+    sushiv_objective_t *o = p->objective_list[i].o;
+    
+    /* by x */
+    for(j=0;j<w;j++){
+      
+      /* compute value for this objective for this pixel */
+      dim_vals[x_d] = (x_max-x_min) * inv_w * j + x_min;
+      work[j] = o->callback(dim_vals);
+      
+    }
+    
+    gdk_threads_enter (); // misuse me as a global mutex
+    if(p1->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){
+  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);
+
+  if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
+
+    if(p1->link_x){
+      dw = p2->data_w;
+      p1->x_d = p2->x_d;
+    }
+    if(p1->link_y){
+      dw = p2->data_h;
+      p1->x_d = p2->y_d;
+    }
+
+    p1->x = scalespace_linear(p1->x_d->bracket[0],
+			      p1->x_d->bracket[1],
+			      (p1->flip?h:w),
+			      PLOT(p->private->graph)->scalespacing,
+			      p1->x_d->name);
+    p1->y = scalespace_linear(p1->range_bracket[0],
+			      p1->range_bracket[1],
+			      (p1->flip?h:w),
+			      PLOT(p->private->graph)->scalespacing,
+			      p1->range_scale->legend);
+    
+    // 2d panels do not necessarily update their scales until
+    // recompute time, and 1d panels may be recomputed first,
+    // thus duplicate the scale computaiton here
+    p1->vs = scalespace_linear(p1->x_d->bracket[0],
+			       p1->x_d->bracket[1],
+			       dw,
+			       PLOT(p->private->graph)->scalespacing,
+			       p1->x_d->name);
+
+
+    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;
+    p1->serialno++;
+    
+    if(!p1->data_vec){
+      int i,j;
+      // 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_wake_workers();
+  }
+}
+
+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(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 = slider_get_value(link->private->dim_scales[i],1);
+    }
+  }else{
+    for(i=0;i<p->dimensions;i++){
+      sushiv_dimension_t *d = p->dimension_list[i].d;
+      if(d == p1->x_d)
+	x = slider_get_value(p->private->dim_scales[i],1);
+    }
+  }
+  
+  if(p1->flip)
+    plot_set_crosshairs(PLOT(p->private->graph),0,x);
+  else
+    plot_set_crosshairs(PLOT(p->private->graph),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));
+    }
+  }
+  update_legend(p);
+}
+
+void _sushiv_panel1d_update_linked_crosshairs(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)
+	update_crosshair(q);
+      else{
+	if(q1->link_y == p)
+	  update_crosshair(q);
+      }
+    }
+  }
+}
+
+static void dim_callback_1d(void *in, int buttonstate){
+  sushiv_dimension_list_t *dptr = (sushiv_dimension_list_t *)in;
+  sushiv_dimension_t *d = dptr->d;
+  sushiv_panel_t *p = dptr->p;
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  //Plot *plot = PLOT(p->private->graph);
+  int dnum = dptr - p->dimension_list;
+  int axisp = (d == p1->x_d);
+  double val = slider_get_value(p->private->dim_scales[dnum],1);
+  int recursep = (val != d->val);
+
+  if(buttonstate == 0){
+    _sushiv_panel_undo_push(p);
+    _sushiv_panel_undo_suspend(p);
+  }
+
+  d->val = slider_get_value(p->private->dim_scales[dnum],1);
+
+  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);
+  }
+
+  /* dims can be shared amongst multiple panels; all must be updated */
+  if(recursep)
+    _sushiv_panel_update_shared_dimension(d,val);
+
+  if(buttonstate == 2)
+    _sushiv_panel_undo_resume(p);
+}
+
+static void bracket_callback_1d(void *in, int buttonstate){
+  sushiv_dimension_list_t *dptr = (sushiv_dimension_list_t *)in;
+  sushiv_dimension_t *d = dptr->d;
+  sushiv_panel_t *p = dptr->p;
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  int dnum = dptr - p->dimension_list;
+  double lo = slider_get_value(p->private->dim_scales[dnum],0);
+  double hi = slider_get_value(p->private->dim_scales[dnum],2);
+  
+  if(buttonstate == 0){
+    _sushiv_panel_undo_push(p);
+    _sushiv_panel_undo_suspend(p);
+  }
+
+  if(d->bracket[0] != lo || d->bracket[1] != hi){
+    scalespace s = scalespace_linear(lo,hi,p1->data_size,
+				     PLOT(p->private->graph)->scalespacing,
+				     d->name);
+    
+    if(s.m == 0){
+      fprintf(stderr,"X scale underflow; cannot zoom further.\n");
+    }else{
+      p1->x=s;
+      
+      d->bracket[0] = lo;
+      d->bracket[1] = hi;
+      update_crosshair(p);
+
+      _mark_recompute_1d(p);
+      _sushiv_panel_update_shared_bracket(d,lo,hi);
+    }
+  }
+ 
+  if(buttonstate == 2)
+    _sushiv_panel_undo_resume(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_panel_undo_push(p);
+    _sushiv_panel_undo_suspend(p);
+
+    update_x_sel(p);
+    update_crosshair(p);
+    plot_unset_box(PLOT(p->private->graph));
+    _mark_recompute_1d(p);
+
+    _sushiv_panel_undo_resume(p);
+  }
+}
+
+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;
+  
+  if(p1->link_x){
+    // make it the master panel's problem.
+    plot_set_crosshairs(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(PLOT(link->private->graph),
+			PLOT(link->private->graph)->selx,
+			x);
+    link->private->crosshair_action(link);
+  }else{
+
+    _sushiv_panel_undo_push(p);
+    _sushiv_panel_undo_suspend(p);
+
+    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){
+	slider_set_value(p->private->dim_scales[i],1,x);
+	
+	// key bindings could move crosshairs out of the window; we
+	// stretch in that case, which requires a recompute.
+	bracket_callback_1d(p->dimension_list+i,1);
+      }
+            
+      p1->oldbox_active = 0;
+    }
+  }
+  _sushiv_panel_undo_resume(p);
+}
+
+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_panel_undo_push(p);
+    plot_box_vals(plot,p1->oldbox);
+    p1->oldbox_active = plot->box_active;
+    break;
+  case 1: // box activate
+    _sushiv_panel_undo_push(p);
+    _sushiv_panel_undo_suspend(p);
+
+    crosshair_callback(p);
+
+    slider_set_value(p1->x_scale,0,p1->oldbox[0]);
+    slider_set_value(p1->x_scale,2,p1->oldbox[1]);
+    p1->oldbox_active = 0;
+    _sushiv_panel_undo_resume(p);
+    break;
+  }
+  update_context_menus(p);
+}
+
+int _sushiv_panel_cooperative_compute_1d(sushiv_panel_t *p){
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  Plot *plot;
+  
+  int dw,w,h,i,d;
+  int serialno;
+  double x_min, x_max;
+  int x_d=-1;
+  int render_scale_flag = 0;
+  scalespace sx;
+  scalespace sy;
+  scalespace sv;
+
+  // lock during setup
+  gdk_threads_enter ();
+  dw = p1->data_size;
+  w = p1->panel_w;
+  h = p1->panel_h;
+
+  sx = p1->x;
+  sy = p1->y;
+  sv = p1->vs;
+  
+  if(p1->last_line==2){
+    gdk_threads_leave ();
+    return 0;
+  }
+
+  plot = PLOT(p->private->graph);
+
+  if(p1->last_line){
+    p1->last_line++;
+    gdk_threads_leave ();
+    plot_expose_request(plot);
+    update_legend(p); 
+    return 0;
+  }
+  
+  serialno = p1->serialno;
+  d = p->dimensions;
+
+  /* render using local dimension array; several threads will be
+     computing objectives */
+  double dim_vals[p->sushi->dimensions];
+
+  x_min = scalespace_value(&sv,0);
+  x_max = scalespace_value(&sv,w);
+  x_d = p1->x_d->number;
+
+  plot->x = sx;
+  plot->y = sy;
+
+  // Bulletproofing; shouldn't ever come up
+  if(x_d==-1){
+    gdk_threads_leave ();
+    fprintf(stderr,"Invalid/missing x dimension setting in 1d panel x_d\n");
+    return 0;
+  }
+
+  // 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;
+  }
+
+  // update scales if we're just starting
+  if(p1->last_line==0) render_scale_flag = 1;
+
+  if(plot->w.allocation.height == h &&
+     serialno == p1->serialno){
+    p1->last_line++;
+    
+    /* unlock for computation */
+    gdk_threads_leave ();
+    
+    if(render_scale_flag){
+      plot_draw_scales(plot);
+      render_scale_flag = 0;
+    }
+    
+    /* compute */
+    compute_1d(p, serialno, x_d, x_min, x_max, dw, dim_vals);
+  }else
+    gdk_threads_leave ();
+
+  return 1;
+}
+
+static void panel1d_undo_log(sushiv_panel_undo_t *u){
+  sushiv_panel_t *p = u->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->submappings)
+    u->submappings =  calloc(p->objectives,sizeof(*u->submappings));
+  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(1,sizeof(**u->scale_vals));
+  if(!u->dim_vals[0])
+    u->dim_vals[0] =  calloc(p->dimensions,sizeof(**u->dim_vals));
+  if(!u->dim_vals[1])
+    u->dim_vals[1] =  calloc(p->dimensions,sizeof(**u->dim_vals));
+  if(!u->dim_vals[2])
+    u->dim_vals[2] =  calloc(p->dimensions,sizeof(**u->dim_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);
+  u->scale_vals[2][0] = slider_get_value(p1->range_slider,2);
+
+  for(i=0;i<p->objectives;i++){
+    u->mappings[i] = p1->mappings[i].mapnum;
+    u->submappings[i] = p1->linetype[i];
+  }
+
+  for(i=0;i<p->dimensions;i++){
+    u->dim_vals[0][i] = slider_get_value(p->private->dim_scales[i],0);
+    u->dim_vals[1][i] = slider_get_value(p->private->dim_scales[i],1);
+    u->dim_vals[2][i] = slider_get_value(p->private->dim_scales[i],2);
+  }
+  
+  u->x_d = p1->x_dnum;
+  u->box[0] = p1->oldbox[0];
+  u->box[1] = p1->oldbox[1];
+  u->box_active = p1->oldbox_active;
+  
+}
+
+static void panel1d_undo_restore(sushiv_panel_undo_t *u, int *remap_flag, int *recomp_flag){
+  sushiv_panel_t *p = u->p;
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  Plot *plot = PLOT(p->private->graph);
+  int i;
+  
+  *remap_flag=0;
+  *recomp_flag=0;
+
+  // go in through widgets
+  if(slider_get_value(p1->range_slider,0)!=u->scale_vals[0][0] ||
+     slider_get_value(p1->range_slider,1)!=u->scale_vals[1][0] ||
+     slider_get_value(p1->range_slider,2)!=u->scale_vals[2][0]){ 
+    *remap_flag = 1;
+  }
+   
+  slider_set_value(p1->range_slider,0,u->scale_vals[0][0]);
+  slider_set_value(p1->range_slider,1,u->scale_vals[1][0]);
+  slider_set_value(p1->range_slider,2,u->scale_vals[2][0]);
+
+  for(i=0;i<p->objectives;i++){
+    if(gtk_combo_box_get_active(GTK_COMBO_BOX(p1->map_pulldowns[i])) != u->mappings[i] ||
+       gtk_combo_box_get_active(GTK_COMBO_BOX(p1->line_pulldowns[i])) != u->submappings[i]){
+      *remap_flag = 1;
+    }
+    
+    gtk_combo_box_set_active(GTK_COMBO_BOX(p1->map_pulldowns[i]),u->mappings[i]);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(p1->line_pulldowns[i]),u->submappings[i]);
+  }
+
+  for(i=0;i<p->dimensions;i++){
+    slider_set_value(p->private->dim_scales[i],0,u->dim_vals[0][i]);
+    slider_set_value(p->private->dim_scales[i],1,u->dim_vals[1][i]);
+    slider_set_value(p->private->dim_scales[i],2,u->dim_vals[2][i]);
+  }
+
+  if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p1->dim_xb[u->x_d]))){
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p1->dim_xb[u->x_d]),TRUE);
+    *recomp_flag=1;
+  }
+
+  update_x_sel(p);
+
+  if(u->box_active){
+    plot_box_set(plot,u->box);
+    p1->oldbox_active = 1;
+  }else{
+    plot_unset_box(plot);
+    p1->oldbox_active = 0;
+  }
+}
+
+// called with lock
+static void panel1d_find_peak(sushiv_panel_t *p){
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  Plot *plot = PLOT(p->private->graph);
+  int i,j;
+  int dw = p1->data_size;
+  int count = 0;
+  
+  // finds in order each peak (in the event there's more than one) of
+  // each active objective
+  while(1){
+    
+    for(i=0;i<p->objectives;i++){
+      if(p1->data_vec && p1->data_vec[i] && !mapping_inactive_p(p1->mappings+i)){
+	double *data=p1->data_vec[i];
+	double best_val = data[0];
+	double best_j = 0;
+	int inner_count = count+1;
+	
+	for(j=1;j<dw;j++){
+	  if(!isnan(data[j])){
+	    if(data[j]>best_val){
+	      inner_count = count+1;
+	      best_val = data[j];
+	      best_j = j;
+	    }else if (data[j]==best_val){
+	      if(inner_count <= p1->peak_count){
+		inner_count++;
+		best_val = data[j];
+		best_j = j;
+	      }
+	    }
+	  }
+	}
+	
+	count = inner_count;
+	if(count>p1->peak_count){
+	  double xv = scalespace_value(&p1->vs,best_j);
+
+	  if(p1->flip)
+	    plot_set_crosshairs(plot,0,xv);
+	  else
+	    plot_set_crosshairs(plot,xv,0);
+	  crosshair_callback(p);
+	  
+	  p1->peak_count++;
+	  
+	  return;
+	}
+      }
+    }
+    
+    if(p1->peak_count==0)
+      return; // must be all inactive
+    else
+      p1->peak_count=0;
+  }
+}
+ 
+static gboolean panel1d_keypress(GtkWidget *widget,
+				 GdkEventKey *event,
+				 gpointer in){
+  sushiv_panel_t *p = (sushiv_panel_t *)in;
+  //  sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+  
+  if(event->state&GDK_MOD1_MASK) return FALSE;
+  if(event->state&GDK_CONTROL_MASK)return FALSE;
+  
+  /* non-control keypresses */
+  switch(event->keyval){
+    
+  case GDK_Q:
+  case GDK_q:
+    // quit
+    _sushiv_clean_exit(SIGINT);
+    return TRUE;
+
+  case GDK_BackSpace:
+    // undo 
+    _sushiv_panel_undo_down(p);
+    return TRUE;
+
+  case GDK_r:
+  case GDK_space:
+    // redo/forward
+    _sushiv_panel_undo_up(p);
+    return TRUE;
+
+  case GDK_p:
+    // find [next] peak
+    panel1d_find_peak(p);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static void update_context_menus(sushiv_panel_t *p){
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+
+  // is undo active?
+  if(!p->private->undo_stack ||
+     !p->private->undo_level){
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->popmenu),0),FALSE);
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->graphmenu),0),FALSE);
+  }else{
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->popmenu),0),TRUE);
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->graphmenu),0),TRUE);
+  }
+
+  // is redo active?
+  if(!p->private->undo_stack ||
+     !p->private->undo_stack[p->private->undo_level] ||
+     !p->private->undo_stack[p->private->undo_level+1]){
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->popmenu),1),FALSE);
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->graphmenu),1),FALSE);
+  }else{
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->popmenu),1),TRUE);
+    gtk_widget_set_sensitive(gtk_menu_get_item(GTK_MENU(p1->graphmenu),1),TRUE);
+  }
+
+  // are we starting or enacting a zoom box?
+  if(p1->oldbox_active){ 
+    gtk_menu_alter_item_label(GTK_MENU(p1->graphmenu),3,"Zoom to selection");
+  }else{
+    gtk_menu_alter_item_label(GTK_MENU(p1->graphmenu),3,"Start zoom selection");
+  }
+
+}
+
+void wrap_exit(sushiv_panel_t *dummy){
+  _sushiv_clean_exit(SIGINT);
+}
+
+static char *panel_menulist[]={
+  "Undo",
+  "Redo",
+  "",
+  "Quit",
+  NULL
+};
+
+static char *panel_shortlist[]={
+  "Backspace",
+  "Space",
+  NULL,
+  "q",
+  NULL
+};
+
+static void (*panel_calllist[])(sushiv_panel_t *)={
+  &_sushiv_panel_undo_down,
+  &_sushiv_panel_undo_up,
+  NULL,
+  &wrap_exit,
+  NULL,
+};
+
+void wrap_enter(sushiv_panel_t *p){
+  plot_do_enter(PLOT(p->private->graph));
+}
+
+void wrap_escape(sushiv_panel_t *p){
+  plot_do_escape(PLOT(p->private->graph));
+}
+
+static char *graph_menulist[]={
+  "Undo",
+  "Redo",
+  "",
+  "Start zoom selection",
+  "Clear selection",
+  "Find peaks",
+  "",
+  "Quit",
+  NULL
+};
+
+static char *graph_shortlist[]={
+  "Backspace",
+  "Space",
+  NULL,
+  "Enter",
+  "Escape",
+  "p",
+  NULL,
+  "q",
+  NULL
+};
+
+static void (*graph_calllist[])(sushiv_panel_t *)={
+  &_sushiv_panel_undo_down,
+  &_sushiv_panel_undo_up,
+  NULL,
+
+  &wrap_enter,
+  &wrap_escape,
+  &panel1d_find_peak,
+  NULL,
+  &wrap_exit,
+  NULL,
+};
+
+void _sushiv_realize_panel1d(sushiv_panel_t *p){
+  sushiv_panel1d_t *p1 = p->subtype->p1;
+  int i;
+
+  _sushiv_panel_undo_suspend(p);
+
+  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);
+ 
+  p1->top_table = gtk_table_new(4,4,0);
+
+  gtk_container_add (GTK_CONTAINER (p->private->toplevel), p1->top_table);
+  gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 5);
+  
+  p1->obj_table = gtk_table_new(p->objectives,3,0);
+  gtk_table_attach(GTK_TABLE(p1->top_table),p1->obj_table,0,4,2,3,
+		   GTK_EXPAND|GTK_FILL,0,0,5);
+
+  p1->dim_table = gtk_table_new(p->dimensions,4,0);
+  gtk_table_attach(GTK_TABLE(p1->top_table),p1->dim_table,0,4,3,4,
+		   GTK_EXPAND|GTK_FILL,0,0,5);
+  
+  /* graph */
+  {
+    unsigned flags = 0;
+    if(p1->flip)
+      flags |= PLOT_NO_X_CROSS;
+    else
+      flags |= PLOT_NO_Y_CROSS;
+    p->private->graph = GTK_WIDGET(plot_new(recompute_callback_1d,p,
+					    (void *)(void *)crosshair_callback,p,
+					    box_callback,p,flags)); 
+    gtk_table_attach(GTK_TABLE(p1->top_table),p->private->graph,0,4,0,1,
+		     GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,5);
+  }
+
+  /* range slider */
+  {
+    GtkWidget **sl = calloc(3,sizeof(*sl));
+
+    int lo = p1->range_scale->val_list[0];
+    int hi = p1->range_scale->val_list[p1->range_scale->vals-1];
+
+    /* label */
+    {
+      char *buf;
+      asprintf(&buf,"%s range",p1->range_scale->legend);
+      GtkWidget *label = gtk_label_new(buf);
+      gtk_table_attach(GTK_TABLE(p1->top_table),label,0,1,1,2,
+		       0,0,10,0);
+      free(label);
+    }
+
+    /* the range slices/slider */ 
+    sl[0] = slice_new(map_callback_1d,p);
+    sl[1] = slice_new(map_callback_1d,p);
+    sl[2] = slice_new(map_callback_1d,p);
+
+    gtk_table_attach(GTK_TABLE(p1->top_table),sl[0],1,2,1,2,
+		     GTK_EXPAND|GTK_FILL,0,0,0);
+    gtk_table_attach(GTK_TABLE(p1->top_table),sl[1],2,3,1,2,
+		     GTK_EXPAND|GTK_FILL,0,0,0);
+    gtk_table_attach(GTK_TABLE(p1->top_table),sl[2],3,4,1,2,
+		     GTK_EXPAND|GTK_FILL,0,0,0);
+    p1->range_slider = slider_new((Slice **)sl,3,
+				  p1->range_scale->label_list,
+				  p1->range_scale->val_list,
+				  p1->range_scale->vals,
+				  SLIDER_FLAG_INDEPENDENT_MIDDLE);
+
+    slice_thumb_set((Slice *)sl[0],lo);
+    slice_thumb_set((Slice *)sl[1],lo);
+    slice_thumb_set((Slice *)sl[2],hi);
+  }
+
+  /* objective pulldowns */
+  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));
+
+  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_table_attach(GTK_TABLE(p1->obj_table),label,0,1,i,i+1,
+		     0,0,10,0);
+    
+    /* mapping pulldown */
+    {
+      GtkWidget *menu=gtk_combo_box_new_markup();
+      int j;
+      for(j=0;j<num_solids();j++)
+	gtk_combo_box_append_text (GTK_COMBO_BOX (menu), solid_name(j));
+      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;
+    }
+
+    /* 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]);
+      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;
+    }
+  }
+
+  if(p->dimensions){
+    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++){
+      GtkWidget **sl = calloc(3,sizeof(*sl));
+      sushiv_dimension_t *d = p->dimension_list[i].d;
+      
+      /* label */
+      GtkWidget *label = gtk_label_new(d->name);
+      gtk_table_attach(GTK_TABLE(p1->dim_table),label,0,1,i,i+1,
+		       0,0,10,0);
+      
+      /* x radio buttons */
+      if(!(d->flags & SUSHIV_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,10,0);
+      }
+    
+      /* the dimension slices/slider */ 
+      sl[0] = slice_new(bracket_callback_1d,p->dimension_list+i);
+      sl[1] = slice_new(dim_callback_1d,p->dimension_list+i);
+      sl[2] = slice_new(bracket_callback_1d,p->dimension_list+i);
+
+      gtk_table_attach(GTK_TABLE(p1->dim_table),sl[0],2,3,i,i+1,
+		       GTK_EXPAND|GTK_FILL,0,0,0);
+      gtk_table_attach(GTK_TABLE(p1->dim_table),sl[1],3,4,i,i+1,
+		       GTK_EXPAND|GTK_FILL,0,0,0);
+      gtk_table_attach(GTK_TABLE(p1->dim_table),sl[2],4,5,i,i+1,
+		       GTK_EXPAND|GTK_FILL,0,0,0);
+      
+      p->private->dim_scales[i] = slider_new((Slice **)sl,3,d->scale->label_list,d->scale->val_list,
+					     d->scale->vals,0);
+      
+      slice_thumb_set((Slice *)sl[0],d->scale->val_list[0]);
+      slice_thumb_set((Slice *)sl[1],0);
+      slice_thumb_set((Slice *)sl[2],d->scale->val_list[d->scale->vals-1]);
+    }
+
+    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);
+  }
+
+  p1->popmenu = gtk_menu_new_twocol(p->private->toplevel,
+				    panel_menulist,
+				    panel_shortlist,
+				    (void *)(void *)panel_calllist,
+				    p);
+  p1->graphmenu = gtk_menu_new_twocol(p->private->graph,
+				      graph_menulist,
+				      graph_shortlist,
+				      (void *)(void *)graph_calllist,
+				      p);
+
+  update_context_menus(p);
+
+  g_signal_connect (G_OBJECT (p->private->toplevel), "key-press-event",
+                    G_CALLBACK (panel1d_keypress), p);
+  gtk_window_set_title (GTK_WINDOW (p->private->toplevel), p->name);
+
+  gtk_widget_realize(p->private->toplevel);
+  gtk_widget_realize(p->private->graph);
+  gtk_widget_show_all(p->private->toplevel);
+
+  _sushiv_panel_undo_resume(p);
+}
+
+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(s,number,name,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 = calloc(1, sizeof(*p1));
+  p->subtype = 
+    calloc(1, sizeof(*p->subtype)); /* the union is alloced not
+				       embedded as its internal
+				       structure must be hidden */
+  p->subtype->p1 = p1;
+  p->type = SUSHIV_PANEL_1D;
+
+  p1->range_scale = scale;
+
+  if(flags && SUSHIV_LINK_Y)
+    p1->link_y = p2;
+  else
+    p1->link_x = p2;
+
+  if(p->flags && SUSHIV_FLIP)
+    p1->flip=1;
+
+  p->private->realize = _sushiv_realize_panel1d;
+  p->private->map_redraw = _sushiv_panel1d_map_redraw;
+  p->private->legend_redraw = _sushiv_panel1d_legend_redraw;
+  p->private->compute_action = _sushiv_panel_cooperative_compute_1d;
+  p->private->request_compute = _mark_recompute_1d;
+  p->private->crosshair_action = crosshair_callback;
+
+  p->private->undo_log = panel1d_undo_log;
+  p->private->undo_restore = panel1d_undo_restore;
+  p->private->update_menus = update_context_menus;
+
+  return 0;
+}
+

Added: trunk/sushivision/panel-1d.h
===================================================================
--- trunk/sushivision/panel-1d.h	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/panel-1d.h	2006-12-28 06:06:26 UTC (rev 12248)
@@ -0,0 +1,69 @@
+/*
+ *
+ *     sushivision copyright (C) 2006 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.
+ *
+ * 
+ */
+
+typedef struct sushiv_panel1d {
+
+  sushiv_panel_t *link_x;
+  sushiv_panel_t *link_y;
+
+  GtkWidget *top_table;
+  GtkWidget *obj_table;
+  GtkWidget *dim_table;
+  GtkWidget *popmenu;
+  GtkWidget *graphmenu;
+
+  int panel_w;
+  int panel_h;
+  int data_size;
+  int serialno;
+  double **data_vec;
+
+  scalespace x;
+  scalespace vs;
+  scalespace y;
+
+  int scales_init;
+  double oldbox[4];
+  int oldbox_active;
+
+  int flip;
+  sushiv_scale_t *range_scale;
+  Slider *range_slider;
+  double alphaval;
+  double range_bracket[2];
+  
+  mapping *mappings;
+  int *linetype;
+  GtkWidget **map_pulldowns;
+  GtkWidget **line_pulldowns;
+
+  GtkWidget **dim_xb;
+
+  sushiv_dimension_t *x_d;
+  Slider *x_scale;
+  int x_dnum; // number of dimension within panel, not global instance
+
+  int last_line;
+  int dirty_flag;
+
+  int peak_count;
+} sushiv_panel1d_t;
+

Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/panel-2d.c	2006-12-28 06:06:26 UTC (rev 12248)
@@ -533,7 +533,7 @@
   int w = plot->w.allocation.width;
   int h = plot->w.allocation.height;
 
-  //_sushiv_panel1d_mark_recompute_linked(p);    XXXX
+  _sushiv_panel1d_mark_recompute_linked(p);   
 
   if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
     if(p2->data_w != plot->w.allocation.width ||
@@ -623,7 +623,7 @@
       d->val = scalespace_value(&plot->y,p2->data_h - plot_get_crosshair_ypixel(plot));
   }
 
-  // _sushiv_panel1d_update_linked_crosshairs(p); XXXX
+  _sushiv_panel1d_update_linked_crosshairs(p); 
 
   update_legend(p);
 }
@@ -1246,7 +1246,7 @@
   /* graph */
   p->private->graph = GTK_WIDGET(plot_new(recompute_callback_2d,p,
 				  (void *)(void *)_sushiv_panel2d_crosshairs_callback,p,
-				  box_callback,p)); 
+				  box_callback,p,0)); 
   gtk_table_attach(GTK_TABLE(p2->top_table),p->private->graph,0,5,0,1,
 		   GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,5);
 

Modified: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/plot.c	2006-12-28 06:06:26 UTC (rev 12248)
@@ -343,10 +343,16 @@
       double sy = plot_get_crosshair_ypixel(p);
       cairo_set_source_rgba(c,1.,1.,1.,.8);
       cairo_set_line_width(c,1.);
-      cairo_move_to(c,0,sy+.5);
-      cairo_line_to(c,widget->allocation.width,sy+.5);
-      cairo_move_to(c,sx+.5,0);
-      cairo_line_to(c,sx+.5,widget->allocation.height);
+
+      if(! (p->flags && PLOT_NO_Y_CROSS)){
+	cairo_move_to(c,0,sy+.5);
+	cairo_line_to(c,widget->allocation.width,sy+.5);
+      }
+
+      if(! (p->flags && PLOT_NO_X_CROSS)){
+	cairo_move_to(c,sx+.5,0);
+	cairo_line_to(c,sx+.5,widget->allocation.height);
+      }
       cairo_stroke(c);
     }
 
@@ -354,6 +360,16 @@
       double vals[4];
       box_corners(p,vals);
 
+      if(p->flags && PLOT_NO_X_CROSS){
+	vals[0]=-1;
+	vals[2]=widget->allocation.width+2;
+      }
+
+      if(p->flags && PLOT_NO_Y_CROSS){
+	vals[1]=-1;
+	vals[2]=widget->allocation.height+2;
+      }
+
       cairo_rectangle(c,vals[0],vals[1],vals[2]+1,vals[3]+1);	
       if(p->box_active>1)
 	cairo_set_source_rgba(c,1.,1.,.6,.4);
@@ -819,7 +835,8 @@
 
 Plot *plot_new (void (*callback)(void *),void *app_data,
 		void (*cross_callback)(void *),void *cross_data,
-		void (*box_callback)(void *, int),void *box_data) {
+		void (*box_callback)(void *, int),void *box_data,
+		unsigned flags) {
   GtkWidget *g = GTK_WIDGET (g_object_new (PLOT_TYPE, NULL));
   Plot *p = PLOT (g);
   p->recompute_callback = callback;
@@ -828,6 +845,7 @@
   p->cross_data = cross_data;
   p->box_callback = box_callback;
   p->box_data = box_data;
+  p->flags = flags;
 
   struct timeval now;
   gettimeofday(&now,NULL);

Modified: trunk/sushivision/plot.h
===================================================================
--- trunk/sushivision/plot.h	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/plot.h	2006-12-28 06:06:26 UTC (rev 12248)
@@ -78,6 +78,8 @@
   int expose_y_hi;
   time_t last_line_expose;
   time_t begin;
+
+  unsigned flags;
 };
 
 struct _PlotClass{
@@ -88,7 +90,8 @@
 GType     plot_get_type        (void);
 Plot     *plot_new (void (*callback)(void *),void *app_data,
 		    void (*cross_callback)(void *),void *cross_data,
-		    void (*box_callback)(void *,int),void *box_data);
+		    void (*box_callback)(void *,int),void *box_data,
+		    unsigned flags);
 
 G_END_DECLS
 
@@ -114,3 +117,6 @@
 
 void plot_do_enter(Plot *p);
 void plot_do_escape(Plot *p);
+
+#define PLOT_NO_X_CROSS 1
+#define PLOT_NO_Y_CROSS 2

Modified: trunk/sushivision/scale.c
===================================================================
--- trunk/sushivision/scale.c	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/scale.c	2006-12-28 06:06:26 UTC (rev 12248)
@@ -155,11 +155,12 @@
 	free(s->label_list[i]);
       free(s->label_list);
     }
+    if(s->legend)free(s->legend);
     free(s);
   }
 }
 
-sushiv_scale_t *scale_new(unsigned scalevals, double *scaleval_list){
+sushiv_scale_t *scale_new(unsigned scalevals, double *scaleval_list, const char *legend){
   int i;
 
   sushiv_scale_t *s = NULL;
@@ -179,7 +180,10 @@
 
   // generate labels
   s->label_list = scale_generate_labels(scalevals,scaleval_list);
-
+  if(legend)
+    s->legend=strdup(legend);
+  else
+    s->legend=strdup("");
   return s;
 }
 

Modified: trunk/sushivision/sushivision.h
===================================================================
--- trunk/sushivision/sushivision.h	2006-12-28 04:37:54 UTC (rev 12247)
+++ trunk/sushivision/sushivision.h	2006-12-28 06:06:26 UTC (rev 12248)
@@ -44,11 +44,15 @@
 
 #define SUSHIV_NO_X 0x100
 #define SUSHIV_NO_Y 0x200
+#define SUSHIV_LINK_X 0x400 
+#define SUSHIV_LINK_Y 0x800 
+#define SUSHIV_FLIP 0x1000 
 
 struct sushiv_scale{
   int vals;
   double *val_list;
   char **label_list; 
+  char *legend;
 };
 
 typedef struct sushiv_panel_internal sushiv_panel_internal_t;
@@ -114,7 +118,7 @@
 extern sushiv_instance_t *sushiv_new_instance(void);
 
 extern void scale_free(sushiv_scale_t *s);
-extern sushiv_scale_t *scale_new(unsigned scalevals, double *scaleval_list);
+extern sushiv_scale_t *scale_new(unsigned scalevals, double *scaleval_list, const char *legend);
 extern int scale_set_scalelabels(sushiv_scale_t *s, char **scalelabel_list);
 
 extern int sushiv_new_dimension(sushiv_instance_t *s,
@@ -153,7 +157,7 @@
 				      const char *name,
 				      sushiv_scale_t *scale,
 				      int *objectives,
-				      sushiv_panel_t *s2d,
+				      int linkee,
 				      unsigned flags);
 
 extern int sushiv_new_panel_xy(sushiv_instance_t *s,



More information about the commits mailing list