moldedit.cpp

Go to the documentation of this file.
00001 // $Id: moldedit.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 // This file contains a library of mould functions defined in the mould lib class.
00099 // This class can be derived from by other operations outside the mould tool to
00100 // provide mould functionality.
00101 
00102 /*
00103 */
00104 
00105 #include "camtypes.h"
00106 //#include "resource.h"
00107 #include "moldedit.h"
00108 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 #include "nodemold.h"
00111 #include "nodemldr.h"
00112 #include "ndmldgrp.h"
00113 #include "ndmldpth.h"
00114 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "moldpers.h"
00117 #include "pathedit.h"
00118 //#include "mike.h"
00119 #include "helpuser.h"
00120 #include "progress.h"
00121 #include "keypress.h"
00122 #include "objchge.h"
00123 #include "ophist.h"
00124 
00125 class Node;
00126 
00127 DECLARE_SOURCE("$Revision: 1282 $");
00128 
00129 CC_IMPLEMENT_DYNCREATE( OpMouldLibSel,SelOperation )
00130 CC_IMPLEMENT_DYNCREATE( OpMouldLib,UndoableOperation )
00131 CC_IMPLEMENT_DYNCREATE( OpDragOrigin, SelOperation )
00132 CC_IMPLEMENT_DYNCREATE( InvalidateRectAction, Action )
00133 CC_IMPLEMENT_DYNCREATE( RecordGeometryAction, Action )
00134 CC_IMPLEMENT_DYNCREATE( SaveDetachAction, Action )
00135 CC_IMPLEMENT_DYNCREATE( RedrawBoundsAction, Action )
00136 CC_IMPLEMENT_DYNCREATE( BuildMouldAction, Action )
00137 CC_IMPLEMENT_DYNCREATE( StartRebuildMouldAction, Action )
00138 CC_IMPLEMENT_DYNCREATE( EndRebuildMouldAction, Action )
00139 
00140 #define new CAM_DEBUG_NEW
00141 
00142 
00143 /********************************************************************************************
00144 
00145 >   OpMouldLibSel::OpMouldLibSel() 
00146 
00147     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00148     Created:    18/01/95
00149     Purpose:    OpMouldLibSel() constructor
00150     SeeAlso:    -
00151 
00152 ********************************************************************************************/
00153 
00154 OpMouldLibSel::OpMouldLibSel()
00155 {
00156     // Dummy constructor
00157 }
00158 
00159 
00160 /********************************************************************************************
00161 
00162 >   BOOL OpMouldLibSel::CreateNewMould(Path* pShape,
00163                                       MouldSpace m_space,
00164                                       BOOL FitSelection,
00165                                       BOOL LockAspect)
00166 
00167     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>       
00168     Created:    11/12/94
00169     Inputs:     pShape      = A path to use as a mould shape
00170                 mSpace      = The mould space to create, currently only envelope and
00171                               perspective spaces are defined
00172                 ScaleToFit  = If TRUE then the shape will be scaled to fit over the 
00173                               bounds of the objects.
00174                 LockAspect  = If TRUE then the paths current dimensions are scaled so that
00175                               the minor dimension fits over pBounds
00176     Outputs:    -
00177     Returns:    TRUE if CreateNewMould has successfully created the mould object and children
00178                 FALSE if failed.
00179     Purpose:    Creates a complete mould object from the selected objects. Certain rules are
00180                 used for creating moulds when moulds are already selected. If the selection
00181                 contains mould objects only, then each mould will have its geometry changed
00182                 to that of m_space. If however there are a selection of unlike objects, they
00183                 will all be placed in a new mould whose geometry is specified in this function
00184                 call.
00185 
00186 **********************************************************************************************/
00187 
00188 BOOL OpMouldLibSel::CreateNewMould(Path* pShape, MouldSpace m_space, BOOL FitSelection, BOOL LockAspect)
00189 {
00190     ERROR3IF(pShape==NULL,"CreateNewMould called with a NULL shape pointer");
00191 
00192     // Obtain the current selections 
00193     SelRange* Selected = GetApplication()->FindSelection();
00194     if (!Selected)
00195         return FALSE;
00196 
00197     // Trash the old selection bounds
00198     Range Rnge = (*Selected);
00199     if (!DoInvalidateNodesRegions(Rnge,FALSE,FALSE))
00200         return FALSE;
00201 
00202     // Remember the selection before the operation
00203     if (!DoStartSelOp(FALSE,TRUE))
00204         return FALSE;
00205 
00206     // Check that we are actually allowed to do this operation
00207     ObjChangeFlags cFlags;
00208     cFlags.MultiReplaceNode=TRUE;
00209     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
00210 
00211     // Mark nodes that will allow this to happen, and error if no nodes will let it happen
00212     if (!Selected->AllowOp(&ObjChange))
00213     {
00214         ERROR3("AllowOp() returned FALSE, i.e. op should have been greyed out");
00215         return FALSE;
00216     }
00217 
00218     // using this list create or replace the mould bits
00219     BOOL ok = DoCreateOrReplaceMould(Selected, pShape, m_space, FitSelection, LockAspect);
00220     if (!ok)
00221         return FALSE;
00222 
00223     // Update all the changed nodes, i.e. tell all the parents of the children that have been effected
00224     ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
00225     return UpdateChangedNodes(&ObjChange);
00226 }
00227 
00228 
00229 
00230 /********************************************************************************************
00231 
00232 >   BOOL OpMouldLibSel::DoCreateOrReplaceMould( SelRange* pSelected,
00233                                                 Path* pShape,
00234                                                 MouldSpace m_space,
00235                                                 BOOL FitSelection,
00236                                                 BOOL LockAspect)
00237 
00238     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00239     Created:    16/03/95
00240     Inputs:     pShape      = A path to use as a mould shape
00241                 mSpace      = The mould space to create, currently only envelope and
00242                               perspective spaces are defined
00243                 ScaleToFit  = If TRUE then the shape will be scaled to fit over the 
00244                               bounds of the objects.
00245                 LockAspect  = If TRUE then the paths current dimensions are scaled so that
00246                               the minor dimension fits over pBounds
00247     Returns:    TRUE if the job has been done
00248                 FALSE if not
00249     Purpose:
00250 
00251 ********************************************************************************************/
00252 
00253 BOOL OpMouldLibSel::DoCreateOrReplaceMould( SelRange* pSelected,
00254                                             Path* pShape,
00255                                             MouldSpace m_space,
00256                                             BOOL FitSelection,
00257                                             BOOL LockAspect)
00258 {
00259     BOOL ok;
00260 
00261     // Create a list of all the selected nodes
00262     List* pNodeList = pSelected->MakeListOfNodes();
00263     if (pNodeList==NULL)
00264         return FALSE;
00265 
00266     // Get the bounds of the selection
00267     DocRect Bounds = pSelected->GetBoundingRect();
00268 
00269     if (AllMouldObjects(pNodeList))
00270     {
00271         // Ohh arr, we need to replace all selected mould shapes, here goes!!
00272         ok = DoReplaceAllMoulds(pNodeList, pShape, m_space, FitSelection, LockAspect);
00273     }
00274     else
00275     {       
00276         // call the mould builder
00277         NodeMould* pMould = DoCreateMould(pShape, m_space, pNodeList, &Bounds, FitSelection, LockAspect);
00278         ok = (pMould!=NULL);
00279 
00280         if (ok)
00281         {
00282             // Recalculate the mould's bounding box
00283             pMould->InvalidateBoundingRect();
00284             GetApplication()->UpdateSelection();
00285             ok = DoInvalidateNodeRegion(pMould, TRUE);
00286         }
00287     }
00288 
00289     // delete all elements in our compiled list
00290     while (!pNodeList->IsEmpty())
00291         delete (NodeListItem*)(pNodeList->RemoveHead());
00292     delete pNodeList;
00293 
00294     return ok;
00295 }
00296 
00297 
00298 /********************************************************************************************
00299 
00300 >   BOOL OpMouldLibSel::AllMouldObjects(List* pNodeList) 
00301 
00302     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00303     Created:    16/03/95
00304     Inputs:     pNodeList = a list of object pointers to objects to mould.
00305     Returns:    TRUE if the list contains mould objects only, at the top level.
00306                 FALSE if there are other object types.
00307     Purpose:    Scans the list of nodes provided. If any objects which are not node moulds
00308                 are found, false is returned
00309 
00310 ********************************************************************************************/
00311 
00312 BOOL OpMouldLibSel::AllMouldObjects(List* pNodeList)
00313 {
00314     NodeListItem* CurItem = (NodeListItem*)(pNodeList->GetHead());
00315     if (!CurItem) return FALSE;
00316 
00317     while (CurItem)
00318     {
00319         if (CurItem->pNode->GetRuntimeClass() != CC_RUNTIME_CLASS(NodeMould))
00320             return FALSE;
00321         CurItem = (NodeListItem*)(pNodeList->GetNext(CurItem));
00322     }
00323     return TRUE;
00324 }
00325 
00326 
00327 
00328 /********************************************************************************************
00329 
00330 >   NodeMould* OpMouldLibSel::DoCreateMould(Path* pShape, 
00331                                             MouldSpace mSpace,
00332                                             List* NodeList,
00333                                             DocRect* pBounds,
00334                                             BOOL ScaleToFit,
00335                                             BOOL LockAspect)
00336 
00337     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00338     Created:    19/12/94
00339     Inputs:     pShape      = A path to use as a mould shape
00340                 mSpace      = The mould space to create, currently only envelope and
00341                               perspective spaces are defined
00342                 NodeList    = A list of tree object nodes to place in the Mould
00343                 pBounds     = The bounding box of the objects in the node list
00344                 ScaleToFit  = If TRUE then the shape will be scaled to fit over the 
00345                               bounds of the objects.
00346                 LockAspect  = If TRUE then the paths current dimensions are scaled so that
00347                               the minor dimension fits over pBounds
00348     Returns:    TRUE if DoCreateMould has successfully created the mould object and children
00349                 FALSE if failed.
00350     Purpose:    Creates a complete mould object positioned on the next pointer of the
00351                 last node in the list. All nodes in the list will move inside this new
00352                 mould object.
00353 
00354 ********************************************************************************************/
00355 
00356 NodeMould* OpMouldLibSel::DoCreateMould(Path* pShape, 
00357                                         MouldSpace mSpace,
00358                                         List* NodeList,
00359                                         DocRect* pBounds,
00360                                         BOOL ScaleToFit,
00361                                         BOOL LockAspect)
00362 {
00363     ERROR2IF(pShape==NULL, NULL, "OpMouldLibSel::DoCreateMould() called with a NULL shape pointer");
00364     ERROR2IF(mSpace==MOULDSPACE_UNDEFINED, NULL, "pMouldLib::DoCreateMould() called with an undefined space type");
00365     ERROR2IF(NodeList==NULL, NULL, "OpMouldLibSel::DoCreateMould() called with a NULL list pointer");
00366 
00367     // initialise various locals
00368     BOOL ok;
00369 
00370     NodeListItem* CurItem = (NodeListItem*)(NodeList->GetTail());
00371     if (!CurItem)
00372         return NULL;
00373 
00374     Node* Context = CurItem->pNode;
00375     if (!Context)
00376         return NULL; 
00377 
00378     // create a mould parent and insert it in the tree
00379     NodeMould* pMouldParent;
00380     ALLOC_WITH_FAIL( pMouldParent, new NodeMould, this);
00381     if (!pMouldParent)
00382         return NULL;
00383 
00384     // give the parent mould object a shape and mould space to work with and stick it
00385     // in the tree
00386             CALL_WITH_FAIL(pMouldParent->CreateGeometry(mSpace), this, ok);
00387     if (ok) CALL_WITH_FAIL(DoInsertNewNode(pMouldParent, Context, NEXT, FALSE, TRUE, TRUE, FALSE), this, ok);
00388     if (!ok)
00389     {   
00390         delete pMouldParent;
00391         return NULL;
00392     }
00393 
00394     // check the shape we've been given is fine and lovely  
00395     UINT32 errID;
00396     if (!pMouldParent->GetGeometry()->Validate(pShape, errID))
00397     {
00398         SetNextMsgHelpContext(errID);
00399         ERROR1(NULL, errID);
00400     }
00401 
00402     // build a destination scale rectangle
00403     DocRect DRect, *pRect;
00404     pRect = FindScaleRect(pBounds, &DRect, ScaleToFit, LockAspect);
00405 
00406     // Create and add a mould shape object
00407     NodeMouldPath* pNodeMPath = pMouldParent->AddNewMouldShape(pShape,pRect,this);
00408     if (!pNodeMPath)
00409         return NULL;
00410 
00411     // set the geometry using this new mould shape
00412     ok = pMouldParent->GetGeometry()->Define(&pNodeMPath->InkPath, pBounds);
00413     if (!ok)
00414         return NULL;
00415 
00416     // now create the mould group object
00417     NodeMouldGroup* pMouldGroup = pMouldParent->AddNewMouldGroup(this);
00418     if (!pMouldGroup)
00419         return NULL;
00420 
00421     // and fill it with our object list
00422     if (!pMouldParent->FillMouldGroup(pMouldGroup, NodeList, this))
00423         return NULL;
00424 
00425     // Now build the moulder object and its list structure
00426     NodeMoulder* pMoulder = pMouldParent->AddNewMoulder(pMouldParent, LASTCHILD, this);
00427     if (!pMoulder)
00428         return NULL;
00429 
00430     // create all the moulded objects inside the moulder
00431     if (!pMoulder->CreateMouldedObjects(pMouldGroup, pMouldParent->GetGeometry(), this)) 
00432         return NULL;
00433 
00434     return pMouldParent; 
00435 }
00436 
00437 
00438 
00439 
00440 /********************************************************************************************
00441 
00442     DocRect* OpMouldLibSel::FindScaleRect(  DocRect* pSRect,
00443                                             DocRect* pDRect,
00444                                             BOOL ScaleToFit,
00445                                             BOOL KeepSquare)
00446  
00447     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00448     Created:    19/01/95
00449     Inputs:     pSRect = a pointer to a source rectangle
00450                 pDRect = a pointer to a destination rectangle
00451                 ScaleToFit  = If TRUE then pDRect will contain pSRect
00452                 KeepSquare  = If TRUE then pDRect is converted to have equal width and
00453                               height using its max dimension 
00454     Returns:    a pointer to pDRect or null if pDRect has not been affected
00455     Purpose:    Internal scaling rectangle calculator. Using the flags scaletofit, lock
00456                 a destination rectangle is build from the souce. If both flags are false
00457                 a null pointer will be returned else a pointer to pDRect.
00458 
00459 ********************************************************************************************/
00460 
00461 DocRect* OpMouldLibSel::FindScaleRect(DocRect* pSRect, DocRect* pDRect, BOOL ScaleToFit, BOOL KeepSquare)
00462 {
00463     if (ScaleToFit)
00464     {
00465         (*pDRect)=(*pSRect);
00466 
00467         // form a square rectangle if lock aspect is on.
00468         if (KeepSquare)
00469         {
00470             INT32 wid = pDRect->Width();
00471             INT32 hgt = pDRect->Height();
00472             INT32 max = (hgt>wid) ? hgt : wid;
00473 
00474             INT32 cx = (pDRect->lo.x + pDRect->hi.x)/2;
00475             INT32 cy = (pDRect->lo.y + pDRect->hi.y)/2;
00476 
00477             pDRect->lo.x = cx-max/2;
00478             pDRect->lo.y = cy-max/2;
00479             pDRect->hi.x = cx+max/2;
00480             pDRect->hi.y = cy+max/2;
00481         }
00482         
00483         return pDRect;
00484     }
00485     return NULL;
00486 }
00487 
00488 
00489 /********************************************************************************************
00490 
00491 >   static BOOL OpMouldLibSel::IsAMouldSelected(NodeMould** pNodeMould)
00492 
00493     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00494     Created:    19/01/95
00495     Inputs:     pNodeMould, a return pointer (can be null)
00496     Outputs:    pNodeMould points to the selected mould object if one exists
00497     Returns:    TRUE if there is a selected mould object
00498                 FALSE if not
00499     Purpose:    Scans the selection hunting for a selected mould object.
00500                 It will return a pointer to the object if found and if the return pointer
00501                 is none null.
00502                 Hopefully this will be replaced at some point by Selection->FindObject(type)
00503 
00504 ********************************************************************************************/
00505 
00506 BOOL OpMouldLibSel::IsAMouldSelected(NodeMould** pNodeMould)
00507 {
00508     BOOL Sel = FALSE;
00509     Node* pNode =NULL;
00510     if (Document::GetCurrent() != NULL)
00511     {
00512         SelRange* Selected = GetApplication()->FindSelection();
00513         pNode = Selected->FindFirst();
00514         while ((pNode!=NULL) && (!Sel))
00515         {
00516             if (pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeMould))
00517                 Sel=TRUE;
00518             else
00519                 pNode = Selected->FindNext(pNode);
00520         }
00521     }
00522     if (Sel && pNodeMould)
00523         *pNodeMould = (NodeMould*)pNode;
00524 
00525     return Sel;
00526 }
00527 
00528 
00529 
00530 
00531 /********************************************************************************************
00532 
00533 >   BOOL OpMouldLibSel::DoRemoveAllMould(List* pNodeList)
00534  
00535     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00536     Created:    19/01/95
00537     Inputs:     pNodeList = pointer to a list of selected nodes to process
00538     Returns:    TRUE if successfully removed all the mould objects
00539                 FALSE if failed.
00540     Purpose:    Removes the mould from around an object.
00541                 To do this it 
00542 
00543 ********************************************************************************************/
00544 
00545 BOOL OpMouldLibSel::DoRemoveAllMoulds(List* pNodeList)
00546 {
00547     BOOL ok, constrain, putonclip;
00548     INT32 count = 0;
00549 
00550     NodeListItem* CurItem = (NodeListItem*)(pNodeList->GetHead());
00551     if (!CurItem) 
00552         return FALSE;
00553 
00554     constrain=KeyPress::IsConstrainPressed();
00555 
00556     while (CurItem)
00557     {
00558         if (CurItem->pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeMould))
00559         {
00560             NodeMould* pMould = (NodeMould*)(CurItem->pNode);
00561 
00562             count++;
00563             putonclip = (constrain && (count==1));
00564 
00565             CALL_WITH_FAIL(DoRemoveMould(pMould, putonclip),this,ok);
00566             if (!ok) 
00567                 return FALSE;
00568         }
00569         CurItem = (NodeListItem*)(pNodeList->GetNext(CurItem));
00570     }
00571     return TRUE;
00572 }
00573 
00574 
00575 
00576 
00577 /********************************************************************************************
00578 
00579 >   BOOL OpMouldLibSel::DoRemoveMould(NodeMould* pMould, BOOL PutOnClip)
00580  
00581     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00582     Created:    19/01/95
00583     Inputs:     pMould  = pointer to a mould object
00584     Returns:    TRUE if successfully removed the mould object
00585                 FALSE if failed.
00586     Purpose:    Removes the mould from around an object.
00587                 To do this it 
00588 
00589 ********************************************************************************************/
00590 
00591 BOOL OpMouldLibSel::DoRemoveMould(NodeMould* pMould, BOOL PutOnClip)
00592 {
00593     ERROR2IF(pMould==NULL, FALSE, "OpMouldBuild::DoCreateMould() called with a NULL shape pointer");
00594 
00595     // Ask the mould if it's OK to do the op.
00596     // If not, pretend that everything went OK, because we wouldn't have got called unless at least
00597     // one selected mould could be removed.  This is ensured by OpRemoveMould::GetState
00598     ObjChangeFlags cFlags;
00599     cFlags.MultiReplaceNode = TRUE;
00600     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,pMould,this);
00601     if (!pMould->AllowOp(&ObjChange))
00602         return TRUE;
00603 
00604     // Make sure each child contains the correct attributes.
00605     //if (!DoLocaliseCommonAttributes(pMould))
00606 //      return FALSE;
00607 
00608     if (PutOnClip)
00609     {
00610         NodeMouldPath* pMouldPath = pMould->GetPathShape();
00611         if (pMouldPath!=NULL)
00612         {
00613             // RangeControl Cntrl = Selected + Unselected + don't cross layers  
00614             Range CopyRange(pMouldPath,pMouldPath,RangeControl(TRUE,TRUE,FALSE));
00615             if (!DoCopyNodesToClipboard(CopyRange))
00616                 return FALSE;
00617         }
00618     }
00619 
00620     NodeMouldGroup* pNodeMouldGroup = pMould->FindMouldGroup();
00621     if (!pNodeMouldGroup) 
00622         return FALSE;
00623 
00624     // now make sure the nodemouldgroups kids have localised attributes
00625     if (!DoLocaliseCommonAttributes(pNodeMouldGroup))
00626         return FALSE;
00627 
00628     // Now localise all those unsafe attributes at the top.
00629     if (!LocaliseMouldAttributes(pMould))
00630         return FALSE;
00631 
00632     if (!HideAllMouldAttrs(pMould))
00633         return FALSE;
00634 
00635     Spread* pSpread = pMould->FindParentSpread();
00636 
00637     Node* pNode = pNodeMouldGroup->FindLastChild();
00638     while (pNode!=NULL)
00639     {
00640         Node* pPrevNode = pNode->FindPrevious();
00641 
00642         if (pNode->IS_KIND_OF(NodeRenderableInk))
00643         {
00644             if (!DoSelectNode((NodeRenderableInk*)pNode,pSpread))
00645                 return FALSE;
00646 
00647             if (!DoInvalidateNodeRegion((NodeRenderableInk*)pNode,TRUE))
00648                 return FALSE;
00649         }
00650 
00651         if (pNode->IsAnObject())
00652         {
00653             if (!DoMoveNode(pNode, pMould, NEXT))
00654                 return FALSE;
00655         }
00656         
00657         pNode = pPrevNode;  
00658     }
00659 
00660     if (!DoDeselectNode(pMould, pSpread))
00661         return FALSE;
00662 
00663     if (!DoInvalidateNodeRegion(pMould, TRUE))
00664         return FALSE;
00665 
00666     // Hide the mould node
00667     if (!DoHideNode(pMould, FALSE, NULL))
00668         return FALSE;                
00669 
00670     // inform the selection something has changed?
00671     GetApplication()->UpdateSelection();
00672 
00673     return TRUE;
00674 }
00675 
00676 
00677 /********************************************************************************************
00678 
00679     BOOL OpMouldLibSel::LocaliseMouldAttributes(NodeMould* pMould)
00680  
00681     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00682     Created:    19/01/95
00683     Inputs:     pMould  = pointer to a mould object
00684     Returns:    TRUE if successfully localised the mould attributes
00685                 FALSE if failed.
00686     Purpose:    
00687 
00688 ********************************************************************************************/
00689 
00690 BOOL OpMouldLibSel::LocaliseMouldAttributes(NodeMould* pMould)
00691 {
00692     ERROR2IF(pMould==NULL, FALSE, "LocaliseMouldAttributes() given a null mould pointer");
00693 
00694     NodeMouldGroup* pNodeMouldGroup = pMould->FindMouldGroup();
00695     if (!pNodeMouldGroup) 
00696         return FALSE;
00697 
00698     Node* pNode = pNodeMouldGroup->FindFirstChild();
00699     while (pNode)
00700     {
00701         if (pNode->IsAnObject())
00702         {
00703             NodeRenderableInk* pInkNode = (NodeRenderableInk*)pNode;
00704             if (!LocaliseObjectAttrs(pMould, pInkNode))
00705                 return FALSE;
00706         }
00707         pNode=pNode->FindNext();
00708     }
00709     return TRUE;
00710 }
00711 
00712 
00713 
00714 /********************************************************************************************
00715 
00716     BOOL OpMouldLibSel::LocaliseObjectAttrs(NodeRenderableInk* pParent, NodeRenderableInk* pInkNode)
00717  
00718     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00719     Created:    19/01/95
00720     Inputs:     pMould  = pointer to a mould object
00721     Returns:    TRUE if successfully localised the mould attributes
00722                 FALSE if failed.
00723     Purpose:    
00724 
00725 ********************************************************************************************/
00726 
00727 BOOL OpMouldLibSel::LocaliseObjectAttrs(NodeRenderableInk* pParent, NodeRenderableInk* pInkNode)
00728 {
00729     CCRuntimeClass* AttrType;
00730     BOOL Exists; 
00731     NodeAttribute* pCurAttr;
00732     Node* pCloneAttr;
00733     Node* Current;
00734 
00735     ERROR2IF(pInkNode==NULL, FALSE, "LocaliseObjectAttrs() given a null object pointer");
00736 
00737     Current = pParent->FindFirstChild();
00738     while (Current)
00739     {
00740         if (Current->IsAnAttribute())
00741         {
00742             pCurAttr = (NodeAttribute*)Current;
00743             // Some attributes cannot be applied to objects
00744             if (pCurAttr->CanBeAppliedToObject())
00745             {
00746                 AttrType = pCurAttr->GetAttributeType();
00747 
00748                 if (pInkNode->RequiresAttrib(pCurAttr))
00749                 {
00750                     // Does the node already have this child attribute?
00751                     Exists = (pInkNode->GetChildAttrOfType(AttrType) != NULL);
00752                     ERROR3IF(Exists, "LocaliseMouldAttributes: Duplicate attr found !"); 
00753 
00754                     if (!Exists)
00755                     {
00756                         pCloneAttr = pCurAttr->SimpleCopy();
00757                         if (pCloneAttr)
00758                         {
00759                             pCloneAttr->AttachNode(pInkNode, FIRSTCHILD, TRUE, FALSE);
00760 
00761                             HideNodeAction* UndoHideNodeAction; 
00762 
00763                             if (HideNodeAction::Init(this,  
00764                                                      GetUndoActionList(),
00765                                                      pCloneAttr, 
00766                                                      TRUE,
00767                                                      (Action**)(&UndoHideNodeAction)
00768                                                      ) == AC_FAIL)
00769                             {   
00770                                 pCloneAttr->UnlinkNodeFromTree();
00771                                 delete pCloneAttr;
00772                                 pCloneAttr=NULL;
00773                                 return FALSE; 
00774                             }
00775 
00776                         }
00777                     }
00778                 }
00779             }
00780         }
00781         Current = Current->FindNext();
00782     }
00783     return TRUE;
00784 }
00785 
00786 
00787 
00788 
00789 /********************************************************************************************
00790 
00791     BOOL OpMouldLibSel::HideAllMouldAttrs(NodeMould* pMould)
00792  
00793     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00794     Created:    19/01/95
00795     Inputs:     pMould  = pointer to a mould object
00796     Returns:    TRUE if successfully hidden all the mould attributes
00797                 FALSE if failed.
00798     Purpose:    
00799 
00800 ********************************************************************************************/
00801 
00802 BOOL OpMouldLibSel::HideAllMouldAttrs(NodeMould* pMould)
00803 {
00804     ERROR2IF(pMould==NULL, FALSE, "HideAllMouldAttrs() given a null mould pointer");
00805 
00806     Node* pNode = pMould->FindFirstChild();
00807     while (pNode)
00808     {
00809         if (pNode->IsAnAttribute())
00810         {
00811             NodeAttribute* pAttr = (NodeAttribute*)pNode;
00812             if (!DoHideNode(pAttr, TRUE))
00813                 return FALSE;
00814         }
00815         pNode=pNode->FindNext();
00816     }
00817     return TRUE;
00818 }
00819 
00820 
00821 
00822 
00823 /********************************************************************************************
00824 
00825 >   BOOL OpMouldLibSel::DoReplaceAllMoulds( List* pNodeList,
00826                                             Path* pShape,
00827                                             MouldSpace mSpace,
00828                                             BOOL ScaleToFit,
00829                                             BOOL LockAspect)
00830     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00831     Created:    19/01/95
00832     Inputs:     pNodeList   = pointer to list of nodes to process
00833                 pNewShape   = A path to use as a mould shape
00834                 mSpace      = The mould space to create, currently only envelope and
00835                               perspective spaces are defined
00836     Returns:    TRUE if successfully replaced all mould shapes with the new shape.
00837                 FALSE if failed.
00838     Purpose:    Scans all nodes in the node list. If moulds are found, their shapes will
00839                 be replaced with pShape.
00840 
00841 ********************************************************************************************/
00842 
00843 BOOL OpMouldLibSel::DoReplaceAllMoulds( List* pNodeList,
00844                                         Path* pShape,
00845                                         MouldSpace mSpace,
00846                                         BOOL ScaleToFit,
00847                                         BOOL LockAspect)
00848 {
00849     ERROR2IF(pNodeList==NULL, FALSE, "DoReplaceAllMoulds() given a null nodelist pointer");
00850     
00851     NodeListItem* CurItem = (NodeListItem*)(pNodeList->GetHead());
00852     if (!CurItem)
00853         return FALSE;
00854 
00855     while (CurItem)
00856     {
00857         if (CurItem->pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeMould))
00858         {
00859             NodeMould* pMould = (NodeMould*)(CurItem->pNode);
00860             if (!DoInvalidateNodeRegion(pMould, TRUE))
00861                 return FALSE;
00862 
00863             if (!DoReplaceMould(pMould, pShape, mSpace, ScaleToFit, LockAspect))
00864                 return FALSE;
00865 
00866             // Recalculate the mould's bounding box
00867             pMould->InvalidateBoundingRect();
00868 
00869             if (!DoInvalidateNodeRegion(pMould, TRUE))
00870                 return FALSE;
00871         }
00872         CurItem = (NodeListItem*)(pNodeList->GetNext(CurItem));
00873     }
00874 
00875     GetApplication()->UpdateSelection();
00876 
00877     return TRUE;
00878 }
00879 
00880 
00881 /********************************************************************************************
00882 
00883 >   BOOL OpMouldLibSel::DoReplaceMould( NodeMould* pMould,
00884                                         Path* pShape,
00885                                         MouldSpace mSpace,
00886                                         BOOL ScaleToFit,
00887                                         BOOL LockAspect)
00888     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00889     Created:    19/01/95
00890     Inputs:     pMould      = pointer to a mould object
00891                 pNewShape   = A path to use as a mould shape
00892                 mSpace      = The mould space to create, currently only envelope and
00893                               perspective spaces are defined
00894     Returns:    TRUE if successfully removed the mould object
00895                 FALSE if failed.
00896     Purpose:    Replaces one mould shape with another definition
00897 
00898 ********************************************************************************************/
00899 
00900 BOOL OpMouldLibSel::DoReplaceMould( NodeMould* pMould,
00901                                     Path* pNewShape,
00902                                     MouldSpace mSpace,
00903                                     BOOL ScaleToFit,
00904                                     BOOL LockAspect )
00905 {
00906     ERROR2IF(pMould==NULL, FALSE, "DoReplaceMould() called with no mould pointer");
00907     ERROR2IF(pNewShape==NULL, FALSE, "DoReplaceMould() called with a NULL shape pointer");
00908 
00909     // cache the old geometry
00910     MouldGeometry* pGeometry=pMould->GetGeometry();
00911     if (!pGeometry)
00912         return FALSE;
00913 
00914     DocRect Bounds, DRect, *pRect;
00915     Bounds = pGeometry->GetSourceRect();
00916 
00917     if ((pMould->StartSaveContext(this, REC_REBUILD | REC_GEOMETRY)) == CC_FAIL)
00918         return FALSE;
00919 
00920     // create a new one (will automatically delete the old)
00921     if (!pMould->CreateGeometry(mSpace))
00922         return FALSE;
00923 
00924     // cache a pointer to the new geometry
00925     pGeometry=pMould->GetGeometry();
00926     if (!pGeometry)
00927         return FALSE;
00928 
00929     // check the shape we've been given is fine and lovely  
00930     UINT32 errID;
00931     if (!pGeometry->Validate(pNewShape,errID))
00932     {
00933         ERROR1(FALSE, errID);
00934     }
00935 
00936     // build a destination scale rectangle
00937     pRect = FindScaleRect(&Bounds, &DRect, ScaleToFit, LockAspect);
00938 
00939     // Find the current mould path object
00940     NodeMouldPath* pNodeMPath = pMould->GetPathShape(); 
00941     if (!pNodeMPath)
00942         return FALSE;
00943 
00944     // Hide the mould path node
00945     if (!DoHideNode(pNodeMPath, FALSE, NULL))
00946         return FALSE;                
00947 
00948     // Create and add a mould shape object
00949     pNodeMPath = pMould->AddNewMouldShape(pNewShape,pRect,this);
00950     if (!pNodeMPath)
00951         return FALSE;
00952 
00953     // set the geometry using this new mould shape
00954     if (!pGeometry->Define(&(pNodeMPath->InkPath), &Bounds))
00955         return FALSE;
00956 
00957     // finally generate some new mould shapes.
00958     if (pMould->RemouldAll(this)==CC_FAIL)
00959         return FALSE;
00960 
00961     // Ilan 7/5/00
00962     // Inform geom linked attrs of the change. Nb outside the normal AllowOp mechanism
00963     NodeAttribute* pNA = pMould->FindFirstGeometryLinkedAttr();
00964     while(pNA)
00965     {
00966         pNA->LinkedNodeGeometryHasChanged(this);
00967         pNA = pNA->FindNextGeometryLinkedAttr();
00968     }
00969 
00970     if ((pMould->EndSaveContext(this, REC_REBUILD | REC_GEOMETRY)) == CC_FAIL)
00971         return FALSE;
00972 
00973     return TRUE;
00974 }
00975 
00976 
00977 /********************************************************************************************
00978 
00979 >   BOOL OpMouldLibSel::DoRecordGeometry(NodeMould* pMould)
00980  
00981     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00982     Created:    19/01/95
00983     Inputs:     pMould  = pointer to a mould object
00984     Returns:    TRUE if successfully recorded the mould geometry
00985                 FALSE if failed.
00986     Purpose:    Asks the geometry to record its own internal data and then records the
00987                 type of geometry on the undo, ready to be replaced.
00988 
00989 ********************************************************************************************/
00990 
00991 BOOL OpMouldLibSel::DoRecordGeometry(NodeMould* pMould)
00992 {
00993     ActionCode Act;
00994 
00995     // call the actions static init function to get the action going.
00996     Act = RecordGeometryAction::DoRecord(this,pMould);
00997     if (Act==AC_FAIL)
00998         return FALSE;
00999 
01000     return TRUE;
01001 }
01002 
01003 
01004 
01005 
01006 /********************************************************************************************
01007 
01008 >   OpMouldLib::OpMouldLib() 
01009 
01010     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01011     Created:    18/01/95
01012     Purpose:    OpMouldLib() constructor
01013     SeeAlso:    -
01014 
01015 ********************************************************************************************/
01016 
01017 OpMouldLib::OpMouldLib()
01018 {
01019     // Dummy constructor
01020 }
01021 
01022 
01023 /********************************************************************************************
01024 
01025 >   BOOL OpMouldLib::DoRotateMould(NodeMould* pMould)
01026 
01027     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01028     Created:    19/01/95
01029     Inputs:     pMould      = pointer to a mould object
01030     Returns:    TRUE if successfully rotated the geometry around by one path element
01031     Purpose:    Simply rotates the orientation of all objects within the geometry.
01032 
01033 ********************************************************************************************/
01034 /*
01035 BOOL OpMouldLib::DoRotateMould(NodeMould* pMould)
01036 {
01037     ERROR2IF(pMould==NULL, FALSE, "DoRotateMould() called with no mould pointer");
01038 
01039     MouldGeometry* pGeometry=pMould->GetGeometry();
01040     NodeMouldPath* pMouldPath=pMould->GetPathShape();
01041     if (!pMouldPath || !pGeometry)
01042         return FALSE;
01043 
01044     // cache the actual path shape
01045     Path* pEditPath = &(pMouldPath->InkPath);
01046 
01047     // record the current path data, ie its flags,verbs & coords
01048     if (SavePathArraysAction::DoRecord(this, &UndoActions, pEditPath) == AC_FAIL)
01049         return FALSE;
01050 
01051     // record the current mould shape on the undo and any blob rectangles
01052     if (pMould->SaveContext(this)==CC_FAIL)
01053         return FALSE;
01054 
01055     // rotate the path around
01056     INT32 index=0;
01057     if (!pEditPath->FindNextEndPoint(&index))
01058         return FALSE;
01059     if (!pEditPath->ChangeStartElement(index))
01060         return FALSE;
01061 
01062     // set the geometry using this new mould shape
01063     if (!pGeometry->Define(pEditPath, NULL))
01064         return FALSE;
01065 
01066     // finally generate some new mould shapes.
01067     if (pMould->RemouldAll(this)==CC_FAIL)
01068         return FALSE;
01069 
01070     return TRUE;
01071 }
01072 */
01073 
01074 BOOL OpMouldLib::DoRotateMould(NodeMould* pMould)
01075 {
01076     ERROR2IF(pMould==NULL, FALSE, "DoRotateMould() called with no mould pointer");
01077 
01078     MouldGeometry* pGeometry=pMould->GetGeometry();
01079     NodeMouldPath* pMouldPath=pMould->GetPathShape();
01080     if (!pMouldPath || !pGeometry)
01081         return FALSE;
01082 
01083     // save the bits we need on the undo
01084     if ((pMould->StartSaveContext(this, REC_REBUILD | REC_GEOMCONTEXT | REC_PATHARRAYS)) == CC_FAIL)
01085         return FALSE;
01086 
01087     Path* pEditPath = &(pMouldPath->InkPath);
01088     // rotate the path around
01089     INT32 index=0;
01090     if (!pEditPath->FindNextEndPoint(&index))
01091         return FALSE;
01092     if (!pEditPath->ChangeStartElement(index))
01093         return FALSE;
01094 
01095     // set the geometry using this new mould shape
01096     if (!pGeometry->Define(pEditPath, NULL))
01097         return FALSE;
01098 
01099     // finally generate some new mould shapes.
01100     if (pMould->RemouldAll(this)==CC_FAIL)
01101         return FALSE;
01102 
01103     // Ilan 7/5/00
01104     // Inform geom linked attrs of the change. Nb outside the normal AllowOp mechanism
01105     NodeAttribute* pNA = pMould->FindFirstGeometryLinkedAttr();
01106     while(pNA)
01107     {
01108         pNA->LinkedNodeGeometryHasChanged(this);
01109         pNA = pNA->FindNextGeometryLinkedAttr();
01110     }
01111 
01112     if ((pMould->EndSaveContext(this, REC_REBUILD | REC_GEOMCONTEXT | REC_PATHARRAYS)) == CC_FAIL)
01113         return FALSE;
01114 
01115     return TRUE;
01116 }
01117 
01118 
01119 
01120 /********************************************************************************************
01121 
01122 >   RecordGeometryAction::RecordGeometryAction()
01123 
01124     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01125     Created:    26/01/95
01126     Purpose:    RecordGeometryAction constructor
01127 
01128 ********************************************************************************************/
01129 
01130 RecordGeometryAction::RecordGeometryAction()
01131 {
01132     pSavedMould=NULL;
01133     pSavedGeometry=NULL;
01134 }
01135 
01136 RecordGeometryAction::~RecordGeometryAction()
01137 {
01138     if (pSavedGeometry!=NULL)
01139     {
01140         delete pSavedGeometry;
01141         pSavedGeometry=NULL;
01142     }
01143 }
01144 
01145 
01146 /********************************************************************************************
01147 
01148 >   static ActionCode RecordGeometryAction::DoRecord(Operation* const pOp, 
01149                                                      NodeMould* const pMould)   
01150 
01151     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01152     Created:    16/03/95  
01153     Inputs:     pOp     = The operation to which the action should be added
01154                 pMould  = a pointer to a mould object we wish to record the geometry of
01155     Outputs:    -
01156     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01157                            
01158     Purpose:    This simple action saves away the current mould space (geometry) defined by
01159                 this mould object. The mould space may then be deleted externally and 
01160                 replaced with another. During undo the new space will be recorded and the 
01161                 old space rebuilt.
01162 
01163 ********************************************************************************************/
01164 
01165 ActionCode RecordGeometryAction::DoRecord(Operation* const pOp, 
01166                                           NodeMould* const pMould) 
01167 {
01168     ERROR2IF(pMould==NULL,AC_FAIL,"Mould pointer is NULL in RecordGeometryAction()");
01169     RecordGeometryAction* GeomAction;
01170     // Attempt to initialise the next action    
01171     return RecordGeometryAction::Init(pOp, pOp->GetUndoActionList(), pMould, (Action**)(&GeomAction));
01172 }
01173 
01174 
01175 
01176 
01177 /********************************************************************************************
01178 
01179 >   static ActionCode RecordGeometryAction::Init(Operation* const pOp, 
01180                                                  ActionList* pActionList,   
01181                                                  MouldGeometry* pGeometry,
01182                                                  Action** NewAction)    
01183 
01184     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01185     Created:    16/03/95  
01186     Inputs:     pOp:         The operation to which the action should be added
01187                 pActionList: The action list in the operation object
01188                 pMould:      A pointer to a mould object whose geometry we will record.
01189     Outputs:    NewAction:   A pointer to the action if it could be allocated. 
01190     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01191                            
01192     Purpose:    This simple action saves away the current mould space (geometry) defined by
01193                 this mould object. The mould space may then be deleted externally and 
01194                 replaced with another. During undo the new space will be recorded and the 
01195                 old space rebuilt.
01196 
01197 ********************************************************************************************/
01198 
01199 ActionCode RecordGeometryAction::Init(Operation* const pOp, 
01200                                       ActionList* pActionList,  
01201                                       NodeMould* const pMould,
01202                                       Action** NewAction)   
01203 {       
01204     ERROR2IF(pMould==NULL,AC_FAIL,"Mould pointer is NULL in RecordGeometryAction()");
01205     MouldGeometry* pGeometry = pMould->GetGeometry();
01206     ERROR2IF(pGeometry==NULL, AC_FAIL, "There was no defined geometry in RecordGeometryAction");
01207 
01208     // find the size of the geometry we need to save
01209     ActionCode Ac = (Action::Init(pOp,
01210                                   pActionList,
01211                                   sizeof(RecordGeometryAction), 
01212                                   CC_RUNTIME_CLASS(RecordGeometryAction), 
01213                                   NewAction));
01214     if (*NewAction != NULL)
01215     {
01216         ((RecordGeometryAction*)(*NewAction))->pSavedMould = pMould;
01217         ((RecordGeometryAction*)(*NewAction))->pSavedGeometry = pGeometry;
01218     }
01219 
01220     return (Ac); 
01221 } 
01222 
01223 
01224 
01225 /********************************************************************************************
01226 
01227 >   ActionCode RecordGeometryAction::Execute()   
01228 
01229     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01230     Created:    16/03/95
01231     Inputs:     -
01232     Returns:    ActionCode indicating if the action was successfully executed or not
01233     Purpose:    Executes the InvalidateRectAction which invalidates a rectangular region
01234                 of the current document.
01235     
01236 ********************************************************************************************/
01237 
01238 ActionCode RecordGeometryAction::Execute()
01239 {
01240     RecordGeometryAction* GeomAction;  
01241     ActionCode Ac;  
01242     // Attempt to initialise the next action    
01243     Ac = RecordGeometryAction::Init(pOperation, pOppositeActLst, pSavedMould, (Action**)(&GeomAction));
01244     
01245     if (Ac!=AC_FAIL)
01246     {   
01247         // set the geometry using this new mould shape
01248         if (!pSavedMould->SetGeometry(pSavedGeometry))
01249             return AC_FAIL;
01250 
01251         // Make sure the destructor doesn't vape it
01252         pSavedGeometry=NULL;
01253     }
01254     return Ac;
01255 }   
01256 
01257 
01258 
01259 
01260 
01261 /********************************************************************************************
01262 
01263 >   InvalidateRectAction::InvalidateRectAction()
01264 
01265     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01266     Created:    26/01/95
01267     Purpose:    InvalidateRectAction constructor
01268 
01269 ********************************************************************************************/
01270 
01271 InvalidateRectAction::InvalidateRectAction()
01272 {
01273     InvalidSpread=NULL;
01274 }
01275 
01276 
01277 
01278 /********************************************************************************************
01279 
01280 >   static ActionCode InvalidateRectAction::DoRecord(Operation* const pOp, 
01281                                                      const DocRect& Rect, 
01282                                                      Spread* pSpread)   
01283 
01284     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01285     Created:    26/01/95  
01286     Inputs:     pOp     = The operation to which the action should be added
01287                 Rect    = The rectangle to save
01288                 pSpread = The rectangles spread 
01289     Outputs:    -
01290     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01291                            
01292     Purpose:    This simple action saves away a rectangle on the undo, which will be 
01293                 invalidated during execution of undo and redo.
01294 
01295 ********************************************************************************************/
01296 
01297 ActionCode InvalidateRectAction::DoRecord(  Operation* const pOp, 
01298                                             const DocRect& Rect, 
01299                                             Spread* pSpread)
01300 {
01301     InvalidateRectAction* InvRctAct;  
01302     // Attempt to initialise the next action    
01303     return InvalidateRectAction::Init(pOp, pOp->GetUndoActionList(), Rect, pSpread, (Action**)(&InvRctAct));
01304 }
01305 
01306 
01307 /********************************************************************************************
01308 
01309 >   static ActionCode InvalidateRectAction::Init(Operation* const pOp, 
01310                                                  ActionList* pActionList,   
01311                                                  const DocRect& Rect,
01312                                                  Spread* pSpread,
01313                                                  Action** NewAction)    
01314 
01315     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01316     Created:    26/01/95  
01317     Inputs:     pOp:         The operation to which the action should be added
01318                 pActionList: The action list in the operation object
01319                 pSpread:     The rectangles spread 
01320     Outputs:    NewAction:   A pointer to the action if it could be allocated. 
01321     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01322                            
01323     Purpose:    This simple action invalidates a rectangular region.    
01324 
01325 ********************************************************************************************/
01326  
01327 ActionCode InvalidateRectAction::Init(Operation* const pOp, 
01328                                       ActionList* pActionList,  
01329                                       const DocRect& Rect, 
01330                                       Spread* pSpread,  
01331                                       Action** NewAction)   
01332 {       
01333     ActionCode Ac = (Action::Init(pOp,
01334                                   pActionList,
01335                                   sizeof(InvalidateRectAction), 
01336                                   CC_RUNTIME_CLASS(InvalidateRectAction), 
01337                                   NewAction));
01338     if (*NewAction != NULL)
01339     {
01340         ((InvalidateRectAction*)(*NewAction))->InvalidRect = Rect;
01341         ((InvalidateRectAction*)(*NewAction))->InvalidSpread = pSpread; 
01342     }
01343     return (Ac); 
01344 } 
01345 
01346 
01347 
01348 /********************************************************************************************
01349 
01350 >   ActionCode InvalidateRectAction::Execute()   
01351 
01352     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01353     Created:    26/01/95
01354     Inputs:     -
01355     Returns:    ActionCode indicating if the action was successfully executed or not
01356     Purpose:    Executes the InvalidateRectAction which invalidates a rectangular region
01357                 of the current document.
01358     
01359 ********************************************************************************************/
01360 
01361 ActionCode InvalidateRectAction::Execute()
01362 {
01363     InvalidateRectAction* InvRctAct;  
01364     ActionCode Ac;  
01365     // Attempt to initialise the next action    
01366     Ac = InvalidateRectAction::Init(pOperation, pOppositeActLst, InvalidRect, InvalidSpread, (Action**)(&InvRctAct));
01367     
01368     if (Ac!=AC_FAIL)
01369     {   
01370         // The action was successfully initialised   
01371         Document* pDocument = Document::GetCurrent();
01372         ENSURE(pDocument!=NULL, "There was no current document in InvalidateRectAction" );
01373         if (pDocument!=NULL)
01374             pDocument->ForceRedraw(InvalidSpread, InvalidRect);
01375 
01376     }
01377     return Ac;
01378 }   
01379 
01380 
01381 /********************************************************************************************
01382 
01383 >   RedrawBoundsAction::RedrawBoundsAction()
01384 
01385     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01386     Created:    11/7/94
01387 
01388 ********************************************************************************************/
01389 
01390 RedrawBoundsAction::RedrawBoundsAction()
01391 {
01392     ChangedNode = NULL;
01393 }
01394 
01395 
01396 ActionCode RedrawBoundsAction::DoRecord(Operation* pOp, NodeMould* WhichNode, BOOL Redraw)
01397 {
01398     RedrawBoundsAction* RecAction;
01399     ActionCode Act = RedrawBoundsAction::Init(pOp, 
01400                                               pOp->GetUndoActionList(),
01401                                               WhichNode,
01402                                               (Action**)&RecAction);
01403     if (Act != AC_FAIL && Redraw)
01404         RedrawNode(pOp, WhichNode);
01405     return Act;
01406 }
01407 
01408 
01409 ActionCode RedrawBoundsAction::Init(Operation* pOp,
01410                                     ActionList* pActionList,
01411                                     NodeMould* WhichNode,
01412                                     Action** NewAction)
01413 {
01414     UINT32 ActSize = sizeof(RedrawBoundsAction);
01415     ActionCode Ac = Action::Init( pOp, pActionList, ActSize, CC_RUNTIME_CLASS(RedrawBoundsAction), NewAction);
01416     if ((Ac == AC_OK) && (*NewAction != NULL))
01417         ((RedrawBoundsAction*)*NewAction)->ChangedNode = WhichNode;
01418 
01419     return Ac;
01420 }
01421 
01422 
01423 ActionCode RedrawBoundsAction::Execute()
01424 {
01425     RedrawBoundsAction* ReAction;
01426     ActionCode Act;
01427     Act = RedrawBoundsAction::Init(pOperation, pOppositeActLst, ChangedNode, (Action**)(&ReAction));
01428     if (Act != AC_FAIL)
01429         RedrawNode(pOperation, ChangedNode);
01430     return Act;
01431 }
01432 
01433 
01434 void RedrawBoundsAction::RedrawNode(Operation* pOp, NodeMould* pNode)
01435 {
01436     Document* pDoc = pOp->GetWorkingDoc();
01437     ERROR3IF( pDoc == NULL, "There was no current document when undoing RecordMouldBounds" );
01438     Spread* pSpread = pNode->FindParentSpread();
01439     DocRect Invalid = pNode->GetChildrensBounds();
01440     pDoc->ForceRedraw( pSpread, Invalid, FALSE, pNode);
01441 }
01442 
01443 
01444 
01445 
01446 
01447 /********************************************************************************************
01448 
01449 >   SaveDetachAction::SaveDetachAction()
01450 
01451     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01452     Created:    26/01/95
01453     Purpose:    SaveDetachAction constructor
01454 
01455 ********************************************************************************************/
01456 
01457 SaveDetachAction::SaveDetachAction()
01458 {
01459     pCurrMould=NULL;
01460     CurrDetached=FALSE;
01461 }
01462 
01463 
01464 /********************************************************************************************
01465 
01466 >   static ActionCode SaveDetachAction::Save(Operation* const pOp, 
01467                                              NodeMould* const pMould)   
01468 
01469     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01470     Created:    26/01/95  
01471     Inputs:     pOp     = The operation to which the action should be added
01472                 pMould  = The mould object whose data we are saving
01473     Outputs:    -
01474     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01475                            
01476     Purpose:    This simple action saves away a rectangle on the undo, which will be 
01477                 invalidated during execution of undo and redo.
01478 
01479 ********************************************************************************************/
01480 
01481 ActionCode SaveDetachAction::Save(Operation* const pOp, 
01482                                   NodeMould* const pMould) 
01483 {
01484     SaveDetachAction* SvDetAct;  
01485     // Attempt to initialise the next action    
01486     return SaveDetachAction::Init(pOp, pOp->GetUndoActionList(), pMould, (Action**)(&SvDetAct));
01487 }
01488 
01489 
01490 
01491 /********************************************************************************************
01492 
01493 >   static ActionCode SaveDetachAction::Init(Operation* const pOp,
01494                                                  ActionList* pActionList, 
01495                                          
01496                                                  Action** NewAction)    
01497 
01498     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01499     Created:    26/01/95  
01500     Inputs:     pOp:         The operation to which the action should be added
01501                 pActionList: The action list in the operation object
01502                 pSpread:     The rectangles spread 
01503     Outputs:    NewAction:   A pointer to the action if it could be allocated. 
01504     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01505                            
01506     Purpose:    An action to save away the state of the detach flag.    
01507 
01508 ********************************************************************************************/
01509  
01510 ActionCode SaveDetachAction::Init(  Operation* const pOp, 
01511                                     ActionList* pActionList,    
01512                                     NodeMould* const pMould,   
01513                                     Action** NewAction) 
01514 {       
01515     ActionCode Ac = (Action::Init(pOp,
01516                                   pActionList,
01517                                   sizeof(SaveDetachAction), 
01518                                   CC_RUNTIME_CLASS(SaveDetachAction), 
01519                                   NewAction));
01520     if (*NewAction != NULL)
01521     {
01522         ((SaveDetachAction*)(*NewAction))->pCurrMould = pMould;
01523         ((SaveDetachAction*)(*NewAction))->CurrDetached = pMould->IsDetached();
01524     }
01525     return (Ac); 
01526 } 
01527 
01528 
01529 
01530 /********************************************************************************************
01531 
01532 >   ActionCode SaveDetachAction::Execute()   
01533 
01534     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01535     Created:    26/01/95
01536     Inputs:     -
01537     Returns:    ActionCode indicating if the action was successfully executed or not
01538     Purpose:    Executes the SaveDetachAction
01539     
01540 ********************************************************************************************/
01541 
01542 ActionCode SaveDetachAction::Execute()
01543 {
01544     SaveDetachAction* MyAct;  
01545     ActionCode Ac = SaveDetachAction::Init( pOperation,
01546                                             pOppositeActLst,
01547                                             pCurrMould,
01548                                             (Action**)(&MyAct));
01549     
01550     if (Ac!=AC_FAIL)
01551     {
01552         if ((pCurrMould->IsDetached())!=CurrDetached)
01553             pCurrMould->ToggleDetachFlag();
01554     }
01555     return Ac;
01556 }   
01557 
01558 
01559 
01560 
01561 
01562 
01563 /********************************************************************************************
01564 
01565 >   OpDragOrigin::OpDragOrigin()
01566 
01567     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01568     Created:    25/01/95
01569     Purpose:    Constructs an Operation that allows the user to drag vanishing points of
01570                 a perspective mould
01571 
01572 ********************************************************************************************/
01573 
01574 OpDragOrigin::OpDragOrigin()
01575 {
01576     StartSpread     = NULL;
01577     pEditMould      = NULL;
01578     pEditMouldPath  = NULL;
01579     pEditPath       = NULL;
01580     pEditGeometry   = NULL;
01581 }
01582 
01583 /********************************************************************************************
01584 
01585 >   BOOL OpDragOrigin::Declare()
01586 
01587     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01588     Created:    25/01/95
01589     Inputs:     -
01590     Outputs:    -
01591     Returns:    TRUE if the op is correctly registered.
01592     Purpose:    Registers the rotation centre drag Operation.
01593     Errors:     -
01594     SeeAlso:    -
01595 
01596 ********************************************************************************************/
01597 
01598 BOOL OpDragOrigin::Init()
01599 {
01600     return RegisterOpDescriptor(0, /* _R(IDS_DRAGOriginOP), */ 
01601                                 _R(IDS_DRAGORIGINOP),
01602                                 CC_RUNTIME_CLASS(OpDragOrigin),
01603                                 OPTOKEN_DRAGVANISHPOINT, 
01604                                 OpDragOrigin::GetState,
01605                                 0,
01606                                 _R(IDBBL_DRAGORIGINOP));
01607 }
01608 
01609 
01610 
01611 /********************************************************************************************
01612 
01613 >   OpState OpDragOrigin::GetState(String_256*, OpDescriptor*)
01614 
01615     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01616     Created:    27/01/95
01617     Inputs:     -
01618     Outputs:    -
01619     Returns:    Returns a default OpState.
01620     Purpose:    Controls whether the rotation-centre mouse drag operation is available or
01621                 not.  Currently, is always available (the internal logic of the selector
01622                 tool & info-bar handle this really).
01623     Errors:     -
01624     SeeAlso:    -
01625 
01626 ********************************************************************************************/
01627 
01628 OpState OpDragOrigin::GetState(String_256*, OpDescriptor*)
01629 {
01630     OpState os;
01631     return os;
01632 }
01633 
01634 
01635 /********************************************************************************************
01636 
01637 >   virtual void OpDragOrigin::GetOpName(String_256* OpName)
01638 
01639     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01640     Created:    27/01/95
01641     Inputs:     -
01642     Outputs:    The undo string for the operation
01643     Returns:    
01644     Purpose:    The GetOpName fn is overridden so that we return back a description
01645                 appropriate to this type of operation.
01646 
01647 ********************************************************************************************/
01648 
01649 void OpDragOrigin::GetOpName(String_256* OpName)
01650 {
01651     *OpName = String_256(_R(IDS_UNDO_DRAGVPOINT));
01652 }
01653 
01654 /********************************************************************************************
01655 
01656 >   void OpDragOrigin::DoDragVanishPoint(Spread* pSpread, 
01657                                          const DocCoord& dcPos,
01658                                          ClickModifiers mods,
01659                                          NodeMould* pMould,
01660                                          BOOL WhichBlob)
01661 
01662     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01663     Created:    25/01/95
01664     Inputs:     pSpread = the spread containing the rotation centre blob
01665                 dcPos   = the initial position of the blob
01666                 mods    = the mouse button click modifiers (eg ctrl click etc)
01667                 pMould  = a pointer to the mould we will drag
01668     Outputs:    -
01669     Returns:    -
01670     Purpose:    Starts a drag of one of the perspective moulds vanishing points.
01671                 Note, a lot of effort has been put into the redraw of perspectives when
01672                 dragging vanishing points. We must make sure the vanishing point rectangles
01673                 are redrawn separately to the actual mould contents. If not it is v likely
01674                 that you will get a huge rectangle as a result of the union. Redrawing this
01675                 area is very bad.
01676                 Also note, we do not drag a copy of the envelope or perspective control
01677                 polygon but the control polygon itself. This means we must make sure when
01678                 we scroll we prevent the mould object from attempting to eor its blobs on,
01679                 this has the tendancy to leave large amounts of unsightly eor all over the
01680                 place.
01681 
01682 ********************************************************************************************/
01683 
01684 void OpDragOrigin::DoDragVanishPoint(Spread* pSpread, 
01685                                      const DocCoord& dcPos,
01686                                      ClickModifiers mods,
01687                                      NodeMould* pMould,
01688                                      BOOL WhichBlob)
01689 {
01690     ERROR3IF(pMould==NULL,"DoDragVanishPoint() given a null mould object");
01691     DocCoord v0,v1;
01692 
01693     // Remember the starting positions etc and initiate a drag.
01694     StartSpread = pSpread;
01695     pEditMould  = pMould;
01696 
01697     // try to find the geometry
01698     MouldGeometry* pGeometry = pMould->GetGeometry();
01699     if (!pGeometry->IsKindOf(CC_RUNTIME_CLASS(MouldPerspective)))
01700     {
01701         ERROR3("DoDragVanishPoint() called on an illegal geometry");
01702         goto Failed;
01703     }
01704 
01705     pEditGeometry = (MouldPerspective*)pGeometry;
01706 
01707     // read the current vanishing point positions for this mould.
01708     pEditGeometry->GetVanishingPoints(v0,v1);
01709     WhichBlob ? (Blob=v1) : (Blob=v0);
01710 
01711     // get hold of the moulds nodepath object
01712     pEditMouldPath = pMould->GetPathShape();
01713     if (!pEditMouldPath)
01714         goto Failed;
01715 
01716     // cache the actual path shape
01717     pEditPath = &(pEditMouldPath->InkPath);
01718 
01719     // record an action to redraw the node in its current state during undo/redo
01720     // we use our own special action to do this RecordBoundsAction uses the nasty
01721     // GetUnionBlobBounds() which unions the vanishing points in there too.
01722     // PS.. Pass FALSE into this function to avoid redraw at this stage
01723     if (RedrawBoundsAction::DoRecord(this,pEditMould,FALSE)==AC_FAIL)
01724         goto Failed;
01725     
01726     // Save the current rectangular bounds to redraw after the dragop has finished
01727     OpDragOrigin::EditRect = pMould->GetChildrensBounds();
01728 
01729     // record the current path data, ie its flags,verbs & coords
01730     if ((pEditMould->StartSaveContext(this, REC_REBUILD | REC_BLOBS | REC_GEOMCONTEXT | REC_PATHARRAYS)) == CC_FAIL)
01731         goto Failed;
01732 
01733 /*  if (SavePathArraysAction::DoRecord(this, &UndoActions, pEditPath) == AC_FAIL)
01734         goto Failed;
01735 
01736     // record the current mould shape on the undo and any blob rectangles
01737     if (pEditMould->SaveContext(this)==CC_FAIL)
01738         goto Failed;
01739 */
01740     // turn the display blobs off to prevent the mould from drawing them on
01741     // during a scroll.
01742     pEditMould->DisableBlobs();
01743 
01744     // start off the drag and get ready
01745     StartDrag(DRAGTYPE_AUTOSCROLL);
01746     return;
01747 
01748 Failed:
01749     FailAndExecute();
01750     End();
01751 }
01752 
01753 
01754 
01755 /********************************************************************************************
01756 
01757 >   void OpDragOrigin::DragPointerMove(DocCoord dcPos, ClickModifiers, Spread* pSpread, BOOL bSolidDrag)
01758 
01759     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01760     Created:    26/01/95
01761     Inputs:     dcPos   = the current mouse position
01762                 pSpread = the spread containing the mouse
01763     Outputs:    -
01764     Returns:    -
01765     Purpose:    Called while the vanishing point is being dragged around.  Erases it
01766                 from its old position and redraws it at its new position.
01767 
01768 ********************************************************************************************/
01769 
01770 void OpDragOrigin::DragPointerMove(DocCoord dcPos, ClickModifiers mods, Spread* pSpread, BOOL bSolidDrag)
01771 {   
01772     // If the mouse has moved outside the spread the drag was started on then we must
01773     // account for this.
01774     if (pSpread != StartSpread)
01775         dcPos = MakeRelativeToSpread(StartSpread, pSpread, dcPos);
01776 
01777     // Erase the old blobs.
01778     RenderDragBlobs(CalcBlobClipRect(), StartSpread, bSolidDrag);
01779 
01780     if (pEditGeometry->MoveVanishingPoint(Blob,dcPos))
01781     {
01782         Blob=dcPos;
01783         // Update the new shape in the path.
01784         DocCoord* pCoords = pEditPath->GetCoordArray();
01785         pEditGeometry->CopyShape(pCoords);
01786     }   
01787 
01788     // Draw on the new blobs
01789     RenderDragBlobs(CalcBlobClipRect(), StartSpread, bSolidDrag);
01790 }
01791 
01792 
01793 
01794 
01795 /********************************************************************************************
01796 
01797 >   void OpDragOrigin::DragFinished(DocCoord PointerPos, 
01798                                     ClickModifiers ClickMods,
01799                                     Spread* pSpread,
01800                                     BOOL success,
01801                                     BOOL bSolidDrag)
01802 
01803     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01804     Created:    26/01/95
01805     Inputs:     PointerPos  = final position of the mouse
01806                 ClickMods   = the click modifiers.
01807                 pSpread     = spread containing the mouse
01808                 success     = whether the drag was cancelled or not
01809     Outputs:    -
01810     Returns:    -
01811     Purpose:    Update the perspective mould object with the final resting place of this
01812                 mould vanishing point.
01813 
01814 ********************************************************************************************/
01815 void OpDragOrigin::DragFinished(DocCoord dcPos,     
01816                                 ClickModifiers mods,
01817                                 Spread* pSpread,
01818                                 BOOL success,
01819                                 BOOL bSolidDrag)
01820 {
01821     EndDrag();
01822     Document* pDoc = Document::GetCurrent();
01823     NodeAttribute* pNA = NULL;
01824 
01825     // Make sure the nodes blob rendering is enabled again
01826     pEditMould->EnableBlobs();
01827 
01828     // Act on the termination status of the drag operation.
01829     if (!success)
01830     {
01831         // Get rid of what ever new stuff we have, the unwind handler will
01832         // cause our original stuff to be replaced.
01833         RenderDragBlobs(CalcBlobClipRect(), StartSpread, bSolidDrag);
01834         goto Failed;
01835     }
01836 
01837     // Turn that hourglass on
01838     BeginSlowJob();
01839 
01840     // Make sure we invalidate the edit object
01841     pEditMouldPath->InvalidateBoundingRect();
01842 
01843     // Force a redraw on the original position. 
01844     // Note, we cannot do this before we start dragging as EORing goes mad!
01845     if (pDoc)
01846         pDoc->ForceRedraw( StartSpread, OpDragOrigin::EditRect, FALSE, pEditMould);
01847 
01848     if (pEditMould->RemouldAll(this)==CC_FAIL)
01849         goto Failed;
01850 
01851     // Ilan 7/5/00
01852     // Inform geom linked attrs of the change. Nb outside the normal AllowOp mechanism
01853     pNA = pEditMould->FindFirstGeometryLinkedAttr();
01854     while(pNA)
01855     {
01856         pNA->LinkedNodeGeometryHasChanged(this);
01857         pNA = pNA->FindNextGeometryLinkedAttr();
01858     }
01859 
01860     if ((pEditMould->EndSaveContext(this, REC_REBUILD | REC_BLOBS | REC_GEOMCONTEXT | REC_PATHARRAYS)) == CC_FAIL)
01861         goto Failed;
01862 
01863     // record an action to redraw the state of the mould (but not vanishpoints)
01864     if (RedrawBoundsAction::DoRecord(this,pEditMould,TRUE)==AC_FAIL)
01865         goto Failed;
01866 
01867     // record the vanish points separately (important to avoid unionblobbounds()!)
01868     if (pEditGeometry->RecordBlobs(this,StartSpread)==CC_FAIL)
01869         goto Failed;
01870 
01871     End();
01872     return;
01873 
01874 Failed:
01875     FailAndExecute();
01876     End();
01877     return;
01878 }
01879 
01880 
01881 /********************************************************************************************
01882 
01883 >   void OpDragOrigin::RenderDragBlobs(DocRect Clip, Spread* pSpread, BOOL bSolidDrag)
01884 
01885     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01886     Created:    25/01/95
01887     Inputs:     Clip    = clipping rectangle for output
01888                 pSpread = the spread to render into
01889     Outputs:    -
01890     Returns:    -
01891     Purpose:    Draws the drag path and new vanishing point positions
01892 
01893 ********************************************************************************************/
01894 
01895 void OpDragOrigin::RenderDragBlobs(DocRect Clip, Spread* pSpread, BOOL bSolidDrag)
01896 {
01897     RenderRegion* pRegion = DocView::RenderOnTop(&Clip, pSpread, ClippedEOR);
01898     while (pRegion != NULL)
01899     {
01900         // Get the edit path to render itself
01901         pEditMouldPath->RenderObjectBlobs(pRegion);
01902         pEditGeometry->RenderControlBlobs(pRegion);
01903 
01904         pRegion = DocView::GetNextOnTop(&Clip);
01905     }
01906 }
01907 
01908 
01909 /********************************************************************************************
01910 
01911 >   DocRect OpDragOrigin::CalcBlobClipRect()
01912 
01913     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01914     Created:    27/01/95
01915     Inputs:     -
01916     Outputs:    -
01917     Returns:    A clipping rectangle for use by RenderDragBlobs.
01918     Purpose:    Constructs a rectangle that surrounds the objects we are eoring
01919 
01920 ********************************************************************************************/
01921 
01922 DocRect OpDragOrigin::CalcBlobClipRect()
01923 {
01924     // get the current vanish point clip rects
01925     DocRect Rect0 = pEditGeometry->GetBlobBoundingRect();
01926     DocRect Rect1 = pEditMouldPath->GetBlobBoundingRect();
01927 
01928     return Rect0.Union(Rect1);
01929 }
01930 
01931 
01932 
01933 
01934 
01935 
01936 
01937 /********************************************************************************************
01938 
01939 >   StartRebuildMouldAction::StartRebuildMouldAction()
01940 
01941     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01942     Created:    26/01/95
01943     Purpose:    RebuildMouldAction constructor
01944 
01945 ********************************************************************************************/
01946 
01947 StartRebuildMouldAction::StartRebuildMouldAction()
01948 {
01949     pRebuildMould=NULL;
01950 }
01951 
01952 
01953 
01954 /********************************************************************************************
01955 
01956 >   static ActionCode StartRebuildMouldAction::DoRecord(Operation* const pOp, NodeMould* pMould)
01957 
01958     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01959     Created:    26/01/95  
01960     Inputs:     pOp     = The operation to which the action should be added
01961                 pMould  = A pointer to a mould to rebuild
01962     Outputs:    -
01963     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01964     Purpose:    
01965 
01966 ********************************************************************************************/
01967 
01968 ActionCode StartRebuildMouldAction::DoRecord(Operation* const pOp, NodeMould* pMould)
01969 {
01970     StartRebuildMouldAction* Act;  
01971     // Attempt to initialise the next action    
01972     return StartRebuildMouldAction::Init(pOp, pOp->GetUndoActionList(), pMould, (Action**)(&Act));
01973 }
01974 
01975 
01976 /********************************************************************************************
01977 
01978 >   static ActionCode StartRebuildMouldAction::Init(    Operation* const pOp, 
01979                                                  ActionList* pActionList,   
01980                                                  NodeMould* pMould,
01981                                                  Action** NewAction)    
01982 
01983     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01984     Created:    26/01/95  
01985     Inputs:     pOp:         The operation to which the action should be added
01986                 pActionList: The action list in the operation object
01987                 pMould:      A pointer to a mould to rebuild
01988     Outputs:    NewAction:   A pointer to the action if it could be allocated. 
01989     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
01990                            
01991     Purpose:    This simple action invalidates a rectangular region.    
01992 
01993 ********************************************************************************************/
01994  
01995 ActionCode StartRebuildMouldAction::Init(Operation* const pOp, 
01996                                     ActionList* pActionList,    
01997                                     NodeMould* pMould,
01998                                     Action** NewAction) 
01999 {       
02000     ActionCode Ac = (Action::Init(pOp,
02001                                   pActionList,
02002                                   sizeof(StartRebuildMouldAction), 
02003                                   CC_RUNTIME_CLASS(StartRebuildMouldAction), 
02004                                   NewAction));
02005     if (*NewAction != NULL)
02006     {
02007         ((StartRebuildMouldAction*)(*NewAction))->pRebuildMould = pMould;
02008     }
02009     return (Ac); 
02010 } 
02011 
02012 
02013 
02014 /********************************************************************************************
02015 
02016 >   ActionCode RebuildMouldAction::Execute()   
02017 
02018     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02019     Created:    26/01/95
02020     Inputs:     -
02021     Returns:    ActionCode indicating if the action was successfully executed or not
02022     Purpose:    Executes the RebuildMouldAction which invalidates a rectangular region
02023                 of the current document.
02024     
02025 ********************************************************************************************/
02026 
02027 ActionCode StartRebuildMouldAction::Execute()
02028 {
02029     EndRebuildMouldAction* Act;  
02030     ActionCode Ac;  
02031     // Attempt to initialise the next action    
02032     Ac = EndRebuildMouldAction::Init(pOperation, pOppositeActLst, pRebuildMould, (Action**)(&Act));
02033     
02034     if (Ac!=AC_FAIL)
02035     {   
02036         if (!pRebuildMould->IsDetached())
02037         {
02038             // The action was successfully initialised   
02039             NodeMoulder* pMoulder = pRebuildMould->FindFirstMoulder();
02040             NodeMouldGroup* pMouldGroup = pRebuildMould->FindMouldGroup();
02041 
02042             if (pMoulder!=NULL && pMouldGroup!=NULL)
02043             {
02044                 pMoulder->DestroyMouldedObjects();
02045                 if (!pMoulder->CreateMouldedObjects(pMouldGroup, pRebuildMould->GetGeometry(), NULL)) 
02046                 {
02047                     pMoulder->DestroyMouldedObjects();
02048                     return AC_FAIL;
02049                 }
02050             }
02051         }
02052     }
02053     return Ac;
02054 }   
02055 
02056 
02057 
02058 /********************************************************************************************
02059 
02060 >   EndRebuildMouldAction::EndRebuildMouldAction()
02061 
02062     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02063     Created:    26/01/95
02064     Purpose:    RebuildMouldAction constructor
02065 
02066 ********************************************************************************************/
02067 
02068 EndRebuildMouldAction::EndRebuildMouldAction()
02069 {
02070     pRebuildMould=NULL;
02071 }
02072 
02073 
02074 /********************************************************************************************
02075 
02076 >   static ActionCode EndRebuildMouldAction::DoRecord(Operation* const pOp, NodeMould* pMould)
02077 
02078     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02079     Created:    26/01/95  
02080     Inputs:     pOp     = The operation to which the action should be added
02081                 pMould  = A pointer to a mould to rebuild
02082     Outputs:    -
02083     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
02084     Purpose:    
02085 
02086 ********************************************************************************************/
02087 
02088 ActionCode EndRebuildMouldAction::DoRecord(Operation* const pOp, NodeMould* pMould)
02089 {
02090     EndRebuildMouldAction* Act;  
02091     // Attempt to initialise the next action    
02092     return EndRebuildMouldAction::Init(pOp, pOp->GetUndoActionList(), pMould, (Action**)(&Act));
02093 }
02094 
02095 /********************************************************************************************
02096 
02097 >   static ActionCode EndRebuildMouldAction::Init(  Operation* const pOp, 
02098                                                  ActionList* pActionList,   
02099                                                  NodeMould* pMould,
02100                                                  Action** NewAction)    
02101 
02102     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02103     Created:    26/01/95  
02104     Inputs:     pOp:         The operation to which the action should be added
02105                 pActionList: The action list in the operation object
02106                 pMould:      A pointer to a mould to rebuild
02107     Outputs:    NewAction:   A pointer to the action if it could be allocated. 
02108     Returns:    ActionCode:  one of AC_OK, AC_NORESTORE, AC_FAIL
02109     Purpose:
02110 
02111 ********************************************************************************************/
02112  
02113 ActionCode EndRebuildMouldAction::Init(Operation* const pOp, 
02114                                     ActionList* pActionList,    
02115                                     NodeMould* pMould,
02116                                     Action** NewAction) 
02117 {       
02118     ActionCode Ac = (Action::Init(pOp,
02119                                   pActionList,
02120                                   sizeof(EndRebuildMouldAction), 
02121                                   CC_RUNTIME_CLASS(EndRebuildMouldAction), 
02122                                   NewAction));
02123     if (*NewAction != NULL)
02124     {
02125         ((EndRebuildMouldAction*)(*NewAction))->pRebuildMould = pMould;
02126     }
02127     return (Ac); 
02128 } 
02129 
02130 
02131 
02132 /********************************************************************************************
02133 
02134 >   ActionCode EndRebuildMouldAction::Execute()   
02135 
02136     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02137     Created:    26/01/95
02138     Inputs:     -
02139     Returns:    ActionCode indicating if the action was successfully executed or not
02140     Purpose:    Executes the RebuildMouldAction which invalidates a rectangular region
02141                 of the current document.
02142     
02143 ********************************************************************************************/
02144 
02145 ActionCode EndRebuildMouldAction::Execute()
02146 {
02147     StartRebuildMouldAction* Act;  
02148     // Attempt to initialise the next action    
02149     return StartRebuildMouldAction::Init(pOperation, pOppositeActLst, pRebuildMould, (Action**)(&Act));
02150 }   
02151 
02152 
02153 
02154 
02155 
02156 
02157 
02158 /********************************************************************************************
02159 
02160 >   BuildMouldAction::BuildMouldAction()
02161 
02162     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02163     Created:    26/01/95
02164     Purpose:    BuildMouldAction constructor
02165 
02166 ********************************************************************************************/
02167 
02168 BuildMouldAction::BuildMouldAction()
02169 {
02170     pBuildMould=NULL;
02171 }
02172 
02173 
02174 /********************************************************************************************
02175 ********************************************************************************************/
02176 
02177 ActionCode BuildMouldAction::DoRecord(Operation* const pOp, NodeMould* pMould)
02178 {
02179     EndRebuildMouldAction* Act;  
02180     // Attempt to initialise the next action    
02181     return BuildMouldAction::Init(pOp, pOp->GetUndoActionList(), pMould, (Action**)(&Act));
02182 }
02183 
02184 
02185 /********************************************************************************************
02186 ********************************************************************************************/
02187  
02188 ActionCode BuildMouldAction::Init(Operation* const pOp, 
02189                                     ActionList* pActionList,    
02190                                     NodeMould* pMould,
02191                                     Action** NewAction) 
02192 {       
02193     ActionCode Ac = (Action::Init(pOp,
02194                                   pActionList,
02195                                   sizeof(BuildMouldAction), 
02196                                   CC_RUNTIME_CLASS(BuildMouldAction), 
02197                                   NewAction));
02198     if (*NewAction != NULL)
02199     {
02200         ((BuildMouldAction*)(*NewAction))->pBuildMould = pMould;
02201     }
02202     return (Ac); 
02203 } 
02204 
02205 
02206 /********************************************************************************************
02207 ********************************************************************************************/
02208 
02209 ActionCode BuildMouldAction::Execute()
02210 {
02211     ActionCode Ac = AC_OK;
02212     OperationStatus OpStat = pOperation->OpStatus;
02213     BuildMouldAction Act;
02214 
02215     Ac = BuildMouldAction::Init(pOperation, pOppositeActLst, pBuildMould, (Action**)(&Act));
02216 
02217     if (Ac != AC_FAIL)
02218     {
02219         NodeMoulder* pMoulder = pBuildMould->FindFirstMoulder();
02220         NodeMouldGroup* pMouldGroup = pBuildMould->FindMouldGroup();
02221 
02222         if (pMoulder!=NULL && pMouldGroup!=NULL)
02223         {
02224             // DO, UNDO, REDO destroy all moulder objects
02225             pMoulder->DestroyMouldedObjects();
02226 
02227             // for DO and REDO we need to recreate them
02228             if (OpStat==DO || OpStat==REDO)
02229             {
02230                 if (!pMoulder->CreateMouldedObjects(pMouldGroup, pBuildMould->GetGeometry(), NULL)) 
02231                 {
02232                     // failed to recreate so toast em.
02233                     pMoulder->DestroyMouldedObjects();
02234                     Ac = AC_FAIL;
02235                 }
02236             }
02237         }
02238     }
02239 
02240     return Ac;
02241 }
02242 

Generated on Sat Nov 10 03:45:43 2007 for Camelot by  doxygen 1.4.4