From b51884cd24b7c74b0c5d89731d93221b022de62a Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Dec 20 2019 16:13:13 +0000 Subject: gtk3: life --- diff --git a/c/gtk3/life/life.c b/c/gtk3/life/life.c new file mode 100644 index 0000000..8e66357 --- /dev/null +++ b/c/gtk3/life/life.c @@ -0,0 +1,120 @@ +#include +#include +#include + +#define ROWS 20 +#define COLS 30 + +const double pi = 3.141592653589793; + +const int size = 20; + +int field1[COLS][ROWS]; +int field2[COLS][ROWS]; +GtkWidget *drawing_area; +GtkWidget *toggle_button; + + +int get_cell(int x, int y) { + x = (x + COLS)%COLS; + y = (y + ROWS)%ROWS; + return field1[x][y]; +} + +gboolean timeout(gpointer data) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button))) { + for(int i = 0; i < COLS; ++i) { + for(int j = 0; j < ROWS; ++j) { + int count = 0; + count += get_cell(i-1, j-1); + count += get_cell(i-1, j); + count += get_cell(i-1, j+1); + count += get_cell(i, j-1); + count += get_cell(i, j+1); + count += get_cell(i+1, j-1); + count += get_cell(i+1, j); + count += get_cell(i+1, j+1); + if (field1[i][j]) { + field2[i][j] = (count == 2 || count == 3); + } else { + field2[i][j] = (count == 3); + } + } + } + for(int i = 0; i < COLS; ++i) + for(int j = 0; j < ROWS; ++j) + field1[i][j] = field2[i][j]; + gtk_widget_queue_draw(drawing_area); + } + 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_rgba(cr, 0.0, 0.0, 0.0, 1); + for(int i = 0; i <= COLS; ++i) { + cairo_move_to(cr, i*size, 0.0); + cairo_line_to(cr, i*size, ROWS*size); + } + for(int j = 0; j < ROWS; ++j) { + cairo_move_to(cr, 0.0, j*size); + cairo_line_to(cr, COLS*size, j*size); + } + cairo_stroke(cr); + + for(int i = 0; i < COLS; ++i) { + for(int j = 0; j < ROWS; ++j) { + if (field1[i][j]) { + cairo_arc(cr, (i + 0.5)*size, (j + 0.5)*size, 0.5*size, 0.0, 2.0*pi); + cairo_fill(cr); + } + } + } + + return TRUE; +} + +gboolean button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) { + int x = (int)(event->x)/size; + int y = (int)(event->y)/size; + if (x >= 0 && y >= 0 && x < COLS && y < ROWS) { + field1[x][y] = !field1[x][y]; + gtk_widget_queue_draw(drawing_area); + } + return TRUE; +} + +void activate(GtkApplication* app, gpointer data) { + srand(time(NULL)); + + GtkWidget *window = gtk_application_window_new (app); + + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + gtk_container_add(GTK_CONTAINER(window), hbox); + + drawing_area = gtk_drawing_area_new(); + gtk_widget_set_size_request(GTK_WIDGET(drawing_area), COLS*size, ROWS*size); + gtk_widget_set_hexpand(drawing_area, TRUE); + gtk_widget_add_events(drawing_area, GDK_BUTTON_PRESS_MASK); + g_signal_connect(drawing_area, "draw", G_CALLBACK(draw), NULL); + g_signal_connect(drawing_area, "button-press-event", G_CALLBACK(button_press), NULL); + gtk_container_add(GTK_CONTAINER(hbox), drawing_area); + + toggle_button = gtk_toggle_button_new_with_label("Start/Stop"); + gtk_widget_set_valign(toggle_button, GTK_ALIGN_START); + gtk_container_add(GTK_CONTAINER(hbox), toggle_button); + + gtk_widget_show_all(window); + + g_timeout_add(100, timeout, NULL); +} + +int main(int argc, char **argv) { + 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); + return status; +}