Advertisement
Guest User

Drawing strokes with cairo

a guest
May 29th, 2014
291
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.24 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <gtk/gtk.h>
  3. #include <cairo.h>
  4.  
  5. GtkWidget* window;
  6. GtkWidget* darea;
  7.  
  8. gboolean full_redraw = FALSE;
  9.  
  10. gboolean pressed = FALSE;
  11. GList* pts = NULL;
  12. cairo_surface_t* surfBuffer = NULL;
  13.  
  14.  
  15. void invalidate_all()
  16. {
  17.     GdkRectangle rect;
  18.  
  19.     gtk_widget_get_allocation(darea, &rect);
  20.  
  21.     gdk_window_invalidate_rect(darea->window, &rect, TRUE);
  22. }
  23.  
  24. void draw_stroke(cairo_t *cr)
  25. {
  26.     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
  27.  
  28.     cairo_set_source_rgba(cr, 1, 0, 0, 0.2);
  29.  
  30.     cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
  31.     cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
  32.     cairo_set_antialias(cr, CAIRO_ANTIALIAS_GOOD);
  33.     cairo_set_line_width(cr, 5);
  34.  
  35.     GList *current = pts;
  36.  
  37.     GdkPoint *cur_pt = (GdkPoint *) current->data;
  38.  
  39.     cairo_move_to(cr, cur_pt->x, cur_pt->y);
  40.  
  41.     current = current->next;
  42.  
  43.     for(; current; current = current->next)
  44.     {
  45.         cur_pt = (GdkPoint *) current->data;
  46.        
  47.         cairo_line_to(cr, cur_pt->x, cur_pt->y);
  48.     }
  49.  
  50.     cairo_stroke(cr);
  51. }
  52.  
  53.  
  54. static gboolean
  55. on_motion_event(GtkWidget *widget,
  56.                 GdkEvent  *event,
  57.                 gpointer   user_data)
  58. {
  59.     if(!pressed)
  60.         return TRUE;
  61.    
  62.     GdkPoint *pt = g_malloc(sizeof(GdkPoint));
  63.    
  64.     pt->x = ((GdkEventButton*)event)->x;
  65.     pt->y = ((GdkEventButton*)event)->y;
  66.    
  67.     pts = g_list_append(pts, pt);
  68.    
  69.     invalidate_all();
  70.    
  71.     return TRUE;
  72. }
  73.  
  74. static gboolean
  75. on_button_press_event(GtkWidget *widget, GdkEventButton *event)
  76. {
  77.     if (event->button == 1)
  78.     {
  79.         pressed = TRUE;
  80.     }
  81.    
  82.     return TRUE;
  83. }
  84.  
  85. static gboolean
  86. on_button_release_event(GtkWidget *widget, GdkEventButton *event)
  87. {
  88.     if (event->button == 1)
  89.     {
  90.         pressed = FALSE;
  91.        
  92.         if(full_redraw)
  93.         {
  94.             cairo_t *cr = cairo_create(surfBuffer);
  95.            
  96.             draw_stroke(cr);
  97.            
  98.             cairo_destroy(cr);
  99.            
  100.             invalidate_all();
  101.         }
  102.        
  103.         g_list_free(pts);
  104.         pts = NULL;
  105.     }
  106.    
  107.     return TRUE;
  108. }
  109.  
  110. static void
  111. on_size_allocate_event(GtkWidget *widget,
  112.                        GdkRectangle *allocation,
  113.                        gpointer user_data)
  114. {
  115.     const gint size = 20;
  116.     const gint w = allocation->width, h = allocation->height;
  117.    
  118.     if(surfBuffer)
  119.     {
  120.         cairo_surface_destroy(surfBuffer);
  121.         surfBuffer = NULL;
  122.     }
  123.    
  124.     surfBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
  125.                                             w, h);
  126.    
  127.     cairo_t* cr = cairo_create(surfBuffer);
  128.    
  129.     // draw a test pattern to the surface...
  130.    
  131.     cairo_rectangle(cr, 0, 0, w, h);
  132.     cairo_set_source_rgb(cr, 1, 1, 1);
  133.     cairo_fill(cr);
  134.    
  135.     gint x = 5, y = 5;
  136.    
  137.     cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
  138.    
  139.     while(x + size < w)
  140.     {
  141.         while(y + size < h)
  142.         {
  143.             cairo_rectangle(cr, x, y, size, size);
  144.             cairo_fill(cr);
  145.            
  146.             y += 5 + size;
  147.         }
  148.        
  149.         y = 5;
  150.         x += 5 + size;
  151.     }
  152.    
  153.     cairo_destroy(cr);
  154.    
  155.     g_list_free(pts);
  156.     pts = NULL;
  157. }
  158.  
  159. static gboolean
  160. on_expose_event(GtkWidget *widget,
  161.                 GdkEventExpose *event,
  162.                 gpointer data)
  163. {
  164.     cairo_t *cr;
  165.     GtkAllocation alloc;
  166.    
  167.     if(!full_redraw && pts)
  168.     {
  169.         GList *last = g_list_last(pts);
  170.         GList *bef = g_list_previous(last);
  171.        
  172.         if(last && bef)
  173.         {
  174.             cairo_t *crBuffer = cairo_create(surfBuffer);
  175.            
  176.             cairo_set_operator(crBuffer, CAIRO_OPERATOR_OVER);
  177.  
  178.             cairo_set_source_rgba(crBuffer, 1, 0, 0, 0.2);
  179.  
  180.             cairo_set_line_join(crBuffer, CAIRO_LINE_JOIN_ROUND);
  181.             cairo_set_line_cap(crBuffer, CAIRO_LINE_CAP_ROUND);
  182.             cairo_set_antialias(crBuffer, CAIRO_ANTIALIAS_GOOD);
  183.             cairo_set_line_width(crBuffer, 5);
  184.            
  185.             GdkPoint *last_pt = (GdkPoint *) last->data;
  186.             GdkPoint *bef_pt = (GdkPoint *) bef->data;
  187.            
  188.            
  189.            
  190.             cairo_move_to(crBuffer, bef_pt->x, bef_pt->y);
  191.             cairo_line_to(crBuffer, last_pt->x, last_pt->y);
  192.            
  193.             cairo_stroke(crBuffer);
  194.            
  195.             cairo_destroy(crBuffer);
  196.         }
  197.     }
  198.    
  199.     gtk_widget_get_allocation(darea, &alloc);
  200.    
  201.     cr = gdk_cairo_create(darea->window);
  202.    
  203.     cairo_set_source_surface(cr, surfBuffer, 0, 0);
  204.    
  205.     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  206.    
  207.     cairo_rectangle(cr, 0, 0, alloc.width, alloc.height);
  208.    
  209.     cairo_fill(cr);
  210.    
  211.     if(!pts || !pressed)
  212.     {
  213.         cairo_destroy(cr);
  214.         return TRUE;
  215.     }
  216.    
  217.     if(full_redraw)
  218.     {
  219.         draw_stroke(cr);
  220.     }
  221.    
  222.     cairo_destroy(cr);
  223.    
  224.     return TRUE;
  225. }
  226.  
  227. int main(int argc, char **argv)
  228. {
  229.     gtk_init(&argc, &argv);    
  230.     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  231.     gtk_window_set_default_size(GTK_WINDOW(window), 390, 240);
  232.  
  233.     darea = gtk_drawing_area_new();
  234.  
  235.     gtk_container_add(GTK_CONTAINER(window), darea);
  236.  
  237.     g_signal_connect(darea, "expose-event",
  238.                      G_CALLBACK(on_expose_event),
  239.                      NULL);
  240.  
  241.     g_signal_connect(darea, "motion-notify-event",
  242.                      G_CALLBACK(on_motion_event),
  243.                      NULL);
  244.  
  245.     g_signal_connect(darea, "button_press_event",
  246.                      G_CALLBACK(on_button_press_event),
  247.                      NULL);
  248.  
  249.     g_signal_connect(darea, "button_release_event",
  250.                      G_CALLBACK(on_button_release_event),
  251.                      NULL);
  252.  
  253.     g_signal_connect(darea, "size-allocate",
  254.                      G_CALLBACK(on_size_allocate_event),
  255.                      NULL);
  256.  
  257.     gtk_widget_set_events(darea, GDK_EXPOSURE_MASK
  258.                             | GDK_LEAVE_NOTIFY_MASK
  259.                             | GDK_BUTTON_PRESS_MASK
  260.                             | GDK_BUTTON_RELEASE_MASK
  261.                             | GDK_POINTER_MOTION_MASK
  262.                             | GDK_POINTER_MOTION_HINT_MASK);
  263.  
  264.     gtk_widget_show_all(window);
  265.  
  266.     gtk_main();
  267.  
  268.     return 0;
  269. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement