coriolis/hurricane/doc/hurricane/Command.dox

395 lines
13 KiB
C++

// -*- C++ -*-
namespace Hurricane {
/*! \class Command
* \brief Command description (\b API)
*
* \section secCommandIntro Introduction
*
* A command is an object which models the behaviour to be
* obtained in reaction to mouse or keyboard events within a
* view.
*
* In order to better understand the interaction between the
* view and the command we will study, at the end of this
* chapter, a specific and useful command : the zoom.
*
* Let us notice first that, in order to be active in a given
* view, a command must be installed within this view. Notice
* also that a command can be installed within many views.
* Therefore when a new type of command is needed only one
* instance has to be created, so we avoid dealing with
* allocation and deletion issues.
*
* Notice also that a view may have many commands installed :
* the first bound to the left mouse button (the zoom for
* instance) and a second one on the middle button (the
* selection command for instance). The right button is, in
* principle, reserved to a contextual pop-up menu, but could
* also be used to bind a third command.
*
* A command is associated to a mouse button and has a name.
* This name may be usefull within the graphic interface for
* informing the user about the currently installed command.
*
* A command being a data base object properties can be attached
* to it.
*
*
* \section secCommandInstallationAndUninstallation Installation and un-installation
*
* Please refer to theses functions :
* <ul>
* <li><b>Command::InstallOn</b>
* <li><b>Command::UninstallFrom</b>
* </ul>
*
*
* \section secCommandRemarks Remarks
*
* Commands are very powerful objects of which the zoom is a
* rudimentary embodiment. It is perfectly feasible, for
* instance, at click time to create a contact and display as a
* real drawing (not a ghost) and move this contact according to
* the mouse movements, always with a real display, and at last
* drop it in the right place when the button is released.
*
* Furthermore, commands manage perfectly the complex effects
* introduced by the auto-scroll and double buffering
* techniques, without having to worry about. On the same way it
* is perfectly possible, while the command is ongoing, to apply
* actions like zoom in, zoom out and pan, thanks to the
* available keyboard shortcuts (and even to spawn more complex
* actions). The system will manage all those contradictory
* events in an efficient and secure way (when an auto-scroll
* occurs, a part of the ghost may have been moved and it is
* worthwile that we don't need to care about, and still more,
* if a "zoom in" is being requested at the same time ...).
*
*
* \section secCommandImportant Important : Coordinates of Messages
*
* In those messages, the position, when provided, is in the
* client coordinate system of the view (and not in the screen
* pixel coordinates).
*
* But for obtaining the position in the cell coordinate system,
* the inverse of the tranformation associated to the view must
* be applied to the point.
*
*
* \section secCommandCaseStudyTheZoom Case study : the Zoom
*
* Extracted from the file ZoomCommand.h
\code
class ZoomCommand : public Command {
// *******************************
// Types
// *****
public: typedef Command Inherit;
// Attributes
// **********
private: bool _started; // flag indicating that the zoom has started
private: Point _origin; // mouse position when zoom started
private: Point _extremity; // current mouse position
// Constructors
// ************
protected: ZoomCommand();
public: static ZoomCommand* Create();
// Destructor and message handlers
// *******************************
protected: virtual void _PreDelete();
public: virtual void _OnDrawGhost(View* view);
public: virtual void _OnMouseMove(View* view, const Point& position);
public: virtual void _OnButtonPress(View* view, const Point& position);
public: virtual void _OnButtonRelease(View* view, const Point& position);
// all those messages are not overloaded
};
// global function returning the zoom command object
ZoomCommand* GetZoomCommand();
\endcode
* Extracted from the file ZoomCommand.cpp
\code
static ZoomCommand* ZOOM_COMMAND = NULL;
ZoomCommand* GetZoomCommand()
// **************************
{
// global function which gets the zoom command
// or creates it when needed
if (!ZOOM_COMMAND) ZOOM_COMMAND = ZoomCommand::Create();
return ZOOM_COMMAND;
}
ZoomCommand::ZoomCommand()
// ***********************
: Inherit("Zoom", 1),
_started(false),
_origin(),
_extremity()
{
// the zoom command has name "Zoom" (as expected)
// and is bound to the left mouse button (button 1)
}
ZoomCommand* ZoomCommand::Create()
// *******************************
{
// A command being a data base object
// the classical Create function must be provided
ZoomCommand* zoomCommand = new ZoomCommand();
if (!zoomCommand)
throw Error("Can't create ZoomCommand : allocation failed");
zoomCommand_PostCreate();
return zoomCommand;
}
void ZoomCommand::_PreDelete()
// ***************************
{
// A command being a data base object
// a pre-delete function must be provided
// (the function of post-creation being not needed here)
Inherit::_PreDelete();
if (ZOOM_COMMAND == this) ZOOM_COMMAND = NULL;
}
void ZoomCommand::_OnDrawGhost(View* view)
// ***************************************
{
// The drawing of the ghost must appear only when the zoom starts
// it is a simple rubber rectangle between the start and current points
if (_started) viewDrawRectangle(_origin, _extremity);
}
void ZoomCommand::_OnMouseMove(View* view, const Point& position)
// **************************************************************
{
// when the mouse moves and the zoom has already started
if (_started) {
// the ghost drawing must be erased by calling the function
// viewDrawGhost(this) which prepares the graphic context
// and calls upon the message _OnDrawGhost(view)
// (don't call directly the message _OnDrawGhost of the command)
viewDrawGhost(this);
// then change the position
_extremity = position;
// and at last draw the new ghost (same method)
viewDrawGhost(this);
}
}
void ZoomCommand::_OnButtonPress(View* view, const Point& position)
// ****************************************************************
{
// When the user presses the button bound to the command
// we set-up different attributs to start a new zoom
// the starting and current point are the same
// the zomm is flagged as started
_origin = position;
_extremity = position;
_started = true;
// we draw the new ghost (same method)
viewDrawGhost(this);
}
void ZoomCommand::_OnButtonRelease(View* view, const Point& position)
// ******************************************************************
{
// we erase the ghost (same method)
viewDrawGhost(this);
// we flag the zoom as ended
_started = false;
// if the defined rectangle is meaningful we can trigger
// the reframe and the refresh of the view
if (_extremity != _origin) {
viewReframe(Box(_origin, _extremity));
viewRefresh();
}
}
\endcode
* The following piece of code shows now how to proceed for
* installing the zoom command on a given view
\code
View* view = ...; // we get the view
GetZoomCommand()InstallOn(view);
assert(GetZoomCommand()IsInstalledOn(view));
\endcode
*/
/*! \function const Name& Command::GetName() const;
* \Return the command name.
*/
/*! \function unsigned Command::GetButton() const;
* \Return the command mouse button.
*/
/*! \function Views Command::GetViews() const;
* \Return the collection of views where this command is installed.
*/
/*! \function bool Command::IsInstalledOn(View* view) const;
* \Return \true if the command is installed within the view, else
* \false.
*/
/*! \function void Command::_OnInstalledOn(View* view);
* Message called upon to inform the command that it has been
* installed in the view.
*/
/*! \function void Command::_OnUninstalledFrom(View* view);
* Message called upon to inform the command that it has been
* un-installed from the view.
*/
/*! \function void Command::_OnDrawGhost(View* view);
* Message called upon to inform the command that it has to draw
* its ghost.
*
* \important This message must not be called directly, even inside the
* following commands.
*
* Indeed, the view must prepare the graphic context in order to
* set up the appropriate display mode (i.e. xor). Therefore a
* request must be done to the view to call upon this message,
* once it has made the preliminary preparations, by writing
* view-\>DrawGhost(this).
*/
/*! \function void Command::_OnMouseEnter(View* view, const Point& position);
* Message called upon to inform the command that the mouse has
* entered the window associated to the drawing area.
*/
/*! \function void Command::_OnMouseMove(View* view, const Point& position, unsigned state);
* Message called upon to inform the command that the mouse has
* just moved.
*
* \important This message is received whatever the command button is being
* pressed or not.
*/
/*! \function void Command::_OnMouseLeave(View* view, const Point& position);
* Message called upon to inform the command that the mouse has
* exited the window associated to the drawing area.
*/
/*! \function void Command::_OnButtonPress(View* view, const Point& position, unsigned state);
* Message called upon to inform the command that a mouse button
* has just been pressed.
*/
/*! \function void Command::_OnButtonRelease(View* view, const Point& position, unsigned state);
* Message called upon to inform the command that a mouse button
* has just been released.
*/
/* \function void Command::_OnKeyPress(View* view, unsigned key);
* Message called upon to inform the command that a key has just
* been pressed.
*/
/* \function void Command::_OnKeyRelease(View* view, unsigned key);
* Message called upon to inform the command that a key has just
* been released.
*/
//! \name Command Collection
// \{
/*! \typedef Commands
* Generic collection representing a set of commands.
*/
/*! \typedef CommandLocator
* Generic locator for traversing a collection of commands.
*/
/*! \typedef CommandFilter
* Filter for selecting a sub-set of commands matching some
* criteria.
*/
/*! \def for_each_command(command, commands)
* Macro for visiting all commands of a collection of commands.
*/
// \}
/*! \function void Command::InstallOn(View* view);
* Allows to install the command in the view.
*
* \caution An exception is thrown if the view is null.
*
* Does nothing if the command is already installed in the view.
* On the other hand, if a command bound to the same button was
* already installed in the view, this last is automatically
* un-installed.
*
* When the command is effectively installed in the view, in
* order to inform this command of its installation and let it
* handle possible additional processing, a message
* <b>_OnInstalledOn()</b> is issued by the view.
*/
/*! \function void Command::UninstallFrom(View* view);
* Allows to un-install the command in the view.
*
* \caution An exception is thrown if the view is null.
*
* In order to inform the command of its un-installation and let
* it handle possible additional processing, a message
* <b>_OnUnInstalledFrom()</b> is issued by the view.
*/
}