head 1.9; access; symbols; locks; strict; comment @ * @; 1.9 date 2005.08.16.00.22.14; author behdad; state Exp; branches; next 1.8; commitid 1daa430131b14567; 1.8 date 2005.08.08.00.31.39; author pippin; state Exp; branches; next 1.7; commitid f1c42f6a7ea4567; 1.7 date 2005.08.07.23.59.48; author pippin; state Exp; branches; next 1.6; commitid 81442f6a0734567; 1.6 date 2005.04.15.18.49.55; author pippin; state Exp; branches; next 1.5; 1.5 date 2005.03.30.12.55.38; author pippin; state Exp; branches; next 1.4; 1.4 date 2004.11.11.15.20.56; author pippin; state Exp; branches; next 1.3; 1.3 date 2004.09.20.16.45.11; author pippin; state Exp; branches; next 1.2; 1.2 date 2004.05.29.16.39.03; author pippin; state Exp; branches; next 1.1; 1.1 date 2004.05.27.19.54.25; author pippin; state Exp; branches; next ; desc @@ 1.9 log @2005-08-15 Behdad Esfahbod * path_paint.c: use Gtk+ proper instead of gtkcairo. Patch from Behnam Esfahbod. (#4081) @ text @#include #include #include #include #include #define WIDTH 800 #define HEIGHT 600 #define STRIDE WIDTH*4 #define MAX_COORDS 1024 /* uncomment this to decrease the density of coordinate samples used for * the current stroke, this is not an optimal solution, a better solution * would be to use actual smoothing on the coordinate data */ #define USE_HINT GtkWidget *canvas = NULL; gboolean pen_color_is_black = TRUE; gint pen_radius = 8; gdouble coord_x [MAX_COORDS]; gdouble coord_y [MAX_COORDS]; gint coord_count = 0; guchar buffer [WIDTH*HEIGHT*4]; guchar temp_buffer [WIDTH*HEIGHT*4]; cairo_surface_t *back_surface = NULL; cairo_surface_t *temp_surface = NULL; cairo_t *cr_save = NULL; gboolean pen_is_down = FALSE; /* utility functions, defined at bottom, * constructing a path from coordinate arrays */ static void points_to_linear_path (cairo_t *cr, gdouble coord_x[], gdouble coord_y[], gint n_coords); static void points_to_bezier_path (cairo_t *cr, gdouble coord_x[], gdouble coord_y[], gint n_coords); static void drawapp_render (cairo_t *cr) { cairo_save (cr); cairo_set_source_rgb (cr, 1,1,1); cairo_paint (cr); cairo_set_source_surface (cr, back_surface, 0, 0); cairo_paint (cr); cairo_set_line_width (cr, pen_radius*2); if (pen_color_is_black) cairo_set_source_rgba (cr, 0,0,0, 0.5); else cairo_set_source_rgba (cr, 1,1,1, 0.5); cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); points_to_bezier_path (cr, coord_x, coord_y, coord_count); cairo_stroke (cr); cairo_restore (cr); } static void apply_coords (guchar *buffer) { drawapp_render (cr_save); memcpy (buffer, temp_buffer, HEIGHT*STRIDE); } static void coords_clear (void) { coord_count = 0; } static void coords_add (gdouble x, gdouble y) { if (coord_count< MAX_COORDS-3) { coord_x [coord_count]=x; coord_y [coord_count]=y; coord_count++; } } static void paint (GtkWidget *widget, GdkEventExpose *eev, gpointer data) { cairo_t *cr; cr = gdk_cairo_create (widget->window); drawapp_render (cr); cairo_destroy (cr); } static void pen_motion (gdouble x, gdouble y) { if (pen_is_down) { coords_add (x,y); gtk_widget_queue_draw (canvas); } } static void pen_down (gdouble x, gdouble y) { pen_is_down = TRUE; coords_add (x,y); gtk_widget_queue_draw (canvas); } static void pen_up (gdouble x, gdouble y) { pen_is_down = FALSE; apply_coords (buffer); coords_clear (); gtk_widget_queue_draw (canvas); } static void init (void) { coords_clear (); memset (buffer, 0, sizeof(buffer)); back_surface = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE); temp_surface = cairo_image_surface_create_for_data (temp_buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE); memset (temp_buffer, 0, sizeof(temp_buffer)); cr_save = cairo_create (temp_surface); } /* just wrapping the gtk events */ static gboolean event_press (GtkWidget *widget, GdkEventButton *bev, gpointer user_data) { pen_down (bev->x, bev->y); return TRUE; } static gboolean event_release (GtkWidget *widget, GdkEventButton *bev, gpointer user_data) { pen_up (bev->x, bev->y); return TRUE; } static gboolean event_motion (GtkWidget *widget, GdkEventMotion *mev, gpointer user_data) { pen_motion (mev->x, mev->y); gdk_window_get_pointer (widget->window, NULL, NULL, NULL); return TRUE; } static gboolean event_keypress (GtkWidget *widget, GdkEventKey *kev, gpointer user_data) { switch (kev->keyval) { case GDK_x: case GDK_X: pen_color_is_black = !pen_color_is_black; default: break; } return TRUE; } gint main (gint argc, gchar **argv) { GtkWidget *mainwin; gtk_init (&argc, &argv); mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL); canvas = gtk_drawing_area_new (); gtk_widget_set_events (canvas, GDK_EXPOSURE_MASK | #ifdef USE_HINT GDK_POINTER_MOTION_HINT_MASK | #endif GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_widget_set_size_request (canvas, WIDTH, HEIGHT); g_signal_connect (mainwin, "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (G_OBJECT (canvas), "expose-event", G_CALLBACK (paint), NULL); g_signal_connect (G_OBJECT (canvas), "motion_notify_event", G_CALLBACK (event_motion), NULL); g_signal_connect (G_OBJECT (canvas), "button_press_event", G_CALLBACK (event_press), NULL); g_signal_connect (G_OBJECT (canvas), "button_release_event", G_CALLBACK (event_release), NULL); g_signal_connect (G_OBJECT (canvas), "key_press_event", G_CALLBACK (event_keypress), NULL); g_object_set (G_OBJECT (canvas), "can_focus", 1, NULL); gtk_container_add (GTK_CONTAINER (mainwin), canvas); init (); gtk_widget_show_all (mainwin); g_print ("press X to change between black and white ink\n"); gtk_main (); return 0; } /* utility function that creates a smooth path from a set * of coordinates */ static void points_to_bezier_path (cairo_t *cr, gdouble coord_x[], gdouble coord_y[], gint n_coords) { gint i; gdouble smooth_value; smooth_value = 1; cairo_new_path (cr); if (!n_coords) return; cairo_move_to (cr, coord_x[0], coord_y[0]); for (i=1;i d20 1 a20 1 GtkWidget *gtkcairo = NULL; a37 7 void destroy () { cairo_destroy (cr_save); } d41 1 a41 1 void d46 1 a46 1 void d53 1 a53 1 void a57 1 cairo_rectangle (cr, 0,0, WIDTH, HEIGHT); d59 1 a59 1 cairo_fill (cr); d62 1 a62 2 cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); cairo_fill (cr); a66 1 { a67 1 } a68 1 { a69 1 } d80 1 a80 1 void d87 1 a87 1 void d93 1 a93 1 void d105 4 a108 4 void paint (GtkCairo *gtkcairo, cairo_t *cr, gpointer data) d110 2 d113 1 d116 1 a116 1 void d118 1 a118 2 gdouble y, gboolean pen_is_down) d123 1 a123 1 gtk_widget_queue_draw (gtkcairo); d127 1 a127 1 void d133 1 a133 1 gtk_widget_queue_draw (gtkcairo); d136 1 a136 1 void d143 1 a143 1 gtk_widget_queue_draw (gtkcairo); d147 1 a147 1 void a160 1 d188 1 a188 1 pen_motion (mev->x, mev->y, pen_is_down); d203 1 a203 4 if (pen_color_is_black) pen_color_is_black = FALSE; else pen_color_is_black = TRUE; d220 1 a220 1 gtkcairo = gtk_cairo_new (); d222 1 a222 1 gtk_widget_set_events (gtkcairo, d231 1 a231 1 gtk_widget_set_size_request (gtkcairo, WIDTH, HEIGHT); d233 3 a235 1 g_signal_connect (G_OBJECT (gtkcairo), "paint", d237 1 a237 1 g_signal_connect (G_OBJECT (gtkcairo), "motion_notify_event", d239 1 a239 1 g_signal_connect (G_OBJECT (gtkcairo), "button_press_event", d241 1 a241 1 g_signal_connect (G_OBJECT (gtkcairo), "button_release_event", d243 1 a243 1 g_signal_connect (G_OBJECT (gtkcairo), "key_press_event", d245 1 a245 1 g_object_set (G_OBJECT (gtkcairo), "can_focus", 1, NULL); d247 1 a247 1 gtk_container_add (GTK_CONTAINER (mainwin), gtkcairo); d262 1 a262 1 void d349 1 a349 1 void @ 1.7 log @update to work with cairo after api shakeup @ text @a73 1 cairo_set_source_rgba (cr, 1,1,1, 0.5); d77 1 a77 1 cairo_set_source_rgb (cr, 0,0,0); d81 1 a81 1 cairo_set_source_rgb (cr, 1,1,1); @ 1.6 log @use cairo_set_source_rgb? @ text @d32 2 a33 1 cairo_surface_t *backbuffer = NULL; d61 1 a61 2 drawapp_render (cairo_t *cr, guchar *buffer) d69 3 a71 2 cairo_move_to (cr, 0,0); cairo_show_surface (cr, backbuffer, WIDTH, HEIGHT); d97 1 a97 1 drawapp_render (cr_save, buffer); d124 1 a124 1 drawapp_render (cr, buffer); d163 1 a163 1 cr_save = cairo_create (); d165 5 d172 1 a172 2 cairo_set_target_image (cr_save, temp_buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE); a173 2 backbuffer = cairo_surface_create_for_image (buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE); @ 1.5 log @reorder arguments to memset @ text @d66 1 a66 1 cairo_set_rgb_color (cr, 1,1,1); d73 1 a73 1 cairo_set_alpha (cr, 0.5); d77 1 a77 1 cairo_set_rgb_color (cr, 0,0,0); d81 1 a81 1 cairo_set_rgb_color (cr, 1,1,1); @ 1.4 log @reorganization of code @ text @d5 1 d163 2 a164 2 memset (buffer, sizeof(buffer), 0); memset (temp_buffer, sizeof(temp_buffer), 0); @ 1.3 log @signal renamed from redraw to paint in late june,. @ text @d8 1 d15 1 a15 1 * would be to use actuall smoothing on the coordinate data d21 2 a22 2 int pen_color_is_black=1; int pen_radius=8; d24 3 a26 3 double coord_x [MAX_COORDS]; double coord_y [MAX_COORDS]; int coord_count = 0; d28 2 a29 2 unsigned char buffer [WIDTH*HEIGHT*4]; unsigned char temp_buffer [WIDTH*HEIGHT*4]; d32 1 a32 1 cairo_t *cr_save = NULL; d34 1 a34 1 int pen_is_down=0; d39 1 a39 1 cairo_destroy (cr_save); d48 3 a50 3 double coord_x[], double coord_y[], int n_coords); d53 3 a55 3 double coord_x[], double coord_y[], int n_coords); d60 1 a60 1 unsigned char *buffer) d62 1 a62 1 cairo_save (cr); d64 3 a66 3 cairo_rectangle (cr, 0,0, WIDTH, HEIGHT); cairo_set_rgb_color (cr, 1,1,1); cairo_fill (cr); d68 2 a69 2 cairo_move_to (cr, 0,0); cairo_show_surface (cr, backbuffer, WIDTH, HEIGHT); d71 2 a72 2 cairo_set_line_width (cr, pen_radius*2); cairo_set_alpha (cr, 0.5); d74 7 a80 4 if (pen_color_is_black) { cairo_set_rgb_color (cr, 0,0,0); } else { cairo_set_rgb_color (cr, 1,1,1); d83 2 a84 2 cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); d86 2 a87 2 points_to_bezier_path (cr, coord_x, coord_y, coord_count); cairo_stroke (cr); d89 1 a89 1 cairo_restore (cr); d93 1 a93 1 apply_coords (char *buffer) d95 2 a96 2 drawapp_render (cr_save, buffer); memcpy (buffer, temp_buffer, HEIGHT*STRIDE); d102 1 a102 1 coord_count = 0; d106 2 a107 1 coords_add (double x, double y) d109 6 a114 5 if (coord_count< MAX_COORDS-3) { coord_x [coord_count]=x; coord_y [coord_count]=y; coord_count++; } d122 1 a122 1 drawapp_render (cr, buffer); d126 3 a128 3 pen_motion (double x, double y, int pen_is_down) d130 4 a133 3 if (pen_is_down) { coords_add (x,y); gtk_widget_queue_draw (gtkcairo); d138 2 a139 2 pen_down (double x, double y) d141 3 a143 2 coords_add (x,y); gtk_widget_queue_draw (gtkcairo); d146 3 a148 2 void pen_up (double x, double y) d150 4 a153 3 apply_coords (buffer); coords_clear (); gtk_widget_queue_draw (gtkcairo); a156 1 d158 1 a158 1 init () d160 4 a163 4 coords_clear (); cr_save = cairo_create (); memset (buffer, sizeof(buffer), 0); memset (temp_buffer, sizeof(temp_buffer), 0); d165 2 a166 2 cairo_set_target_image ( cr_save, temp_buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE); d168 2 a169 2 backbuffer = cairo_surface_create_for_image ( buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE); d172 2 d179 2 a180 3 pen_down (bev->x, bev->y); pen_is_down = 1; return TRUE; d186 1 a186 1 gpointer user_data) d188 2 a189 3 pen_up (bev->x, bev->y); pen_is_down = 0; return TRUE; d197 4 a200 3 pen_motion (mev->x, mev->y, pen_is_down); gdk_window_get_pointer (widget->window, NULL, NULL, NULL); return TRUE; d208 12 a219 11 switch (kev->keyval) { case GDK_x: case GDK_X: if (pen_color_is_black) pen_color_is_black=0; else pen_color_is_black=1; default: break; } return TRUE; d222 3 a224 2 int main (int argc, char **argv) d226 1 a226 1 GtkWidget *mainwin; d228 1 a228 1 gtk_init (&argc, &argv); d230 1 a230 1 mainwin= gtk_window_new (GTK_WINDOW_TOPLEVEL); d232 1 a232 1 gtkcairo = gtk_cairo_new (); d234 2 a235 2 gtk_widget_set_events (gtkcairo, GDK_EXPOSURE_MASK | d237 1 a237 1 GDK_POINTER_MOTION_HINT_MASK | d239 27 a265 25 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_widget_set_size_request (gtkcairo, WIDTH, HEIGHT); g_signal_connect (G_OBJECT (gtkcairo), "paint", G_CALLBACK (paint), NULL); g_signal_connect (G_OBJECT (gtkcairo), "motion_notify_event", G_CALLBACK (event_motion), NULL); g_signal_connect (G_OBJECT (gtkcairo), "button_press_event", G_CALLBACK (event_press), NULL); g_signal_connect (G_OBJECT (gtkcairo), "button_release_event", G_CALLBACK (event_release), NULL); g_signal_connect (G_OBJECT (gtkcairo), "key_press_event", G_CALLBACK (event_keypress), NULL); g_object_set (G_OBJECT (gtkcairo), "can_focus", 1, NULL); gtk_container_add (GTK_CONTAINER (mainwin), gtkcairo); init (); gtk_widget_show_all (mainwin); gtk_main (); return 0; d274 36 a309 33 double coord_x[], double coord_y[], int n_coords) { int i; double smooth_value = 1; cairo_new_path (cr); if (!n_coords) return; cairo_move_to (cr, coord_x[0], coord_y[0]); for (i=1;i