cntrtool.cpp

Go to the documentation of this file.
00001 // $Id: cntrtool.cpp 1386 2006-06-28 17:49:55Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // Implementation of the blend tool
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "oilfiles.h"
00105 #include "csrstack.h"
00106 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "markn.h"
00108 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "nodepath.h"
00110 #include "progress.h"
00111 #include "nodeblnd.h"
00112 #include "nodebldr.h"
00113 //#include "simon.h"
00114 #include "blobs.h"
00115 //#include "blndres.h"
00116 #include "objchge.h"
00117 //#include "resource.h"
00118 //#include "barsdlgs.h"
00119 //#include "will.h"
00120 #include "filltool.h"
00121 #include "bubbleid.h"
00122 //#include "becomea.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "attrmap.h"
00124 #include "ndbldpth.h"
00125 #include "pathedit.h"
00126 #include "keypress.h"
00127 #include "vkextra.h"
00128 #include "ezmodule.h"
00129 #include "opbevel.h"
00130 //#include "will2.h"
00131 //#include "biasres.h"
00132 #include "opcntr.h"
00133 #include "cntrtool.h"
00134 #include "ppbevel.h"
00135 #include "nodetxts.h"   // for TextStory.
00136 //#include "camvw.h"
00137 #include "layer.h"
00138 #include "ophist.h"
00139 // the resources headers
00140 //#include "cntres.h"
00141 #include "gclips.h"
00142 
00143 // for bevels & shadows
00144 #include "nodecont.h"
00145 #include "nodecntr.h"
00146 #include "ncntrcnt.h"
00147 //#include "rikdlg.h"
00148 #include "nodemold.h"
00149 #include "ndclpcnt.h"
00150 #include "biasdlg.h"
00151 #include "helpuser.h"
00152 //#include "xshelpid.h"
00153 //#include "helppath.h"
00154 #include "dragmgr.h"
00155 #include "lineattr.h"
00156 #include "effects_stack.h"
00157 #include "blndtool.h"
00158 #include "nbevcont.h"
00159 
00160 DECLARE_SOURCE( "$Revision: 1386 $" );
00161                                                 
00162 CC_IMPLEMENT_MEMDUMP(ContourTool,Tool_v1)
00163 CC_IMPLEMENT_DYNCREATE(ContourInfoBarOp,InformationBarOp)
00164 CC_IMPLEMENT_DYNCREATE(OpContourNodes,SelOperation)
00165 
00166 // Must come after the last CC_IMPLEMENT.. macro
00167 #define new CAM_DEBUG_NEW     
00168 
00169 // These are still char* while we wait for resource technology to be developed for modules
00170 TCHAR* ContourTool::FamilyName  = _T("Contour Tools");
00171 TCHAR* ContourTool::ToolName    = _T("Contour Tool");
00172 TCHAR* ContourTool::Purpose     = _T("Contour manipulation");
00173 TCHAR* ContourTool::Author      = _T("David Mc");
00174 
00175 // Init those other useful static vars
00176 ContourInfoBarOp*   ContourTool::pContourInfoBarOp          = NULL;
00177 BlendToolRef*   ContourTool::pRefStart              = NULL;
00178 BlendToolRef*   ContourTool::pRefEnd                = NULL;
00179 Cursor*         ContourTool::pcNormalCursor         = NULL;
00180 Cursor*         ContourTool::pcOverBlob             = NULL;
00181 Cursor*         ContourTool::pcCurrentCursor            = NULL;
00182 INT32           ContourTool::CurrentCursorID            = 0;
00183 UINT32          ContourTool::StatusID                   = _R(IDS_CONTOURDRAGHELP);
00184 
00185 OpContourNodes      *ContourTool::m_pOpContourNodes = NULL;
00186 
00187 // maximum & minimum values for the contour slider
00188 #define CONTOUR_DEPTH_MIN 10
00189 #define CONTOUR_DEPTH_MAX 250000
00190 
00191 //#define Swap(a,b)       { (a)^=(b), (b)^=(a), (a)^=(b); }
00192 
00193 #define SWAP(type,a,b) { type x=a; a=b; b=x; }
00194 
00196 // Flatness settings
00197 const INT32 ContourToolFlatness=2048;
00198 
00200 // Profile for the logarithmic width slider
00201 CProfileBiasGain SliderProfile((AFp)0.7, (AFp)0.0);
00202 
00203 
00204 /********************************************************************************************
00205 
00206 >   ContourTool::ContourTool()
00207 
00208     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00209     Created:    3/10/94
00210     Purpose:    Default Constructor.
00211                 Other initialisation is done in ContourTool::Init which is called by the Tool Manager
00212     SeeAlso:    ContourTool::Init
00213 
00214 ********************************************************************************************/
00215 
00216 ContourTool::ContourTool()
00217 {
00218     pcCurrentCursor = NULL;
00219     m_bDisableBlobRenderingFlag = FALSE;
00220 }
00221 
00222 /********************************************************************************************
00223 
00224 >   ContourTool::~ContourTool()
00225 
00226     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00227     Created:    3/10/94
00228     Purpose:    Destructor.
00229 
00230 ********************************************************************************************/
00231 
00232 ContourTool::~ContourTool()
00233 {
00234     if (pRefStart != NULL)
00235     {
00236         delete pRefStart;
00237         pRefStart = NULL;
00238     }
00239 
00240     if (pRefEnd != NULL)
00241     {
00242         delete pRefEnd;
00243         pRefEnd = NULL;
00244     }
00245 
00246     if (m_pOpContourNodes)
00247     {
00248         delete m_pOpContourNodes;
00249         m_pOpContourNodes = NULL;
00250     }
00251 }
00252 
00253 
00254 /********************************************************************************************
00255 
00256 >   BOOL ContourTool::Init( INT32 Pass )
00257 
00258     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00259     Created:    3/10/94
00260     Returns:    FALSE if it does not want to be created, TRUE otherwise
00261     Purpose:    Used to check if the Tool was properly constructed
00262     SeeAlso:    ContourTool::ContourTool
00263 
00264 ********************************************************************************************/
00265 
00266 BOOL ContourTool::Init()
00267 {
00268     // Declare all your ops here and only succeed if all declarations succeed
00269     BOOL ok =   OpContourNodes::Declare() &&
00270         OpChangeContourToInner::Declare() &&
00271         OpChangeContourToOuter::Declare() &&
00272         OpRemoveContour::Declare() &&
00273         OpChangeContourSteps::Declare() &&
00274         OpChangeContourColourType::Declare() &&
00275         OpChangeContourAttributeProfile::Declare() &&
00276         OpChangeContourObjectProfile::Declare() &&
00277         OpChangeContourStepDistance::Declare() &&
00278         OpToggleContourInsetPath::Declare();
00279     
00280     if (!ok) return FALSE;
00281 
00282     m_pOpContourNodes = new OpContourNodes;
00283 
00284     if (!m_pOpContourNodes)
00285         return FALSE;
00286 
00287     // We need two BlendToolRef objects
00288     ContourTool::pRefStart = new BlendToolRef;
00289     ContourTool::pRefEnd   = new BlendToolRef;
00290 
00291     ok = (ContourTool::pRefStart != NULL && ContourTool::pRefEnd != NULL);
00292 
00293     // This section reads in the infobar definition and creates an instance of
00294     // ContourInfoBarOp.  Also pContourInfoBarOp, the ptr to the tool's infobar, is set up
00295     // after the infobar is successfully read and created.
00296     if (ok)
00297     {
00298 #if 0       
00299         CCResTextFile       file;               // Resource File
00300         ContourInfoBarOpCreate BarCreate;           // Object that creates ContourInfoBarOp objects
00301 
00302 //              ok = file.open(_R(IDM_BLEND_BAR), _R(IDT_INFO_BAR_RES));        // Open resource
00303                 ok = file.open( _R(IDM_CONTOUR_BAR), _R(IDT_INFO_BAR_RES) );
00304         if (ok) ok = DialogBarOp::ReadBarsFromFile(file,BarCreate); // Read and create info bar
00305         if (ok) file.close();                                       // Close resource
00306 
00307         ENSURE(ok,"Unable to load blendbar.ini from resource\n"); 
00308 
00309         if (ok)
00310         {
00311             // Info bar now exists.  Now get a pointer to it
00312             String_32 str = String_32(_R(IDS_CONTOURTOOL_INFOBARNAME));
00313             DialogBarOp* pDialogBarOp = DialogBarOp::FindDialogBarOp(str);
00314 
00315                     ok = (pDialogBarOp != NULL);
00316             if (ok) ok = pDialogBarOp->IsKindOf(CC_RUNTIME_CLASS(ContourInfoBarOp));
00317             if (ok) pContourInfoBarOp = (ContourInfoBarOp*)pDialogBarOp;
00318 
00319             ENSURE(ok,"Error finding the blend tool info bar");
00320         }
00321 #endif
00322         pContourInfoBarOp = new ContourInfoBarOp();
00323         ok = (pContourInfoBarOp != NULL);
00324 
00325     }
00326 
00327     return (ok);
00328 }
00329 
00330 
00331 /********************************************************************************************
00332 
00333 >   void ContourTool::Describe(void *InfoPtr)
00334 
00335     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00336     Created:    3/10/94
00337     Inputs:     InfoPtr -   A pointer to a tool info block. It is passed cast to void* as
00338                             the version of the tool is unknown at this point. Later versions 
00339                             of the Tool class may have more items in this block, that this 
00340                             tool will not use
00341     Outputs:    InfoPtr -   The structure pointed to by InfoPtr will have had all the info
00342                             that this version of the Tool knows about
00343     Purpose:    Allows the tool manager to extract information about the tool
00344 
00345 ********************************************************************************************/
00346 
00347 void ContourTool::Describe(void *InfoPtr)
00348 {
00349     // Cast structure into the latest one we understand.
00350     ToolInfo_v1 *Info = (ToolInfo_v1 *) InfoPtr;
00351 
00352     Info->InfoVersion = 1;
00353     
00354     Info->InterfaceVersion = GetToolInterfaceVersion();  // You should always have this line.
00355         
00356     // These are all arbitrary at present.
00357     Info->Version = 1;
00358     Info->ID      = GetID();
00359     Info->TextID  = _R(IDS_CONTOUR_TOOL);
00360 
00361     Info->Family  = FamilyName;
00362     Info->Name    = ToolName;
00363     Info->Purpose = Purpose;
00364     Info->Author  = Author;
00365 
00366     Info->BubbleID = _R(IDBBL_CONTOUR_TOOLBOX);
00367 }
00368 
00369 /********************************************************************************************
00370 
00371 >   virtual void ContourTool::SelectChange(BOOL isSelected)
00372 
00373     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00374     Created:    3/10/94
00375     Inputs:     isSelected  - TRUE  = tool has been selected
00376                             - FALSE = tool has been deselected
00377     Outputs:    -
00378     Returns:    -
00379     Purpose:    Starts up and closes down the blend tool
00380     Errors:     Debug warning if creating the cursor fails.
00381     SeeAlso:    -
00382 
00383 ********************************************************************************************/
00384 
00385 void ContourTool::SelectChange(BOOL isSelected)
00386 {
00387 // Stub out this function if the tool isn't wanted
00388 #ifndef NO_ADVANCED_TOOLS
00389     if (isSelected)
00390     {
00391         if (!CreateCursors()) return;
00392         CurrentCursorID = CursorStack::GPush(pcNormalCursor, FALSE);        // Push cursor but don't display now
00393         pcCurrentCursor = pcNormalCursor;
00394 
00395         // Create and display the tool's info bar
00396         pContourInfoBarOp->Create();
00397 
00398         // Which blobs do I want displayed
00399         BlobManager* BlobMgr = GetApplication()->GetBlobManager();
00400         if (BlobMgr != NULL)
00401         {
00402             // Decide which blobs we will display
00403             BlobStyle MyBlobs;
00404             MyBlobs.Object = FALSE;
00405             MyBlobs.Tiny = TRUE;
00406             // Tell the blob manager
00407             BlobMgr->ToolInterest(MyBlobs);
00408         }
00409 
00410         Document* pDoc = Document::GetCurrent();
00411         SetupToolBlobs();
00412 
00413         if (pDoc != NULL)
00414             RenderToolBlobs(pDoc->GetSelectedSpread(),NULL);
00415 
00416         pContourInfoBarOp->m_pTool = this;
00417     }
00418     else
00419     {
00420         // Deselection - destroy the tool's cursors, if they exist.
00421         if (pcCurrentCursor != NULL)
00422         {
00423             CursorStack::GPop(CurrentCursorID);
00424             pcCurrentCursor = NULL;
00425             CurrentCursorID = 0;
00426         }
00427         DestroyCursors();
00428 
00429         pContourInfoBarOp->CloseProfileDialog (pContourInfoBarOp->m_BiasGainObjectGadget);
00430         pContourInfoBarOp->CloseProfileDialog (pContourInfoBarOp->m_BiasGainAttrGadget);
00431 
00432         // Remove the info bar from view by deleting the actual underlying window
00433         pContourInfoBarOp->Delete();
00434 
00435         // ensure any tool object blobs are removed.
00436         BlobManager* BlobMgr = GetApplication()->GetBlobManager();
00437         if (BlobMgr != NULL)
00438         {
00439             BlobStyle bsRemoves;
00440             bsRemoves.ToolObject = TRUE;
00441             BlobMgr->RemoveInterest(bsRemoves);
00442         }
00443 
00444         Document* pDoc = Document::GetCurrent();
00445         if (pDoc != NULL)
00446             RenderToolBlobs(pDoc->GetSelectedSpread(),NULL);
00447     }
00448 #endif  // NO_ADVANCED_TOOLS
00449 }
00450 
00451 /********************************************************************************************
00452 
00453 >   void ContourTool::SetupToolBlobs()
00454 
00455     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00456     Created:    3/10/94
00457     Inputs:     -
00458     Outputs:    -
00459     Returns:    
00460     Purpose:    Sets up the tool blobs for the current selection.
00461 
00462                 Karim 28/07/2000
00463                 Contour tool blobs are laid out like so relative to the selection:
00464 
00465                         2   4   3
00466 
00467                         6   *   7
00468 
00469                         0   5   1
00470 
00471                 with corner blobs positioned 1 pixel out from the bounds rect
00472                 and middle blobs positioned 2 pixels out from the bounds rect.
00473 
00474     SeeAlso:    -
00475 
00476 ********************************************************************************************/
00477 void ContourTool::SetupToolBlobs()
00478 {
00479     // reset the blob positions.
00480     for (INT32 i = 0 ; i < 8; i++)
00481     {
00482         m_BlobPoints[i].x = 0;
00483         m_BlobPoints[i].y = 0;
00484     }
00485 
00486     // give up if we there is no selection or we can't get the info we need.
00487     if (GetApplication()->FindSelection() == NULL)
00488         return;
00489 
00490     if (GetApplication()->FindSelection()->IsEmpty())
00491         return;
00492 
00493     BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
00494     if (pBlobMgr == NULL)
00495         return;
00496 
00497     // figure out the blob offsets, in millipoints.
00498     INT32 BlobGap = 0;
00499     DocView* pDocView = DocView::GetSelected();
00500     if (pDocView != NULL)
00501         BlobGap = pDocView->GetScaledPixelWidth().MakeLong();
00502 
00503     // ok, get the bounds of the selection, including contours.
00504     SelRange Sel(*(GetApplication()->FindSelection()));
00505     DocRect drBounds;
00506     Node* pN = Sel.FindFirst();
00507     while (pN != NULL)
00508     {
00509         if (pN->IsBounded())
00510         {
00511             Node* pParent = pN->FindParent();
00512             while (pParent != NULL && pParent->IS_KIND_OF(NodeContourController))
00513             {
00514                 pN = pParent;
00515                 pParent = pN->FindParent();
00516             }
00517 
00518             drBounds = drBounds.Union( ((NodeRenderableBounded*)pN)->GetBoundingRect() );
00519         }
00520         pN = Sel.FindNext(pN);
00521     }
00522 
00523     // lets set up those blobs!
00524     DocCoord dc;
00525     drBounds.Inflate(BlobGap);
00526     INT32 BlobSize = pBlobMgr->GetBlobSize();
00527 
00528     dc.x = drBounds.lo.x - BlobSize;
00529     dc.y = drBounds.lo.y - BlobSize;
00530     m_BlobPoints[0] = dc;
00531 
00532     dc.x = drBounds.hi.x + BlobSize;
00533     dc.y = drBounds.lo.y - BlobSize;
00534     m_BlobPoints[1] = dc;
00535 
00536     dc.x = drBounds.lo.x - BlobSize;
00537     dc.y = drBounds.hi.y + BlobSize;
00538     m_BlobPoints[2] = dc;
00539 
00540     dc.x = drBounds.hi.x + BlobSize;
00541     dc.y = drBounds.hi.y + BlobSize;
00542     m_BlobPoints[3] = dc;
00543 
00544     dc.x = (drBounds.lo.x + drBounds.hi.x) / 2;
00545     dc.y = drBounds.hi.y + BlobSize + BlobGap;
00546     m_BlobPoints[4] = dc;
00547 
00548     dc.x = (drBounds.lo.x + drBounds.hi.x) / 2;
00549     dc.y = drBounds.lo.y - BlobSize - BlobGap;
00550     m_BlobPoints[5] = dc;
00551 
00552     dc.x = drBounds.lo.x - BlobSize - BlobGap;
00553     dc.y = (drBounds.lo.y + drBounds.hi.y) / 2;
00554     m_BlobPoints[6] = dc;
00555 
00556     dc.x = drBounds.hi.x + BlobSize + BlobGap;
00557     dc.y = (drBounds.lo.y + drBounds.hi.y) / 2;
00558     m_BlobPoints[7] = dc;
00559 }
00560 
00561 
00562 
00563 /********************************************************************************************
00564 
00565 >   BOOL ContourTool::CreateCursors()
00566 
00567     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00568     Created:    3/10/94
00569     Inputs:     -
00570     Outputs:    -
00571     Returns:    TRUE if all the blend tool cursors have been successfully created
00572     Purpose:    Creates all the blend tool cursors
00573     SeeAlso:    -
00574 
00575 ********************************************************************************************/
00576 
00577 BOOL ContourTool::CreateCursors()
00578 {
00579     // This tool has just been selected.  Create the cursors.
00580     pcNormalCursor          = new Cursor(this, _R(IDC_POINTER_CONTOUR));
00581     pcOverBlob              = new Cursor(this, _R(IDC_SELECT_CONTOUR));
00582     
00583     if ( pcNormalCursor         ==NULL || !pcNormalCursor->IsValid() ||
00584         pcOverBlob== NULL || !pcOverBlob->IsValid()
00585        )
00586     {
00587         DestroyCursors();
00588         return FALSE;
00589     }
00590     else
00591         return TRUE;
00592 }
00593 
00594 /********************************************************************************************
00595 
00596 >   BOOL ContourTool::IsPointOverBlob(DocCoord &Point, DocRect * pBlobRect)
00597 
00598     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00599     Created:    3/10/94
00600     Inputs:     A point in document coordinates, and the doc rect variable to
00601                 put the blob rect into
00602     Outputs:    -
00603     Returns:    TRUE if the point is over a blob, false otherwise
00604     Purpose:    Creates all the blend tool cursors
00605     SeeAlso:    -
00606 
00607 ********************************************************************************************/
00608 BOOL ContourTool::IsPointOverBlob(DocCoord &Point, DocRect * pBlobRect)
00609 {
00610     // check to see if I'm over a blob
00611     BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
00612 
00613     INT32 BlobSize = 0;
00614 
00615     // Karim 18/09/2000
00616     // The contour blobs are about twice the size of normal blobs,
00617     // so I'm doubling the value of BlobSize when checking for them.
00618     if (pBlobMgr)
00619         BlobSize = pBlobMgr->GetBlobSize();
00620 //      BlobSize = pBlobMgr->GetBlobSize()/2;
00621 
00622     for (INT32 i = 0; i < 8; i++)
00623     {
00624         DocRect dr( m_BlobPoints[i].x - BlobSize,
00625                     m_BlobPoints[i].y - BlobSize,
00626                     m_BlobPoints[i].x + BlobSize,
00627                     m_BlobPoints[i].y + BlobSize);
00628 
00629         if (dr.ContainsCoord(Point))
00630         {
00631             if (pBlobRect)
00632                 *pBlobRect = dr;
00633             return TRUE;
00634         }
00635     }
00636 
00637     return FALSE;
00638 }
00639 
00640 /********************************************************************************************
00641 
00642 >   void ContourTool::DestroyCursors()
00643 
00644     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00645     Created:    3/10/94
00646     Inputs:     -
00647     Outputs:    -
00648     Returns:    -
00649     Purpose:    Destroys all the blend tool cursors
00650     SeeAlso:    -
00651 
00652 ********************************************************************************************/
00653 
00654 void ContourTool::DestroyCursors()
00655 {
00656     if (pcNormalCursor          != NULL) delete pcNormalCursor;
00657     if (pcOverBlob              != NULL) delete pcOverBlob;
00658 
00659     pcNormalCursor = NULL;
00660     pcOverBlob = NULL;
00661 }
00662 
00663 /********************************************************************************************
00664 
00665 >   BOOL ContourTool::OnKeyPress(KeyPress* pKeyPress)
00666 
00667     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00668     Created:    1/6/99
00669     Inputs:     pKeyPress - pointer to a keypress object
00670     Returns:    TRUE if it handled the keypress, FALSE otherwise
00671     Purpose:    To handle keypress events for the Blend Tool.
00672 
00673 ********************************************************************************************/
00674 
00675 BOOL ContourTool::OnKeyPress(KeyPress* pKeyPress)
00676 {
00677 #ifdef _DEBUG
00678     if (pKeyPress == NULL)
00679         return FALSE;
00680 
00681     if (pKeyPress->IsRepeat())
00682         return FALSE;
00683 
00684     if (pKeyPress->IsRelease())
00685         return FALSE;
00686 
00687     AFp BiasDelta = 0.0;
00688     AFp GainDelta = 0.0;
00689     BOOL Reset = FALSE;
00690     if (*pKeyPress == KeyPress(CAMKEY(Z)))  { BiasDelta = -0.1; TRACEUSER( "Markn", _T("Decrease Bias by 0.1\n"));}
00691     if (*pKeyPress == KeyPress(CAMKEY(X)))  { BiasDelta =  0.1; TRACEUSER( "Markn", _T("Increase Bias by 0.1\n"));}
00692     if (*pKeyPress == KeyPress(CAMKEY(N)))  { GainDelta = -0.1; TRACEUSER( "Markn", _T("Decrease Gain by 0.1\n"));}
00693     if (*pKeyPress == KeyPress(CAMKEY(M)))  { GainDelta =  0.1; TRACEUSER( "Markn", _T("Increase Gain by 0.1\n"));}
00694 
00695     if (*pKeyPress == KeyPress(CAMKEY(R)))  { Reset = TRUE;     TRACEUSER( "Markn", _T("Resetting Bias and Gain\n"));}
00696 
00697     SelRange* pSelRange = GetApplication()->FindSelection();
00698     Node* pNode = pSelRange->FindFirst();
00699     while (pNode)
00700     {
00701         if (IS_A(pNode,NodeBlend))
00702         {
00703             NodeBlend* pNodeBlend = (NodeBlend*)pNode;
00704 
00705             // This alters the Attribute profile, but can easily be modified to alter the Object profile if necessary
00706             CProfileBiasGain* pProfile = pNodeBlend->GetAttrProfile();
00707             if (pProfile)
00708             {
00709                 AFp Bias = pProfile->GetBias() + BiasDelta;
00710                 AFp Gain = pProfile->GetGain() + GainDelta;
00711                 if (Reset)
00712                     Bias = Gain = 0.0;
00713 
00714                 if (Bias < -0.9)    Bias = -0.9;
00715                 if (Bias >  0.9)    Bias =  0.9;
00716                 if (Gain < -0.9)    Gain = -0.9;
00717                 if (Gain >  0.9)    Gain =  0.9;
00718 
00719                 pProfile->SetBiasGain(Bias,Gain);
00720             }
00721         }
00722         // Now find the next selected node
00723         pNode = pSelRange->FindNext(pNode);
00724     }
00725 #endif // _DEBUG
00726 
00727     return FALSE;
00728 }
00729 
00730 /********************************************************************************************
00731 
00732 >   void ContourTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
00733                         Spread* pSpread )
00734 
00735     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00736     Created:    3/10/94
00737     Inputs:     PointerPos  -   The DocCoord of the point where the mouse button was clicked
00738                 Click       -   Describes the type of click that was detected. 
00739                 ClickMods   -   Indicates which buttons caused the click and which modifers were
00740                                 pressed at the same time
00741                 pSpread     -   The spread in which the click happened
00742     Returns:    -
00743     Purpose:    To handle a Mouse Click event for the Blend Tool.
00744     SeeAlso:    Tool::MouseClick; ClickType; ClickModifiers
00745 
00746 ********************************************************************************************/
00747 
00748 void ContourTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
00749                         Spread* pSpread )
00750 {
00751 // Stub out this function if the tool isn't wanted
00752 #ifndef NO_ADVANCED_TOOLS
00753     if (ClickMods.Menu) return;                         // Don't do anything if the user clicked the Menu button
00754 
00755     ERROR3IF_PF(pSpread==NULL,("pSpread is NULL"));
00756 
00757 //  NodeCompound * pCompound = NULL;
00758 
00759     DocRect BlobRect;
00760 
00761     switch (Click)
00762     {
00763         // if a drag was started, we alter or create a contour.
00764         case CLICKTYPE_DRAG:
00765         {
00766             if (m_pOpContourNodes)
00767             {
00768                 m_pOpContourNodes->DoDrag(this, pContourInfoBarOp, PointerPos,
00769                     IsPointOverBlob(PointerPos, &BlobRect), &BlobRect);
00770                 return;
00771             }
00772         }
00773         break;
00774 
00775         // we ignore all other click types, but note that they aren't drag-clicks.
00776         case CLICKTYPE_SINGLE:
00777         {
00778             // check for bevels existing
00779             List BevelList;
00780             BevelTools::BuildListOfSelectedNodes(&BevelList, CC_RUNTIME_CLASS(NodeBevelController));
00781             
00782             if (!BevelList.IsEmpty())
00783             {
00784                 BevelList.DeleteAll();
00785                 
00786                 DocRect BlobRect;
00787 
00788                 // disable the drag
00789                 if (IsPointOverBlob(PointerPos, &BlobRect))
00790                 {
00791                     DocView * pView = DocView::GetCurrent();
00792 
00793                     if (pView)
00794                         pView->EndDrag(NULL);               
00795                     
00796                     InformWarningBevelExistsInSelection();
00797                 }
00798             }
00799 
00800             // call the base class ....
00801 
00802             DragTool::OnClick (PointerPos, Click, ClickMods, pSpread);
00803         }
00804         break;
00805         
00806         default:
00807             // call the base class ....
00808             
00809             DragTool::OnClick (PointerPos, Click, ClickMods, pSpread);
00810         break;
00811     }
00812 #endif  // NO_ADVANCED_TOOLS
00813 }
00814 
00815 /********************************************************************************************
00816 
00817 >   void ContourTool::InformWarningBevelExistsInSelection()
00818 
00819     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00820     Created:    7/4/2000
00821     Purpose:    Brings up the associated warning dialog
00822     SeeAlso:    Tool::MouseClick; ClickType; ClickModifiers
00823 
00824 ********************************************************************************************/
00825 void ContourTool::InformWarningBevelExistsInSelection()
00826 {
00827     String_256 QueryString(_R(IDS_CANTCONTOURBEVEL));
00828 
00829     Error::SetError(0, QueryString, 0);             
00830     // The only way of bringing up a box with a string in it
00831     INT32 DlgResult = InformError(_R(IDS_CANTCONTOURBEVEL),
00832         _R(IDS_OK), _R(IDS_HELP));
00833                 
00834     if (DlgResult == 2)
00835     {
00836         HelpUserTopic(_R(IDS_HELPPATH_Message__Bevel_already_applied));
00837     }
00838 }
00839 
00840 
00841 /********************************************************************************************
00842 
00843 >   void ContourTool::OnMouseMove( DocCoord PointerPos,Spread* pSpread, ClickModifiers ClickMods)
00844 
00845     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00846     Created:    3/10/94
00847     Inputs:     PointerPos  -   The DocCoord of the point where the mouse has moved to
00848                 pSpread     -   The spread in which the move occurred
00849     Returns:    TRUE if it handled the Click, FALSE otherwise
00850     Purpose:    To handle a Mouse Move event for the Blend Tool.
00851     SeeAlso:    Tool::MouseClick; ClickType; ClickModifiers
00852 
00853 ********************************************************************************************/
00854 
00855 void ContourTool::OnMouseMove(DocCoord PointerPos,Spread* pSpread,ClickModifiers ClickMods)
00856 {
00857 // Stub out this function if the tool isn't wanted
00858 #ifndef NO_ADVANCED_TOOLS
00859     ERROR3IF_PF(pSpread==NULL,("pSpread is NULL"));
00860 
00861 //  BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
00862 //  INT32 BlobSize = pBlobMgr->GetBlobSize();
00863 
00864     if (IsPointOverBlob(PointerPos))
00865     {
00866         // change the cursor
00867         if (pcCurrentCursor != pcOverBlob )
00868         {
00869             if (pcCurrentCursor)
00870             {
00871                 CursorStack::GPop(CurrentCursorID);
00872             }
00873             
00874             CurrentCursorID = CursorStack::GPush(pcOverBlob, TRUE);
00875             pcCurrentCursor = pcOverBlob;
00876             DisplayStatusBarHelp(_R(IDS_CONTOUROVERBLOBHELP));
00877         }
00878     }
00879     else
00880     {
00881         // change the cursor back
00882         if (pcCurrentCursor != pcNormalCursor )
00883         {
00884             if (pcCurrentCursor)
00885             {
00886                 CursorStack::GPop(CurrentCursorID);
00887             }
00888             
00889             CurrentCursorID = CursorStack::GPush(pcNormalCursor, TRUE);
00890             pcCurrentCursor = pcNormalCursor;
00891             DisplayStatusBarHelp(_R(IDS_CONTOURDRAGHELP));
00892         }
00893     }
00894 #endif  // NO_ADVANCED_TOOLS
00895 }
00896 
00897 /********************************************************************************************
00898 >   void ContourTool::UpdateRef(    BlendToolRef* pRef,
00899                                 Spread* pSpread, 
00900                                 DocCoord PointerPos,
00901                                 BOOL CheckNodeUnderPoint = TRUE)
00902 
00903     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00904     Created:    10/10/94
00905     Inputs:     pRef                = ptr to a reference struct to update
00906                 pSpread             = ptr to spread click occurred
00907                 PointerPos          = the DocCoord of the click
00908                 CheckNodeUnderPoint = TRUE to revert to click-detection search for underlying node
00909     Outputs:    The members of pRef are updated.
00910     Returns:    -
00911     Purpose:    This will update the blend tool ref depending on the current pointer pos.
00912                 If CheckNodeUnderPoint is TRUE, then the routine will revert to a click-detection search
00913                 to find out which node lies under the given point.  This is potentially very time-consuming.
00914     Errors:     -
00915     SeeAlso:    -
00916 ********************************************************************************************/
00917 
00918 void ContourTool::UpdateRef(BlendToolRef* pRef,Spread* pSpread, DocCoord PointerPos,BOOL CheckNodeUnderPoint)
00919 {
00920     ERROR3IF_PF(pRef   ==NULL,("pRef is NULL"));
00921     ERROR3IF_PF(pSpread==NULL,("pSpread is NULL"));
00922 
00923     // Set the spread and pointer pos members
00924     pRef->pSpread    = pSpread;
00925     pRef->PointerPos = PointerPos;
00926 }
00927 
00928 /********************************************************************************************
00929 >   void ContourTool::UpdateCursorAndStatus()
00930 
00931     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00932     Created:    10/10/94
00933     Inputs:     -
00934     Outputs:    -
00935     Returns:    -
00936     Purpose:    This will update the cursor and status line text depending on the data in the 
00937                 two blend tool references within ContourTool.
00938 
00939                 Copes with the following scenarios:
00940                     Pointer over an object
00941                     Dragging to another object
00942                     Pointer over a selected path's blob
00943                     Dragging to another blob in a selected path
00944                     Pointer over a blend blob
00945                     Dragging to a corresponding blend blob for remapping
00946 
00947     Errors:     -
00948     SeeAlso:    -
00949 ********************************************************************************************/
00950 
00951 void ContourTool::UpdateCursorAndStatus()
00952 {
00953     ERROR3IF_PF(pRefStart==NULL,("pRefStart is NULL"));
00954     ERROR3IF_PF(pRefEnd  ==NULL,("pRefEnd   is NULL"));
00955 
00956     DisplayStatusBarHelp(StatusID);
00957 }
00958 
00959 /********************************************************************************************
00960 
00961 >   virtual BOOL ContourTool::GetStatusLineText(    String_256* ptext, 
00962                                                 Spread* pSpread,
00963                                                 DocCoord DocPos, 
00964                                                 ClickModifiers ClickMods)
00965     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00966     Created:    19/12/94
00967     Inputs:     pStr        - ptr to string to place text in
00968                 pSpread     - ptr to the spread in question
00969                 DocPos      - position of mouse in doc (in spread coords)
00970                 ClickMods   - mouse click modifiers
00971     Outputs:    *pStr - text for status line
00972     Returns:    TRUE if outputting valid text
00973     Purpose:    generate up-to-date text for the status line (called on idles)
00974 
00975 ********************************************************************************************/
00976 
00977 BOOL ContourTool::GetStatusLineText(String_256* pStr,Spread* pSpread,DocCoord DocPos,ClickModifiers ClickMods)
00978 {
00979     if (StatusID != 0)
00980     {
00981         *pStr = String_256(StatusID);
00982     }
00983     else
00984     {
00985         *pStr = String_256(_R(IDS_CONTOURDRAGHELP));
00986     }
00987 
00988     return TRUE;
00989 }
00990 
00991 /********************************************************************************************
00992 
00993 >   BOOL ContourTool::IsPointOverPathBlob(DocCoord* pPointerPos,BlendToolRef* pRef)
00994 
00995     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00996     Created:    10/10/94
00997     Inputs:     pPointerPos = ptr to position of mouse in DocCoords
00998                 pRef        = ptr to blend tool ref to update
00999     Outputs:    Updates pRef->pNode and pRef->pIndex if a path blob was found.
01000                 Also, if blob found, *pPointerPos is snapped to coord of blob
01001     Returns:    TRUE if the coord is over a blob of a selected path
01002     Purpose:    Scans for selected paths.  If the coord is over a selected path's blob,
01003                 it returns TRUE and pRef->pNode points to the path, and pRef->Index contains
01004                 the element index of the blob.
01005                 Also, *pPointerPos is snapped to the coord of the centre of the blob, if found.
01006 
01007 ********************************************************************************************/
01008 
01009 BOOL ContourTool::IsPointOverPathBlob(DocCoord* pPointerPos,BlendToolRef* pRef)
01010 {
01011     if (pRef == NULL) return FALSE;
01012 
01013     // Find the selected range of objects
01014     SelRange* pSelRange = GetApplication()->FindSelection();
01015     Node* pNode = pSelRange->FindFirst();
01016 
01017     BOOL BlobFound = FALSE;
01018 
01019     // Scan the selection for NodePath objects
01020     while (!BlobFound && pNode != NULL && pNode->FindParent() != NULL)
01021     {
01022         // Only look at selected NodePaths that are NOT selected inside another node.
01023         if (IS_A(pNode,NodePath) && IS_A(pNode->FindParent(),Layer))
01024         {
01025             NodePath* pNodePath = (NodePath*)pNode;
01026 
01027             if (pNodePath->GetUnionBlobBoundingRect().ContainsCoord(*pPointerPos))
01028             {
01029                 // Get a pointer to the Path object within the NodePath
01030                 Path* pPath = &(pNodePath->InkPath);
01031 
01032                 // Is it over a blob? (Only check end points. Forget about control points)
01033                 BlobFound = pPath->FindNearestPoint(*pPointerPos,POINTFLAG_ENDPOINTS,&(pRef->Index));
01034 
01035                 // If a blob is found, store ptr to the node
01036                 if (BlobFound)
01037                 {
01038                     pRef->pNode = pNodePath;
01039                     pPath->SetPathPosition(pRef->Index);
01040                     *pPointerPos = pPath->GetCoord();
01041                 }
01042             }
01043         }
01044 
01045         // Now find the next selected node
01046         pNode = pSelRange->FindNext(pNode);
01047     }
01048 
01049     return BlobFound;
01050 }
01051 
01052 /********************************************************************************************
01053 
01054 >   BOOL ContourTool::IsPointOverBlendBlob(DocCoord* pPointerPos,NodeRenderableInk** ppNodePath,INT32* pIndex)
01055 
01056     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01057     Created:    10/11/94
01058     Inputs:     pPointerPos = ptr to position of mouse in DocCoords
01059                 pRef        = ptr to blend tool ref to update
01060     Outputs:    Updates pRef->pNode pRef->pNodeBlend and pRef->Index if a blend blob was found.
01061                 Also, if found, *pPointerPos = centre of blob
01062     Returns:    TRUE if the coord is over a blob of a selected blend
01063     Purpose:    Scans for selected blends.  If the coord is over a selected blend's blob,
01064                 it returns TRUE and pRef->pNode points to the path, pRef->pNodeBlend points to the blend
01065                 containing the path, and *pIndex contains the element index of the blob.
01066                 Also, if found, *pPointerPos = centre of blob.
01067 
01068 ********************************************************************************************/
01069 
01070 BOOL ContourTool::IsPointOverBlendBlob(DocCoord* pPointerPos,BlendToolRef* pRef)
01071 {
01072     if (pRef == NULL) return FALSE;
01073 
01074     // Find the selected range of objects
01075     SelRange* pSelRange = GetApplication()->FindSelection();
01076     Node* pNode = pSelRange->FindFirst();
01077 
01078     BOOL BlobFound = FALSE;
01079 
01080     // Scan the selection for NodePath objects
01081     while (pNode != NULL && !BlobFound)
01082     {
01083         if (pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeBlend))
01084         {
01085             NodeBlend* pNodeBlend = (NodeBlend*)pNode;
01086 
01087             if (pNodeBlend->GetUnionBlobBoundingRect().ContainsCoord(*pPointerPos))
01088             {
01089                 BlobFound = pNodeBlend->IsPointOverBlob(pPointerPos,
01090                                                         &(pRef->pBlendPath),
01091                                                         &(pRef->Index),
01092                                                         &(pRef->AStartNode),
01093                                                         &(pRef->RemapRef));
01094 
01095                 if (BlobFound)
01096                 {
01097                     pRef->pNode      = pNodeBlend;
01098                     pRef->pNodeBlend = pNodeBlend;
01099 //                  *pPointerPos = pRef->pBlendPath->GetPathCoord(pRef->Index);
01100                 }
01101             }
01102         }
01103 
01104         // Now find the next selected node
01105         pNode = pSelRange->FindNext(pNode);
01106     }
01107 
01108     return BlobFound;
01109 }
01110 
01111 /********************************************************************************************
01112 
01113 >   void ContourTool::CheckNodeRemapping(BlendToolRef* pRefStart, BlendToolRef* pRefEnd)
01114 
01115     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01116     Created:    6/12/94
01117     Inputs:     pRefStart = ptr to start ref
01118                 pRefEnd   = ptr to end ref
01119     Outputs:    Potentailly updates pRefStart and pRefEnd, so that if they represent a remapping of nodes,
01120                 they have the same remap reference
01121     Returns:    -
01122     Purpose:    This checks to see if the two references actually represent a node remapping within a blend.
01123                 In order to cope with multi-stage blends, both references have to be looked at the same time.
01124 
01125                 This is not the neatest way of doing it, but it's the quickest and safest method, given that
01126                 it has to work for the gamma release it a few days time.
01127 
01128 ********************************************************************************************/
01129 
01130 void ContourTool::CheckNodeRemapping(BlendToolRef* pRefStart, BlendToolRef* pRefEnd)
01131 {
01132     ERROR3IF(pRefStart == NULL,"pRefStart == NULL");
01133     ERROR3IF(pRefEnd   == NULL,"pRefEnd == NULL");
01134 }
01135 
01136 /********************************************************************************************
01137 >   NodeRenderableInk* ContourTool::FindObject(Spread* pSpread, DocCoord PointerPos)
01138 
01139     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01140     Created:    7/10/94
01141     Inputs:     pSpread  = ptr to spread click occurred
01142                 PointerPos = the DocCoord of the click
01143     Outputs:    -
01144     Returns:    -
01145     Purpose:    Looks for a (possibly grouped) node(s) in the given spread at the
01146                 given mouse-click position.  Convenient shorthand for the hit-testing
01147                 functions.
01148     Errors:     -
01149     SeeAlso:    -
01150 ********************************************************************************************/
01151 
01152 NodeRenderableInk* ContourTool::FindObject(Spread* pSpread, DocCoord PointerPos)
01153 {
01154     return NodeRenderableInk::FindCompoundAtPoint(pSpread,PointerPos,NULL);
01155 }
01156 
01157 /********************************************************************************************
01158 
01159 >   void ContourTool::RenderToolBlobs(Spread* pSpread,DocRect* pDocRect)
01160 
01161     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01162     Created:    28/07/2000
01163     Inputs:     pSpread     ptr to a spread.
01164                 pDocRect    ptr to DocRect of spread to render in.
01165     Returns:    -
01166     Purpose:    Handles the RenderToolBlobs method.
01167                 Renders the tool's blobs into the current doc view.
01168 
01169                 In case you were wondering, this is how contour blobs are arranged:
01170 
01171                     2   4   3
01172 
01173                     6   *   7
01174 
01175                     0   5   1
01176     SeeAlso:    
01177 
01178 ********************************************************************************************/
01179 
01180 void ContourTool::RenderToolBlobs(Spread* pSpread,DocRect* pDocRect)
01181 {
01182 //  BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
01183 
01184     if (m_bDisableBlobRenderingFlag)
01185         return;
01186 
01187     // check the blobs to see if they're valid
01188     BOOL bZeroBlobs = TRUE;
01189 
01190     for (UINT32 i = 0 ; i < 8; i++)
01191     {
01192         if (m_BlobPoints[i].x != 0 ||
01193             m_BlobPoints[i].y != 0)
01194         {
01195             bZeroBlobs = FALSE;
01196             break;
01197         }