diff --git a/c/gtk3/kaleidoscope/kaleidoscope.c b/c/gtk3/kaleidoscope/kaleidoscope.c new file mode 100644 index 0000000..bfc43bf --- /dev/null +++ b/c/gtk3/kaleidoscope/kaleidoscope.c @@ -0,0 +1,100 @@ +#include +#include + + +#define COUNT 16 + +const double pi = 3.141592653589793; + +GtkWidget *window; +cairo_surface_t *surface; +cairo_t *context; + +double mouse_x = 0.0; +double mouse_y = 0.0; + + +void line_polar(double x1, double y1, double x2, double y2) { + double cx = cairo_image_surface_get_width(surface)/2.0; + double cy = cairo_image_surface_get_height(surface)/2.0; + + x1 -= cx; + y1 -= cy; + x2 -= cx; + y2 -= cy; + + double a1 = atan2(y1, x1); + double r1 = sqrt(x1*x1 + y1*y1); + double a2 = atan2(y2, x2); + double r2 = sqrt(x2*x2 + y2*y2); + + cairo_set_source_rgba(context, 0, 0, 0, 1); + cairo_set_line_width(context, 3.0); + cairo_set_line_cap(context, CAIRO_LINE_CAP_ROUND); + for(int sector = 0; sector < COUNT; ++sector) { + x1 = r1 * cos(a1 + sector*2*pi/COUNT) + cx; + y1 = r1 * sin(a1 + sector*2*pi/COUNT) + cy; + x2 = r2 * cos(a2 + sector*2*pi/COUNT) + cx; + y2 = r2 * sin(a2 + sector*2*pi/COUNT) + cy; + cairo_move_to(context, x1, y1); + cairo_line_to(context, x2, y2); + } + cairo_stroke(context); +} + +gboolean motion(GtkWidget *widget, GdkEventMotion *event, gpointer data) { + if (event->state & GDK_BUTTON1_MASK) { + line_polar(mouse_x, mouse_y, event->x, event->y); + cairo_surface_flush(surface); + gtk_widget_queue_draw(window); + } + + if (event->state & GDK_BUTTON3_MASK) { + cairo_save(context); + cairo_set_operator(context, CAIRO_OPERATOR_CLEAR); + cairo_paint(context); + cairo_restore(context); + cairo_surface_flush(surface); + gtk_widget_queue_draw(window); + } + + mouse_x = event->x; + mouse_y = event->y; + return TRUE; +} + +gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data) { + cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 1); + cairo_paint(cr); + cairo_set_source_surface(cr, surface, 0, 0); + cairo_paint(cr); + return TRUE; +} + +void activate(GtkApplication* app, gpointer data) { + window = gtk_application_window_new(app); + g_signal_connect(window, "draw", G_CALLBACK(draw), NULL); + g_signal_connect(window, "motion-notify-event", G_CALLBACK(motion), NULL); + gtk_widget_add_events(window, GDK_POINTER_MOTION_MASK); + gtk_window_set_default_size( + GTK_WINDOW(window), + cairo_image_surface_get_width(surface), + cairo_image_surface_get_height(surface) ); + gtk_widget_show_all(window); +} + +int main(int argc, char **argv) { + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 700, 500); + context = cairo_create(surface); + + GtkApplication *application = gtk_application_new(NULL, 0); + g_signal_connect(application, "activate", G_CALLBACK(activate), NULL); + int status = g_application_run(G_APPLICATION(application), argc, argv); + g_object_unref(application); + + cairo_destroy(context); + cairo_surface_destroy(surface); + return status; +} + +