// Gtk C code implementing a // Contact Process model // in a Gtk3 written GUI // _________________________ // Juan E. Keymer // // Institute for Advanced Studies // Shenzhen X-Institute // Shenzhen China, May 2024 // Libraries #include // GUI, Gtk Lib #include "CP_core_IPS.h" // Simulation Structures #include "IPS_graphics.h" // Graphics for IPS // Structure & pointer IPSmodel s, *ptr_s; // Update function // simulates the stochastic process // updates the lattice configuration int update_lattice(gpointer data)\ { update_IPS(ptr_s); //Monte Carlo Step paint_lattice(data, ptr_s); g_print ("\tGeneration:\t%u\t\tOccupancy:\t%f\n", s.generation_time, (s.occupancy/(X_SIZE * Y_SIZE))); return 0; } // time handler // connects update function // to the Gtk loop for its computation gboolean time_handler (gpointer data) { update_lattice(data); return TRUE; } // callback to initialize the lattice static void init_lattice(GtkWidget *widget, gpointer data) { initialize_IPS(ptr_s); paint_lattice(data, ptr_s); // log to console g_print ("\tGeneration:\t%u\t\tOccupancy:\t%f\n", s.generation_time, (s.occupancy/(X_SIZE * Y_SIZE))); g_print ("Lattice initialized\n"); } // callback to start the simulation static void start_simulation (GtkWidget *widget, gpointer data) { if(!s.running && s.initialized) { s.run = g_idle_add((GSourceFunc) (GSourceFunc) time_handler, GTK_IMAGE(data)); s.running = TRUE; // log to console g_print ("Simulation started\n"); } } // callback to stop simulation static void stop_simulation (GtkWidget *widget, gpointer data) { if(s.running) { g_source_remove(s.run); s.running = FALSE; // log to console g_print ("Simulation Stopped\n"); } } // callback to respond parameter change scale static void mortality_scale_moved (GtkRange *range, gpointer data) { GtkWidget *label = data; gdouble pos = gtk_range_get_value (range); s.dead_rate = (float) pos; gchar *str = g_strdup_printf ("death = %.2f", pos); gtk_label_set_text (GTK_LABEL (label), str); g_free(str); } // to render parameter control GtkWidget * render_parameter(void) { // to control the parameter of the process GtkWidget *mortality_scale, *mortality_label; GtkWidget *box, *parameter_frame; // Container to pack: horizontal box box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); // label for motality mortality_label = gtk_label_new ("death rate"); /* LABEL*/ gtk_box_pack_start(GTK_BOX(box), mortality_label, TRUE, TRUE, 0); // Scale to set mortality mortality_scale = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0,1,0.01); gtk_range_set_value (GTK_RANGE(mortality_scale), (gfloat) MORTALITY); gtk_box_pack_start(GTK_BOX(box), mortality_scale, TRUE, TRUE, 0); // connect scale and label to handler g_signal_connect (mortality_scale,"value-changed", G_CALLBACK (mortality_scale_moved), mortality_label); // put it all in a frame to return it parameter_frame = gtk_frame_new ("Parameters"); gtk_container_add (GTK_CONTAINER (parameter_frame), box); return parameter_frame; } // to render an image display // for lattice configuration GtkWidget * render_image(void) { // Gtk image widget GtkWidget *image; // Gdk pixbuffer to make an image GdkPixbuf *pixbuf; // pixbuffer pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 0, 8, X_SIZE, Y_SIZE); image = gtk_image_new_from_pixbuf(pixbuf); paint_a_background(image); return image; } // to render simulation controls // initialize, start, stop, about, quit GtkWidget * render_simulation_ctrls(GtkWidget *window, GtkWidget *image_lattice) { // Widgets GtkWidget *button, *button_box, *ctrl_frame; ctrl_frame = gtk_frame_new ("Simulation Control"); button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); // init button = gtk_button_new_with_label ("Init"); g_signal_connect (button, "clicked", G_CALLBACK (init_lattice), GTK_IMAGE (image_lattice)); gtk_container_add (GTK_CONTAINER (button_box), button); // start button = gtk_button_new_with_label ("Start"); g_signal_connect (button, "clicked", G_CALLBACK (start_simulation), GTK_IMAGE (image_lattice)); gtk_container_add (GTK_CONTAINER (button_box), button); // stop button = gtk_button_new_with_label ("Stop"); g_signal_connect (button, "clicked", G_CALLBACK (stop_simulation), NULL /* (gpointer) ptr_s*/); gtk_container_add (GTK_CONTAINER (button_box), button); // about button = gtk_button_new_with_label ("About"); g_signal_connect (button, "clicked", G_CALLBACK (show_about), NULL); gtk_container_add (GTK_CONTAINER (button_box), button); // quit button = gtk_button_new_with_label ("Quit"); g_signal_connect (button, "clicked", G_CALLBACK (stop_simulation), NULL); g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window); gtk_container_add (GTK_CONTAINER (button_box), button); // Add all buttons into a frame gtk_container_add (GTK_CONTAINER (ctrl_frame), button_box); // Return the frame return ctrl_frame; }; // ACTIVATE function with all Widget Initialization and creation static void activate (GtkApplication *app, gpointer user_data) { // get the address (pointer) of the global structure ptr_s = &s; // set up default values //(GUI--IPS_defult_Parameters + randomness) prepare_IPS(ptr_s); // declare a bunch of Gtk widgets for the GUI GtkWidget *window,*grid, *image_lattice,*frame; // Gdk Pixbuffer to draw an image GdkPixbuf *pixbuf; // Create a window and set its title window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "Langton Ant IPS"); gtk_window_set_resizable (GTK_WINDOW(window), FALSE); // Make a grid to pack our Widgets grid = gtk_grid_new (); // Pack the grid in the window gtk_container_add (GTK_CONTAINER (window), grid); // Parameter control frame = render_parameter(); gtk_grid_attach (GTK_GRID (grid), frame, 0, 0, 4, 1); // Lattice configuration image image_lattice = render_image(); gtk_grid_attach (GTK_GRID (grid), image_lattice, 0, 1, 4, 1); // position (0,1) spanning 5 col and 1 raw) // Simulation Control frame = render_simulation_ctrls(window, image_lattice); gtk_grid_attach (GTK_GRID (grid), frame, 0, 2, 4, 1); // Show the window and all widgets gtk_widget_show_all (window); } // Main int main (int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new ("keymer.lab.CP_IPS", G_APPLICATION_FLAGS_NONE); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }