gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog libbase/image_filters.cpp libba...


From: Sandro Santilli
Subject: [Gnash-commit] gnash ChangeLog libbase/image_filters.cpp libba...
Date: Sat, 26 Aug 2006 22:58:13 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Sandro Santilli <strk>  06/08/26 22:58:12

Modified files:
        .              : ChangeLog 
        libbase        : image_filters.cpp utility.cpp 
        server         : Makefile.am impl.cpp movie_root.cpp 
                         movie_root.h 
        server/asobj   : ASSound.cpp MovieClipLoader.h 
        server/parser  : Makefile.am movie_def_impl.h movie_definition.h 
        server/swf     : tag_loaders.cpp 
Added files:
        server         : button_character_instance.cpp 
                         button_character_instance.h 
                         mouse_button_state.h 
        server/parser  : button_character_def.cpp button_character_def.h 
Removed files:
        server         : button.cpp button.h 

Log message:
                * Split button.{h,cpp} into button_character_instance.{cpp,h},
                  mouse_button_events.h and parser/button_character_def.{cpp,h};
                  headers inclusion shaking.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.730&r2=1.731
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/image_filters.cpp?cvsroot=gnash&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/utility.cpp?cvsroot=gnash&r1=1.8&r2=1.9
http://cvs.savannah.gnu.org/viewcvs/gnash/server/Makefile.am?cvsroot=gnash&r1=1.62&r2=1.63
http://cvs.savannah.gnu.org/viewcvs/gnash/server/impl.cpp?cvsroot=gnash&r1=1.53&r2=1.54
http://cvs.savannah.gnu.org/viewcvs/gnash/server/movie_root.cpp?cvsroot=gnash&r1=1.13&r2=1.14
http://cvs.savannah.gnu.org/viewcvs/gnash/server/movie_root.h?cvsroot=gnash&r1=1.11&r2=1.12
http://cvs.savannah.gnu.org/viewcvs/gnash/server/button_character_instance.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/button_character_instance.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/mouse_button_state.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/button.cpp?cvsroot=gnash&r1=1.29&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/server/button.h?cvsroot=gnash&r1=1.10&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/ASSound.cpp?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/MovieClipLoader.h?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/Makefile.am?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/movie_def_impl.h?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/movie_definition.h?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/button_character_def.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/button_character_def.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/swf/tag_loaders.cpp?cvsroot=gnash&r1=1.33&r2=1.34

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.730
retrieving revision 1.731
diff -u -b -r1.730 -r1.731
--- ChangeLog   26 Aug 2006 22:09:12 -0000      1.730
+++ ChangeLog   26 Aug 2006 22:58:12 -0000      1.731
@@ -1,3 +1,9 @@
+2006-08-27 Sandro Santilli  <address@hidden>
+
+       * Split button.{h,cpp} into button_character_instance.{cpp,h},
+         mouse_button_events.h and parser/button_character_def.{cpp,h};
+         headers inclusion shaking.
+
 2006-08-26 Markus Gothe <address@hidden>
 
        * server/asobj/Global.cpp, libbase/image.cpp: Found and fixed memory 

Index: libbase/image_filters.cpp
===================================================================
RCS file: /sources/gnash/gnash/libbase/image_filters.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- libbase/image_filters.cpp   26 Aug 2006 00:12:37 -0000      1.9
+++ libbase/image_filters.cpp   26 Aug 2006 22:58:12 -0000      1.10
@@ -752,7 +752,7 @@
     rgba *csp, *sp;
     sp = csp = (rgba *) src->m_data;
     rgba *dp = (rgba *) dst->m_data;
-    int sgap = src->m_pitch - src->m_width * 4;
+    //int sgap = src->m_pitch - src->m_width * 4;
     int dgap = dst->m_pitch - dst->m_width * 4;
 
     /* Interpolating Zoom */

Index: libbase/utility.cpp
===================================================================
RCS file: /sources/gnash/gnash/libbase/utility.cpp,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -b -r1.8 -r1.9
--- libbase/utility.cpp 25 Aug 2006 23:35:20 -0000      1.8
+++ libbase/utility.cpp 26 Aug 2006 22:58:12 -0000      1.9
@@ -68,7 +68,7 @@
 #endif
 
 
-void dump_memory_stats(const char *from, int line, const char *label) 
+void dump_memory_stats(const char* from, int line, const char *label) 
 // Dump the internal statistics from malloc() so we can track memory leaks
 {
 

Index: server/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/Makefile.am,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -b -r1.62 -r1.63
--- server/Makefile.am  26 Aug 2006 10:14:51 -0000      1.62
+++ server/Makefile.am  26 Aug 2006 22:58:12 -0000      1.63
@@ -86,7 +86,7 @@
         string.cpp \
         action.cpp \
        ActionExec.cpp \
-        button.cpp \
+        button_character_instance.cpp \
         dlist.cpp \
        edit_text_character.cpp \
         font.cpp \
@@ -122,7 +122,8 @@
        as_member.h \
        as_prop_flags.h \
        as_object.h \
-       button.h \
+       button_character_instance.h \
+       mouse_button_state.h \
        dlist.h \
        character.h \
        generic_character.h \

Index: server/impl.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/impl.cpp,v
retrieving revision 1.53
retrieving revision 1.54
diff -u -b -r1.53 -r1.54
--- server/impl.cpp     26 Aug 2006 17:58:24 -0000      1.53
+++ server/impl.cpp     26 Aug 2006 22:58:12 -0000      1.54
@@ -52,7 +52,7 @@
 #include "tu_file.h"
 #include "utility.h"
 #include "action.h"
-#include "button.h"
+//#include "button.h"
 #include "impl.h"
 #include "font.h"
 #include "fontlib.h"

Index: server/movie_root.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/movie_root.cpp,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -b -r1.13 -r1.14
--- server/movie_root.cpp       23 Aug 2006 21:30:49 -0000      1.13
+++ server/movie_root.cpp       26 Aug 2006 22:58:12 -0000      1.14
@@ -145,6 +145,151 @@
     fire_mouse_event();
 }
 
+void generate_mouse_button_events(mouse_button_state* ms)
+{
+       smart_ptr<movie>        active_entity = ms->m_active_entity;
+       smart_ptr<movie>        topmost_entity = ms->m_topmost_entity;
+
+       if (ms->m_mouse_button_state_last == 1)
+       {
+               // Mouse button was down.
+
+               // Handle trackAsMenu dragOver
+               if (active_entity == NULL
+                   || active_entity->get_track_as_menu())
+               {
+                       if (topmost_entity != NULL
+                           && topmost_entity != active_entity
+                           && topmost_entity->get_track_as_menu() == true)
+                       {
+                               // Transfer to topmost entity, dragOver
+                               active_entity = topmost_entity;
+                               
active_entity->on_button_event(event_id::DRAG_OVER);
+                               ms->m_mouse_inside_entity_last = true;
+                       }
+               }
+
+               // Handle onDragOut, onDragOver
+               if (ms->m_mouse_inside_entity_last == false)
+               {
+                       if (topmost_entity == active_entity)
+                       {
+                               // onDragOver
+                               if (active_entity != NULL)
+                               {
+                                       
active_entity->on_button_event(event_id::DRAG_OVER);
+                               }
+                               ms->m_mouse_inside_entity_last = true;
+                       }
+               }
+               else
+               {
+                       // mouse_inside_entity_last == true
+                       if (topmost_entity != active_entity)
+                       {
+                               // onDragOut
+                               if (active_entity != NULL)
+                               {
+                                       
active_entity->on_button_event(event_id::DRAG_OUT);
+                               }
+                               ms->m_mouse_inside_entity_last = false;
+                       }
+               }
+
+               // Handle onRelease, onReleaseOutside
+               if (ms->m_mouse_button_state_current == 0)
+               {
+                       // Mouse button just went up.
+                       ms->m_mouse_button_state_last = 0;
+
+                       if (active_entity != NULL)
+                       {
+                               if (ms->m_mouse_inside_entity_last)
+                               {
+                                       // onRelease
+                                       
active_entity->on_button_event(event_id::RELEASE);
+                               }
+                               else
+                               {
+                                       // onReleaseOutside
+                                       if (active_entity->get_track_as_menu() 
== false)
+                                       {
+                                               
active_entity->on_button_event(event_id::RELEASE_OUTSIDE);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (ms->m_mouse_button_state_last == 0)
+       {
+               // Mouse button was up.
+
+               // New active entity is whatever is below the mouse right now.
+               if (topmost_entity != active_entity)
+               {
+                       // onRollOut
+                       if (active_entity != NULL)
+                       {
+                               
active_entity->on_button_event(event_id::ROLL_OUT);
+                       }
+
+                       active_entity = topmost_entity;
+
+                       // onRollOver
+                       if (active_entity != NULL)
+                       {
+                               
active_entity->on_button_event(event_id::ROLL_OVER);
+                       }
+
+                       ms->m_mouse_inside_entity_last = true;
+               }
+
+               // mouse button press
+               if (ms->m_mouse_button_state_current == 1)
+               {
+                       // onPress
+
+                       // set/kill focus for current root
+                       movie_root* mroot = (movie_root*) get_current_root();
+                       movie* current_active_entity = 
mroot->get_active_entity();
+
+                       // It's another entity ?
+                       if (current_active_entity != active_entity.get_ptr())
+                       {
+                               // First to clean focus
+                               if (current_active_entity != NULL)
+                               {
+                                       
current_active_entity->on_event(event_id::KILLFOCUS);
+                                       mroot->set_active_entity(NULL);
+                               }
+
+                               // Then to set focus
+                               if (active_entity != NULL)
+                               {
+                                       if 
(active_entity->on_event(event_id::SETFOCUS))
+                                       {
+                                               
mroot->set_active_entity(active_entity.get_ptr());
+                                       }
+                               }
+                       }
+
+                       if (active_entity != NULL)
+                       {
+                               active_entity->on_button_event(event_id::PRESS);
+                       }
+                       ms->m_mouse_inside_entity_last = true;
+                       ms->m_mouse_button_state_last = 1;
+               }
+       }
+
+       // Write the (possibly modified) smart_ptr copies back
+       // into the state struct.
+       ms->m_active_entity = active_entity;
+       ms->m_topmost_entity = topmost_entity;
+}
+
+
 void
 movie_root::fire_mouse_event()
 {

Index: server/movie_root.h
===================================================================
RCS file: /sources/gnash/gnash/server/movie_root.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -b -r1.11 -r1.12
--- server/movie_root.h 26 Aug 2006 02:08:31 -0000      1.11
+++ server/movie_root.h 26 Aug 2006 22:58:12 -0000      1.12
@@ -39,7 +39,7 @@
 #define GNASH_MOVIE_ROOT_H
 
 #include "container.h"
-#include "button.h" // for mouse_button_state
+#include "mouse_button_state.h" // for mouse_button_state
 #include "timers.h" // for Timer
 #include "fontlib.h"
 #include "font.h"

Index: server/asobj/ASSound.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/ASSound.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- server/asobj/ASSound.cpp    24 Jul 2006 18:59:40 -0000      1.2
+++ server/asobj/ASSound.cpp    26 Aug 2006 22:58:12 -0000      1.3
@@ -22,6 +22,7 @@
 
 #include "log.h"
 #include "ASSound.h"
+#include "sound.h" // for sound_sample_impl
 #include "movie_definition.h"
 #include "sprite_instance.h"
 #include "fn_call.h"

Index: server/asobj/MovieClipLoader.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/MovieClipLoader.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- server/asobj/MovieClipLoader.h      26 Aug 2006 13:09:53 -0000      1.3
+++ server/asobj/MovieClipLoader.h      26 Aug 2006 22:58:12 -0000      1.4
@@ -41,9 +41,9 @@
 #ifndef GNASH_MOVIECLIPLOADER_H
 #define GNASH_MOVIECLIPLOADER_H
 
-#include "button.h"
+#include "button_character_instance.h" // for mouse_state enum
 #include "action.h"
-#include "impl.h"
+//#include "impl.h"
 
 namespace gnash {
 

Index: server/parser/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/parser/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- server/parser/Makefile.am   26 Aug 2006 10:14:51 -0000      1.3
+++ server/parser/Makefile.am   26 Aug 2006 22:58:12 -0000      1.4
@@ -68,6 +68,7 @@
 
 libgnashparser_la_SOURCES = \
        action_buffer.cpp \
+       button_character_def.cpp \
        character_def.cpp \
        edit_text_character_def.cpp \
        text_character_def.cpp \
@@ -78,6 +79,7 @@
 
 noinst_HEADERS = \
        action_buffer.h \
+       button_character_def.h \
        character_def.h \
        bitmap_character_def.h \
        edit_text_character_def.h \

Index: server/parser/movie_def_impl.h
===================================================================
RCS file: /sources/gnash/gnash/server/parser/movie_def_impl.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- server/parser/movie_def_impl.h      26 Aug 2006 02:08:32 -0000      1.2
+++ server/parser/movie_def_impl.h      26 Aug 2006 22:58:12 -0000      1.3
@@ -40,7 +40,7 @@
 
 #include "container.h"
 #include "smart_ptr.h"
-#include "button.h" // for mouse_button_state
+//#include "button.h" // for mouse_button_state
 #include "timers.h" // for Timer
 #include "fontlib.h"
 #include "font.h"

Index: server/parser/movie_definition.h
===================================================================
RCS file: /sources/gnash/gnash/server/parser/movie_definition.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- server/parser/movie_definition.h    26 Aug 2006 02:08:32 -0000      1.3
+++ server/parser/movie_definition.h    26 Aug 2006 22:58:12 -0000      1.4
@@ -63,8 +63,9 @@
 #ifndef GNASH_MOVIE_DEFINITION_H
 #define GNASH_MOVIE_DEFINITION_H
 
+#include "character_def.h" // for inheritance
 #include "container.h"
-#include "button.h" // for mouse_button_state
+//#include "button.h" // for mouse_button_state
 #include "timers.h" // for Timer
 #include "fontlib.h"
 #include "font.h"

Index: server/swf/tag_loaders.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/swf/tag_loaders.cpp,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -b -r1.33 -r1.34
--- server/swf/tag_loaders.cpp  26 Aug 2006 21:04:31 -0000      1.33
+++ server/swf/tag_loaders.cpp  26 Aug 2006 22:58:12 -0000      1.34
@@ -46,8 +46,8 @@
 #include "utility.h"
 #include "action.h"
 #include "action_buffer.h"
-#include "button.h"
-#include "impl.h"
+#include "button_character_def.h"
+//#include "impl.h"
 #include "font.h"
 #include "fontlib.h"
 #include "log.h"

Index: server/button_character_instance.cpp
===================================================================
RCS file: server/button_character_instance.cpp
diff -N server/button_character_instance.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/button_character_instance.cpp        26 Aug 2006 22:58:12 -0000      
1.1
@@ -0,0 +1,713 @@
+// button.cpp  -- Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain.  Do
+// whatever you want with it.
+
+// SWF buttons.  Mouse-sensitive update/display, actions, etc.
+
+
+#include "button_character_instance.h"
+#include "button_character_def.h"
+
+//#include "action.h"
+//#include "render.h"
+//#include "sound.h"
+//#include "stream.h"
+//#include "movie_definition.h"
+#include "sprite_instance.h"
+#include "movie_root.h"
+//#include "action_buffer.h"
+
+
+/** \page buttons Buttons and mouse behaviour
+
+Observations about button & mouse behavior
+
+Entities that receive mouse events: only buttons and sprites, AFAIK
+
+When the mouse button goes down, it becomes "captured" by whatever
+element is topmost, directly below the mouse at that moment.  While
+the mouse is captured, no other entity receives mouse events,
+regardless of how the mouse or other elements move.
+
+The mouse remains captured until the mouse button goes up.  The mouse
+remains captured even if the element that captured it is removed from
+the display list.
+
+If the mouse isn't above a button or sprite when the mouse button goes
+down, then the mouse is captured by the background (i.e. mouse events
+just don't get sent, until the mouse button goes up again).
+
+Mouse events:
+
++------------------+---------------+-------------------------------------+
+| Event            | Mouse Button  | description                         |
+=========================================================================
+| onRollOver       |     up        | sent to topmost entity when mouse   |
+|                  |               | cursor initially goes over it       |
++------------------+---------------+-------------------------------------+
+| onRollOut        |     up        | when mouse leaves entity, after     |
+|                  |               | onRollOver                          |
++------------------+---------------+-------------------------------------+
+| onPress          |  up -> down   | sent to topmost entity when mouse   |
+|                  |               | button goes down.  onRollOver       |
+|                  |               | always precedes onPress.  Initiates |
+|                  |               | mouse capture.                      |
++------------------+---------------+-------------------------------------+
+| onRelease        |  down -> up   | sent to active entity if mouse goes |
+|                  |               | up while over the element           |
++------------------+---------------+-------------------------------------+
+| onDragOut        |     down      | sent to active entity if mouse      |
+|                  |               | is no longer over the entity        |
++------------------+---------------+-------------------------------------+
+| onReleaseOutside |  down -> up   | sent to active entity if mouse goes |
+|                  |               | up while not over the entity.       |
+|                  |               | onDragOut always precedes           |
+|                  |               | onReleaseOutside                    |
++------------------+---------------+-------------------------------------+
+| onDragOver       |     down      | sent to active entity if mouse is   |
+|                  |               | dragged back over it after          |
+|                  |               | onDragOut                           |
++------------------+---------------+-------------------------------------+
+
+There is always one active entity at any given time (considering NULL to
+be an active entity, representing the background, and other objects that
+don't receive mouse events).
+
+When the mouse button is up, the active entity is the topmost element
+directly under the mouse pointer.
+
+When the mouse button is down, the active entity remains whatever it
+was when the button last went down.
+
+The active entity is the only object that receives mouse events.
+
+!!! The "trackAsMenu" property alters this behavior!  If trackAsMenu
+is set on the active entity, then onReleaseOutside is filtered out,
+and onDragOver from another entity is allowed (from the background, or
+another trackAsMenu entity). !!!
+
+
+Pseudocode:
+
+active_entity = NULL
+mouse_button_state = UP
+mouse_inside_entity_state = false
+frame loop:
+  if mouse_button_state == DOWN
+
+    // Handle trackAsMenu
+    if (active_entity->trackAsMenu)
+      possible_entity = topmost entity below mouse
+      if (possible_entity != active_entity && possible_entity->trackAsMenu)
+        // Transfer to possible entity
+       active_entity = possible_entity
+       active_entity->onDragOver()
+       mouse_inside_entity_state = true;
+
+    // Handle onDragOut, onDragOver
+    if (mouse_inside_entity_state == false)
+      if (mouse is actually inside the active_entity)
+        // onDragOver
+       active_entity->onDragOver()
+        mouse_inside_entity_state = true;
+
+    else // mouse_inside_entity_state == true
+      if (mouse is actually outside the active_entity)
+        // onDragOut
+       active_entity->onDragOut()
+       mouse_inside_entity_state = false;
+
+    // Handle onRelease, onReleaseOutside
+    if (mouse button is up)
+      if (mouse_inside_entity_state)
+        // onRelease
+        active_entity->onRelease()
+      else
+        // onReleaseOutside
+       if (active_entity->trackAsMenu == false)
+          active_entity->onReleaseOutside()
+      mouse_button_state = UP
+    
+  if mouse_button_state == UP
+    new_active_entity = topmost entity below the mouse
+    if (new_active_entity != active_entity)
+      // onRollOut, onRollOver
+      active_entity->onRollOut()
+      active_entity = new_active_entity
+      active_entity->onRollOver()
+    
+    // Handle press
+    if (mouse button is down)
+      // onPress
+      active_entity->onPress()
+      mouse_inside_entity_state = true
+      mouse_button_state = DOWN
+
+*/
+
+
+namespace gnash {
+
+button_character_instance::button_character_instance(
+               button_character_definition* def,
+               character* parent, int id)
+       :
+       character(parent, id),
+       m_def(def),
+       m_last_mouse_flags(IDLE),
+       m_mouse_flags(IDLE),
+       m_mouse_state(UP)
+{
+       assert(m_def);
+
+       int r, r_num =  m_def->m_button_records.size();
+       m_record_character.resize(r_num);
+
+       movie_definition* movie_def = 
parent->get_root_movie()->get_movie_definition();
+
+       for (r = 0; r < r_num; r++)
+       {
+               button_record*  bdef = &m_def->m_button_records[r];
+
+               if (bdef->m_character_def == NULL)
+               {
+                       // Resolve the character id.
+                       bdef->m_character_def = 
movie_def->get_character_def(bdef->m_character_id);
+               }
+               assert(bdef->m_character_def != NULL);
+
+               const matrix&   mat = 
m_def->m_button_records[r].m_button_matrix;
+               const cxform&   cx = m_def->m_button_records[r].m_button_cxform;
+
+               smart_ptr<character> ch = 
bdef->m_character_def->create_character_instance(this, id);
+               m_record_character[r] = ch;
+               ch->set_matrix(mat);
+               ch->set_cxform(cx);
+               ch->restart();
+       }
+
+       // check up presence KeyPress events
+       for (unsigned int i = 0; i < m_def->m_button_actions.size(); i++)
+       {
+               if (m_def->m_button_actions[i].m_conditions & 0xFE00)   // 
check up on CondKeyPress: UB[7]
+               {
+                       get_root()->add_keypress_listener(this);
+                       break;
+               }
+       }
+
+}
+
+button_character_instance::~button_character_instance()
+{
+       get_root()->remove_keypress_listener(this);
+}
+
+// called from keypress listener only
+bool
+button_character_instance::on_event(event_id id)
+{
+
+       if (id.m_id != event_id::KEY_PRESS)
+       {
+               return false;
+       }
+
+       bool called = false;
+
+       static const event_id s_key[32] =
+       {
+               event_id(),
+               event_id(event_id::KEY_PRESS, key::LEFT),
+               event_id(event_id::KEY_PRESS, key::RIGHT),
+               event_id(event_id::KEY_PRESS, key::HOME),
+               event_id(event_id::KEY_PRESS, key::END),
+               event_id(event_id::KEY_PRESS, key::INSERT),
+               event_id(event_id::KEY_PRESS, key::DELETEKEY),
+               event_id(),
+               event_id(event_id::KEY_PRESS, key::BACKSPACE),  //8
+               event_id(),
+               event_id(),
+               event_id(),
+               event_id(),
+               event_id(event_id::KEY_PRESS, key::ENTER),      //13
+               event_id(event_id::KEY_PRESS, key::UP),
+               event_id(event_id::KEY_PRESS, key::DOWN),
+               event_id(event_id::KEY_PRESS, key::PGUP),
+               event_id(event_id::KEY_PRESS, key::PGDN),
+               event_id(event_id::KEY_PRESS, key::TAB),
+               // 32-126 folows ASCII
+       };
+
+
+       // Add appropriate actions to the movie's execute list...
+       for (unsigned int i = 0; i < m_def->m_button_actions.size(); i++)
+       {
+               int keycode = (m_def->m_button_actions[i].m_conditions & 
0xFE00) >> 9;
+               event_id key_event = keycode < 32 ? s_key[keycode] : 
event_id(event_id::KEY_PRESS, (key::code) keycode);
+               if (key_event == id)
+               {
+                       // Matching action.
+                       for (unsigned int j = 0; j < 
m_def->m_button_actions[i].m_actions.size(); j++)
+                       {
+                               
get_parent()->add_action_buffer(m_def->m_button_actions[i].m_actions[j]);
+                       }
+                       called = true;
+               }
+       }
+
+       return called;
+}
+
+void
+button_character_instance::restart()
+{
+       m_last_mouse_flags = IDLE;
+       m_mouse_flags = IDLE;
+       m_mouse_state = UP;
+       int r, r_num =  m_record_character.size();
+       for (r = 0; r < r_num; r++)
+       {
+               m_record_character[r]->restart();
+       }
+}
+
+void
+button_character_instance::advance(float delta_time)
+{
+//                     printf("%s:\n", __PRETTY_FUNCTION__); // FIXME:
+       // Implement mouse-drag.
+       character::do_mouse_drag();
+
+       matrix  mat = get_world_matrix();
+
+       // Advance our relevant characters.
+       {for (unsigned int i = 0; i < m_def->m_button_records.size(); i++)
+       {
+               button_record&  rec = m_def->m_button_records[i];
+               if (m_record_character[i] == NULL)
+               {
+                       continue;
+               }
+
+               // Matrix
+               matrix sub_matrix = mat;
+               sub_matrix.concatenate(rec.m_button_matrix);
+
+               // Advance characters that are activated by the new mouse state
+               if (((m_mouse_state == UP) && (rec.m_up)) ||
+                   ((m_mouse_state == DOWN) && (rec.m_down)) ||
+                   ((m_mouse_state == OVER) && (rec.m_over)))
+               {
+                       m_record_character[i]->advance(delta_time);
+               }
+       }}
+}
+
+
+void
+button_character_instance::display()
+{
+//                     GNASH_REPORT_FUNCTION;
+       for (unsigned int i = 0; i < m_def->m_button_records.size(); i++)
+       {
+               button_record&  rec = m_def->m_button_records[i];
+               if (m_record_character[i] == NULL)
+               {
+                       continue;
+               }
+               if ((m_mouse_state == UP && rec.m_up)
+                   || (m_mouse_state == DOWN && rec.m_down)
+                   || (m_mouse_state == OVER && rec.m_over))
+               {
+                               matrix  mat = get_world_matrix();
+
+                       m_record_character[i]->display();
+               }
+       }
+
+       do_display_callback();
+}
+
+
+movie*
+button_character_instance::get_topmost_mouse_entity(float x, float y)
+// Return the topmost entity that the given point covers.  NULL if none.
+// I.e. check against ourself.
+{
+       if (get_visible() == false) {
+               return false;
+       }
+
+       matrix  m = get_matrix();
+       point   p;
+       m.transform_by_inverse(&p, point(x, y));
+
+       {for (unsigned int i = 0; i < m_def->m_button_records.size(); i++)
+       {
+               button_record&  rec = m_def->m_button_records[i];
+               if (rec.m_character_id < 0 || rec.m_hit_test == false)
+               {
+                       continue;
+               }
+
+               // Find the mouse position in button-record space.
+               point   sub_p;
+               rec.m_button_matrix.transform_by_inverse(&sub_p, p);
+
+               if (rec.m_character_def->point_test_local(sub_p.m_x, sub_p.m_y))
+               {
+                       // The mouse is inside the shape.
+                       return this;
+                       // @@ Are there any circumstances where this is correct:
+                       //return m_record_character[i].get_ptr();
+               }
+       }}
+
+       return NULL;
+}
+
+
+void
+button_character_instance::on_button_event(event_id event)
+{
+       // Set our mouse state (so we know how to render).
+       switch (event.m_id)
+       {
+       case event_id::ROLL_OUT:
+       case event_id::RELEASE_OUTSIDE:
+               m_mouse_state = UP;
+               break;
+
+       case event_id::RELEASE:
+       case event_id::ROLL_OVER:
+       case event_id::DRAG_OUT:
+               m_mouse_state = OVER;
+               break;
+
+       case event_id::PRESS:
+       case event_id::DRAG_OVER:
+               m_mouse_state = DOWN;
+               break;
+
+       default:
+               assert(0);      // missed a case?
+               break;
+       };
+
+       // Button transition sounds.
+       if (m_def->m_sound != NULL)
+       {
+               int bi; // button sound array index [0..3]
+               sound_handler* s = get_sound_handler();
+
+               // Check if there is a sound handler
+               if (s != NULL) {
+                       switch (event.m_id)
+                       {
+                       case event_id::ROLL_OUT:
+                               bi = 0;
+                               break;
+                       case event_id::ROLL_OVER:
+                               bi = 1;
+                               break;
+                       case event_id::PRESS:
+                               bi = 2;
+                               break;
+                       case event_id::RELEASE:
+                               bi = 3;
+                               break;
+                       default:
+                               bi = -1;
+                               break;
+                       }
+                       if (bi >= 0)
+                       {
+                               button_character_definition::button_sound_info& 
bs = m_def->m_sound->m_button_sounds[bi];
+                               // character zero is considered as null 
character
+                               if (bs.m_sound_id > 0)
+                               {
+                                       
assert(m_def->m_sound->m_button_sounds[bi].m_sam != NULL);
+                                       if (bs.m_sound_style.m_stop_playback)
+                                       {
+                                               
s->stop_sound(bs.m_sam->m_sound_handler_id);
+                                       }
+                                       else
+                                       {
+                                               
s->play_sound(bs.m_sam->m_sound_handler_id, bs.m_sound_style.m_loop_count, 0, 
0);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // @@ eh, should just be a lookup table.
+       int     c = 0;
+       if (event.m_id == event_id::ROLL_OVER) c |= 
(button_action::IDLE_TO_OVER_UP);
+       else if (event.m_id == event_id::ROLL_OUT) c |= 
(button_action::OVER_UP_TO_IDLE);
+       else if (event.m_id == event_id::PRESS) c |= 
(button_action::OVER_UP_TO_OVER_DOWN);
+       else if (event.m_id == event_id::RELEASE) c |= 
(button_action::OVER_DOWN_TO_OVER_UP);
+       else if (event.m_id == event_id::DRAG_OUT) c |= 
(button_action::OVER_DOWN_TO_OUT_DOWN);
+       else if (event.m_id == event_id::DRAG_OVER) c |= 
(button_action::OUT_DOWN_TO_OVER_DOWN);
+       else if (event.m_id == event_id::RELEASE_OUTSIDE) c |= 
(button_action::OUT_DOWN_TO_IDLE);
+       //IDLE_TO_OVER_DOWN = 1 << 7,
+       //OVER_DOWN_TO_IDLE = 1 << 8,
+
+       // restart the characters of the new state.
+       restart_characters(c);
+
+       // Add appropriate actions to the movie's execute list...
+       {for (unsigned int i = 0; i < m_def->m_button_actions.size(); i++)
+       {
+               if (m_def->m_button_actions[i].m_conditions & c)
+               {
+                       // Matching action.
+                       for (unsigned int j = 0; j < 
m_def->m_button_actions[i].m_actions.size(); j++)
+                       {
+                               
get_parent()->add_action_buffer(m_def->m_button_actions[i].m_actions[j]);
+                       }
+               }
+       }}
+
+       // Call conventional attached method.
+       // @@ TODO
+}
+
+
+void
+button_character_instance::restart_characters(int condition)
+{
+       // Restart our relevant characters
+       for (unsigned int i = 0; i < m_def->m_button_records.size(); i++)
+       {
+               bool    restart = false;
+               button_record* rec = &m_def->m_button_records[i];
+
+               switch (m_mouse_state)
+               {
+               case OVER:
+               {
+                       if ((rec->m_over) && (condition & 
button_action::IDLE_TO_OVER_UP))
+                       {
+                               restart = true;
+                       }
+                       break;
+               }
+               // @@ Hm, are there other cases where we restart stuff?
+               default:
+               {
+                       break;
+               }
+               }
+
+               if (restart == true)
+               {
+                       m_record_character[i]->restart();
+               }
+       }
+}
+
+
+void
+button_character_instance::get_mouse_state(int* x, int* y, int* buttons)
+{
+       get_parent()->get_mouse_state(x, y, buttons);
+}
+
+
+//
+// ActionScript overrides
+//
+
+void
+button_character_instance::set_member(const tu_stringi& name,
+               const as_value& val)
+{
+       // TODO: pull these up into a base class, to
+       // share as much as possible with sprite_instance.
+       as_standard_member      std_member = get_standard_member(name);
+       switch (std_member)
+       {
+       default:
+       case M_INVALID_MEMBER:
+               break;
+       case M_VISIBLE:  // _visible
+       {
+               m_visible = val.to_bool();
+               return;
+       }
+       case M_ALPHA:  // _alpha
+       {
+               // Set alpha modulate, in percent.
+               cxform  cx = get_cxform();
+               cx.m_[3][0] = float(val.to_number()) / 100.f;
+               set_cxform(cx);
+               //m_accept_anim_moves = false;
+               return;
+       }
+       case M_X:  // _x
+       {
+               matrix  m = get_matrix();       // @@ get_world_matrix()???
+               m.m_[0][2] = float(PIXELS_TO_TWIPS(val.to_number()));
+               this->set_matrix(m);
+               return;
+       }
+       case M_Y:  // _y
+       {
+               matrix  m = get_matrix();       // @@ get_world_matrix()???
+               m.m_[1][2] = float(PIXELS_TO_TWIPS(val.to_number()));
+               this->set_matrix(m);
+               return;
+       }
+// evan : need set_width and set_height function for struct character
+#if 0
+       case M_WIDTH:  // _width
+       {
+               for (int i = 0; i < m_def->m_button_records.size(); i++)
+               {
+                       button_record&  rec = m_def->m_button_records[i];
+                       if (m_record_character[i] == NULL)
+                       {
+                               continue;
+                       }
+                       if ((m_mouse_state == UP && rec.m_up)
+                           || (m_mouse_state == DOWN && rec.m_down)
+                           || (m_mouse_state == OVER && rec.m_over))
+                       {
+                               m_record_character[i]->set_width(val.to_number);
+                               // @@ evan: should we return here?
+                               return;
+                       }
+               }
+
+               return;
+       }
+       else if (name == "enabled")
+       {
+               m_enabled = val.to_bool();
+       }
+       case M_HEIGHT:  // _height
+       {
+               for (int i = 0; i < m_def->m_button_records.size(); i++)
+               {
+                       button_record&  rec = m_def->m_button_records[i];
+                       if (m_record_character[i] == NULL)
+                       {
+                               continue;
+                       }
+                       if ((m_mouse_state == UP && rec.m_up)
+                           || (m_mouse_state == DOWN && rec.m_down)
+                           || (m_mouse_state == OVER && rec.m_over))
+                       {
+                               
m_record_character[i]->set_height(val.to_number);
+                               // @@ evan: should we return here?
+                               return;
+                       }
+               }
+
+               return;
+       }
+#endif
+       }
+
+       log_error("error: button_character_instance::set_member('%s', '%s') not 
implemented yet\n",
+                         name.c_str(),
+                         val.to_string());
+}
+
+bool
+button_character_instance::get_member(const tu_stringi& name, as_value* val)
+{
+       // TODO: pull these up into a base class, to
+       // share as much as possible with sprite_instance.
+       as_standard_member      std_member = get_standard_member(name);
+       switch (std_member)
+       {
+       default:
+       case M_INVALID_MEMBER:
+               break;
+       case M_VISIBLE:  // _visible
+       {
+               val->set_bool(this->get_visible());
+               return true;
+       }
+       case M_ALPHA:  // _alpha
+       {
+               // @@ TODO this should be generic to struct character!
+               // Alpha units are in percent.
+               val->set_double(get_cxform().m_[3][0] * 100.f);
+               return true;
+       }
+       case M_X:  // _x
+       {
+               matrix  m = get_matrix();       // @@ get_world_matrix()???
+               val->set_double(TWIPS_TO_PIXELS(m.m_[0][2]));
+               return true;
+       }
+       case M_Y:  // _y
+       {
+               matrix  m = get_matrix();       // @@ get_world_matrix()???
+               val->set_double(TWIPS_TO_PIXELS(m.m_[1][2]));
+               return true;
+       }
+       case M_WIDTH:  // _width
+       {
+               for (unsigned int i = 0; i < m_def->m_button_records.size(); 
i++)
+               {
+                       button_record&  rec = m_def->m_button_records[i];
+                       if (m_record_character[i] == NULL)
+                       {
+                               continue;
+                       }
+                       if ((m_mouse_state == UP && rec.m_up)
+                           || (m_mouse_state == DOWN && rec.m_down)
+                           || (m_mouse_state == OVER && rec.m_over))
+                       {
+                               
val->set_double(TWIPS_TO_PIXELS(m_record_character[i]->get_width()));
+                               // @@ evan: should we return here?
+                               return true;
+                       }
+               }
+
+               // from the experiments with macromedia flash player
+               val->set_double(0);
+               return true;
+       }
+       case M_HEIGHT:  // _height
+       {
+               for (unsigned int i = 0; i < m_def->m_button_records.size(); 
i++)
+               {
+                       button_record&  rec = m_def->m_button_records[i];
+                       if (m_record_character[i] == NULL)
+                       {
+                               continue;
+                       }
+                       if ((m_mouse_state == UP && rec.m_up)
+                           || (m_mouse_state == DOWN && rec.m_down)
+                           || (m_mouse_state == OVER && rec.m_over))
+                       {
+                               
val->set_double(TWIPS_TO_PIXELS(m_record_character[i]->get_height()));
+                               // @@ evan: should we return here?
+                               return true;
+                       }
+               }
+
+               // from the experiments with macromedia flash player
+               val->set_double(0);
+               return true;
+       }
+       } // end of switch
+
+       return false;
+}
+
+} // end of namespace gnash
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8 
+// tab-width: 8
+// indent-tabs-mode: t
+// End:

Index: server/button_character_instance.h
===================================================================
RCS file: server/button_character_instance.h
diff -N server/button_character_instance.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/button_character_instance.h  26 Aug 2006 22:58:12 -0000      1.1
@@ -0,0 +1,130 @@
+// Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain.  Do
+// whatever you want with it.
+
+// SWF buttons.  Mouse-sensitive update/display, actions, etc.
+
+
+#ifndef GNASH_BUTTON_CHARACTER_INSTANCE_H
+#define GNASH_BUTTON_CHARACTER_INSTANCE_H
+
+
+//#include "impl.h" // should get rid of this
+#include "character.h" // for inheritance
+//#include "sound.h"
+
+// Forward declarations
+namespace gnash {
+       class sprite_instance;
+       class button_character_definition;
+}
+
+namespace gnash {
+
+
+//
+// button characters
+//
+
+enum mouse_state
+{
+       MOUSE_UP,
+       MOUSE_DOWN,
+       MOUSE_OVER
+};
+
+//
+// button_character_instance
+//
+
+class button_character_instance : public character
+{
+public:
+       button_character_definition*    m_def;
+       std::vector< smart_ptr<character> >     m_record_character;
+
+       enum mouse_flags
+       {
+               IDLE = 0,
+               FLAG_OVER = 1,
+               FLAG_DOWN = 2,
+               OVER_DOWN = FLAG_OVER|FLAG_DOWN,
+
+               // aliases
+               OVER_UP = FLAG_OVER,
+               OUT_DOWN = FLAG_DOWN
+       };
+       int     m_last_mouse_flags, m_mouse_flags;
+       enum e_mouse_state
+       {
+               UP = 0,
+               DOWN,
+               OVER
+       };
+       e_mouse_state m_mouse_state;
+
+       button_character_instance(button_character_definition* def,
+                       character* parent, int id);
+
+       ~button_character_instance();
+
+       bool can_handle_mouse_event() { return true; }
+
+       // called from keypress listener only
+       bool on_event(event_id id);
+
+       movie_root*     get_root() { return get_parent()->get_root(); }
+
+       void    restart();
+
+       virtual void    advance(float delta_time);
+
+       void    display();
+
+       /// Combine the flags to avoid a conditional.
+       //  It would be faster with a macro.
+       inline int      transition(int a, int b) const
+       {
+               return (a << 2) | b;
+       }
+
+
+       /// \brief
+       /// Return the topmost entity that the given point covers. 
+       /// NULL if none.
+       //
+       /// I.e. check against ourself.
+       ///
+       virtual movie*  get_topmost_mouse_entity(float x, float y);
+
+       virtual void    on_button_event(event_id event);
+
+       void restart_characters(int condition);
+
+       virtual void    get_mouse_state(int* x, int* y, int* buttons);
+
+       //
+       // ActionScript overrides
+       //
+
+       virtual void set_member(const tu_stringi& name, const as_value& val);
+
+       virtual bool get_member(const tu_stringi& name, as_value* val);
+
+       // not sure if we need to override this one.
+       //virtual const char*   get_text_value() const { return NULL; } // 
edit_text_character overrides this
+};
+
+}      // end namespace gnash
+
+
+#endif // GNASH_BUTTON_CHARACTER_INSTANCE_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8 
+// tab-width: 8
+// indent-tabs-mode: t
+// End:

Index: server/mouse_button_state.h
===================================================================
RCS file: server/mouse_button_state.h
diff -N server/mouse_button_state.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/mouse_button_state.h 26 Aug 2006 22:58:12 -0000      1.1
@@ -0,0 +1,61 @@
+// Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain.  Do
+// whatever you want with it.
+
+
+#ifndef GNASH_MOUSE_BUTTON_STATE_H
+#define GNASH_MOUSE_BUTTON_STATE_H
+
+
+//#include "impl.h" // should get rid of this
+#include "character_def.h"
+#include "sound.h"
+
+// Forward declarations
+namespace gnash {
+       class sprite_instance;
+}
+
+namespace gnash {
+
+//
+// Helper to generate mouse events, given mouse state & history.
+//
+
+
+//
+// Helper to generate mouse events, given mouse state & history.
+//
+class mouse_button_state
+{
+public:
+       weak_ptr<movie> m_active_entity;        // entity that currently owns 
the mouse pointer
+       weak_ptr<movie> m_topmost_entity;       // what's underneath the mouse 
right now
+
+       bool    m_mouse_button_state_last;              // previous state of 
mouse button
+       bool    m_mouse_button_state_current;           // current state of 
mouse button
+
+       bool    m_mouse_inside_entity_last;     // whether mouse was inside the 
active_entity last frame
+
+       mouse_button_state()
+               :
+               m_mouse_button_state_last(0),
+               m_mouse_button_state_current(0),
+               m_mouse_inside_entity_last(false)
+       {
+       }
+};
+
+}      // end namespace gnash
+
+
+#endif // GNASH_MOUSE_BUTTON_STATE_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8 
+// tab-width: 8
+// indent-tabs-mode: t
+// End:

Index: server/parser/button_character_def.cpp
===================================================================
RCS file: server/parser/button_character_def.cpp
diff -N server/parser/button_character_def.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/parser/button_character_def.cpp      26 Aug 2006 22:58:12 -0000      
1.1
@@ -0,0 +1,265 @@
+// -- Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain.  Do
+// whatever you want with it.
+
+// SWF buttons.  Mouse-sensitive update/display, actions, etc.
+
+
+#include "button_character_def.h"
+#include "button_character_instance.h" // for create_character_instance()
+
+//#include "action.h"
+//#include "render.h"
+//#include "sound.h"
+#include "stream.h" // for read()
+#include "movie_definition.h"
+//#include "sprite_instance.h"
+//#include "movie_root.h"
+#include "action_buffer.h"
+
+
+
+namespace gnash {
+
+//
+// button_action
+//
+
+
+button_action::~button_action()
+{
+       m_actions.clear();
+}
+
+void   button_action::read(stream* in, int tag_type)
+{
+       // Read condition flags.
+       if (tag_type == 7)
+       {
+               m_conditions = OVER_DOWN_TO_OVER_UP;
+       }
+       else
+       {
+               assert(tag_type == 34);
+               m_conditions = in->read_u16();
+       }
+
+       IF_VERBOSE_PARSE (
+       log_parse("-- actions in button\n"); // @@ need more info about which 
actions
+       );
+
+       // Read actions.
+       action_buffer*  a = new action_buffer;
+       a->read(in);
+       m_actions.push_back(a);
+}
+
+//
+// button_record
+//
+
+// Return true if we read a record; false if this is a null record.
+bool
+button_record::read(stream* in, int tag_type,
+               movie_definition* /*m*/)
+{
+       int     flags = in->read_u8();
+       if (flags == 0)
+       {
+               return false;
+       }
+       m_hit_test = flags & 8 ? true : false;
+       m_down = flags & 4 ? true : false;
+       m_over = flags & 2 ? true : false;
+       m_up = flags & 1 ? true : false;
+
+       m_character_id = in->read_u16();
+       m_character_def = NULL;
+       m_button_layer = in->read_u16(); 
+       m_button_matrix.read(in);
+
+       if (tag_type == 34)
+       {
+               m_button_cxform.read_rgba(in);
+       }
+
+       return true;
+}
+
+
+//
+// button_character_definition
+//
+
+button_character_definition::button_character_definition()
+       :
+       m_sound(NULL)
+// Constructor.
+{
+}
+
+button_character_definition::~button_character_definition()
+{
+       delete m_sound;
+}
+
+
+void button_character_definition::sound_info::read(stream* in)
+{
+       m_in_point = m_out_point = m_loop_count = 0;
+       in->read_uint(2);       // skip reserved bits.
+       m_stop_playback = in->read_uint(1) ? true : false;
+       m_no_multiple = in->read_uint(1) ? true : false;
+       m_has_envelope = in->read_uint(1) ? true : false;
+       m_has_loops = in->read_uint(1) ? true : false;
+       m_has_out_point = in->read_uint(1) ? true : false;
+       m_has_in_point = in->read_uint(1) ? true : false;
+       if (m_has_in_point) m_in_point = in->read_u32();
+       if (m_has_out_point) m_out_point = in->read_u32();
+       if (m_has_loops) m_loop_count = in->read_u16();
+       if (m_has_envelope)
+       {
+               int nPoints = in->read_u8();
+               m_envelopes.resize(nPoints);
+               for (int i=0; i < nPoints; i++)
+               {
+                       m_envelopes[i].m_mark44 = in->read_u32();
+                       m_envelopes[i].m_level0 = in->read_u16();
+                       m_envelopes[i].m_level1 = in->read_u16();
+               }
+       }
+       else
+       {
+               m_envelopes.resize(0);
+       }
+
+       IF_VERBOSE_PARSE(
+       log_parse("     has_envelope = %d", m_has_envelope);
+       log_parse("     has_loops = %d", m_has_loops);
+       log_parse("     has_out_point = %d", m_has_out_point);
+       log_parse("     has_in_point = %d", m_has_in_point);
+       log_parse("     in_point = %d", m_in_point);
+       log_parse("     out_point = %d", m_out_point);
+       log_parse("     loop_count = %d", m_loop_count);
+       log_parse("     envelope size = %u", m_envelopes.size());
+       );
+}
+
+
+
+void   button_character_definition::read(stream* in, int tag_type, 
movie_definition* m)
+// Initialize from the given stream.
+{
+       assert(tag_type == 7 || tag_type == 17 || tag_type == 34);
+
+       if (tag_type == 7)
+       {
+               // Old button tag.
+                       
+               // Read button character records.
+               for (;;)
+               {
+                       button_record   r;
+                       if (r.read(in, tag_type, m) == false)
+                       {
+                               // Null record; marks the end of button records.
+                               break;
+                       }
+                       m_button_records.push_back(r);
+               }
+
+               // Read actions.
+               m_button_actions.resize(m_button_actions.size() + 1);
+               m_button_actions.back().read(in, tag_type);
+       }
+       else if (tag_type == 17)
+       {
+               assert(m_sound == NULL);        // redefinition button sound is 
error
+               m_sound = new button_sound_def();
+               IF_VERBOSE_PARSE(
+               log_parse("button sound options: ");
+               );
+               for (int i = 0; i < 4; i++)
+               {
+                       button_sound_info& bs = m_sound->m_button_sounds[i];
+                       bs.m_sound_id = in->read_u16();
+                       if (bs.m_sound_id > 0)
+                       {
+                               bs.m_sam = (sound_sample_impl*) 
m->get_sound_sample(bs.m_sound_id);
+                               if (bs.m_sam == NULL)
+                               {
+//                                             printf("sound tag not found, 
sound_id=%d, button state #=%i", bs.sound_id, i);
+                               }
+                               IF_VERBOSE_PARSE(
+                               log_parse("\n   sound_id = %d", bs.m_sound_id);
+                               );
+                               bs.m_sound_style.read(in);
+                       }
+               }
+       }
+       else if (tag_type == 34)
+       {
+               // Read the menu flag.
+               m_menu = in->read_u8() != 0;
+
+               int     button_2_action_offset = in->read_u16();
+               int     next_action_pos = in->get_position() + 
button_2_action_offset - 2;
+
+               // Read button records.
+               for (;;)
+               {
+                       button_record   r;
+                       if (r.read(in, tag_type, m) == false)
+                       {
+                               // Null record; marks the end of button records.
+                               break;
+                       }
+                       m_button_records.push_back(r);
+               }
+
+               if (button_2_action_offset > 0)
+               {
+                       in->set_position(next_action_pos);
+
+                       // Read Button2ActionConditions
+                       for (;;)
+                       {
+                               int     next_action_offset = in->read_u16();
+                               next_action_pos = in->get_position() + 
next_action_offset - 2;
+
+                               m_button_actions.resize(m_button_actions.size() 
+ 1);
+                               m_button_actions.back().read(in, tag_type);
+
+                               if (next_action_offset == 0
+                                   || in->get_position() >= 
in->get_tag_end_position())
+                               {
+                                       // done.
+                                       break;
+                               }
+
+                               // seek to next action.
+                               in->set_position(next_action_pos);
+                       }
+               }
+       }
+}
+
+
+character*
+button_character_definition::create_character_instance(
+               character* parent, int id)
+{
+       character* ch = new button_character_instance(this, parent, id);
+       return ch;
+}
+
+}
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8 
+// tab-width: 8
+// indent-tabs-mode: t
+// End:

Index: server/parser/button_character_def.h
===================================================================
RCS file: server/parser/button_character_def.h
diff -N server/parser/button_character_def.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/parser/button_character_def.h        26 Aug 2006 22:58:12 -0000      
1.1
@@ -0,0 +1,128 @@
+// -- Thatcher Ulrich <address@hidden> 2003
+
+// This source code has been donated to the Public Domain.  Do
+// whatever you want with it.
+
+// SWF buttons.  Mouse-sensitive update/display, actions, etc.
+
+
+#ifndef GNASH_BUTTON_CHARACTER_DEF_H
+#define GNASH_BUTTON_CHARACTER_DEF_H
+
+
+//#include "impl.h" // should get rid of this
+#include "character_def.h"
+#include "sound.h"
+
+// Forward declarations
+namespace gnash {
+       class sprite_instance;
+}
+
+namespace gnash {
+
+class button_record
+{
+public:
+       bool    m_hit_test;
+       bool    m_down;
+       bool    m_over;
+       bool    m_up;
+       int     m_character_id;
+       character_def*  m_character_def;
+       int     m_button_layer;
+       matrix  m_button_matrix;
+       cxform  m_button_cxform;
+
+       bool    read(stream* in, int tag_type, movie_definition* m);
+};
+       
+class button_action
+{
+public:
+       enum condition
+       {
+               IDLE_TO_OVER_UP = 1 << 0,
+               OVER_UP_TO_IDLE = 1 << 1,
+               OVER_UP_TO_OVER_DOWN = 1 << 2,
+               OVER_DOWN_TO_OVER_UP = 1 << 3,
+               OVER_DOWN_TO_OUT_DOWN = 1 << 4,
+               OUT_DOWN_TO_OVER_DOWN = 1 << 5,
+               OUT_DOWN_TO_IDLE = 1 << 6,
+               IDLE_TO_OVER_DOWN = 1 << 7,
+               OVER_DOWN_TO_IDLE = 1 << 8
+       };
+       int     m_conditions;
+       std::vector<action_buffer*>     m_actions;
+
+       ~button_action();
+       void    read(stream* in, int tag_type);
+};
+
+
+class button_character_definition : public character_def
+{
+public:
+       struct sound_envelope
+       {
+               uint32_t m_mark44;
+               uint16_t m_level0;
+               uint16_t m_level1;
+       };
+
+       struct sound_info
+       {
+               void read(stream* in);
+
+               bool m_no_multiple;
+               bool m_stop_playback;
+               bool m_has_envelope;
+               bool m_has_loops;
+               bool m_has_out_point;
+               bool m_has_in_point;
+               uint32_t m_in_point;
+               uint32_t m_out_point;
+               uint16_t m_loop_count;
+               std::vector<sound_envelope> m_envelopes;
+       };
+
+       struct button_sound_info
+       {
+               uint16_t m_sound_id;
+               sound_sample_impl*      m_sam;
+               sound_info m_sound_style;
+       };
+
+       struct button_sound_def
+       {
+               void    read(stream* in, movie_definition* m);
+               button_sound_info m_button_sounds[4];
+       };
+
+
+       bool m_menu;
+       std::vector<button_record>      m_button_records;
+       std::vector<button_action>      m_button_actions;
+       button_sound_def*       m_sound;
+
+       button_character_definition();
+       virtual ~button_character_definition();
+
+       /// Create a mutable instance of our definition.
+       character* create_character_instance(character* parent, int id);
+
+       void    read(stream* in, int tag_type, movie_definition* m);
+};
+
+}      // end namespace gnash
+
+
+#endif // GNASH_BUTTON_CHARACTER_DEF_H
+
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 8 
+// tab-width: 8
+// indent-tabs-mode: t
+// End:

Index: server/button.cpp
===================================================================
RCS file: server/button.cpp
diff -N server/button.cpp
--- server/button.cpp   26 Aug 2006 02:08:31 -0000      1.29
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,1119 +0,0 @@
-// button.cpp  -- Thatcher Ulrich <address@hidden> 2003
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// SWF buttons.  Mouse-sensitive update/display, actions, etc.
-
-
-#include "button.h"
-
-#include "action.h"
-#include "render.h"
-#include "sound.h"
-#include "stream.h"
-#include "movie_definition.h"
-#include "sprite_instance.h"
-#include "movie_root.h"
-#include "action_buffer.h"
-
-
-/** \page buttons Buttons and mouse behaviour
-
-Observations about button & mouse behavior
-
-Entities that receive mouse events: only buttons and sprites, AFAIK
-
-When the mouse button goes down, it becomes "captured" by whatever
-element is topmost, directly below the mouse at that moment.  While
-the mouse is captured, no other entity receives mouse events,
-regardless of how the mouse or other elements move.
-
-The mouse remains captured until the mouse button goes up.  The mouse
-remains captured even if the element that captured it is removed from
-the display list.
-
-If the mouse isn't above a button or sprite when the mouse button goes
-down, then the mouse is captured by the background (i.e. mouse events
-just don't get sent, until the mouse button goes up again).
-
-Mouse events:
-
-+------------------+---------------+-------------------------------------+
-| Event            | Mouse Button  | description                         |
-=========================================================================
-| onRollOver       |     up        | sent to topmost entity when mouse   |
-|                  |               | cursor initially goes over it       |
-+------------------+---------------+-------------------------------------+
-| onRollOut        |     up        | when mouse leaves entity, after     |
-|                  |               | onRollOver                          |
-+------------------+---------------+-------------------------------------+
-| onPress          |  up -> down   | sent to topmost entity when mouse   |
-|                  |               | button goes down.  onRollOver       |
-|                  |               | always precedes onPress.  Initiates |
-|                  |               | mouse capture.                      |
-+------------------+---------------+-------------------------------------+
-| onRelease        |  down -> up   | sent to active entity if mouse goes |
-|                  |               | up while over the element           |
-+------------------+---------------+-------------------------------------+
-| onDragOut        |     down      | sent to active entity if mouse      |
-|                  |               | is no longer over the entity        |
-+------------------+---------------+-------------------------------------+
-| onReleaseOutside |  down -> up   | sent to active entity if mouse goes |
-|                  |               | up while not over the entity.       |
-|                  |               | onDragOut always precedes           |
-|                  |               | onReleaseOutside                    |
-+------------------+---------------+-------------------------------------+
-| onDragOver       |     down      | sent to active entity if mouse is   |
-|                  |               | dragged back over it after          |
-|                  |               | onDragOut                           |
-+------------------+---------------+-------------------------------------+
-
-There is always one active entity at any given time (considering NULL to
-be an active entity, representing the background, and other objects that
-don't receive mouse events).
-
-When the mouse button is up, the active entity is the topmost element
-directly under the mouse pointer.
-
-When the mouse button is down, the active entity remains whatever it
-was when the button last went down.
-
-The active entity is the only object that receives mouse events.
-
-!!! The "trackAsMenu" property alters this behavior!  If trackAsMenu
-is set on the active entity, then onReleaseOutside is filtered out,
-and onDragOver from another entity is allowed (from the background, or
-another trackAsMenu entity). !!!
-
-
-Pseudocode:
-
-active_entity = NULL
-mouse_button_state = UP
-mouse_inside_entity_state = false
-frame loop:
-  if mouse_button_state == DOWN
-
-    // Handle trackAsMenu
-    if (active_entity->trackAsMenu)
-      possible_entity = topmost entity below mouse
-      if (possible_entity != active_entity && possible_entity->trackAsMenu)
-        // Transfer to possible entity
-       active_entity = possible_entity
-       active_entity->onDragOver()
-       mouse_inside_entity_state = true;
-
-    // Handle onDragOut, onDragOver
-    if (mouse_inside_entity_state == false)
-      if (mouse is actually inside the active_entity)
-        // onDragOver
-       active_entity->onDragOver()
-        mouse_inside_entity_state = true;
-
-    else // mouse_inside_entity_state == true
-      if (mouse is actually outside the active_entity)
-        // onDragOut
-       active_entity->onDragOut()
-       mouse_inside_entity_state = false;
-
-    // Handle onRelease, onReleaseOutside
-    if (mouse button is up)
-      if (mouse_inside_entity_state)
-        // onRelease
-        active_entity->onRelease()
-      else
-        // onReleaseOutside
-       if (active_entity->trackAsMenu == false)
-          active_entity->onReleaseOutside()
-      mouse_button_state = UP
-    
-  if mouse_button_state == UP
-    new_active_entity = topmost entity below the mouse
-    if (new_active_entity != active_entity)
-      // onRollOut, onRollOver
-      active_entity->onRollOut()
-      active_entity = new_active_entity
-      active_entity->onRollOver()
-    
-    // Handle press
-    if (mouse button is down)
-      // onPress
-      active_entity->onPress()
-      mouse_inside_entity_state = true
-      mouse_button_state = DOWN
-
-*/
-
-
-namespace gnash {
-
-void generate_mouse_button_events(mouse_button_state* ms)
-{
-       smart_ptr<movie>        active_entity = ms->m_active_entity;
-       smart_ptr<movie>        topmost_entity = ms->m_topmost_entity;
-
-       if (ms->m_mouse_button_state_last == 1)
-       {
-               // Mouse button was down.
-
-               // Handle trackAsMenu dragOver
-               if (active_entity == NULL
-                   || active_entity->get_track_as_menu())
-               {
-                       if (topmost_entity != NULL
-                           && topmost_entity != active_entity
-                           && topmost_entity->get_track_as_menu() == true)
-                       {
-                               // Transfer to topmost entity, dragOver
-                               active_entity = topmost_entity;
-                               
active_entity->on_button_event(event_id::DRAG_OVER);
-                               ms->m_mouse_inside_entity_last = true;
-                       }
-               }
-
-               // Handle onDragOut, onDragOver
-               if (ms->m_mouse_inside_entity_last == false)
-               {
-                       if (topmost_entity == active_entity)
-                       {
-                               // onDragOver
-                               if (active_entity != NULL)
-                               {
-                                       
active_entity->on_button_event(event_id::DRAG_OVER);
-                               }
-                               ms->m_mouse_inside_entity_last = true;
-                       }
-               }
-               else
-               {
-                       // mouse_inside_entity_last == true
-                       if (topmost_entity != active_entity)
-                       {
-                               // onDragOut
-                               if (active_entity != NULL)
-                               {
-                                       
active_entity->on_button_event(event_id::DRAG_OUT);
-                               }
-                               ms->m_mouse_inside_entity_last = false;
-                       }
-               }
-
-               // Handle onRelease, onReleaseOutside
-               if (ms->m_mouse_button_state_current == 0)
-               {
-                       // Mouse button just went up.
-                       ms->m_mouse_button_state_last = 0;
-
-                       if (active_entity != NULL)
-                       {
-                               if (ms->m_mouse_inside_entity_last)
-                               {
-                                       // onRelease
-                                       
active_entity->on_button_event(event_id::RELEASE);
-                               }
-                               else
-                               {
-                                       // onReleaseOutside
-                                       if (active_entity->get_track_as_menu() 
== false)
-                                       {
-                                               
active_entity->on_button_event(event_id::RELEASE_OUTSIDE);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       if (ms->m_mouse_button_state_last == 0)
-       {
-               // Mouse button was up.
-
-               // New active entity is whatever is below the mouse right now.
-               if (topmost_entity != active_entity)
-               {
-                       // onRollOut
-                       if (active_entity != NULL)
-                       {
-                               
active_entity->on_button_event(event_id::ROLL_OUT);
-                       }
-
-                       active_entity = topmost_entity;
-
-                       // onRollOver
-                       if (active_entity != NULL)
-                       {
-                               
active_entity->on_button_event(event_id::ROLL_OVER);
-                       }
-
-                       ms->m_mouse_inside_entity_last = true;
-               }
-
-               // mouse button press
-               if (ms->m_mouse_button_state_current == 1)
-               {
-                       // onPress
-
-                       // set/kill focus for current root
-                       movie_root* mroot = (movie_root*) get_current_root();
-                       movie* current_active_entity = 
mroot->get_active_entity();
-
-                       // It's another entity ?
-                       if (current_active_entity != active_entity.get_ptr())
-                       {
-                               // First to clean focus
-                               if (current_active_entity != NULL)
-                               {
-                                       
current_active_entity->on_event(event_id::KILLFOCUS);
-                                       mroot->set_active_entity(NULL);
-                               }
-
-                               // Then to set focus
-                               if (active_entity != NULL)
-                               {
-                                       if 
(active_entity->on_event(event_id::SETFOCUS))
-                                       {
-                                               
mroot->set_active_entity(active_entity.get_ptr());
-                                       }
-                               }
-                       }
-
-                       if (active_entity != NULL)
-                       {
-                               active_entity->on_button_event(event_id::PRESS);
-                       }
-                       ms->m_mouse_inside_entity_last = true;
-                       ms->m_mouse_button_state_last = 1;
-               }
-       }
-
-       // Write the (possibly modified) smart_ptr copies back
-       // into the state struct.
-       ms->m_active_entity = active_entity;
-       ms->m_topmost_entity = topmost_entity;
-}
-
-
-class button_character_instance : public character
-{
-public:
-       button_character_definition*    m_def;
-       std::vector< smart_ptr<character> >     m_record_character;
-
-       enum mouse_flags
-       {
-               IDLE = 0,
-               FLAG_OVER = 1,
-               FLAG_DOWN = 2,
-               OVER_DOWN = FLAG_OVER|FLAG_DOWN,
-
-               // aliases
-               OVER_UP = FLAG_OVER,
-               OUT_DOWN = FLAG_DOWN
-       };
-       int     m_last_mouse_flags, m_mouse_flags;
-       enum e_mouse_state
-       {
-               UP = 0,
-               DOWN,
-               OVER
-       };
-       e_mouse_state m_mouse_state;
-
-       button_character_instance(button_character_definition* def,
-                       character* parent, int id)
-               :
-               character(parent, id),
-               m_def(def),
-               m_last_mouse_flags(IDLE),
-               m_mouse_flags(IDLE),
-               m_mouse_state(UP)
-       {
-               assert(m_def);
-
-               int r, r_num =  m_def->m_button_records.size();
-               m_record_character.resize(r_num);
-
-               movie_definition* movie_def = 
parent->get_root_movie()->get_movie_definition();
-
-               for (r = 0; r < r_num; r++)
-               {
-                       button_record*  bdef = &m_def->m_button_records[r];
-
-                       if (bdef->m_character_def == NULL)
-                       {
-                               // Resolve the character id.
-                               bdef->m_character_def = 
movie_def->get_character_def(bdef->m_character_id);
-                       }
-                       assert(bdef->m_character_def != NULL);
-
-                       const matrix&   mat = 
m_def->m_button_records[r].m_button_matrix;
-                       const cxform&   cx = 
m_def->m_button_records[r].m_button_cxform;
-
-                       smart_ptr<character> ch = 
bdef->m_character_def->create_character_instance(this, id);
-                       m_record_character[r] = ch;
-                       ch->set_matrix(mat);
-                       ch->set_cxform(cx);
-                       ch->restart();
-               }
-
-               // check up presence KeyPress events
-               for (unsigned int i = 0; i < m_def->m_button_actions.size(); 
i++)
-               {
-                       if (m_def->m_button_actions[i].m_conditions & 0xFE00)   
// check up on CondKeyPress: UB[7]
-                       {
-                               get_root()->add_keypress_listener(this);
-                               break;
-                       }
-               }
-
-       }
-
-       ~button_character_instance()
-       {
-               get_root()->remove_keypress_listener(this);
-       }
-
-       bool can_handle_mouse_event() { return true; }
-
-       // called from keypress listener only
-       bool on_event(event_id id)
-       {
-
-               if (id.m_id != event_id::KEY_PRESS)
-               {
-                       return false;
-               }
-
-               bool called = false;
-
-               static const event_id s_key[32] =
-               {
-                       event_id(),
-                       event_id(event_id::KEY_PRESS, key::LEFT),
-                       event_id(event_id::KEY_PRESS, key::RIGHT),
-                       event_id(event_id::KEY_PRESS, key::HOME),
-                       event_id(event_id::KEY_PRESS, key::END),
-                       event_id(event_id::KEY_PRESS, key::INSERT),
-                       event_id(event_id::KEY_PRESS, key::DELETEKEY),
-                       event_id(),
-                       event_id(event_id::KEY_PRESS, key::BACKSPACE),  //8
-                       event_id(),
-                       event_id(),
-                       event_id(),
-                       event_id(),
-                       event_id(event_id::KEY_PRESS, key::ENTER),      //13
-                       event_id(event_id::KEY_PRESS, key::UP),
-                       event_id(event_id::KEY_PRESS, key::DOWN),
-                       event_id(event_id::KEY_PRESS, key::PGUP),
-                       event_id(event_id::KEY_PRESS, key::PGDN),
-                       event_id(event_id::KEY_PRESS, key::TAB),
-                       // 32-126 folows ASCII
-               };
-
-
-               // Add appropriate actions to the movie's execute list...
-               for (unsigned int i = 0; i < m_def->m_button_actions.size(); 
i++)
-               {
-                       int keycode = (m_def->m_button_actions[i].m_conditions 
& 0xFE00) >> 9;
-                       event_id key_event = keycode < 32 ? s_key[keycode] : 
event_id(event_id::KEY_PRESS, (key::code) keycode);
-                       if (key_event == id)
-                       {
-                               // Matching action.
-                               for (unsigned int j = 0; j < 
m_def->m_button_actions[i].m_actions.size(); j++)
-                               {
-                                       
get_parent()->add_action_buffer(m_def->m_button_actions[i].m_actions[j]);
-                               }
-                               called = true;
-                       }
-               }
-
-               return called;
-       }
-
-       movie_root*     get_root() { return get_parent()->get_root(); }
-
-       void    restart()
-       {
-               m_last_mouse_flags = IDLE;
-               m_mouse_flags = IDLE;
-               m_mouse_state = UP;
-               int r, r_num =  m_record_character.size();
-               for (r = 0; r < r_num; r++)
-               {
-                       m_record_character[r]->restart();
-               }
-       }
-
-
-       virtual void    advance(float delta_time)
-       {
-//                     printf("%s:\n", __PRETTY_FUNCTION__); // FIXME:
-               // Implement mouse-drag.
-               character::do_mouse_drag();
-
-               matrix  mat = get_world_matrix();
-
-               // Advance our relevant characters.
-               {for (unsigned int i = 0; i < m_def->m_button_records.size(); 
i++)
-               {
-                       button_record&  rec = m_def->m_button_records[i];
-                       if (m_record_character[i] == NULL)
-                       {
-                               continue;
-                       }
-
-                       // Matrix
-                       matrix sub_matrix = mat;
-                       sub_matrix.concatenate(rec.m_button_matrix);
-
-                       // Advance characters that are activated by the new 
mouse state
-                       if (((m_mouse_state == UP) && (rec.m_up)) ||
-                           ((m_mouse_state == DOWN) && (rec.m_down)) ||
-                           ((m_mouse_state == OVER) && (rec.m_over)))
-                       {
-                               m_record_character[i]->advance(delta_time);
-                       }
-               }}
-       }
-
-
-       void    display()
-       {
-//                     GNASH_REPORT_FUNCTION;
-               for (unsigned int i = 0; i < m_def->m_button_records.size(); 
i++)
-               {
-                       button_record&  rec = m_def->m_button_records[i];
-                       if (m_record_character[i] == NULL)
-                       {
-                               continue;
-                       }
-                       if ((m_mouse_state == UP && rec.m_up)
-                           || (m_mouse_state == DOWN && rec.m_down)
-                           || (m_mouse_state == OVER && rec.m_over))
-                       {
-                                       matrix  mat = get_world_matrix();
-
-                               m_record_character[i]->display();
-                       }
-               }
-
-               do_display_callback();
-       }
-
-       inline int      transition(int a, int b) const
-       // Combine the flags to avoid a conditional. It would be faster with a 
macro.
-       {
-               return (a << 2) | b;
-       }
-
-
-       virtual movie*  get_topmost_mouse_entity(float x, float y)
-       // Return the topmost entity that the given point covers.  NULL if none.
-       // I.e. check against ourself.
-       {
-               if (get_visible() == false) {
-                       return false;
-               }
-
-               matrix  m = get_matrix();
-               point   p;
-               m.transform_by_inverse(&p, point(x, y));
-
-               {for (unsigned int i = 0; i < m_def->m_button_records.size(); 
i++)
-               {
-                       button_record&  rec = m_def->m_button_records[i];
-                       if (rec.m_character_id < 0 || rec.m_hit_test == false)
-                       {
-                               continue;
-                       }
-
-                       // Find the mouse position in button-record space.
-                       point   sub_p;
-                       rec.m_button_matrix.transform_by_inverse(&sub_p, p);
-
-                       if (rec.m_character_def->point_test_local(sub_p.m_x, 
sub_p.m_y))
-                       {
-                               // The mouse is inside the shape.
-                               return this;
-                               // @@ Are there any circumstances where this is 
correct:
-                               //return m_record_character[i].get_ptr();
-                       }
-               }}
-
-               return NULL;
-       }
-
-
-       virtual void    on_button_event(event_id event)
-       {
-               // Set our mouse state (so we know how to render).
-               switch (event.m_id)
-               {
-               case event_id::ROLL_OUT:
-               case event_id::RELEASE_OUTSIDE:
-                       m_mouse_state = UP;
-                       break;
-
-               case event_id::RELEASE:
-               case event_id::ROLL_OVER:
-               case event_id::DRAG_OUT:
-                       m_mouse_state = OVER;
-                       break;
-
-               case event_id::PRESS:
-               case event_id::DRAG_OVER:
-                       m_mouse_state = DOWN;
-                       break;
-
-               default:
-                       assert(0);      // missed a case?
-                       break;
-               };
-
-               // Button transition sounds.
-               if (m_def->m_sound != NULL)
-               {
-                       int bi; // button sound array index [0..3]
-                       sound_handler* s = get_sound_handler();
-
-                       // Check if there is a sound handler
-                       if (s != NULL) {
-                               switch (event.m_id)
-                               {
-                               case event_id::ROLL_OUT:
-                                       bi = 0;
-                                       break;
-                               case event_id::ROLL_OVER:
-                                       bi = 1;
-                                       break;
-                               case event_id::PRESS:
-                                       bi = 2;
-                                       break;
-                               case event_id::RELEASE:
-                                       bi = 3;
-                                       break;
-                               default:
-                                       bi = -1;
-                                       break;
-                               }
-                               if (bi >= 0)
-                               {
-                                       
button_character_definition::button_sound_info& bs = 
m_def->m_sound->m_button_sounds[bi];
-                                       // character zero is considered as null 
character
-                                       if (bs.m_sound_id > 0)
-                                       {
-                                               
assert(m_def->m_sound->m_button_sounds[bi].m_sam != NULL);
-                                               if 
(bs.m_sound_style.m_stop_playback)
-                                               {
-                                                       
s->stop_sound(bs.m_sam->m_sound_handler_id);
-                                               }
-                                               else
-                                               {
-                                                       
s->play_sound(bs.m_sam->m_sound_handler_id, bs.m_sound_style.m_loop_count, 0, 
0);
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               // @@ eh, should just be a lookup table.
-               int     c = 0;
-               if (event.m_id == event_id::ROLL_OVER) c |= 
(button_action::IDLE_TO_OVER_UP);
-               else if (event.m_id == event_id::ROLL_OUT) c |= 
(button_action::OVER_UP_TO_IDLE);
-               else if (event.m_id == event_id::PRESS) c |= 
(button_action::OVER_UP_TO_OVER_DOWN);
-               else if (event.m_id == event_id::RELEASE) c |= 
(button_action::OVER_DOWN_TO_OVER_UP);
-               else if (event.m_id == event_id::DRAG_OUT) c |= 
(button_action::OVER_DOWN_TO_OUT_DOWN);
-               else if (event.m_id == event_id::DRAG_OVER) c |= 
(button_action::OUT_DOWN_TO_OVER_DOWN);
-               else if (event.m_id == event_id::RELEASE_OUTSIDE) c |= 
(button_action::OUT_DOWN_TO_IDLE);
-               //IDLE_TO_OVER_DOWN = 1 << 7,
-               //OVER_DOWN_TO_IDLE = 1 << 8,
-
-               // restart the characters of the new state.
-               restart_characters(c);
-
-               // Add appropriate actions to the movie's execute list...
-               {for (unsigned int i = 0; i < m_def->m_button_actions.size(); 
i++)
-               {
-                       if (m_def->m_button_actions[i].m_conditions & c)
-                       {
-                               // Matching action.
-                               for (unsigned int j = 0; j < 
m_def->m_button_actions[i].m_actions.size(); j++)
-                               {
-                                       
get_parent()->add_action_buffer(m_def->m_button_actions[i].m_actions[j]);
-                               }
-                       }
-               }}
-
-               // Call conventional attached method.
-               // @@ TODO
-       }
-
-
-       void restart_characters(int condition)
-       {
-               // Restart our relevant characters
-               for (unsigned int i = 0; i < m_def->m_button_records.size(); 
i++)
-               {
-                       bool    restart = false;
-                       button_record* rec = &m_def->m_button_records[i];
-
-                       switch (m_mouse_state)
-                       {
-                       case OVER:
-                       {
-                               if ((rec->m_over) && (condition & 
button_action::IDLE_TO_OVER_UP))
-                               {
-                                       restart = true;
-                               }
-                               break;
-                       }
-                       // @@ Hm, are there other cases where we restart stuff?
-                       default:
-                       {
-                               break;
-                       }
-                       }
-
-                       if (restart == true)
-                       {
-                               m_record_character[i]->restart();
-                       }
-               }
-       }
-
-
-       virtual void    get_mouse_state(int* x, int* y, int* buttons)
-       {
-               get_parent()->get_mouse_state(x, y, buttons);
-       }
-
-
-       //
-       // ActionScript overrides
-       //
-
-       virtual void    set_member(const tu_stringi& name, const as_value& val)
-       {
-               // TODO: pull these up into a base class, to
-               // share as much as possible with sprite_instance.
-               as_standard_member      std_member = get_standard_member(name);
-               switch (std_member)
-               {
-               default:
-               case M_INVALID_MEMBER:
-                       break;
-               case M_VISIBLE:  // _visible
-               {
-                       m_visible = val.to_bool();
-                       return;
-               }
-               case M_ALPHA:  // _alpha
-               {
-                       // Set alpha modulate, in percent.
-                       cxform  cx = get_cxform();
-                       cx.m_[3][0] = float(val.to_number()) / 100.f;
-                       set_cxform(cx);
-                       //m_accept_anim_moves = false;
-                       return;
-               }
-               case M_X:  // _x
-               {
-                       matrix  m = get_matrix();       // @@ 
get_world_matrix()???
-                       m.m_[0][2] = float(PIXELS_TO_TWIPS(val.to_number()));
-                       this->set_matrix(m);
-                       return;
-               }
-               case M_Y:  // _y
-               {
-                       matrix  m = get_matrix();       // @@ 
get_world_matrix()???
-                       m.m_[1][2] = float(PIXELS_TO_TWIPS(val.to_number()));
-                       this->set_matrix(m);
-                       return;
-               }
-// evan : need set_width and set_height function for struct character
-#if 0
-               case M_WIDTH:  // _width
-               {
-                       for (int i = 0; i < m_def->m_button_records.size(); i++)
-                       {
-                               button_record&  rec = 
m_def->m_button_records[i];
-                               if (m_record_character[i] == NULL)
-                               {
-                                       continue;
-                               }
-                               if ((m_mouse_state == UP && rec.m_up)
-                                   || (m_mouse_state == DOWN && rec.m_down)
-                                   || (m_mouse_state == OVER && rec.m_over))
-                               {
-                                       
m_record_character[i]->set_width(val.to_number);
-                                       // @@ evan: should we return here?
-                                       return;
-                               }
-                       }
-
-                       return;
-               }
-               else if (name == "enabled")
-               {
-                       m_enabled = val.to_bool();
-               }
-               case M_HEIGHT:  // _height
-               {
-                       for (int i = 0; i < m_def->m_button_records.size(); i++)
-                       {
-                               button_record&  rec = 
m_def->m_button_records[i];
-                               if (m_record_character[i] == NULL)
-                               {
-                                       continue;
-                               }
-                               if ((m_mouse_state == UP && rec.m_up)
-                                   || (m_mouse_state == DOWN && rec.m_down)
-                                   || (m_mouse_state == OVER && rec.m_over))
-                               {
-                                       
m_record_character[i]->set_height(val.to_number);
-                                       // @@ evan: should we return here?
-                                       return;
-                               }
-                       }
-
-                       return;
-               }
-#endif
-               }
-
-               log_error("error: button_character_instance::set_member('%s', 
'%s') not implemented yet\n",
-                                 name.c_str(),
-                                 val.to_string());
-       }
-
-       virtual bool    get_member(const tu_stringi& name, as_value* val)
-       {
-               // TODO: pull these up into a base class, to
-               // share as much as possible with sprite_instance.
-               as_standard_member      std_member = get_standard_member(name);
-               switch (std_member)
-               {
-               default:
-               case M_INVALID_MEMBER:
-                       break;
-               case M_VISIBLE:  // _visible
-               {
-                       val->set_bool(this->get_visible());
-                       return true;
-               }
-               case M_ALPHA:  // _alpha
-               {
-                       // @@ TODO this should be generic to struct character!
-                       // Alpha units are in percent.
-                       val->set_double(get_cxform().m_[3][0] * 100.f);
-                       return true;
-               }
-               case M_X:  // _x
-               {
-                       matrix  m = get_matrix();       // @@ 
get_world_matrix()???
-                       val->set_double(TWIPS_TO_PIXELS(m.m_[0][2]));
-                       return true;
-               }
-               case M_Y:  // _y
-               {
-                       matrix  m = get_matrix();       // @@ 
get_world_matrix()???
-                       val->set_double(TWIPS_TO_PIXELS(m.m_[1][2]));
-                       return true;
-               }
-               case M_WIDTH:  // _width
-               {
-                       for (unsigned int i = 0; i < 
m_def->m_button_records.size(); i++)
-                       {
-                               button_record&  rec = 
m_def->m_button_records[i];
-                               if (m_record_character[i] == NULL)
-                               {
-                                       continue;
-                               }
-                               if ((m_mouse_state == UP && rec.m_up)
-                                   || (m_mouse_state == DOWN && rec.m_down)
-                                   || (m_mouse_state == OVER && rec.m_over))
-                               {
-                                       
val->set_double(TWIPS_TO_PIXELS(m_record_character[i]->get_width()));
-                                       // @@ evan: should we return here?
-                                       return true;
-                               }
-                       }
-
-                       // from the experiments with macromedia flash player
-                       val->set_double(0);
-                       return true;
-               }
-               case M_HEIGHT:  // _height
-               {
-                       for (unsigned int i = 0; i < 
m_def->m_button_records.size(); i++)
-                       {
-                               button_record&  rec = 
m_def->m_button_records[i];
-                               if (m_record_character[i] == NULL)
-                               {
-                                       continue;
-                               }
-                               if ((m_mouse_state == UP && rec.m_up)
-                                   || (m_mouse_state == DOWN && rec.m_down)
-                                   || (m_mouse_state == OVER && rec.m_over))
-                               {
-                                       
val->set_double(TWIPS_TO_PIXELS(m_record_character[i]->get_height()));
-                                       // @@ evan: should we return here?
-                                       return true;
-                               }
-                       }
-
-                       // from the experiments with macromedia flash player
-                       val->set_double(0);
-                       return true;
-               }
-               }
-
-               return false;
-       }
-
-       // not sure if we need to override this one.
-       //virtual const char*   get_text_value() const { return NULL; } // 
edit_text_character overrides this
-};
-
-
-       //
-       // button_record
-       //
-
-       // Return true if we read a record; false if this is a null record.
-       bool    button_record::read(stream* in, int tag_type,
-                       movie_definition* /*m*/)
-       {
-               int     flags = in->read_u8();
-               if (flags == 0)
-               {
-                       return false;
-               }
-               m_hit_test = flags & 8 ? true : false;
-               m_down = flags & 4 ? true : false;
-               m_over = flags & 2 ? true : false;
-               m_up = flags & 1 ? true : false;
-
-               m_character_id = in->read_u16();
-               m_character_def = NULL;
-               m_button_layer = in->read_u16(); 
-               m_button_matrix.read(in);
-
-               if (tag_type == 34)
-               {
-                       m_button_cxform.read_rgba(in);
-               }
-
-               return true;
-       }
-
-
-       //
-       // button_action
-       //
-
-
-       button_action::~button_action()
-       {
-               m_actions.clear();
-       }
-
-       void    button_action::read(stream* in, int tag_type)
-       {
-               // Read condition flags.
-               if (tag_type == 7)
-               {
-                       m_conditions = OVER_DOWN_TO_OVER_UP;
-               }
-               else
-               {
-                       assert(tag_type == 34);
-                       m_conditions = in->read_u16();
-               }
-
-               IF_VERBOSE_PARSE (
-               log_parse("-- actions in button\n"); // @@ need more info about 
which actions
-               );
-
-               // Read actions.
-               action_buffer*  a = new action_buffer;
-               a->read(in);
-               m_actions.push_back(a);
-       }
-
-
-       //
-       // button_character_definition
-       //
-
-       button_character_definition::button_character_definition()
-               :
-               m_sound(NULL)
-       // Constructor.
-       {
-       }
-
-       button_character_definition::~button_character_definition()
-       {
-               delete m_sound;
-       }
-
-
-       void button_character_definition::sound_info::read(stream* in)
-       {
-               m_in_point = m_out_point = m_loop_count = 0;
-               in->read_uint(2);       // skip reserved bits.
-               m_stop_playback = in->read_uint(1) ? true : false;
-               m_no_multiple = in->read_uint(1) ? true : false;
-               m_has_envelope = in->read_uint(1) ? true : false;
-               m_has_loops = in->read_uint(1) ? true : false;
-               m_has_out_point = in->read_uint(1) ? true : false;
-               m_has_in_point = in->read_uint(1) ? true : false;
-               if (m_has_in_point) m_in_point = in->read_u32();
-               if (m_has_out_point) m_out_point = in->read_u32();
-               if (m_has_loops) m_loop_count = in->read_u16();
-               if (m_has_envelope)
-               {
-                       int nPoints = in->read_u8();
-                       m_envelopes.resize(nPoints);
-                       for (int i=0; i < nPoints; i++)
-                       {
-                               m_envelopes[i].m_mark44 = in->read_u32();
-                               m_envelopes[i].m_level0 = in->read_u16();
-                               m_envelopes[i].m_level1 = in->read_u16();
-                       }
-               }
-               else
-               {
-                       m_envelopes.resize(0);
-               }
-
-               IF_VERBOSE_PARSE(
-               log_parse("     has_envelope = %d", m_has_envelope);
-               log_parse("     has_loops = %d", m_has_loops);
-               log_parse("     has_out_point = %d", m_has_out_point);
-               log_parse("     has_in_point = %d", m_has_in_point);
-               log_parse("     in_point = %d", m_in_point);
-               log_parse("     out_point = %d", m_out_point);
-               log_parse("     loop_count = %d", m_loop_count);
-               log_parse("     envelope size = %u", m_envelopes.size());
-               );
-       }
-
-
-
-       void    button_character_definition::read(stream* in, int tag_type, 
movie_definition* m)
-       // Initialize from the given stream.
-       {
-               assert(tag_type == 7 || tag_type == 17 || tag_type == 34);
-
-               if (tag_type == 7)
-               {
-                       // Old button tag.
-                               
-                       // Read button character records.
-                       for (;;)
-                       {
-                               button_record   r;
-                               if (r.read(in, tag_type, m) == false)
-                               {
-                                       // Null record; marks the end of button 
records.
-                                       break;
-                               }
-                               m_button_records.push_back(r);
-                       }
-
-                       // Read actions.
-                       m_button_actions.resize(m_button_actions.size() + 1);
-                       m_button_actions.back().read(in, tag_type);
-               }
-               else if (tag_type == 17)
-               {
-                       assert(m_sound == NULL);        // redefinition button 
sound is error
-                       m_sound = new button_sound_def();
-                       IF_VERBOSE_PARSE(
-                       log_parse("button sound options: ");
-                       );
-                       for (int i = 0; i < 4; i++)
-                       {
-                               button_sound_info& bs = 
m_sound->m_button_sounds[i];
-                               bs.m_sound_id = in->read_u16();
-                               if (bs.m_sound_id > 0)
-                               {
-                                       bs.m_sam = (sound_sample_impl*) 
m->get_sound_sample(bs.m_sound_id);
-                                       if (bs.m_sam == NULL)
-                                       {
-//                                             printf("sound tag not found, 
sound_id=%d, button state #=%i", bs.sound_id, i);
-                                       }
-                                       IF_VERBOSE_PARSE(
-                                       log_parse("\n   sound_id = %d", 
bs.m_sound_id);
-                                       );
-                                       bs.m_sound_style.read(in);
-                               }
-                       }
-               }
-               else if (tag_type == 34)
-               {
-                       // Read the menu flag.
-                       m_menu = in->read_u8() != 0;
-
-                       int     button_2_action_offset = in->read_u16();
-                       int     next_action_pos = in->get_position() + 
button_2_action_offset - 2;
-
-                       // Read button records.
-                       for (;;)
-                       {
-                               button_record   r;
-                               if (r.read(in, tag_type, m) == false)
-                               {
-                                       // Null record; marks the end of button 
records.
-                                       break;
-                               }
-                               m_button_records.push_back(r);
-                       }
-
-                       if (button_2_action_offset > 0)
-                       {
-                               in->set_position(next_action_pos);
-
-                               // Read Button2ActionConditions
-                               for (;;)
-                               {
-                                       int     next_action_offset = 
in->read_u16();
-                                       next_action_pos = in->get_position() + 
next_action_offset - 2;
-
-                                       
m_button_actions.resize(m_button_actions.size() + 1);
-                                       m_button_actions.back().read(in, 
tag_type);
-
-                                       if (next_action_offset == 0
-                                           || in->get_position() >= 
in->get_tag_end_position())
-                                       {
-                                               // done.
-                                               break;
-                                       }
-
-                                       // seek to next action.
-                                       in->set_position(next_action_pos);
-                               }
-                       }
-               }
-       }
-
-
-character*
-button_character_definition::create_character_instance(
-               character* parent, int id)
-{
-       character* ch = new button_character_instance(this, parent, id);
-       return ch;
-}
-
-}
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8 
-// tab-width: 8
-// indent-tabs-mode: t
-// End:

Index: server/button.h
===================================================================
RCS file: server/button.h
diff -N server/button.h
--- server/button.h     26 Aug 2006 02:08:31 -0000      1.10
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,166 +0,0 @@
-// button.h    -- Thatcher Ulrich <address@hidden> 2003
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// SWF buttons.  Mouse-sensitive update/display, actions, etc.
-
-
-#ifndef GNASH_BUTTON_H
-#define GNASH_BUTTON_H
-
-
-#include "impl.h" // should get rid of this
-#include "character_def.h"
-#include "sound.h"
-
-// Forward declarations
-namespace gnash {
-       class sprite_instance;
-}
-
-namespace gnash {
-
-//
-// Helper to generate mouse events, given mouse state & history.
-//
-
-class mouse_button_state
-{
-public:
-       weak_ptr<movie> m_active_entity;        // entity that currently owns 
the mouse pointer
-       weak_ptr<movie> m_topmost_entity;       // what's underneath the mouse 
right now
-
-       bool    m_mouse_button_state_last;              // previous state of 
mouse button
-       bool    m_mouse_button_state_current;           // current state of 
mouse button
-
-       bool    m_mouse_inside_entity_last;     // whether mouse was inside the 
active_entity last frame
-
-       mouse_button_state()
-               :
-               m_mouse_button_state_last(0),
-               m_mouse_button_state_current(0),
-               m_mouse_inside_entity_last(false)
-       {
-       }
-};
-
-void   generate_mouse_button_events(mouse_button_state* ms);
-
-
-//
-// button characters
-//
-enum mouse_state
-{
-       MOUSE_UP,
-       MOUSE_DOWN,
-       MOUSE_OVER
-};
-
-class button_record
-{
-public:
-       bool    m_hit_test;
-       bool    m_down;
-       bool    m_over;
-       bool    m_up;
-       int     m_character_id;
-       character_def*  m_character_def;
-       int     m_button_layer;
-       matrix  m_button_matrix;
-       cxform  m_button_cxform;
-
-       bool    read(stream* in, int tag_type, movie_definition* m);
-};
-       
-
-class button_action
-{
-public:
-       enum condition
-       {
-               IDLE_TO_OVER_UP = 1 << 0,
-               OVER_UP_TO_IDLE = 1 << 1,
-               OVER_UP_TO_OVER_DOWN = 1 << 2,
-               OVER_DOWN_TO_OVER_UP = 1 << 3,
-               OVER_DOWN_TO_OUT_DOWN = 1 << 4,
-               OUT_DOWN_TO_OVER_DOWN = 1 << 5,
-               OUT_DOWN_TO_IDLE = 1 << 6,
-               IDLE_TO_OVER_DOWN = 1 << 7,
-               OVER_DOWN_TO_IDLE = 1 << 8
-       };
-       int     m_conditions;
-       std::vector<action_buffer*>     m_actions;
-
-       ~button_action();
-       void    read(stream* in, int tag_type);
-};
-
-
-class button_character_definition : public character_def
-{
-public:
-       struct sound_envelope
-       {
-               uint32_t m_mark44;
-               uint16_t m_level0;
-               uint16_t m_level1;
-       };
-
-       struct sound_info
-       {
-               void read(stream* in);
-
-               bool m_no_multiple;
-               bool m_stop_playback;
-               bool m_has_envelope;
-               bool m_has_loops;
-               bool m_has_out_point;
-               bool m_has_in_point;
-               uint32_t m_in_point;
-               uint32_t m_out_point;
-               uint16_t m_loop_count;
-               std::vector<sound_envelope> m_envelopes;
-       };
-
-       struct button_sound_info
-       {
-               uint16_t m_sound_id;
-               sound_sample_impl*      m_sam;
-               sound_info m_sound_style;
-       };
-
-       struct button_sound_def
-       {
-               void    read(stream* in, movie_definition* m);
-               button_sound_info m_button_sounds[4];
-       };
-
-
-       bool m_menu;
-       std::vector<button_record>      m_button_records;
-       std::vector<button_action>      m_button_actions;
-       button_sound_def*       m_sound;
-
-       button_character_definition();
-       virtual ~button_character_definition();
-
-       /// Create a mutable instance of our definition.
-       character* create_character_instance(character* parent, int id);
-
-       void    read(stream* in, int tag_type, movie_definition* m);
-};
-
-}      // end namespace gnash
-
-
-#endif // GNASH_BUTTON_H
-
-
-// Local Variables:
-// mode: C++
-// c-basic-offset: 8 
-// tab-width: 8
-// indent-tabs-mode: t
-// End:




reply via email to

[Prev in Thread] Current Thread [Next in Thread]