[xiph-commits] r12475 - trunk/sushivision

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Thu Feb 15 15:07:43 PST 2007


Author: xiphmont
Date: 2007-02-15 15:07:39 -0800 (Thu, 15 Feb 2007)
New Revision: 12475

Added:
   trunk/sushivision/spinner.c
   trunk/sushivision/spinner.h
Modified:
   trunk/sushivision/Makefile
   trunk/sushivision/internal.h
   trunk/sushivision/main.c
   trunk/sushivision/panel-1d.c
   trunk/sushivision/panel-2d.c
   trunk/sushivision/panel.c
   trunk/sushivision/plot.c
   trunk/sushivision/plot.h
Log:
Complete spinner revamp; move it to a minimal position above plot
Also correct several spinner placement bugs that were killing responsiveness



Modified: trunk/sushivision/Makefile
===================================================================
--- trunk/sushivision/Makefile	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/Makefile	2007-02-15 23:07:39 UTC (rev 12475)
@@ -24,14 +24,14 @@
 SOCFLAGS  = -fPIC
 SOLDFLAGS = -shared -nostdlib -Wl,-soname="lib$(NAME).so.$(MAJOR)"
 
-SRC       = main.c scale.c plot.c slider.c slice.c panel.c panel-1d.c panel-2d.c \
+SRC       = main.c scale.c plot.c slider.c slice.c spinner.c panel.c panel-1d.c panel-2d.c \
 	mapping.c dimension.c function.c objective.c undo.c gtksucks.c \
 	example_fractal.c example_discrete.c	
 INC       = sushivision.h
 MAN	  =
 EXAMPLES  = sushivision_fractal sushivision_discrete
 EX_OBJ    = example_fractal.o example_discrete.o
-OBJ       = main.o scale.o plot.o slider.o slice.o panel.o panel-1d.o panel-2d.o \
+OBJ       = main.o scale.o plot.o slider.o slice.o spinner.c panel.o panel-1d.o panel-2d.o \
 	mapping.o dimension.o function.o objective.o undo.o gtksucks.o
 LIBS      = -lpthread -ldl
 CAIROVER  =  >= 1.0.0

Modified: trunk/sushivision/internal.h
===================================================================
--- trunk/sushivision/internal.h	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/internal.h	2007-02-15 23:07:39 UTC (rev 12475)
@@ -25,6 +25,7 @@
 #include "sushivision.h"
 #include "mapping.h"
 #include "slice.h"
+#include "spinner.h"
 #include "slider.h"
 #include "scale.h"
 #include "gtksucks.h"
@@ -63,6 +64,7 @@
 struct sushiv_panel_internal {
   GtkWidget *toplevel;
   GtkWidget *graph;
+  Spinner *spinner;
   sushiv_dim_widget_t **dim_scales;
 
   int realized;

Modified: trunk/sushivision/main.c
===================================================================
--- trunk/sushivision/main.c	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/main.c	2007-02-15 23:07:39 UTC (rev 12475)
@@ -117,7 +117,7 @@
 	  if(p->private->realized && p->private->graph){
 
 	    if(p->private->map_active){
-	      plot_set_busy(PLOT(p->private->graph));
+	      spinner_set_busy(p->private->spinner);
 	      flag |= p->private->map_action(p); // may drop lock internally
 	      if(!p->private->map_active)
 		set_map_throttle_time(p);
@@ -125,20 +125,20 @@
 	    
 	    // pending legend work?
 	    if(p->private->legend_active){
-	      plot_set_busy(PLOT(p->private->graph));
+	      spinner_set_busy(p->private->spinner);
 	      flag |= p->private->legend_action(p); // may drop lock internally
 	    }
 	    
 	    // pending computation work?
 	    if(p->private->plot_active){
-	      plot_set_busy(PLOT(p->private->graph));
+	      spinner_set_busy(p->private->spinner);
 	      flag |= p->private->compute_action(p,&c[j][i]); // may drop lock internally
 	    }
 	    
 	    if(!p->private->plot_active &&
 	       !p->private->legend_active &&
 	       !p->private->map_active)
-	      plot_set_idle(PLOT(p->private->graph));
+	      spinner_set_idle(p->private->spinner);
 	  }
 	  gdk_threads_leave ();
 	}

Modified: trunk/sushivision/panel-1d.c
===================================================================
--- trunk/sushivision/panel-1d.c	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/panel-1d.c	2007-02-15 23:07:39 UTC (rev 12475)
@@ -1250,18 +1250,26 @@
   g_signal_connect_swapped (G_OBJECT (p->private->toplevel), "delete-event",
 			    G_CALLBACK (_sushiv_clean_exit), (void *)SIGINT);
  
-  p1->top_table = gtk_table_new(3,4,0);
+  p1->top_table = gtk_table_new(5,3,0);
 
   gtk_container_add (GTK_CONTAINER (p->private->toplevel), p1->top_table);
-  gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 5);
+  gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 1);
   
   p1->obj_table = gtk_table_new(p->objectives,5,0);
-  gtk_table_attach(GTK_TABLE(p1->top_table),p1->obj_table,0,4,2,3,
+  gtk_table_attach(GTK_TABLE(p1->top_table),p1->obj_table,0,3,3,4,
 		   GTK_EXPAND|GTK_FILL,0,0,5);
 
+  /* spinner, top bar */
+  {
+    GtkWidget *hbox = gtk_hbox_new(0,0);
+    gtk_table_attach(GTK_TABLE(p1->top_table),hbox,0,4,0,1,GTK_EXPAND|GTK_FILL,0,4,0);
+    gtk_box_pack_end(GTK_BOX(hbox),GTK_WIDGET(p->private->spinner),0,0,0);
+  }
+
+  /* dim table */
   p1->dim_table = gtk_table_new(p->dimensions,3,0);
-  gtk_table_attach(GTK_TABLE(p1->top_table),p1->dim_table,0,4,3,4,
-		   GTK_EXPAND|GTK_FILL,0,0,5);
+  gtk_table_attach(GTK_TABLE(p1->top_table),p1->dim_table,0,4,4,5,
+		   GTK_EXPAND|GTK_FILL,0,4,4);
   
   /* graph */
   {
@@ -1273,8 +1281,11 @@
     p->private->graph = GTK_WIDGET(plot_new(recompute_callback_1d,p,
 					    (void *)(void *)crosshair_callback,p,
 					    box_callback,p,flags)); 
-    gtk_table_attach(GTK_TABLE(p1->top_table),p->private->graph,0,4,0,1,
-		     GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,5);
+    gtk_table_attach(GTK_TABLE(p1->top_table),p->private->graph,0,4,1,2,
+		     GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,4,1);
+    gtk_table_set_row_spacing(GTK_TABLE(p1->top_table),1,4);
+    gtk_table_set_col_spacing(GTK_TABLE(p1->top_table),2,4);
+
   }
 
   /* range slider */
@@ -1288,7 +1299,7 @@
     {
       GtkWidget *label = gtk_label_new("range");
       gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
-      gtk_table_attach(GTK_TABLE(p1->top_table),label,0,1,1,2,
+      gtk_table_attach(GTK_TABLE(p1->top_table),label,0,1,2,3,
 		       GTK_FILL,0,10,0);
     }
 
@@ -1296,9 +1307,9 @@
     sl[0] = slice_new(map_callback_1d,p);
     sl[1] = slice_new(map_callback_1d,p);
 
-    gtk_table_attach(GTK_TABLE(p1->top_table),sl[0],1,2,1,2,
+    gtk_table_attach(GTK_TABLE(p1->top_table),sl[0],1,2,2,3,
 		     GTK_EXPAND|GTK_FILL,0,0,0);
-    gtk_table_attach(GTK_TABLE(p1->top_table),sl[1],2,3,1,2,
+    gtk_table_attach(GTK_TABLE(p1->top_table),sl[1],2,3,2,3,
 		     GTK_EXPAND|GTK_FILL,0,0,0);
     p1->range_slider = slider_new((Slice **)sl,2,
 				  p1->range_scale->label_list,
@@ -1453,6 +1464,7 @@
 
   gtk_widget_realize(p->private->toplevel);
   gtk_widget_realize(p->private->graph);
+  gtk_widget_realize(GTK_WIDGET(p->private->spinner));
   gtk_widget_show_all(p->private->toplevel);
 
   _sushiv_panel_undo_resume(p);

Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/panel-2d.c	2007-02-15 23:07:39 UTC (rev 12475)
@@ -344,16 +344,17 @@
     for(i=0;i<ph;i++){
 
       int yend=ynumB[i];
+
+      gdk_threads_enter ();  
+      if(plot_serialno != p->private->plot_serialno ||
+	 map_serialno != p->private->map_serialno)
+	goto abort;
+      spinner_set_busy(p->private->spinner);
+      gdk_threads_leave();
       
       /* by panel col */
       for(j=0;j<pw;j++){
 	
-	gdk_threads_enter ();  
-	if(plot_serialno != p->private->plot_serialno ||
-	   map_serialno != p->private->map_serialno)
-	  goto abort;
-	gdk_threads_leave();
-
 	lcolor out = (lcolor){0,0,0,0}; 
 	int ydel = ydelA[i];
 	int y = ynumA[i];
@@ -414,13 +415,15 @@
     /* non-resampling render */
     for(i=0;i<ph;i++){
       int *dline = data+i*dw;
+
+      gdk_threads_enter ();  
+      if(plot_serialno != p->private->plot_serialno ||
+	 map_serialno != p->private->map_serialno)
+	goto abort;
+      spinner_set_busy(p->private->spinner);
+      gdk_threads_leave();
       
       for(j=0;j<pw;j++){
-	gdk_threads_enter ();  
-	if(plot_serialno != p->private->plot_serialno ||
-	   map_serialno != p->private->map_serialno)
-	  goto abort;
-	gdk_threads_leave();
 
 	lcolor out = (lcolor){0,0,0,0};
 	l_mapping_calc(map->mapfunc, ol_low, ol_range, dline[j], ol_alpha, 255, &out);
@@ -701,7 +704,8 @@
 }
 
 // assumes data is locked
-static void fast_scale_x(int *data, 
+static void fast_scale_x(Spinner *sp,
+			 int *data, 
 			 int w,
 			 int h,
 			 scalespace new,
@@ -737,6 +741,7 @@
 
   for(y=0;y<h;y++){
     int *data_line = data+y*w;
+    spinner_set_busy(sp);
     for(x=0;x<w;x++){
       if(mapbase[x]<0 || mapbase[x]>=(w-1)){
 	work[x]=-1;
@@ -756,7 +761,8 @@
   }   
 }
 
-static void fast_scale_y(int *data, 
+static void fast_scale_y(Spinner *sp,
+			 int *data, 
 			 int w,
 			 int h,
 			 scalespace new,
@@ -794,6 +800,7 @@
   for(x=0;x<w;x++){
     int *data_column = data+x;
     int stride = w;
+    spinner_set_busy(sp);
     for(y=0;y<h;y++){
       if(mapbase[y]<0 || mapbase[y]>=(h-1)){
 	work[y]=-1;
@@ -816,7 +823,8 @@
   }   
 }
 
-static void fast_scale(int *newdata, 
+static void fast_scale(Spinner *sp, 
+		       int *newdata, 
 		       scalespace xnew,
 		       scalespace ynew,
 		       int *olddata,
@@ -837,33 +845,33 @@
 	int *old_line = olddata+y*old_w;
 	memcpy(new_line,old_line,old_w*(sizeof*new_line));
       }
-      fast_scale_x(newdata,new_w,new_h,xnew,xold);
-      fast_scale_y(newdata,new_w,new_h,ynew,yold);
+      fast_scale_x(sp,newdata,new_w,new_h,xnew,xold);
+      fast_scale_y(sp,newdata,new_w,new_h,ynew,yold);
     }else{
       // scale y in old pane, copy to new, scale x 
-      fast_scale_y(olddata,old_w,old_h,ynew,yold);
+      fast_scale_y(sp,olddata,old_w,old_h,ynew,yold);
       for(y=0;y<new_h;y++){
 	int *new_line = newdata+y*new_w;
 	int *old_line = olddata+y*old_w;
 	memcpy(new_line,old_line,old_w*(sizeof*new_line));
       }
-      fast_scale_x(newdata,new_w,new_h,xnew,xold);
+      fast_scale_x(sp,newdata,new_w,new_h,xnew,xold);
     }
   }else{
     if(new_h > old_h){
       // scale x in old pane, o=copy to new, scale y
-      fast_scale_x(olddata,old_w,old_h,xnew,xold);
+      fast_scale_x(sp,olddata,old_w,old_h,xnew,xold);
       for(y=0;y<old_h;y++){
 	int *new_line = newdata+y*new_w;
 	int *old_line = olddata+y*old_w;
 	memcpy(new_line,old_line,new_w*(sizeof*new_line));
       }
-      fast_scale_y(newdata,new_w,new_h,ynew,yold);
+      fast_scale_y(sp,newdata,new_w,new_h,ynew,yold);
     }else{
       // scale in old pane, copy to new 
       // also the case where newdata == olddata and the size is unchanged
-      fast_scale_x(olddata,old_w,old_h,xnew,xold);
-      fast_scale_y(olddata,old_w,old_h,ynew,yold);
+      fast_scale_x(sp,olddata,old_w,old_h,xnew,xold);
+      fast_scale_y(sp,olddata,old_w,old_h,ynew,yold);
       if(olddata != newdata){
 	for(y=0;y<new_h;y++){
 	  int *new_line = newdata+y*new_w;
@@ -1151,7 +1159,7 @@
 	
 	// zoom scale data in map planes as placeholder for render
 	if(oldmap){
-	  fast_scale(newmap, sx_v, sy_v,
+	  fast_scale(p->private->spinner,newmap, sx_v, sy_v,
 		     oldmap,old_xv, old_yv);
 	  free(oldmap);
 	}
@@ -1460,20 +1468,29 @@
   g_signal_connect_swapped (G_OBJECT (p->private->toplevel), "delete-event",
 			    G_CALLBACK (_sushiv_clean_exit), (void *)SIGINT);
  
-  p2->top_table = gtk_table_new(2 + p->objectives,5,0);
+  p2->top_table = gtk_table_new(3 + p->objectives,5,0);
   gtk_container_add (GTK_CONTAINER (p->private->toplevel), p2->top_table);
-  gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 5);
-  
+  gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 1);
+
+  /* spinner, top bar */
+  {
+    GtkWidget *hbox = gtk_hbox_new(0,0);
+    gtk_table_attach(GTK_TABLE(p2->top_table),hbox,0,5,0,1,GTK_EXPAND|GTK_FILL,0,4,0);
+    gtk_box_pack_end(GTK_BOX(hbox),GTK_WIDGET(p->private->spinner),0,0,0);
+  }
+
+  /* dims */
   p2->dim_table = gtk_table_new(p->dimensions,4,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);
+  gtk_table_attach(GTK_TABLE(p2->top_table),p2->dim_table,0,5,2+p->objectives,3+p->objectives,
+		   GTK_EXPAND|GTK_FILL,0,4,5);
   
   /* graph */
   p->private->graph = GTK_WIDGET(plot_new(recompute_callback_2d,p,
 				  (void *)(void *)_sushiv_panel2d_crosshairs_callback,p,
 				  box_callback,p,0)); 
-  gtk_table_attach(GTK_TABLE(p2->top_table),p->private->graph,0,5,0,1,
-		   GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,5);
+  gtk_table_attach(GTK_TABLE(p2->top_table),p->private->graph,0,5,1,2,
+		   GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,4,1);
+  gtk_table_set_row_spacing(GTK_TABLE(p2->top_table),1,4);
 
   /* objective sliders */
   p2->range_scales = calloc(p->objectives,sizeof(*p2->range_scales));
@@ -1489,7 +1506,7 @@
     /* label */
     GtkWidget *label = gtk_label_new(o->name);
     gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
-    gtk_table_attach(GTK_TABLE(p2->top_table),label,0,1,i+1,i+2,
+    gtk_table_attach(GTK_TABLE(p2->top_table),label,0,1,i+2,i+3,
 		     GTK_FILL,0,10,0);
     
     /* mapping pulldown */
@@ -1501,8 +1518,8 @@
       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);
+      gtk_table_attach(GTK_TABLE(p2->top_table),menu,4,5,i+2,i+3,
+		       GTK_SHRINK,GTK_SHRINK,4,0);
       p2->range_pulldowns[i] = menu;
     }
 
@@ -1511,11 +1528,11 @@
     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_table_attach(GTK_TABLE(p2->top_table),sl[0],1,2,i+2,i+3,
 		     GTK_EXPAND|GTK_FILL,0,0,0);
-    gtk_table_attach(GTK_TABLE(p2->top_table),sl[1],2,3,i+1,i+2,
+    gtk_table_attach(GTK_TABLE(p2->top_table),sl[1],2,3,i+2,i+3,
 		     GTK_EXPAND|GTK_FILL,0,0,0);
-    gtk_table_attach(GTK_TABLE(p2->top_table),sl[2],3,4,i+1,i+2,
+    gtk_table_attach(GTK_TABLE(p2->top_table),sl[2],3,4,i+2,i+3,
 		     GTK_EXPAND|GTK_FILL,0,0,0);
     p2->range_scales[i] = slider_new((Slice **)sl,3,o->scale->label_list,o->scale->val_list,
 				    o->scale->vals,SLIDER_FLAG_INDEPENDENT_MIDDLE);
@@ -1606,6 +1623,7 @@
 
   gtk_widget_realize(p->private->toplevel);
   gtk_widget_realize(p->private->graph);
+  gtk_widget_realize(GTK_WIDGET(p->private->spinner));
   gtk_widget_show_all(p->private->toplevel);
   update_xy_availability(p); // yes, this was already done; however,
 			     // gtk clobbered the event setup on the

Modified: trunk/sushivision/panel.c
===================================================================
--- trunk/sushivision/panel.c	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/panel.c	2007-02-15 23:07:39 UTC (rev 12475)
@@ -179,6 +179,7 @@
   p->flags = flags;
   p->sushi = s;
   p->private = calloc(1, sizeof(*p->private));
+  p->private->spinner = spinner_new();
 
   i=0;
   while(objectives && objectives[i]>=0)i++;

Modified: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/plot.c	2007-02-15 23:07:39 UTC (rev 12475)
@@ -34,69 +34,6 @@
 
 static GtkWidgetClass *parent_class = NULL;
 
-static void plot_draw_busy(Plot *p, cairo_t *c){
-  cairo_surface_t *s = p->stage;
-  int w = cairo_image_surface_get_width(s);
-  int h = cairo_image_surface_get_height(s);
-  int xv[8] = {-20,-13,-10,-13,-20,-27,-30,-27};
-  int yv[8] = {-30,-27,-20,-13,-10,-13,-20,-27};
-  int i;
-  double alpha=1.;
-
-  i = p->busy_count;
-  do{
-    double x = w+xv[i]+.5;
-    double y = h+yv[i]+.5;
-    
-    cairo_set_source_rgba (c, 0,0,.5,1.);
-    cairo_arc(c,x,y,3.5,0,M_PI*2.);
-    cairo_fill(c);
-
-    cairo_set_source_rgba (c, 1.,1.,1.,alpha);
-    cairo_arc(c,x,y,3.5,0,M_PI*2.);
-    cairo_fill(c);
-
-    i--;
-    alpha *=.8;
-    if(i<0)i=7;
-  }while(i!=p->busy_count);
-}
-
-void plot_expose_busy(Plot *p){
-  cairo_surface_t *s = p->stage;
-  int w = cairo_image_surface_get_width(s);
-  int h = cairo_image_surface_get_height(s);
-
-  plot_expose_request_partial(p,w - 40, h - 40, 40, 40);
-}
-
-void plot_set_busy(Plot *p){
-  struct timeval now;
-  long test;
-
-  if(!p->busy){
-    p->busy=1;
-    plot_expose_busy(p);
-  }else{
-    gettimeofday(&now,NULL);
-    
-    test = now.tv_sec*1000 + now.tv_usec/1000;
-    if(p->last_busy_throttle + 100 < test) {
-      p->busy_count++;
-      if(p->busy_count>7)
-	p->busy_count=0;
-      p->last_busy_throttle = test;
-      plot_expose_busy(p);
-      return;
-    }
-  }
-}
-
-void plot_set_idle(Plot *p){
-  p->busy=0;
-  plot_expose_busy(p);
-}
-
 static void draw_scales_work(cairo_surface_t *s, scalespace xs, scalespace ys){
   int w = cairo_image_surface_get_width(s);
   int h = cairo_image_surface_get_height(s);
@@ -470,10 +407,6 @@
       cairo_restore(c);
     }
 
-    // busy indicator
-    if(p->busy)
-      plot_draw_busy(p, c);
-
     cairo_destroy(c);
 
     // blit to window

Modified: trunk/sushivision/plot.h
===================================================================
--- trunk/sushivision/plot.h	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/plot.h	2007-02-15 23:07:39 UTC (rev 12475)
@@ -1,6 +1,6 @@
 /*
  *
- *  sushivision copyright (C) 2005 Monty <monty at xiph.org>
+ *  sushivision copyright (C) 2005-2007 Monty <monty at xiph.org>
  *
  *  sushivision is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -57,9 +57,6 @@
   double selx;
   double sely;
   int cross_active;
-  int busy;
-  int busy_count;
-  time_t last_busy_throttle;
 
   double box_x1;
   double box_y1;
@@ -122,8 +119,5 @@
 void plot_do_enter(Plot *p);
 void plot_do_escape(Plot *p);
 
-void plot_set_busy(Plot *p);
-void plot_set_idle(Plot *p);
-
 #define PLOT_NO_X_CROSS 1
 #define PLOT_NO_Y_CROSS 2

Added: trunk/sushivision/spinner.c
===================================================================
--- trunk/sushivision/spinner.c	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/spinner.c	2007-02-15 23:07:39 UTC (rev 12475)
@@ -0,0 +1,256 @@
+/*
+ *
+ *     sushivision copyright (C) 2006-2007 Monty <monty at xiph.org>
+ *
+ *  sushivision is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *   
+ *  sushivision is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *   
+ *  You should have received a copy of the GNU General Public License
+ *  along with sushivision; see the file COPYING.  If not, write to the
+ *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 
+ */
+
+#define _GNU_SOURCE
+#include <gtk/gtk.h>
+#include <gtk/gtkmain.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include "spinner.h"
+
+static GtkWidgetClass *parent_class = NULL;
+
+#define DIA 4
+#define SPA 6
+
+static void spinner_draw(GtkWidget *wg, cairo_surface_t *s,int n){
+  cairo_t *c = cairo_create(s);
+  int w = cairo_image_surface_get_width(s);
+  int h = cairo_image_surface_get_height(s);
+  int i = n;
+  double alpha = (n>=0?1.:0.);
+
+  if(n==-1)i=n=7;
+
+  GdkColor *bg = &wg->style->bg[GTK_STATE_NORMAL];
+  double shade_r=bg->red/65535.;
+  double shade_g=bg->green/65535.;
+  double shade_b=bg->blue/65535.;
+  cairo_set_source_rgb (c, shade_r,shade_g,shade_b);
+  cairo_paint(c);
+  
+  do{
+    double x = w/2 - 7*SPA/2 + i*SPA +.5;
+    double y = h/2 + .5;
+    
+    cairo_set_source_rgba (c, 0,0,.5,1.);
+    cairo_arc(c,x,y,DIA*.5,0,M_PI*2.);
+    cairo_fill(c);
+
+    cairo_set_source_rgba (c, 1.,1.,1.,alpha);
+    cairo_arc(c,x,y,DIA*.5,0,M_PI*2.);
+    cairo_fill(c);
+
+    i--;
+    alpha *=.8;
+    if(i<0)i=7;
+  }while(i!=n);
+}
+
+static void spinner_init (Spinner *p){
+  // instance initialization
+}
+
+static void spinner_destroy (GtkObject *object){
+  int i;
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+
+  GtkWidget *widget = GTK_WIDGET(object);
+  Spinner *p = SPINNER (widget);
+  // free local resources
+  if(p->wc){
+    cairo_destroy(p->wc);
+    p->wc=0;
+  }
+  if(p->b){
+    for(i=0;i<9;i++)
+      if(p->b[i]){
+	cairo_surface_destroy(p->b[i]);
+	p->b[i]=0;
+      }
+  }
+}
+
+static gint spinner_expose (GtkWidget      *widget,
+			    GdkEventExpose *event){
+  if (GTK_WIDGET_REALIZED (widget)){
+    Spinner *sp = SPINNER (widget);
+    int frame = (sp->busy?sp->busy_count+1:0);
+
+    // blit to window
+    if(sp->b && sp->b[frame]){
+      cairo_set_source_surface(sp->wc,
+			       sp->b[frame],0,0);
+      cairo_paint(sp->wc);
+      gdk_flush();
+    }
+  }
+  return FALSE;
+}
+
+static void spinner_size_request (GtkWidget *widget,
+				  GtkRequisition *requisition){
+  requisition->width = SPA*7 + DIA + 2;
+  requisition->height = DIA + 2;
+}
+
+static void spinner_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;
+
+  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 spinner_size_allocate (GtkWidget     *widget,
+				GtkAllocation *allocation){
+  Spinner *p = SPINNER (widget);
+  int i; 
+
+  if (GTK_WIDGET_REALIZED (widget)){
+
+    if(p->wc)
+      cairo_destroy(p->wc);
+
+    if(p->b){
+      for(i=0;i<9;i++)
+	if(p->b[i]){
+	  cairo_surface_destroy(p->b[i]);
+	  p->b[i]=0;
+	}
+    }
+
+    gdk_window_move_resize (widget->window, allocation->x, allocation->y, 
+			    allocation->width, allocation->height);
+    
+    p->wc = gdk_cairo_create(widget->window);
+
+    for(i=0;i<9;i++){
+      p->b[i] = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+					   allocation->width,
+					   allocation->height);
+      spinner_draw(widget, p->b[i],i-1);
+    }
+  }
+
+  widget->allocation = *allocation;
+}
+
+static void spinner_class_init (SpinnerClass * 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 = spinner_destroy;
+  widget_class->realize = spinner_realize;
+  widget_class->expose_event = spinner_expose;
+  widget_class->size_request = spinner_size_request;
+  widget_class->size_allocate = spinner_size_allocate;
+
+}
+
+GType spinner_get_type (void){
+
+  static GType spinner_type = 0;
+
+  if (!spinner_type)
+    {
+      static const GTypeInfo spinner_info = {
+        sizeof (SpinnerClass),
+        NULL,
+        NULL,
+        (GClassInitFunc) spinner_class_init,
+        NULL,
+        NULL,
+        sizeof (Spinner),
+        0,
+        (GInstanceInitFunc) spinner_init,
+	0
+      };
+
+      spinner_type = g_type_register_static (GTK_TYPE_WIDGET, "Spinner",
+                                               &spinner_info, 0);
+    }
+  
+  return spinner_type;
+}
+
+Spinner *spinner_new (){
+  GtkWidget *g = GTK_WIDGET (g_object_new (SPINNER_TYPE, NULL));
+  Spinner *p = SPINNER (g);
+  return p;
+}
+
+void spinner_set_busy(Spinner *p){
+  struct timeval now;
+  long test;
+
+  if(!p)return;
+  
+  if(!p->busy){
+    p->busy=1;
+    spinner_expose(GTK_WIDGET(p),NULL); // do it now
+  }else{
+    gettimeofday(&now,NULL);
+    
+    test = now.tv_sec*1000 + now.tv_usec/1000;
+    if(p->last_busy_throttle + 100 < test) {
+      p->busy_count++;
+      if(p->busy_count>7)
+	p->busy_count=0;
+      p->last_busy_throttle = test;
+      spinner_expose(GTK_WIDGET(p),NULL); // do it now
+    }
+  }
+}
+
+void spinner_set_idle(Spinner *p){
+  if(!p)return;
+  p->busy=0;
+  spinner_expose(GTK_WIDGET(p),NULL); // do it now
+}
+

Added: trunk/sushivision/spinner.h
===================================================================
--- trunk/sushivision/spinner.h	2007-02-15 03:48:15 UTC (rev 12474)
+++ trunk/sushivision/spinner.h	2007-02-15 23:07:39 UTC (rev 12475)
@@ -0,0 +1,62 @@
+/*
+ *
+ *  sushivision copyright (C) 2005-2007 Monty <monty at xiph.org>
+ *
+ *  sushivision is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *   
+ *  sushivision is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *   
+ *  You should have received a copy of the GNU General Public License
+ *  along with sushivision; see the file COPYING.  If not, write to the
+ *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+G_BEGIN_DECLS
+
+#define SPINNER_TYPE            (spinner_get_type ())
+#define SPINNER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SPINNER_TYPE, Spinner))
+#define SPINNER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SPINNER_TYPE, SpinnerClass))
+#define IS_SPINNER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SPINNER_TYPE))
+#define IS_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPINNER_TYPE))
+
+typedef struct _Spinner       Spinner;
+typedef struct _SpinnerClass  SpinnerClass;
+
+struct _Spinner{
+  GtkWidget w;
+  cairo_t         *wc;
+  cairo_surface_t *b[9];
+
+  int busy;
+  int busy_count;
+  time_t last_busy_throttle;
+};
+
+struct _SpinnerClass{
+  GtkWidgetClass parent_class;
+  void (*spinner) (Spinner *m);
+};
+
+GType     spinner_get_type        (void);
+Spinner  *spinner_new (void);
+
+G_END_DECLS
+
+// the widget subclass half
+void spinner_set_busy(Spinner *p);
+void spinner_set_idle(Spinner *p);



More information about the commits mailing list