1 | #include "demowidget.h" |
2 | #include "demolayout.h" |
3 | |
4 | /* parent widget */ |
5 | |
6 | struct _DemoWidget |
7 | { |
8 | GtkWidget parent_instance; |
9 | |
10 | gboolean backward; /* whether we go 0 -> 1 or 1 -> 0 */ |
11 | gint64 start_time; /* time the transition started */ |
12 | guint tick_id; /* our tick cb */ |
13 | }; |
14 | |
15 | struct _DemoWidgetClass |
16 | { |
17 | GtkWidgetClass parent_class; |
18 | }; |
19 | |
20 | G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET) |
21 | |
22 | /* The widget is controlling the transition by calling |
23 | * demo_layout_set_position() in a tick callback. |
24 | * |
25 | * We take half a second to go from one layout to the other. |
26 | */ |
27 | |
28 | #define DURATION (0.5 * G_TIME_SPAN_SECOND) |
29 | |
30 | static gboolean |
31 | transition (GtkWidget *widget, |
32 | GdkFrameClock *frame_clock, |
33 | gpointer data) |
34 | { |
35 | DemoWidget *self = DEMO_WIDGET (ptr: widget); |
36 | DemoLayout *demo_layout = DEMO_LAYOUT (ptr: gtk_widget_get_layout_manager (widget)); |
37 | gint64 now = g_get_monotonic_time (); |
38 | |
39 | gtk_widget_queue_allocate (widget); |
40 | |
41 | if (self->backward) |
42 | demo_layout_set_position (layout: demo_layout, position: 1.0 - (now - self->start_time) / DURATION); |
43 | else |
44 | demo_layout_set_position (layout: demo_layout, position: (now - self->start_time) / DURATION); |
45 | |
46 | if (now - self->start_time >= DURATION) |
47 | { |
48 | self->backward = !self->backward; |
49 | demo_layout_set_position (layout: demo_layout, position: self->backward ? 1.0 : 0.0); |
50 | /* keep things interesting by shuffling the positions */ |
51 | if (!self->backward) |
52 | demo_layout_shuffle (layout: demo_layout); |
53 | self->tick_id = 0; |
54 | |
55 | return G_SOURCE_REMOVE; |
56 | } |
57 | |
58 | return G_SOURCE_CONTINUE; |
59 | } |
60 | |
61 | static void |
62 | clicked (GtkGestureClick *gesture, |
63 | guint n_press, |
64 | double x, |
65 | double y, |
66 | gpointer data) |
67 | { |
68 | DemoWidget *self = data; |
69 | |
70 | if (self->tick_id != 0) |
71 | return; |
72 | |
73 | self->start_time = g_get_monotonic_time (); |
74 | self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), callback: transition, NULL, NULL); |
75 | } |
76 | |
77 | static void |
78 | demo_widget_init (DemoWidget *self) |
79 | { |
80 | GtkGesture *gesture; |
81 | |
82 | gesture = gtk_gesture_click_new (); |
83 | g_signal_connect (gesture, "pressed" , G_CALLBACK (clicked), self); |
84 | gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture)); |
85 | } |
86 | |
87 | static void |
88 | demo_widget_dispose (GObject *object) |
89 | { |
90 | GtkWidget *child; |
91 | |
92 | while ((child = gtk_widget_get_first_child (GTK_WIDGET (object)))) |
93 | gtk_widget_unparent (widget: child); |
94 | |
95 | G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object); |
96 | } |
97 | |
98 | static void |
99 | demo_widget_class_init (DemoWidgetClass *class) |
100 | { |
101 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
102 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
103 | |
104 | object_class->dispose = demo_widget_dispose; |
105 | |
106 | /* here is where we use our custom layout manager */ |
107 | gtk_widget_class_set_layout_manager_type (widget_class, DEMO_TYPE_LAYOUT); |
108 | } |
109 | |
110 | GtkWidget * |
111 | demo_widget_new (void) |
112 | { |
113 | return g_object_new (DEMO_TYPE_WIDGET, NULL); |
114 | } |
115 | |
116 | void |
117 | demo_widget_add_child (DemoWidget *self, |
118 | GtkWidget *child) |
119 | { |
120 | gtk_widget_set_parent (widget: child, GTK_WIDGET (self)); |
121 | } |
122 | |