home *** CD-ROM | disk | FTP | other *** search
/ Freelog 65 / Freelog065.iso / BAS / Bureautique / Gnumeric / gnumeric-1.3.92-rc1.exe / drawingarea.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-10-15  |  8.6 KB  |  324 lines

  1. /* Drawing Area
  2.  *
  3.  * GtkDrawingArea is a blank area where you can draw custom displays
  4.  * of various kinds.
  5.  *
  6.  * This demo has two drawing areas. The checkerboard area shows
  7.  * how you can just draw something; all you have to do is write
  8.  * a signal handler for expose_event, as shown here.
  9.  *
  10.  * The "scribble" area is a bit more advanced, and shows how to handle
  11.  * events such as button presses and mouse motion. Click the mouse
  12.  * and drag in the scribble area to draw squiggles. Resize the window
  13.  * to clear the area.
  14.  */
  15.  
  16. #include <config.h>
  17. #include <gtk/gtk.h>
  18.  
  19. static GtkWidget *window = NULL;
  20. /* Pixmap for scribble area, to store current scribbles */
  21. static GdkPixmap *pixmap = NULL;
  22.  
  23. /* Create a new pixmap of the appropriate size to store our scribbles */
  24. static gboolean
  25. scribble_configure_event (GtkWidget        *widget,
  26.               GdkEventConfigure *event,
  27.               gpointer         data)
  28. {
  29.   if (pixmap)
  30.     g_object_unref (pixmap);
  31.  
  32.   pixmap = gdk_pixmap_new (widget->window,
  33.                widget->allocation.width,
  34.                widget->allocation.height,
  35.                -1);
  36.  
  37.   /* Initialize the pixmap to white */
  38.   gdk_draw_rectangle (pixmap,
  39.               widget->style->white_gc,
  40.               TRUE,
  41.               0, 0,
  42.               widget->allocation.width,
  43.               widget->allocation.height);
  44.  
  45.   /* We've handled the configure event, no need for further processing. */
  46.   return TRUE;
  47. }
  48.  
  49. /* Redraw the screen from the pixmap */
  50. static gboolean
  51. scribble_expose_event (GtkWidget      *widget,
  52.                GdkEventExpose *event,
  53.                gpointer           data)
  54. {
  55.   /* We use the "foreground GC" for the widget since it already exists,
  56.    * but honestly any GC would work. The only thing to worry about
  57.    * is whether the GC has an inappropriate clip region set.
  58.    */
  59.   
  60.   gdk_draw_drawable (widget->window,
  61.              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
  62.              pixmap,
  63.              /* Only copy the area that was exposed. */
  64.              event->area.x, event->area.y,
  65.              event->area.x, event->area.y,
  66.              event->area.width, event->area.height);
  67.   
  68.   return FALSE;
  69. }
  70.  
  71. /* Draw a rectangle on the screen */
  72. static void
  73. draw_brush (GtkWidget *widget,
  74.         gdouble    x,
  75.         gdouble    y)
  76. {
  77.   GdkRectangle update_rect;
  78.  
  79.   update_rect.x = x - 3;
  80.   update_rect.y = y - 3;
  81.   update_rect.width = 6;
  82.   update_rect.height = 6;
  83.  
  84.   /* Paint to the pixmap, where we store our state */
  85.   gdk_draw_rectangle (pixmap,
  86.               widget->style->black_gc,
  87.               TRUE,
  88.               update_rect.x, update_rect.y,
  89.               update_rect.width, update_rect.height);
  90.  
  91.   /* Now invalidate the affected region of the drawing area. */
  92.   gdk_window_invalidate_rect (widget->window,
  93.                   &update_rect,
  94.                   FALSE);
  95. }
  96.  
  97. static gboolean
  98. scribble_button_press_event (GtkWidget        *widget,
  99.                  GdkEventButton *event,
  100.                  gpointer         data)
  101. {
  102.   if (pixmap == NULL)
  103.     return FALSE; /* paranoia check, in case we haven't gotten a configure event */
  104.   
  105.   if (event->button == 1)
  106.     draw_brush (widget, event->x, event->y);
  107.  
  108.   /* We've handled the event, stop processing */
  109.   return TRUE;
  110. }
  111.  
  112. static gboolean
  113. scribble_motion_notify_event (GtkWidget         *widget,
  114.                   GdkEventMotion *event,
  115.                   gpointer          data)
  116. {
  117.   int x, y;
  118.   GdkModifierType state;
  119.  
  120.   if (pixmap == NULL)
  121.     return FALSE; /* paranoia check, in case we haven't gotten a configure event */
  122.  
  123.   /* This call is very important; it requests the next motion event.
  124.    * If you don't call gdk_window_get_pointer() you'll only get
  125.    * a single motion event. The reason is that we specified
  126.    * GDK_POINTER_MOTION_HINT_MASK to gtk_widget_set_events().
  127.    * If we hadn't specified that, we could just use event->x, event->y
  128.    * as the pointer location. But we'd also get deluged in events.
  129.    * By requesting the next event as we handle the current one,
  130.    * we avoid getting a huge number of events faster than we
  131.    * can cope.
  132.    */
  133.   
  134.   gdk_window_get_pointer (event->window, &x, &y, &state);
  135.     
  136.   if (state & GDK_BUTTON1_MASK)
  137.     draw_brush (widget, x, y);
  138.  
  139.   /* We've handled it, stop processing */
  140.   return TRUE;
  141. }
  142.  
  143.  
  144. static gboolean
  145. checkerboard_expose (GtkWidget        *da,
  146.              GdkEventExpose *event,
  147.              gpointer         data)
  148. {
  149.   gint i, j, xcount, ycount;
  150.   GdkGC *gc1, *gc2;
  151.   GdkColor color;
  152.   
  153. #define CHECK_SIZE 10
  154. #define SPACING 2
  155.   
  156.   /* At the start of an expose handler, a clip region of event->area
  157.    * is set on the window, and event->area has been cleared to the
  158.    * widget's background color. The docs for
  159.    * gdk_window_begin_paint_region() give more details on how this
  160.    * works.
  161.    */
  162.  
  163.   /* It would be a bit more efficient to keep these
  164.    * GC's around instead of recreating on each expose, but
  165.    * this is the lazy/slow way.
  166.    */
  167.   gc1 = gdk_gc_new (da->window);
  168.   color.red = 30000;
  169.   color.green = 0;
  170.   color.blue = 30000;
  171.   gdk_gc_set_rgb_fg_color (gc1, &color);
  172.  
  173.   gc2 = gdk_gc_new (da->window);
  174.   color.red = 65535;
  175.   color.green = 65535;
  176.   color.blue = 65535;
  177.   gdk_gc_set_rgb_fg_color (gc2, &color);
  178.   
  179.   xcount = 0;
  180.   i = SPACING;
  181.   while (i < da->allocation.width)
  182.     {
  183.       j = SPACING;
  184.       ycount = xcount % 2; /* start with even/odd depending on row */
  185.       while (j < da->allocation.height)
  186.     {
  187.       GdkGC *gc;
  188.       
  189.       if (ycount % 2)
  190.         gc = gc1;
  191.       else
  192.         gc = gc2;
  193.  
  194.       /* If we're outside event->area, this will do nothing.
  195.        * It might be mildly more efficient if we handled
  196.        * the clipping ourselves, but again we're feeling lazy.
  197.        */
  198.       gdk_draw_rectangle (da->window,
  199.                   gc,
  200.                   TRUE,
  201.                   i, j,
  202.                   CHECK_SIZE,
  203.                   CHECK_SIZE);
  204.  
  205.       j += CHECK_SIZE + SPACING;
  206.       ++ycount;
  207.     }
  208.  
  209.       i += CHECK_SIZE + SPACING;
  210.       ++xcount;
  211.     }
  212.   
  213.   g_object_unref (gc1);
  214.   g_object_unref (gc2);
  215.   
  216.   /* return TRUE because we've handled this event, so no
  217.    * further processing is required.
  218.    */
  219.   return TRUE;
  220. }
  221.  
  222. GtkWidget *
  223. do_drawingarea (GtkWidget *do_widget)
  224. {
  225.   GtkWidget *frame;
  226.   GtkWidget *vbox;
  227.   GtkWidget *da;
  228.   GtkWidget *label;
  229.   
  230.   if (!window)
  231.     {
  232.       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  233.       gtk_window_set_screen (GTK_WINDOW (window),
  234.                  gtk_widget_get_screen (do_widget));
  235.       gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
  236.  
  237.       g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
  238.  
  239.       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
  240.  
  241.       vbox = gtk_vbox_new (FALSE, 8);
  242.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
  243.       gtk_container_add (GTK_CONTAINER (window), vbox);
  244.  
  245.       /*
  246.        * Create the checkerboard area
  247.        */
  248.       
  249.       label = gtk_label_new (NULL);
  250.       gtk_label_set_markup (GTK_LABEL (label),
  251.                 "<u>Checkerboard pattern</u>");
  252.       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  253.       
  254.       frame = gtk_frame_new (NULL);
  255.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  256.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  257.       
  258.       da = gtk_drawing_area_new ();
  259.       /* set a minimum size */
  260.       gtk_widget_set_size_request (da, 100, 100);
  261.  
  262.       gtk_container_add (GTK_CONTAINER (frame), da);
  263.  
  264.       g_signal_connect (da, "expose_event",
  265.             G_CALLBACK (checkerboard_expose), NULL);
  266.  
  267.       /*
  268.        * Create the scribble area
  269.        */
  270.       
  271.       label = gtk_label_new (NULL);
  272.       gtk_label_set_markup (GTK_LABEL (label),
  273.                 "<u>Scribble area</u>");
  274.       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  275.       
  276.       frame = gtk_frame_new (NULL);
  277.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  278.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  279.       
  280.       da = gtk_drawing_area_new ();
  281.       /* set a minimum size */
  282.       gtk_widget_set_size_request (da, 100, 100);
  283.  
  284.       gtk_container_add (GTK_CONTAINER (frame), da);
  285.  
  286.       /* Signals used to handle backing pixmap */
  287.       
  288.       g_signal_connect (da, "expose_event",
  289.             G_CALLBACK (scribble_expose_event), NULL);
  290.       g_signal_connect (da,"configure_event",
  291.             G_CALLBACK (scribble_configure_event), NULL);
  292.       
  293.       /* Event signals */
  294.       
  295.       g_signal_connect (da, "motion_notify_event",
  296.             G_CALLBACK (scribble_motion_notify_event), NULL);
  297.       g_signal_connect (da, "button_press_event",
  298.             G_CALLBACK (scribble_button_press_event), NULL);
  299.  
  300.  
  301.       /* Ask to receive events the drawing area doesn't normally
  302.        * subscribe to
  303.        */
  304.       gtk_widget_set_events (da, gtk_widget_get_events (da)
  305.                  | GDK_LEAVE_NOTIFY_MASK
  306.                  | GDK_BUTTON_PRESS_MASK
  307.                  | GDK_POINTER_MOTION_MASK
  308.                  | GDK_POINTER_MOTION_HINT_MASK);
  309.  
  310.     }
  311.  
  312.   if (!GTK_WIDGET_VISIBLE (window))
  313.     {
  314.       gtk_widget_show_all (window);
  315.     }
  316.   else
  317.     {
  318.       gtk_widget_destroy (window);
  319.       window = NULL;
  320.     }
  321.  
  322.   return window;
  323. }
  324.