GTK+ Code Demos : Drawing Area (+ Main)


/ Published in: C
Save to your folder(s)

Get from the gtk-demo Application. Drawing Area demo

It's stand alone program you can modify and compil.
It was missing the main in source to be able to use it.


Copy this code and paste it in your HTML
  1. #include <string.h>
  2. #include <gtk/gtk.h>
  3.  
  4. static GtkWidget *window = NULL;
  5.  
  6. /*!
  7.  * \brief Pixmap to scribble area, to store our scribbles
  8.  */
  9. static cairo_surface_t *surface = NULL;
  10.  
  11. /*!
  12.  * \brief Create a new surface of the appropriate size to store our scribbles
  13.  */
  14. static gboolean scribble_configure_event (GtkWidget*, GdkEventConfigure*, gpointer);
  15.  
  16. /*!
  17.  * \brief Redraw the screen from the surface
  18.  */
  19. static gboolean scribble_expose_event (GtkWidget*, GdkEventExpose*, gpointer);
  20.  
  21. /*!
  22.  * \brief Draw a rectangle on the screen
  23.  */
  24. static void draw_brush (GtkWidget *widget, gdouble x, gdouble y);
  25.  
  26. static gboolean scribble_button_press_event (GtkWidget*, GdkEventButton*, gpointer);
  27. static gboolean scribble_motion_notify_event (GtkWidget*, GdkEventMotion*, gpointer);
  28. static gboolean checkerboard_expose (GtkWidget*, GdkEventExpose*, gpointer);
  29. static void close_window (void);
  30. GtkWidget * do_drawingarea ();
  31.  
  32. /*!
  33.  * \brief Create a new surface of the appropriate size to store our scribbles
  34.  */
  35. static gboolean scribble_configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer data)
  36. {
  37. cairo_t *cr = NULL;
  38.  
  39. if (surface)
  40. {
  41. cairo_surface_destroy (surface);
  42. }
  43.  
  44. surface = gdk_window_create_similar_surface (widget -> window,
  45. CAIRO_CONTENT_COLOR,
  46. widget -> allocation.width,
  47. widget -> allocation.height);
  48.  
  49. /* Initialize the surface to white */
  50. cr = cairo_create (surface);
  51. cairo_set_source_rgb (cr, 1, 1, 1);
  52. cairo_paint (cr);
  53. cairo_destroy (cr);
  54.  
  55. /* We've handled the configure event, no need for further processing. */
  56. return TRUE;
  57. }
  58.  
  59. /*!
  60.  * \brief Redraw the screen from the surface
  61.  */
  62. static gboolean scribble_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data)
  63. {
  64. cairo_t *cr = NULL;
  65.  
  66. cr = gdk_cairo_create (widget->window);
  67. cairo_set_source_surface (cr, surface, 0, 0);
  68. gdk_cairo_rectangle (cr, &event->area);
  69. cairo_fill (cr);
  70.  
  71. cairo_destroy (cr);
  72.  
  73. return FALSE;
  74. }
  75.  
  76. /*!
  77.  * \brief Draw a rectangle on the screen
  78.  */
  79. static void draw_brush (GtkWidget *widget, gdouble x, gdouble y)
  80. {
  81. GdkRectangle update_rect;
  82. memset(&update_rect, 0, sizeof(GdkRectangle));
  83.  
  84. cairo_t *cr = NULL;
  85.  
  86. update_rect.x = x - 3;
  87. update_rect.y = y - 3;
  88. update_rect.width = 6;
  89. update_rect.height = 6;
  90.  
  91. /* Paint to the surface, where we store our state */
  92. cr = cairo_create (surface);
  93. gdk_cairo_rectangle (cr, &update_rect);
  94. cairo_fill (cr);
  95. cairo_destroy (cr);
  96.  
  97. /* Now invalidate the affected region of the drawing area. */
  98. gdk_window_invalidate_rect (widget->window,
  99. &update_rect,
  100. FALSE);
  101. }
  102.  
  103. static gboolean scribble_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
  104. {
  105. if (surface == NULL)
  106. {
  107. return FALSE; /* Paranoia check, in case we haven't gotten a configure event */
  108. }
  109.  
  110. if (event->button == 1)
  111. {
  112. draw_brush (widget, event->x, event->y);
  113. }
  114.  
  115. /* We've handled the event, stop processing */
  116. return TRUE;
  117. }
  118.  
  119. static gboolean scribble_motion_notify_event (GtkWidget *widget, GdkEventMotion *event, gpointer data)
  120. {
  121. int x = 0, y = 0;
  122. GdkModifierType state = 0;
  123.  
  124. if (surface == NULL)
  125. {
  126. return FALSE; /* paranoia check, in case we haven't gotten a configure event */
  127. }
  128.  
  129. /* This call is very important; it requests the next motion event.
  130.   * If you don't call gdk_window_get_pointer(), you'll only get a single
  131.   * motion event.The reason is that we specified GDK_POINTER_MOTION_HINT_MASK to gtk_widget_set_events()
  132.   * If we hadn't specified that, we could juste use event->x, event->y as the pointer location.
  133.   * But we'd also get deluged in events.
  134.   * By requesting the next event as we handle the current one, we avoid getting a huge number of
  135.   * events faster than we can cope.
  136.   */
  137. gdk_window_get_pointer (event->window, &x, &y, &state);
  138.  
  139. if (state & GDK_BUTTON1_MASK)
  140. {
  141. draw_brush (widget, x, y);
  142. }
  143.  
  144. /* We've handled it, stop processing */
  145. return TRUE;
  146. }
  147.  
  148. static gboolean checkerboard_expose (GtkWidget *da, GdkEventExpose *event, gpointer data)
  149. {
  150. gint i = 0, j = 0, xcount = 0, ycount = 0;
  151. cairo_t *cr = NULL;
  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 is set on the window, and event
  157.   * ->area has been cleared to the widget's background. The docs for gdk_window_begin_paint_region() give
  158.   * more details on how this works.
  159.   */
  160.  
  161. cr = gdk_cairo_create (da -> window);
  162. gdk_cairo_rectangle (cr, &event->area);
  163. cairo_clip(cr);
  164.  
  165. xcount = 0;
  166. i = SPACING;
  167. while (i < da->allocation.width)
  168. {
  169. j = SPACING;
  170. ycount = xcount %2; /* start with even /odd depending on row */
  171. while (j < da->allocation.height)
  172. {
  173. if (ycount % 2)
  174. {
  175. cairo_set_source_rgb (cr, 0.45777, 0, 0.45777);
  176. }
  177. else
  178. {
  179. cairo_set_source_rgb (cr, 1, 1, 1);
  180. }
  181.  
  182. /* If we're outside event->area, this will do nothing.
  183.   * It might be mildly more efficient if we handled
  184.   * the clipping ourselves, but again we're feeling lazy
  185.   */
  186. cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
  187. cairo_fill(cr);
  188.  
  189. j += CHECK_SIZE + SPACING;
  190. ++ycount;
  191. }
  192.  
  193. i += CHECK_SIZE + SPACING;
  194. ++xcount;
  195. }
  196.  
  197. cairo_destroy (cr);
  198.  
  199. /* return TRUE because we've handled this event, so no further
  200.   * processing is required.
  201.   */
  202. return TRUE;
  203. }
  204.  
  205. static void close_window (void)
  206. {
  207. window = NULL;
  208.  
  209. if (surface)
  210. {
  211. g_object_unref (surface);
  212. }
  213.  
  214. surface = NULL;
  215. gtk_main_quit();
  216. }
  217.  
  218. GtkWidget * do_drawingarea ()
  219. {
  220. GtkWidget *frame = NULL, *vbox = NULL, *da = NULL, *label = NULL;
  221.  
  222. if (!window)
  223. {
  224. window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  225. //gtk_window_set_screen (GTK_WINDOW (window), gtk_widget_get_screen (do_widget));
  226. gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
  227.  
  228. g_signal_connect (G_OBJECT(window), "destroy", G_CALLBACK (close_window), NULL);
  229.  
  230. gtk_container_set_border_width (GTK_CONTAINER (window), 8);
  231.  
  232. vbox = gtk_vbox_new (FALSE, 8);
  233. gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
  234. gtk_container_add (GTK_CONTAINER (window), vbox);
  235.  
  236. /*
  237.   * Create the checkerboard area
  238.   */
  239. label = gtk_label_new (NULL);
  240. gtk_label_set_markup (GTK_LABEL (label), "<u>Checkerboard pattern</u>");
  241.  
  242. gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  243.  
  244. frame = gtk_frame_new (NULL);
  245. gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  246. gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  247.  
  248. da = gtk_drawing_area_new();
  249. /* Set a minimum size */
  250. gtk_widget_set_size_request (da, 100, 100);
  251.  
  252. gtk_container_add (GTK_CONTAINER (frame), da);
  253.  
  254. g_signal_connect (da, "expose-event", G_CALLBACK (checkerboard_expose), NULL);
  255.  
  256. /*
  257.   * Create the scribble area
  258.   */
  259. label = gtk_label_new (NULL);
  260. gtk_label_set_markup (GTK_LABEL (label), "<u>Scribble area</u>");
  261. gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  262.  
  263. frame = gtk_frame_new (NULL);
  264. gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  265. gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  266.  
  267. da = gtk_drawing_area_new();
  268.  
  269. /* Set a minimum size */
  270. gtk_widget_set_size_request (da, 100, 100);
  271.  
  272. gtk_container_add (GTK_CONTAINER (frame), da);
  273.  
  274. /* Signals used to handle backing surface */
  275. g_signal_connect (da, "expose_event", G_CALLBACK (scribble_expose_event), NULL);
  276. g_signal_connect (da, "configure_event", G_CALLBACK (scribble_configure_event), NULL);
  277.  
  278. /* Event signals */
  279. g_signal_connect (da, "motion-notify-event", G_CALLBACK (scribble_motion_notify_event), NULL);
  280. g_signal_connect (da, "button-press-event", G_CALLBACK (scribble_button_press_event), NULL);
  281.  
  282. /* Ask to receive events the drawing area doesn't normally
  283.   * subscribe to
  284.   */
  285. gtk_widget_set_events (da, gtk_widget_get_events (da)
  286. | GDK_LEAVE_NOTIFY_MASK
  287. | GDK_BUTTON_PRESS_MASK
  288. | GDK_POINTER_MOTION_MASK
  289. | GDK_POINTER_MOTION_HINT_MASK);
  290.  
  291. }
  292.  
  293. if (!gtk_widget_get_visible (window))
  294. {
  295. gtk_widget_show_all (window);
  296. }
  297. else
  298. {
  299. gtk_widget_destroy (window);
  300. }
  301.  
  302. return window;
  303. }
  304.  
  305. int main(int argc, char *argv[])
  306. {
  307. gtk_init (&argc, &argv);
  308.  
  309. do_drawingarea();
  310.  
  311. gtk_main();
  312. return 0;
  313. }

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.