// $Revision: 1.2 $ // Copyright (C) 1994, 1995 Taligent, Inc. All rights reserved. #ifndef TaligentSample_TILESINTERACTORS #include "TilesInteractors.h" #endif TaligentTypeExtensionMacro(TMoveInteractor); TMoveInteractor::TMoveInteractor() : fView(), fCommandBinding(0), fOrigin(0, 0) {} // The constructor takes a pointer to the view in which the mouse down // event occured and in which the TMoveInteractor should operate. TMoveInteractor::TMoveInteractor(TTilesView *view) : fView(view), fCommandBinding(0), fOrigin(0, 0) { // Sets the coordinates to be relative to the view in // which this interactor will operate. This is also // required so that MouseEntered and MouseExited events // will occur when the user enters and exits the view. SetCoordinateView(TViewHandle(*fView)); } TMoveInteractor::~TMoveInteractor() { // Delete the fCommandBinding if it exists. If no exception // occurs, then fCommandBinding will be NIL because the command // binding will be adopted by the document. delete fCommandBinding; } // MouseDown begins the process of tracking the mouse. bool TMoveInteractor::MouseDown(TMouseDownEvent& mouseDown) { // Turn on mouse moved event tracking. Normally mouse moved event // tracking is off because it is expensive. It must be turned on or // the MouseMoved handler will never get called. StartMouseMovedEvents(*mouseDown.GetMouseInputDevice()); // Turn on MouseEntered and MouseExited event tracking. Must be // explicitly turned on for the reasons above. When the mouse exits // the window, MouseMoved handling will be turned off. When the mouse // enters the window, MouseMoved handling will be turned back on. This // prevents the user from moving a TTile outside of the window. StartMouseEntryEvents(); // Store the location of the mouse down so the delta can be calculated // when the mouse moves. fOrigin = mouseDown.GetEventPosition(); // Always return true if the mouse event is handled. return true; } // MouseMoved will apply the TMoveCommand incrementally to the target, which // is the current selection. MouseMoved will not actually create a TMoveCommand // until the user has moved the mouse at least some minimal distance. bool TMoveInteractor::MouseMoved(TMouseMovedEvent& mouseMoved) { // Calculate the delta from the location of the MouseDown TGPoint delta = mouseMoved.GetEventPosition() - fOrigin; // If a command binding exists then a TMoveCommand is already created so // track the mouse and apply the command incrementally. // If a command binding does not exists then only create the TMoveCommand // if the user has moved at least 3.0 units from the mouse down location. if (fCommandBinding || delta.VectorLength() > 3.0) { // Mouse track has begun or is continuing. Start a try block // in order to catch any exceptions in mouse event handling. try { TMoveCommand* command; // If a command binding does not already exist, then this is // the first significant mouse movement since the mouse down. // Create a command binding consisting of the TMoveCommand and // the view's current selection if (fCommandBinding == 0) { // Make a new TMoveCommand command = new TMoveCommand; // Create a binding, passing the command, the current // selection retrieved from the view, the TGUIBundle and // an undo/redo label. fCommandBinding = new TTilesCommandBinding( command, ::CopyPointer(fView->GetTilesSelection()), *fView->GetGUIBundle(), TStandardText("Move")); // Call DoBegin on the TMoveCommand so it can save information // for undo purposes and do whatever else it needs to get ready. fView->DoBegin(*fCommandBinding); } // At this point the command binding has just been created or it already // existed. In either case, apply the incremental change to the command. // First get the command from the command binding. It must be cast to // a TMoveCommand* because GetCommand returns a generic TCommand*. command = (TMoveCommand*) fCommandBinding->GetCommand(); // Call MoveBy to set the delta command->MoveBy(delta); // Call DoIncrement to actually perform the incremental command step fView->DoIncrement(*fCommandBinding); } // Handle any exceptions. catch (const TStandardException &e) { HandleException(); } } // Always return true if the mouse event is handled. return true; } bool TMoveInteractor::MouseUp(TMouseUpEvent &mouseUp) { // The user has released the mouse button so stop watching for entry/exit events. StopMouseEntryEvents(); // And stop watching for mouse moved events. StopMouseMovedEvents(); // The user may not have moved the mouse after mouse down so check if // the command binding exists before attempting to finish the command. if (fCommandBinding) { try { // Get the command from the command binding, a downcast to TMoveCommand* // is necessary because GetCommand returns a generic TCommand* TMoveCommand* command = (TMoveCommand*) fCommandBinding->GetCommand(); // Have the document adopt the command binding and finish the command. // This is done through the view's AdoptAndDoEnd funciton inherited from // MGUIBundle. AdoptAndDoEnd hands the command over to the document // referenced in the TGUIBundle. fView->AdoptAndDoEnd(fCommandBinding); // Set fCommandBinding to NIL so that the destructor does not delete // the command binding which is now owned by the document. fCommandBinding = NIL; } // Handle exceptions. catch (const TStandardException &e) { HandleException(); } } // SetDone to true so this interactor finishes. Otherwise the next mouse // event would continue using this interactor. SetDone(true); // Always return true if the mouse event is handled. return true; } bool TMoveInteractor::MouseExited(TMouseMovedEvent& mouseExit) { // If the mouse exits the view, turn off mouse moved events so that // MouseMoved is not called and the TTile cannot be moved outside the window. StopMouseMovedEvents(); // Always return true if the mouse event is handled. return true; } bool TMoveInteractor::MouseEntered(TMouseMovedEvent& mouseEnter) { // If the mouse re-enters the view, turn on mouse moved events so that // MouseMoved is called and the TTile cannot be moved again. StartMouseMovedEvents(*mouseEnter.GetMouseInputDevice()); // Always return true if the mouse event is handled. return true; } void TMoveInteractor::HandleException() { // In case of an exception the command binding which is not adopted // by the document must be deleted. delete fCommandBinding; fCommandBinding = NIL; // Give up, finish this interactor. SetDone(true); }