/* gcc -o pressure-snake pressure-snake.c `pkg-config --cflags --libs gtk+-3.0` */
#include <gtk/gtk.h>
#include <math.h>

#define SNAKE_LENGTH 300
double cursor_x[SNAKE_LENGTH], cursor_y[SNAKE_LENGTH], pressure[SNAKE_LENGTH];
int snake_head = 0;

GtkAdjustment *adjustment;

static void
on_motion_notify (GtkWidget      *window,
                  GdkEventMotion *event)
{
  if (event->window == gtk_widget_get_window (window))
    {
      int i;
      cursor_x[snake_head] = event->x;
      cursor_y[snake_head] = event->y;
      gdk_event_get_axis((GdkEvent *)event, GDK_AXIS_PRESSURE,
                         &pressure[snake_head]);
      snake_head = (snake_head + 1) % SNAKE_LENGTH;
      gtk_widget_queue_draw (window);
    }
}

static void
on_draw (GtkWidget *window,
         cairo_t   *cr)
{
  int i, j;
  float displaying_ms = gtk_adjustment_get_value (adjustment);
  g_usleep (displaying_ms * 1000);

  cairo_set_source_rgb (cr, 0, 0, 0);
  cairo_paint (cr);

  // avoid artefacts
  cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
  cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);

  j = snake_head;
  cairo_move_to (cr, cursor_x[j], cursor_y[j]);
  for (i=1; i<SNAKE_LENGTH; i++) {
    j = (j + 1) % SNAKE_LENGTH;
    gdouble p = pressure[j];
    // gdouble p = ((gdouble)i) / ((gdouble)SNAKE_LENGTH);
    p = p > 1 ? 1 : (p < 0 ? 0 : p); 
    cairo_set_source_rgb (cr, 1.0-p, p, 0.2);
    cairo_set_line_width(cr, 1.0 + 10*p);
    cairo_line_to (cr, cursor_x[j], cursor_y[j]);
    cairo_stroke (cr);
    cairo_move_to (cr, cursor_x[j], cursor_y[j]);
  }
}

int
main (int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *vbox;
  GtkWidget *label;
  GtkWidget *scale;
  GtkWidget *area;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size (GTK_WINDOW (window), 500, 500);
  gtk_widget_set_app_paintable (window, TRUE);
  gtk_widget_add_events (window, GDK_POINTER_MOTION_MASK);
  gtk_widget_set_app_paintable (window, TRUE);

  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
  gtk_container_add (GTK_CONTAINER (window), vbox);

  area = gtk_drawing_area_new();
  gtk_widget_set_has_window(area, TRUE);
  gtk_widget_add_events(area, GDK_BUTTON_MOTION_MASK);
  gtk_widget_add_events(area, GDK_BUTTON1_MASK);
  gtk_box_pack_start (GTK_BOX (vbox), area, TRUE, TRUE, 0);

  adjustment = gtk_adjustment_new (20, 0, 200, 1, 10, 0);
  scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjustment);
  gtk_box_pack_end (GTK_BOX (vbox), scale, FALSE, FALSE, 0);

  label = gtk_label_new ("Screen update time (ms):");
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_box_pack_end (GTK_BOX (vbox), label, FALSE, FALSE, 0);

  g_signal_connect (area, "motion-notify-event",
                    G_CALLBACK (on_motion_notify), NULL);
  g_signal_connect (area, "draw",
                    G_CALLBACK (on_draw), NULL);
  g_signal_connect (window, "destroy",
                    G_CALLBACK (gtk_main_quit), NULL);

  gtk_widget_show_all (window);
  gtk_main ();

  return 0;
}
