/* libsswf_event.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */

/*

Copyright (c) 2002-2008 Made to Order Software Corp.

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

/** \file
 *
 * \brief The implementation of the sswf::Event class
 *
 * This file declares the body of the functions which are not
 * inline. It is part of the SSWF library.
 */

#include	"sswf/libsswf.h"

using namespace sswf;





/////////////////////////////////////////// Event


/** \class sswf::Event
 *
 * \brief The Event class used to declare the events a button or place object support
 *
 * This class is used to define the events of a TagButton or a TagPlace.
 * Both of these objects support the same events.
 *
 * \sa <a href="../SWFalexref.html#swf_event">SWF Alexis' Reference&mdash;swf_event</a>
 */


/** \enum sswf::Event::event_flag_t
 *
 * \brief Enumeration used to define a set of condition flags.
 *
 * This enumeration lists the set of flags used to define an event
 * condition. The events can be used with the TagButton or the
 * TagPlace objects.
 *
 * All condition flags are not available for both tags. The button
 * accept two conditions in link with implementing menu like
 * functionality. The place object accept all the other flags
 * at this time.
 *
 * The place object can also be used to create a class definition
 * which later can be instantiated in an object with the new
 * operator.
 *
 * \bug
 * If a TagButton flag is specified in an event used for a TagPlace,
 * an error will occur when you try to save the movie.
 *
 * \par
 * If a TagPlace flag is specified in an event used for a TagButton,
 * an error will occur when you try to save the movie.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 */

/** \var sswf::Event::event_flag_t sswf::Event::EVENT_COND_MENU_LEAVE
 *
 * \brief %Event signaling that the mouse pointer left the corresponding menu.
 *
 * This event is specific to the TagButton object.
 *
 * This flag appeared in version 3 of SWF.
 *
 * This flag can only be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_COND_MENU_ENTER
 *
 * \brief %Event signaling that the mouse pointer entered the corresponding menu.
 *
 * This event is specific to the TagButton object.
 *
 * This flag appeared in version 3 of SWF.
 *
 * This flag can only be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_CONSTRUCT
 *
 * \brief %Event received once whenever the corresponding object is created.
 *
 * This event is used to write a constructor in an object. This is used
 * for the constructor of objects as defined in Javascript. Yet, it is
 * not possible to select such a constructor depending on parameters.
 *
 * This flag appeared in version 7 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_KEY_PRESS
 *
 * \brief %Event reveiced whenever a key is pressed.
 *
 * This event is sent when the SWF movie has the focus and no text box
 * is currently selected (focused.)
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_DRAG_LEAVE
 *
 * \brief %Event received while dragging an object outside of this event object.
 *
 * This event is sent to the event object whenever the mouse pointer is
 * dragging an object outside of this object active area.
 *
 * This flag appeared in version 6 of SWF.
 *
 * This flag can be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_DRAG_ENTER
 *
 * \brief %Event received while dragging an object inside of this event object.
 *
 * This event is sent to the event object whenever the mouse pointer is
 * dragging an object is enters this object active area.
 *
 * This flag appeared in version 5 of SWF.
 *
 * This flag can be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_LEAVE
 *
 * \brief %Event received when the mouse pointer exits this object.
 *
 * This event is sent to the event object whenever the mouse pointer is
 * leaving the object active area.
 *
 * This flag appeared in version 5 of SWF.
 *
 * This flag can be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_ENTER
 *
 * \brief %Event received when the mouse pointer enters this object.
 *
 * This event is sent to the event object whenever the mouse pointer is
 * entering the object active area.
 *
 * This flag appeared in version 5 of SWF.
 *
 * This flag can be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_RELEASE_OUTSIDE
 *
 * \brief %Event received when the mouse button is released outside.
 *
 * This event is sent to the event object whenever the user clicked
 * inside this event object but released the mouse button once outside
 * of the object.
 *
 * This flag appeared in version 5 of SWF.
 *
 * This flag can be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_RELEASE_INSIDE
 *
 * \brief %Event received when the mouse button is released inside.
 *
 * This event is sent to the event object whenever the user clicked
 * inside this event object and released the mouse button while
 * still inside the object.
 *
 * This flag appeared in version 5 of SWF.
 *
 * This flag can be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_PUSH
 *
 * \brief %Event received when the user push a mouse button.
 *
 * This event is sent at the time the user pushes a button over
 * an event object.
 *
 * This flag appeared in version 5 of SWF.
 *
 * This flag can be used with a DefineButton2 object.
 *
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_INITIALIZE
 *
 * \brief %Event received to initialize a new instance of an object.
 *
 * This event is sent whenever an object is duplicated to re-initialize
 * variables. This event is somewhat similar to the
 * sswf::Event::EVENT_CONSTRUCT but I have no idea what the
 * differences are. I think that since version 7 of SWF, one should
 * use the construct event instead of this one.
 *
 * This flag appeared in version 5 of SWF.
 *
 * \note
 * This flag is supposed to be used by itself.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_DATA
 *
 * \brief %Event received ?
 *
 * I have no idea what this is for.
 *
 * This flag appeared in version 5 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_KEY_UP
 *
 * \brief %Event received whenever the user releases a key.
 *
 * An event object can be setup to receive a signal whenever a key is
 * released. Use an ActionScript Key object to know which key
 * was released.
 *
 * This key event is not linked with the sswf::Event::EVENT_KEY_PRESS
 * which is a specific ASCII key assigned to the event object.
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_KEY_DOWN
 *
 * \brief %Event received whenever the user presses a key.
 *
 * An event object can be setup to receive a signal whenever a key is
 * pressed down. Use an ActionScript Key object to know which key
 * was released.
 *
 * This key event is not linked with the sswf::Event::EVENT_KEY_PRESS
 * which is a specific ASCII key assigned to the event object.
 *
 * You may want to consider using the sswf::Event::EVENT_KEY_UP
 * instead of this event. In most cases, it is better adapted.
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_UP
 *
 * \brief %Event received when a mouse button is released over the event object.
 *
 * This event is sent when the mouse button is released over the
 * event object. This does not guarantee that the mouse button was
 * pushed over the same event object. In order to check for a mouse
 * click on an object, use the
 * sswf::Event::EVENT_POINTER_RELEASE_INSIDE
 * event instead.
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_DOWN
 *
 * \brief %Event received when the user clicks the event object.
 *
 * This event is sent whenever the user clicks with a mouse button
 * over the event object.
 *
 * If you are writing a button, you should use the
 * sswf::Event::EVENT_POINTER_RELEASE_INSIDE
 * to know when the user <i>clicked</i> the button.
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_POINTER_MOVE
 *
 * \brief %Event received when the mouse move within this object.
 *
 * An object marked with this event receives all the mouse movement
 * information.
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_UNLOAD
 *
 * \brief %Event received whenever the object is unloaded.
 *
 * This event can occurs only if you first load sub-movies. It
 * is sent to the object whenever that sub-movie is deleted.
 * This gives you a chance to do some extra cleanup.
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_ENTER_FRAME
 *
 * \brief %Event received whenever the object enters the frame?
 *
 * I'm still not too sure what this flag is for...
 *
 * This flag appeared in version 6 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 *
 * <hr>
 */


/** \var sswf::Event::event_flag_t sswf::Event::EVENT_ONLOAD
 *
 * \brief %Event received whenever the sample object is loaded.
 *
 * This event lets you initialize the event object once when first loading
 * the movie. This is useful to make an object available to the
 * user. At least, this is the technique used by Macromedia to initialize
 * classes on startup.
 *
 * Also, this event can be used to know once a specific object was loaded
 * (especially if the SWF is used on a modem, it can take a while to load!)
 *
 * If you need a constructor for your object, use the EVENT_CONSTRUCT
 * instead or call a construction function as required.
 *
 * This flag appeared in version 5 of SWF.
 *
 * \sa sswf::TagPlace::AddEvent(Event *event)
 */





/** \enum sswf::Event::condition_flag_t
 *
 * \brief Set of conditions understood by the TagButton
 *
 * This enumeration lists the flags understood by the
 * TagButton obect. The Events flags can be transformed
 * into a mask of condition flags using the
 * Event::Conditions(void) const function.
 *
 * \bug
 * If flags which are only for the TagPlace are set in an event
 * added to a TagButton, an error will occur.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_KEY_MASK
 *
 * \brief Mask of bits reserved for the key code.
 *
 * Whenever a key code is specified, it is saved in these bits. Notice
 * that the code is limited to 7 bits only. In order to support international
 * key code, one needs to use an event with the sswf::Event::EVENT_KEY_UP
 * or sswf::Event::EVENT_KEY_DOWN.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::EVENT_KEY_UP
 * \sa sswf::Event::EVENT_KEY_DOWN
 * \sa sswf::Event::CONDITION_KEY_SHIFT
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_KEY_SHIFT
 *
 * \brief Number of bits the key code needs to be shifted
 *
 * The number of bits the key code needs to be shifted to be included in
 * a condition mask.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_KEY_MASK
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_MENU_LEAVE
 *
 * \brief %Event received whenever the mouse leaves a menu.
 *
 * A button can be used to create a menu type of widget. This event can
 * be used to know whenever the menu is being exited by the mouse pointer.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_DRAG_LEAVE
 * \sa sswf::Event::CONDITION_POINTER_LEAVE
 * \sa sswf::Event::CONDITION_MENU_ENTER
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_MENU_ENTER
 *
 * \brief %Event received whenever the mouse enters a menu.
 *
 * A button can be used to create a menu type of widget. This event can
 * be used to know whenever the menu is being entered by the mouse pointer.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_DRAG_ENTER
 * \sa sswf::Event::CONDITION_POINTER_ENTER
 * \sa sswf::Event::CONDITION_MENU_LEAVE
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_POINTER_RELEASE_OUTSIDE
 *
 * \brief %Event received when the mouse button is released outside of the event object.
 *
 * This event is sent whenever the mouse button was clicked the event
 * object but relased outside of the event object.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_RELEASE_INSIDE
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_POINTER_DRAG_ENTER
 *
 * \brief %Event received whenever the mouse pointer enters the event object.
 *
 * This event is sent whenever the mouse pointer enters the event object
 * and is used to drag another object.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_ENTER
 * \sa sswf::Event::CONDITION_MENU_ENTER
 * \sa sswf::Event::CONDITION_POINTER_DRAG_LEAVE
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_POINTER_DRAG_LEAVE
 *
 * \brief %Event received whenever the mouse pointer leaves the event object.
 *
 * This event is sent whenever the mouse pointer leaves the event object
 * and is used to drag another object.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_PUSH
 * \sa sswf::Event::CONDITION_POINTER_LEAVE
 * \sa sswf::Event::CONDITION_POINTER_DRAG_ENTER
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_POINTER_RELEASE_INSIDE
 *
 * \brief %Event received whenever the mouse button is released inside the event object.
 *
 * This message is received after the used clicked in the event object
 * and released the mouse button when the mouse pointer was still inside
 * the event object.
 *
 * This is the event to use to react as a standard UI button.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_PUSH
 * \sa sswf::Event::CONDITION_POINTER_RELEASE_OUTSIDE
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_POINTER_PUSH
 *
 * \brief %Event received when the mouse button is clicked inside the event object.
 *
 * The user clicked on the event object. Notice that this event is sent when
 * the mouse button is still pushed. If you want to have the button reacts as
 * a usual UI button, you may want to use the
 * sswf::Event::CONDITION_POINTER_RELEASE_INSIDE
 * instead.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_RELEASE_INSIDE
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_POINTER_LEAVE
 *
 * \brief %Event received whenever the mouse pointer leaves the event object.
 *
 * Detects when the mouse leaves your event object active area.
 *
 * Note that under Linux it does not detect all cases. For instance, if the
 * mouse leaves the SWF window entirely, you usually don't receive this
 * event. Similarly, if a window opens in front of the SWF plugin, the
 * event is not sent.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_DRAG_LEAVE
 * \sa sswf::Event::CONDITION_MENU_LEAVE
 * \sa sswf::Event::CONDITION_POINTER_ENTER
 *
 * <hr>
 */


/** \var sswf::Event::condition_flag_t sswf::Event::CONDITION_POINTER_ENTER
 *
 * \brief %Event received whenever the mouse pointer enters the event object.
 *
 * This event is sent whenever the system detects that the mouse pointer
 * is moved over your event object.
 *
 * Note that when the user moves his mouse pointer really fast, the object
 * may never be hit in this way.
 *
 * \sa sswf::Event::Conditions(void) const
 * \sa sswf::TagButton::AddEvent(Event *event)
 * \sa sswf::Event::CONDITION_POINTER_DRAG_ENTER
 * \sa sswf::Event::CONDITION_MENU_ENTER
 * \sa sswf::Event::CONDITION_POINTER_LEAVE
 */







/** \enum sswf::Event::key_code_t
 *
 * \brief The enumeration representing all the ASCII key codes.
 *
 * This enumeration specifically lists the key codes which are not
 * standard ASCII codes such as the arrows, Home, End, Escape keys.
 *
 * If you need to catch international keys, use the
 * sswf::Event::EVENT_KEY_UP or sswf::Event::EVENT_KEY_DOWN
 * instead. Those events are triggered whatever the key and
 * the code is saved in the ActionScript Key object.
 *
 * This code is used whenever the sswf::Event::EVENT_KEY_PRESS
 * flag is set. Note that this flag is set automatically
 * whenever the sswf::Even::SetKey(unsigned char key) function
 * is called.
 *
 * It is expected that the corresponding keypad keys will be
 * generating the same events when NumLock is not turned on.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 * \sa sswf::Event::EVENT_KEY_UP
 * \sa sswf::Event::EVENT_KEY_DOWN
 * \sa sswf::Event::EVENT_KEY_PRESS
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_NONE
 *
 * \brief Special key code representing no key.
 *
 * This key code represents no key. When used with the SetKey(unsigned char key)
 * function, it clears the key from the corresponding event.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_LEFT_ARROW
 *
 * \brief Special key code representing the Left Arrow key.
 *
 * This key code catches the special Left Arrow key on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_RIGHT_ARROW
 *
 * \brief Special key code representing the Right Arrow key.
 *
 * This key code catches the special Right Arrow key on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_HOME
 *
 * \brief Special key code representing the Home key.
 *
 * This key code catches the special key named Home on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_END
 *
 * \brief Special key code representing the End key.
 *
 * This key code catches the special key named End on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_INSERT
 *
 * \brief Special key code representing the Insert key.
 *
 * This key code catches the special key named Insert (or Ins.)
 * on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_DELETE
 *
 * \brief Special key code representing the Delete key.
 *
 * This key code catches the special key named Delete (or Del.)
 * on the keyboard.
 *
 * Some keyboard may interpret the Backspace key as the
 * Delete key and vice versa.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_BACKSPACE
 *
 * \brief Special key code representing the Backspace key.
 *
 * This key code catches the special key named Backspace (or |<-)
 * on the keyboard.
 *
 * Some keyboard may interpret the Backspace key as the
 * Delete key and vice versa.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_ENTER
 *
 * \brief Special key code representing the Enter key.
 *
 * This key code catches the special key named Enter or Return
 * on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_UP_ARROW
 *
 * \brief Special key code representing the Up Arrow key.
 *
 * This key code catches the special Up Arrow key on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_DOWN_ARROW
 *
 * \brief Special key code representing the Down Arrow key.
 *
 * This key code catches the special Down Arrow key on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_PAGE_UP
 *
 * \brief Special key code representing the Page Up key.
 *
 * This key code catches the special Page Up key on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_PAGE_DOWN
 *
 * \brief Special key code representingthe Page Down key. 
 *
 * This key code catches the special Page Down key on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_TAB
 *
 * \brief Special key code representing the Tab key.
 *
 * This key code catches the special Tab key on the keyboard.
 *
 * Note that Shift-Tab is caught too. To distinguish between
 * both forms, you need to use the ActionScript Key object
 * and check for the Shift key flags.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_ESCAPE
 *
 * \brief Special key code representing the Escape key.
 *
 * This key code catches the special key named Escape (or Ecs.)
 * on the keyboard.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 *
 * <hr>
 */


/** \var sswf::Event::key_code_t sswf::Event::KEY_CODE_SPACE
 *
 * \brief Special key code representing Space key.
 *
 * This key code catches the Space key. This is equivalent
 * to using the ASCII space (' ') character.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 */









/** \struct sswf::Event::event_names_t
 *
 * \brief Internal structure used to save event name names and their corresponding bits.
 *
 * This is an internal structure only.
 *
 * \sa sswf::Event::g_event_names
 */

/** \property sswf::Event::event_names_t::f_flag
 *
 * \brief The flag value.
 *
 * The flag of this event as defined in SWF.
 */

/** \property sswf::Event::event_names_t::f_name
 *
 * \brief The flag name.
 *
 * The SSWF name for this flag.
 */

/** \brief %Event names.
 *
 * This array defines the names of events and the corresponding bit.
 *
 * The names are compared case insensitively, but the underscore has
 * to be just that and not a space. Change your user string before
 * a call to StringToEvents(const char *s) if you want to allow your
 * users to type a space.
 *
 * \sa sswf::Event::StringToEvents(const char *s)
 */
const Event::event_names_t	Event::g_event_names[SSWF_EVENT_COUNT] = {
	// V5.x
	{ EVENT_ONLOAD,			"ONLOAD" },
	{ EVENT_POINTER_DRAG_ENTER,	"POINTER_DRAG_ENTER" },
	{ EVENT_POINTER_LEAVE,		"POINTER_LEAVE" },
	{ EVENT_POINTER_ENTER,		"POINTER_ENTER" },
	{ EVENT_POINTER_RELEASE_OUTSIDE,"POINTER_RELEASE_OUTSIDE" },
	{ EVENT_POINTER_RELEASE_INSIDE,	"POINTER_RELEASE_INSIDE" },
	{ EVENT_POINTER_PUSH,		"POINTER_PUSH" },
	{ EVENT_INITIALIZE,		"INITIALIZE" },
	{ EVENT_DATA,			"DATA" },

	// V6.x
	{ EVENT_KEY_PRESS,		"KEY_PRESS" },
	{ EVENT_KEY_UP,			"KEY_UP" },
	{ EVENT_KEY_DOWN,		"KEY_DOWN" },
	{ EVENT_POINTER_UP,		"POINTER_UP" },
	{ EVENT_POINTER_DOWN,		"POINTER_DOWN" },
	{ EVENT_POINTER_MOVE,		"POINTER_MOVE" },
	{ EVENT_UNLOAD,			"UNLOAD" },
	{ EVENT_ENTER_FRAME,		"ENTER_FRAME" },
	{ EVENT_POINTER_DRAG_LEAVE,	"DRAG_LEAVE" },

	// Extras for DefineButton2
	{ EVENT_COND_MENU_ENTER,	"MENU_ENTER" },
	{ EVENT_COND_MENU_LEAVE,	"MENU_LEAVE" }
};


/** \struct sswf::Event::key_names_t
 *
 * \brief This is an internal structure used to list keys and their code.
 *
 * This structure is used internally to list the special key codes and their
 * name. It is used by the StringToKeyCode(const char *s) function.
 *
 * \sa sswf::Event::StringToKeyCode(const char *s)
 */

/** \property sswf::Event::key_names_t::f_code
 *
 * \brief The code of the key.
 *
 * The code of the special key named in f_name.
 *
 * \sa sswf::Event::key_names_t
 * \sa sswf::Event::StringToKeyCode(const char *s)
 */

/** \property sswf::Event::key_names_t::f_name
 *
 * \brief The name of the key.
 *
 * The name of the special key with its code.
 *
 * \sa sswf::Event::key_names_t
 * \sa sswf::Event::StringToKeyCode(const char *s)
 */

/** \brief Special key names.
 *
 * This array lists the special keys with their SWF code and their
 * name. See the function StringToKeyCode(const char *s) for more
 * information.
 *
 * The names are compared case insensitively, but the underscore (_)
 * must be an underscore. If you want to let your users enter a space
 * instead, change the string before a call to the function.
 *
 * \sa sswf::Event::StringToKeyCode(const char *s)
 */
const Event::key_names_t	Event::g_key_names[SSWF_KEY_COUNT] = {
	{ KEY_CODE_LEFT_ARROW,	"LEFT_ARROW" },
	{ KEY_CODE_RIGHT_ARROW,	"RIGHT_ARROW" },
	{ KEY_CODE_HOME,	"HOME" },
	{ KEY_CODE_END,		"END" },
	{ KEY_CODE_INSERT,	"INSERT" },
	{ KEY_CODE_DELETE,	"DELETE" },
	{ KEY_CODE_BACKSPACE,	"BACKSPACE" },
	{ KEY_CODE_ENTER,	"ENTER" },
	{ KEY_CODE_UP_ARROW,	"UP_ARROW" },
	{ KEY_CODE_DOWN_ARROW,	"DOWN_ARROW" },
	{ KEY_CODE_PAGE_UP,	"PAGE_UP" },
	{ KEY_CODE_PAGE_DOWN,	"PAGE_DOWN" },
	{ KEY_CODE_TAB,		"TAB" },
	{ KEY_CODE_ESCAPE,	"ESCAPE" },
	{ KEY_CODE_SPACE,	"SPACE" }
};


/** \brief Initialize an event object.
 *
 * By default an event object is initialized to a "no event" Event.
 *
 * \sa sswf::Event::Reset(void)
 */
Event::Event(void)
{
	Reset();
}


/** \brief Reset an event object.
 *
 * This function marks the Event object as empty. This is the
 * same as a newly created Event object.
 *
 * \sa sswf::Event::Event()
 */
void Event::Reset(void)
{
	int		max;

	f_events = 0;

	max = f_actions.Count();
	while(max > 0) {
		max--;
		delete f_actions.Get(max);
	}
	f_actions.Empty();
}


/** \brief Set event flags.
 *
 * This function sets the events mask to the specified set of flags. All the
 * following flags can be used. Use the or (|) operator to merge multiple
 * flags together.
 *
 * \code
 *  EVENT_COND_MENU_LEAVE
 *  EVENT_COND_MENU_ENTER
 *  EVENT_CONSTRUCT
 *  EVENT_KEY_PRESS
 *  EVENT_POINTER_DRAG_LEAVE
 *  EVENT_POINTER_DRAG_ENTER
 *  EVENT_POINTER_LEAVE
 *  EVENT_POINTER_ENTER
 *  EVENT_POINTER_RELEASE_OUTSIDE
 *  EVENT_POINTER_RELEASE_INSIDE
 *  EVENT_POINTER_PUSH
 *  EVENT_INITIALIZE
 *  EVENT_DATA
 *  EVENT_KEY_UP
 *  EVENT_KEY_DOWN
 *  EVENT_POINTER_UP
 *  EVENT_POINTER_DOWN
 *  EVENT_POINTER_MOVE
 *  EVENT_UNLOAD
 *  EVENT_ENTER_FRAME
 *  EVENT_ONLOAD
 * \endcode
 *
 * To change the flags currently set, one may call Events() first
 * to read the currently defined flags, and then SetEvents() with
 * the new mask.
 *
 * If you include the EVENT_KEY_PRESS, you need to also call
 * the SetKey(unsigned char key) function.
 *
 * \sa sswf::Event::Events(void) const
 * \sa sswf::Event::SetKey(unsigned char key)
 */
void Event::SetEvents(unsigned long events)
{
	f_events = events;
}


/** \brief Reads the current events mask.
 *
 * This functions returns the current events mask. This includes
 * all the events which will generate a reaction in the attached
 * object.
 *
 * This value is used with the SWF_TAG_PLACE_OBJECT2 (v3) and
 * SWF_TAG_PLACE_OBJECT3 (v8) tags.
 *
 * \sa sswf::Event::SetEvents(unsigned long events)
 * \sa sswf::Event::SetKey(unsigned char key)
 */
unsigned long Event::Events(void) const
{
	return f_events;
}


/** \brief Setup a key in that event.
 *
 * An event can react to the mouse and the keyboard.
 * To activate the keyboard functionality, you need to setup a
 * key. The object forces the EVENT_KEY_PRESS flag in the
 * events mask.
 *
 * The characters 32 to 126 can be used as is and they represent
 * the corresponding ASCII character (space, 0, 1, 2, A, B, etc.)
 *
 * The following special keys are also available:
 *
 * \code
 *  Event::KEY_CODE_NONE
 *  Event::KEY_CODE_LEFT_ARROW
 *  Event::KEY_CODE_RIGHT_ARROW
 *  Event::KEY_CODE_HOME
 *  Event::KEY_CODE_END
 *  Event::KEY_CODE_INSERT
 *  Event::KEY_CODE_DELETE
 *  Event::KEY_CODE_BACKSPACE
 *  Event::KEY_CODE_ENTER
 *  Event::KEY_CODE_UP_ARROW
 *  Event::KEY_CODE_DOWN_ARROW
 *  Event::KEY_CODE_PAGE_UP
 *  Event::KEY_CODE_PAGE_DOWN
 *  Event::KEY_CODE_TAB
 *  Event::KEY_CODE_ESCAPE
 *  Event::KEY_CODE_SPACE
 * \endcode
 *
 * Note that setting the key to KEY_CODE_NONE cancels a
 * previous SetKey() call.
 *
 * If you offer an end user a way to name a key, you may
 * want to use the StringToKeyCode(const char *s) to first
 * convert the name of the key into a valid keycode.
 *
 * \sa sswf::Event::Events(void) const
 * \sa sswf::Event::SetEvents(unsigned long events)
 * \sa sswf::Event::StringToKeyCode(const char *s)
 */
void Event::SetKey(unsigned char key)
{
	if(key == KEY_CODE_NONE) {
		f_events &= ~EVENT_KEY_PRESS;
	}
	else {
		f_events |= EVENT_KEY_PRESS;
	}

	f_key = key;
}


/** \brief Reset an event object.
 *
 * This functions returns the current key assigned to this event.
 *
 * By default the key is set to Event::KEY_CODE_NONE.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::SetEvents(unsigned long events)
 */
unsigned char Event::Key(void) const
{
	return f_key;
}


/** \brief Converts the events mask in a conditions mask.
 *
 * This functions converts the bits present in the current events mask
 * into a mask of conditions mask. The flags are very similar, but are
 * not at the same bit position.
 *
 * This function is similar to the Events() const function which reads
 * the current events plus the conversion.
 *
 * This value is used with the SWF_TAG_DEFINE_BUTTON2 tag.
 *
 * \sa sswf::Event::Events(void) const
 */
unsigned long Event::Conditions(void) const
{
	unsigned long	conditions;

	conditions = 0;

	if((f_events & EVENT_KEY_PRESS) != 0) {
		conditions |= f_key << CONDITION_KEY_SHIFT;
	}
	if((f_events & EVENT_COND_MENU_LEAVE) != 0) {
		conditions |= CONDITION_MENU_LEAVE;
	}
	if((f_events & EVENT_COND_MENU_ENTER) != 0) {
		conditions |= CONDITION_MENU_ENTER;
	}
	if((f_events & EVENT_POINTER_RELEASE_OUTSIDE) != 0) {
		conditions |= CONDITION_POINTER_RELEASE_OUTSIDE;
	}
	if((f_events & EVENT_POINTER_DRAG_ENTER) != 0) {
		conditions |= CONDITION_POINTER_DRAG_ENTER;
	}
	if((f_events & EVENT_POINTER_DRAG_LEAVE) != 0) {
		conditions |= CONDITION_POINTER_DRAG_LEAVE;
	}
	if((f_events & EVENT_POINTER_RELEASE_INSIDE) != 0) {
		conditions |= CONDITION_POINTER_RELEASE_INSIDE;
	}
	if((f_events & EVENT_POINTER_PUSH) != 0) {
		conditions |= CONDITION_POINTER_PUSH;
	}
	if((f_events & EVENT_POINTER_LEAVE) != 0) {
		conditions |= CONDITION_POINTER_LEAVE;
	}
	if((f_events & EVENT_POINTER_ENTER) != 0) {
		conditions |= CONDITION_POINTER_ENTER;
	}

	return conditions;
}


/** \brief Get the array of actions of this event.
 *
 * This functions returns a direct reference to the array of actions
 * available in this event object.
 *
 * This array can be used to read the existing actions or to add new
 * actions to the event.
 *
 * Actions are executed whenever the corresponding event is triggered.
 *
 * Use of the Reset() function deletes all the actions saved in this
 * array.
 *
 * \sa sswf::Event::Reset(void)
 */
Vectors& Event::Actions(void)
{
	return f_actions;
}


/** \brief Converts a set of events in a mask of bits.
 *
 * This functions transforms an ASCII string in a set of bits representing
 * the corresponding mask of events. The mask returned by this function can later
 * be used with the SetEvents(unsigned long events) function.
 *
 * The string is composed of event names separated by commas. Extraneous
 * spaces before and after each name are silently ignored. Events can be specified
 * either as a name or as a number. The number can be specified in decimal,
 * hexadecimal or octal.
 *
 * The following table lists the event names that this function can convert:
 *
 * \code
 *  // V5.x
 *  ONLOAD
 *  POINTER_DRAG_ENTER
 *  POINTER_LEAVE
 *  POINTER_ENTER
 *  POINTER_RELEASE_OUTSIDE
 *  POINTER_RELEASE_INSIDE
 *  POINTER_PUSH
 *  INITIALIZE
 *  DATA
 *  
 *  // V6.x
 *  KEY_PRESS
 *  KEY_UP
 *  KEY_DOWN
 *  POINTER_UP
 *  POINTER_DOWN
 *  POINTER_MOVE
 *  UNLOAD
 *  ENTER_FRAME
 *  DRAG_LEAVE
 *  
 *  // Extras for DefineButton2
 *  MENU_ENTER
 *  MENU_LEAVE
 * \endcode
 *
 * The event names are case insensitive.
 *
 * \bug
 * At this time, this function asserts() in debug mode when the input string
 * is invalid. There is otherwise no error reported to the caller.
 *
 * \par
 * The function will ignore names which are more than 31 characters.
 *
 * \sa sswf::Event::SetEvents(unsigned long events)
 * \sa sswf::Event::Events(void) const
 * \sa sswf::Event::g_event_names
 */
unsigned long Event::StringToEvents(const char *s)
{
	const char	*name;
	char		tmp[32];
	long		idx;
	unsigned long	l, flags;

	flags = 0;

	while(*s != '\0') {
		// clip leading spaces
		while(isspace(*s) || *s == ',') {
			s++;
		}
		name = s;
		while(*s != '\0' && *s != ',') {
			s++;
		}
		// clip ending spaces
		while(s > name && isspace(s[-1])) {
			s--;
		}

		l = s - name;
		assert(l < sizeof(tmp), "event name too long \"%s\"", name);
		if(l < sizeof(tmp)) {
			strncpy(tmp, name, l);
			tmp[l] = '\0';

			if(*tmp >= '0' && *tmp <= '9') {
				flags |= strtoul(tmp, NULL, 0);
			}
			else {
				// search for this name
				for(idx = 0; idx < SSWF_EVENT_COUNT; idx++) {
					if(strcasecmp(tmp, g_event_names[idx].f_name) == 0) {
						flags |= g_event_names[idx].f_flag;
						break;
					}
				}
				// TODO: should we have some kind of error
				//	 reporting here? instead of an assert
				assert(idx < SSWF_EVENT_COUNT, "event \"%s\" unknown", tmp);
			}
		}
	}

	return flags;
}



/** \brief Converts a string into a key code.
 *
 * This functions converts the specified string into a valid
 * SWF keycode. The input string is taken as an ASCII string.
 *
 * A key such as "A", "0" and "?" is returned as is.
 *
 * A special key such as "LEFT_ARROW" and "HOME" is converted
 * to the corresponding KEY_CODE_<name> keycode. The following
 * table lists the currently understood key names:
 *
 * \code
 *  LEFT_ARROW
 *  RIGHT_ARROW
 *  HOME
 *  END
 *  INSERT
 *  DELETE
 *  BACKSPACE
 *  ENTER
 *  UP_ARROW
 *  DOWN_ARROW
 *  PAGE_UP
 *  PAGE_DOWN
 *  TAB
 *  ESCAPE
 *  SPACE
 * \endcode
 *
 * The comparison is case insensitive, but the underscore (_) must
 * be an underscore. If you want your users to be able to type a
 * space, then you need to first convert the spaces into underscores.
 *
 * If the name passed does not correspond to a valid key, then the
 * function returns KEY_CODE_NONE.
 *
 * \sa sswf::Event::SetKey(unsigned char key)
 * \sa sswf::Event::Key(void) const
 * \sa sswf::Event::g_key_names
 */
unsigned char Event::StringToKeyCode(const char *s)
{
	long		idx;

	if(s == 0 || s[0] == '\0') {
		return KEY_CODE_NONE;
	}
	if(s[1] == '\0') {
		// a single character is returned as is (if valid)
		if(s[0] >= 32 && s[0] <= 126) {
			return s[0];
		}
		return KEY_CODE_NONE;
	}

	// search for a corresponding key
	for(idx = 0; idx < SSWF_EVENT_COUNT; idx++) {
		if(strcasecmp(s, g_key_names[idx].f_name) == 0) {
			return g_key_names[idx].f_code;
		}
	}

	return KEY_CODE_NONE;
}



/* The following options fold the documentation; use 'zi' to turn on and off
 *
 * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
 */
