From ddfb72868742434d9660e8a5c5cf94af6e59e324 Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Tue, 2 Apr 2024 12:53:31 -0400 Subject: [PATCH] *: add source from drawing example and using gtk builder Signed-off-by: Vincent Batts --- Makefile | 12 ++++ builder.ui | 38 +++++++++++ example-3.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++ example-4.c | 59 +++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 builder.ui create mode 100644 example-3.c create mode 100644 example-4.c diff --git a/Makefile b/Makefile index 66aafb8..49b87b2 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,18 @@ CFLAGS ?= -Wall -g $(shell pkg-config --cflags gtk4) LDFLAGS ?= $(shell pkg-config --libs gtk4) CLEANFILES := +all: main example-3 example-4 + +example-3: example-3.c + gcc $(CFLAGS) -o $@ $< $(LDFLAGS) + +CLEANFILES += example-3 + +example-4: example-4.c + gcc $(CFLAGS) -o $@ $< $(LDFLAGS) + +CLEANFILES += example-4 + main: main.c gcc $(CFLAGS) -o $@ $< $(LDFLAGS) diff --git a/builder.ui b/builder.ui new file mode 100644 index 0000000..194fcde --- /dev/null +++ b/builder.ui @@ -0,0 +1,38 @@ + + + + Grid + + + + + Button 1 + + 0 + 0 + + + + + + Button 2 + + 1 + 0 + + + + + + Quit + + 0 + 1 + 2 + + + + + + + diff --git a/example-3.c b/example-3.c new file mode 100644 index 0000000..3e18f23 --- /dev/null +++ b/example-3.c @@ -0,0 +1,187 @@ +#include + +/* Surface to store current scribbles */ +static cairo_surface_t *surface = NULL; + +static void +clear_surface (void) +{ + cairo_t *cr; + + cr = cairo_create (surface); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_destroy (cr); +} + +/* Create a new surface of the appropriate size to store our scribbles */ +static void +resize_cb (GtkWidget *widget, + int width, + int height, + gpointer data) +{ + if (surface) + { + cairo_surface_destroy (surface); + surface = NULL; + } + + if (gtk_native_get_surface (gtk_widget_get_native (widget))) + { + surface = gdk_surface_create_similar_surface (gtk_native_get_surface (gtk_widget_get_native (widget)), + CAIRO_CONTENT_COLOR, + gtk_widget_get_width (widget), + gtk_widget_get_height (widget)); + + /* Initialize the surface to white */ + clear_surface (); + } +} + +/* Redraw the screen from the surface. Note that the draw + * callback receives a ready-to-be-used cairo_t that is already + * clipped to only draw the exposed areas of the widget + */ +static void +draw_cb (GtkDrawingArea *drawing_area, + cairo_t *cr, + int width, + int height, + gpointer data) +{ + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); +} + +/* Draw a rectangle on the surface at the given position */ +static void +draw_brush (GtkWidget *widget, + double x, + double y) +{ + cairo_t *cr; + + /* Paint to the surface, where we store our state */ + cr = cairo_create (surface); + + cairo_rectangle (cr, x - 3, y - 3, 6, 6); + cairo_fill (cr); + + cairo_destroy (cr); + + /* Now invalidate the drawing area. */ + gtk_widget_queue_draw (widget); +} + +static double start_x; +static double start_y; + +static void +drag_begin (GtkGestureDrag *gesture, + double x, + double y, + GtkWidget *area) +{ + start_x = x; + start_y = y; + + draw_brush (area, x, y); +} + +static void +drag_update (GtkGestureDrag *gesture, + double x, + double y, + GtkWidget *area) +{ + draw_brush (area, start_x + x, start_y + y); +} + +static void +drag_end (GtkGestureDrag *gesture, + double x, + double y, + GtkWidget *area) +{ + draw_brush (area, start_x + x, start_y + y); +} + +static void +pressed (GtkGestureClick *gesture, + int n_press, + double x, + double y, + GtkWidget *area) +{ + clear_surface (); + gtk_widget_queue_draw (area); +} + +static void +close_window (void) +{ + if (surface) + cairo_surface_destroy (surface); +} + +static void +activate (GtkApplication *app, + gpointer user_data) +{ + GtkWidget *window; + GtkWidget *frame; + GtkWidget *drawing_area; + GtkGesture *drag; + GtkGesture *press; + + window = gtk_application_window_new (app); + gtk_window_set_title (GTK_WINDOW (window), "Drawing Area"); + + g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL); + + frame = gtk_frame_new (NULL); + gtk_window_set_child (GTK_WINDOW (window), frame); + + drawing_area = gtk_drawing_area_new (); + /* set a minimum size */ + gtk_widget_set_size_request (drawing_area, 100, 100); + + gtk_frame_set_child (GTK_FRAME (frame), drawing_area); + + gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area), draw_cb, NULL, NULL); + + g_signal_connect_after (drawing_area, "resize", G_CALLBACK (resize_cb), NULL); + + drag = gtk_gesture_drag_new (); + gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY); + gtk_widget_add_controller (drawing_area, GTK_EVENT_CONTROLLER (drag)); + g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), drawing_area); + g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), drawing_area); + g_signal_connect (drag, "drag-end", G_CALLBACK (drag_end), drawing_area); + + press = gtk_gesture_click_new (); + gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (press), GDK_BUTTON_SECONDARY); + gtk_widget_add_controller (drawing_area, GTK_EVENT_CONTROLLER (press)); + + g_signal_connect (press, "pressed", G_CALLBACK (pressed), drawing_area); + + gtk_window_present (GTK_WINDOW (window)); +} + +int +main (int argc, + char **argv) +{ + GtkApplication *app; + int status; + + app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); + status = g_application_run (G_APPLICATION (app), argc, argv); + g_object_unref (app); + + return status; +} diff --git a/example-4.c b/example-4.c new file mode 100644 index 0000000..fbfb982 --- /dev/null +++ b/example-4.c @@ -0,0 +1,59 @@ +#include +#include + +static void +print_hello (GtkWidget *widget, + gpointer data) +{ + g_print ("Hello World\n"); +} + +static void +quit_cb (GtkWindow *window) +{ + gtk_window_close (window); +} + +static void +activate (GtkApplication *app, + gpointer user_data) +{ + /* Construct a GtkBuilder instance and load our UI description */ + GtkBuilder *builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, "builder.ui", NULL); + + /* Connect signal handlers to the constructed widgets. */ + GObject *window = gtk_builder_get_object (builder, "window"); + gtk_window_set_application (GTK_WINDOW (window), app); + + GObject *button = gtk_builder_get_object (builder, "button1"); + g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL); + + button = gtk_builder_get_object (builder, "button2"); + g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL); + + button = gtk_builder_get_object (builder, "quit"); + g_signal_connect_swapped (button, "clicked", G_CALLBACK (quit_cb), window); + + gtk_widget_set_visible (GTK_WIDGET (window), TRUE); + + /* We do not need the builder any more */ + g_object_unref (builder); +} + +int +main (int argc, + char *argv[]) +{ +#ifdef GTK_SRCDIR + g_chdir (GTK_SRCDIR); +#endif + + GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); + + int status = g_application_run (G_APPLICATION (app), argc, argv); + g_object_unref (app); + + return status; +}