395 lines
13 KiB
C++
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.
|
|
*/
|
|
|
|
}
|