summaryrefslogtreecommitdiff
path: root/demos/gtk-demo/demowidget.c
blob: 16c5c28ad349f6f6d60d3b88fa998513e4ce674b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "demowidget.h"
#include "demolayout.h"

/* parent widget */

struct _DemoWidget
{
  GtkWidget parent_instance;

  gboolean backward; /* whether we go 0 -> 1 or 1 -> 0 */
  gint64 start_time; /* time the transition started */
  guint tick_id;     /* our tick cb */
};

struct _DemoWidgetClass
{
  GtkWidgetClass parent_class;
};

G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET)

/* The widget is controlling the transition by calling
 * demo_layout_set_position() in a tick callback.
 *
 * We take half a second to go from one layout to the other.
 */

#define DURATION (0.5 * G_TIME_SPAN_SECOND)

static gboolean
transition (GtkWidget     *widget,
            GdkFrameClock *frame_clock,
            gpointer       data)
{
  DemoWidget *self = DEMO_WIDGET (widget);
  DemoLayout *demo_layout = DEMO_LAYOUT (gtk_widget_get_layout_manager (widget));
  gint64 now = g_get_monotonic_time ();

  gtk_widget_queue_allocate (widget);

  if (self->backward)
    demo_layout_set_position (demo_layout, 1.0 - (now - self->start_time) / DURATION);
  else
    demo_layout_set_position (demo_layout, (now - self->start_time) / DURATION);

  if (now - self->start_time >= DURATION)
    {
      self->backward = !self->backward;
      demo_layout_set_position (demo_layout, self->backward ? 1.0 : 0.0);
      /* keep things interesting by shuffling the positions */
      if (!self->backward)
        demo_layout_shuffle (demo_layout);
      self->tick_id = 0;

      return G_SOURCE_REMOVE;
    }

  return G_SOURCE_CONTINUE;
}

static void
clicked (GtkGestureClick *gesture,
         guint            n_press,
         double           x,
         double           y,
         gpointer         data)
{
  DemoWidget *self = data;

  if (self->tick_id != 0)
    return;

  self->start_time = g_get_monotonic_time ();
  self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), transition, NULL, NULL);
}

static void
demo_widget_init (DemoWidget *self)
{
  GtkGesture *gesture;

  gesture = gtk_gesture_click_new ();
  g_signal_connect (gesture, "pressed", G_CALLBACK (clicked), self);
  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
}

static void
demo_widget_dispose (GObject *object)
{
  GtkWidget *child;

  while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))))
    gtk_widget_unparent (child);

  G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object);
}

static void
demo_widget_class_init (DemoWidgetClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);

  object_class->dispose = demo_widget_dispose;

  /* here is where we use our custom layout manager */
  gtk_widget_class_set_layout_manager_type (widget_class, DEMO_TYPE_LAYOUT);
}

GtkWidget *
demo_widget_new (void)
{
  return g_object_new (DEMO_TYPE_WIDGET, NULL);
}

void
demo_widget_add_child (DemoWidget *self,
                       GtkWidget  *child)
{
  gtk_widget_set_parent (child, GTK_WIDGET (self));
}