2 * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
24 #include "swfdec_button_movie.h"
25 #include "swfdec_as_strings.h"
26 #include "swfdec_audio_event.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_event.h"
29 #include "swfdec_filter.h"
30 #include "swfdec_player_internal.h"
31 #include "swfdec_resource.h"
33 G_DEFINE_TYPE (SwfdecButtonMovie
, swfdec_button_movie
, SWFDEC_TYPE_ACTOR
)
36 swfdec_button_movie_update_extents (SwfdecMovie
*movie
,
39 swfdec_rect_union (extents
, extents
, &movie
->graphic
->extents
);
43 swfdec_button_movie_perform_place (SwfdecButtonMovie
*button
, SwfdecBits
*bits
)
45 SwfdecMovie
*movie
= SWFDEC_MOVIE (button
);
46 gboolean has_blend_mode
, has_filters
, v2
;
47 SwfdecColorTransform ctrans
;
48 SwfdecGraphic
*graphic
;
55 swfdec_bits_getbits (bits
, 2); /* reserved */
56 has_blend_mode
= swfdec_bits_getbit (bits
);
57 has_filters
= swfdec_bits_getbit (bits
);
58 SWFDEC_LOG (" has_blend_mode = %d", has_blend_mode
);
59 SWFDEC_LOG (" has_filters = %d", has_filters
);
60 swfdec_bits_getbits (bits
, 4); /* states */
61 id
= swfdec_bits_get_u16 (bits
);
62 depth
= swfdec_bits_get_u16 (bits
);
64 if (swfdec_movie_find (movie
, depth
)) {
65 SWFDEC_WARNING ("depth %d already occupied, skipping placement.", depth
+ 16384);
68 graphic
= swfdec_swf_decoder_get_character (SWFDEC_SWF_DECODER (movie
->resource
->decoder
), id
);
69 if (!SWFDEC_IS_GRAPHIC (graphic
)) {
70 SWFDEC_ERROR ("id %u does not specify a graphic", id
);
74 player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (movie
));
75 new = swfdec_movie_new (player
, depth
, movie
, movie
->resource
, graphic
, NULL
);
76 swfdec_bits_get_matrix (bits
, &trans
, NULL
);
77 if (swfdec_bits_left (bits
)) {
79 swfdec_bits_get_color_transform (bits
, &ctrans
);
81 blend_mode
= swfdec_bits_get_u8 (bits
);
82 SWFDEC_LOG (" blend mode = %u", blend_mode
);
87 new->filters
= swfdec_filter_parse (player
, bits
);
89 /* DefineButton1 record */
91 if (has_blend_mode
|| has_filters
) {
92 SWFDEC_ERROR ("cool, a DefineButton1 with filters or blend mode");
96 swfdec_movie_set_static_properties (new, &trans
, v2
? &ctrans
: NULL
, 0, 0, blend_mode
, NULL
);
97 if (SWFDEC_IS_ACTOR (new)) {
98 SwfdecActor
*actor
= SWFDEC_ACTOR (new);
99 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_INITIALIZE
);
100 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_CONSTRUCT
);
101 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_LOAD
);
103 swfdec_movie_initialize (new);
104 if (swfdec_bits_left (bits
)) {
105 SWFDEC_WARNING ("button record for id %u has %u bytes left", id
,
106 swfdec_bits_left (bits
) / 8);
111 swfdec_button_movie_set_state (SwfdecButtonMovie
*button
, SwfdecButtonState state
)
113 SwfdecMovie
*movie
= SWFDEC_MOVIE (button
);
121 if (button
->state
== state
) {
122 SWFDEC_LOG ("not changing state, it's already in %d", state
);
125 SWFDEC_DEBUG ("changing state from %d to %d", button
->state
, state
);
126 but
= SWFDEC_BUTTON (movie
->graphic
);
127 /* remove all movies that aren't in the new state */
129 if (button
->state
>= 0) {
130 old
= 1 << button
->state
;
131 for (walk
= but
->records
; walk
; walk
= walk
->next
) {
132 swfdec_bits_init (&bits
, walk
->data
);
133 i
= swfdec_bits_get_u8 (&bits
);
134 if ((i
& old
) && !(i
& new)) {
135 swfdec_bits_get_u16 (&bits
);
136 depth
= swfdec_bits_get_u16 (&bits
);
137 child
= swfdec_movie_find (movie
, depth
- 16384);
139 swfdec_movie_remove (child
);
141 SWFDEC_WARNING ("no child at depth %d, none removed", depth
);
146 /* to make sure that this never triggers when initializing */
149 button
->state
= state
;
150 /* add all movies that are in the new state */
151 for (walk
= but
->records
; walk
; walk
= walk
->next
) {
152 swfdec_bits_init (&bits
, walk
->data
);
153 i
= swfdec_bits_peek_u8 (&bits
);
154 if ((i
& old
) || !(i
& new))
156 swfdec_button_movie_perform_place (button
, &bits
);
161 swfdec_button_movie_mouse_events (SwfdecActor
*actor
)
167 swfdec_button_movie_mouse_in (SwfdecActor
*actor
)
169 if (swfdec_player_is_mouse_pressed (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor
))))
170 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor
), SWFDEC_BUTTON_DOWN
);
172 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor
), SWFDEC_BUTTON_OVER
);
174 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class
)->mouse_in (actor
);
178 swfdec_button_movie_mouse_out (SwfdecActor
*actor
)
180 SwfdecButtonMovie
*button
= SWFDEC_BUTTON_MOVIE (actor
);
182 if (swfdec_player_is_mouse_pressed (SWFDEC_PLAYER (swfdec_gc_object_get_context (button
)))) {
183 if (SWFDEC_BUTTON (SWFDEC_MOVIE (actor
)->graphic
)->menubutton
) {
184 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor
), SWFDEC_BUTTON_UP
);
186 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor
), SWFDEC_BUTTON_OVER
);
189 swfdec_button_movie_set_state (button
, SWFDEC_BUTTON_UP
);
192 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class
)->mouse_out (actor
);
196 swfdec_button_movie_mouse_press (SwfdecActor
*actor
, guint button
)
200 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor
), SWFDEC_BUTTON_DOWN
);
202 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class
)->mouse_press (actor
, button
);
206 swfdec_button_movie_mouse_release (SwfdecActor
*actor
, guint button
)
208 SwfdecPlayer
*player
;
212 player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (actor
));
213 if (player
->priv
->mouse_below
== actor
) {
214 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor
), SWFDEC_BUTTON_OVER
);
216 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class
)->mouse_release (actor
, button
);
218 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor
), SWFDEC_BUTTON_UP
);
220 /* NB: We don't chain to parent here for menubuttons*/
221 if (!SWFDEC_BUTTON (SWFDEC_MOVIE (actor
)->graphic
)->menubutton
) {
222 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class
)->mouse_release (actor
, button
);
224 SWFDEC_FIXME ("use mouse_below as recipient for mouse_release events?");
230 swfdec_button_movie_init_movie (SwfdecMovie
*mov
)
232 SwfdecButtonMovie
*movie
= SWFDEC_BUTTON_MOVIE (mov
);
234 swfdec_button_movie_set_state (movie
, SWFDEC_BUTTON_UP
);
238 swfdec_button_movie_hit_test (SwfdecButtonMovie
*button
, double x
, double y
)
240 SwfdecSwfDecoder
*dec
;
244 dec
= SWFDEC_SWF_DECODER (SWFDEC_MOVIE (button
)->resource
->decoder
);
245 for (walk
= SWFDEC_BUTTON (SWFDEC_MOVIE (button
)->graphic
)->records
; walk
; walk
= walk
->next
) {
246 SwfdecGraphic
*graphic
;
248 cairo_matrix_t matrix
, inverse
;
251 swfdec_bits_init (&bits
, walk
->data
);
253 if ((swfdec_bits_get_u8 (&bits
) & (1 << SWFDEC_BUTTON_HIT
)) == 0)
256 id
= swfdec_bits_get_u16 (&bits
);
257 swfdec_bits_get_u16 (&bits
); /* depth */
258 graphic
= swfdec_swf_decoder_get_character (dec
, id
);
259 if (!SWFDEC_IS_GRAPHIC (graphic
)) {
260 SWFDEC_ERROR ("id %u is no graphic", id
);
265 swfdec_bits_get_matrix (&bits
, &matrix
, &inverse
);
266 cairo_matrix_transform_point (&inverse
, &tmpx
, &tmpy
);
268 SWFDEC_LOG ("Checking button contents at %g %g (transformed from %g %g)", tmpx
, tmpy
, x
, y
);
269 if (swfdec_graphic_mouse_in (graphic
, tmpx
, tmpy
))
271 SWFDEC_LOG (" missed");
277 swfdec_button_movie_contains (SwfdecMovie
*movie
, double x
, double y
, gboolean events
)
280 /* check for movies in a higher layer that react to events */
282 ret
= SWFDEC_MOVIE_CLASS (swfdec_button_movie_parent_class
)->contains (movie
, x
, y
, TRUE
);
283 if (ret
&& ret
!= movie
&& SWFDEC_IS_ACTOR (ret
) && swfdec_actor_get_mouse_events (SWFDEC_ACTOR (ret
)))
287 return swfdec_button_movie_hit_test (SWFDEC_BUTTON_MOVIE (movie
), x
, y
) ? movie
: NULL
;
291 swfdec_button_movie_constructor (GType type
, guint n_construct_properties
,
292 GObjectConstructParam
*construct_properties
)
297 object
= G_OBJECT_CLASS (swfdec_button_movie_parent_class
)->constructor (type
,
298 n_construct_properties
, construct_properties
);
300 movie
= SWFDEC_MOVIE (object
);
301 g_assert (movie
->graphic
);
302 if (SWFDEC_BUTTON (movie
->graphic
)->events
) {
303 SWFDEC_ACTOR (movie
)->events
= swfdec_event_list_copy (
304 SWFDEC_BUTTON (movie
->graphic
)->events
);
311 swfdec_button_movie_class_init (SwfdecButtonMovieClass
* g_class
)
313 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
314 SwfdecMovieClass
*movie_class
= SWFDEC_MOVIE_CLASS (g_class
);
315 SwfdecActorClass
*actor_class
= SWFDEC_ACTOR_CLASS (g_class
);
317 object_class
->constructor
= swfdec_button_movie_constructor
;
319 movie_class
->init_movie
= swfdec_button_movie_init_movie
;
320 movie_class
->update_extents
= swfdec_button_movie_update_extents
;
321 movie_class
->contains
= swfdec_button_movie_contains
;
323 actor_class
->mouse_events
= swfdec_button_movie_mouse_events
;
324 actor_class
->mouse_in
= swfdec_button_movie_mouse_in
;
325 actor_class
->mouse_out
= swfdec_button_movie_mouse_out
;
326 actor_class
->mouse_press
= swfdec_button_movie_mouse_press
;
327 actor_class
->mouse_release
= swfdec_button_movie_mouse_release
;
331 swfdec_button_movie_init (SwfdecButtonMovie
*movie
)
333 movie
->state
= SWFDEC_BUTTON_INIT
;