bevtool.cpp

Go to the documentation of this file.
00001 // $Id: bevtool.cpp 1282 2006-06-09 09:46:49Z 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 // The FreeHand Tool
00099 // Created by DMc on 2/9/93
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 //#include "ensure.h"
00106 //#include "resource.h" // _R(IDS_OUTOFMEMORY)
00107 //#include "barsdlgs.h"
00108 //#include "mario.h"
00109 //#include "rik.h"
00110 //#include "markn.h"
00111 //#include "viewrc.h"
00112 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "document.h"
00114 //#include "mainfrm.h"
00115 #include "infobar.h"
00116 #include "csrstack.h"
00117 //#include "app.h"
00118 #include "osrndrgn.h"
00119 #include "oilfiles.h"
00120 #include "blobs.h"
00121 //#include "viewrc.h"
00122 
00123 #include "bevinfo.h"
00124 #include "bevtool.h"
00125 #include "module.h"
00126 #include "ezmodule.h"
00127 //#include "bevres.h"
00128 #include "progress.h"
00129 #include "opbevel.h"
00130 
00131 //#include "will2.h"
00132 
00133 #include "nodetxts.h"
00134 #include "attrbev.h"
00135 //#include "attrmgr.h"
00136 //#include "nodebev.h"
00137 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00138 #include "cntrtool.h"
00139 #include "gclips.h"
00140 #include "bubbleid.h"
00141 #include "objchge.h"
00142 #include "nodemold.h"
00143 #include "ndclpcnt.h"
00144 #include "ncntrcnt.h"
00145 //#include "simon.h"
00146 //#include "xshelpid.h"
00147 //#include "helppath.h"
00148 #include "helpuser.h"
00149 #include "dragmgr.h"
00150 #include "lineattr.h"
00151 //#include "cntres.h"
00152 #include "strkattr.h"
00153 #include "nodebev.h"
00154 #include "nbevcont.h"
00155 #include "ophist.h"
00156 
00157 #ifdef BUILDSHADOWS
00158 
00159 // Set things up so that the tool will be listed in the Dialog box
00160 DECLARE_SOURCE("$Revision: 1282 $");
00161 
00162 
00163 // These are still char* while we wait for resource technology to be developed for modules
00164 TCHAR* BevelTool::FamilyName    = _T("Bevelling Tool");
00165 TCHAR* BevelTool::ToolName      = _T("Bevelling Tool");
00166 TCHAR* BevelTool::Purpose       = _T("To Bevel things");
00167 TCHAR* BevelTool::Author        = _T("DMc");
00168 
00169 BevelInfoBarOp * BevelTool::pBevelInfoBarOp = NULL;
00170 BOOL BevelTool::m_bActive = FALSE;
00171 UINT32 BevelTool::StatusID   = _R(IDS_BEVELSTATUSHELP);
00172 OpDragBevel *  BevelTool::m_pDragBevelOp = NULL;
00173 
00174 CC_IMPLEMENT_MEMDUMP( BevelTool, Tool_v1 )
00175 CC_IMPLEMENT_MEMDUMP( BevelBlob, ListItem )
00176 CC_IMPLEMENT_DYNCREATE(OpDragBevel,SelOperation)
00177 
00179 // standard flatness
00180 const MILLIPOINT BevelToolFlatness=200;
00181 
00182 
00183 // Better memory tracking please
00184 #define new CAM_DEBUG_NEW
00185 
00186 /********************************************************************************************
00187 
00188 >   BevelTool::BevelTool()
00189 
00190     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00191     Created:    21/6/93
00192     Purpose:    Dummp Constructor - It does nothing. All the real initialisation is done
00193                 in BevelTool::Init which is called by the Tool Manager
00194     SeeAlso:    BevelTool::Init
00195 
00196 ********************************************************************************************/
00197 
00198 BevelTool::BevelTool()
00199 {
00200     // Set the cursor pointers to null
00201     pNormalCursor = NULL;
00202     pActiveCursor = NULL;
00203     pBevelInfoBarOp = NULL;
00204     pMouseOverCursor = NULL;
00205     m_bRegenBlobsOnNextRender = FALSE;
00206     m_LastZoom = FIXED16(0);
00207     m_bDisableBlobRendering = FALSE;
00208     m_pDragBevelOp = NULL;
00209 }
00210 
00211 
00212 
00213 
00214 
00215 /********************************************************************************************
00216 
00217 >   BevelTool::~BevelTool()
00218 
00219     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00220     Created:    21/6/93
00221     Purpose:    Destructor (Virtual). Does nothing.
00222 
00223 ********************************************************************************************/
00224 
00225 BevelTool::~BevelTool()
00226 {
00227     // delete the attribute list
00228     m_BevelBlobList.DeleteAll();
00229     
00230     RemoveCursors();
00231 
00232     if (m_pDragBevelOp)
00233     {
00234         delete m_pDragBevelOp;
00235         m_pDragBevelOp = NULL;
00236     }
00237 }
00238 
00239 
00240 
00241 /********************************************************************************************
00242 
00243 >   BOOL BevelTool::Init( INT32 Pass )
00244 
00245     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00246     Created:    21/6/93
00247     Returns:    FALSE if it does not want to be created, TRUE otherwise
00248     Purpose:    Used to check if the Tool was properly constructed
00249     SeeAlso:    BevelTool::BevelTool
00250 
00251 ********************************************************************************************/
00252 
00253 BOOL BevelTool::Init()
00254 {
00255     BOOL ok = OpDragBevel::Declare();
00256 
00257     if (!m_pDragBevelOp)
00258         m_pDragBevelOp = new OpDragBevel;
00259 
00260     // This section reads in the infobar definition and creates an instance of
00261     // BevelInfoBarOp.  Also pBevelInfoBarOp, the ptr to the tool's infobar, is set up
00262     // after the infobar is successfully read and created.
00263     if (ok)
00264     {
00265 #if 0
00266         CCResTextFile       file;               // Resource File
00267         BevelInfoBarOpCreate BarCreate;         // Object that creates BlankInfoBarOp objects
00268 
00269         ok = file.open(_R(IDM_BEVEL_BAR), _R(IDT_INFO_BAR_RES));        // Open resource
00270         if (ok) ok = DialogBarOp::ReadBarsFromFile(file,BarCreate); // Read and create info bar
00271         if (ok) file.close();                                       // Close resource
00272 
00273         ERROR3IF(!ok,"Unable to load bevbar.ini from resource\n"); 
00274 
00275         if (ok)
00276         {
00277             // Info bar now exists.  Now get a pointer to it
00278             String_32 str = String_32(_R(IDS_BEVELTOOL_INFOBARNAME));
00279             DialogBarOp* pDialogBarOp = DialogBarOp::FindDialogBarOp(str);
00280             ok = (pDialogBarOp != NULL);
00281 
00282             if (ok)
00283                 ok = pDialogBarOp->IsKindOf(CC_RUNTIME_CLASS(BevelInfoBarOp));
00284 
00285             if (ok)
00286             {
00287                 pBevelInfoBarOp = (BevelInfoBarOp*)pDialogBarOp;
00288                 pBevelInfoBarOp->pTool = this;
00289             }
00290         }
00291 #endif
00292         pBevelInfoBarOp = new BevelInfoBarOp();
00293         ok = (pBevelInfoBarOp != NULL);
00294         if (ok) pBevelInfoBarOp->pTool = this;
00295         
00296         ERROR3IF(!ok,"Error finding the bevel tool info bar");
00297     }
00298 
00299     return (ok);
00300 }
00301 
00302 /********************************************************************************************
00303 
00304 >   void BevelTool::Describe(void *InfoPtr)
00305 
00306     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00307     Created:    21/6/93
00308     Inputs:     InfoPtr - A pointer to a tool info block. It is passed cast to void* as
00309                 the version of the tool is unknown at this point. Later versions of the
00310                 Tool class may have more items in this block, that this tool will not use
00311     Outputs:    InfoPtr - The structure pointed to by InfoPtr will have had all the info
00312                 that this version of the Tool knows about
00313     Purpose:    Allows the tool manager to extract information about the tool
00314 
00315 ********************************************************************************************/
00316 
00317 void BevelTool::Describe(void *InfoPtr)
00318 {
00319     // Cast structure into the latest one we understand.
00320     ToolInfo_v1 *Info = (ToolInfo_v1 *) InfoPtr;
00321 
00322     Info->InfoVersion = 1;
00323     Info->InterfaceVersion = GetToolInterfaceVersion();  // You should always have this line.
00324         
00325     // These are all arbitrary at present.
00326     Info->Version = 1;
00327     Info->ID      = GetID();
00328     Info->TextID  = _R(IDS_BEVEL_TOOL);
00329     Info->BubbleID = _R(IDBBL_BEVEL_TOOLBOX);
00330 
00331     Info->Family  = FamilyName;
00332     Info->Name    = ToolName;
00333     Info->Purpose = Purpose;
00334     Info->Author  = Author;
00335 
00336     Info->InfoBarDialog = _R(IDD_BEVELINFOBAR);
00337 }
00338 
00339 
00340 UINT32 BevelTool::GetID()
00341 {
00342     return TOOLID_BEVELTOOL;
00343 }
00344 
00345 
00346 
00347 // The Free Hand Tools EventHandlers
00348 
00349 /********************************************************************************************
00350 
00351 >   virtual void BevelTool::SelectChange(BOOL isSelected)
00352 
00353     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00354     Created:    24/11/93
00355     Inputs:     IsSelected - TRUE if the tool is becoming selected, FALSE if it is loosing
00356                 the selection
00357     Purpose:    Called when the tool is selected or deselected.  Creates and pushes the
00358                 tool's cursor; pops and destroys it.
00359     Errors:     Sends warning to debugging terminal if creating the cursor fails.
00360 
00361 ********************************************************************************************/
00362 
00363 void BevelTool::SelectChange(BOOL isSelected)
00364 {
00365     // get the blob manager
00366     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
00367     Spread * pSpread = Document::GetSelectedSpread();
00368 //  DocView * pView = DocView::GetCurrent();
00369     // register my interest in blob rendering
00370     BlobStyle BevelBlobs;
00371 
00372     if (isSelected)
00373     {
00374         // Load the cursors
00375         m_bDisableBlobRendering = TRUE;
00376         if (!LoadCursors())
00377             InformError();
00378 
00379         // register the tool interest
00380         BevelBlobs.Tiny = TRUE;
00381         BlobMgr->ToolInterest(BevelBlobs);      
00382 
00383         m_bActive = TRUE;
00384 
00385         // pBevelInfoBarOp->MakeCurrent();
00386 
00387         // update the blob list
00388         SetupBlobList();
00389 
00390         // create & show the dialog
00391         pBevelInfoBarOp->Create();
00392         
00393         if (pBevelInfoBarOp->pCurrentBar)
00394         {
00395             pBevelInfoBarOp->Open();
00396         }
00397 
00398         if (pBevelInfoBarOp)
00399         {
00400             pBevelInfoBarOp->SetToolActiveState(TRUE);
00401         }
00402 
00403         m_bDisableBlobRendering = FALSE;
00404 
00405         if (BlobMgr && pSpread)
00406         {
00407             // render the tool blobs on
00408             BlobMgr->RenderToolBlobsOn(this, pSpread, NULL);
00409         }
00410     }
00411     else
00412     {
00413         // Deselection of the tool
00414         // we need to do this otherwise the blobs are rendered incorrectly
00415         // when switching to another tool
00416 
00417         if (BlobMgr && pSpread)
00418         {
00419             // SetupBlobList();
00420             // render the tool blobs off
00421             BlobMgr->RenderToolBlobsOff(this, pSpread, NULL);
00422         }
00423 
00424         m_bDisableBlobRendering = TRUE;
00425         
00426         RemoveCursors();
00427 
00428         BevelBlobs.Tiny = FALSE;
00429         BlobMgr->ToolInterest(BevelBlobs);      
00430 
00431         m_bActive = FALSE;
00432         
00433         if (pBevelInfoBarOp)
00434         {
00435             pBevelInfoBarOp->SetToolActiveState(FALSE);
00436             pBevelInfoBarOp->Delete();
00437         }
00438         
00439         // ensure any tool object blobs are removed.
00440         BlobStyle bsRemoves;
00441         bsRemoves.ToolObject = TRUE;
00442         BlobMgr->RemoveInterest(bsRemoves);
00443 
00444         m_BevelBlobList.DeleteAll();
00445 
00446         // RecalculateSelectionBoundingBoxes(FALSE);
00447 
00448         m_bDisableBlobRendering = FALSE;
00449     }
00450 }
00451 
00452 /********************************************************************************************
00453 
00454 >   void BevelTool::RecalculateSelectionBoundingBoxes(BOOL InvalidateDoc);
00455 
00456     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00457     Created:    15/3/99
00458     Inputs:     Whether the invalidate the document region
00459     Returns:    
00460     Purpose:    Forces the bounding rects of all bevel nodes (with blobs) to
00461                 be recalculated, and if InvalidateDoc is TRUE then it invalidates the
00462                 document's rect
00463     Errors:     
00464 
00465 ********************************************************************************************/
00466 
00467 void BevelTool::RecalculateSelectionBoundingBoxes(BOOL InvalidateDoc)
00468 {
00469     Spread * pSpread = Document::GetSelectedSpread();
00470     
00471     // can't do anything
00472     if (!pSpread)
00473         return;
00474 
00475     Document * pDoc = Document::GetCurrent();
00476 
00477     if (!pDoc)
00478         return;
00479     
00480     DocRect ClipRect;
00481     Node * pNode = NULL;
00482 
00483     Range Sel(*(GetApplication()->FindSelection()));
00484 
00485     if (Sel.IsEmpty())
00486         return;
00487 
00488     pNode = Sel.FindFirst(TRUE);
00489 
00490     while (pNode)
00491     {
00492         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)) &&
00493             !pNode->IsNodeHidden())
00494         {
00495             ClipRect = ClipRect.Union(((NodeRenderableBounded *)pNode)->GetBlobBoundingRect());
00496         }
00497 
00498         pNode = Sel.FindNext(pNode, TRUE);
00499     }
00500     
00501     if (InvalidateDoc)
00502     {
00503         pDoc->ForceRedraw(pSpread, ClipRect, TRUE);
00504     }
00505 }
00506 
00507 /********************************************************************************************
00508 
00509 >   BOOL BevelTool::LoadCursors()
00510 
00511     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00512     Created:    1/3/99
00513     Returns:    TRUE if it worked, FALSE if it did not
00514     Purpose:    Loads all the cursors used by the freehand tool and pushs the normal
00515                 one onto the top of the cursor stack
00516     Errors:     ERROR1 (_R(IDE_FHAND_BADCURSORS)) if it fails to load the cursors
00517 
00518 ********************************************************************************************/
00519 
00520 BOOL BevelTool::LoadCursors()
00521 {
00522     // This tool has just been selected, so it is not displaying a cursor
00523     pActiveCursor = NULL;
00524 
00525     // Try to create all our cursors - The normal cursor
00526         pNormalCursor = new Cursor(this, _R(IDC_POINTER_BEVEL));
00527     pMouseOverCursor = new Cursor(this, _R(IDC_ELIPTOOLOVERBLOB));
00528     pSizeCursor = new Cursor(this, _R(IDC_SIZE_BEVEL));
00529     
00530     // did we get all the cursors ok
00531     if (pNormalCursor==NULL || pMouseOverCursor==NULL || pSizeCursor==NULL)
00532     {
00533         // No, at least one of them was NULL, so delete them all
00534         // Deleting the null cursor will be ok
00535         delete pNormalCursor;
00536 
00537         // and ensure that the pointers are set to NULL
00538         pNormalCursor = NULL;
00539 
00540         // and set an error and return
00541         ERROR1(FALSE, _R(IDE_FHAND_BADCURSORS));
00542     }
00543 
00544     // All the cursors loaded ok if we got to here
00545     // So push the normal cursor onto the stack and mark it as active
00546     CurrentCursorID = CursorStack::GPush(pNormalCursor, FALSE);
00547     pActiveCursor = pNormalCursor;
00548 
00549     // return that it worked
00550     return TRUE;
00551 
00552 }
00553 
00554 
00555 
00556 /********************************************************************************************
00557 
00558 >   void BevelTool::RemoveCursors()
00559 
00560     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00561     Created:    1/3/99
00562     Purpose:    Pops the freehand tools cursor off the top of the cursor stack, frees the
00563                 memory used by all the cursors in the freehand tool and sets all the pointers
00564                 to NULL.
00565     SeeAlso:    BevelTool::LoadCursors
00566 
00567 ********************************************************************************************/
00568 
00569 void BevelTool::RemoveCursors()
00570 {
00571     // If we ever had a cursor
00572     if (pActiveCursor!=NULL)
00573     {
00574         // pop it off the stack
00575         CursorStack::GPop(CurrentCursorID);
00576 
00577         // and free up the cursors we allocated
00578         delete pNormalCursor;
00579 
00580         delete pMouseOverCursor;
00581 
00582         delete pSizeCursor;
00583 
00584         // and set them all to NULL
00585         pNormalCursor = NULL;
00586         pActiveCursor = NULL;
00587         pMouseOverCursor = NULL;
00588         pSizeCursor = NULL;
00589         CurrentCursorID = 0;
00590     }
00591 }
00592 
00593 /********************************************************************************************
00594 
00595 >   void BevelTool::OnMouseMove(DocCoord Pos, Spread* pSpread, ClickModifiers ClickMods);
00596 
00597     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00598     Created:    1/3/99
00599     Inputs:     ID of the cursor you want to flip to
00600     Purpose:    Sorts out the movement cursor
00601     Errors:     can fail if the cursor cannot be created - the cursor code will fail.
00602 
00603 ********************************************************************************************/
00604 void BevelTool::OnMouseMove(DocCoord Pos, Spread* pSpread, ClickModifiers ClickMods)
00605 {
00606     // step through all the bevel controller nodes in the selection hit testing
00607     BOOL bFound = FALSE;
00608 
00609     // run through the blob list testing
00610     BevelBlob * pBlob = (BevelBlob *)m_BevelBlobList.GetHead();
00611 
00612     while (pBlob && !bFound)
00613     {
00614         if (pBlob->HitTest(Pos))
00615         {
00616             bFound = TRUE;
00617             TRACEUSER( "MarkH", _T("Hittesting!\n"));
00618         }
00619 
00620         pBlob = (BevelBlob *)m_BevelBlobList.GetNext(pBlob);
00621     }
00622 
00623     if (bFound)
00624     {
00625         ChangeCursor(pMouseOverCursor);
00626 
00627         // update the info bar
00628         DisplayStatusBarHelp(_R(IDS_BEVELDRAGBLOBHELP));
00629 
00630     }
00631     else
00632     {
00633         if (IsPointOverSelectionBlob(Pos, NULL))
00634         {
00635             ChangeCursor(pSizeCursor);
00636             DisplayStatusBarHelp(_R(IDS_BEVELDRAGSTATUSHELP));
00637         }
00638         else
00639         {       
00640             ChangeCursor(pNormalCursor);
00641             DisplayStatusBarHelp(_R(IDS_BEVELSTATUSHELP));
00642         }
00643     }
00644 }
00645 
00646 /********************************************************************************************
00647 
00648 >   void BevelTool::DisplayStatusBarHelp(UINT32 StatusID)
00649 
00650     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> Mc
00651     Created:    29/9/99
00652     Inputs:     StatusID = ID of status help string
00653     Outputs:    -
00654     Returns:    -
00655     Purpose:    Displays the given status help string in the status bar
00656     SeeAlso:    -
00657 
00658 ********************************************************************************************/
00659 
00660 void BevelTool::DisplayStatusBarHelp(UINT32 StatusIDX)
00661 {
00662     String_256 StatusMsg("");
00663     StatusMsg.Load(StatusIDX);
00664     GetApplication()->UpdateStatusBarText(&StatusMsg);
00665     BevelTool::StatusID = StatusIDX;
00666 }
00667 
00668 /********************************************************************************************
00669 
00670 >   BOOL BevelTool::GetStatusLineText(String_256* ptext, Spread* pSpread, DocCoord DocPos, 
00671                     ClickModifiers ClickMods);
00672 
00673     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> Mc
00674     Created:    29/9/99
00675     Inputs:     StatusID = ID of status help string
00676     Outputs:    -
00677     Returns:    -
00678     Purpose:    Displays the given status help string in the status bar
00679     SeeAlso:    -
00680 
00681 ********************************************************************************************/
00682 BOOL BevelTool::GetStatusLineText(String_256* ptext, Spread* pSpread, DocCoord DocPos, ClickModifiers ClickMods)
00683 {
00684     ptext->Load(BevelTool::StatusID);
00685     return TRUE;
00686 }
00687 
00688 /********************************************************************************************
00689 
00690 >   void BevelTool::ChangeCursor(Cursor* cursor)
00691 
00692     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00693     Created:    1/3/99
00694     Inputs:     ID of the cursor you want to flip to
00695     Purpose:    Changes to the specified cursor. Will only change the cursor if it isn't already
00696                 this cursor, so it doesn't flicker.
00697     Errors:     can fail if the cursor cannot be created - the cursor code will fail.
00698 
00699 ********************************************************************************************/
00700 
00701 void BevelTool::ChangeCursor(Cursor* pCursor)
00702 {
00703     // only change if this cursor is different from the current cursor
00704     if ((pCursor!=pActiveCursor) && (pCursor!=NULL))
00705     {
00706         // set this cursor as the current cursor and immediately display it
00707         CursorStack::GSetTop(pCursor, CurrentCursorID);
00708 
00709         // remember this is our current cursor
00710         pActiveCursor = pCursor;
00711 
00712         DisplayStatusBarHelp(BevelTool::StatusID);
00713     }
00714 }
00715 
00716 
00717 
00718 
00719 
00720 
00721 /********************************************************************************************
00722 
00723 >   void BevelTool::OnClick( DocCoord PointerPos, ClickType Click, 
00724                                 ClickModifiers ClickMods, Spread *pSpread )
00725 
00726     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00727     Created:    16/2/99
00728     Inputs:     PointerPos - The Coords (in spread coords) of the point where the mouse 
00729                 button was clicked
00730                 Click - Describes the type of click that was detected. 
00731                 ClickMods - Indicates which buttons caused the click and which modifers were
00732                 pressed at the same time
00733                 pSpread - the spread in which the click happened
00734     Returns:    TRUE if it handled the Click, FALSE otherwise
00735     Purpose:    Handle selection messages by the bevelling tool
00736     SeeAlso:    
00737 
00738 ********************************************************************************************/
00739 
00740 void BevelTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
00741                         Spread* pSpread )
00742 {
00743     ERROR3IF_PF(pSpread==NULL,("pSpread is NULL"));
00744 
00745     if (ClickMods.Menu) return;                         // Don't do anything if the user clicked the Menu button
00746 
00747 //  NodeCompound * pCompound = NULL;
00748 
00749     DocRect BlobRect;
00750 
00751     switch (Click)
00752     {
00753         // if a drag was started, we alter or create a contour.
00754         case CLICKTYPE_DRAG:
00755         {   
00756             // run through my blob list testing the pointer position
00757             BOOL bDoingDrag = FALSE;
00758             BevelBlob* pBlob = (BevelBlob *) m_BevelBlobList.GetHead();
00759 
00760             while (pBlob && !bDoingDrag)
00761             {
00762                 if (pBlob->HitTest(PointerPos))
00763                 {
00764                     bDoingDrag = TRUE;
00765                     pBevelInfoBarOp->BeginDrag(pBlob);
00766                 }
00767 
00768                 pBlob = (BevelBlob *)m_BevelBlobList.GetNext(pBlob);
00769             }
00770 
00771             // if we're not doing a drag yet, then start a drag create.
00772             if (!bDoingDrag)
00773             {
00774                 if (m_pDragBevelOp)
00775                 {
00776                     DocRect BlobRect;
00777 
00778                     m_pDragBevelOp->DoDrag(pBevelInfoBarOp, PointerPos, 
00779                         IsPointOverSelectionBlob(PointerPos, &BlobRect), &BlobRect);
00780                 }
00781             }
00782         }
00783         break;
00784 
00785         case CLICKTYPE_SINGLE:
00786         {
00787             // check for contours existing
00788             List ContourList;
00789             BevelTools::BuildListOfSelectedNodes(&ContourList, CC_RUNTIME_CLASS(NodeContourController));
00790 
00791             if (!ContourList.IsEmpty())
00792             {
00793                 ContourList.DeleteAll();
00794 
00795                 DocRect BlobRect;
00796 
00797                 // disable the drag
00798                 if (IsPointOverSelectionBlob(PointerPos, &BlobRect))
00799                 {
00800                     DocView * pView = DocView::GetCurrent();
00801 
00802                     if (pView)
00803                         pView->EndDrag(NULL);               
00804                     
00805                     InformWarningContourExistsInSelection();            
00806                 }
00807             }
00808 
00809             // call the base class ....
00810             
00811             DragTool::OnClick (PointerPos, Click, ClickMods, pSpread);
00812         }
00813         break;
00814         
00815         default:
00816             // call the base class ....
00817             
00818             DragTool::OnClick (PointerPos, Click, ClickMods, pSpread);
00819         break;
00820     }
00821 
00822 }
00823 
00824 /********************************************************************************************
00825 
00826 >   void BevelTool::InformWarningContourExistsInSelection()
00827 
00828     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00829     Created:    7/4/2000
00830     Purpose:    Invokes the 'cant bevel contour' dialog
00831 
00832 ********************************************************************************************/
00833 void BevelTool::InformWarningContourExistsInSelection()
00834 {
00835     String_256 QueryString(_R(IDS_CANTBEVELCONTOUR));
00836 
00837     Error::SetError(0, QueryString, 0);             
00838     // The only way of bringing up a box with a string in it
00839     INT32 DlgResult = InformError(_R(IDS_CANTBEVELCONTOUR),
00840         _R(IDS_OK), _R(IDS_HELP));
00841                 
00842     if (DlgResult == 2)
00843     {
00844         HelpUserTopic(_R(IDS_HELPPATH_Message__Contour_already_applied));
00845     }
00846 }
00847 
00848 /********************************************************************************************
00849 
00850 >   void BevelTool::RenderBlob(BevelBlob * pBlob)
00851 
00852     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00853     Created:    17/5/94
00854     Inputs:     The blob to render
00855     Purpose:    Renders a single blob with the current spread
00856 
00857 ********************************************************************************************/
00858 void BevelTool::RenderBlob(BevelBlob * pBlob)
00859 {
00860     Spread * pSpread = Document::GetSelectedSpread();
00861 
00862     // get the clipping rect of the blob
00863     DocRect dr = pBlob->GetRect();
00864 
00865     // run through all the render regions on the stack rendering the blob
00866     RenderRegion * pRegion = DocView::RenderOnTop(NULL, pSpread, UnclippedEOR);
00867 
00868     while (pRegion)
00869     {
00870         pBlob->RenderBlob(pRegion);
00871 
00872         pRegion = DocView::GetNextOnTop(NULL);
00873     }
00874 }
00875 
00876 
00877 /********************************************************************************************
00878 
00879 >   void BevelTool::RenderToolBlobs(Spread* pSpread, DocRect* pClipRect)
00880 
00881     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00882     Created:    17/5/94
00883     Inputs:     pSpread - The spread that the blob is to appear on
00884                 pClipRect - Pointer to the rect that contains the blobs
00885     Purpose:    Renders the Tools Blobs. This will be used to draw paths as they are retro
00886                 fitted live, as the accuracy bar is dragged!
00887 
00888                 In case you were wondering, this is how bevel blobs are arranged:
00889 
00890                     2   4   3
00891 
00892                     6   *   7
00893 
00894                     0   5   1
00895 
00896 ********************************************************************************************/
00897 
00898 void BevelTool::RenderToolBlobs(Spread* pSpread, DocRect* pClipRect)
00899 {
00900     // DoSelectBevelNodesFromChildren();
00901 
00902     if (m_bDisableBlobRendering)
00903         return;
00904 
00905     // have we zoomed ?
00906     DocView * pView = DocView::GetSelected(); //GetCurrent();
00907 
00908     if (pView)
00909     {
00910         if (m_LastZoom != pView->GetViewScale())
00911         {
00912             // ensure we recalculate the bounding rect
00913             SetupBlobList();
00914             m_LastZoom = pView->GetViewScale();
00915         }
00916     }
00917 
00918     // run through all the render regions and all blobs in the list
00919     // rendering
00920 
00921     // get the top render region for the blob rendering
00922     RenderRegion * pRegion = DocView::RenderOnTop(pClipRect, pSpread, UnclippedEOR);
00923 
00924     BevelBlob * pBlob = NULL;
00925 
00926     while (pRegion)
00927     {
00928         // go through all blobs in list
00929         pBlob = (BevelBlob *)m_BevelBlobList.GetHead();
00930 
00931         while (pBlob)
00932         {
00933             pBlob->RenderBlob(pRegion);
00934 
00935             pBlob = (BevelBlob *)m_BevelBlobList.GetNext(pBlob);
00936         }       
00937 
00938         // now do the selection blobs as well
00939         pRegion->SaveContext();
00940 /*
00941  *  Karim 26/06/2000
00942  *  commented out - we're running a trial on some new Contour blobs :)
00943         pRegion->SetFillColour(COLOUR_RED);
00944         pRegion->SetLineColour(COLOUR_NONE);
00945 
00946         for (UINT32 i = 0 ; i < 8; i++)
00947             pRegion->DrawBlob(m_BlobPoints[i], BT_SELECTED);
00948  *
00949  */
00950         // left and right.
00951         pRegion->DrawBitmapBlob(m_BlobPoints[6], _R(IDBMP_CONTOUR_LEFTRIGHT));
00952         pRegion->DrawBitmapBlob(m_BlobPoints[7], _R(IDBMP_CONTOUR_LEFTRIGHT));
00953 
00954         // up and down.
00955         pRegion->DrawBitmapBlob(m_BlobPoints[4], _R(IDBMP_CONTOUR_UPDOWN));
00956         pRegion->DrawBitmapBlob(m_BlobPoints[5], _R(IDBMP_CONTOUR_UPDOWN));
00957 
00958         // acute accent (bl to tr).
00959         pRegion->DrawBitmapBlob(m_BlobPoints[0], _R(IDBMP_CONTOUR_ACUTE));
00960         pRegion->DrawBitmapBlob(m_BlobPoints[3], _R(IDBMP_CONTOUR_ACUTE));
00961 
00962         // grave accent (tl to br).
00963         pRegion->DrawBitmapBlob(m_BlobPoints[2], _R(IDBMP_CONTOUR_GRAVE));
00964         pRegion->DrawBitmapBlob(m_BlobPoints[1], _R(IDBMP_CONTOUR_GRAVE));
00965 
00966         pRegion->RestoreContext();      
00967         
00968         pRegion = DocView::GetNextOnTop(NULL);
00969     }
00970 }
00971 
00972 /********************************************************************************************
00973 
00974 >   BOOL BevelTool::IsPointOverSelectionBlob(DocCoord &Point, DocRect * pRect)
00975 
00976     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00977     Created:    5/12/99
00978     Inputs:     Point - the point to test
00979     Purpose:    Returns TRUE if this point is over a selection (i.e. a drag create or
00980                 drag change width blob)
00981 
00982 ********************************************************************************************/
00983 BOOL BevelTool::IsPointOverSelectionBlob(DocCoord &Point, DocRect * pRect)
00984 {
00985     // check to see if I'm over a blob
00986     BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
00987 
00988     INT32 BlobSize = 0;
00989 
00990     // Karim 18/09/2000
00991     // The bevel blobs are about twice the size of normal blobs,
00992     // so I'm doubling the value of BlobSize when checking for them.
00993     if (pBlobMgr)
00994         BlobSize = pBlobMgr->GetBlobSize();
00995 //      BlobSize = pBlobMgr->GetBlobSize()/2;
00996 
00997     for (INT32 i = 0; i < 8; i++)
00998     {
00999         DocRect dr( m_BlobPoints[i].x - BlobSize,
01000                     m_BlobPoints[i].y - BlobSize,
01001                     m_BlobPoints[i].x + BlobSize,
01002                     m_BlobPoints[i].y + BlobSize);
01003 
01004         if (dr.ContainsCoord(Point))
01005         {
01006             if (pRect)
01007                 *pRect = dr;
01008             return TRUE;
01009         }
01010     }
01011 
01012     return FALSE;
01013 }
01014 
01015 /********************************************************************************************
01016 
01017 >   BOOL BevelTool::SetupBlobList()
01018 
01019     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01020     Created:    12/3/99
01021     Inputs:     
01022     Purpose:    Sets up the blob list depending on the selection
01023     Returns:    FALSE for no selection, or no bevel attributes detected
01024 
01025 ********************************************************************************************/
01026 BOOL BevelTool::SetupBlobList()
01027 {
01028     // do the selection blobs first
01029     SetupSelectionBlobs();
01030     
01031     // clear our blob list
01032     m_BevelBlobList.DeleteAll();
01033 
01034     m_BlobListBounds.hi.x = 0;
01035     m_BlobListBounds.lo.x = 0;
01036     m_BlobListBounds.hi.y = 0;
01037     m_BlobListBounds.lo.y = 0;
01038 
01039     // kick the sel range
01040     // GetApplication()->UpdateSelection();
01041     
01042     BOOL bHandled = FALSE;
01043 
01044     BevelBlob * pBlob;
01045 
01046     List BevelNodeList;
01047     
01048     // make a list of all bevel ink nodes
01049     if (!BevelTools::BuildListOfSelectedNodes(&BevelNodeList, CC_RUNTIME_CLASS(NodeBevel)))
01050     {
01051         // failed
01052         return FALSE;
01053     }
01054 
01055     NodeListItem * pItem = (NodeListItem *)BevelNodeList.GetHead();
01056     Node * pNode = NULL;
01057 
01058 //  BOOL bFound = FALSE;
01059 
01060     while (pItem)
01061     {
01062         pNode = pItem->pNode->FindParent();
01063         
01064         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeBevelController)) 
01065             && !pNode->IsNodeHidden() 
01066             && !pNode->IsLocked() 
01067             && pNode->IsRenderable())
01068         {
01069             // ok ! Now, run through our list determining if this light angle
01070             // matches with any others
01071             pBlob = (BevelBlob *)m_BevelBlobList.GetHead();
01072 
01073             bHandled = FALSE;
01074 
01075             while (pBlob && !bHandled)
01076             {
01077                 // try adding the attribute to the list item
01078                 if (pBlob->AddNode((NodeBevelController *)pNode))
01079                 {
01080                     bHandled = TRUE;
01081 
01082                     // update the document rect
01083                     if (m_BlobListBounds.Width() == 0 &&
01084                         m_BlobListBounds.Height() == 0)
01085                     {
01086                         m_BlobListBounds = pBlob->GetRect();
01087                     }
01088                     else
01089                     {
01090                         m_BlobListBounds = m_BlobListBounds.Union(pBlob->GetRect());
01091                     }
01092                 }
01093                 
01094                 pBlob = (BevelBlob *)m_BevelBlobList.GetNext(pBlob);
01095             }
01096 
01097             // if the attribute hasn't been taken by any of the nodes in the list
01098             // then we need to create a new node
01099             if (!bHandled)
01100             {
01101                 // create the bevel blob
01102                 pBlob = new BevelBlob;
01103 
01104                 if (!pBlob)
01105                 {
01106                     ERROR3("Cannot create bevel blob");
01107                     BevelNodeList.DeleteAll();
01108                     return FALSE;
01109                 }
01110 
01111                 if (!pBlob->AddNode((NodeBevelController *)pNode))
01112                 {
01113                     ERROR3("Cannot add attribute to bevel blob");
01114                     BevelNodeList.DeleteAll();
01115                     return FALSE;
01116                 }
01117 
01118                 // insert it into the list
01119                 m_BevelBlobList.AddTail(pBlob);
01120 
01121                 // update the document rect
01122                 if (m_BlobListBounds.Width() == 0 &&
01123                     m_BlobListBounds.Height() == 0)
01124                 {
01125                     m_BlobListBounds = pBlob->GetRect();
01126                 }
01127                 else
01128                 {
01129                     m_BlobListBounds = m_BlobListBounds.Union(pBlob->GetRect());
01130                 }
01131             }
01132         }
01133 
01134         pItem = (NodeListItem *)BevelNodeList.GetNext(pItem);       
01135     }
01136 
01137     BevelNodeList.DeleteAll();
01138 
01139     return TRUE;
01140 }
01141 
01142 /********************************************************************************************
01143 
01144 >   void BevelTool::SetupSelectionBlobs();
01145 
01146     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01147     Created:    5/12/99
01148     Inputs:     
01149     Purpose:    Sets up the bevel tool blobs for the selection.
01150 
01151                 Karim 28/07/2000
01152                 Bevel tool blobs are laid out like so relative to the selection:
01153 
01154                         2   4   3
01155 
01156                         6   *   7
01157 
01158                         0   5   1
01159 
01160                 with corner blobs positioned 1 pixel out from the bounds rect
01161                 and middle blobs positioned 2 pixels out from the bounds rect.
01162 
01163 ********************************************************************************************/
01164 void BevelTool::SetupSelectionBlobs()
01165 {
01166     // reset the blob positions.
01167     for (INT32 i = 0 ; i < 8; i++)
01168     {
01169         m_BlobPoints[i].x = 0;
01170         m_BlobPoints[i].y = 0;
01171     }
01172 
01173     // give up if we there is no selection or we can't get the info we need.
01174     if (GetApplication()->FindSelection() == NULL ||
01175         GetApplication()->FindSelection()->IsEmpty())
01176         return;
01177 
01178     BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
01179     if (pBlobMgr == NULL)
01180         return;
01181 
01182     // figure out the blob offsets, in millipoints.
01183     INT32 BlobGap = 0;
01184     DocView* pDocView = DocView::GetSelected();
01185     if (pDocView != NULL)
01186         BlobGap = pDocView->GetScaledPixelWidth().MakeLong();
01187 
01188     // ok, get the bounds of the selection, including bevels.
01189     SelRange Sel(*(GetApplication()->FindSelection()));
01190     DocRect drBounds;
01191     Node* pN = Sel.FindFirst();
01192     while (pN != NULL)
01193     {
01194         if (pN->IsBounded())
01195         {
01196             Node* pParent = pN->FindParent();
01197             while (pParent != NULL && pParent->IS_KIND_OF(NodeBevelController))
01198             {
01199                 pN = pParent;
01200                 pParent = pN->FindParent();
01201             }
01202 
01203             drBounds = drBounds.Union( ((NodeRenderableBounded*)pN)->GetBoundingRect() );
01204         }
01205         pN = Sel.FindNext(pN);
01206     }
01207 
01208     // lets set up those blobs!
01209     DocCoord dc;
01210     INT32 BlobSize = pBlobMgr->GetBlobSize();
01211     drBounds.Inflate(BlobGap + BlobSize);
01212 
01213     dc.x = drBounds.lo.x;
01214     dc.y = drBounds.lo.y;
01215     m_BlobPoints[0] = dc;
01216 
01217     dc.x = drBounds.hi.x;
01218     dc.y = drBounds.lo.y;
01219     m_BlobPoints[1] = dc;
01220 
01221     dc.x = drBounds.lo.x;
01222     dc.y = drBounds.hi.y;
01223     m_BlobPoints[2] = dc;
01224 
01225     dc.x = drBounds.hi.x;
01226     dc.y = drBounds.hi.y;
01227     m_BlobPoints[3] = dc;
01228 
01229     dc.x = (drBounds.lo.x + drBounds.hi.x) / 2;
01230     dc.y = drBounds.hi.y + BlobGap;
01231     m_BlobPoints[4] = dc;
01232 
01233     dc.x = (drBounds.lo.x + drBounds.hi.x) / 2;
01234     dc.y = drBounds.lo.y - BlobGap;
01235     m_BlobPoints[5] = dc;
01236 
01237     dc.x = drBounds.lo.x - BlobGap;
01238     dc.y = (drBounds.lo.y + drBounds.hi.y) / 2;
01239     m_BlobPoints[6] = dc;
01240 
01241     dc.x = drBounds.hi.x + BlobGap;
01242     dc.y = (drBounds.lo.y + drBounds.hi.y) / 2;
01243     m_BlobPoints[7] = dc;
01244 }
01245 
01246 /********************************************************************************************
01247 
01248 >   void BevelTool::DoSelectBevelNodesFromChildren()
01249 
01250     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01251     Created:    11/3/99
01252     Inputs:     
01253     Purpose:    Selects all bevel controller nodes from the child nodes in the selection
01254 
01255 ********************************************************************************************/
01256 void BevelTool::DoSelectBevelNodesFromChildren()
01257 {
01258     // run through the selection selecting all nodes' parents which
01259     // are bevel controller nodes
01260     // do we have a bevel controller node in the selection ?
01261     // Obtain the current selections 
01262     Range Sel(*(GetApplication()->FindSelection()));
01263     RangeControl rg = Sel.GetRangeControlFlags();
01264     rg.PromoteToParent = TRUE;
01265     Sel.Range::SetRangeControl(rg);
01266     
01267 
01268     // flag to say whether we've changed the selection or not
01269     BOOL bSelChanged = FALSE;
01270 
01271     if (Sel.IsEmpty())
01272         return ;
01273 
01274     // search through until we find a path node
01275     Node *pNode = Sel.FindFirst(TRUE);
01276 
01277     if (!pNode)
01278     {
01279         pNode = Sel.FindFirst(FALSE);
01280     }
01281 
01282     if (!pNode)
01283         return ;
01284 
01285     Node * pOldNode = NULL;
01286 
01287 //  BOOL bOK = FALSE;
01288 
01289 //  NodeBevelController * pBevControl = NULL;
01290     Node * pParent;
01291 
01292     // this is the list of nodes to select
01293     List SelList;
01294     NodeListItem * pListItem = NULL;
01295     
01296     // run through all the nodes in the list finding out if any children of
01297     // bevel controller nodes are selected when the controller node itself isn't
01298     while (pNode)
01299     {
01300         pParent = pNode->FindParent();
01301 
01302         if (pParent)
01303         {
01304             if (pParent->IsKindOf(CC_RUNTIME_CLASS(NodeBevelController)))
01305             {
01306                 // ensure the parent is selected
01307                 if (!pParent->IsSelected())
01308                 {
01309                     pListItem = new NodeListItem;
01310 
01311                     if (!pListItem)
01312                     {
01313                         ERROR3("Can't create list item");
01314                         return;
01315                     }
01316 
01317                     pListItem->pNode = pParent;
01318                     SelList.AddTail(pListItem);
01319                     bSelChanged = TRUE;
01320                 }
01321             }
01322         }
01323 
01324         pOldNode = pNode;
01325         pNode = Sel.FindNext(pNode, TRUE);
01326 
01327         if (!pNode)
01328         {
01329             pNode = Sel.FindNext(pOldNode, FALSE);
01330         }
01331     }
01332 
01333     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
01334 
01335     Spread * pSpread = Document::GetSelectedSpread();
01336 
01337     DocRect dr;
01338 
01339     // update the selection in the app
01340     if (bSelChanged && BlobMgr && pSpread)
01341     {
01342         // first, render the blobs off
01343         dr = Sel.GetBoundingRect();
01344         BlobMgr->RenderOff(&dr, pSpread);
01345 
01346         // run through the list selecting all nodes
01347         pListItem = (NodeListItem *)SelList.GetHead();
01348 
01349         while (pListItem)
01350         {
01351             if (pListItem->pNode)
01352             {
01353                 pListItem->pNode->SetSelected(TRUE);
01354             }
01355 
01356             pListItem = (NodeListItem *)SelList.GetNext(pListItem);
01357         }
01358         
01359         // update the selection
01360         GetApplication()->UpdateSelection();
01361 
01362         // update the blob list
01363         SetupBlobList();
01364 
01365         // render the blobs back on, bearing in mind the selection has changed
01366         Range NewSel(*(GetApplication()->FindSelection()));
01367         RangeControl rg = Sel.GetRangeControlFlags();
01368         rg.PromoteToParent = TRUE;
01369         Sel.Range::SetRangeControl(rg);
01370     
01371         dr = NewSel.GetBoundingRect();
01372         BlobMgr->RenderOn(&dr, pSpread);
01373     }
01374 
01375     SelList.DeleteAll();
01376 }
01377 
01378 /********************************************************************************************
01379 
01380 >   void BevelTool::InvalidateToolBlobs()
01381 
01382     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01383     Created:    11/3/99
01384     Inputs:     
01385     Purpose:    Unrenders all blobs, sets up the blob list again and re-renders
01386 
01387 ********************************************************************************************/
01388 void BevelTool::InvalidateToolBlobs()
01389 {
01390     // render the blobs off first
01391 
01392     // get the blob manager
01393     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
01394     Spread * pSpread = Document::GetSelectedSpread();
01395 
01396     if (!BlobMgr || !pSpread)
01397         return;
01398 
01399     // first, render the blobs off
01400     BlobMgr->RenderToolBlobsOff(this, pSpread, NULL);
01401 
01402     SetupBlobList();
01403 
01404     // render the blobs back on
01405     BlobMgr->RenderToolBlobsOn(this, pSpread, NULL);
01406 
01407     // force a redraw of the area
01408     /*
01409     Document * pDoc = Document::GetCurrent();
01410     DocView * pView = DocView::GetCurrent();
01411 
01412     if (pDoc && pView)
01413     {
01414         pDoc->ForceRedraw(pSpread, m_BlobListBounds);
01415     }
01416     */
01417 }
01418 
01419 /********************************************************************************************
01420 
01421 >   void BevelTool::ChangeBlobAngles(INT32 Angle)
01422 
01423     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01424     Created:    11/3/99
01425     Inputs:     The new angle
01426     Purpose:    Removes all blobs' angles and re-renders them with the new angle
01427 
01428 ********************************************************************************************/
01429 void BevelTool::ChangeBlobAngles(INT32 Angle)
01430 {
01431     if (m_BevelBlobList.IsEmpty())
01432         return;
01433 
01434     // get the blob manager
01435     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
01436     Spread * pSpread = Document::GetSelectedSpread();
01437 
01438     if (!BlobMgr || !pSpread)
01439         return;
01440 
01441     // first, render the blobs off
01442     // BlobMgr->RenderToolBlobsOff(this, pSpread, &m_BlobListBounds);
01443 
01444     BevelBlob * pBlob = (BevelBlob *)m_BevelBlobList.GetHead();
01445 
01446     Document * pDoc = Document::GetCurrent();
01447 
01448     // set all the blob angles to the new value
01449     while (pBlob)
01450     {
01451         pBlob->SetAngle(Angle);
01452 
01453         pBlob->RenderNodes();
01454 
01455         if (pDoc)
01456             pDoc->ForceRedraw(pSpread, m_BlobListBounds);       
01457         
01458         pBlob = (BevelBlob *)m_BevelBlobList.GetNext(pBlob);
01459     }
01460 
01461     GetApplication()->ServiceRendering();
01462 
01463     // render the blobs back on
01464     // BlobMgr->RenderToolBlobsOn(this, pSpread, &m_BlobListBounds);
01465 }
01466 
01467 /********************************************************************************************
01468 
01469 >   void BevelTool::ChangeBlobTilts(INT32 Tilt)
01470 
01471     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01472     Created:    6/2/2000
01473     Inputs:     The new angle
01474     Purpose:    Removes all blobs' angles and re-renders them with the new tilt
01475 
01476 ********************************************************************************************/
01477 void BevelTool::ChangeBlobTilts(INT32 Tilt)
01478 {
01479     if (m_BevelBlobList.IsEmpty())
01480         return;
01481 
01482     // get the blob manager
01483     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
01484     Spread * pSpread = Document::GetSelectedSpread();
01485 
01486     if (!BlobMgr || !pSpread)
01487         return;
01488 
01489     // first, render the blobs off
01490     // BlobMgr->RenderToolBlobsOff(this, pSpread, &m_BlobListBounds);
01491 
01492     BevelBlob * pBlob = (BevelBlob *)m_BevelBlobList.GetHead();
01493 
01494     Document * pDoc = Document::GetCurrent();
01495 
01496     // set all the blob angles to the new value
01497     while (pBlob)
01498     {
01499         pBlob->SetTilt(Tilt);
01500 
01501         pBlob->RenderNodes();
01502 
01503         if (pDoc)
01504             pDoc->ForceRedraw(pSpread, m_BlobListBounds);       
01505         
01506         pBlob = (BevelBlob *)m_BevelBlobList.GetNext(pBlob);
01507     }
01508 
01509     GetApplication()->ServiceRendering();
01510 
01511     // render the blobs back on
01512     // BlobMgr->RenderToolBlobsOn(this, pSpread, &m_BlobListBounds);
01513 }
01514 
01515 
01516 /********************************************************************************************
01517 
01518 >   void BevelTool::ChangeContrastAndReRender(INT32 NewContrast);
01519 
01520     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01521     Created:    11/3/99
01522     Inputs:     The new angle
01523     Purpose:    Removes all blobs' angles and re-renders them with the new angle
01524 
01525 ********************************************************************************************/
01526 void BevelTool::ChangeContrastAndReRender(INT32 NewContrast)
01527 {
01528     if (m_BevelBlobList.IsEmpty())
01529         return;
01530 
01531     // get the blob manager
01532     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
01533     Spread * pSpread = Document::GetSelectedSpread();
01534 
01535     if (!BlobMgr || !pSpread)
01536         return;
01537 
01538     BevelBlob * pBlob = (BevelBlob *)m_BevelBlobList.GetHead();
01539 
01540     Document * pDoc = Document::GetCurrent();
01541 
01542     // set all the blob angles to the new value
01543     while (pBlob)
01544     {
01545         // change all the contrast settings for the nodes
01546         pBlob->ChangeContrast(NewContrast);
01547 
01548         if (pDoc)
01549         {
01550             pDoc->ForceRedraw(pSpread, pBlob->GetRect());
01551         }
01552         
01553         pBlob = (BevelBlob *)m_BevelBlobList.GetNext(pBlob);
01554     }
01555 
01556     GetApplication()->ServiceRendering();
01557 }
01558 
01559 
01560 /********************************************************************************************
01561 
01562 >   BOOL BevelTool::AreManyBevelTypes()
01563 
01564     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01565     Created:    26/7/99
01566     Returns:    TRUE if there are many different types of bevel in the selection,
01567                 FALSE if there is only one
01568     Purpose:    Queries the blob list to see if there are many different types of bevel
01569     SeeAlso:    
01570 
01571 ********************************************************************************************/
01572 
01573 BOOL BevelTool::AreManyBevelTypes()
01574 {
01575     if (m_BevelBlobList.IsEmpty())
01576         return FALSE;
01577 
01578     // run through the blob list, finding out if the selection contains bevelled
01579     // objects with diferent types
01580     BevelBlob * pItem = (BevelBlob *)m_BevelBlobList.GetHead();
01581 
01582     INT32 Type = -1;
01583 
01584     while (pItem)
01585     {
01586         NodeListItem * pNodeItem = (NodeListItem *)pItem->GetList()->GetHead();
01587 
01588         while (pNodeItem)
01589         {
01590             if (Type < 0)
01591             {
01592                 Type = ((NodeBevelController *)pNodeItem->pNode)->m_BevelType;
01593             }
01594             else
01595             {
01596                 if (Type != ((NodeBevelController *)pNodeItem->pNode)->m_BevelType)
01597                 {
01598                     return TRUE;
01599                 }
01600             }
01601 
01602             pNodeItem = (NodeListItem *)pItem->GetList()->GetNext(pNodeItem);
01603         }
01604 
01605         pItem = (BevelBlob *)m_BevelBlobList.GetNext(pItem);
01606     }
01607 
01608     // test for a bevelled node & a non-bevelled node being selected
01609     Range Rng(*(GetApplication()->FindSelection()));
01610     RangeControl rg = Rng.GetRangeControlFlags();
01611     rg.PromoteToParent = TRUE;
01612     Rng.SetRangeControl(rg);
01613 
01614     List BevelList;
01615     
01616     Node * pNode = Rng.FindFirst(FALSE);
01617 
01618     // scan the selection range trying to find any nodes which aren't bevelled  
01619     while (pNode)
01620     {
01621         BevelList.DeleteAll();
01622         
01623         BevelTools::GetAllNodesUnderNode(pNode, &BevelList, CC_RUNTIME_CLASS(NodeBevel));
01624         
01625         if (BevelList.IsEmpty())
01626         {
01627             BevelList.DeleteAll();
01628             return TRUE;
01629         }
01630         
01631         pNode = Rng.FindNext(pNode, FALSE);
01632     }
01633 
01634     BevelList.DeleteAll();
01635     return FALSE;
01636 }
01637 
01638 /********************************************************************************************
01639 
01640 >   BOOL BevelTool::AreManyBevelDirections()
01641 
01642     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01643     Created:    26/7/99
01644     Returns:    TRUE if there are many different directions of bevel in the selection,
01645                 FALSE if there is only one
01646     Purpose:    Queries the blob list to see if there are many different directions of bevel
01647     SeeAlso:    
01648 
01649 ********************************************************************************************/
01650 
01651 BOOL BevelTool::AreManyBevelDirections()
01652 {
01653     if (m_BevelBlobList.IsEmpty())
01654         return FALSE;
01655 
01656     BevelBlob * pItem = (BevelBlob *)m_BevelBlobList.GetHead();
01657 
01658     BOOL bOuter = FALSE;
01659     BOOL bFirst = TRUE;
01660 
01661     while (pItem)
01662     {
01663         NodeListItem * pNodeItem = (NodeListItem *)pItem->GetList()->GetHead();
01664 
01665         while (pNodeItem)
01666         {
01667             if (bFirst)
01668             {
01669                 bOuter = ((NodeBevelController *)pNodeItem->pNode)->m_bOuter;
01670                 bFirst = FALSE;
01671             }
01672             else
01673             {
01674                 if ((bOuter && !((NodeBevelController *)pNodeItem->pNode)->m_bOuter) ||
01675                     (!bOuter && ((NodeBevelController *)pNodeItem->pNode)->m_bOuter))
01676                 {
01677                     return TRUE;
01678                 }
01679             }
01680 
01681             pNodeItem = (NodeListItem *)pItem->GetList()->GetNext(pNodeItem);
01682         }
01683 
01684         pItem = (BevelBlob *)m_BevelBlobList.GetNext(pItem);
01685     }
01686 
01687     return FALSE;
01688 }
01689 
01690 /********************************************************************************************
01691 
01692 >   BOOL BevelTool::AreManyBevelIndents()
01693 
01694     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01695     Created:    26/7/99
01696     Returns:    TRUE if there are many different directions of bevel in the selection,
01697                 FALSE if there is only one
01698     Purpose:    Queries the blob list to see if there are many different directions of bevel
01699     SeeAlso:    
01700 
01701 ********************************************************************************************/
01702 
01703 BOOL BevelTool::AreManyBevelIndents()
01704 {
01705     if (m_BevelBlobList.IsEmpty())
01706         return FALSE;
01707 
01708     BevelBlob * pItem = (BevelBlob *)m_BevelBlobList.GetHead();
01709 
01710     MILLIPOINT Indent = 0;
01711     BOOL bFirst = TRUE;
01712     
01713     while (pItem)
01714     {
01715         NodeListItem * pNodeItem = (NodeListItem *)pItem->GetList()->GetHead();
01716 
01717         while (pNodeItem)
01718         {
01719             if (bFirst)
01720             {
01721                 Indent = ((NodeBevelController *)pNodeItem->pNode)->m_Indent;
01722                 bFirst = FALSE;
01723             }
01724             else
01725             {
01726                 if (Indent != ((NodeBevelController *)pNodeItem->pNode)->m_Indent)
01727                 {
01728                     return TRUE;
01729                 }
01730             }
01731 
01732             pNodeItem = (NodeListItem *)pItem->GetList()->GetNext(pNodeItem);
01733         }
01734 
01735         pItem = (BevelBlob *)m_BevelBlobList.GetNext(pItem);
01736     }
01737 
01738     return FALSE;
01739 }
01740 
01741 
01742 /********************************************************************************************
01743 
01744 >   BOOL BevelTool::AreManyBevelContrasts()
01745 
01746     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01747     Created:    26/7/99
01748     Returns:    TRUE if there are many different c of bevel in the selection,
01749                 FALSE if there is only one
01750     Purpose:    Queries the blob list to see if there are many different contrasts of bevel
01751     SeeAlso:    
01752 
01753 ********************************************************************************************/
01754 
01755 BOOL BevelTool::AreManyBevelContrasts()
01756 {
01757     if (m_BevelBlobList.IsEmpty())
01758         return FALSE;
01759 
01760     BevelBlob * pItem = (BevelBlob *)m_BevelBlobList.GetHead();
01761 
01762     INT32 Contrast = 0;
01763     BOOL bFirst = TRUE;
01764     
01765     while (pItem)
01766     {
01767         NodeListItem * pNodeItem = (NodeListItem *)pItem->GetList()->GetHead();
01768 
01769         while (pNodeItem)
01770         {
01771             if (bFirst)
01772             {
01773                 Contrast = ((NodeBevelController *)pNodeItem->pNode)->m_Contrast;
01774                 bFirst = FALSE;
01775             }
01776             else
01777             {
01778                 if (Contrast != ((NodeBevelController *)pNodeItem->pNode)->m_Contrast)
01779                 {
01780                     return TRUE;
01781                 }
01782             }
01783 
01784             pNodeItem = (NodeListItem *)pItem->GetList()->GetNext(pNodeItem);
01785         }
01786 
01787         pItem = (BevelBlob *)m_BevelBlobList.GetNext(pItem);
01788     }
01789 
01790     return FALSE;
01791 }
01792 
01793 /********************************************************************************************
01794 
01795 >   BOOL BevelTool::AreManyBevelLightAngles()
01796 
01797     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01798     Created:    26/7/99
01799     Returns:    TRUE if there are many different c of bevel in the selection,
01800                 FALSE if there is only one
01801     Purpose:    Queries the blob list to see if there are many different contrasts of bevel
01802     SeeAlso:    
01803 
01804 ********************************************************************************************/
01805 
01806 BOOL BevelTool::AreManyBevelLightAngles()
01807 {
01808     if (m_BevelBlobList.IsEmpty())
01809         return FALSE;
01810 
01811     BevelBlob * pItem = (BevelBlob *)m_BevelBlobList.GetHead();
01812 
01813     double LightAngle = 0;
01814     BOOL bFirst = TRUE;
01815     
01816     while (pItem)
01817     {
01818         NodeListItem * pNodeItem = (NodeListItem *)pItem->GetList()->GetHead();
01819 
01820         while (pNodeItem)
01821         {
01822             if (bFirst)
01823             {
01824                 LightAngle = ((NodeBevelController *)pNodeItem->pNode)->m_LightAngle;
01825                 bFirst = FALSE;
01826             }
01827             else
01828             {
01829                 if (LightAngle != ((NodeBevelController *)pNodeItem->pNode)->m_LightAngle)
01830                 {
01831                     return TRUE;
01832                 }
01833             }
01834 
01835             pNodeItem = (NodeListItem *)pItem->GetList()->GetNext(pNodeItem);
01836         }
01837 
01838         pItem = (BevelBlob *)m_BevelBlobList.GetNext(pItem);
01839     }
01840 
01841     return FALSE;
01842 }
01843 
01844 /********************************************************************************************
01845 
01846 >   BOOL BevelTool::AreManyBevelLightTilts()
01847 
01848     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01849     Created:    26/7/99
01850     Returns:    TRUE if there are many different c of bevel in the selection,
01851                 FALSE if there is only one
01852     Purpose:    Queries the blob list to see if there are many different contrasts of bevel
01853     SeeAlso:    
01854 
01855 ********************************************************************************************/
01856 
01857 BOOL BevelTool::AreManyBevelLightTilts()
01858 {
01859     if (m_BevelBlobList.IsEmpty())
01860         return FALSE;
01861 
01862     BevelBlob * pItem = (BevelBlob *)m_BevelBlobList.GetHead();
01863 
01864     double LightTilt = 0;
01865     BOOL bFirst = TRUE;
01866     
01867     while (pItem)
01868     {
01869         NodeListItem * pNodeItem = (NodeListItem *)pItem->GetList()->GetHead();
01870 
01871         while (pNodeItem)
01872         {
01873             if (bFirst)
01874             {
01875                 LightTilt = ((NodeBevelController *)pNodeItem->pNode)->m_Tilt;
01876                 bFirst = FALSE;
01877             }
01878             else
01879             {
01880                 if (LightTilt != ((NodeBevelController *)pNodeItem->pNode)->m_Tilt)
01881                 {
01882                     return TRUE;
01883                 }
01884             }
01885 
01886             pNodeItem = (NodeListItem *)pItem->GetList()->GetNext(pNodeItem);
01887         }
01888 
01889         pItem = (BevelBlob *)m_BevelBlobList.GetNext(pItem);
01890     }
01891 
01892     return FALSE;
01893 }
01894 
01895 /********************************************************************************************
01896 
01897 >   BOOL BevelTool::DoDrag()
01898 
01899     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01900     Created:    11/3/99
01901     Inputs:     
01902     Purpose:    Starts a drag operation
01903 
01904 ********************************************************************************************/
01905 /*
01906 BOOL BevelTool::DoDrag()
01907 {
01908     StartDrag(DRAGTYPE_AUTOSCROLL);
01909 
01910     return TRUE;
01911 }
01912 */
01913 
01914 /********************************************************************************************
01915 
01916 >   static INT32 BevelTool::CalculateBevelWidth(DocRect &br, DocCoord &PointerPos)
01917 
01918     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01919     Created:    11/9/99
01920     Inputs:     -
01921     Outputs:    -
01922     Returns:    The width of the bevel
01923     Purpose:    Calculates the bevel width for a given node given a pointer position
01924     SeeAlso:    -
01925 
01926 ********************************************************************************************/
01927 
01928 INT32 BevelTool::CalculateBevelWidth(DocRect &br, DocCoord &PointerPos)
01929 {
01930     DocCoord Centre = br.Centre();
01931 
01932     INT32 Width = 0;
01933 
01934     INT32 OffsetX = 0;
01935     INT32 OffsetY = 0;
01936 
01937     double dOffsetX = 0;
01938     double dOffsetY = 0;
01939 
01940     // try to work out the width of the contour
01941     // first, are we dragging inside or outside the bounding rect ?
01942     if (!br.ContainsCoord(PointerPos))
01943     {
01944         // outside the bounding rect
01945         if (PointerPos.x < br.lo.x && PointerPos.y >= br.lo.y &&
01946             PointerPos.y <= br.hi.y)
01947         {
01948             Width = br.lo.x - PointerPos.x;
01949         }
01950         else if (PointerPos.x > br.hi.x && PointerPos.y >= br.lo.y &&
01951             PointerPos.y <= br.hi.y)
01952         {
01953             Width = PointerPos.x - br.hi.x;
01954         }
01955         else if (PointerPos.x >= br.lo.x && PointerPos.x <= br.hi.x &&
01956             PointerPos.y < br.lo.y)
01957         {
01958             Width = br.lo.y - PointerPos.y;
01959         }
01960         else if (PointerPos.x >= br.lo.x && PointerPos.x <= br.hi.x &&
01961             PointerPos.y > br.hi.y)
01962         {
01963             Width = PointerPos.y - br.hi.y;
01964         }
01965         else if (PointerPos.x < br.lo.x && PointerPos.y < br.lo.y)
01966         {
01967             OffsetX = br.lo.x - PointerPos.x;
01968             OffsetY = br.lo.y - PointerPos.y;
01969             
01970             if (OffsetX > OffsetY)
01971             {
01972                 Width = OffsetX;
01973             }
01974             else
01975             {
01976                 Width = OffsetY;
01977             }
01978         }
01979         else if (PointerPos.x > br.hi.x && PointerPos.y < br.lo.y)
01980         {
01981             OffsetX = PointerPos.x - br.hi.x ;
01982             OffsetY = br.lo.y - PointerPos.y;
01983             
01984             if (OffsetX > OffsetY)
01985             {
01986                 Width = OffsetX;
01987             }
01988             else
01989             {
01990                 Width = OffsetY;
01991             }
01992         }
01993         else if (PointerPos.x > br.hi.x && PointerPos.y > br.hi.y)
01994         {
01995             OffsetX = PointerPos.x - br.hi.x ;
01996             OffsetY = PointerPos.y - br.hi.y;
01997             
01998             if (OffsetX > OffsetY)
01999             {
02000                 Width = OffsetX;
02001             }
02002             else
02003             {
02004                 Width = OffsetY;
02005             }
02006         }
02007         else if (PointerPos.x < br.lo.x && PointerPos.y > br.hi.y)
02008         {
02009             OffsetX = br.lo.x - PointerPos.x ;
02010             OffsetY = PointerPos.y - br.hi.y;
02011             
02012             if (OffsetX > OffsetY)
02013             {
02014                 Width = OffsetX;
02015             }
02016             else
02017             {
02018                 Width = OffsetY;
02019             }
02020         }
02021         
02022         Width = -Width;
02023     }
02024     else
02025     {
02026         // inside the bounding rect then
02027 
02028         // work out which quadrant to access
02029         dOffsetX = ((double)(PointerPos.x - Centre.x));
02030         dOffsetY = ((double)(PointerPos.y - Centre.y));
02031 
02032         INT32 RWidth = br.Width()/2;
02033         INT32 RHeight = br.Height()/2;
02034 
02035         if (RWidth > RHeight)
02036         {
02037             INT32 DistX = RWidth - RHeight;
02038 
02039             if (PointerPos.x < Centre.x + DistX &&
02040                 PointerPos.x > Centre.x - DistX)
02041             {
02042                 if (dOffsetY > 0)
02043                 {
02044                     Width = br.hi.y - PointerPos.y;
02045                 }
02046                 else
02047                 {
02048                     Width = PointerPos.y - br.lo.y;
02049                 }
02050             }
02051             else if (PointerPos.x > Centre.x + DistX)
02052             {
02053                 dOffsetX -= (double)DistX;
02054 
02055                 if (dOffsetY > 0)
02056                 {
02057                     if (dOffsetX > dOffsetY)
02058                     {
02059                         Width = br.hi.x - PointerPos.x;
02060                     }
02061                     else
02062                     {
02063                         Width = br.hi.y - PointerPos.y;
02064                     }
02065                 }
02066                 else
02067                 {
02068                     if (dOffsetX > -dOffsetY)
02069                     {
02070                         Width = br.hi.x - PointerPos.x;
02071                     }
02072                     else
02073                     {
02074                         Width = PointerPos.y - br.lo.y;
02075                     }
02076                 }
02077             }
02078             else
02079             {
02080                 dOffsetX += (double)DistX;
02081                 dOffsetX = -dOffsetX;
02082 
02083                 if (dOffsetY > 0)
02084                 {
02085                     if (dOffsetX > dOffsetY)
02086                     {
02087                         Width = PointerPos.x - br.lo.x;
02088                     }
02089                     else
02090                     {
02091                         Width = br.hi.y - PointerPos.y;
02092                     }
02093                 }
02094                 else
02095                 {
02096                     if (dOffsetX > -dOffsetY)
02097                     {
02098                         Width = PointerPos.x - br.lo.x;
02099                     }
02100                     else
02101                     {
02102                         Width = PointerPos.y - br.lo.y;
02103                     }
02104                 }
02105             }
02106         }
02107         else
02108         {
02109             INT32 DistY = RHeight - RWidth;
02110 
02111             if (PointerPos.y < Centre.y + DistY &&
02112                 PointerPos.y > Centre.y - DistY)
02113             {
02114                 if (dOffsetX > 0)
02115                 {
02116                     Width = br.hi.x - PointerPos.x;
02117                 }
02118                 else
02119                 {
02120                     Width = PointerPos.x - br.lo.x;
02121                 }
02122             }
02123             else if (PointerPos.y > Centre.y + DistY)
02124             {
02125                 dOffsetY -= (double)DistY;
02126 
02127                 if (dOffsetX > 0)
02128                 {
02129                     if (dOffsetY > dOffsetX)
02130                     {
02131                         Width = br.hi.y - PointerPos.y;
02132                     }
02133                     else
02134                     {
02135                         Width = br.hi.x - PointerPos.x;
02136                     }
02137                 }
02138                 else
02139                 {
02140                     if (dOffsetY > -dOffsetX)
02141                     {
02142                         Width = br.hi.y - PointerPos.y;
02143                     }
02144                     else
02145                     {
02146                         Width = PointerPos.x - br.lo.x;
02147                     }
02148                 }
02149             }
02150             else
02151             {
02152                 dOffsetY += (double)DistY;
02153                 dOffsetY = -dOffsetY;
02154 
02155                 if (dOffsetX > 0)
02156                 {
02157                     if (dOffsetY > dOffsetX)
02158                     {
02159                         Width = PointerPos.y - br.lo.y;
02160                     }
02161                     else
02162                     {
02163                         Width = br.hi.x - PointerPos.x;
02164                     }
02165                 }
02166                 else
02167                 {
02168                     if (dOffsetY > -dOffsetX)
02169                     {
02170                         Width = PointerPos.y - br.lo.y;
02171                     }
02172                     else
02173                     {
02174                         Width = PointerPos.x - br.lo.x;
02175                     }
02176                 }
02177             }
02178         }
02179     }
02180     
02181     return Width;
02182 }
02183 
02184 /********************************************************************************************
02185 
02186 >   void BevelTool::DragPointerMove(DocCoord PointerPos, ClickModifiers ClickMods,
02187         Spread * pSpread, BOOL bSolidDrag)
02188 
02189     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02190     Created:    11/3/99
02191     Inputs:     
02192     Purpose:    Handles the pointer moving inside of a drag
02193 
02194 ********************************************************************************************/
02195 /*
02196 void BevelTool::DragPointerMove(DocCoord PointerPos, ClickModifiers ClickMods,
02197         Spread * pSpread, BOOL bSolidDrag)
02198 {
02199 }
02200 */
02201 
02202 /********************************************************************************************
02203 
02204 >   void BevelTool::DragFinished(DocCoord PointerPos, ClickModifers ClickMods,
02205         Spread * pSpread, BOOL Success, BOOL bSolidDrag);
02206 
02207 
02208     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02209     Created:    11/3/99
02210     Inputs:     
02211     Purpose:    Ends the drag
02212 
02213 ********************************************************************************************/
02214 /*
02215 void BevelTool::DragFinished(DocCoord PointerPos, ClickModifers ClickMods,
02216         Spread * pSpread, BOOL Success, BOOL bSolidDrag)
02217 {
02218 }
02219 */
02220 
02221 
02222 
02223 
02224 
02225 
02226 
02227 
02228 
02229 /*
02230 IMPLEMENT_SIMPLE_MODULE( BevelModule, MODULEID_BEVEL, BevelTool, 
02231                             "Bevel Tool", "To bevel things", "DavidM" );
02232 */
02233 
02235 // Bevel blob implementation
02236 // DMc 10/3/99
02237 
02238 /********************************************************************************************
02239 
02240 >   BevelBlob::BevelBlob()
02241 
02242     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02243     Created:    11/3/99
02244     Inputs:     
02245     Purpose:    Bevel blob rendering class constructor
02246 
02247 ********************************************************************************************/
02248 BevelBlob::BevelBlob()
02249 {
02250     m_bDragging = FALSE;
02251     m_BlobAngle = 0;
02252     m_BevelNodeList.DeleteAll();
02253 }
02254 
02255 /********************************************************************************************
02256 
02257 >   BevelBlob::~BevelBlob()
02258 
02259     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02260     Created:    11/3/99
02261     Inputs:     
02262     Purpose:    Bevel blob destructor
02263 
02264 ********************************************************************************************/
02265 BevelBlob::~BevelBlob()
02266 {
02267     m_bDragging = FALSE;
02268     m_BlobAngle = 0;
02269     m_BevelNodeList.DeleteAll();
02270 }
02271 
02272 /********************************************************************************************
02273 
02274 >   BOOL BevelBlob::AddNode(NodeBevelController * pAttr)
02275 
02276     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02277     Created:    11/3/99
02278     Inputs:     The bevel controller node to add to my list
02279     Purpose:    Adds the bevel controller node to my list
02280     Returns:    TRUE for node added to the list, FALSE if it wasn't (e.g. if the
02281                 node added wasn't the same as the other attributes in my list
02282 
02283 ********************************************************************************************/
02284 BOOL BevelBlob::AddNode(NodeBevelController * pNode)
02285 {
02286     // continuity checks
02287     if (!pNode)
02288         return FALSE;
02289 
02290     if (!pNode->IsKindOf(CC_RUNTIME_CLASS(NodeBevelController)))
02291         return FALSE;
02292     
02293     NodeListItem * pListItem = NULL;
02294 //  Node * pParent = NULL;
02295 
02296     AttrBevelLightAngle * pAttr = NULL;
02297 
02298     pNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBevelLightAngle), 
02299         (NodeAttribute **)(&pAttr));
02300 
02301     INT32 LightAngle = 0;
02302 
02303     if (pAttr)
02304     {
02305         LightAngle = (INT32)pAttr->Value.m_LightAngle;
02306     }
02307     else
02308     {
02309         LightAngle = (INT32)((NodeBevelController *)pNode)->m_LightAngle;
02310     }
02311     
02312     // is our list empty ?
02313     if (m_BevelNodeList.IsEmpty())
02314     {
02315         // set the bounding rect for this blob
02316         // get the bounding rect
02317         m_BevelNodeListRect = pNode->GetBlobBoundingRect();
02318 
02319         // then add the attribute to our list
02320         pListItem = new NodeListItem;
02321         if (!pListItem)
02322         {
02323             ERROR3("Can't create list item");
02324             return FALSE;
02325         }
02326 
02327         pListItem->pNode = pNode;
02328 
02329         // set up our angle
02330         m_BlobAngle = LightAngle;
02331 
02332         m_BevelNodeList.AddTail(pListItem);
02333 
02334         return TRUE;
02335     }
02336 
02337     // check the angle against mine
02338     if (LightAngle != m_BlobAngle)
02339     {
02340         // we're not dealing with it
02341         return FALSE;
02342     }
02343     
02344     // then add the attribute to our list
02345     pListItem = new NodeListItem;
02346     if (!pListItem)
02347     {
02348         ERROR3("Can't create list item");
02349         return FALSE;
02350     }
02351 
02352     pListItem->pNode = pNode;
02353 
02354     m_BevelNodeListRect = m_BevelNodeListRect.Union(pNode->GetBlobBoundingRect());
02355 
02356     m_BevelNodeList.AddTail(pListItem);
02357 
02358     return TRUE;
02359 }
02360 
02361 /********************************************************************************************
02362 
02363 >   void BevelBlob::RenderBlob(RenderRegion * pRegion)
02364 
02365     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02366     Created:    11/3/99
02367     Inputs:     
02368     Purpose:    Renders the blobs
02369 
02370 ********************************************************************************************/
02371 void BevelBlob::RenderBlob(RenderRegion * pRegion)
02372 {
02373     // this is to prevent the clicking from accidentally rendering the blobs
02374     // twice
02375     pRegion->SaveContext();
02376 
02377     // calculate where to put the other blob
02378     pRegion->SetLineColour(COLOUR_NONE);
02379     pRegion->SetFillColour(COLOUR_BLACK);
02380 
02381     DocRect dr = m_BevelNodeListRect;
02382 
02383     DocCoord blob1((dr.hi.x + dr.lo.x) / 2, (dr.hi.y + dr.lo.y) / 2);
02384     DocCoord blob2;
02385 
02386 //  double dWidth = dr.Width() / 2;
02387 //  double dHeight = dr.Height() / 2;
02388 
02389     double angle = m_BlobAngle;
02390     TRACEUSER( "DavidM", _T("Blob angle %d\n"), m_BlobAngle);
02391 
02392     angle = (angle * 3.142) / 180.0;
02393 
02394     // make line 40 pixels INT32
02395     DocView * pView = DocView::GetSelected();
02396 
02397     if (!pView)
02398     {
02399         pRegion->RestoreContext();
02400         return;
02401     }
02402 
02403     double len = pView->GetScaledPixelWidth().MakeDouble() * 40.0;
02404 
02405     double dx = len * cos(angle);
02406     double dy = len * sin(angle);
02407     
02408     blob2.x = blob1.x - ((INT32)dx);
02409     blob2.y = blob1.y - ((INT32)dy);
02410     
02411     // render a blob in the centre
02412     // pRegion->DrawBlob(blob1, BT_SELECTED);
02413 
02414     m_BlobCentre = blob1;
02415 
02416     // create the arrow
02417     pRegion->SetLineColour(COLOUR_BLACK);
02418 
02419     pRegion->SetLineWidth((INT32)((pRegion->GetScaledPixelWidth()) * 2));
02420     
02421     // turn the capping to butt
02422     StartCapAttribute SCA;
02423     SCA.StartCap = LineCapButt;
02424     pRegion->SetStartCap(&SCA, FALSE);
02425 
02426     ArrowRec mArrow;
02427     mArrow.CreateStockArrow(SA_STRAIGHTARROW);
02428     mArrow.SetArrowSize(mArrow.GetArrowWidth() * 2);
02429 
02430     // draw the arrow head
02431     DocCoord ArrowBottom;
02432 
02433     pRegion->DrawLine(blob1, blob2);
02434 
02435     // draw the arrow head
02436     if (!pRegion->DrawArrowHead(mArrow, blob2, blob1))
02437         ERROR3("Cannot draw arrow");
02438 
02439     // draw the blob at the tip of the arrow head
02440 
02441     DocCoord blob3;
02442 
02443 
02444     len += (pView->GetScaledPixelWidth().MakeDouble()) * 15.0;
02445     
02446     dx = len * cos(angle);
02447     dy = len * sin(angle);
02448     
02449     blob3.x = blob1.x - ((INT32)dx);
02450     blob3.y = blob1.y - ((INT32)dy);
02451 
02452     pRegion->SetFillColour(COLOUR_RED);
02453     pRegion->SetLineColour(COLOUR_NONE);
02454     pRegion->DrawBlob(blob3, BT_SELECTED);  
02455 
02456     // get the blob's bounding rect and put it into our member variable
02457     if (GetApplication()->GetBlobManager())
02458     {
02459         GetApplication()->GetBlobManager()->GetBlobRect(blob3, &m_BlobDocRect);
02460     }
02461 
02462     pRegion->RestoreContext();
02463 }
02464 
02465 /********************************************************************************************
02466 
02467 >   BOOL BevelBlob::IsBlobValid()
02468 
02469     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02470     Created:    21/6/93
02471     Purpose:    Checks all attributes to see if I'm still valid
02472     SeeAlso:    BevelTool::Init
02473 
02474 ********************************************************************************************/
02475 BOOL BevelBlob::IsBlobValid()
02476 {
02477     NodeListItem * pItem = (NodeListItem *)m_BevelNodeList.GetHead();
02478 
02479     if (pItem)
02480     {
02481         if (pItem->pNode)
02482         {
02483             if (pItem->pNode->IsNodeHidden() ||
02484                 pItem->pNode->IsLocked() ||
02485                 !pItem->pNode->IsRenderable())
02486             {
02487                 return FALSE;
02488             }
02489         }
02490 
02491         pItem = (NodeListItem *)m_BevelNodeList.GetNext(pItem);
02492     }
02493 
02494     return TRUE;
02495 }
02496 
02497 /********************************************************************************************
02498 
02499 >   BOOL BevelBlob::HitTest(DocCoord dc)
02500 
02501     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02502     Created:    21/6/93
02503     Inputs:     The doccoord to test (usually the pointer position)
02504     Returns:    TRUE for click on blob, FALSE otherwise
02505     Purpose:    Checks if the doccoord passed in was inside my blob
02506     
02507 ********************************************************************************************/
02508 BOOL BevelBlob::HitTest(const DocCoord &dc)
02509 {
02510     return m_BlobDocRect.ContainsCoord(dc);
02511 }
02512 
02513 /********************************************************************************************
02514 
02515 >   void BevelBlob::CalculateAngle(const DocCoord &dc, BOOL bConstrain)
02516 
02517     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02518     Created:    21/6/93
02519     Inputs:     The doc-coord to recalculate the angle
02520                 bConstrain - whether to constrain the angle to levels of 45 degrees
02521     Returns:    =
02522     Purpose:    Calculates my angle so that the blob's direction arrow will be pointing
02523                 at the given point
02524     
02525 ********************************************************************************************/
02526 void BevelBlob::CalculateAngle(const DocCoord &dc, BOOL bConstrain)
02527 {
02528     // calculate the vector
02529     double dx = dc.x - m_BlobCentre.x;
02530     double dy = dc.y - m_BlobCentre.y;
02531 
02532     // normalise
02533     double len = sqrt(dx*dx + dy*dy);
02534 
02535     // check for valid length
02536     if (len <= 0)
02537         return;
02538 
02539     dx /= len;
02540     dy /= len;
02541 
02542     // calculate the angle given the cosine
02543     double angle = acos(dx);
02544 
02545     angle *= ((double)180) / (3.142);
02546 
02547     // alter the range depending on y
02548     angle = 180.0 - angle;
02549 
02550     if (dy > 0)
02551     {
02552         angle = 360.0 - angle;
02553     }
02554 
02555     // constrain if necessary
02556     if (bConstrain)
02557     {
02558         // Now get the constrain angle from the options
02559         // Doubles actually need document based units to work.
02560         double ConstrainAngle = 0.0;        // Angle stored in radians in the preference system
02561         INT32 ConstrainAngleInDegrees = 0;  // Angle displayed in degrees to the user
02562         BOOL ReadOk = Camelot.GetPrefValue(TEXT("Constraints"), TEXT("Constrain Angle"), &ConstrainAngle);
02563         // Set up the default option displayed
02564         if (ReadOk)
02565         {
02566             ConstrainAngleInDegrees = (INT32)((ConstrainAngle * 180.0/PI) + 0.5);   // Convert angle to degrees
02567             
02568             INT32 NewAngle = ((INT32)angle) / ConstrainAngleInDegrees;
02569             angle = NewAngle * ConstrainAngleInDegrees;
02570         }
02571     }       
02572 
02573     // ok, set my angle
02574     SetAngle((INT32)angle);
02575 }
02576 
02577 /********************************************************************************************
02578 
02579 >   void BevelBlob::SetAngle(INT32 Angle, BOOL bSetList = FALSE)
02580 
02581     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02582     Created:    21/6/93
02583     Inputs:     The angle to set and a flag to indicate whether I should change the light
02584                 angles of the nodes in my list or not
02585 
02586     Returns:    =
02587     Purpose:    Sets the blob's angle
02588     
02589 ********************************************************************************************/
02590 void BevelBlob::SetAngle(INT32 Angle, BOOL bSetList/* = FALSE*/)
02591 {
02592     // set my internal angle
02593     m_BlobAngle = Angle;
02594 
02595     NodeListItem * pItem = NULL;
02596 
02597     // if we are to change the list, then do this
02598     if (bSetList)
02599     {
02600         pItem = (NodeListItem *)m_BevelNodeList.GetHead();
02601 
02602         while (pItem)
02603         {
02604             if (pItem->pNode)
02605             {
02606                 if (pItem->pNode->IsKindOf(CC_RUNTIME_CLASS(NodeBevelController)))
02607                 {
02608 //                  ((NodeBevelController *)pItem->pNode)->m_LightAngle = Angle;
02609                     ((NodeBevelController *)pItem->pNode)->m_LightAngle = 360 - Angle;
02610                     ((NodeBevelController *)pItem->pNode)->ReleaseCached();
02611                 }
02612             }
02613 
02614             pItem = (NodeListItem *)m_BevelNodeList.GetNext(pItem);
02615         }
02616     }
02617 }
02618 
02619 /********************************************************************************************
02620 
02621 >   void BevelBlob::SetAngle(INT32 Angle, BOOL bSetList = FALSE)
02622 
02623     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02624     Created:    21/6/93
02625     Inputs:     The angle to set and a flag to indicate whether I should change the light
02626                 angles of the nodes in my list or not
02627 
02628     Returns:    =
02629     Purpose:    Sets the blob's angle
02630     
02631 ********************************************************************************************/
02632 void BevelBlob::SetTilt(INT32 Angle, BOOL bSetList/* = FALSE*/)
02633 {
02634     NodeListItem * pItem = NULL;
02635 
02636     NodeBevelController * pControl = NULL;
02637     NodeBevel           * pBevel    = NULL;
02638 
02639     // if we are to change the list, then do this
02640     if (bSetList)
02641     {
02642         pItem = (NodeListItem *)m_BevelNodeList.GetHead();
02643 
02644         while (pItem)
02645         {
02646             if (pItem->pNode)
02647             {
02648                 if (pItem->pNode->IsKindOf(CC_RUNTIME_CLASS(NodeBevelController)))
02649                 {
02650                     pControl = ((NodeBevelController *)pItem->pNode);
02651                     pControl->m_Tilt = Angle;
02652                     
02653                     pBevel = pControl->GetBevelNode();
02654 
02655                     if (pBevel)
02656                     {
02657                         pBevel->m_Tilt = Angle;
02658                     }
02659                 }
02660                 ((NodeBevelController *)pItem->pNode)->ReleaseCached();
02661             }
02662 
02663             pItem = (NodeListItem *)m_BevelNodeList.GetNext(pItem);
02664         }
02665     }
02666 }
02667 
02668 
02669 /********************************************************************************************
02670 
02671 >   void BevelBlobs::RenderNodes()
02672 
02673     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02674     Created:    2/11/99
02675     Inputs:     
02676 
02677     Returns:    =
02678     Purpose:    Renders the bevel nodes with my light angle
02679     
02680 ********************************************************************************************/
02681 void BevelBlob::RenderNodes()
02682 {
02683     TRACEUSER( "DavidM", _T("BevelBlob - render nodes\n"));
02684     
02685     NodeListItem * pItem = (NodeListItem *)m_BevelNodeList.GetHead();
02686 
02687     while (pItem)
02688     {
02689         ((NodeBevelController *)pItem->pNode)->ReRenderBevelBitmap((double)m_BlobAngle);
02690 
02691         pItem = (NodeListItem *)m_BevelNodeList.GetNext(pItem);
02692     }
02693 }
02694 
02695 /********************************************************************************************
02696 
02697 >   void BevelBlob::ChangeContrast(INT32 NewContrast)
02698 
02699     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02700     Created:    2/11/99
02701     Inputs:     
02702 
02703     Returns:    =
02704     Purpose:    Changes the contrast of all bevel nodes' attributes
02705     
02706 ********************************************************************************************/
02707 void BevelBlob::ChangeContrast(INT32 NewContrast)
02708 {
02709     NodeListItem * pItem = (NodeListItem *)m_BevelNodeList.GetHead();
02710 
02711     NodeBevelController * pControl = NULL;
02712 
02713 //  INT32 Count = 0;
02714 
02715 //  Document * pDoc = Document::GetCurrent();
02716     
02717     while (pItem)
02718     {
02719         pControl = (NodeBevelController *)pItem->pNode;
02720         pControl->m_Contrast = NewContrast;
02721         ((NodeBevelController *)pItem->pNode)->ReleaseCached();
02722 
02723         pItem = (NodeListItem *)m_BevelNodeList.GetNext(pItem);
02724     }
02725 }
02726 
02727 BOOL BevelTool::AreToolBlobsRenderedOnSelection()
02728 {
02729     return TRUE;
02730 }
02731 
02733 // Drag op for Bevelling - V similar to the one for contouring
02735 //  OpDragBevel
02736 //
02737 // This operation is responsible for creating and editing
02738 
02739 
02740 
02741 /********************************************************************************************
02742 
02743 >   OpDragBevel::OpDragBevel()
02744 
02745     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02746     Created:    11/10/94
02747     Purpose:    Constructor. 
02748 
02749 ********************************************************************************************/
02750 
02751 OpDragBevel::OpDragBevel()
02752 {
02753     m_pBarOp = NULL;
02754 
02755     m_bHasDragged = FALSE;
02756 
02757     m_pPathList = NULL;
02758     m_NumPaths = 0;
02759     m_pSetList = NULL;
02760     m_NumSets = 0;
02761     m_pPathOuterList = NULL;
02762     m_JoinType = RoundJoin;
02763     m_pPathLineWidthList = NULL;
02764 }
02765 
02766 /********************************************************************************************
02767 
02768 >   OpDragBevel::~OpDragBevel()
02769 
02770     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02771     Created:    11/10/94
02772     Purpose:    Destructor.
02773 
02774 ********************************************************************************************/
02775 
02776 OpDragBevel::~OpDragBevel()
02777 {
02778     if (m_pPathList)
02779     {
02780         delete [] m_pPathList;
02781     }   
02782 
02783     if (m_pSetList)
02784     {
02785         delete [] m_pSetList;
02786     }
02787 
02788     if (m_pPathOuterList)
02789     {
02790         delete [] m_pPathOuterList;
02791     }
02792 
02793     if (m_pPathLineWidthList)
02794     {
02795         delete [] m_pPathLineWidthList;
02796     }
02797 }
02798 
02799 /********************************************************************************************
02800 
02801 >   BOOL OpDragBevel::SetupDragInfo()
02802     
02803     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02804     Created:    2/12/99
02805     Inputs:     
02806     Outputs:    TRUE for success
02807     Returns:    -
02808     Purpose:    Sets up the drag information necessary to render the drag blobs
02809 
02810 ********************************************************************************************/
02811 BOOL OpDragBevel::SetupDragInfo()
02812 {
02813     Range Sel((*GetApplication()->FindSelection()));
02814 
02815     if (Sel.IsEmpty())
02816         return FALSE;
02817 
02818     RangeControl rg = Sel.GetRangeControlFlags();
02819     rg.PromoteToParent = TRUE;
02820     Sel.SetRangeControl(rg);
02821     
02822     // go through all nodes getting their inside bounding rects, and
02823     // building up the summed path
02824     CProfileBiasGain Profile;
02825 
02826     // find out how many paths we require
02827 
02828     Node * pNode = Sel.FindFirst();
02829 
02830     DocRect dr(0,0,0,0);
02831 
02832     // how many paths do we need ?
02833     m_NumPaths = 0;
02834 
02835     Node * pSubNode = NULL;
02836 
02837     // don't do needs parent nodes !!!
02838     // therefore, recurse through the subtree of every node in the selection
02839     // calling their can become a's individually
02840     m_NumSets = 0;
02841 
02842     // now, also test to see if there are any bevel nodes in the selection
02843     // if there are, ignore the non-bevelled nodes.
02844     BOOL bBevelNodesExist = FALSE;
02845 
02846     List BevelNodeList;
02847     BevelTools::BuildListOfSelectedNodes(&BevelNodeList, CC_RUNTIME_CLASS(NodeBevelController),TRUE);
02848 
02849     if (!BevelNodeList.IsEmpty())
02850     {
02851         bBevelNodesExist = TRUE;
02852     }
02853 
02854     BevelNodeList.DeleteAll();
02855 
02856     DocView * pView = DocView::GetCurrent();
02857     m_Flatness = 200.0;
02858 
02859     if (pView)
02860     {
02861         double ZoomFactor = pView->GetScaledPixelWidth().MakeDouble() / pView->GetPixelWidth().MakeDouble();
02862         m_Flatness *= ZoomFactor;
02863     }
02864 
02865     // we do a depth first search of the selection, calling DoBecomeA on the appropriate nodes
02866     // we do this because
02867     // a) we need to neglect all 'needs parent' nodes, which means calling doBecomeA on
02868     // just the top level selected nodes is insufficient
02869     // we also count how many 'sets' we need
02870     // a set defines a range in the path list (i.e. between path 2 and path 6) of paths
02871     // which need to be merged together before rendering
02872     // in building this set, we need to take into account when the nodes switch from one
02873     // contour controller node to another, as this obviously indicates the start of a new set
02874     // if any contour controller nodes exist, then we must ignore all nodes which are in the
02875     // selection but not part of a contour node. This is because in this case, when dragging,
02876     // no new contour nodes are created - the existing ones widths are changed
02877 
02878     Node* pLastController = NULL;
02879     Node* pParentController = NULL;
02880     AttrJoinType* pJoinType = NULL;
02881     AttrLineWidth* pLineWidth = NULL;
02882 
02883     BOOL bFoundJoinType = FALSE;
02884     UINT32 ObjectCount = 0;
02885 
02886     m_JoinType = RoundJoin;
02887     BecomeA MyTestBecomeA(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath));
02888     MyTestBecomeA.ResetCount();
02889 
02890     while (pNode)
02891     {
02892         pSubNode = pNode->FindFirstDepthFirst();
02893 
02894         // set up the parent controller from this node
02895         if (bBevelNodesExist)
02896         {
02897             pLastController = pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController));
02898 
02899             if(pLastController)
02900             {
02901                 ((NodeRenderableInk *)pLastController)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrJoinType), (NodeAttribute **)(&pJoinType));
02902 
02903                 if (pJoinType)
02904                 {
02905                     bFoundJoinType = TRUE;
02906                     m_JoinType = pJoinType->Value.JoinType;
02907                 }
02908             }
02909         }
02910     
02911         while (pSubNode)
02912         {
02913             if(pSubNode->IsABevel())
02914             {
02915                 ((NodeRenderableInk *)pSubNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrJoinType),
02916                     (NodeAttribute **)(&pJoinType));
02917                 
02918                 if (pJoinType)
02919                 {
02920                     bFoundJoinType = TRUE;
02921                     m_JoinType = pJoinType->Value.JoinType;
02922                 }
02923             }
02924 
02925             MyTestBecomeA.ResetCount();
02926             if (NodeCanBeDragBevelled(pSubNode, pNode, bBevelNodesExist) &&
02927                 pSubNode->CanBecomeA(&MyTestBecomeA))
02928             {
02929                 // test for whether we're just doing bevel nodes or all nodes
02930                 if (!bBevelNodesExist || 
02931                         pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController)) != NULL)
02932                     m_NumPaths += MyTestBecomeA.GetCount();
02933 
02934                 if (!bFoundJoinType)
02935                 {
02936                     ((NodeRenderableInk *)pSubNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrJoinType),
02937                         (NodeAttribute **)(&pJoinType));
02938                     
02939                     if (pJoinType)
02940                     {
02941                         bFoundJoinType = TRUE;
02942                         m_JoinType = pJoinType->Value.JoinType;
02943                     }
02944                 }
02945                 
02946                 // check for the number of sets needing to be increased - i.e. if
02947                 // the controller node of the new node is different to the last controller
02948                 if (bBevelNodesExist)
02949                 {
02950                     pParentController = pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController));
02951 
02952                     if (pParentController)
02953                     {
02954                         if (pParentController != pLastController &&
02955                             pLastController != NULL)
02956                         {
02957                             m_NumSets ++;
02958                         }
02959 
02960                         pLastController = pParentController;
02961                     }
02962                 }
02963             }
02964 
02965             pSubNode = pSubNode->FindNextDepthFirst(pNode);
02966         }
02967 
02968         m_NumSets ++;
02969 
02970         pNode = Sel.FindNext(pNode);
02971     }
02972 
02973     // increase the number of sets by 1
02974     m_NumSets++;
02975 
02976     ERROR2IF(m_NumPaths == 0, FALSE, "Nothing to bevel");
02977 
02978     if (m_pPathList)
02979         delete [] m_pPathList;
02980 
02981     if (m_pSetList)
02982         delete [] m_pSetList;
02983 
02984     if (m_pPathOuterList)
02985         delete [] m_pPathOuterList;
02986 
02987     if (m_pPathLineWidthList)
02988         delete [] m_pPathLineWidthList;
02989 
02990     // each path has whether the object it came from was an inner or an outer bevel
02991     // or not
02992     ALLOC_WITH_FAIL(m_pPathOuterList, new BOOL[m_NumPaths], this);
02993     ALLOC_WITH_FAIL(m_pPathList, new Path[m_NumPaths], this);
02994     ALLOC_WITH_FAIL(m_pPathLineWidthList, new LineWidthAttribute*[m_NumPaths], this);
02995     ALLOC_WITH_FAIL(m_pSetList, new UINT32[m_NumSets], this);
02996 
02997     UINT32 i;
02998     for (i = 0; i < m_NumPaths; i++)
02999     {
03000         m_pPathList[i].Initialise();
03001         m_pPathOuterList[i] = TRUE;
03002         m_pPathLineWidthList[i] = NULL;
03003     }
03004 
03005     // Make sure we have a valid pOurDoc as Contouring moulds with bitmap fills go bang!
03006     pOurDoc = Document::GetCurrent();
03007 
03008     // sum all paths together in the range
03009     ContourDragBecomeA MyBecomeA(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), this, FALSE,
03010         m_pPathList, m_NumPaths);
03011 
03012     pNode = Sel.FindFirst();
03013 
03014     // don't do needs parent nodes !!!
03015     // therefore, recurse through the subtree of every node in the selection
03016     // calling their do become a's individually
03017 
03018     NodeBevelController * pControl = NULL;
03019 
03020     UINT32 SetCount = 0;
03021     NodeAttribute* pAttr = NULL;
03022     BOOL IsVariableWidth = FALSE;
03023     Node* pNodePath = NULL;
03024     UINT32 StartCount = 0;
03025     UINT32 x = 0;
03026 
03027     while (pNode)
03028     {
03029         pSubNode = pNode->FindFirstDepthFirst();
03030 
03031         // set up the parent controller from this node
03032         if (bBevelNodesExist)
03033             pLastController = pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController));
03034 
03035         // start a new set
03036         m_pSetList[SetCount++] = MyBecomeA.GetCount();
03037 
03038         ERROR3IF(SetCount >= m_NumSets, "Number of sets doesn't match");        
03039 
03040         while (pSubNode)
03041         {
03042 //          MyTestBecomeA.ResetCount();
03043             if (NodeCanBeDragBevelled(pSubNode, pNode, bBevelNodesExist) &&
03044                 pSubNode->CanBecomeA(&MyTestBecomeA) &&
03045                 pSubNode->IsAnObject())
03046             {
03047                 // check for the number of sets needing to be increased - i.e. if
03048                 // the controller node of the new node is different to the last controller
03049                 if (bBevelNodesExist)
03050                 {
03051                     pParentController = pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController));
03052 
03053                     if (pParentController)
03054                     {
03055                         if (pParentController != pLastController && pLastController != NULL)
03056                             m_pSetList[SetCount++] = MyBecomeA.GetCount(); // start a new set
03057 
03058                         pLastController = pParentController;
03059                     }
03060                 }
03061 
03062                 // do the DoBecomeA
03063                 if (!bBevelNodesExist || pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController)) != NULL)
03064                 {
03065                     // get the start path count
03066                     StartCount = MyBecomeA.GetCount();
03067                     
03068                     // find out if we have a parent bevel controller node or not
03069                     pControl = (NodeBevelController *)pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController));
03070 
03071                     pLineWidth = NULL;
03072                     ((NodeRenderableInk *)pSubNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrLineWidth),(NodeAttribute**)(&pLineWidth));
03073 
03074                     // do the become A
03075                     if (!pSubNode->IsNodePath())
03076                         pSubNode->DoBecomeA(&MyBecomeA);
03077                     else
03078                     {
03079                         // make the node out of the path first
03080                         pNodePath = ((NodePath *)pSubNode)->MakeNodePathFromAttributes(m_Flatness,NULL,FALSE,FALSE);
03081 
03082                         if(pNodePath)
03083                         {
03084                             pNodePath->DoBecomeA(&MyBecomeA);
03085                             delete pNodePath;
03086                         }
03087                     }
03088                                         
03089                     if(((NodePath*)pSubNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrVariableWidth),&pAttr))
03090                         IsVariableWidth = (pAttr && ((VariableWidthAttrValue*)pAttr->GetAttributeValue())->GetWidthFunction() != NULL);
03091 
03092                     if (pLineWidth && !IsVariableWidth)
03093                         m_pPathLineWidthList[ObjectCount] = &pLineWidth->Value;
03094 
03095                     ObjectCount++;
03096 
03097                     // find out if my parent controller is an inner or an outer,
03098                     // and store the value for each path which has just been created
03099                     if (pControl)
03100                     {
03101                         // find the applied join type attribute for this particular series of
03102                         for (x = StartCount; x < MyBecomeA.GetCount(); x++)
03103                         {
03104                             if (!pControl->m_bOuter)
03105                                 m_pPathOuterList[x] = FALSE;
03106                         }
03107                     }
03108                 }
03109             }
03110 
03111             pSubNode = pSubNode->FindNextDepthFirst(pNode);
03112         }
03113 
03114         pNode = Sel.FindNext(pNode);
03115     }
03116 
03117     // put the last set node in
03118     m_pSetList[SetCount] = MyBecomeA.GetCount();
03119 
03120     m_SelRect.MakeEmpty();
03121 
03122     // calculate the rect from the paths
03123     for (i = 0 ; i < m_NumPaths; i++)
03124     {
03125         if (m_pPathList[i].GetNumCoords() > 2)
03126         {
03127             m_pPathList[i].GetTrueBoundingRect(&dr);
03128             m_SelRect = m_SelRect.Union(dr);
03129         }
03130     }
03131 
03132     // reduce by the blob rect
03133     BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
03134 
03135     if(pBlobMgr)
03136         m_SelRect.Inflate(pBlobMgr->GetBlobSize());
03137 
03138     return TRUE;
03139 }
03140 
03141 
03142 
03143 /********************************************************************************************
03144 
03145 >   BOOL OpDragBevel::NodeCanBeDragBevelled(Node* pSubNode,
03146                                             Node* pNode,
03147                                             BOOL bBevelNodesExist)
03148     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03149     Created:    10/05/2000
03150     Inputs:     pSubNode    the node which we are considering.
03151                 pNode       the node on which the drag is actually occurring.
03152                             note that this should be an ancestor of pSubNode in the tree.
03153                 bBevelNodesExist    TRUE if we're editting existing bevels,
03154                                     FALSE if we're creating new bevels.
03155 
03156     Returns:    TRUE if pSubNode should have its outline taken into account when the user
03157                 creates or changes a bevel by dragging.
03158                 FALSE if not.
03159 
03160     Purpose:    Helper function for SetupDragInfo(), which encapsulates a test for whether
03161                 a node's outline should be considered when dragging bevels.
03162                 There are a number of rules for exactly which nodes should be considered;
03163                 examine the body of this function for details.
03164     Errors:     ERROR3 in DEBUG if any parameters are NULL.
03165                 *Will* bomb out with AV's if NULL parameters are passed, so don't!
03166     See also:   SetupDragInfo()
03167 
03168 ********************************************************************************************/
03169 BOOL OpDragBevel::NodeCanBeDragBevelled(Node* pSubNode,
03170                                             Node* pNode,
03171                                             BOOL bBevelNodesExist)
03172 {
03173     // subnode must not require a parent node to exist.
03174     BOOL    ok = !pSubNode->NeedsParent(NULL);
03175 
03176     // subnode must be a NodeRenderableInk.
03177     if (ok) ok = pSubNode->IsAnObject();
03178 
03179     // subnode must not be any compound node other than the exceptions listed here.
03180     if (ok) ok = !pSubNode->IsCompound() || pSubNode->IsABaseTextClass() ||
03181                     pSubNode->IS_KIND_OF(NodeMould) || pSubNode->IsANodeClipViewController();
03182 
03183     // subnode must not reside within a NodeMould.
03184     if (ok) ok = (pSubNode->FindParent(CC_RUNTIME_CLASS(NodeMould)) == NULL);
03185 
03186     // ClipView tests.
03187     if (ok)
03188     {
03189         // if bevels do exist, then subnode must not reside within a ClipView group
03190         // which has, or whose parents have, a bevel currently applied, and which is,
03191         // or lies beneath, the bevel's object node.
03192         if (bBevelNodesExist)
03193         {
03194             Node* pNCC = pSubNode->FindParent(CC_RUNTIME_CLASS(NodeBevelController));
03195             if (pNCC != NULL)
03196             {
03197                 Node* pNodeTest = pNCC;
03198                 while (pNodeTest != pNode && pNodeTest != NULL)
03199                     pNodeTest = pNodeTest->FindParent();
03200                 if (pNodeTest != NULL)
03201                 {
03202                     // pNCC is, or is a child of, pNode.
03203                     // now we just need to find out whether pSubNode and pNCC
03204                     // have a NCVC in between.
03205                     ok = !pSubNode->IsFamily(CC_RUNTIME_CLASS(NodeClipViewController), pNCC);
03206                 }
03207             }
03208         }
03209 
03210         // if no bevels exist yet, then subnode must not reside within a ClipView group
03211         // which either is, or lies beneath, the bevel's object node.
03212         else
03213             ok = !pSubNode->IsFamily(CC_RUNTIME_CLASS(NodeClipViewController), pNode);
03214     }
03215 
03216     return ok;
03217 
03218 /*
03219  *  This comment holds the unexpanded version of the above tests,
03220  *  apart from the ClipView test for when bevels do exist.
03221  *
03222     return !pSubNode->NeedsParent(NULL) && 
03223             (!pSubNode->IsCompound() || pSubNode->IsABaseTextClass() || 
03224             pSubNode->IS_KIND_OF(NodeMould) || pSubNode->IsANodeClipViewController()) && 
03225             pSubNode->IsAnObject() &&
03226             pSubNode->FindParent(CC_RUNTIME_CLASS(NodeMould)) == NULL &&
03227             (bBevelNodesExist || 
03228             !pSubNode->IsFamily(CC_RUNTIME_CLASS(NodeClipViewController), pNode))
03229             ;
03230 */
03231 }
03232 
03233 
03234 
03235 /********************************************************************************************
03236 
03237 >   void OpDragBevel::AlterPointerPosToAccountForBlob(DocCoord * pPoint)
03238 
03239     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03240     Created:    11/10/94
03241     Inputs:     The point to change
03242     Purpose:    Ensures that dragging back onto a blob returns you to the original
03243                 contour value
03244 
03245 ********************************************************************************************/
03246 void OpDragBevel::AlterPointerPosToAccountForBlob(DocCoord * pPoint)
03247 {
03248     DocCoord PPos;
03249 
03250     DocCoord Offset;
03251 
03252     double Scale = 0;
03253 
03254     BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
03255 
03256     double BlobSize = 0;
03257 
03258     if (pBlobMgr)
03259         BlobSize = pBlobMgr->GetBlobSize()/2;
03260     else
03261         return;
03262     
03263     if (m_BlobRect.IsValid())
03264     {
03265         DocCoord Centre = m_BlobRect.Centre();
03266             
03267         if (m_BlobRect.ContainsCoord(*pPoint))
03268         {
03269             
03270             pPoint->x = Centre.x;
03271             pPoint->y = Centre.y;
03272         }
03273         else
03274         {
03275             // move the pointer appropriately so that the blob is always
03276             // the same value
03277             
03278             // first find the point which is the intersection between the line from
03279             // the centre of the blob to the point on the outside of the blob
03280             PPos.x = pPoint->x - Centre.x;
03281             PPos.y = pPoint->y - Centre.y;
03282 
03283             if (abs(PPos.x) > abs(PPos.y))
03284             {
03285                 Scale = ((double)abs(PPos.y)) / ((double)abs(PPos.x));
03286                 Scale *= BlobSize;
03287 
03288                 if (PPos.x > 0)
03289                 {
03290                     Offset.x = (INT32)BlobSize;
03291                 }
03292                 else
03293                 {
03294                     Offset.x = (INT32)-BlobSize;
03295                 }
03296 
03297                 if (PPos.y > 0)
03298                 {
03299                     Offset.y = (INT32)Scale;
03300                 }
03301                 else
03302                 {
03303                     Offset.y = (INT32)-Scale;
03304                 }
03305             }
03306             else
03307             {
03308                 Scale = ((double)PPos.x) / ((double)PPos.y);
03309                 Scale *= BlobSize;
03310 
03311                 if (PPos.y > 0)
03312                 {
03313                     Offset.y = (INT32)BlobSize;
03314                 }
03315                 else
03316                 {
03317                     Offset.y = (INT32)-BlobSize;
03318                 }
03319 
03320                 if (PPos.x > 0)
03321                 {
03322                     Offset.x = (INT32)Scale;
03323                 }
03324                 else
03325                 {
03326                     Offset.x = (INT32)-Scale;
03327                 }
03328             }
03329 
03330             pPoint->x -= Offset.x;
03331             pPoint->y -= Offset.y;
03332         }
03333     }
03334 }
03335 
03336 /********************************************************************************************
03337 
03338 >   BOOL OpDragBevel::DoDrag(BevelInfoBarOp * pBar, DocCoord &PointerPos,
03339                                 BOOL bDragOnBlob, DocRect *pBlobRect)
03340     
03341     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03342     Created:    2/12/99
03343     Inputs:     The info bar starting the drag, and the pointer position when the drag is 
03344                 started.
03345                 bDragOnBlob = TRUE if the drag started on a tool blob
03346     Outputs:    -
03347     Returns:    -
03348     Purpose:    This starts a drag that may lead to a contour.
03349                 The DragFinished() method will do the hard work of contouring if it can be done.
03350 
03351 ********************************************************************************************/
03352 
03353 BOOL OpDragBevel::DoDrag(BevelInfoBarOp * pBar, DocCoord &PointerPos, BOOL bDragOnBlob,
03354                          DocRect *pBlobRect)
03355 {   
03356     // snap the pointer position
03357     DocView *pView = DocView::GetCurrent();
03358     Spread * pSpread = Document::GetSelectedSpread();
03359 
03360     if (pView && pSpread)
03361     {
03362         pView->Snap(pSpread, &PointerPos, FALSE, TRUE);
03363     }
03364     
03366     //
03367     // This added by Karim MacDonald 17/12/1999, to fix a bug, whereby starting a bevel
03368     // drag whilst a text char was sub-selected, then dragging with selector tool, caused
03369     // and error.
03370     //
03371 
03372     // if the drag was started on a blob, ensure any text in the selection is valid for this.
03373     if (bDragOnBlob)
03374         GetApplication()->FindSelection()->MakePartialSelectionWhole();
03375 
03376     // otherwise quit - can't do this drag unless it's from a blob.
03377     else
03378         return FALSE;
03379     //
03381 
03382     // check whether the selection allows the drag
03383     // if so, just treat it like a non-blob drag
03384     /*
03385     OpCreateBevel * pCreateOp = NULL;
03386     ALLOC_WITH_FAIL(pCreateOp, new OpCreateBevel, this);
03387 
03388     ObjChangeFlags flgs(FALSE, FALSE, FALSE, FALSE);
03389     flgs.MultiReplaceNode = TRUE;
03390     ObjChangeParam OP(OBJCHANGE_STARTING, flgs, NULL, pCreateOp, OBJCHANGE_CALLEDBYOP);
03391 
03392     if (!GetApplication()->FindSelection()->AllowOp(&OP) && bDragOnBlob)
03393     {
03394         delete pCreateOp;
03395         return TRUE;
03396     }           
03397 
03398     delete pCreateOp;
03399     */
03400     
03401     m_pBarOp = pBar;
03402     m_bHasDragged = FALSE;
03403     m_LastPointerPos = PointerPos;
03404     m_ThisPointerPos = PointerPos;  
03405 
03406     if (pBlobRect)
03407         m_BlobRect = *pBlobRect;
03408     else
03409         m_BlobRect = DocRect(0,0,0,0);
03410 
03411     m_bDragStartedOnBlob = bDragOnBlob;
03412 
03413     // if there's no selection then forget it !
03414     if (!GetApplication()->FindSelection())
03415         return FALSE;
03416 
03417     // decide what the start value for the drag will be
03418     List BevelList;
03419     BevelTools::BuildListOfSelectedNodes(&BevelList, CC_RUNTIME_CLASS(NodeBevelController));
03420 
03421     if (BevelList.IsEmpty())
03422     {
03423         m_OriginalWidth = 0;
03424     }
03425     else
03426     {
03427         NodeListItem * pItem = (NodeListItem *)BevelList.GetHead();
03428 
03429         m_OriginalWidth = ((NodeBevelController *)(pItem->pNode))->m_Indent;
03430 
03431         if (((NodeBevelController *)(pItem->pNode))->m_bOuter)
03432             m_OriginalWidth = -m_OriginalWidth;
03433 
03434         BevelList.DeleteAll();
03435     }
03436 
03437     // Tell the Dragging system that we need drags to happen
03438     StartDrag( DRAGTYPE_AUTOSCROLL );
03439 
03440     if (bDragOnBlob)
03441     {
03442         if (!SetupDragInfo())
03443         {
03444             EndDrag();
03445             return FALSE;
03446         }
03447         
03448         DocCoord BlobCentre(pBlobRect->Centre());
03449 
03450         m_LastPointerPos = BlobCentre;
03451         m_ThisPointerPos = BlobCentre;
03452 
03453         // calculate the width
03454         INT32 Width = ContourTool::CalculateContourWidth(m_SelRect, 
03455             BlobCentre);
03456 
03457         m_StartDragWidth = Width;
03458     }
03459     
03460     return TRUE;
03461 }
03462 
03463 
03464 
03465 
03466 /********************************************************************************************
03467 
03468 >   void OpDragBevel::DragPointerMove( DocCoord PointerPos, ClickModifiers ClickMods, 
03469                                    Spread* pSpread, BOOL bSolidDrag)
03470     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03471     Created:    25/11/99
03472     Inputs:     PointerPos - The current position of the mouse in Doc Coords
03473                 ClickMods  - Which key modifiers are being pressed
03474                 pSpread    - The spread that the mouse pointer is over
03475     Purpose:    Takes the pointer position and calculates the new dragged outline of the EORd
03476                 bounding box
03477     SeeAlso:    ClickModifiers
03478 
03479 ********************************************************************************************/
03480 
03481 void OpDragBevel::DragPointerMove( DocCoord PointerPos, ClickModifiers ClickMods, 
03482                                    Spread* pSpread, BOOL bSolidDrag)
03483 {
03484     ERROR3IF(!m_pBarOp, "No info bar op");
03485 
03486     // snap the pointer position
03487     DocView *pView = DocView::GetCurrent();
03488 
03489     if (pView && pSpread)
03490     {
03491         pView->Snap(pSpread, &PointerPos, FALSE, TRUE);
03492     }
03493 
03494     if (PointerPos == m_LastPointerPos)
03495         return;
03496 
03497     if (!m_bDragStartedOnBlob)
03498     {
03499         m_bHasDragged = TRUE;
03500         return;
03501     }
03502 
03503     // render the drag blobs off first
03504     if (m_bHasDragged)
03505         RenderDragBlobs(m_SelRect, pSpread, bSolidDrag);
03506 
03507     m_bHasDragged = TRUE;
03508     m_LastPointerPos = PointerPos;
03509     m_ThisPointerPos = PointerPos;  
03510 
03511     BevelTool::DisplayStatusBarHelp(_R(IDS_BEVELDRAGSTATUSHELP));
03512     
03513     // calculate the contour width & set the infobar
03514     INT32 Width = (ContourTool::CalculateContourWidth(m_SelRect, PointerPos) - m_StartDragWidth) 
03515         + m_OriginalWidth;
03516 
03517     RenderDragBlobs(m_SelRect, pSpread, bSolidDrag);
03518 
03519     if (Width < 0)
03520     {
03521         // outer contour
03522         m_pBarOp->SetBoolGadgetSelected(_R(IDC_BTN_BEVELOUTER), TRUE);
03523         m_pBarOp->SetBoolGadgetSelected(_R(IDC_BTN_BEVELINNER), FALSE);
03524     }
03525     else
03526     {
03527         // inner contour
03528         m_pBarOp->SetBoolGadgetSelected(_R(IDC_BTN_BEVELOUTER), FALSE);
03529         m_pBarOp->SetBoolGadgetSelected(_R(IDC_BTN_BEVELINNER), TRUE);
03530     }
03531 
03532     m_pBarOp->PaintGadgetNow(_R(IDC_BTN_BEVELINNER));
03533     m_pBarOp->PaintGadgetNow(_R(IDC_BTN_BEVELOUTER));
03534 
03535     m_pBarOp->m_Depth = abs(Width);
03536     m_pBarOp->SliderUpdate(FALSE, FALSE);
03537 }
03538 
03539 
03540 
03541 /********************************************************************************************
03542 
03543 >   void OpDragBevel::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 
03544                                 Spread* pSpread, BOOL Success, BOOL bSolidDrag)
03545 
03546     
03547     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03548     Created:    11/10/94
03549     Inputs:     PointerPos - The position of the mouse at the end of the drag
03550                 ClickMods - the key modifiers being pressed
03551                 pSpread - The spread that the drag finished on
03552                 Success - TRUE if the drag was terminated properly, FALSE if it
03553                 was ended with the escape key being pressed
03554     Purpose:    Ends the drag.
03555                 Either creates a new grid or resizes GridClicked depending on the state of affairs
03556                 when the drag started
03557     SeeAlso:    ClickModifiers
03558 
03559 ********************************************************************************************/
03560 
03561 void OpDragBevel::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 
03562                                 Spread* pSpread, BOOL Success, BOOL bSolidDrag)
03563 {
03564     // snap the pointer position
03565     DocView *pView = DocView::GetCurrent();
03566 
03567     if (pView && pSpread)
03568     {
03569         pView->Snap(pSpread, &PointerPos, FALSE, TRUE);
03570     }
03571 
03572     if (Tool::GetCurrentID() != TOOLID_BEVELTOOL)
03573         return;
03574 
03575     //  Karim 11/04/2000
03576     //  Commented out - this test shouldn't be needed, as unless the current tool is derived
03577     //  from BevelTool, testing the tool's ID as above should always give the same result.
03578 //  if (!Tool::GetCurrent()->IS_KIND_OF(BevelTool))
03579 //      return;
03580     
03581     BevelTool * pTool = (BevelTool *)Tool::GetCurrent();
03582     
03583     // End the drag and the op
03584 //  BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
03585 
03586     EndDrag();
03587 
03588     // added 20/12/1999 by Karim MacDonald.
03589     // if the drag did not start on a blob, we quit now.
03590     if (!m_bDragStartedOnBlob)
03591         return;
03592 
03593     // calculate the contour width & set the infobar
03594     INT32 Width = (ContourTool::CalculateContourWidth(m_SelRect, PointerPos) - m_StartDragWidth) 
03595         + m_OriginalWidth;
03596 
03597     // if we've not dragged, then do nothing
03598     if (!m_bHasDragged)
03599         return;
03600 
03601     if (m_pBarOp)
03602         m_pBarOp->UpdateState();
03603 
03604     m_bHasDragged = FALSE;
03605 
03606     if (!pSpread)
03607         pSpread = Document::GetSelectedSpread();
03608 
03609     // render the drag blobs off
03610     RenderDragBlobs(m_SelRect, pSpread, bSolidDrag);    
03611 
03612     // create the bevel, or change its width
03613     if (Success)
03614     {
03615         if (pTool)
03616         {
03617             pTool->RenderToolBlobs(pSpread, NULL);
03618             pTool->SetBlobRendering(FALSE);
03619         }
03620         
03621         // set up the bevel creation param
03622         BevelInfo Info;
03623 
03624         Info.m_bCreateNewBevels = FALSE;
03625 
03626         Info.m_Indent = abs(Width);
03627         Info.m_bBevelIndentChanged = TRUE;
03628         
03629         if (Width < 0)
03630         {
03631             Info.m_bOuter = TRUE;
03632         }
03633         else
03634         {
03635             Info.m_bOuter = FALSE;
03636         }
03637 
03638         Info.m_bBevelDirectionChanged = (m_OriginalWidth > 0 && Width < 0) || (m_OriginalWidth < 0 && Width > 0);
03639 
03640         // standard attributes
03641         Info.m_BevelType = 0;
03642         Info.m_Contrast = 50;
03643         Info.m_LightAngle = 300;
03644 
03645         OpDescriptor * pOpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpCreateBevel));
03646         
03647         if (pOpDesc)
03648         {
03649             pOpDesc->Invoke(&Info);
03650         }
03651         
03652         // put the tool blobs back on
03653         if (pTool)
03654         {
03655             pTool->SetBlobRendering(TRUE);
03656             pTool->SetupBlobList();
03657             pTool->RenderToolBlobs(pSpread, NULL);
03658         }
03659     }
03660 
03661     delete [] m_pPathList;
03662     m_pPathList = NULL;
03663 
03664     delete [] m_pSetList;
03665     m_pSetList = NULL;
03666 
03667     delete [] m_pPathOuterList;
03668     m_pPathOuterList = NULL;
03669 }
03670 
03671 /********************************************************************************************
03672 
03673 >   void OpDragBevel::RenderDragBlobs(MILLIPOINT Width,Spread* pSpread,
03674                                     BOOL bKeepDirections)
03675 
03676     Author:     Mark_Howitt (Xara Group Ltd) <camelotdev@xara.com> - rewritten Dave Mc code 06/06/00
03677     Created:    11/10/94
03678     Inputs:     Width   - The width of the bevel to render the drag blobs of
03679                 pSpread - The spread that the drawing will happen on
03680                 bKeepDirections - Whether to maintian each set's direction (either inner
03681                                   or outer) or to render the blobs with the signed value
03682                                   passed in.
03683     Purpose:    Draws an EORed outline of distance Width away from the original objects!
03684 
03685 ********************************************************************************************/
03686 void OpDragBevel::RenderDragBlobs(MILLIPOINT Width,Spread* pSpread, BOOL bKeepDirections)
03687 {
03688     bool Outer = false;
03689     if(Width < 0)
03690         Outer = true;
03691 
03692     if (bKeepDirections)
03693         Width = abs(Width);
03694 
03695     if (m_pPathLineWidthList == NULL || m_pPathList == NULL || m_pSetList == NULL)
03696     {
03697         ERROR3("No list defined");
03698         return;
03699     }
03700 
03701     // Allocate Two Path Arrays to hold the outline information
03702     // SetPathList holds the all the paths inside compound nodes
03703     Path * pSetPathList = NULL;
03704     ALLOC_WITH_FAIL(pSetPathList, new Path[m_NumSets-1], this);
03705 
03706     // DrawPAthList holds the path that has been expanded by the width
03707     Path * pDrawPathList = NULL;
03708     ALLOC_WITH_FAIL(pDrawPathList, new Path[m_NumPaths], this);
03709 
03710     // Two local paths to hold intermediate path steps
03711     Path CopyPath;
03712     Path TempPath;
03713     CopyPath.Initialise();
03714     TempPath.Initialise();
03715 
03716     DocRect DrawBounds(0,0,0,0);
03717     DocRect dri(0,0,0,0);
03718     DocRect drj(0,0,0,0);
03719     UINT32 j = 0;
03720     INT32 PathWidth = 0;
03721 
03722     //  Get the current Join Style
03723     JoinStyles JoinS = (m_JoinType==MitreJoin) ? JOIN_MITER : (m_JoinType==RoundJoin) ? JOIN_ROUND : JOIN_BEVEL;
03724 
03725     INT32 CurrentWidth = 0;
03726     UINT32 i;
03727     // Loop trough the path list expanding them and saving the result into the DrawPathList
03728     for (i = 0 ; i < m_NumPaths; i++)
03729     {
03730         pDrawPathList[i].Initialise();
03731         PathWidth = Width;
03732 
03733         // We now require to add the linewidth to the bevel outline!
03734         if(m_pPathLineWidthList[i] != NULL)
03735         {
03736             CurrentWidth = m_pPathLineWidthList[i]->LineWidth;
03737             PathWidth -= (CurrentWidth >> 1);
03738             Outer |= (Width >= 0 && Width < (CurrentWidth >> 1));
03739         }
03740 
03741         // Make sure we use the correct function by checking to see if the path is closed or not!
03742         BOOL IsPathClosed = m_pPathList[i].IsClosed() && m_pPathList[i].IsFilled;
03743         m_pPathList[i].InitializeContourValues(abs(PathWidth)*2,JoinS,Outer,m_Flatness,IsPathClosed,IsPathClosed,CAPS_ROUND);
03744         m_pPathList[i].GetContourForStep(&pDrawPathList[i],1.0);
03745     }
03746 
03747     // merge all the paths in each set and keep an overall bounding rect going
03748     for (i = 0 ; i < m_NumSets - 1; i++)
03749     {
03750         pSetPathList[i].Initialise();
03751         pSetPathList[i].GetTrueBoundingRect(&dri);
03752         
03753         for (j = m_pSetList[i]; j < m_pSetList[i+1]; j++)
03754         {
03755             pDrawPathList[j].GetTrueBoundingRect(&drj);
03756             pSetPathList[i].MergeTwoPaths(pDrawPathList[j]);
03757         }
03758 
03759         if(m_NumSets > 1)
03760         {
03761             CopyPath.ClearPath(FALSE);
03762             CopyPath.MergeTwoPaths(pSetPathList[i]);
03763             pSetPathList[i].ClearPath(FALSE);
03764             TempPath.ClipPathToPath(CopyPath,&pSetPathList[i],7|(1<<4),50,m_Flatness,m_Flatness);
03765         }
03766 
03767         pSetPathList[i].IsFilled = TRUE;
03768         pSetPathList[i].IsStroked = FALSE;
03769 
03770         DrawBounds = DrawBounds.Union(dri);
03771     }
03772 
03773     // increase the bounds slightly - David code ?
03774     DrawBounds.Inflate(750);
03775 
03776     // Get the render region required
03777     RenderRegion* pRegion = DocView::RenderOnTop( NULL, pSpread, UnclippedEOR );
03778 
03779     while ( pRegion != NULL )
03780     {
03781         // Set the line colour and Draw the rect
03782         pRegion->SaveContext();
03783 
03784         pRegion->SetLineWidth(0);
03785         
03786         pRegion->SetWindingRule(PositiveWinding);
03787         
03788         pRegion->SetLineColour(COLOUR_RED);
03789         pRegion->SetFillColour(COLOUR_NONE);
03790 
03791         // draw all the paths in the current SetPathList
03792         for (i = 0 ; i < m_NumSets-1; i++)
03793         {
03794             pRegion->DrawPath(&(pSetPathList[i]));
03795         }
03796         
03797         // Get the Next render region
03798         pRegion->RestoreContext();
03799         pRegion = DocView::GetNextOnTop( NULL );
03800     }
03801 
03802     // tidy up and finish!
03803     delete [] pDrawPathList;
03804     delete [] pSetPathList;
03805 }
03806 
03807 
03808 /********************************************************************************************
03809 
03810 >   void OpDragBevel::RenderDragBlobs(DocRect Rect,Spread* pSpread, BOOL bSolidDrag)
03811 
03812     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03813     Created:    11/10/94
03814     Inputs:     Rect    - The region that needs the blobs to be drawn
03815                 pSpread - The spread that the drawing will happen on
03816     Purpose:    Draws an EORed rectangle defined by AnchorPoint and DragPoint
03817 
03818 ********************************************************************************************/
03819 
03820 void OpDragBevel::RenderDragBlobs(DocRect Rect,Spread* pSpread, BOOL bSolidDrag)
03821 {
03822     if (m_pPathList == NULL || m_NumPaths == 0)
03823     {
03824         ERROR3("Render drag blobs - no path list");
03825         return;
03826     }
03827     
03828     // set up the bounds
03829     INT32 Width = (ContourTool::CalculateContourWidth(m_SelRect, m_ThisPointerPos) - m_StartDragWidth) 
03830         + m_OriginalWidth;
03831 
03832     RenderDragBlobs(Width, pSpread);    
03833 }
03834 
03835 /********************************************************************************************
03836 
03837 >   BOOL OpDragBevel::Declare()
03838 
03839     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03840     Created:    11/10/94
03841     Returns:    TRUE if all went OK, FALSE otherwise
03842     Purpose:    Adds the operation to the list of all known operations
03843 
03844 ********************************************************************************************/
03845 
03846 BOOL OpDragBevel::Declare()
03847 {
03848     return (RegisterOpDescriptor(
03849                                 0, 
03850                                 _R(IDS_BEVEL_TOOL),
03851                                 CC_RUNTIME_CLASS(OpDragBevel), 
03852                                 OPTOKEN_DRAGBEVEL,
03853                                 OpDragBevel::GetState,
03854                                 0,          /* help ID */
03855                                 _R(IDBBL_NOOP), /* bubble ID */
03856                                 0           /* bitmap ID */
03857                                 ));
03858 }
03859 
03860 
03861 /********************************************************************************************
03862 
03863 >   static OpState OpDragBevel::GetState(String_256* Description, OpDescriptor*)
03864 
03865     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03866     Created:    11/10/94
03867     Outputs:    Description - GetState fills this string with an approriate description
03868                 of the current state of the push tool
03869     Returns:    The state of the operation, so that menu items (ticks and greying can be
03870                 done properly
03871     Purpose:    Find out the state of the operation at the specific time
03872 
03873 ********************************************************************************************/
03874 
03875 OpState OpDragBevel::GetState(String_256* Description, OpDescriptor*)
03876 {
03877     OpState State;
03878     
03879     return State;
03880 }
03881 
03882 /********************************************************************************************
03883 
03884 >   virtual void OpDragBevel::GetOpName(String_256* OpName) 
03885 
03886     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03887     Created:    11/10/94
03888     Inputs:     OpName = ptr to str to place op name in
03889     Outputs:    The undo string for the operation
03890     Returns:    
03891     Purpose:    The GetOpName fn is overridden so that we return back a description 
03892                 appropriate to the type of attribute that the operation applies. 
03893     Errors:     -
03894     SeeAlso:    -
03895 
03896 ********************************************************************************************/
03897 
03898 void OpDragBevel::GetOpName(String_256* OpName) 
03899 { 
03900     *OpName = String_256(_R(IDS_BEVELDRAGCREATEOP));
03901 }  
03902 
03903 
03904 
03905 #endif
03906 
03907 

Generated on Sat Nov 10 03:47:30 2007 for Camelot by  doxygen 1.4.4