// $Revision: 1.23 $ //======================================================================= // file CanvasGraphicManipulation.C // // description Classes used for generic direct manipulation // (scale, rotate and translate) of canvas graphics. // // modification history rtw 2/16/94 new file // // Copyright (C) 1994 Taligent, Inc. All rights reserved. //======================================================================== #ifndef Taligent_CANVASGRAPHICMANIPULATION #include "CanvasGraphicManipulation.h" #endif #ifndef Taligent_BUNDLES #include #endif #ifndef Taligent_GRAFPENS #include #endif #ifndef Taligent_RGBCOLOR #include #endif #ifndef Taligent_GRAFEDITTRACE #include "GrafEditTrace.h" #endif //================================================================================ // class TCanvasGraphicScalingInteractor // // description An interactor that scales canvas graphics. // //================================================================================ //======================================== // Constructors and Destructors //======================================== TCanvasGraphicScalingInteractor::TCanvasGraphicScalingInteractor ( MCanvasSelection* adoptTarget, MToolHandler* handler, const TGPoint& centerOfScale, const TGrafMatrix& tform ) : TCanvasDragInteractor (handler), fCenter (centerOfScale), fTransform (tform), fBinding (NIL) { PVMARK("TCanvasGraphicScalingInteractor::TCanvasGraphicScalingInteractor"); #ifdef DEBUG ::qprintf ("TCanvasGraphicScalingInteractor::TCanvasGraphicScalingInteractor\n"); #endif fCommand = new TScaleCanvasGraphicCmd (centerOfScale); fSelection = ::CopyPointer(adoptTarget); fBinding = new TToolCommandBindingTo (fCommand, adoptTarget); } TCanvasGraphicScalingInteractor::~TCanvasGraphicScalingInteractor () { PVMARK("TCanvasGraphicScalingInteractor::~TCanvasGraphicScalingInteractor"); #ifdef DEBUG ::qprintf ("TCanvasGraphicScalingInteractor::~TCanvasGraphicScalingInteractor\n"); #endif } //======================================== // Metadata //======================================== VersionDefinitionsMacro (TCanvasGraphicScalingInteractor,0); //======================================== // TCanvasInteractor Overrides //======================================== void TCanvasGraphicScalingInteractor::StartInteraction () { PVMARK("TCanvasGraphicScalingInteractor::StartInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicScalingInteractor::StartInteraction\n"); #endif TGPoint endPoint = GetLastPoint (); endPoint = fTransform.UntransformPoint (endPoint); fLastVector = endPoint - fCenter; DoBegin (*(fBinding.GetObject())); } void TCanvasGraphicScalingInteractor::ContinueInteraction () { PVMARK("TCanvasGraphicScalingInteractor::ContinueInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicScalingInteractor::ContinueInteraction\n"); #endif TGPoint endPoint = GetLastPoint (); endPoint = fTransform.UntransformPoint (endPoint); TGPoint newVector = endPoint - fCenter; if ( newVector.fX != 0.0 && newVector.fY != 0.0 ) { // potential bug workaround - if fLastVector has a 0 point, the new scaleFactor will have // a corresponding infinite point. Likely we should check this and set it to some // arbitrarily small number. (as follows) if (fLastVector.fX == 0.0) fLastVector.fX = 0.00001; if (fLastVector.fY == 0.0) fLastVector.fY = 0.00001; TGPoint scaleFactor = newVector / fLastVector; if ( scaleFactor != TGPoint (1.,1.) ) { fCommand->SetScaleFactor (scaleFactor); try { DoIncrement (*(fBinding.GetObject())); } catch(TCompoundDocumentException& theException) { if(theException.GetDescriptionIndex() == TCompoundDocumentException::kExpectedDoBegin) { fCommand = new TScaleCanvasGraphicCmd(fCenter); fCommand->SetScaleFactor(scaleFactor); MCanvasSelection *selection = ::CopyPointer(fSelection); fBinding = new TToolCommandBindingTo(fCommand, selection); DoBegin (*(fBinding.GetObject())); } else { // Not our exception, let it fly! throw; } } } fLastVector = newVector; } } void TCanvasGraphicScalingInteractor::EndInteraction () { PVMARK("TCanvasGraphicScalingInteractor::EndInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicScalingInteractor::EndInteraction\n"); #endif TGPoint endPoint = GetLastPoint (); endPoint = fTransform.UntransformPoint (endPoint); TGPoint newVector = endPoint - fCenter; if ( newVector.fX != 0.0 && newVector.fY != 0.0 ) { TGPoint scaleFactor = newVector / fLastVector; if ( scaleFactor != TGPoint (1.,1.) ) { fCommand->SetScaleFactor (scaleFactor); try { DoIncrement (*(fBinding.GetObject())); } catch(TCompoundDocumentException& theException) { if(theException.GetDescriptionIndex() == TCompoundDocumentException::kExpectedDoBegin) { fCommand = new TScaleCanvasGraphicCmd (fCenter); fCommand->SetScaleFactor(scaleFactor); 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; } //================================================================================ // class TCanvasGraphicRotatingInteractor // // description An interactor that rotates canvas graphics. // //================================================================================ //======================================== // Constructors and Destructors //======================================== TCanvasGraphicRotatingInteractor::TCanvasGraphicRotatingInteractor ( MCanvasSelection* adoptTarget, MToolHandler* handler, const TGPoint& centerOfRotate ) : TCanvasDragInteractor (handler), fCenter (centerOfRotate), fBinding (NIL) { PVMARK("TCanvasGraphicRotatingInteractor::TCanvasGraphicRotatingInteractor"); #ifdef DEBUG ::qprintf ("TCanvasGraphicRotatingInteractor::TCanvasGraphicRotatingInteractor\n"); #endif fCommand = new TRotateCanvasGraphicCmd (centerOfRotate); fSelection = ::CopyPointer(adoptTarget); fBinding = new TToolCommandBindingTo (fCommand, adoptTarget); } TCanvasGraphicRotatingInteractor::~TCanvasGraphicRotatingInteractor () { PVMARK("TCanvasGraphicRotatingInteractor::~TCanvasGraphicRotatingInteractor"); #ifdef DEBUG ::qprintf ("TCanvasGraphicRotatingInteractor::~TCanvasGraphicRotatingInteractor\n"); #endif } //======================================== // Metadata //======================================== VersionDefinitionsMacro (TCanvasGraphicRotatingInteractor,0); //======================================== // TCanvasInteractor Overrides //======================================== void TCanvasGraphicRotatingInteractor::StartInteraction () { PVMARK("TCanvasGraphicRotatingInteractor::StartInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicRotatingInteractor::StartInteraction\n"); #endif TGPoint endPoint = GetLastPoint (); fLastVector = endPoint - fCenter; DoBegin (*(fBinding.GetObject())); } void TCanvasGraphicRotatingInteractor::ContinueInteraction () { PVMARK("TCanvasGraphicRotatingInteractor::ContinueInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicRotatingInteractor::ContinueInteraction\n"); #endif TGPoint endPoint = GetLastPoint (); TGPoint newVector = endPoint - fCenter; GDegrees oldAngle = fLastVector.VectorAngle(); GDegrees newAngle = newVector.VectorAngle(); GDegrees angle = newAngle - oldAngle; if ( angle != 0. ) { fCommand->SetAngle (angle); try { DoIncrement (*(fBinding.GetObject())); } catch(TCompoundDocumentException& theException) { if(theException.GetDescriptionIndex() == TCompoundDocumentException::kExpectedDoBegin) { fCommand = new TRotateCanvasGraphicCmd (fCenter); fCommand->SetAngle(angle); MCanvasSelection *selection = ::CopyPointer(fSelection); fBinding = new TToolCommandBindingTo (fCommand, selection); DoBegin(*(fBinding.GetObject())); } else { // Not our exception, let it fly! throw; } } fLastVector = newVector; } } void TCanvasGraphicRotatingInteractor::EndInteraction () { PVMARK("TCanvasGraphicRotatingInteractor::EndInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicRotatingInteractor::EndInteraction\n"); #endif TGPoint endPoint = GetLastPoint (); TGPoint newVector = endPoint - fCenter; GDegrees oldAngle = fLastVector.VectorAngle(); GDegrees newAngle = newVector.VectorAngle(); GDegrees angle = newAngle - oldAngle; if ( angle != 0. ) { fCommand->SetAngle (angle); try { DoIncrement (*(fBinding.GetObject())); } catch(TCompoundDocumentException& theException) { if(theException.GetDescriptionIndex() == TCompoundDocumentException::kExpectedDoBegin) { fCommand = new TRotateCanvasGraphicCmd (fCenter); fCommand->SetAngle(angle); MCanvasSelection *selection = ::CopyPointer(fSelection); fBinding = new TToolCommandBindingTo (fCommand, selection); DoBegin(*(fBinding.GetObject())); } else { // Not our exception, let it fly! throw; } } fLastVector = newVector; } AdoptAndDoEnd (fBinding.OrphanObject()); fBinding = NIL; } //================================================================================ // class TCanvasGraphicTranslatingInteractor // // description An interactor that moves canvas graphics. // //================================================================================ //======================================== // Constructors and Destructors //======================================== TCanvasGraphicTranslatingInteractor::TCanvasGraphicTranslatingInteractor ( MCanvasSelection* adoptTarget, MToolHandler* handler ) : TCanvasDragInteractor (handler), fBinding (NIL) { PVMARK("TCanvasGraphicTranslatingInteractor::TCanvasGraphicTranslatingInteractor"); #ifdef DEBUG ::qprintf ("TCanvasGraphicTranslatingInteractor::TCanvasGraphicTranslatingInteractor\n"); #endif fCommand = new TTranslateCanvasGraphicCmd (); fSelection = ::CopyPointer(adoptTarget); fBinding = new TToolCommandBindingTo (fCommand, adoptTarget); } TCanvasGraphicTranslatingInteractor::~TCanvasGraphicTranslatingInteractor () { PVMARK("TCanvasGraphicTranslatingInteractor::~TCanvasGraphicTranslatingInteractor"); #ifdef DEBUG ::qprintf ("TCanvasGraphicTranslatingInteractor::~TCanvasGraphicTranslatingInteractor\n"); #endif } //======================================== // Metadata //======================================== VersionDefinitionsMacro (TCanvasGraphicTranslatingInteractor,0); //======================================== // TCanvasInteractor Overrides //======================================== void TCanvasGraphicTranslatingInteractor::StartInteraction () { PVMARK("TCanvasGraphicTranslatingInteractor::StartInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicTranslatingInteractor::StartInteraction\n"); #endif // hack for testing bool localDebug = false; if ( localDebug ) return; DoBegin (*(fBinding.GetObject())); } void TCanvasGraphicTranslatingInteractor::ContinueInteraction () { PVMARK("TCanvasGraphicTranslatingInteractor::ContinueInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicTranslatingInteractor::ContinueInteraction\n"); #endif // hack for testing bool localDebug = false; if ( localDebug ) return; 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 TCanvasGraphicTranslatingInteractor::EndInteraction () { PVMARK("TCanvasGraphicTranslatingInteractor::EndInteraction"); #ifdef DEBUG ::qprintf ("TCanvasGraphicTranslatingInteractor::EndInteraction\n"); #endif // hack for testing bool localDebug = false; if ( localDebug ) return; 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; } // ******************************************************************************** // class TSRTFeedbacker // // description An SRT feedbacker is a canvas graphic that depicts "hot" areas // for launching scale, rotate and translate operations on the // graphics in a canvas selection. // // An SRT feedbacker provides helper methods for creating the // scaling, rotating and translating interactors. Subclasses // determine the feedbacker visual appearance and determine which // areas reult in producing which interactors. It is generally a // good idea to make these areas visually obvious in the appearance. // // ******************************************************************************** //======================================== // Constructors and destructors //======================================== TSRTFeedbacker::TSRTFeedbacker () : MCanvasGraphic () { PVMARK("TSRTFeedbacker::TSRTFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::TSRTFeedbacker\n"); #endif fBounds = TGRect(TGPoint( 0.0, 0.0), TGPoint( 10.0, 10.0) ); AdoptBundle (new TGrafBundle(new TColorPaint(TRGBColor(0.,0.,0.)),TAttributeState::kFrame)); } TSRTFeedbacker::TSRTFeedbacker (const MCanvasGraphic& forThis) : fBounds (forThis.HandleGetBounds()), MCanvasGraphic () { PVMARK("TSRTFeedbacker::TSRTFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::TSRTFeedbacker\n"); #endif const TGrafMatrix* otherTform = forThis.GetTransform (); if ( otherTform ) MCanvasGraphic::TransformBy (*otherTform); fBounds.SetSize (fBounds.GetSize()*1.2); AdoptBundle (new TGrafBundle(new TColorPaint(TRGBColor(0.,0.,0.)),TAttributeState::kFrame)); } TSRTFeedbacker::TSRTFeedbacker (const TSRTFeedbacker& source) : fBounds (source.fBounds), MCanvasGraphic (source) { PVMARK("TSRTFeedbacker::TSRTFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::TSRTFeedbacker\n"); #endif //fBounds.Inset (TGPoint(5.,5.)); } TSRTFeedbacker::~TSRTFeedbacker () { PVMARK("TSRTFeedbacker::~TSRTFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::~TSRTFeedbacker\n"); #endif } //======================================== // MCollectible overrides //======================================== MCollectibleDefinitionsMacro (TSRTFeedbacker,kOriginalVersion); DynamicCastDefinitionsMacroOne (TSRTFeedbacker, MCanvasGraphic); // // Assignment // TSRTFeedbacker& TSRTFeedbacker::operator= (const TSRTFeedbacker& source) { PVMARK("TSRTFeedbacker::operator="); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::operator=\n"); #endif if ( this != &source ) { MCanvasGraphic::operator= (source); fBounds = source.fBounds; } return *this; } // // Streaming // TStream& TSRTFeedbacker::operator>>= (TStream& toWhere) const { PVMARK("TSRTFeedbacker::operator>>="); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::operator>>=\n"); #endif WriteVersion (toWhere); MCanvasGraphic::operator>>= (toWhere); fBounds >>= toWhere; return toWhere; } TStream& TSRTFeedbacker::operator<<= (TStream& fromWhere) { PVMARK("TSRTFeedbacker::operator<<="); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::operator<<=\n"); #endif VersionInfo version = ReadVersion (fromWhere); if ( version != kOriginalVersion ) throw TGlobalExceptionKludge (kStreamBadVersion, 0); MCanvasGraphic::operator<<= (fromWhere); fBounds <<= fromWhere; return fromWhere; } //======================================== // MCanvasGraphic Overrides //======================================== TGRect TSRTFeedbacker::HandleGetBounds () const { PVMARK("TSRTFeedbacker::HandleGetBounds"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::HandleGetBounds\n"); #endif return fBounds; } bool TSRTFeedbacker::HandleHit (const TGPoint& p) const { PVMARK("TSRTFeedbacker::HandleHit"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::HandleHit\n"); #endif return fBounds.Contains (p); } //======================================== // TSRTFeedbacker Helper Methods //======================================== TCanvasInteractor* TSRTFeedbacker::CreateScalingInteractor (MCanvasSelection* adoptTarget, MToolHandler* handler, const TGPoint& center) const { PVMARK("TSRTFeedbacker::CreateScalingInteractor"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::CreateScalingInteractor\n"); #endif return new TCanvasGraphicScalingInteractor (adoptTarget, handler, center, *GetTransform()); } TCanvasInteractor* TSRTFeedbacker::CreateRotatingInteractor (MCanvasSelection* adoptTarget, MToolHandler* handler, const TGPoint& center) const { PVMARK("TSRTFeedbacker::CreateRotatingInteractor"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::CreateRotatingInteractor\n"); #endif TGPoint transformedCenter (center); const TGrafMatrix* tform = GetTransform (); if ( tform != NIL ) transformedCenter = tform->TransformPoint (center); return new TCanvasGraphicRotatingInteractor (adoptTarget, handler, transformedCenter); } TCanvasInteractor* TSRTFeedbacker::CreateTranslatingInteractor (MCanvasSelection* adoptTarget, MToolHandler* handler) const { PVMARK("TSRTFeedbacker::CreateTranslatingInteractor"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::CreateTranslatingInteractor\n"); #endif return new TCanvasGraphicTranslatingInteractor (adoptTarget, handler); } void TSRTFeedbacker::HandleDraw (TGrafPort& port) const { PVMARK("TSRTFeedbacker::HandleDraw"); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::HandleDraw\n"); #endif // Override this method to call the desired interactors based on the hit location TGRect bounds = HandleGetBounds (); port.Draw (bounds); } void TSRTFeedbacker::SetGraphic (const MCanvasGraphic* forThis) { PVMARK("TSRTFeedbacker::SetGraphic"); #ifdef DEBUG ::qprintf ("TSRTFeedbacker::SetGraphic\n"); #endif fBounds = forThis->HandleGetBounds(); const TGrafMatrix* otherTform = forThis->GetTransform (); if ( otherTform ) MCanvasGraphic::TransformTo (*otherTform); fBounds.SetSize (fBounds.GetSize()*1.2); AdoptBundle (new TGrafBundle(new TColorPaint(TRGBColor(0.,0.,0.)),TAttributeState::kFrame)); } void TSRTFeedbacker::HandleSetBounds (const TGRect& size) { #ifdef DEBUG ::qprintf ("TSRTFeedbacker::HandleSetBounds\n"); #endif fBounds = size; } // ******************************************************************************** // class TSRTBoxFeedbacker // // description This is a specific SRT feedbacker that depicts "hot" areas // for launching scale, rotate and translate operations on the // graphics in a canvas selection. // // ******************************************************************************** //======================================== // Constructors and destructors //======================================== TSRTBoxFeedbacker::TSRTBoxFeedbacker () : TSRTFeedbacker () { PVMARK("TSRTBoxFeedbacker::TSRTBoxFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::TSRTBoxFeedbacker\n"); #endif } TSRTBoxFeedbacker::TSRTBoxFeedbacker (const MCanvasGraphic& forThis) : TSRTFeedbacker (forThis) { PVMARK("TSRTBoxFeedbacker::TSRTBoxFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::TSRTBoxFeedbacker\n"); #endif } TSRTBoxFeedbacker::TSRTBoxFeedbacker (const TSRTBoxFeedbacker& source) : TSRTFeedbacker (source) { PVMARK("TSRTBoxFeedbacker::TSRTBoxFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::TSRTBoxFeedbacker\n"); #endif } TSRTBoxFeedbacker::~TSRTBoxFeedbacker () { PVMARK("TSRTBoxFeedbacker::~TSRTBoxFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::~TSRTBoxFeedbacker\n"); #endif } //======================================== // MCollectible overrides //======================================== MCollectibleDefinitionsMacro (TSRTBoxFeedbacker,kOriginalVersion); DynamicCastDefinitionsMacroOne (TSRTBoxFeedbacker, TSRTFeedbacker); // // Assignment // TSRTBoxFeedbacker& TSRTBoxFeedbacker::operator= (const TSRTBoxFeedbacker& source) { PVMARK("TSRTBoxFeedbacker::operator="); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::operator=\n"); #endif if ( this != &source ) { TSRTFeedbacker::operator= (source); } return *this; } // // Streaming // TStream& TSRTBoxFeedbacker::operator>>= (TStream& toWhere) const { PVMARK("TSRTBoxFeedbacker::operator>>="); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::operator>>=\n"); #endif WriteVersion (toWhere); TSRTFeedbacker::operator>>= (toWhere); return toWhere; } TStream& TSRTBoxFeedbacker::operator<<= (TStream& fromWhere) { PVMARK("TSRTBoxFeedbacker::operator<<="); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::operator<<=\n"); #endif VersionInfo version = ReadVersion (fromWhere); if ( version != kOriginalVersion ) throw TGlobalExceptionKludge (kStreamBadVersion, 0); TSRTFeedbacker::operator<<= (fromWhere); return fromWhere; } //======================================== // MCanvasGraphic Overrides //======================================== void TSRTBoxFeedbacker::HandleDraw (TGrafPort& port) const { PVMARK("TSRTBoxFeedbacker::HandleDraw"); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::HandleDraw\n"); #endif TGRect bounds = HandleGetBounds (); // qprintf(" Feedbacker: "); // bounds.PrintDebugInfo(); port.Draw (bounds); // We set the inset equal to at least 5x5 in case the graphic is too skinny to be visible GCoordinate hInset = Max(bounds.GetWidth() / 6.0, 5.0); // was *.15 but /6 is more accurate GCoordinate vInset = Max(bounds.GetHeight() / 6.0, 5.0); bounds.Inset (TGPoint(hInset,0)); port.Draw (bounds); bounds.Inset (TGPoint(-hInset,vInset)); port.Draw (bounds); } TCanvasInteractor* TSRTBoxFeedbacker::HandleCreateInteractor (MCanvasSelection* adoptTarget, MToolHandler* handler, const TGPoint& point) const { PVMARK("TSRTBoxFeedbacker::HandleCreateInteractor"); #ifdef DEBUG ::qprintf ("TSRTBoxFeedbacker::HandleCreateInteractor\n"); #endif TGRect bounds = HandleGetBounds (); TGPoint center = bounds.GetCenter(); GCoordinate hInset = Max(bounds.GetWidth() / 6.0, 5.0); GCoordinate vInset = Max(bounds.GetHeight() / 6.0, 5.0); // Translating case (center) bounds.Inset (TGPoint(hInset,vInset)); if ( bounds.Contains(point) ) return CreateTranslatingInteractor (adoptTarget, handler); // Rotating cases (allow overlap with center which has already been ruled out) bounds.Inset (TGPoint(-hInset,0)); if ( bounds.Contains(point) ) return CreateRotatingInteractor (adoptTarget, handler, center); bounds.Inset (TGPoint(hInset,-vInset)); if ( bounds.Contains(point) ) return CreateRotatingInteractor (adoptTarget, handler, center); // Scaling case - all remaining points (the four corners) bounds.Inset (TGPoint(-hInset,0)); if ( bounds.Contains(point) ) { // Now, depending on which corner the point is in, we need to return a scale center point equivalent // to the opposite corner. This pin points our scale origin. TGRect inner = bounds; inner.Inset (TGPoint(hInset,vInset)); TGRect topLeft = TGRect(bounds.GetTopLeft(), inner.GetTopLeft()); TGRect topRight = TGRect(TGPoint(inner.GetTopRight().fX, bounds.GetTopRight().fY), TGPoint(bounds.GetTopRight().fX, inner.GetTopRight().fY)); TGRect bottomLeft = TGRect(TGPoint(bounds.GetBottomLeft().fX, inner.GetBottomLeft().fY), TGPoint(inner.GetBottomLeft().fX, bounds.GetBottomLeft().fY)); TGRect bottomRight = TGRect(inner.GetBottomRight(), bounds.GetBottomRight()); if (topLeft.Contains(point)) center = inner.GetBottomRight(); if (topRight.Contains(point)) center = inner.GetBottomLeft(); if (bottomLeft.Contains(point)) center = inner.GetTopRight(); if (bottomRight.Contains(point)) center = inner.GetTopLeft(); return CreateScalingInteractor (adoptTarget, handler, center); } delete adoptTarget; return NIL; } // ******************************************************************************** // class TSRTHandleFeedbacker // // description This is a specific SRT feedbacker that depicts "hot" areas // for translate and rotate or scale operations on the // graphics in a canvas selection. // // ******************************************************************************** //======================================== // Constructors and destructors //======================================== TSRTHandleFeedbacker::TSRTHandleFeedbacker () : TSRTFeedbacker () { PVMARK("TSRTHandleFeedbacker::TSRTHandleFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::TSRTHandleFeedbacker\n"); #endif } TSRTHandleFeedbacker::TSRTHandleFeedbacker (const MCanvasGraphic& forThis) : TSRTFeedbacker (forThis) { PVMARK("TSRTHandleFeedbacker::TSRTHandleFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::TSRTHandleFeedbacker\n"); #endif HandleSetBounds(forThis.HandleGetBounds()); // Sets fBounds to exact size of MCanvasGraphic } TSRTHandleFeedbacker::TSRTHandleFeedbacker (const TSRTHandleFeedbacker& source) : TSRTFeedbacker (source) { PVMARK("TSRTHandleFeedbacker::TSRTHandleFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::TSRTHandleFeedbacker\n"); #endif } TSRTHandleFeedbacker::~TSRTHandleFeedbacker () { PVMARK("TSRTHandleFeedbacker::~TSRTHandleFeedbacker"); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::~TSRTHandleFeedbacker\n"); #endif } //======================================== // MCollectible overrides //======================================== MCollectibleDefinitionsMacro (TSRTHandleFeedbacker,kOriginalVersion); DynamicCastDefinitionsMacroOne (TSRTHandleFeedbacker, TSRTFeedbacker); // // Assignment // TSRTHandleFeedbacker& TSRTHandleFeedbacker::operator= (const TSRTHandleFeedbacker& source) { PVMARK("TSRTHandleFeedbacker::operator="); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::operator=\n"); #endif if ( this != &source ) { TSRTFeedbacker::operator= (source); } return *this; } // // Streaming // TStream& TSRTHandleFeedbacker::operator>>= (TStream& toWhere) const { PVMARK("TSRTHandleFeedbacker::operator>>="); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::operator>>=\n"); #endif WriteVersion (toWhere); TSRTFeedbacker::operator>>= (toWhere); return toWhere; } TStream& TSRTHandleFeedbacker::operator<<= (TStream& fromWhere) { PVMARK("TSRTHandleFeedbacker::operator<<="); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::operator<<=\n"); #endif VersionInfo version = ReadVersion (fromWhere); if ( version != kOriginalVersion ) throw TGlobalExceptionKludge (kStreamBadVersion, 0); TSRTFeedbacker::operator<<= (fromWhere); return fromWhere; } //======================================== // MCanvasGraphic Overrides //======================================== // Look Ma, no transforms! //void //TSRTHandleFeedbacker::Draw (TGrafPort& port) const //{ // #ifdef DEBUG // ::qprintf ("TSRTHandleFeedbacker::Draw\n"); // #endif // // HandleDraw(port); //} // // //TCanvasInteractor* //TSRTHandleFeedbacker::CreateInteractor (MCanvasSelection* adoptTarget, MToolHandler* toolHandler, const TGPoint& point) const //{ // #ifdef DEBUG // ::qprintf("TSRTHandleFeedbacker::CreateInteractor\n"); // #endif // // return HandleCreateInteractor(adoptTarget, toolHandler, point); //} void TSRTHandleFeedbacker::HandleDraw (TGrafPort& port) const { PVMARK("TSRTHandleFeedbacker::HandleDraw"); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::HandleDraw\n"); #endif // // We're not doing this here, but... // In order to draw this in such a way so as to not cause the squares in the corners of the feedbacker // to be transformed, we need to not override HandleDraw or HandleCreateInteractor because they are called // once we're in transformed space. Instead, override Draw and CreateInteractor which are called before this. // For instance, Override draw, use the transform, get bounds in untransformed space, take each of the squares // and run them through the object's transform (apply the transform) to get their transformed locations, then // draw a square around them as desired. But then you have to figure out how to keep the feedbacker graphic // synched up with the canvas graphic being manipulated. This is best left until after beta because we need to // extract transform dependencies in general. // TGPoint rectSize(6.0, 6.0); TFillAndHairlineFrameBundle bundle(TRGBColor(0.8333,0.8333,0.8333), TRGBColor(0.,0.,0.)); // Draw black squares centered on the corners of the bounds TGRect bounds = HandleGetBounds(); GCoordinate hInset = 4.0; GCoordinate vInset = 4.0; bounds.Inset (TGPoint(hInset,vInset)); // Top left TGRect topLeft(bounds.GetTopLeft(),bounds.GetTopLeft()); topLeft.SetSize(rectSize); port.Draw(topLeft,bundle); // Top Right TGRect topRight(bounds.GetTopRight(),bounds.GetTopRight()); topRight.SetSize(rectSize); port.Draw(topRight,bundle); // Bottom Left TGRect bottomLeft(bounds.GetBottomLeft(),bounds.GetBottomLeft()); bottomLeft.SetSize(rectSize); port.Draw(bottomLeft,bundle); // Bottom Right TGRect bottomRight(bounds.GetBottomRight(),bounds.GetBottomRight()); bottomRight.SetSize(rectSize); port.Draw(bottomRight,bundle); } TCanvasInteractor* TSRTHandleFeedbacker::HandleCreateInteractor (MCanvasSelection* adoptTarget, MToolHandler* handler, const TGPoint& point) const { PVMARK("TSRTHandleFeedbacker::HandleCreateInteractor"); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::HandleCreateInteractor\n"); #endif TGRect bounds = HandleGetBounds (); TGPoint center = bounds.GetCenter(); // Scaling case - scale if we hit any of the corners TGRect hitRect(point,point); hitRect.SetSize(TGPoint(6.0,6.0)); // Top left TGRect topLeft(bounds.GetTopLeft(),bounds.GetTopLeft()); topLeft.SetSize(TGPoint(6.0,6.0)); if ( topLeft.Intersects(hitRect) ) return CreateScalingInteractor (adoptTarget, handler, bounds.GetBottomRight()); // Top Right TGRect topRight(bounds.GetTopRight(),bounds.GetTopRight()); topRight.SetSize(TGPoint(6.0,6.0)); if ( topRight.Intersects(hitRect) ) return CreateScalingInteractor (adoptTarget, handler, bounds.GetBottomLeft()); // Bottom Left TGRect bottomLeft(bounds.GetBottomLeft(),bounds.GetBottomLeft()); bottomLeft.SetSize(TGPoint(6.0,6.0)); if ( bottomLeft.Intersects(hitRect) ) return CreateScalingInteractor (adoptTarget, handler, bounds.GetTopRight()); // Bottom Right TGRect bottomRight(bounds.GetBottomRight(),bounds.GetBottomRight()); bottomRight.SetSize(TGPoint(6.0,6.0)); if ( bottomRight.Intersects(hitRect) ) return CreateScalingInteractor (adoptTarget, handler, bounds.GetTopLeft()); // Translating case (center) if ( bounds.Contains(point) ) return CreateTranslatingInteractor (adoptTarget, handler); delete adoptTarget; return NIL; } void TSRTHandleFeedbacker::SetGraphic (const MCanvasGraphic* forThis) { PVMARK("TSRTHandleFeedbacker::SetGraphic"); #ifdef DEBUG ::qprintf ("TSRTHandleFeedbacker::SetGraphic\n"); #endif const TGrafMatrix* otherTform = forThis->GetTransform (); if ( otherTform ) MCanvasGraphic::TransformTo (*otherTform); HandleSetBounds(forThis->HandleGetBounds()); }