diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2018-02-02 16:04:17 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2018-02-02 16:46:01 +0100 |
commit | 721e3258020bff31ab01a231f80bf5e2e6309979 (patch) | |
tree | ad9670ac890fe2b0345a5acc8bab446ae00f47b6 | |
parent | 1e52541c22c91e0204cfeb7f1b2aa0a4fc2288d8 (diff) | |
download | gtk+-wip/carlosg/stylus-gesture.tar.gz |
demos: Add "Paint" demowip/carlosg/stylus-gesture
-rw-r--r-- | demos/gtk-demo/demo.gresource.xml | 1 | ||||
-rw-r--r-- | demos/gtk-demo/meson.build | 1 | ||||
-rw-r--r-- | demos/gtk-demo/paint.c | 273 |
3 files changed, 275 insertions, 0 deletions
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index 2d69cdad78..42c0705a90 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -180,6 +180,7 @@ <file>modelbutton.c</file> <file>overlay.c</file> <file>overlay2.c</file> + <file>paint.c</file> <file>pagesetup.c</file> <file>panes.c</file> <file>pickers.c</file> diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index ed2e58c5df..ae1bf7e79f 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -45,6 +45,7 @@ demos = files([ 'modelbutton.c', 'overlay.c', 'overlay2.c', + 'paint.c', 'panes.c', 'pickers.c', 'pixbufs.c', diff --git a/demos/gtk-demo/paint.c b/demos/gtk-demo/paint.c new file mode 100644 index 0000000000..d83c42537b --- /dev/null +++ b/demos/gtk-demo/paint.c @@ -0,0 +1,273 @@ +/* Paint + * + * Demonstrates practical handling of drawing tablets in a real world + * usecase. + */ +#include <gtk/gtk.h> + +typedef struct +{ + GtkWidget parent_instance; + cairo_surface_t *surface; + cairo_t *cr; + GdkRGBA draw_color; + + GtkGesture *stylus_gesture; +} DrawingArea; + +typedef struct +{ + GtkWidgetClass parent_class; +} DrawingAreaClass; + +G_DEFINE_TYPE (DrawingArea, drawing_area, GTK_TYPE_WIDGET) + +static void +drawing_area_ensure_surface (DrawingArea *area, + gint width, + gint height) +{ + if (!area->surface || + cairo_image_surface_get_width (area->surface) != width || + cairo_image_surface_get_height (area->surface) != height) + { + cairo_surface_t *surface; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + if (area->surface) + { + cairo_t *cr; + + cr = cairo_create (surface); + cairo_set_source_surface (cr, area->surface, 0, 0); + cairo_paint (cr); + + cairo_surface_destroy (area->surface); + cairo_destroy (area->cr); + cairo_destroy (cr); + } + + area->surface = surface; + area->cr = cairo_create (surface); + } +} + +static void +drawing_area_size_allocate (GtkWidget *widget, + const GtkAllocation *allocation, + int baseline, + GtkAllocation *out_clip) +{ + DrawingArea *area = (DrawingArea *) widget; + + drawing_area_ensure_surface (area, allocation->width, allocation->height); + + GTK_WIDGET_CLASS (drawing_area_parent_class)->size_allocate (widget, allocation, baseline, out_clip); +} + +static void +drawing_area_map (GtkWidget *widget) +{ + GtkAllocation allocation; + + GTK_WIDGET_CLASS (drawing_area_parent_class)->map (widget); + + gtk_widget_get_allocation (widget, &allocation); + drawing_area_ensure_surface ((DrawingArea *) widget, + allocation.width, allocation.height); +} + +static void +drawing_area_unmap (GtkWidget *widget) +{ + DrawingArea *area = (DrawingArea *) widget; + + g_clear_pointer (&area->cr, cairo_destroy); + g_clear_pointer (&area->surface, cairo_surface_destroy); + + GTK_WIDGET_CLASS (drawing_area_parent_class)->unmap (widget); +} + +static gboolean +drawing_area_draw (GtkWidget *widget, + cairo_t *cr) +{ + DrawingArea *area = (DrawingArea *) widget; + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_surface (cr, area->surface, 0, 0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.6, 0.6, 0.6); + cairo_rectangle (cr, 0, 0, allocation.width, allocation.height); + cairo_stroke (cr); + + return FALSE; +} + +static void +drawing_area_class_init (DrawingAreaClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->size_allocate = drawing_area_size_allocate; + widget_class->draw = drawing_area_draw; + widget_class->map = drawing_area_map; + widget_class->unmap = drawing_area_unmap; +} + +static void +drawing_area_apply_stroke (DrawingArea *area, + GdkDeviceTool *tool, + gdouble x, + gdouble y, + gdouble pressure) +{ + if (gdk_device_tool_get_tool_type (tool) == GDK_DEVICE_TOOL_TYPE_ERASER) + { + cairo_set_line_width (area->cr, 10 * pressure); + cairo_set_operator (area->cr, CAIRO_OPERATOR_DEST_OUT); + } + else + { + cairo_set_line_width (area->cr, 4 * pressure); + cairo_set_operator (area->cr, CAIRO_OPERATOR_SATURATE); + } + + cairo_set_source_rgba (area->cr, area->draw_color.red, + area->draw_color.green, area->draw_color.blue, + area->draw_color.alpha * pressure); + + //cairo_set_source_rgba (area->cr, 0, 0, 0, pressure); + + cairo_line_to (area->cr, x, y); + cairo_stroke (area->cr); + cairo_move_to (area->cr, x, y); +} + +static void +stylus_gesture_down (GtkGestureStylus *gesture, + gdouble x, + gdouble y, + DrawingArea *area) +{ + cairo_new_path (area->cr); +} + +static void +stylus_gesture_motion (GtkGestureStylus *gesture, + gdouble x, + gdouble y, + DrawingArea *area) +{ + GdkTimeCoord *backlog; + GdkDeviceTool *tool; + gdouble pressure; + guint n_items; + + tool = gtk_gesture_stylus_get_device_tool (gesture); + + if (gtk_gesture_stylus_get_backlog (gesture, &backlog, &n_items)) + { + guint i; + + for (i = 0; i < n_items; i++) + { + drawing_area_apply_stroke (area, tool, + backlog[i].axes[GDK_AXIS_X], + backlog[i].axes[GDK_AXIS_Y], + backlog[i].axes[GDK_AXIS_PRESSURE]); + } + } + else + { + if (!gtk_gesture_stylus_get_axis (gesture, GDK_AXIS_PRESSURE, &pressure)) + pressure = 1; + + drawing_area_apply_stroke (area, tool, x, y, pressure); + } + + gtk_widget_queue_draw (GTK_WIDGET (area)); +} + +static void +drawing_area_init (DrawingArea *area) +{ + gtk_widget_set_has_window (GTK_WIDGET (area), FALSE); + + area->stylus_gesture = gtk_gesture_stylus_new (GTK_WIDGET (area)); + g_signal_connect (area->stylus_gesture, "down", + G_CALLBACK (stylus_gesture_down), area); + g_signal_connect (area->stylus_gesture, "motion", + G_CALLBACK (stylus_gesture_motion), area); + + area->draw_color = (GdkRGBA) { 0, 0, 0, 1 }; +} + +GtkWidget * +drawing_area_new (void) +{ + return g_object_new (drawing_area_get_type (), NULL); +} + +void +drawing_area_set_color (DrawingArea *area, + GdkRGBA *color) +{ + area->draw_color = *color; +} + +static void +color_button_color_set (GtkColorButton *button, + DrawingArea *draw_area) +{ + GdkRGBA color; + + gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (button), &color); + drawing_area_set_color (draw_area, &color); +} + +GtkWidget * +do_paint (GtkWidget *toplevel) +{ + static GtkWidget *window = NULL; + + if (!window) + { + GtkWidget *draw_area, *headerbar, *colorbutton; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + draw_area = drawing_area_new (); + gtk_container_add (GTK_CONTAINER (window), draw_area); + + headerbar = gtk_header_bar_new (); + gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), "Paint"); + gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (headerbar), TRUE); + + colorbutton = gtk_color_button_new (); + g_signal_connect (colorbutton, "color-set", + G_CALLBACK (color_button_color_set), draw_area); + gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (colorbutton), + &(GdkRGBA) { 0, 0, 0, 1 }); + + gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), colorbutton); + gtk_window_set_titlebar (GTK_WINDOW (window), headerbar); + + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_widget_destroyed), &window); + + } + + if (!gtk_widget_get_visible (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); + + return window; +} |