Re: gnome-canvas scrolling - simple example



Havoc,

I came up with a pretty clean work-around for the automatic recentering
of the scroll region that was causing me problems. This may be of 
interest to others, so I am attaching the improved c code.

To summarize:
1. set the scrolled region to zero size, at the center of the area
   of interest
2. use gnome_canvas_item_get_bounds to get an area of interest 
   (for a real application i would probably cache this)
3. use gnome_canvas_w2c to convert the bounds to pixels
4. convert from spot in the world (xo,yo) to pixels in the canvas(i,j)
5. set (hadj,vadj)->value to (i,j) - this effectively makes
   (xo,yo) at the center of the window

this seems to work well and is pretty clean.

> If the visible region is
> larger than the scroll region, then IIRC the canvas just centers the
> scroll region in the visible region. It's hard to know what else the
> canvas should do in this case...
>  
> Havoc


thanks for your help and a great book (it is the only computer book
that i have bought that i haven't regretted buying).

Seth
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gnome.h>

typedef struct { GnomeCanvas *canvas; GtkAdjustment *zadj; } mystuff;
static void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); }

static gint my_events (GtkWidget *w,GdkEvent *event,mystuff *z) {
  GdkEventButton *bevent;
  GdkEventMotion *mevent;
  gint tx,ty,x, y, width, height;
  int b1;
  GnomeCanvas *canvas;
  int m2=(GDK_CONTROL_MASK|GDK_MOD1_MASK|GDK_MOD2_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK);
  int m1=(GDK_SHIFT_MASK|m2);
  GtkAdjustment *adj;
  int i,j;

  canvas=GNOME_CANVAS(w);
  gdk_window_get_size(w->window,&width,&height);
  gdk_window_get_pointer (w->window, &tx, &ty, NULL);
  x = (1.0*CLAMP (tx, 0, width-1));
  y = (1.0*CLAMP (ty, 0, height-1));
  b1=0;

  if (event->type==GDK_BUTTON_PRESS) {
    gtk_grab_add (w); bevent=(GdkEventButton *)event;
    if (bevent->button==1 && !(bevent->state & m1)) { b1=1; }
    else if (bevent->button==1 && (bevent->state & GDK_SHIFT_MASK) && !(bevent->state & m2)) { b1=2; }
    else if (bevent->button==3 && (bevent->state & GDK_SHIFT_MASK) && !(bevent->state & m2)) { b1=3; }
  }
  else if (event->type==GDK_BUTTON_RELEASE) {
    gtk_grab_remove(w); bevent=(GdkEventButton *)event; 
    if (bevent->button==1 && !(bevent->state & m1)) { b1=1; }
  }
  else if (event->type==GDK_MOTION_NOTIFY) {
    mevent = (GdkEventMotion *) event; 
    if ((mevent->state & GDK_BUTTON1_MASK) && !(mevent->state & m1)) { b1=1; }
  }

  if (b1==1) {
    double xc1,xc2,yc1,yc2;
    gnome_canvas_item_get_bounds(canvas->root,&xc1,&yc1,&xc2,&yc2);
    if (width>1 && height>1) gnome_canvas_w2c(canvas,xc1+(xc2-xc1)*x/(width-1),yc1+(yc2-yc1)*y/(height-1),&i,&j); else { i=0; j=0; }
  }
  else if (b1==2 || b1==3) {
    gfloat zo,z1,z2;
    double xo,yo;

    i=GTK_LAYOUT(w)->hadjustment->value;
    j=GTK_LAYOUT(w)->vadjustment->value;
    gnome_canvas_c2w(canvas,i,j,&xo,&yo);
    adj=z->zadj;
    zo=adj->value;
    z1=adj->lower;
    z2=adj->upper;

    if (b1==2) (adj->value) *= 2;
    else if (b1==3) (adj->value) /= 2;
    if (adj->value<z1) adj->value=z1;
    if (adj->value>=z2) adj->value=z2;
    if (adj->value != zo)   gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas),adj->value);
    gnome_canvas_w2c(canvas,xo,yo,&i,&j);
  }
  if (b1==1 || b1==2 || b1==3) {
    adj=GTK_LAYOUT(w)->hadjustment; 
    if (adj && width>0) { adj->value=i; gtk_adjustment_value_changed(adj); }
    adj=GTK_LAYOUT(w)->vadjustment;
    if (adj && height>0) { adj->value=j; gtk_adjustment_value_changed(adj); }
  }

  if (0) printf("event: %5d %5d | %d %d \n",width,height,i,j);
  return(0);
}

int main( int argc, char *argv[] ) {
  GtkWidget *window,*canvas;
  GnomeCanvasGroup *root;
  mystuff *z;

  gnome_init ("testGNOME", "1.2", argc, argv);
  gdk_rgb_set_verbose (TRUE);
  gdk_rgb_init ();
  gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
  gtk_widget_set_default_visual (gdk_rgb_get_visual ());

  window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
  gtk_signal_connect (GTK_OBJECT (window), "destroy",(GtkSignalFunc) destroy, NULL);
  gtk_widget_show( window );

  canvas = gnome_canvas_new ();
  root = gnome_canvas_root (GNOME_CANVAS (canvas));
  gnome_canvas_item_new(root,
			gnome_canvas_rect_get_type(),
			"x1",0.0,"x2",100.0,
			"y1",0.0,"y2",100.0,
			"fill_color", "red",
			"outline_color", "black",
			"width_units", 1.0,
			NULL);

  z=(mystuff *)calloc(1,sizeof(mystuff));
  z->canvas=GNOME_CANVAS(canvas);
  z->zadj=GTK_ADJUSTMENT(gtk_adjustment_new (1.00, 0.0625,256, 0.05, 0.50, 0.50));
  gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(canvas),z->zadj->value);

  gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas),50.0,50.0,50.0,50.0);
  gtk_container_add (GTK_CONTAINER (window), canvas);
  gtk_widget_show (canvas);
  gtk_signal_connect_after (GTK_OBJECT (canvas),"event",(GtkSignalFunc) my_events,z);
  GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
  gtk_widget_grab_focus (canvas);
  

  gtk_widget_show_all (window);
  gtk_main ();
  return 0;
}
/* example-end */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]