[xiph-commits] r11955 - in trunk: . sushivision
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Thu Oct 26 19:14:26 PDT 2006
Author: xiphmont
Date: 2006-10-26 19:14:20 -0700 (Thu, 26 Oct 2006)
New Revision: 11955
Added:
trunk/sushivision/
trunk/sushivision/Makefile
trunk/sushivision/dimension.c
trunk/sushivision/example_submain.c
trunk/sushivision/internal.h
trunk/sushivision/main.c
trunk/sushivision/mapping.c
trunk/sushivision/mapping.h
trunk/sushivision/objective.c
trunk/sushivision/panel-2d.c
trunk/sushivision/panel-2d.h
trunk/sushivision/panel.c
trunk/sushivision/plot.c
trunk/sushivision/plot.h
trunk/sushivision/scale.c
trunk/sushivision/scale.h
trunk/sushivision/slice.c
trunk/sushivision/slice.h
trunk/sushivision/slider.c
trunk/sushivision/slider.h
trunk/sushivision/sushi-gtkrc
trunk/sushivision/sushi.h
trunk/sushivision/sushivision.h
Log:
Initial commit of sushivision code. BUild system incomplete, example
submain doesn't do much of anything, lots of funcitonality still
missing.
Added: trunk/sushivision/Makefile
===================================================================
--- trunk/sushivision/Makefile 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/Makefile 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,59 @@
+# Fuck Automake
+# Fuck the horse it rode in on
+# and Fuck its little dog Libtool too
+
+TARGET = sushivision
+CC = gcc
+LD = gcc
+INSTALL = install
+STRIP = strip
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+ETCDIR = /etc/$(TARGET)
+MANDIR = $(PREFIX)/man
+
+SRC = main.c scale.c plot.c slider.c slice.c panel.c panel-2d.c mapping.c dimension.c objective.c example_submain.c
+OBJ = main.o scale.o plot.o slider.o slice.o panel.o panel-2d.o mapping.o dimension.o objective.o example_submain.o
+INC = sushivision.h
+LIBS = -lpthread
+CAIROVER = >= 1.0.0
+GTKVER = >= 2.8.0
+GCF = `pkg-config --static --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER) freetype2 gthread-2.0"`
+LDF = -pthread -L/lib -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lm -lfontconfig -lpng12 -lXrender -lX11 -lpthread -lfreetype -lz -lgthread-2.0 -lglib-2.0 -lcairo
+
+all:
+ pkg-config --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER) freetype2" 1>/dev/null
+ $(MAKE) target CFLAGS='-O2 -ffast-math $(GCF) $(ADD_DEF)'
+ $(STRIP) $(TARGET)
+
+debug:
+ pkg-config --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER) freetype2" 1>/dev/null
+ $(MAKE) target CFLAGS='-g -Wall -W -Wno-unused-parameter -D__NO_MATH_INLINES $(GCF) $(ADD_DEF)'
+
+profile:
+ pkg-config --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER) freetype2" 1>/dev/null
+ $(MAKE) target CFLAGS='-pg -g -O2 -ffast-math $(GCF) $(ADD_DEF)' LIBS='-lgprof-helper'
+
+clean:
+ rm -f $(OBJ) *.d *.d.* gmon.out $(TARGET)
+
+distclean: clean
+ rm -f *~
+
+%.d: %.c
+ $(CC) -M $(CFLAGS) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$
+
+ifeq ($(MAKECMDGOALS),target)
+include $(SRC:.c=.d)
+endif
+
+ifeq ($(MAKECMDGOALS),static-target)
+include $(SRC:.c=.d)
+endif
+
+target: $(OBJ)
+ $(LD) $(OBJ) $(CFLAGS) -o $(TARGET) $(LIBS) $(LDF)
+
+install: target
+ $(INSTALL) -d -m 0755 $(BINDIR)
+ $(INSTALL) -m 0755 $(TARGET) $(BINDIR)
Added: trunk/sushivision/dimension.c
===================================================================
--- trunk/sushivision/dimension.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/dimension.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sushivision.h"
+#include "internal.h"
+#include "scale.h"
+
+int sushiv_dim_set_scale(sushiv_dimension_t *d, unsigned scalevals, double *scaleval_list){
+ int i;
+
+ if(scalevals<2){
+ fprintf(stderr,"Scale requires at least two scale values.");
+ return -EINVAL;
+ }
+
+ if(d->scale_val_list)free(d->scale_val_list);
+ if(d->scale_label_list){
+ for(i=0;i<d->scale_vals;i++)
+ free(d->scale_label_list[i]);
+ free(d->scale_label_list);
+ }
+
+ // copy values
+ d->scale_vals = scalevals;
+ d->scale_val_list = calloc(scalevals,sizeof(*d->scale_val_list));
+ for(i=0;i<(int)scalevals;i++)
+ d->scale_val_list[i] = scaleval_list[i];
+
+ // generate labels
+ d->scale_label_list = scale_generate_labels(scalevals,scaleval_list);
+
+ return 0;
+}
+
+int sushiv_dim_set_scalelabels(sushiv_dimension_t *d, char **scalelabel_list){
+ int i;
+ for(i=0;i<d->scale_vals;i++){
+ if(d->scale_label_list[i])
+ free(d->scale_label_list[i]);
+ d->scale_label_list[i] = strdup(scalelabel_list[i]);
+ }
+ return 0;
+}
+
+int sushiv_new_dimension(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ unsigned scalevals, double *scaleval_list,
+ int (*callback)(sushiv_dimension_t *),
+ unsigned flags){
+ sushiv_dimension_t *d;
+
+ if(number<0){
+ fprintf(stderr,"Dimension number must be >= 0\n");
+ return -EINVAL;
+ }
+
+ if(number<s->dimensions){
+ if(s->dimension_list[number]!=NULL){
+ fprintf(stderr,"Dimension number %d already exists\n",number);
+ return -EINVAL;
+ }
+ }else{
+ if(s->dimensions == 0){
+ s->dimension_list = calloc (number+1,sizeof(*s->dimension_list));
+ }else{
+ s->dimension_list = realloc (s->dimension_list,(number+1) * sizeof(*s->dimension_list));
+ memset(s->dimension_list + s->dimensions, 0, sizeof(*s->dimension_list)*(number + 1 - s->dimensions));
+ }
+ s->dimensions=number+1;
+ }
+
+ d = s->dimension_list[number] = calloc(1, sizeof(**s->dimension_list));
+ d->number = number;
+ d->name = strdup(name);
+ d->flags = flags;
+ d->sushi = s;
+ d->callback = callback;
+ d->panel = NULL;
+ return sushiv_dim_set_scale(d, scalevals, scaleval_list);
+}
Added: trunk/sushivision/example_submain.c
===================================================================
--- trunk/sushivision/example_submain.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/example_submain.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,135 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "sushivision.h"
+
+sushiv_instance_t *s;
+#define todB(x) ((x)==0?-400.f:log((x)*(x))*4.34294480f)
+
+/* time, blocksz, amp_0, amp_del, freq_0, phase_0, phase_del */
+int funcsize=64;
+double function[64];
+static double fourier_objective(double *d){
+ int i;
+ double re_obj=0;
+ double im_obj=0;
+ double obj;
+
+ for(i=0;i<funcsize;i++){
+ im_obj += function[i] * sin(i*d[4]*2*M_PI);
+ re_obj += function[i] * cos(i*d[4]*2*M_PI);
+
+ }
+ im_obj/=funcsize;
+ re_obj/=funcsize;
+
+ obj = sqrt(im_obj*im_obj + re_obj*re_obj);
+ return todB(obj);
+
+}
+
+/*
+static double objective(double *d){
+
+ return .5;
+
+}
+*/
+
+static int time_callback(sushiv_dimension_t *d){
+
+
+ return 1; // indicate that default processing chain should continue
+}
+
+static int blocksize_callback(sushiv_dimension_t *d){
+
+
+ return 1; // indicate that default processing chain should continue
+}
+
+int sushiv_submain(int argc, char *argv[]){
+ int i;
+
+ for(i=0;i<funcsize;i++)
+ function[i]=sin(i*.1)*.1;
+
+
+ s=sushiv_new_instance();
+
+ sushiv_new_dimension(s,0,"time",
+ 4,(double []){0,1024,2048,4096},
+ time_callback,
+ 0);
+ sushiv_new_dimension(s,1,"blocksize",
+ 8,(double []){64,128,256,512,1024,2048,4096,8192},
+ blocksize_callback,
+ 0);
+
+ sushiv_new_dimension(s,2,"amplitude",
+ 9,(double []){-96,-84,-72,-60,-48,-36,-24,-12,0},
+ NULL,
+ SUSHIV_X_RANGE|SUSHIV_Y_RANGE);
+ sushiv_new_dimension(s,3,"amplitude delta",
+ 9,(double []){-96,-48,-24,-12,0,12,24,48,96},
+ NULL,
+ SUSHIV_X_RANGE|SUSHIV_Y_RANGE);
+ sushiv_new_dimension(s,4,"frequency",
+ 6,(double []){0,.1,.2,.3,.4,.5},
+ NULL,
+ SUSHIV_X_RANGE|SUSHIV_Y_RANGE);
+ sushiv_new_dimension(s,5,"phase",
+ 3,(double []){-.5,0,.5},
+ NULL,
+ SUSHIV_X_RANGE|SUSHIV_Y_RANGE);
+ sushiv_new_dimension(s,6,"phase delta",
+ 3,(double []){-10,0,10},
+ NULL,
+ SUSHIV_X_RANGE|SUSHIV_Y_RANGE);
+
+ sushiv_new_objective(s,0,"fourier",fourier_objective,0);
+ //sushiv_new_objective(s,1,"fit",fit_objective,0);
+ //sushiv_new_objective(s,2,"waveform",fourier_objective,0);
+
+ sushiv_new_panel_2d(s,0,"fourier objective",8,
+ (double []){-96,-48,-36,-24,-12,-6,0,6},
+ (int []){0,-1},
+ (int []){2,3,4,5,6,-1},
+ 0);
+
+ /*sushiv_linked_panel_1d(s,1,"fourier x slice",8,
+ (double []){-96,-48,-36,-24,-12,-6,0,6},
+ 0,0,
+ 0);
+ sushiv_linked_panel_1d(s,2,"fourier y slice",8,
+ (double []){-96,-48,-36,-24,-12,-6,0,6},
+ 0,1,
+ 0);
+ sushiv_new_panel_1d(s,3,"input block",8,
+ (double []){-96,-48,-36,-24,-12,-6,0,6},
+ (int *){2,-1},
+ NULL,
+ 0);*/
+
+ return 0;
+}
Added: trunk/sushivision/internal.h
===================================================================
--- trunk/sushivision/internal.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/internal.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <signal.h>
+extern void _sushiv_realize_panel(sushiv_panel_t *p);
+extern void _sushiv_clean_exit(int sig);
+extern int _sushiv_new_panel(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ unsigned scalevals,
+ double *scaleval_list,
+ int *objectives,
+ int *dimensions,
+ unsigned flags);
+
+extern void _sushiv_panel_dirty_map(sushiv_panel_t *p);
+extern void _sushiv_wake_workers(void);
+
+extern int _sushiv_panel_cooperative_compute(sushiv_panel_t *p);
+
+extern sig_atomic_t _sushiv_exiting;
+
+#define SUSHIV_DIM_MASK 0x003
+#define SUSHIV_X_DIM 0x001
+#define SUSHIV_Y_DIM 0x002
Added: trunk/sushivision/main.c
===================================================================
--- trunk/sushivision/main.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/main.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,179 @@
+/*
+ *
+ * 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 <pthread.h>
+#include "sushivision.h"
+#include "internal.h"
+
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t mc = PTHREAD_COND_INITIALIZER;
+sig_atomic_t _sushiv_exiting=0;
+
+static int instances;
+static sushiv_instance_t **instance_list;
+
+void _sushiv_clean_exit(int sig){
+ _sushiv_exiting = 1;
+
+ pthread_mutex_lock(&m);
+ pthread_cond_broadcast(&mc);
+ pthread_mutex_unlock(&m);
+
+ signal(sig,SIG_IGN);
+ if(sig!=SIGINT)
+ fprintf(stderr,
+ "\nTrapped signal %d; exiting!\n",sig);
+
+ gtk_main_quit();
+ exit(0);
+}
+
+static int num_proccies(){
+ FILE *f = fopen("/proc/cpuinfo","r");
+ char * line = NULL;
+ size_t len = 0;
+ ssize_t read;
+ int num=1,arg;
+
+ if (f == NULL) return 1;
+ while ((read = getline(&line, &len, f)) != -1) {
+ if(sscanf(line,"processor : %d",&arg)==1)
+ if(arg+1>num)num=arg+1;
+ }
+ if (line)
+ free(line);
+
+ fprintf(stderr,"Number of processors: %d\n",num);
+ fclose(f);
+ return num;
+}
+
+void _sushiv_wake_workers(){
+ if(instances){
+ pthread_mutex_lock(&m);
+ pthread_cond_broadcast(&mc);
+ pthread_mutex_unlock(&m);
+ }
+}
+
+static void *worker_thread(void *dummy){
+ pthread_mutex_lock(&m);
+ while(1){
+ if(_sushiv_exiting)break;
+
+ // look for work
+ {
+ int i,j,flag=0;
+ // by instance
+ for(j=0;j<instances;j++){
+ sushiv_instance_t *s = instance_list[j];
+
+ for(i=0;i<s->panels;i++){
+ if(_sushiv_exiting)break;
+ pthread_mutex_unlock(&m);
+ flag |= _sushiv_panel_cooperative_compute(s->panel_list[i]);
+ pthread_mutex_lock(&m);
+ }
+ }
+ if(flag==1)continue;
+ }
+
+ // nothing to do, wait
+ pthread_cond_wait(&mc,&m);
+ }
+
+ pthread_mutex_unlock(&m);
+ return 0;
+}
+
+static char * gtkrc_string(){
+
+ return "";
+}
+
+static void sushiv_realize_instance(sushiv_instance_t *s){
+ int i;
+ for(i=0;i<s->panels;i++)
+ _sushiv_realize_panel(s->panel_list[i]);
+}
+
+static void sushiv_realize_all(void){
+ int i;
+ for(i=0;i<instances;i++)
+ sushiv_realize_instance(instance_list[i]);
+}
+
+int main (int argc, char *argv[]){
+ int ret;
+
+ gtk_init (&argc, &argv);
+ g_thread_init (NULL);
+ gdk_threads_init ();
+ gtk_rc_parse_string(gtkrc_string());
+ gtk_rc_add_default_file("sushi-gtkrc");
+
+ ret = sushiv_submain(argc,argv);
+ if(ret)return ret;
+
+ sushiv_realize_all();
+
+ {
+ pthread_t dummy;
+ int threads = num_proccies();
+ while(threads--)
+ pthread_create(&dummy, NULL, &worker_thread,NULL);
+ }
+
+ signal(SIGINT,_sushiv_clean_exit);
+ //signal(SIGSEGV,_sushiv_clean_exit);
+ gtk_main ();
+
+
+ return 0;
+}
+
+/* externally visible interface */
+
+sushiv_instance_t *sushiv_new_instance(void) {
+ sushiv_instance_t *ret=calloc(1,sizeof(*ret));
+
+ if(instances){
+ instance_list = realloc(instance_list,(instances+1)*sizeof(*instance_list));
+ }else{
+ instance_list = malloc((instances+1)*sizeof(*instance_list));
+ }
+ instance_list[instances] = ret;
+ instances++;
+
+ return ret;
+}
+
Added: trunk/sushivision/mapping.c
===================================================================
--- trunk/sushivision/mapping.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/mapping.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,213 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "mapping.h"
+
+static u_int32_t scalloped_colorwheel(double val){
+ if(val<0.)val=0.;
+ if(val>1.)val=1.;
+ {
+ int r,g,b;
+
+ int category = val*12;
+ int v = rint((val*12 - category)*255.);
+
+ switch(category){
+ case 0:
+ r=0;g=v;b=0;break;
+ case 1:
+ r=v;g=v;b=0;break;
+ case 2:
+ r=v;g=(v>>1);b=0;break;
+ case 3:
+ r=v;g=0;b=0;break;
+ case 4:
+ r=v;g=0;b=v*3/4;break;
+ case 5:
+ r=v*3/4;g=0;b=v;break;
+ case 6:
+ r=(v>>1);g=0;b=v;break;
+ case 7:
+ r=0;g=0;b=v;break;
+ case 8:
+ r=0;g=v*2/3;b=v;break;
+ case 9:
+ r=0;g=v;b=v;break;
+ case 10:
+ r=v*2/3;g=v;b=v;break;
+ case 11:
+ r=v;g=v;b=v;break;
+ case 12:
+ r=255;g=255;b=255;break;
+ }
+
+ return (r<<16) + (g<<8) + b;
+ }
+}
+
+#include <stdio.h>
+static u_int32_t smooth_colorwheel(double val){
+ if(val<0)val=0;
+ if(val>1)val=1;
+ {
+ int r,g,b;
+
+ if(val<= (4./7.)){
+ if(val<= (2./7.)){
+ if(val<= (1./7.)){
+ // 0->1, 0->g
+ r=0;
+ g= rint(7.*255.*val);
+ b=0;
+
+ }else{
+ // 1->2, g->rg
+ r= rint(7.*255.*val-255.);
+ g=255;
+ b=0;
+
+ }
+ }else{
+ if(val<=(3./7.)){
+ // 2->3, rg->r
+ r= 255;
+ g= rint(3.*255. - 7.*255.*val);
+ b=0;
+
+ }else{
+ // 3->4, r->rb
+ r= 255;
+ g= 0.;
+ b= rint(7.*255.*val-3.*255.);
+ }
+ }
+ }else{
+ if(val<= (5./7.)){
+ // 4->5, rb->b
+ r= rint(5.*255. - 7.*255.*val);
+ g= 0;
+ b= 255;
+
+ }else{
+ if(val<= (6./7.)){
+ // 5->6, b->bg
+ r= 0.;
+ g= rint(7.*255.*val-5.*255.);
+ b= 255;
+
+ }else{
+ // 6->7, bg->rgb
+ r= rint(7.*255.*val-6.*255.);
+ g= 255;
+ b= 255;
+
+ }
+ }
+ }
+ return (r<<16) + (g<<8) + b;
+ }
+}
+
+static u_int32_t grayscale(double val){
+ if(val<0)val=0;
+ if(val>1)val=1;
+ {
+ int g=rint(val*255.);
+ return (g<<16)+(g<<8)+g;
+ }
+}
+
+static u_int32_t grayscale_cont(double val){
+ if(val<0)val=0;
+ if(val>1)val=1;
+ {
+ int g=rint(val*255.);
+ if((g & 0xf) < 0x1) g=0;
+ return (g<<16)+(g<<8)+g;
+ }
+}
+
+static u_int32_t (*mapfunc[])(double)={
+ scalloped_colorwheel,
+ smooth_colorwheel,
+ grayscale,
+ grayscale_cont,
+};
+
+static char *mapnames[]={
+ "scalloped colorwheel",
+ "smooth colorwheel",
+ "grayscale",
+ "grayscale with contours",
+ 0
+};
+
+int num_mappings(){
+ int i=0;
+ while(mapnames[i])i++;
+ return i;
+}
+
+char *mapping_name(int i){
+ return mapnames[i];
+}
+
+void mapping_setup(mapping *m, double lo, double hi, int funcnum){
+ m->low = lo;
+ m->high = hi;
+ m->i_range = 1./(hi-lo);
+ m->mapfunc = mapfunc[funcnum];
+}
+
+void mapping_set_lo(mapping *m, double lo){
+ m->low = lo;
+ if(m->high-m->low>0.)
+ m->i_range = 1./(m->high-m->low);
+ else
+ m->i_range=0;
+}
+
+void mapping_set_hi(mapping *m, double hi){
+ m->high=hi;
+ if(m->high-m->low>0.)
+ m->i_range = 1./(m->high-m->low);
+ else
+ m->i_range=0;
+}
+
+void mapping_set_func(mapping *m, int funcnum){
+ m->mapfunc = mapfunc[funcnum];
+}
+
+u_int32_t mapping_calc(mapping *m, double in){
+ if(m->i_range==0){
+ if(in<=m->low)
+ return m->mapfunc(0.);
+ else
+ return m->mapfunc(1.);
+ }else{
+ double val = (in - m->low) * m->i_range;
+ return m->mapfunc(val);
+ }
+}
Added: trunk/sushivision/mapping.h
===================================================================
--- trunk/sushivision/mapping.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/mapping.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <sys/types.h>
+typedef struct {
+
+ double low;
+ double high;
+ double i_range;
+ u_int32_t (*mapfunc)(double val);
+
+} mapping;
+
+extern int num_mappings();
+extern char *mapping_name(int i);
+extern void mapping_setup(mapping *m, double lo, double hi, int funcnum);
+extern void mapping_set_lo(mapping *m, double lo);
+extern void mapping_set_hi(mapping *m, double hi);
+extern void mapping_set_func(mapping *m, int funcnum);
+extern u_int32_t mapping_calc(mapping *m, double in);
Added: trunk/sushivision/objective.c
===================================================================
--- trunk/sushivision/objective.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/objective.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,64 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "sushivision.h"
+#include "internal.h"
+
+int sushiv_new_objective(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ double(*callback)(double *),
+ unsigned flags){
+ sushiv_objective_t *o;
+
+ if(number<0){
+ fprintf(stderr,"Objective number must be >= 0\n");
+ return -EINVAL;
+ }
+
+ if(number<s->objectives){
+ if(s->objective_list[number]!=NULL){
+ fprintf(stderr,"Objective number %d already exists\n",number);
+ return -EINVAL;
+ }
+ }else{
+ if(s->objectives == 0){
+ s->objective_list = calloc (number+1,sizeof(*s->objective_list));
+ }else{
+ s->objective_list = realloc (s->objective_list,(number+1) * sizeof(*s->objective_list));
+ memset(s->objective_list + s->objectives, 0, sizeof(*s->objective_list)*(number +1 - s->objectives));
+ }
+ s->objectives=number+1;
+ }
+
+ o = s->objective_list[number] = calloc(1, sizeof(**s->objective_list));
+ o->number = number;
+ o->name = strdup(name);
+ o->flags = flags;
+ o->sushi = s;
+ o->panel = NULL;
+ o->callback = callback;
+ return 0;
+}
Added: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/panel-2d.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,671 @@
+/*
+ *
+ * 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 "sushivision.h"
+#include "mapping.h"
+#include "plot.h"
+#include "slice.h"
+#include "slider.h"
+#include "panel-2d.h"
+#include "internal.h"
+
+static void render_checks(int w, int y, u_int32_t *render){
+ int x,j;
+ /* default checked background */
+ /* 16x16 'mid-checks' */
+ int phase = (y>>4)&1;
+ for(x=0;x<w;){
+ u_int32_t phaseval = 0x505050;
+ if(phase) phaseval = 0x808080;
+ for(j=0;j<16 && x<w;j++,x++)
+ render[x] = phaseval;
+ phase=!phase;
+ }
+}
+
+/* called from idle handler only, and as such, we can be sure we're
+ locked and uninterruptable */
+void _sushiv_panel2d_map_redraw(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ Plot *plot = PLOT(p2->graph);
+
+ int w,h,x,y,i;
+ w = p2->data_w;
+ h = p2->data_h;
+
+ if(plot){
+ u_int32_t render[w];
+
+ /* iterate */
+ /* by line */
+ for(y = 0; y<h; y++){
+
+ render_checks(w,y,render);
+
+ /* by objective */
+ for(i=0;i<p->objectives;i++){
+ double *data_rect = p2->data_rect[i] + y*w;
+ double alpha = p2->alphadel[i];
+
+ /* by x */
+ for(x=0;x<w;x++){
+ double val = data_rect[x];
+
+ /* map/render result */
+ if(!isnan(val) && val>=alpha)
+ render[x] = mapping_calc(p2->mappings+i,val);
+
+ }
+ }
+
+ /* store result in panel */
+ memcpy(plot->datarect+y*w,render,w*sizeof(*render));
+ }
+ plot_expose_request(plot);
+ }
+}
+
+static void mapchange_callback_2d(GtkWidget *w,gpointer in){
+ sushiv_objective_t **optr = (sushiv_objective_t **)in;
+ sushiv_objective_t *o = *optr;
+ sushiv_panel_t *p = o->panel;
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ int onum = optr - p->objective_list;
+
+ mapping_set_func(&p2->mappings[onum],gtk_combo_box_get_active(GTK_COMBO_BOX(w)));
+
+ //redraw the map slider
+ slider_draw_background(p2->range_scales[onum]);
+ slider_draw(p2->range_scales[onum]);
+ slider_expose(p2->range_scales[onum]);
+
+ //redraw the plot
+ _sushiv_panel_dirty_map(p);
+}
+
+static void map_callback_2d(void *in){
+ sushiv_objective_t **optr = (sushiv_objective_t **)in;
+ sushiv_objective_t *o = *optr;
+ sushiv_panel_t *p = o->panel;
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ int onum = optr - p->objective_list;
+
+ // recache alpha del */
+ p2->alphadel[onum] =
+ slider_val_to_del(p2->range_scales[onum],
+ slider_get_value(p2->range_scales[onum],1));
+
+ //redraw the plot
+ _sushiv_panel_dirty_map(p);
+}
+
+static void update_xy_availability(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ int i;
+ // update which x/y buttons are pressable */
+ // enable/disable dimension slider thumbs
+ for(i=0;i<p->dimensions;i++){
+ if(p2->dim_xb[i] &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_xb[i]))){
+ // make the y insensitive
+ if(p2->dim_yb[i])
+ gtk_widget_set_sensitive(p2->dim_yb[i],FALSE);
+ // set the dim x flag
+ p->dimension_list[i]->flags |= SUSHIV_X_DIM;
+ }else{
+ // if there is a y, make it sensitive
+ if(p2->dim_yb[i])
+ gtk_widget_set_sensitive(p2->dim_yb[i],TRUE);
+ // unset dim x flag
+ p->dimension_list[i]->flags &= ~SUSHIV_X_DIM;
+ }
+ if(p2->dim_yb[i] &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_yb[i]))){
+ // make the x insensitive
+ if(p2->dim_xb[i])
+ gtk_widget_set_sensitive(p2->dim_xb[i],FALSE);
+ // set the dim y flag
+ p->dimension_list[i]->flags |= SUSHIV_Y_DIM;
+ }else{
+ // if there is a x, make it sensitive
+ if(p2->dim_xb[i])
+ gtk_widget_set_sensitive(p2->dim_xb[i],TRUE);
+ // unset dim y flag
+ p->dimension_list[i]->flags &= ~SUSHIV_Y_DIM;
+ }
+ if((p2->dim_xb[i] &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_xb[i]))) ||
+ (p2->dim_yb[i] &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_yb[i])))){
+ // make all thumbs visible
+ slider_set_thumb_active(p2->dim_scales[i],0,1);
+ slider_set_thumb_active(p2->dim_scales[i],2,1);
+ }else{
+ // make bracket thumbs invisible */
+ slider_set_thumb_active(p2->dim_scales[i],0,0);
+ slider_set_thumb_active(p2->dim_scales[i],2,0);
+ }
+ }
+}
+
+static void compute_one_line_2d(sushiv_panel_t *p,
+ int serialno,
+ int y,
+ int x_d,
+ double x_min,
+ double x_max,
+ int w,
+ double *dim_vals,
+ u_int32_t *render){
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ double work[w];
+ double inv_w = 1./w;
+ int i,j;
+
+ render_checks(w,y,render);
+ gdk_threads_enter (); // misuse me as a global mutex
+
+ /* by objective */
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i];
+ double alpha = p2->alphadel[i];
+
+ gdk_threads_leave (); // misuse me as a global mutex
+
+ /* 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;
+ work[j] = o->callback(dim_vals);
+
+ }
+
+ gdk_threads_enter (); // misuse me as a global mutex
+ if(p2->serialno == serialno){
+
+ /* map/render result */
+ for(j=0;j<w;j++){
+ double val = slider_val_to_del(p2->range_scales[i],work[j]);
+ work[j] = val;
+
+ if(!isnan(val) && val>=alpha)
+ render[j] = mapping_calc(p2->mappings+i,val);
+
+ }
+
+ /* store result in panel */
+ memcpy(p2->data_rect[i]+y*w,work,w*sizeof(*work));
+ }else
+ break;
+ }
+ gdk_threads_leave (); // misuse me as a global mutex
+}
+
+static int v_swizzle(int y, int height){
+ int yy = height >> 5;
+ if(y < yy)
+ return (y<<5)+31;
+
+ y -= yy;
+ yy = (height+16) >> 5;
+ if(y < yy)
+ return (y<<5)+15;
+
+ y -= yy;
+ yy = (height+8) >> 4;
+ if(y < yy)
+ return (y<<4)+7;
+
+ y -= yy;
+ yy = (height+4) >> 3;
+ if(y < yy)
+ return (y<<3)+3;
+
+ y -= yy;
+ yy = (height+2) >> 2;
+ if(y < yy)
+ return (y<<2)+1;
+
+ y -= yy;
+ return y<<1;
+}
+
+// call only from main gtk thread!
+void _mark_recompute_2d(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ Plot *plot = PLOT(p2->graph);
+
+ if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
+ if(p2->data_w != plot->w.allocation.width ||
+ p2->data_h != plot->w.allocation.height){
+ if(p2->data_rect){
+ int i;
+ for(i=0;i<p->objectives;i++)
+ free(p2->data_rect[i]);
+ free(p2->data_rect);
+ p2->data_rect = NULL;
+ }
+
+ }
+
+ p2->data_w = plot->w.allocation.width;
+ p2->data_h = plot->w.allocation.height;
+ p2->serialno++;
+ p2->last_line = 0;
+
+ if(!p2->data_rect){
+ int i;
+ // allocate it
+ p2->data_rect = calloc(p->objectives,sizeof(*p2->data_rect));
+ for(i=0;i<p->objectives;i++)
+ p2->data_rect[i] = malloc(p2->data_w * p2->data_h* sizeof(**p2->data_rect));
+ }
+ {
+ int i,j;
+ // blank it
+ for(i=0;i<p->objectives;i++)
+ for(j=0;j<p2->data_w*p2->data_h;j++)
+ p2->data_rect[i][j]=NAN;
+ _sushiv_panel2d_map_redraw(p);
+ }
+
+ _sushiv_wake_workers();
+ }
+}
+
+static void recompute_callback_2d(void *ptr){
+ sushiv_panel_t *p = (sushiv_panel_t *)ptr;
+ _mark_recompute_2d(p);
+}
+
+static void dim_callback_2d(void *in){
+ sushiv_dimension_t **dptr = (sushiv_dimension_t **)in;
+ sushiv_dimension_t *d = *dptr;
+ sushiv_panel_t *p = d->panel;
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ int dnum = dptr - p->dimension_list;
+
+ int axisp = (d->flags & SUSHIV_DIM_MASK);
+
+ d->val = slider_get_value(p2->dim_scales[dnum],1);
+
+ // if the mid slider of a non-axis dimension changed, rerender
+ if(!axisp){
+ _mark_recompute_2d(p);
+ return;
+ }else{
+
+ // if the mid slider of an axis dimension changed, move crosshairs
+ double x=0,y=0;
+ int i;
+
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = p->dimension_list[i];
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ if(d->flags & SUSHIV_X_DIM)
+ x = slider_get_value(p2->dim_scales[i],1);
+ if(d->flags & SUSHIV_Y_DIM)
+ y = slider_get_value(p2->dim_scales[i],1);
+
+ }
+
+ plot_set_crosshairs(PLOT(p2->graph),x,y);
+
+ }
+
+}
+
+static void bracket_callback_2d(void *in){
+ sushiv_dimension_t **dptr = (sushiv_dimension_t **)in;
+ sushiv_dimension_t *d = *dptr;
+ sushiv_panel_t *p = d->panel;
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ int dnum = dptr - p->dimension_list;
+
+ int axisp = (d->flags & SUSHIV_DIM_MASK);
+
+ d->bracket[0] = slider_get_value(p2->dim_scales[dnum],0);
+ d->bracket[1] = slider_get_value(p2->dim_scales[dnum],2);
+
+ // if the bracketing of an axis dimension changed, rerender
+ if(axisp)
+ _mark_recompute_2d(p);
+
+}
+
+static void dimchange_callback_2d(GtkWidget *button,gpointer in){
+ sushiv_panel_t *p = (sushiv_panel_t *)in;
+
+ update_xy_availability(p);
+ _mark_recompute_2d(p);
+}
+
+static void crosshairs_callback(void *in){
+ sushiv_panel_t *p = (sushiv_panel_t *)in;
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ double x=PLOT(p2->graph)->selx_val;
+ double y=PLOT(p2->graph)->sely_val;
+ int i;
+
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = p->dimension_list[i];
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ if(d->flags & SUSHIV_X_DIM)
+ slider_set_value(p2->dim_scales[i],1,x);
+ if(d->flags & SUSHIV_Y_DIM)
+ slider_set_value(p2->dim_scales[i],1,y);
+ }
+}
+
+// called from one/all of the worker threads; the idea is that several
+// of the threads will all call this and they collectively interleave
+// ongoing computation of the pane
+int _sushiv_panel_cooperative_compute_2d(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ Plot *plot;
+
+ int w,h,i,d;
+ int serialno;
+ double x_min, x_max;
+ double y_min, y_max;
+ double invh;
+ int x_d=-1, y_d=-1;
+
+ // lock during setup
+ gdk_threads_enter ();
+ w = p2->data_w;
+ h = p2->data_h;
+
+ if(p2->last_line>=h){
+ gdk_threads_leave ();
+ return 0;
+ }
+
+ plot = PLOT(p2->graph);
+ serialno = p2->serialno;
+ invh = 1./h;
+ d = p->dimensions;
+
+ /* render using local dimension array; several threads will be
+ computing objectives */
+ double dim_vals[d];
+
+ /* render into temporary line; computation may be interrupted by
+ events such as resizing, so we must be careful to simply assume
+ the widget is unaltered between locks. This allows us to minimize
+ checks. */
+ u_int32_t render[w];
+
+ /* which dim is our x? Our y? */
+ for(i=0;i<d;i++){
+ sushiv_dimension_t *dim = p->dimension_list[i];
+ if((dim->flags & SUSHIV_DIM_MASK) == SUSHIV_X_DIM ){
+ x_d = dim->number;
+ x_min = dim->bracket[0];
+ x_max = dim->bracket[1];
+ break;
+ }
+ }
+
+ for(i=0;i<d;i++){
+ sushiv_dimension_t *dim = p->dimension_list[i];
+ if((dim->flags & SUSHIV_DIM_MASK) == SUSHIV_Y_DIM){
+ y_d = dim->number;
+ y_min = dim->bracket[0];
+ y_max = dim->bracket[1];
+ break;
+ }
+ }
+
+ // Bulletproofing; shouldn't ever come up
+ if(x_d == y_d || x_d==-1 || y_d==-1){
+ gdk_threads_leave ();
+ fprintf(stderr,"Invalid/missing x/y dimension setting in panel x_d=%d, y_d=%d\n",
+ x_d,y_d);
+ return 0;
+ }
+
+ // Initialize local dimension value array
+ for(i=0;i<d;i++){
+ sushiv_dimension_t *dim = p->dimension_list[i];
+ dim_vals[i]=dim->val;
+ }
+
+ // update scales if we're just starting
+ if(p2->last_line==0){
+ plot_set_x_scale(PLOT(p2->graph),x_min,x_max);
+ plot_set_y_scale(PLOT(p2->graph),y_min,y_max);
+ }
+
+ /* iterate */
+ /* by line */
+ while(!_sushiv_exiting){
+ int last = p2->last_line;
+ int y;
+ if(plot->w.allocation.height != h)break;
+ if(last>=h)break;
+ p2->last_line++;
+
+ /* unlock for computation */
+ gdk_threads_leave ();
+ y = v_swizzle(last,h);
+ dim_vals[y_d]= (y_max - y_min) * h * y;
+
+ /* compute line */
+ compute_one_line_2d(p, serialno, y, x_d, x_min, x_max, w, dim_vals, render);
+
+ /* move rendered line back into widget */
+ gdk_threads_enter ();
+ if(p2->serialno == serialno){
+ u_int32_t *line = plot_get_background_line(plot, y);
+ memcpy(line,render,w*sizeof(*render));
+ plot_expose_request_line(plot,y);
+ }else
+ break;
+ }
+
+ gdk_threads_leave ();
+ return 1;
+}
+
+void _sushiv_realize_panel2d(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ int i;
+ int lo = p->scale_val_list[0];
+ int hi = p->scale_val_list[p->scale_vals-1];
+
+ p2->toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect_swapped (G_OBJECT (p2->toplevel), "delete-event",
+ G_CALLBACK (_sushiv_clean_exit), (void *)SIGINT);
+
+ p2->top_table = gtk_table_new(2 + p->objectives,5,0);
+ gtk_container_add (GTK_CONTAINER (p2->toplevel), p2->top_table);
+ gtk_container_set_border_width (GTK_CONTAINER (p2->toplevel), 5);
+
+ p2->dim_table = gtk_table_new(p->dimensions,6,0);
+ gtk_table_attach(GTK_TABLE(p2->top_table),p2->dim_table,0,5,1+p->objectives,2+p->objectives,
+ GTK_EXPAND|GTK_FILL,0,0,5);
+
+ /* graph */
+ p2->graph = GTK_WIDGET(plot_new(recompute_callback_2d,p,
+ crosshairs_callback,p));
+ gtk_table_attach(GTK_TABLE(p2->top_table),p2->graph,0,5,0,1,
+ GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,5);
+
+ /* objective sliders */
+ p2->range_scales = calloc(p->objectives,sizeof(*p2->range_scales));
+ p2->alphadel = calloc(p->objectives,sizeof(*p2->alphadel));
+ p2->mappings = calloc(p->objectives,sizeof(*p2->mappings));
+ for(i=0;i<p->objectives;i++){
+ GtkWidget **sl = calloc(3,sizeof(*sl));
+ sushiv_objective_t *o = p->objective_list[i];
+
+ /* label */
+ GtkWidget *label = gtk_label_new(o->name);
+ gtk_table_attach(GTK_TABLE(p2->top_table),label,0,1,i+1,i+2,
+ 0,0,10,0);
+
+ /* mapping pulldown */
+ {
+ GtkWidget *menu=gtk_combo_box_new_text();
+ int j;
+ for(j=0;j<num_mappings();j++)
+ gtk_combo_box_append_text (GTK_COMBO_BOX (menu), mapping_name(j));
+ gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
+ g_signal_connect (G_OBJECT (menu), "changed",
+ G_CALLBACK (mapchange_callback_2d), p->objective_list+i);
+ gtk_table_attach(GTK_TABLE(p2->top_table),menu,4,5,i+1,i+2,
+ GTK_SHRINK,GTK_SHRINK,5,0);
+ }
+
+ /* the range mapping slices/slider */
+ sl[0] = slice_new(map_callback_2d,p->objective_list+i);
+ sl[1] = slice_new(map_callback_2d,p->objective_list+i);
+ sl[2] = slice_new(map_callback_2d,p->objective_list+i);
+
+ gtk_table_attach(GTK_TABLE(p2->top_table),sl[0],1,2,i+1,i+2,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+ gtk_table_attach(GTK_TABLE(p2->top_table),sl[1],2,3,i+1,i+2,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+ gtk_table_attach(GTK_TABLE(p2->top_table),sl[2],3,4,i+1,i+2,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+ p2->range_scales[i] = slider_new((Slice **)sl,3,p->scale_label_list,p->scale_val_list,
+ p->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);
+ mapping_setup(&p2->mappings[i],0.,1.,0);
+ slider_set_gradient(p2->range_scales[i], &p2->mappings[i]);
+ }
+
+ GtkWidget *first_x = NULL;
+ GtkWidget *first_y = NULL;
+ GtkWidget *pressed_y = NULL;
+ p2->dim_scales = calloc(p->dimensions,sizeof(*p2->dim_scales));
+ p2->dim_xb = calloc(p->dimensions,sizeof(*p2->dim_xb));
+ p2->dim_yb = calloc(p->dimensions,sizeof(*p2->dim_yb));
+
+ for(i=0;i<p->dimensions;i++){
+ GtkWidget **sl = calloc(3,sizeof(*sl));
+ sushiv_dimension_t *d = p->dimension_list[i];
+
+ /* label */
+ GtkWidget *label = gtk_label_new(d->name);
+ gtk_table_attach(GTK_TABLE(p2->dim_table),label,0,1,i,i+1,
+ 0,0,10,0);
+
+ /* x/y radio buttons */
+ if(d->flags & SUSHIV_X_RANGE){
+ if(first_x)
+ p2->dim_xb[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_x),"X");
+ else{
+ first_x = p2->dim_xb[i] = gtk_radio_button_new_with_label(NULL,"X");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2->dim_xb[i]),TRUE);
+ }
+ gtk_table_attach(GTK_TABLE(p2->dim_table),p2->dim_xb[i],1,2,i,i+1,
+ 0,0,10,0);
+ }
+
+ if(d->flags & SUSHIV_Y_RANGE){
+ if(first_y)
+ p2->dim_yb[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_y),"Y");
+ else
+ first_y = p2->dim_yb[i] = gtk_radio_button_new_with_label(NULL,"Y");
+ if(!pressed_y && p2->dim_xb[i]!=first_x){
+ pressed_y = p2->dim_yb[i];
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2->dim_yb[i]),TRUE);
+ }
+ gtk_table_attach(GTK_TABLE(p2->dim_table),p2->dim_yb[i],2,3,i,i+1,
+ 0,0,10,0);
+ }
+
+ /* the dimension slices/slider */
+ sl[0] = slice_new(bracket_callback_2d,p->dimension_list+i);
+ sl[1] = slice_new(dim_callback_2d,p->dimension_list+i);
+ sl[2] = slice_new(bracket_callback_2d,p->dimension_list+i);
+
+ gtk_table_attach(GTK_TABLE(p2->dim_table),sl[0],3,4,i,i+1,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+ gtk_table_attach(GTK_TABLE(p2->dim_table),sl[1],4,5,i,i+1,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+ gtk_table_attach(GTK_TABLE(p2->dim_table),sl[2],5,6,i,i+1,
+ GTK_EXPAND|GTK_FILL,0,0,0);
+
+ p2->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(p2->dim_xb[i])
+ g_signal_connect (G_OBJECT (p2->dim_xb[i]), "toggled",
+ G_CALLBACK (dimchange_callback_2d), p);
+ if(p2->dim_yb[i])
+ g_signal_connect (G_OBJECT (p2->dim_yb[i]), "toggled",
+ G_CALLBACK (dimchange_callback_2d), p);
+ }
+ update_xy_availability(p);
+
+
+ gtk_widget_realize(p2->toplevel);
+ gtk_widget_realize(p2->graph);
+ gtk_widget_show_all(p2->toplevel);
+}
+
+int sushiv_new_panel_2d(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ unsigned scalevals,
+ double *scaleval_list,
+ int *objectives,
+ int *dimensions,
+ unsigned flags){
+
+ int ret = _sushiv_new_panel(s,number,name,scalevals,scaleval_list,
+ objectives,dimensions,flags);
+ sushiv_panel_t *p;
+ sushiv_panel2d_t *p2;
+
+ if(ret<0)return ret;
+ p = s->panel_list[number];
+ p2 = calloc(1, sizeof(*p2));
+ p->internal = p2;
+ p->type = SUSHIV_PANEL_2D;
+
+ return 0;
+}
+
Added: trunk/sushivision/panel-2d.h
===================================================================
--- trunk/sushivision/panel-2d.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/panel-2d.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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_panel2d {
+
+ GtkWidget *toplevel;
+ GtkWidget *graph;
+ GtkWidget *top_table;
+ GtkWidget *dim_table;
+
+ int data_w;
+ int data_h;
+ int serialno;
+ double **data_rect;
+
+ mapping *mappings;
+ Slider **range_scales;
+ GtkWidget **range_pulldowns;
+ double *alphadel;
+
+ Slider **dim_scales;
+ GtkWidget **dim_xb;
+ GtkWidget **dim_yb;
+
+ int last_line;
+ int dirty_flag;
+} sushiv_panel2d_t;
+
+extern void _sushiv_realize_panel2d(sushiv_panel_t *p);
+extern int _sushiv_panel_cooperative_compute_2d(sushiv_panel_t *p);
+extern void _sushiv_panel2d_map_redraw(sushiv_panel_t *p);
Added: trunk/sushivision/panel.c
===================================================================
--- trunk/sushivision/panel.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/panel.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,205 @@
+/*
+ *
+ * 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 "sushivision.h"
+#include "mapping.h"
+#include "plot.h"
+#include "slice.h"
+#include "slider.h"
+#include "panel-2d.h"
+#include "internal.h"
+
+void _sushiv_realize_panel(sushiv_panel_t *p){
+ if(!p->realized){
+ switch(p->type){
+ case SUSHIV_PANEL_1D:
+ //_sushiv_realize_panel1d(p);
+ break;
+ case SUSHIV_PANEL_2D:
+ _sushiv_realize_panel2d(p);
+ break;
+ }
+ p->realized=1;
+ }
+}
+
+int sushiv_panel_set_scale(sushiv_panel_t *d, unsigned scalevals,
+ double *scaleval_list){
+ int i;
+
+ if(scalevals<2){
+ fprintf(stderr,"Scale requires at least two scale values.");
+ return -EINVAL;
+ }
+
+ if(d->scale_val_list)free(d->scale_val_list);
+ if(d->scale_label_list){
+ for(i=0;i<d->scale_vals;i++)
+ free(d->scale_label_list[i]);
+ free(d->scale_label_list);
+ }
+
+ // copy values
+ d->scale_vals = scalevals;
+ d->scale_val_list = calloc(scalevals,sizeof(*d->scale_val_list));
+ for(i=0;i<(int)scalevals;i++)
+ d->scale_val_list[i] = scaleval_list[i];
+
+ // generate labels
+ d->scale_label_list = scale_generate_labels(scalevals,scaleval_list);
+
+ return 0;
+}
+
+int sushiv_panel_set_scalelabels(sushiv_panel_t *d, char **scalelabel_list){
+ int i;
+ for(i=0;i<d->scale_vals;i++){
+ if(d->scale_label_list[i])
+ free(d->scale_label_list[i]);
+ d->scale_label_list[i] = strdup(scalelabel_list[i]);
+ }
+ return 0;
+}
+
+static void _sushiv_panel_map_redraw(sushiv_panel_t *p){
+ if(p->maps_dirty){
+ p->maps_dirty = 0;
+ switch(p->type){
+ case SUSHIV_PANEL_1D:
+ //_sushiv_panel1d_map_redraw(p);
+ break;
+ case SUSHIV_PANEL_2D:
+ _sushiv_panel2d_map_redraw(p);
+ break;
+ }
+ }
+}
+
+int _sushiv_panel_cooperative_compute(sushiv_panel_t *p){
+ if(p->realized){
+ if(p->type == SUSHIV_PANEL_2D)
+ return _sushiv_panel_cooperative_compute_2d(p);
+ }
+ return 0;
+}
+
+/* doesn't take an unbounded period, but shouldn't be
+ synchronous in the interests of responsiveness. */
+static gboolean _map_idle_work(gpointer ptr){
+ sushiv_instance_t *s = (sushiv_instance_t *)ptr;
+ int i;
+
+ for(i=0;i<s->panels;i++)
+ _sushiv_panel_map_redraw(s->panel_list[i]);
+
+ return FALSE;
+}
+
+
+void _sushiv_panel_dirty_map(sushiv_panel_t *p){
+ p->maps_dirty = 1;
+ g_idle_add(_map_idle_work,p->sushi);
+}
+
+int _sushiv_new_panel(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ unsigned scalevals,
+ double *scaleval_list,
+ int *objectives,
+ int *dimensions,
+ unsigned flags){
+
+ sushiv_panel_t *p;
+ int i;
+
+ if(number<0){
+ fprintf(stderr,"Panel number must be >= 0\n");
+ return -EINVAL;
+ }
+
+ if(number<s->panels){
+ if(s->panel_list[number]!=NULL){
+ fprintf(stderr,"Panel number %d already exists\n",number);
+ return -EINVAL;
+ }
+ }else{
+ if(s->panels == 0){
+ s->panel_list = calloc (number+1,sizeof(*s->panel_list));
+ }else{
+ s->panel_list = realloc (s->panel_list,(number+1) * sizeof(*s->panel_list));
+ memset(s->panel_list + s->panels, 0, sizeof(*s->panel_list)*(number+1 - s->panels));
+ }
+ s->panels = number+1;
+ }
+
+ p = s->panel_list[number] = calloc(1, sizeof(**s->panel_list));
+
+ p->number = number;
+ p->name = strdup(name);
+ p->flags = flags;
+ p->sushi = s;
+
+ i=0;
+ while(objectives && objectives[i]>=0)i++;
+ p->objectives = i;
+ p->objective_list = malloc(i*sizeof(*p->objective_list));
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = s->objective_list[objectives[i]];
+ if(o->panel){
+ fprintf(stderr,"Objective %d already in use with another panel\n",o->number);
+ return -EINVAL;
+ }
+ o->panel = p;
+ p->objective_list[i] = o;
+
+ }
+
+ i=0;
+ while(dimensions && dimensions[i]>=0)i++;
+ p->dimensions = i;
+ p->dimension_list = malloc(i*sizeof(*p->dimension_list));
+ for(i=0;i<p->dimensions;i++){
+ sushiv_dimension_t *d = s->dimension_list[dimensions[i]];
+ if(d->panel){
+ fprintf(stderr,"Dimension %d already in use with another panel\n",d->number);
+ return -EINVAL;
+ }
+ d->panel = p;
+ p->dimension_list[i] = d;
+ }
+
+ sushiv_panel_set_scale(p, scalevals, scaleval_list);
+
+ return number;
+}
+
Added: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/plot.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,492 @@
+/*
+ *
+ * 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 <gtk/gtk.h>
+#include <gtk/gtkmain.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+
+#include "plot.h"
+
+static GtkWidgetClass *parent_class = NULL;
+
+static void draw_scales(Plot *p){
+ GtkWidget *widget = GTK_WIDGET(p);
+ cairo_t *c = cairo_create(p->fore);
+ int i=0,x,y;
+ char buffer[80];
+
+ cairo_save(c);
+ cairo_set_operator(c,CAIRO_OPERATOR_CLEAR);
+ cairo_set_source_rgba (c, 1,1,1,1);
+ cairo_paint(c);
+ cairo_restore(c);
+
+ // draw all axis lines, then stroke
+ cairo_save(c);
+ cairo_set_operator(c,CAIRO_OPERATOR_XOR);
+
+ cairo_set_line_width(c,1.);
+ cairo_set_source_rgba(c,.7,.7,1.,.3);
+
+ i=0;
+ x=scalespace_mark(&p->x,i++);
+ while(x < widget->allocation.width){
+ cairo_move_to(c,x+.5,0);
+ cairo_line_to(c,x+.5,widget->allocation.height);
+ x=scalespace_mark(&p->x,i++);
+ }
+
+ i=0;
+ y=scalespace_mark(&p->y,i++);
+ while(y < widget->allocation.height){
+ cairo_move_to(c,0,widget->allocation.height-y+.5);
+ cairo_line_to(c,widget->allocation.width,widget->allocation.height-y+.5);
+ y=scalespace_mark(&p->y,i++);
+ }
+ cairo_stroke(c);
+ cairo_restore(c);
+
+ // text labels
+ cairo_select_font_face (c, "Sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (c, 10);
+ cairo_set_line_width(c,2);
+
+ i=0;
+ y=scalespace_mark(&p->y,i);
+ scalespace_label(&p->y,i++,buffer);
+
+ while(y < widget->allocation.height){
+ cairo_text_extents_t extents;
+ cairo_text_extents (c, buffer, &extents);
+
+ if(y - extents.height > 0){
+
+ double yy = widget->allocation.height-y+.5-(extents.height/2 + extents.y_bearing);
+
+ cairo_move_to(c,2, yy);
+ cairo_set_source_rgba(c,0,0,0,.5);
+ cairo_text_path (c, buffer);
+ cairo_stroke(c);
+
+ cairo_set_source_rgba(c,1.,1.,1.,1.);
+ cairo_move_to(c,2, yy);
+ cairo_show_text (c, buffer);
+ }
+
+ y=scalespace_mark(&p->y,i);
+ scalespace_label(&p->y,i++,buffer);
+ }
+
+ i=0;
+ x=scalespace_mark(&p->x,i);
+ scalespace_label(&p->x,i++,buffer);
+
+ {
+ cairo_matrix_t m = {0.,-1., 1.,0., 0.,widget->allocation.height};
+ cairo_set_matrix(c,&m);
+ }
+
+ while(x < widget->allocation.width){
+ cairo_text_extents_t extents;
+ cairo_text_extents (c, buffer, &extents);
+
+ if(x - extents.height > 0){
+
+ cairo_move_to(c,2, x+.5-(extents.height/2 + extents.y_bearing));
+ cairo_set_source_rgba(c,0,0,0,.5);
+ cairo_text_path (c, buffer);
+ cairo_stroke(c);
+
+ cairo_move_to(c,2, x+.5-(extents.height/2 + extents.y_bearing));
+ cairo_set_source_rgba(c,1.,1.,1.,1.);
+ cairo_show_text (c, buffer);
+ }
+
+ x=scalespace_mark(&p->x,i);
+ scalespace_label(&p->x,i++,buffer);
+ }
+
+ cairo_destroy(c);
+}
+
+
+static void plot_init (Plot *p){
+ // instance initialization
+ p->scalespacing = 50;
+ p->x = scalespace_linear(0.0,1.0,400,p->scalespacing);
+ p->y = scalespace_linear(0.0,1.0,200,p->scalespacing);
+}
+
+static void plot_destroy (GtkObject *object){
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+
+ GtkWidget *widget = GTK_WIDGET(object);
+ Plot *p = PLOT (widget);
+ // free local resources
+ if(p->wc){
+ cairo_destroy(p->wc);
+ p->wc=0;
+ }
+ if(p->back){
+ cairo_surface_destroy(p->back);
+ p->back=0;
+ }
+ if(p->fore){
+ cairo_surface_destroy(p->fore);
+ p->fore=0;
+ }
+ if(p->stage){
+ cairo_surface_destroy(p->stage);
+ p->stage=0;
+ }
+
+}
+
+void plot_draw (Plot *p,
+ int x, int y, int w, int h){
+
+ GtkWidget *widget = GTK_WIDGET(p);
+
+ if (GTK_WIDGET_REALIZED (widget)){
+
+ cairo_t *c = cairo_create(p->stage);
+ cairo_set_source_surface(c,p->back,0,0);
+ cairo_rectangle(c,x,y,w,h);
+ cairo_fill(c);
+
+ cairo_set_source_surface(c,p->fore,0,0);
+ cairo_rectangle(c,x,y,w,h);
+ cairo_fill(c);
+
+ // transient foreground
+ cairo_set_source_rgba(c,1.,1.,1.,.6);
+ cairo_set_line_width(c,1.);
+ cairo_move_to(c,0,p->sely+.5);
+ cairo_line_to(c,widget->allocation.width,p->sely+.5);
+ cairo_move_to(c,p->selx+.5,0);
+ cairo_line_to(c,p->selx+.5,widget->allocation.height);
+ cairo_stroke(c);
+
+ cairo_destroy(c);
+
+ // blit to window
+ cairo_set_source_surface(p->wc,p->stage,0,0);
+ cairo_rectangle(p->wc,x,y,w,h);
+ cairo_fill(p->wc);
+
+ }
+}
+
+static gint plot_expose (GtkWidget *widget,
+ GdkEventExpose *event){
+ if (GTK_WIDGET_REALIZED (widget)){
+ Plot *p = PLOT (widget);
+
+ int x = event->area.x;
+ int y = event->area.y;
+ int w = event->area.width;
+ int h = event->area.height;
+
+ plot_draw(p, x, y, w, h);
+
+ }
+ return FALSE;
+}
+
+static void plot_size_request (GtkWidget *widget,
+ GtkRequisition *requisition){
+ requisition->width = 400; // XXX
+ requisition->height = 200; // XXX
+}
+
+static void plot_realize (GtkWidget *widget){
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask =
+ gtk_widget_get_events (widget) |
+ GDK_EXPOSURE_MASK|
+ GDK_POINTER_MOTION_MASK|
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK|
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_STRUCTURE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK;
+
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ widget->window = gdk_window_new (widget->parent->window,
+ &attributes, attributes_mask);
+ gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+ gdk_window_set_user_data (widget->window, widget);
+ gtk_widget_set_double_buffered (widget, FALSE);
+}
+
+static void plot_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation){
+ Plot *p = PLOT (widget);
+
+ if (GTK_WIDGET_REALIZED (widget)){
+
+ if(p->wc)
+ cairo_destroy(p->wc);
+ if (p->fore)
+ cairo_surface_destroy(p->fore);
+ if (p->back)
+ cairo_surface_destroy(p->back);
+ if (p->stage)
+ cairo_surface_destroy(p->stage);
+
+ gdk_window_move_resize (widget->window, allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ p->wc = gdk_cairo_create(widget->window);
+
+ // the background is created from data
+ p->datarect = calloc(allocation->width * allocation->height,4);
+
+ p->back = cairo_image_surface_create_for_data ((unsigned char *)p->datarect,
+ CAIRO_FORMAT_RGB24,
+ allocation->width,
+ allocation->height,
+ allocation->width*4);
+
+ p->stage = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+ allocation->width,
+ allocation->height);
+ p->fore = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ allocation->width,
+ allocation->height);
+
+ }
+
+ widget->allocation = *allocation;
+ p->x = scalespace_linear(p->x.lo,p->x.hi,widget->allocation.width,p->scalespacing);
+ p->y = scalespace_linear(p->y.lo,p->y.hi,widget->allocation.height,p->scalespacing);
+ draw_scales(p);
+ if(p->recompute_callback)p->recompute_callback(p->app_data);
+
+}
+
+static gint mouse_motion(GtkWidget *widget,
+ GdkEventMotion *event){
+ //Plot *p = PLOT (widget);
+
+ return TRUE;
+}
+
+static gboolean mouse_press (GtkWidget *widget,
+ GdkEventButton *event){
+ //Plot *p = PLOT (widget);
+
+
+ return TRUE;
+}
+
+static gboolean mouse_release (GtkWidget *widget,
+ GdkEventButton *event){
+ Plot *p = PLOT (widget);
+ plot_expose_request(p);
+ p->selx = event->x;
+ p->sely = event->y;
+ p->selx_val = scalespace_value(&p->x,p->selx);
+ p->sely_val = scalespace_value(&p->y,widget->allocation.height-p->sely);
+
+ if(p->crosshairs_callback)
+ p->crosshairs_callback(p->cross_data);
+ plot_expose_request(p);
+
+ return TRUE;
+}
+
+static gboolean plot_enter (GtkWidget *widget,
+ GdkEventCrossing *event){
+ //Plot *p = PLOT (widget);
+
+ return TRUE;
+}
+
+static gboolean plot_leave (GtkWidget *widget,
+ GdkEventCrossing *event){
+ //Plot *p = PLOT (widget);
+
+ return TRUE;
+}
+
+static void plot_class_init (PlotClass * class) {
+
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = (GtkObjectClass *) class;
+ widget_class = (GtkWidgetClass *) class;
+
+ parent_class = gtk_type_class (GTK_TYPE_WIDGET);
+
+ object_class->destroy = plot_destroy;
+
+ widget_class->realize = plot_realize;
+ widget_class->expose_event = plot_expose;
+ widget_class->size_request = plot_size_request;
+ widget_class->size_allocate = plot_size_allocate;
+ widget_class->button_press_event = mouse_press;
+ widget_class->button_release_event = mouse_release;
+ widget_class->motion_notify_event = mouse_motion;
+ widget_class->enter_notify_event = plot_enter;
+ widget_class->leave_notify_event = plot_leave;
+
+}
+
+GType plot_get_type (void){
+
+ static GType plot_type = 0;
+
+ if (!plot_type)
+ {
+ static const GTypeInfo plot_info = {
+ sizeof (PlotClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) plot_class_init,
+ NULL,
+ NULL,
+ sizeof (Plot),
+ 0,
+ (GInstanceInitFunc) plot_init,
+ 0
+ };
+
+ plot_type = g_type_register_static (GTK_TYPE_WIDGET, "Plot",
+ &plot_info, 0);
+ }
+
+ return plot_type;
+}
+
+Plot *plot_new (void (*callback)(void *),void *app_data,
+ void (*cross_callback)(void *),void *cross_data) {
+ GtkWidget *g = GTK_WIDGET (g_object_new (PLOT_TYPE, NULL));
+ Plot *p = PLOT (g);
+ p->recompute_callback = callback;
+ p->app_data = app_data;
+ p->crosshairs_callback = cross_callback;
+ p->cross_data = cross_data;
+ return p;
+}
+
+void plot_expose_request(Plot *p){
+ GtkWidget *widget = GTK_WIDGET(p);
+ GdkRectangle r;
+
+ r.x=0;
+ r.y=0;
+ r.width=widget->allocation.width;
+ r.height=widget->allocation.height;
+
+ gdk_window_invalidate_rect (widget->window, &r, FALSE);
+}
+
+void plot_expose_request_line(Plot *p, int num){
+ GtkWidget *widget = GTK_WIDGET(p);
+ GdkRectangle r;
+
+ r.x=0;
+ r.y=num;
+ r.width=widget->allocation.width;
+ r.height=1;
+
+ gdk_window_invalidate_rect (widget->window, &r, FALSE);
+}
+
+void plot_draw_line(Plot *p, int num){
+ GtkWidget *widget = GTK_WIDGET(p);
+ //GdkRectangle r;
+
+ plot_draw(p,0,num,widget->allocation.width,1);
+}
+
+void plot_set_x_scale(Plot *p, double low, double high){
+ GtkWidget *widget = GTK_WIDGET(p);
+ scalespace temp = p->x;
+ p->x = scalespace_linear(low,high,widget->allocation.width,p->scalespacing);
+ p->selx = scalespace_pixel(&p->x,p->selx_val);
+ if(memcmp(&temp,&p->x,sizeof(temp)))
+ draw_scales(p);
+}
+
+void plot_set_y_scale(Plot *p, double low, double high){
+ GtkWidget *widget = GTK_WIDGET(p);
+ scalespace temp = p->y;
+ p->y = scalespace_linear(low,high,widget->allocation.height,p->scalespacing);
+ p->sely = widget->allocation.height - scalespace_pixel(&p->y,p->sely_val);
+
+ if(memcmp(&temp,&p->y,sizeof(temp)))
+ draw_scales(p);
+}
+
+void plot_set_x_name(Plot *p, char *name){
+ p->namex = name;
+ draw_scales(p);
+}
+
+void plot_set_y_name(Plot *p, char *name){
+ p->namey = name;
+ draw_scales(p);
+}
+
+u_int32_t *plot_get_background_line(Plot *p, int num){
+ GtkWidget *widget = GTK_WIDGET(p);
+ return p->datarect + num*widget->allocation.width;
+}
+
+cairo_t *plot_get_background_cairo(Plot *p){
+ return cairo_create(p->back);
+}
+
+void plot_set_crosshairs(Plot *p, double x, double y){
+ p->selx_val = x;
+ p->sely_val = y;
+ p->selx = scalespace_pixel(&p->x,x);
+ p->sely = GTK_WIDGET(p)->allocation.height - scalespace_pixel(&p->y,y);
+
+ plot_expose_request(p);
+}
Added: trunk/sushivision/plot.h
===================================================================
--- trunk/sushivision/plot.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/plot.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,87 @@
+/*
+ *
+ * sushivision copyright (C) 2005 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.
+ *
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <sys/types.h>
+#include "scale.h"
+
+G_BEGIN_DECLS
+
+#define PLOT_TYPE (plot_get_type ())
+#define PLOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLOT_TYPE, Plot))
+#define PLOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLOT_TYPE, PlotClass))
+#define IS_PLOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLOT_TYPE))
+#define IS_PLOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLOT_TYPE))
+
+typedef struct _Plot Plot;
+typedef struct _PlotClass PlotClass;
+
+struct _Plot{
+ GtkWidget w;
+ cairo_t *wc;
+ cairo_t *bc;
+ cairo_surface_t *back;
+ cairo_surface_t *fore;
+ cairo_surface_t *stage;
+
+ int scalespacing;
+ scalespace x;
+ scalespace y;
+ char *namex;
+ char *namey;
+
+ double selx_val;
+ double sely_val;
+ double selx;
+ double sely;
+
+ u_int32_t *datarect;
+ void *app_data;
+ void (*recompute_callback)(void *);
+ void *cross_data;
+ void (*crosshairs_callback)(void *);
+
+};
+
+struct _PlotClass{
+ GtkWidgetClass parent_class;
+ void (*plot) (Plot *m);
+};
+
+GType plot_get_type (void);
+Plot* plot_new (void (*callback)(void *),void *app_data,
+ void (*cross_callback)(void *),void *cross_data);
+
+G_END_DECLS
+
+// the widget subclass half
+void plot_expose_request(Plot *p);
+void plot_expose_request_line(Plot *p, int num);
+void plot_set_x_scale(Plot *p, double low, double high);
+void plot_set_y_scale(Plot *p, double low, double high);
+void plot_set_x_name(Plot *p, char *name);
+void plot_set_y_name(Plot *p, char *name);
+u_int32_t * plot_get_background_line(Plot *p, int num);
+cairo_t *plot_get_background_cairo(Plot *p);
+void plot_set_crosshairs(Plot *p, double x, double y);
Added: trunk/sushivision/scale.c
===================================================================
--- trunk/sushivision/scale.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/scale.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,227 @@
+/*
+ *
+ * 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 <math.h>
+#include <gtk/gtk.h>
+#include <cairo-ft.h>
+#include <fontconfig/fontconfig.h>
+#include <stdio.h>
+#include "scale.h"
+
+/* slider scales */
+static int trailing_zeroes(double A){
+ int count=0;
+ if(A<0)A=-A;
+ if(A==0)return 0;
+ A = floor(A);
+ A/=10;
+ while(A == floor(A)){
+ count++;
+ A/=10;
+ }
+ return count;
+}
+
+/* depth, at a minimum, must capture the difference between consective scale values */
+static int del_depth(double A, double B){
+ int depth = 0;
+
+ double del = B-A;
+ if(del<0)del=-del;
+ if(del != 0){
+ if(del<1){
+ float testdel=del;
+ while(testdel<1){
+ depth++;
+ testdel = del * pow(10,depth);
+ }
+ }else{
+ float testdel=del;
+ while(testdel>10){
+ depth--;
+ testdel = del / pow(10,-depth);
+ }
+ }
+ }
+ return depth;
+}
+
+static int abs_depth(double A){
+ int depth = 0;
+
+ if(A<0)A=-A;
+ if(A != 0){
+ if(A<1){
+ /* first ratchet down to find the beginning */
+ while(A * pow(10.,depth) < 1)
+ depth++;
+
+ /* look for trailing zeroes; assume a reasonable max depth */
+ depth+=5;
+
+ A*=pow(10.,depth);
+ int zero0 = trailing_zeroes(A);
+ int zeroN = trailing_zeroes(A-1);
+ int zeroP = trailing_zeroes(A+1);
+
+ if(zero0 >= zeroN && zero0 >= zeroP)
+ depth -= zero0;
+ else if(zeroN >= zero0 && zeroN >= zeroP)
+ depth -= zeroN;
+ else
+ depth -=zeroP;
+
+ }else
+ // Max at five sig figs, less if trailing zeroes... */
+ depth= 5-trailing_zeroes(A*100000.);
+ }
+
+ return depth;
+}
+
+static char *generate_label(double val,int depth){
+ char *ret;
+
+ if(depth>0){
+ asprintf(&ret,"%.*f",depth,val);
+ }else{
+ asprintf(&ret,"%ld",(long)val);
+ }
+ return ret;
+}
+
+/* default scale label generation is hard, but fill it in in an ad-hoc
+ fashion. Add flags to help out later */
+char **scale_generate_labels(unsigned scalevals, double *scaleval_list){
+ unsigned i;
+ int depth;
+ char **ret;
+
+ // default behavior; display each scale label at a uniform decimal
+ // depth. Begin by finding the smallest significant figure in any
+ // label. Since they're being passed in explicitly, they'll be
+ // pre-hinted to the app's desires. Deal with rounding. */
+
+ if(scalevals<2){
+ fprintf(stderr,"Scale requires at least two scale values.");
+ return NULL;
+ }
+
+ depth = del_depth(scaleval_list[0],scaleval_list[1]);
+
+ for(i=2;i<scalevals;i++){
+ int val = del_depth(scaleval_list[i-1],scaleval_list[i]);
+ if(val>depth)depth=val;
+ }
+
+ for(i=0;i<scalevals;i++){
+ int val = abs_depth(scaleval_list[i]);
+ if(val>depth)depth=val;
+ }
+
+ ret = calloc(scalevals,sizeof(*ret));
+ for(i=0;i<scalevals;i++)
+ ret[i] = generate_label(scaleval_list[i],depth);
+
+ return ret;
+}
+
+
+/* plot and graph scales */
+
+double scalespace_value(scalespace *s, double pixel){
+ double val = (double)((pixel-s->first_pixel)*s->step_val)/s->step_pixel + s->first_val;
+ return val * s->m;
+}
+
+double scalespace_pixel(scalespace *s, double val){
+ val /= s->m;
+ val -= s->first_val;
+ val *= s->step_pixel;
+ val /= s->step_val;
+ val += s->first_pixel;
+
+ return val;
+}
+
+int scalespace_mark(scalespace *s, int num){
+ return s->first_pixel + s->step_pixel*num;
+}
+
+double scalespace_label(scalespace *s, int num, char *buffer){
+ int pixel = scalespace_mark(s,num);
+ double val = scalespace_value(s,pixel);
+
+ if(s->decimal_exponent<0){
+ sprintf(buffer,"%.*f",-s->decimal_exponent,val);
+ }else{
+ sprintf(buffer,"%.0f",val);
+ }
+ return val;
+}
+
+scalespace scalespace_linear (double lowpoint, double highpoint, int pixels, int max_spacing){
+ double range = fabs(highpoint - lowpoint);
+ scalespace ret;
+
+ int place = 0;
+ int step = 1;
+ int first;
+
+ ret.lo = lowpoint;
+ ret.hi = highpoint;
+
+ while(pixels / range < max_spacing){
+ place++;
+ range *= .1;
+ }
+ while(pixels / range > max_spacing){
+ place--;
+ range *= 10;
+ }
+
+ ret.decimal_exponent = place;
+
+ if (pixels / (range*.2) <= max_spacing){
+ step *= 5;
+ range *= .2;
+ }
+ if (pixels / (range*.5) <= max_spacing){
+ step *= 2;
+ range *= .5;
+ }
+
+ ret.step_val = step;
+ ret.step_pixel = rint(pixels / range);
+ ret.m = pow(10,place);
+ first = (int)(lowpoint/ret.m)/step*step;
+
+ while(first * ret.m < lowpoint)
+ first += step;
+ while(first * ret.m > highpoint)
+ first -= step;
+
+ ret.first_val = first;
+ ret.first_pixel = rint((first - (lowpoint / ret.m)) * ret.step_pixel / ret.step_val);
+
+ return ret;
+}
Added: trunk/sushivision/scale.h
===================================================================
--- trunk/sushivision/scale.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/scale.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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 {
+ double lo;
+ double hi;
+
+ long first_val;
+ long first_pixel;
+
+ long step_val;
+ long step_pixel;
+
+ int decimal_exponent;
+ double m;
+} scalespace;
+
+extern char **scale_generate_labels(unsigned scalevals, double *scaleval_list);
+
+extern double scalespace_value(scalespace *s, double pixel);
+extern double scalespace_pixel(scalespace *s, double val);
+extern int scalespace_mark(scalespace *s, int num);
+extern double scalespace_label(scalespace *s, int num, char *buffer);
+extern scalespace scalespace_linear (double lowpoint, double highpoint, int pixels, int max_spacing);
Added: trunk/sushivision/slice.c
===================================================================
--- trunk/sushivision/slice.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/slice.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,257 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <gdk/gdkkeysyms.h>
+#include "mapping.h"
+#include "slice.h"
+#include "slider.h"
+
+static void draw_and_expose(GtkWidget *widget){
+ Slice *s=SLICE(widget);
+
+ slider_draw(s->slider);
+ slider_expose(s->slider);
+}
+
+static gboolean slice_expose(GtkWidget *widget, GdkEventExpose *event ){
+ Slice *s=SLICE(widget);
+ slider_expose_slice(s->slider,s->slicenum);
+ return FALSE;
+}
+
+static void slice_size_request (GtkWidget *widget,GtkRequisition *requisition){
+ Slice *s=SLICE(widget);
+
+ slider_size_request_slice(s->slider,requisition);
+}
+
+static gboolean slice_focus (GtkWidget *widget,
+ GtkDirectionType direction){
+ Slice *s=SLICE(widget);
+
+ if(!s->thumb_active)return FALSE;
+ if(s->thumb_focus)return TRUE;
+
+ s->thumb_focus=1;
+ gtk_widget_grab_focus(widget);
+ draw_and_expose(widget);
+
+ return TRUE;
+}
+
+static gint slice_motion(GtkWidget *widget,
+ GdkEventMotion *event){
+ Slice *s=SLICE(widget);
+ slider_motion(s->slider,s->slicenum,event->x,event->y);
+
+ return TRUE;
+}
+
+static gint slice_enter(GtkWidget *widget,
+ GdkEventCrossing *event){
+ Slice *s=SLICE(widget);
+ slider_lightme(s->slider,s->slicenum,event->x,event->y);
+ draw_and_expose(widget);
+ return TRUE;
+}
+
+static gint slice_leave(GtkWidget *widget,
+ GdkEventCrossing *event){
+ Slice *s=SLICE(widget);
+
+ slider_unlight(s->slider);
+ slider_draw(s->slider);
+ slider_expose(s->slider);
+
+ return TRUE;
+}
+
+static gboolean slice_button_press(GtkWidget *widget,
+ GdkEventButton *event){
+ Slice *s=SLICE(widget);
+
+ slider_button_press(s->slider,s->slicenum,event->x,event->y);
+ return TRUE;
+}
+
+static gboolean slice_button_release(GtkWidget *widget,
+ GdkEventButton *event){
+ Slice *s=SLICE(widget);
+ slider_button_release(s->slider,s->slicenum,event->x,event->y);
+ return TRUE;
+}
+
+static gboolean slice_unfocus(GtkWidget *widget,
+ GdkEventFocus *event){
+ Slice *s=SLICE(widget);
+ if(s->thumb_focus){
+ s->thumb_focus=0;
+ draw_and_expose(widget);
+ }
+ return TRUE;
+}
+
+static gboolean slice_refocus(GtkWidget *widget,
+ GdkEventFocus *event){
+ Slice *s=SLICE(widget);
+ if(!s->thumb_focus){
+ s->thumb_focus=1;
+ draw_and_expose(widget);
+ }
+ return TRUE;
+}
+
+static gboolean slice_key_press(GtkWidget *widget,GdkEventKey *event){
+ Slice *s=SLICE(widget);
+
+ return slider_key_press(s->slider,event);
+}
+
+static void slice_state_changed(GtkWidget *w,GtkStateType ps){
+ draw_and_expose(w);
+}
+
+static void slice_realize (GtkWidget *widget){
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask =
+ gtk_widget_get_events (widget) |
+ GDK_EXPOSURE_MASK|
+ GDK_POINTER_MOTION_MASK|
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK|
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_STRUCTURE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_FOCUS_CHANGE_MASK |
+ GDK_LEAVE_NOTIFY_MASK;
+
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ widget->window = gdk_window_new (widget->parent->window,
+ &attributes, attributes_mask);
+ gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+ gdk_window_set_user_data (widget->window, widget);
+ gtk_widget_set_double_buffered (widget, FALSE);
+}
+
+static void slice_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation){
+ //Slice *s = SLICE (widget);
+ if (GTK_WIDGET_REALIZED (widget)){
+
+ gdk_window_move_resize (widget->window, allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ }
+
+ widget->allocation = *allocation;
+
+}
+
+static GtkWidgetClass *parent_class = NULL;
+
+static void slice_class_init (SliceClass *class){
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+ //GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
+
+ parent_class = g_type_class_peek_parent (class);
+
+ //object_class->destroy = slice_destroy;
+ widget_class->realize = slice_realize;
+ widget_class->expose_event = slice_expose;
+ widget_class->size_request = slice_size_request;
+ widget_class->size_allocate = slice_size_allocate;
+ widget_class->key_press_event = slice_key_press;
+ widget_class->button_press_event = slice_button_press;
+ widget_class->button_release_event = slice_button_release;
+ widget_class->enter_notify_event = slice_enter;
+ widget_class->leave_notify_event = slice_leave;
+ widget_class->motion_notify_event = slice_motion;
+ widget_class->focus_out_event = slice_unfocus;
+ widget_class->focus_in_event = slice_refocus;
+ widget_class->state_changed = slice_state_changed;
+}
+
+static void slice_init (Slice *s){
+}
+
+GType slice_get_type (void){
+ static GType m_type = 0;
+ if (!m_type){
+ static const GTypeInfo m_info={
+ sizeof (SliceClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) slice_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (Slice),
+ 0,
+ (GInstanceInitFunc) slice_init,
+ 0
+ };
+
+ m_type = g_type_register_static (GTK_TYPE_WIDGET, "Slider", &m_info, 0);
+ }
+
+ return m_type;
+}
+
+GtkWidget* slice_new (void (*callback)(void *), void *data){
+ GtkWidget *ret= GTK_WIDGET (g_object_new (slice_get_type (), NULL));
+ Slice *s=SLICE(ret);
+ s->callback = callback;
+ s->callback_data = data;
+ s->thumb_active = 1;
+ return ret;
+}
+
+void slice_set_active(Slice *s, int activep){
+ s->thumb_active = activep;
+ draw_and_expose(GTK_WIDGET(s));
+}
+
+void slice_thumb_set(Slice *s,float v){
+ GtkWidget *w=GTK_WIDGET(s);
+
+ s->thumb_val=v;
+ slider_vals_bound(s->slider,s->slicenum);
+
+ if(s->callback)s->callback(s->callback_data);
+ draw_and_expose(w);
+}
Added: trunk/sushivision/slice.h
===================================================================
--- trunk/sushivision/slice.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/slice.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,73 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#ifndef __SLICE_H__
+#define __SLICE_H__
+
+#include <sys/time.h>
+#include <time.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtkcontainer.h>
+#include <gtk/gtksignal.h>
+
+G_BEGIN_DECLS
+
+#define SLICE_TYPE (slice_get_type ())
+#define SLICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SLICE_TYPE, Slice))
+#define SLICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SLICE_TYPE, SliceClass))
+#define IS_SLICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SLICE_TYPE))
+#define IS_SLICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SLICE_TYPE))
+
+typedef struct _Slice Slice;
+typedef struct _SliceClass SliceClass;
+
+typedef struct _Slider Slider;
+
+struct _Slice{
+ GtkWidget widget;
+
+ Slider *slider;
+ int slicenum;
+
+ int thumb_active;
+ int thumb_focus;
+ int thumb_state;
+ int thumb_grab;
+ double thumb_val;
+
+ void (*callback)(void *);
+ void *callback_data;
+
+};
+
+struct _SliceClass{
+ GtkWidgetClass parent_class;
+ void (*slice) (Slice *s);
+};
+
+extern GType slice_get_type (void);
+extern GtkWidget* slice_new (void (*callback)(void *), void *data);
+extern void slice_set_active(Slice *s, int activep);
+extern void slice_thumb_set(Slice *s,float v);
+
+G_END_DECLS
+#endif
Added: trunk/sushivision/slider.c
===================================================================
--- trunk/sushivision/slider.c 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/slider.c 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,745 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "mapping.h"
+#include "slice.h"
+#include "slider.h"
+
+static int total_slice_width(Slider *s){
+ int i;
+ int count=0;
+ for(i=0;i<s->num_slices;i++)
+ count += s->slices[i]->allocation.width;
+ return count;
+}
+
+static int slice_width(Slider *s,int slices){
+ int i;
+ int count=0;
+ for(i=0;i<slices;i++)
+ count += s->slices[i]->allocation.width;
+ return count;
+}
+
+static int total_slice_height(Slider *s){
+ int i;
+ int max=0;
+ for(i=0;i<s->num_slices;i++)
+ if(max<s->slices[i]->allocation.height)
+ max = s->slices[i]->allocation.height;
+ return max;
+}
+
+/* guess where I came from. */
+static void rounded_rectangle (cairo_t *c,
+ double x, double y, double w, double h,
+ double radius)
+{
+ cairo_move_to (c, x+radius, y);
+ cairo_arc (c, x+w-radius, y+radius, radius, M_PI * 1.5, M_PI * 2);
+ cairo_arc (c, x+w-radius, y+h-radius, radius, 0, M_PI * 0.5);
+ cairo_arc (c, x+radius, y+h-radius, radius, M_PI * 0.5, M_PI);
+ cairo_arc (c, x+radius, y+radius, radius, M_PI, M_PI * 1.5);
+}
+
+double shades[] = {1.15, 0.95, 0.896, 0.82, 0.7, 0.665, 0.5, 0.45, 0.4};
+
+static void set_shade(GtkWidget *w, cairo_t *c, int shade){
+ Slice *sl = SLICE(w);
+ GdkColor *bg = &w->style->bg[sl->thumb_state?GTK_STATE_ACTIVE:GTK_STATE_NORMAL];
+ double shade_r=bg->red*shades[shade]/65535;
+ double shade_g=bg->green*shades[shade]/65535;
+ double shade_b=bg->blue*shades[shade]/65535;
+
+ cairo_set_source_rgb (c, shade_r,shade_g,shade_b);
+}
+
+static void parent_shade(Slider *s, cairo_t *c, int shade){
+ GtkWidget *parent=gtk_widget_get_parent(s->slices[0]);
+ GdkColor *bg = &parent->style->bg[GTK_STATE_NORMAL];
+ double shade_r=bg->red*shades[shade]/65535;
+ double shade_g=bg->green*shades[shade]/65535;
+ double shade_b=bg->blue*shades[shade]/65535;
+
+ cairo_set_source_rgb (c, shade_r,shade_g,shade_b);
+}
+
+void slider_draw_background(Slider *s){
+ int i;
+ GtkWidget *parent=gtk_widget_get_parent(s->slices[0]);
+ GdkColor *bg = &parent->style->bg[0];
+ GdkColor *fg = &s->slices[0]->style->fg[0];
+ int textborder=1;
+ double textr=1.;
+ double textg=1.;
+ double textb=1.;
+
+ int x=0;
+ int y=0;
+ int w=s->w;
+ int h=s->h;
+
+ int tx=x;
+ int ty=y+s->ypad;
+ int tw=w;
+ int th=h - s->ypad*2;
+ cairo_pattern_t *pattern;
+
+ // prepare background
+ cairo_t *c = cairo_create(s->background);
+
+ // Fill with bg color
+ gdk_cairo_set_source_color(c,bg);
+ cairo_rectangle(c,0,0,w,h);
+ cairo_fill(c);
+
+ // Create trough innards
+ if(s->gradient){
+ // background map gradient
+ u_int32_t *pixel=s->backdata+ty*s->w;
+
+ for(i=tx;i<tx+tw;i++)
+ pixel[i]=mapping_calc(s->gradient,slider_pixel_to_del(s,0,i));
+
+ for(i=ty+1;i<ty+th;i++){
+ memcpy(pixel+w,pixel,w*4);
+ pixel+=s->w;
+ }
+
+ }else{
+ // normal background
+ textr=fg->red;
+ textg=fg->green;
+ textb=fg->blue;
+ textborder=0;
+
+ cairo_rectangle (c, x+1, ty, w-2, th);
+ parent_shade(s,c,3);
+ cairo_fill (c);
+ }
+
+ // Top shadow
+ cairo_rectangle (c, tx+1, ty, tw-2, 4);
+ pattern = cairo_pattern_create_linear (0, ty-1, 0, ty+3);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0., 0., 0., 0.2);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0., 0., 0., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill (c);
+ cairo_pattern_destroy (pattern);
+
+ // Left shadow
+ cairo_rectangle (c, tx+1, ty, tx+4, th);
+ pattern = cairo_pattern_create_linear (tx, ty-1, tx+3, ty-1);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0., 0., 0., 0.1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0., 0., 0., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill (c);
+ cairo_pattern_destroy (pattern);
+
+ // lines & labels
+ for(i=0;i<s->labels;i++){
+ int x=rint(((float)i)/(s->labels-1)*(s->w - s->xpad*2 -1))+s->xpad;
+ int y=s->h-s->ypad-1.5;
+
+ cairo_move_to(c,x+.5,s->ypad+2);
+ cairo_line_to(c,x+.5,s->h-s->ypad-2);
+ cairo_set_source_rgba(c,textr,textg,textb,.8);
+ cairo_set_line_width(c,1);
+ cairo_stroke(c);
+
+ if(i>0){
+ cairo_text_extents_t ex;
+ cairo_text_extents (c, s->label[i], &ex);
+
+ x-=2;
+ x-=ex.width;
+
+ }else{
+ x+=2;
+ }
+
+ if(textborder){
+ cairo_set_source_rgba(c,0,0,0,.8);
+ cairo_set_line_width(c,2);
+ cairo_move_to (c, x,y);
+ cairo_text_path (c, s->label[i]);
+ cairo_stroke(c);
+ }
+
+ cairo_set_source_rgba(c,textr,textg,textb,.8);
+ cairo_move_to (c, x,y);
+ cairo_show_text (c, s->label[i]);
+ }
+
+ // Draw border
+ rounded_rectangle (c, tx+0.5, ty-0.5, tw-1, th+1, 1.5);
+ parent_shade(s,c,7);
+ cairo_set_line_width (c, 1.0);
+ cairo_stroke (c);
+
+ cairo_destroy(c);
+}
+
+void slider_realize(Slider *s){
+ int w = total_slice_width(s);
+ int h = total_slice_height(s);
+ if(s->background == 0 || w != s->w || h != s->h){
+
+ if(s->background)
+ cairo_surface_destroy(s->background);
+
+ if(s->foreground)
+ cairo_surface_destroy(s->foreground);
+
+ if(s->backdata)
+ free(s->backdata);
+
+ s->backdata = calloc(w*h,4);
+
+ s->background = cairo_image_surface_create_for_data ((unsigned char *)s->backdata,
+ CAIRO_FORMAT_RGB24,
+ w,h,w*4);
+ s->foreground = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ w,h);
+
+ s->w=w;
+ s->h=h;
+
+ s->xpad=h*.45;
+ if(s->xpad<4)s->xpad=4;
+ slider_draw_background(s);
+ slider_draw(s);
+
+ }
+}
+
+static double val_to_pixel(Slider *s,double v){
+ int j;
+ double ret=0;
+
+ int tx=s->xpad;
+ int tw=s->w - tx*2;
+
+ if(v<s->label_vals[0]){
+ ret=0;
+ }else if(v>s->label_vals[s->labels-1]){
+ ret=tw;
+ }else{
+ for(j=0;j<s->labels;j++){
+ if(v>=s->label_vals[j] && v<=s->label_vals[j+1]){
+ double del=(v-s->label_vals[j])/(s->label_vals[j+1]-s->label_vals[j]);
+ double pixlo=rint((double)j/(s->labels-1)*tw);
+ double pixhi=rint((double)(j+1)/(s->labels-1)*tw);
+ ret=pixlo*(1.-del)+pixhi*del+tx;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+double slider_val_to_del(Slider *s,double v){
+ if(isnan(v))return NAN;
+
+ int j;
+ double ret=0;
+
+ for(j=0;j<s->labels;j++){
+ if(v<=s->label_vals[j+1] || (j+1)==s->labels){
+ double del=(v-s->label_vals[j])/(s->label_vals[j+1]-s->label_vals[j]);
+ return (j+del)/(s->labels-1);
+ }
+ }
+
+ return NAN;
+}
+
+void slider_draw(Slider *s){
+ int i;
+ cairo_t *c;
+ //int w=s->w;
+ int h=s->h;
+
+ c = cairo_create(s->foreground);
+ cairo_set_source_surface(c,s->background,0,0);
+ cairo_rectangle(c,0,0,s->w,s->h);
+ cairo_fill(c);
+
+ // thumbs
+ for(i=0;i<s->num_slices;i++){
+ GtkWidget *sl = s->slices[i];
+ double x = val_to_pixel(s,((Slice *)(s->slices[i]))->thumb_val)+.5;
+ double rad = 2.;
+
+ float y = rint(h/2)+.5;
+ float xd = y*.575;
+ float rx = 1.73*rad;
+ cairo_pattern_t *pattern;
+
+ if(SLICE(sl)->thumb_active){
+ if ((s->num_slices == 1) || (s->num_slices == 3 && i==1)){
+ // outline
+ cairo_move_to(c,x,s->h/2);
+ cairo_arc_negative(c, x+xd-rx, rad+.5, rad, 30.*(M_PI/180.), 270.*(M_PI/180.));
+ cairo_arc_negative(c, x-xd+rx, rad+.5, rad, 270.*(M_PI/180.), 150.*(M_PI/180.));
+ cairo_close_path(c);
+
+ set_shade(sl,c,2);
+ cairo_fill_preserve(c);
+
+ cairo_set_line_width(c,1);
+ set_shade(sl,c,7);
+
+ if(((Slice *)s->slices[i])->thumb_focus)
+ cairo_set_source_rgba(c,0,0,0,1);
+
+ cairo_stroke_preserve(c);
+ cairo_set_dash (c, NULL, 0, 0.);
+
+ // top highlight
+ pattern = cairo_pattern_create_linear (0, 0, 0, 4);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1., 1., 1., 0.2);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1., 1., 1., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill_preserve (c);
+ cairo_pattern_destroy (pattern);
+
+ // Left highlight
+ pattern = cairo_pattern_create_linear (x-xd+3, 0, x-xd+6, 0);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1., 1., 1., 0.1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1., 1., 1., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill (c);
+ cairo_pattern_destroy (pattern);
+
+ // needle shadow
+ cairo_set_line_width(c,2);
+ cairo_move_to(c,x,s->h/2+3);
+ cairo_line_to(c,x,s->ypad/2);
+ cairo_set_source_rgba(c,0.,0.,0.,.5);
+ cairo_stroke(c);
+
+ // needle
+ cairo_set_line_width(c,1);
+ cairo_move_to(c,x,s->h/2+2);
+ cairo_line_to(c,x,s->ypad/2);
+ cairo_set_source_rgb(c,1.,1.,0);
+ cairo_stroke(c);
+
+ }else{
+ if(i==0){
+ // bracket left
+
+ // outline
+ cairo_move_to(c,x,s->h/2);
+ cairo_line_to(c,x-xd/2,s->h/2);
+ cairo_arc_negative(c, x-xd*3/2+rx, h-rad-.5, rad, 210.*(M_PI/180.), 90.*(M_PI/180.));
+ cairo_line_to(c, x, h-.5);
+ cairo_close_path(c);
+
+ set_shade(sl,c,2);
+ cairo_set_line_width(c,1);
+ cairo_fill_preserve(c);
+ set_shade(sl,c,7);
+ if(((Slice *)s->slices[i])->thumb_focus)
+ cairo_set_source_rgba(c,0,0,0,1);
+ cairo_stroke_preserve(c);
+
+ // top highlight
+ pattern = cairo_pattern_create_linear (0, y, 0, y+4);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1., 1., 1., 0.2);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1., 1., 1., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill_preserve (c);
+ cairo_pattern_destroy (pattern);
+
+ // Left highlight
+ pattern = cairo_pattern_create_linear (x-xd*3/2+3, 0, x-xd*3/2+6, 0);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1., 1., 1., 0.1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1., 1., 1., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill (c);
+ cairo_pattern_destroy (pattern);
+ }else{
+
+ // bracket right
+
+ // outline
+ cairo_move_to(c,x,s->h/2);
+ cairo_line_to(c,x+xd/2,s->h/2);
+ cairo_arc(c, x+xd*3/2-rx, h-rad-.5, rad, 330.*(M_PI/180.), 90.*(M_PI/180.));
+ cairo_line_to(c, x, h-.5);
+ cairo_close_path(c);
+
+ set_shade(sl,c,2);
+ cairo_set_line_width(c,1);
+ cairo_fill_preserve(c);
+ set_shade(sl,c,7);
+ if(((Slice *)s->slices[i])->thumb_focus)
+ cairo_set_source_rgba(c,0,0,0,1);
+ cairo_stroke_preserve(c);
+
+ // top highlight
+ pattern = cairo_pattern_create_linear (0, y, 0, y+4);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1., 1., 1., 0.2);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1., 1., 1., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill_preserve (c);
+ cairo_pattern_destroy (pattern);
+
+ // Left highlight
+ pattern = cairo_pattern_create_linear (x+1, 0, x+4, 0);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1., 1., 1., 0.1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1., 1., 1., 0.);
+ cairo_set_source (c, pattern);
+ cairo_fill (c);
+ cairo_pattern_destroy (pattern);
+
+ }
+ // needle shadow
+ cairo_set_line_width(c,2);
+ cairo_move_to(c,x,s->h/2-3);
+ cairo_line_to(c,x,h-s->ypad/2);
+ cairo_set_source_rgba(c,0.,0.,0.,.5);
+ cairo_stroke(c);
+
+ // needle
+ cairo_set_line_width(c,1);
+ cairo_move_to(c,x,s->h/2-2);
+ cairo_line_to(c,x,h-s->ypad/2);
+ cairo_set_source_rgb(c,1.,1.,0);
+ cairo_stroke(c);
+ }
+ }
+ }
+
+ cairo_destroy(c);
+}
+
+void slider_expose_slice(Slider *s, int slicenum){
+ Slice *slice = (Slice *)(s->slices[slicenum]);
+ GtkWidget *w = GTK_WIDGET(slice);
+
+ if(GTK_WIDGET_REALIZED(w)){
+ cairo_t *c = gdk_cairo_create(w->window);
+
+ slider_realize(s);
+ cairo_set_source_surface(c,s->foreground,-slice_width(s,slicenum),0);
+ cairo_rectangle(c,0,0,w->allocation.width,w->allocation.height);
+ cairo_fill(c);
+
+ cairo_destroy(c);
+ }
+}
+
+void slider_expose(Slider *s){
+ int i;
+ for(i=0;i<s->num_slices;i++)
+ slider_expose_slice(s,i);
+}
+
+void slider_size_request_slice(Slider *s,GtkRequisition *requisition){
+ int maxx=0,x0=0,x1=0,maxy=0,i,w;
+
+ // need a dummy surface to find text sizes
+ cairo_surface_t *dummy=cairo_image_surface_create(CAIRO_FORMAT_RGB24,1,1);
+ cairo_t *c = cairo_create(dummy);
+
+ // find the widest label
+ for(i=0;i<s->labels;i++){
+ cairo_text_extents_t ex;
+ cairo_text_extents(c, s->label[i], &ex);
+ if(i==0) x0 = ex.width;
+ if(i==1) x1 = ex.width;
+ if(ex.width > maxx)maxx=ex.width;
+ if(ex.height > maxy)maxy=ex.height;
+ }
+
+ // also check first + second label width
+ if(x0+x1 > maxx)maxx=x0+x1;
+
+ w = (maxx*1.5+2)*s->labels+4;
+ requisition->width = (w+s->num_slices-1)/s->num_slices;
+ requisition->height = maxy+4+s->ypad*2;
+
+ cairo_destroy(c);
+ cairo_surface_destroy(dummy);
+}
+
+static double slice_adjust_pixel(Slider *s,int slicenum, double x){
+ double width = slice_width(s,slicenum);
+ return x+width;
+}
+
+double slider_pixel_to_val(Slider *s,int slicenum,double x){
+ int j;
+ int tx=s->xpad;
+ int tw=s->w - tx*2;
+
+ x=slice_adjust_pixel(s,slicenum,x);
+
+ for(j=0;j<s->labels-1;j++){
+
+ double pixlo=rint((float)j/(s->labels-1)*(tw-1))+tx;
+ double pixhi=rint((float)(j+1)/(s->labels-1)*(tw-1))+tx;
+
+ if(x>=pixlo && x<=pixhi){
+ if(pixlo==pixhi)return s->label_vals[j];
+ double del=(float)(x-pixlo)/(pixhi-pixlo);
+ return (1.-del)*s->label_vals[j] + del*s->label_vals[j+1];
+ }
+ }
+ if(x<tx)
+ return s->label_vals[0];
+ else
+ return (s->label_vals[s->labels-1]);
+}
+
+double slider_pixel_to_del(Slider *s,int slicenum,double x){
+ int tx=s->xpad;
+ int tw=s->w - tx*2;
+
+ x=slice_adjust_pixel(s,slicenum,x-tx);
+
+ if(x<=0){
+ return 0.;
+ }else if (x>tw){
+ return 1.;
+ }else
+ return x/tw;
+}
+
+void slider_vals_bound(Slider *s,int slicenum){
+ int i,flag=0;
+ Slice *center = SLICE(s->slices[slicenum]);
+ double min = s->label_vals[0];
+ double max = s->label_vals[s->labels-1];
+ if(center->thumb_val < min)
+ center->thumb_val = min;
+
+ if(center->thumb_val > max)
+ center->thumb_val = max;
+
+ // now make sure other sliders have valid spacing
+ if( (s->flags & SLIDER_FLAG_INDEPENDENT_MIDDLE) &&
+ s->num_slices == 3)
+ flag=1;
+
+ for(i=slicenum-1; i>=0;i--){
+ if(flag && (i==0 || i==1))continue;
+
+ Slice *sl = SLICE(s->slices[i]);
+ Slice *sl2 = SLICE(s->slices[i+1]);
+ if(sl->thumb_val>sl2->thumb_val)
+ sl->thumb_val=sl2->thumb_val;
+ }
+
+ for(i=slicenum+1; i<s->num_slices;i++){
+ if(flag && (i==2 || i==1))continue;
+
+ Slice *sl = SLICE(s->slices[i]);
+ Slice *sl2 = SLICE(s->slices[i-1]);
+ if(sl->thumb_val<sl2->thumb_val)
+ sl->thumb_val=sl2->thumb_val;
+ }
+}
+
+static int determine_thumb(Slider *s,int slicenum,int x,int y){
+ int i;
+ int best=-1;
+ float bestdist=s->w+1;
+
+ x=slice_adjust_pixel(s,slicenum,x);
+ for(i=0;i<s->num_slices;i++){
+ Slice *sl = SLICE(s->slices[i]);
+ if(sl->thumb_active){
+ float tpix = val_to_pixel(s,sl->thumb_val) + i - s->num_slices/2;
+ float d = fabs(x - tpix);
+ if(d<bestdist){
+ best=i;
+ bestdist=d;
+ }
+ }
+ }
+ return best;
+}
+
+static int lit_thumb(Slider *s){
+ int i;
+ for(i=0;i<s->num_slices;i++){
+ Slice *sl = SLICE(s->slices[i]);
+ if(sl->thumb_state)return i;
+ }
+ return -1;
+}
+
+void slider_unlight(Slider *s){
+ int i;
+ for(i=0;i<s->num_slices;i++){
+ Slice *sl = SLICE(s->slices[i]);
+ if(!sl->thumb_grab)
+ sl->thumb_state = 0;
+ }
+}
+
+int slider_lightme(Slider *s,int slicenum,int x,int y){
+ int last = lit_thumb(s);
+ int best = determine_thumb(s,slicenum,x,y);
+ if(last != best){
+ slider_unlight(s);
+ if(best>-1){
+ Slice *sl = SLICE(s->slices[best]);
+ sl->thumb_state=1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void slider_button_press(Slider *s,int slicenum,int x,int y){
+ int i;
+ for(i=0;i<s->num_slices;i++){
+ Slice *sl = SLICE(s->slices[i]);
+ if(sl->thumb_state){
+ sl->thumb_grab=1;
+ sl->thumb_focus=1;
+ gtk_widget_grab_focus(GTK_WIDGET(sl));
+
+ slider_motion(s,slicenum,x,y);
+ }
+ }
+ slider_draw(s);
+ slider_expose(s);
+}
+
+void slider_button_release(Slider *s,int slicenum,int x,int y){
+ int i;
+ for(i=0;i<s->num_slices;i++){
+ Slice *sl = SLICE(s->slices[i]);
+ sl->thumb_grab=0;
+ }
+}
+
+void slider_motion(Slider *s,int slicenum,int x,int y){
+ int altered=0;
+ int i;
+
+ /* is a thumb already grabbed? */
+ for(i=0;i<s->num_slices;i++){
+ Slice *sl = SLICE(s->slices[i]);
+ if(sl->thumb_grab){
+ sl->thumb_val=slider_pixel_to_val(s,slicenum,x);
+ slider_vals_bound(s,i);
+ altered=i+1;
+ }
+ }
+
+ // did a gradient get altered?
+ if(s->gradient && s->num_slices>=2){
+ Slice *sl = SLICE(s->slices[0]);
+ Slice *sh = SLICE(s->slices[s->num_slices-1]);
+ if(s->gradient->low != sl->thumb_val ||
+ s->gradient->high != sh->thumb_val){
+
+ mapping_set_lo(s->gradient,slider_val_to_del(s,sl->thumb_val));
+ mapping_set_hi(s->gradient,slider_val_to_del(s,sh->thumb_val));
+ slider_draw_background(s);
+ }
+ }
+ if(altered){
+ Slice *sl = SLICE(s->slices[altered-1]);
+
+ if(sl->callback)sl->callback(sl->callback_data);
+ slider_draw(s);
+ slider_expose(s);
+ }else{
+ /* nothing grabbed right now; determine if we're in a a thumb's area */
+ if(slider_lightme(s,slicenum,x,y)){
+ slider_draw(s);
+ slider_expose(s);
+ }
+ }
+}
+
+gboolean slider_key_press(Slider *s,GdkEventKey *event){
+
+ return FALSE; // keep processing
+}
+
+Slider *slider_new(Slice **slices, int num_slices, char **labels, double *label_vals, int num_labels,
+ unsigned flags){
+ int i;
+ Slider *ret = calloc(1,sizeof(*ret));
+
+ ret->slices = (GtkWidget **)slices;
+ ret->num_slices = num_slices;
+
+ ret->label = calloc(num_labels,sizeof(*ret->label));
+ for(i=0;i<num_labels;i++)
+ ret->label[i]=strdup(labels[i]);
+
+ ret->label_vals = calloc(num_labels,sizeof(*ret->label_vals));
+ memcpy(ret->label_vals,label_vals,sizeof(*ret->label_vals)*num_labels);
+ ret->labels = num_labels;
+
+ // set up each slice
+ for(i=0;i<num_slices;i++){
+ slices[i]->slider = ret;
+ slices[i]->slicenum = i;
+ }
+ ret->ypad=8;
+ ret->xpad=5;
+ //ret->minstep=minstep;
+ //ret->step=step;
+
+ ret->flags=flags;
+ return ret;
+}
+
+void slider_set_gradient(Slider *s, mapping *m){
+ s->gradient = m;
+}
+
+void slider_set_thumb_active(Slider *s, int thumbnum, int activep){
+ slice_set_active(SLICE(s->slices[thumbnum]),activep);
+}
+
+double slider_get_value(Slider *s, int thumbnum){
+ GtkWidget *w;
+ if(thumbnum >= s->num_slices)return 0;
+ if(thumbnum < 0)return 0;
+ w = s->slices[thumbnum];
+ return SLICE(w)->thumb_val;
+}
+
+void slider_set_value(Slider *s, int thumbnum, double v){
+ GtkWidget *w;
+ if(thumbnum >= s->num_slices)return;
+ if(thumbnum < 0)return;
+ w = s->slices[thumbnum];
+ slice_thumb_set(SLICE(w),v);
+}
Added: trunk/sushivision/slider.h
===================================================================
--- trunk/sushivision/slider.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/slider.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,70 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <sys/types.h>
+struct _Slider {
+ GtkWidget **slices;
+ int num_slices;
+
+ u_int32_t *backdata;
+ cairo_surface_t *background;
+ cairo_surface_t *foreground;
+ int w;
+ int h;
+ mapping *gradient;
+ int xpad;
+ int ypad;
+
+ char **label;
+ double *label_vals;
+ int labels;
+
+ int flags;
+
+ //double minstep;
+ //double step;
+};
+
+#define SLIDER_FLAG_INDEPENDENT_MIDDLE 0x1
+
+extern void slider_draw_background(Slider *s);
+extern void slider_realize(Slider *s);
+extern void slider_draw(Slider *);
+extern void slider_expose_slice(Slider *s, int slicenum);
+extern void slider_expose(Slider *s);
+extern void slider_size_request_slice(Slider *s,GtkRequisition *requisition);
+extern double slider_pixel_to_val(Slider *slider,int slicenum,double x);
+extern double slider_pixel_to_del(Slider *slider,int slicenum,double x);
+extern double slider_val_to_del(Slider *slider,double v);
+extern void slider_vals_bound(Slider *slider,int slicenum);
+extern int slider_lightme(Slider *slider,int slicenum,int x,int y);
+extern void slider_unlight(Slider *slider);
+extern void slider_button_press(Slider *slider,int slicenum,int x,int y);
+extern void slider_button_release(Slider *s,int slicenum,int x,int y);
+extern void slider_motion(Slider *s,int slicenum,int x,int y);
+extern gboolean slider_key_press(Slider *slider,GdkEventKey *event);
+extern Slider *slider_new(Slice **slices, int num_slices,
+ char **labels, double *label_vals, int num_labels,
+ unsigned flags);
+extern void slider_set_thumb_active(Slider *s, int thumbnum, int activep);
+extern void slider_set_gradient(Slider *s, mapping *m);
+extern double slider_get_value(Slider *s, int thumbnum);
+extern void slider_set_value(Slider *s, int thumbnum, double v);
Added: trunk/sushivision/sushi-gtkrc
===================================================================
--- trunk/sushivision/sushi-gtkrc 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/sushi-gtkrc 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,202 @@
+style "button-poppy" {
+ bg[NORMAL]="#80a0ff"
+ bg[ACTIVE]="#c0f0ff"
+ bg[PRELIGHT]="#c0f0ff"
+
+ text[NORMAL]="#000000"
+ text[ACTIVE]="#000000"
+ text[PRELIGHT]="#000000"
+
+ fg[NORMAL]="#000000"
+ fg[ACTIVE]="#000000"
+ fg[PRELIGHT]="#000000"
+
+ font_name = "sans 8"
+
+ GtkWidget::focus_line_width = 1
+ GtkWidget::focus_padding = 0
+ GtkWidget::interior_focus = 0
+ GtkWidget::internal_padding = 0
+
+}
+
+style "panel-label" {
+ font_name = "sans bold 11"
+}
+
+style "panel-text" {
+ font_name = "sans 9"
+}
+
+style "small-marker" {
+ fg[NORMAL]="#905050"
+ font_name = "sans 6"
+}
+
+style "scale-marker" {
+ font_name = "sans 7"
+}
+
+style "frame-label" {
+ font_name = "sans bold 10"
+}
+
+style "frame-text" {
+ font_name = "sans 9"
+}
+
+style "check-poppy" {
+ bg[NORMAL]="#80a0ff"
+
+ font_name = "sans 8"
+ GtkButton::focus-padding = 0
+ GtkButton::focus-line-width = 1
+ GtkButton::interior-focus = 0
+}
+
+style "slider" {
+ bg[NORMAL]="#80a0ff"
+ bg[PRELIGHT]="#c0f0ff"
+ GtkWidget::focus-padding = 0
+ GtkWidget::focus-line-width = 1
+ GtkWidget::interior-focus = 0
+}
+
+style "multibar" {
+ bg[NORMAL]="#80a0ff"
+ bg[ACTIVE]="#b0b0b0"
+ bg[PRELIGHT]="#c0f0ff"
+
+ fg[NORMAL]="#000000"
+ fg[ACTIVE]="#ff8080"
+ fg[PRELIGHT]="#f0f080"
+
+ text[NORMAL]="#c0c0d0"
+ text[ACTIVE]="#ffb0b0"
+ font_name = "sans 7"
+}
+
+style "multislide" {
+ bg[NORMAL]="#80a0ff"
+ bg[ACTIVE]="#b0b0b0"
+ bg[PRELIGHT]="#c0f0ff"
+
+ fg[NORMAL]="#000000"
+ fg[ACTIVE]="#ff8080"
+ fg[PRELIGHT]="#f0f080"
+
+ text[NORMAL]="#707070"
+ text[ACTIVE]="#905050"
+ font_name = "sans 7"
+}
+
+style "clipbar" {
+ fg[NORMAL]="#404040"
+ fg[ACTIVE]="#ff8080"
+ text[NORMAL]="#c0c0d0"
+ text[ACTIVE]="#c0c0d0"
+ font_name = "sans 8"
+}
+
+style "readout" {
+ base[NORMAL]="#ffffff"
+ base[ACTIVE]="#ffffff"
+ bg[NORMAL]="#ffffff"
+ bg[ACTIVE]="#ffffff"
+
+ font_name = "Fixed, Nimbus Mono L, Courier, Monospace 10"
+}
+
+style "small-readout" {
+ base[NORMAL]="#ffffff"
+ base[ACTIVE]="#ffffff"
+ bg[NORMAL]="#ffffff"
+ bg[ACTIVE]="#ffffff"
+ text[NORMAL]="#606060"
+ font_name = "Fixed, Nimbus Mono L, Courier, Monospace 8"
+}
+
+style "darkpanel" {
+ bg[NORMAL]="#b0b0b0"
+ bg[INSENSITIVE]="#b0b0b0"
+}
+
+style "quitbutton" {
+ bg[NORMAL]="#d0d0d0"
+ bg[PRELIGHT]="#ffc0c0"
+ bg[ACTIVE]="#ffc0c0"
+ font_name = "sans 8"
+ GtkButton::focus-padding = 0
+ GtkButton::focus-line-width = 1
+ GtkButton::interior-focus = 0
+}
+
+style "left" {
+ text[NORMAL] = "#606060"
+ text[ACTIVE] = "#606060"
+ text[SELECTED] = "#606060"
+ text[PRELIGHT] = "#606060"
+ fg[ACTIVE] = "#606060"
+ bg[NORMAL]="#80a0ff"
+}
+style "right" {
+ text[NORMAL] = "#cc0000"
+ text[ACTIVE] = "#cc0000"
+ text[SELECTED] = "#cc0000"
+ text[PRELIGHT] = "#cc0000"
+ bg[NORMAL]="#80a0ff"
+}
+style "mid" {
+ text[NORMAL] = "#0000fc"
+ text[ACTIVE] = "#0000fc"
+ text[SELECTED] = "#0000fc"
+ text[PRELIGHT] = "#0000fc"
+ bg[NORMAL]="#80a0ff"
+}
+style "side" {
+ text[NORMAL] = "#00B200"
+ text[ACTIVE] = "#00B200"
+ text[SELECTED] = "#00B200"
+ text[PRELIGHT] = "#00B200"
+ bg[NORMAL]="#80a0ff"
+}
+
+widget "*.GtkLabel" style "panel-text"
+widget "*.scalemarker" style "scale-marker"
+widget "*.smallmarker" style "small-marker"
+
+widget "*.color0" style "left"
+widget "*.color1" style "right"
+widget "*.color2" style "mid"
+widget "*.color3" style "side"
+
+widget "*.panelbox*" style "darkpanel"
+widget "*.winpanel*" style "darkpanel"
+
+widget "*.choiceframe.*" style "frame-text"
+widget "*.GtkFrame.GtkLabel" style "frame-label"
+widget "*.GtkFrame.GtkHBox.GtkLabel" style "frame-label"
+widget "*.framelabel" style "frame-label"
+
+widget "*.Readout*" style "readout"
+widget "*.smallreadout" style "small-readout"
+widget "*.GtkEntry" style "readout"
+widget "*.GtkHScale" style "slider"
+widget "*.GtkMenu*" style "button-poppy"
+widget "*.GtkComboBox*" style "button-poppy"
+widget "*.GtkToggleButton*" style "button-poppy"
+widget "*.GtkButton*" style "button-poppy"
+widget "*.GtkCheckButton" style "check-poppy"
+widget "*.Windowbutton*" style "button-poppy"
+widget "*.windowbuttonlike" style "button-poppy"
+widget "*.quitbutton" style "quitbutton"
+widget "*.quitbutton.GtkLabel" style "quitbutton"
+
+widget "*.panelbutton*" style "button-poppy"
+widget "*.panelbutton*.GtkLabel" style "panel-label"
+widget "*.Multibar*" style "multibar"
+widget "*.Multislide*" style "multislide"
+
+widget "*.clipbar*" style "clipbar"
+
+widget "*.Slider" style "button-poppy"
Added: trunk/sushivision/sushi.h
===================================================================
--- trunk/sushivision/sushi.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/sushi.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+
+extern void sushi_submain();
+extern void sushi_new_2d(int axes, double (*objective)(double *),
+ char **labels, double *vals,
+ double small_step, double large_step);
+extern void sushi_axis_2d(double range_low, double range_hi,
+ double small_step, double large_step);
+
Added: trunk/sushivision/sushivision.h
===================================================================
--- trunk/sushivision/sushivision.h 2006-10-26 15:53:19 UTC (rev 11954)
+++ trunk/sushivision/sushivision.h 2006-10-27 02:14:20 UTC (rev 11955)
@@ -0,0 +1,137 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+#ifndef _SUSHIVISION_
+#define _SUSHIVISION_
+
+typedef struct sushiv_panel sushiv_panel_t;
+typedef struct sushiv_dimension sushiv_dimension_t;
+typedef struct sushiv_objective sushiv_objective_t;
+
+typedef struct sushiv_instance {
+ int dimensions;
+ sushiv_dimension_t **dimension_list;
+
+ int objectives;
+ sushiv_objective_t **objective_list;
+
+ int panels;
+ struct sushiv_panel **panel_list;
+
+ void *internal;
+} sushiv_instance_t;
+
+#define SUSHIV_X_RANGE 0x100
+#define SUSHIV_Y_RANGE 0x200
+
+struct sushiv_dimension{
+ int number;
+ char *name;
+ double bracket[2];
+ double val;
+
+ int scale_vals;
+ double *scale_val_list;
+ char **scale_label_list;
+ unsigned flags;
+
+ int (*callback)(sushiv_dimension_t *);
+ sushiv_panel_t *panel;
+ sushiv_instance_t *sushi;
+ void *internal;
+};
+
+struct sushiv_objective {
+ int number;
+ char *name;
+
+ double (*callback)(double[]);
+ sushiv_panel_t *panel;
+ sushiv_instance_t *sushi;
+ void *internal;
+ unsigned flags;
+};
+
+enum sushiv_panel_type { SUSHIV_PANEL_1D, SUSHIV_PANEL_2D };
+
+struct sushiv_panel {
+ int number;
+ char *name;
+ enum sushiv_panel_type type;
+ int realized;
+ int maps_dirty;
+
+ int dimensions;
+ sushiv_dimension_t **dimension_list;
+ int objectives;
+ sushiv_objective_t **objective_list;
+
+ int scale_vals;
+ double *scale_val_list;
+ char **scale_label_list;
+
+ sushiv_instance_t *sushi;
+ void *internal;
+ unsigned flags;
+};
+
+extern sushiv_instance_t *sushiv_new_instance(void);
+
+extern int sushiv_new_dimension(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ unsigned scalevals,
+ double *scaleval_list,
+ int (*callback)(sushiv_dimension_t *),
+ unsigned flags);
+extern int sushiv_dim_set_scale(sushiv_dimension_t *d,
+ unsigned scalevals,
+ double *scaleval_list);
+extern int sushiv_dim_set_scalelabels(sushiv_dimension_t *d,
+ char **scalelabel_list);
+
+extern int sushiv_new_objective(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ double (*callback)(double *),
+ unsigned flags);
+
+extern int sushiv_new_panel_2d(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ unsigned scalevals,
+ double *scaleval_list,
+ int *objectives,
+ int *dimensions,
+ unsigned flags);
+
+extern int sushiv_new_panel_1d(sushiv_instance_t *s,
+ int number,
+ const char *name,
+ unsigned scalevals,
+ double *scaleval_list,
+ int *objectives,
+ int *dimensions,
+ unsigned flags);
+
+extern int sushiv_submain(int argc, char *argv[]);
+
+#endif
More information about the commits
mailing list