-
-typedef struct _Color Color;
-struct _Color {
- double red, green, blue;
-};
-
-static void
-draw_sticks (cairo_t *cr,
- Model *model,
- Color *color)
-{
- int i;
-
- cairo_set_source_rgba (cr, color->red, color->green, color->blue, 1);
- cairo_new_path (cr);
- cairo_set_line_width (cr, 2);
- cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
-
- for (i = 0; i < model->num_sticks; i++) {
- cairo_move_to (cr,
- model->sticks[i].a->position.x,
- model->sticks[i].a->position.y);
- cairo_line_to (cr,
- model->sticks[i].b->position.x,
- model->sticks[i].b->position.y);
- }
-
- cairo_stroke (cr);
-}
-
-static void
-draw_offsets (cairo_t *cr,
- Model *model,
- Color *color)
-{
- int i;
-
- cairo_set_source_rgba (cr, color->red, color->green, color->blue, 0.5);
- cairo_new_path (cr);
- cairo_set_line_width (cr, 4);
- cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
-
- for (i = 0; i < model->num_offsets; i++) {
- cairo_move_to (cr,
- model->offsets[i].a->position.x,
- model->offsets[i].a->position.y);
- cairo_line_to (cr,
- model->offsets[i].b->position.x,
- model->offsets[i].b->position.y);
- }
-
- cairo_stroke (cr);
-}
-
-static void
-draw_constraints (cairo_t *cr,
- Model *model,
- Color *color)
-{
- cairo_set_source_rgba (cr, color->red, color->green, color->blue, 0.5);
-
- cairo_move_to (cr, 0, ground_level);
- cairo_line_to (cr, 1500, ground_level);
- cairo_line_to (cr, 1500, ground_level + 10);
- cairo_line_to (cr, 0, ground_level + 10);
- cairo_close_path (cr);
-
- cairo_move_to (cr, 0, box_top);
- cairo_line_to (cr, box_left, box_top);
- cairo_line_to (cr, box_left, box_bottom);
- cairo_line_to (cr, 0, box_bottom);
- cairo_close_path (cr);
-
- cairo_fill (cr);
-}
-
-static void
-draw_objects (cairo_t *cr, Model *model, Color *color)
-{
- int i;
-
- for (i = 0; i < model->num_objects; i++) {
- }
-}
-
-static Color blue = { 0, 0, 1 };
-static Color red = { 1, 0, 0 };
-static Color black = { 0, 0, 0 };
-static Color white = { 1, 1, 1 };
-
-static gboolean
-sproing_expose_event (GtkWidget *widget,
- GdkEventExpose *event,
- gpointer data)
-{
- Model *model = data;
- cairo_t *cr;
-
- cr = gdk_cairo_create (widget->window);
-
- cairo_set_source_rgb (cr, 1, 1, 1);
- cairo_paint (cr);
-
- draw_constraints (cr, model, &red);
- draw_sticks (cr, model, &black);
- draw_offsets (cr, model, &blue);
- draw_objects (cr, model, &white);
-
- cairo_destroy (cr);
-
- return TRUE;
-}
-
-static gboolean
-sproing_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data)
-{
- Model *model = data;
-
- if (event->button != 1)
- return TRUE;
-
- model->anchor_position.x = event->x;
- model->anchor_position.y = event->y;
- model->anchor_object = model_find_nearest (model, event->x, event->y);
-
- return TRUE;
-}
-
-static gboolean
-sproing_button_release_event (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data)
-{
- Model *model = data;
-
- if ((event->state & GDK_BUTTON1_MASK) == 0)
- return TRUE;
-
- model->anchor_object = NULL;
-
- return TRUE;
-}
-
-static gboolean
-sproing_motion_notify_event (GtkWidget *widget,
- GdkEventMotion *event,
- gpointer data)
-{
- Model *model = data;
- int x, y;
- GdkModifierType state;
-
- gdk_window_get_pointer (event->window, &x, &y, &state);
-
- model->anchor_position.x = x + 0.5;
- model->anchor_position.y = y + 0.5;
-
- return TRUE;
-}
-
-static void
-spring_constant_changed (GtkSpinButton *spinbutton, gpointer user_data)
-{
- Model *model = user_data;
-
- model->k = gtk_spin_button_get_value (spinbutton);
-}
-
-static void
-friction_changed (GtkSpinButton *spinbutton, gpointer user_data)
-{
- Model *model = user_data;
-
- model->friction = gtk_spin_button_get_value (spinbutton);
-}
-
-static GtkWidget *
-create_spinners (Model *model)
-{
- GtkWidget *hbox;
- GtkWidget *spinner, *label;
-
- hbox = gtk_hbox_new (FALSE, 8);
-
- label = gtk_label_new_with_mnemonic ("_Spring constant:");
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- spinner = gtk_spin_button_new_with_range (0.05, 30.00, 0.05);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
- gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinner), model->k);
- g_signal_connect (spinner, "value-changed",
- G_CALLBACK (spring_constant_changed), model);
-
- label = gtk_label_new_with_mnemonic ("_Friction:");
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- spinner = gtk_spin_button_new_with_range (0.05, 15.00, 0.05);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
- gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinner), model->friction);
- g_signal_connect (spinner, "value-changed",
- G_CALLBACK (friction_changed), model);
-
- return hbox;
-}
-
-static GtkWidget *
-create_window (Model *model)
-{
- GtkWidget *window;
- GtkWidget *frame;
- GtkWidget *vbox;
- GtkWidget *da;
- GtkWidget *spinners;
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
-
- g_signal_connect (window, "destroy",
- G_CALLBACK (gtk_main_quit), &window);
-
- gtk_container_set_border_width (GTK_CONTAINER (window), 8);
-
- vbox = gtk_vbox_new (FALSE, 8);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
- gtk_container_add (GTK_CONTAINER (window), vbox);
-
- /*
- * Create the drawing area
- */
-
- frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
-
- da = gtk_drawing_area_new ();
- /* set a minimum size */
- gtk_widget_set_size_request (da, 600, 500);
-
- gtk_container_add (GTK_CONTAINER (frame), da);
-
- /* Signals used to handle backing pixmap */
-
- g_signal_connect (da, "expose_event",
- G_CALLBACK (sproing_expose_event), model);
-
- /* Event signals */
-
- g_signal_connect (da, "motion_notify_event",
- G_CALLBACK (sproing_motion_notify_event), model);
- g_signal_connect (da, "button_press_event",
- G_CALLBACK (sproing_button_press_event), model);
- g_signal_connect (da, "button_release_event",
- G_CALLBACK (sproing_button_release_event), model);
-
- /* Ask to receive events the drawing area doesn't normally
- * subscribe to
- */
- gtk_widget_set_events (da, gtk_widget_get_events (da)
- | GDK_LEAVE_NOTIFY_MASK
- | GDK_BUTTON_PRESS_MASK
- | GDK_BUTTON_RELEASE_MASK
- | GDK_POINTER_MOTION_MASK
- | GDK_POINTER_MOTION_HINT_MASK);
-
- spinners = create_spinners (model);
- gtk_box_pack_start (GTK_BOX (vbox), spinners, FALSE, FALSE, 0);
-
- return da;
-}
-
-typedef struct _Closure Closure;
-struct _Closure {
- GtkWidget *drawing_area;
- Model *model;
- int i;
-};
-
-static gint
-timeout_callback (gpointer data)
-{
- Closure *closure = data;
- int i;
-
- for (i = 0; i < 3; i++)
- model_step (closure->model, 0.5);
-
- closure->i++;
- if (closure->i == 1) {
- gtk_widget_queue_draw (closure->drawing_area);
- closure->i = 0;
- }
-
- return TRUE;
-}
-
-int
-main (int argc, char *argv[])
-{
- Closure closure;
- Model model;
-
- gtk_init (&argc, &argv);
- model_init_curtain (&model);
- closure.drawing_area = create_window (&model);
- closure.i = 0;
- gtk_widget_show_all (gtk_widget_get_toplevel (closure.drawing_area));
- closure.model = &model;
- g_timeout_add (100, timeout_callback, &closure);
- gtk_main ();
-
- return 0;
-}