1 #include <stdlib.h>
2 #include <gdk-pixbuf/gdk-pixbuf.h>
3 #include <clutter/clutter.h>
4 #ifdef CLUTTER_WINDOWING_X11
5 #include <clutter/x11/clutter-x11.h>
6 #endif
7 
8 static ClutterActor *
create_content_actor(void)9 create_content_actor (void)
10 {
11   ClutterActor *content;
12   ClutterContent *image;
13   GdkPixbuf *pixbuf;
14 
15   content = clutter_actor_new ();
16   clutter_actor_set_size (content, 720, 720);
17 
18   pixbuf = gdk_pixbuf_new_from_file ("redhand.png", NULL);
19   image = clutter_image_new ();
20   clutter_image_set_data (CLUTTER_IMAGE (image),
21                           gdk_pixbuf_get_pixels (pixbuf),
22                           gdk_pixbuf_get_has_alpha (pixbuf)
23                             ? COGL_PIXEL_FORMAT_RGBA_8888
24                             : COGL_PIXEL_FORMAT_RGB_888,
25                           gdk_pixbuf_get_width (pixbuf),
26                           gdk_pixbuf_get_height (pixbuf),
27                           gdk_pixbuf_get_rowstride (pixbuf),
28                           NULL);
29   g_object_unref (pixbuf);
30 
31   clutter_actor_set_content_scaling_filters (content,
32                                              CLUTTER_SCALING_FILTER_TRILINEAR,
33                                              CLUTTER_SCALING_FILTER_LINEAR);
34   clutter_actor_set_content_gravity (content, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
35   clutter_actor_set_content (content, image);
36   g_object_unref (image);
37 
38   return content;
39 }
40 
41 static gboolean
on_pan(ClutterPanAction * action,ClutterActor * scroll,gboolean is_interpolated,gpointer * user_data)42 on_pan (ClutterPanAction *action,
43         ClutterActor     *scroll,
44         gboolean          is_interpolated,
45         gpointer         *user_data)
46 {
47   gfloat delta_x, delta_y;
48   const ClutterEvent *event = NULL;
49 
50   if (is_interpolated)
51     clutter_pan_action_get_interpolated_delta (action, &delta_x, &delta_y);
52   else
53     {
54       clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (action), 0, &delta_x, &delta_y);
55       event = clutter_gesture_action_get_last_event (CLUTTER_GESTURE_ACTION (action), 0);
56     }
57 
58   g_print ("[%s] panning dx:%.2f dy:%.2f\n",
59            event == NULL ? "INTERPOLATED" :
60            event->type == CLUTTER_MOTION ? "MOTION" :
61            event->type == CLUTTER_TOUCH_UPDATE ? "TOUCH UPDATE" :
62            "?",
63            delta_x, delta_y);
64 
65   return TRUE;
66 }
67 
68 static ClutterActor *
create_scroll_actor(ClutterActor * stage)69 create_scroll_actor (ClutterActor *stage)
70 {
71   ClutterActor *scroll;
72   ClutterAction *pan_action;
73 
74   /* our scrollable viewport */
75   scroll = clutter_actor_new ();
76   clutter_actor_set_name (scroll, "scroll");
77 
78   clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0));
79   clutter_actor_add_constraint (scroll, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0));
80 
81   clutter_actor_add_child (scroll, create_content_actor ());
82 
83   pan_action = clutter_pan_action_new ();
84   clutter_pan_action_set_interpolate (CLUTTER_PAN_ACTION (pan_action), TRUE);
85   g_signal_connect (pan_action, "pan", G_CALLBACK (on_pan), NULL);
86   clutter_actor_add_action_with_name (scroll, "pan", pan_action);
87 
88   clutter_actor_set_reactive (scroll, TRUE);
89 
90   return scroll;
91 }
92 
93 static gboolean
on_key_press(ClutterActor * stage,ClutterEvent * event,gpointer unused)94 on_key_press (ClutterActor *stage,
95               ClutterEvent *event,
96               gpointer      unused)
97 {
98   ClutterActor *scroll;
99   guint key_symbol;
100 
101   scroll = clutter_actor_get_first_child (stage);
102 
103   key_symbol = clutter_event_get_key_symbol (event);
104 
105   if (key_symbol == CLUTTER_KEY_space)
106     {
107       clutter_actor_save_easing_state (scroll);
108       clutter_actor_set_easing_duration (scroll, 1000);
109       clutter_actor_set_child_transform (scroll, NULL);
110       clutter_actor_restore_easing_state (scroll);
111     }
112 
113   return CLUTTER_EVENT_STOP;
114 }
115 
116 static gboolean
label_clicked_cb(ClutterText * label,ClutterEvent * event,ClutterActor * scroll)117 label_clicked_cb (ClutterText *label, ClutterEvent *event, ClutterActor *scroll)
118 {
119   ClutterPanAction *action = CLUTTER_PAN_ACTION (clutter_actor_get_action (scroll, "pan"));
120   const gchar *label_text = clutter_text_get_text (label);
121 
122   if (g_str_equal (label_text, "X AXIS"))
123     clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_X_AXIS);
124   else if (g_str_equal (label_text, "Y AXIS"))
125     clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_Y_AXIS);
126   else if (g_str_equal (label_text, "AUTO"))
127     clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_AXIS_AUTO);
128   else
129     clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_AXIS_NONE);
130 
131   return TRUE;
132 }
133 
134 static void
add_label(const gchar * text,ClutterActor * box,ClutterActor * scroll)135 add_label (const gchar *text, ClutterActor *box, ClutterActor *scroll)
136 {
137   ClutterActor *label;
138 
139   label = clutter_text_new_with_text (NULL, text);
140   clutter_actor_set_reactive (label, TRUE);
141   clutter_actor_set_x_align (label, CLUTTER_ACTOR_ALIGN_START);
142   clutter_actor_set_x_expand (label, TRUE);
143 
144   clutter_actor_add_child (box, label);
145 
146   g_signal_connect (label, "button-release-event",
147                     G_CALLBACK (label_clicked_cb), scroll);
148 }
149 
150 int
main(int argc,char * argv[])151 main (int argc, char *argv[])
152 {
153   ClutterActor *stage, *scroll, *box, *info;
154   ClutterLayoutManager *layout;
155 
156   if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
157     return EXIT_FAILURE;
158 
159   /* create a new stage */
160   stage = clutter_stage_new ();
161   clutter_stage_set_title (CLUTTER_STAGE (stage), "Pan Action");
162   clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
163 
164   scroll = create_scroll_actor (stage);
165   clutter_actor_add_child (stage, scroll);
166 
167   box = clutter_actor_new ();
168   clutter_actor_add_child (stage, box);
169   clutter_actor_set_position (box, 12, 12);
170 
171   layout = clutter_box_layout_new ();
172   clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout), CLUTTER_ORIENTATION_VERTICAL);
173   clutter_actor_set_layout_manager (box, layout);
174 
175   info = clutter_text_new_with_text (NULL, "Press <space> to reset the image position.");
176   clutter_actor_add_child (box, info);
177 
178   info = clutter_text_new_with_text (NULL, "Click labels below to change AXIS pinning.");
179   clutter_actor_add_child (box, info);
180 
181   add_label ("NONE", box, scroll);
182   add_label ("X AXIS", box, scroll);
183   add_label ("Y AXIS", box, scroll);
184   add_label ("AUTO", box, scroll);
185 
186   g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
187   g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), scroll);
188 
189   clutter_actor_show (stage);
190 
191   clutter_main ();
192 
193   return EXIT_SUCCESS;
194 }
195