1 /*
2 * Load an image into a texture, which can then be zoomed in/out
3 * (double click on button 1, double click on button 3 respectively);
4 * also resets the texture to the stage center when a key is pressed
5 * (better would be to prevent drags taking the actor off-stage,
6 * but the implementation is much more complicated)
7 */
8 #include <stdlib.h>
9 #include <clutter/clutter.h>
10
11 #define STAGE_SIDE 400.0
12
13 static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
14
15 /* on key press, center the actor on the stage;
16 * useful if you drag it off-stage accidentally
17 */
18 static gboolean
key_press_cb(ClutterActor * actor,ClutterEvent * event,gpointer user_data)19 key_press_cb (ClutterActor *actor,
20 ClutterEvent *event,
21 gpointer user_data)
22 {
23 gfloat width, height;
24
25 clutter_actor_get_size (actor, &width, &height);
26
27 clutter_actor_set_anchor_point (actor, width / 2, height / 2);
28
29 clutter_actor_set_position (actor,
30 STAGE_SIDE / 2,
31 STAGE_SIDE / 2);
32
33 return TRUE;
34 }
35
36 /* on double click, zoom in on the clicked point;
37 * also keeps scale in the range 0.1 to 20
38 */
39 static gboolean
clicked_cb(ClutterActor * actor,ClutterEvent * event,gpointer user_data)40 clicked_cb (ClutterActor *actor,
41 ClutterEvent *event,
42 gpointer user_data)
43 {
44 gdouble scale;
45 gfloat click_x, click_y;
46 gfloat click_target_x, click_target_y;
47 guint32 button;
48
49 /* don't do anything unless there was a double click */
50 if (clutter_event_get_click_count (event) < 2)
51 return TRUE;
52
53 /* work out new scale */
54 button = clutter_event_get_button (event);
55
56 clutter_actor_get_scale (actor, &scale, NULL);
57
58 if (button == CLUTTER_BUTTON_PRIMARY)
59 scale *= 1.2;
60 else if (button == CLUTTER_BUTTON_SECONDARY)
61 scale /= 1.2;
62
63 /* don't do anything if scale is outside bounds */
64 if (scale < 0.1 || scale > 20.0)
65 return TRUE;
66
67 /* get the location of the click on the scaled actor */
68 clutter_event_get_coords (event, &click_x, &click_y);
69 clutter_actor_transform_stage_point (actor,
70 click_x, click_y,
71 &click_target_x, &click_target_y);
72
73 /* anchor the actor on the clicked point on its surface */
74 clutter_actor_set_anchor_point (actor, click_target_x, click_target_y);
75
76 /* set the actor's position to the click coords: it won't move,
77 * because the anchor point is already there; but
78 * the scale will now be centered on these coords (as the
79 * scale center defaults to the anchor point); so the anchor point
80 * on the actor won't move from under the pointer
81 */
82 clutter_actor_set_position (actor, click_x, click_y);
83
84 clutter_actor_animate (actor, CLUTTER_LINEAR, 500,
85 "scale-x", scale,
86 "scale-y", scale,
87 NULL);
88
89 return TRUE;
90 }
91
92 int
main(int argc,char * argv[])93 main (int argc,
94 char *argv[])
95 {
96 ClutterActor *stage;
97 ClutterActor *texture;
98 gchar *image_path;
99 GError *error = NULL;
100
101 if (argc < 2)
102 {
103 g_print ("Usage: %s <path to image file>\n", argv[0]);
104 exit (EXIT_FAILURE);
105 }
106
107 image_path = argv[1];
108
109 if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
110 return 1;
111
112 stage = clutter_stage_new ();
113 clutter_actor_set_size (stage, STAGE_SIDE, STAGE_SIDE);
114 clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
115 g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
116
117 texture = clutter_texture_new ();
118 clutter_actor_set_reactive (texture, TRUE);
119 clutter_actor_set_width (texture, STAGE_SIDE);
120 clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), TRUE);
121
122 clutter_actor_add_action (texture, clutter_drag_action_new ());
123
124 g_object_set (G_OBJECT (texture),
125 "scale-gravity", CLUTTER_GRAVITY_NORTH_WEST,
126 NULL);
127
128 clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), image_path, &error);
129
130 if (error != NULL)
131 {
132 g_warning ("Error loading %s\n%s", image_path, error->message);
133 g_error_free (error);
134 exit (EXIT_FAILURE);
135 }
136
137 clutter_actor_set_y (texture, (STAGE_SIDE - clutter_actor_get_height (texture)) * 0.5);
138
139 g_signal_connect (texture,
140 "button-release-event",
141 G_CALLBACK (clicked_cb),
142 NULL);
143
144 g_signal_connect_swapped (stage,
145 "key-press-event",
146 G_CALLBACK (key_press_cb),
147 texture);
148
149 clutter_container_add_actor (CLUTTER_CONTAINER (stage), texture);
150
151 clutter_actor_show (stage);
152
153 clutter_main ();
154
155 return EXIT_SUCCESS;
156 }
157