// $Revision: 1.18 $ // Copyright (C) 1994 Taligent, Inc. All rights reserved. #ifndef Taligent_CANVASGRAPHICSELECTION #include "CanvasGraphicSelection.h" #endif #ifndef Taligent_GRAFEDITUTILITIES #include "GrafEditUtilities.h" #endif #ifndef Taligent_BASEGEOMETRY #include #endif #ifndef Taligent_BOUNDSMAKER #include #endif #ifndef Taligent_GRAFEDITTRACE #include "GrafEditTrace.h" #endif //================================================================================ // class TCanvasSelectionInteractor // // description An interactor that creates canvas lines by dragging. // //================================================================================ //======================================== // Metadata //======================================== VersionDefinitionsMacro (TCanvasSelectionInteractor,0); //======================================== // Constructors and Destructors //======================================== TCanvasSelectionInteractor::TCanvasSelectionInteractor ( MCanvasSelection* initialSelection, MToolHandler* handler, TCanvasView* canvasView ) : fRectSelecting (false), fTranslatingGraphic (false), fCanvasView (canvasView), fBinding (NIL), TCanvasRectDragInteractor (handler), fSelection(initialSelection) { PVMARK("TCanvasSelectionInteractor::TCanvasSelectionInteractor"); #ifdef DEBUG ::qprintf ("TCanvasSelectionInteractor::TCanvasSelectionInteractor\n"); #endif } TCanvasSelectionInteractor::~TCanvasSelectionInteractor () { PVMARK("TCanvasSelectionInteractor::~TCanvasSelectionInteractor"); #ifdef DEBUG ::qprintf ("TCanvasSelectionInteractor::~TCanvasSelectionInteractor\n"); #endif delete fSelection; } //======================================== // TCanvasInteractor Overrides //======================================== void TCanvasSelectionInteractor::StartInteraction () { PVMARK("TCanvasSelectionInteractor::StartInteraction"); #ifdef DEBUG ::qprintf ("TCanvasSelectionInteractor::StartInteraction\n"); #endif // Wherever we do a SelectGraphic, we start a drag (essentially what TCanvasGraphicTranslatingInteractor does) // Logic: // start selection drag on no graphic (ignores shift) = make a rect selection // click on valid graphic = select it and optionally move it // shift click on valid non-selected graphic = select it too (and optionally move it) // shift click on valid selected graphic = deselect it TGPoint pt = GetFirstPoint (); TCanvasGraphicID hit = fCanvasView->Hit (pt); if ( hit != TCanvasGraphicID::kInvalidID ) { if ( GetModifierKeys().IsShiftKeyDown() ) { if ( fSelection->IsGraphicSelected (hit) ) // shift click on selected graphic fSelection->DeselectGraphic (hit); else { // shift click on deselected graphic fSelection->SelectGraphic (hit); fTranslatingGraphic = true; fCommand = new TTranslateCanvasGraphicCmd (); fBinding = new TToolCommandBindingTo (fCommand, ::CopyPointer(fSelection)); DoBegin (*(fBinding.GetObject())); } } else { // click on graphic (no shift key) fSelection->DeselectAllGraphics (); fSelection->SelectGraphic (hit); fTranslatingGraphic = true; fCommand = new TTranslateCanvasGraphicCmd (); fBinding = new TToolCommandBindingTo (fCommand, ::CopyPointer(fSelection)); DoBegin (*(fBinding.GetObject())); } fCanvasView->AdoptCurrentSelection (::CopyPointer(fSelection)); } else fRectSelecting = true; } void TCanvasSelectionInteractor::ContinueInteraction () { PVMARK("TCanvasSelectionInteractor::ContinueInteraction"); #ifdef DEBUG ::qprintf ("TCanvasSelectionInteractor::ContinueInteraction\n"); #endif // This is only called by MouseMoved for the purposes of incrementing the translate // graphic command (i.e. when we are clicking on and moving a graphic) unsigned long n = GetNumberOfPoints (); if ( n >= 2 ) { fCommand->SetOffset (GetPoint(n-1)-GetPoint(n-2)); try { DoIncrement (*(fBinding.GetObject())); } catch(TCompoundDocumentException& theException) { if(theException.GetDescriptionIndex() == TCompoundDocumentException::kExpectedDoBegin) { fCommand = new TTranslateCanvasGraphicCmd (); fCommand->SetOffset (GetPoint(n-1)-GetPoint(n-2)); MCanvasSelection *selection = ::CopyPointer(fSelection); fBinding = new TToolCommandBindingTo(fCommand, selection); DoBegin (*(fBinding.GetObject())); } else { // Not our exception, let it fly! throw; } } } } void TCanvasSelectionInteractor::EndInteraction () { PVMARK("TCanvasSelectionInteractor::EndInteraction"); #ifdef DEBUG ::qprintf ("TCanvasSelectionInteractor::EndInteraction\n"); #endif if ( fRectSelecting ) { bool shifted = GetModifierKeys().IsShiftKeyDown(); if ( !shifted ) fSelection->DeselectAllGraphics (); TCanvasFrontToBackFilter filter; TGRect bounds (GetFirstPoint(), GetLastPoint()); bounds.OrderPoints (); TCanvasRectSelectionFunnel funnel (bounds, *fSelection, shifted); fCanvasView->EnumerateGraphics (filter, funnel); fCanvasView->AdoptCurrentSelection (::CopyPointer(fSelection)); } if ( fTranslatingGraphic ) { unsigned long n = GetNumberOfPoints (); if ( n >= 2 ) { fCommand->SetOffset (GetPoint(n-1)-GetPoint(n-2)); try { DoIncrement (*(fBinding.GetObject())); } catch(TCompoundDocumentException& theException) { if(theException.GetDescriptionIndex() == TCompoundDocumentException::kExpectedDoBegin) { fCommand = new TTranslateCanvasGraphicCmd (); fCommand->SetOffset (GetPoint(n-1)-GetPoint(n-2)); MCanvasSelection *selection = ::CopyPointer(fSelection); fBinding = new TToolCommandBindingTo(fCommand, selection); DoBegin (*(fBinding.GetObject())); } else { // Not our exception, let it fly! throw; } } } AdoptAndDoEnd (fBinding.OrphanObject()); fBinding = NIL; } } bool TCanvasSelectionInteractor::MouseMoved (TMouseMovedEvent& theEvent) { PVMARK("TCanvasSelectionInteractor::MouseMoved"); #ifdef DEBUG ::qprintf ("TCanvasSelectionInteractor::MouseMoved\n"); #endif TGPoint p = theEvent.GetEventPosition (); if ( p != GetLastPoint() ) { RecordPoint (p); if ( fRectSelecting ) DrawFeedback (); if ( fTranslatingGraphic ) ContinueInteraction (); } return true; } // ******************************************************************************** // class TCanvasRectSelectionFunnel // // description // // ******************************************************************************** // ======================================== // Constructors and Destructor // ======================================== TCanvasRectSelectionFunnel::TCanvasRectSelectionFunnel (const TGRect& theRect, MCanvasSelection& theSelection, bool shifted) : fRect (theRect), fSelection (theSelection), fShifted (shifted) { PVMARK("TCanvasRectSelectionFunnel::TCanvasRectSelectionFunnel"); #ifdef DEBUG ::qprintf ( "TCanvasRectSelectionFunnel::TCanvasRectSelectionFunnel\n" ); #endif } TCanvasRectSelectionFunnel::~TCanvasRectSelectionFunnel () { PVMARK("TCanvasRectSelectionFunnel::~TCanvasRectSelectionFunnel"); #ifdef DEBUG ::qprintf ( "TCanvasRectSelectionFunnel::~TCanvasRectSelectionFunnel\n" ); #endif } // ======================================== // Enumeration // ======================================== bool TCanvasRectSelectionFunnel::ProcessGraphic (const MCanvasGraphic& theGraphic) { PVMARK("TCanvasRectSelectionFunnel::ProcessGraphic"); #ifdef DEBUG ::qprintf ( "TCanvasRectSelectionFunnel::ProcessGraphic\n" ); #endif // historical note: GetLooseFitBounds is quirky. MGraphic::GLFB has recently been modified // to take a TGrafPort as a parameter so that it can be more accurate. However, the // MCanvasGraphic classes currently don't know about the ports they're being drawn // in, so that is not an option. Thus, GetLooseFitBounds returns bounds that err // toward being too big. Unfortunately, ProcessGraphic will not select a graphic // if you just barely enclose it in a drag selection rect, because the bounds of that // graphic seem to be larger than they really are. Thus, I accumulate the bounds with // TBoundsMaker here. Ultimately, GetLooseFitBounds or GetGeometricBounds should be more // accurate and the following could just be "if ( fRect.Contains (theGraphic.GetLooseFitBounds()) ) {" TBoundsMaker maker; maker.AccumulateBounds( theGraphic ); TGRect exactBounds = maker.GetBounds(); if ( fRect.Contains (exactBounds) ) { if ( fShifted && fSelection.IsGraphicSelected (theGraphic) ) fSelection.DeselectGraphic (theGraphic); else fSelection.SelectGraphic (theGraphic); } return true; }