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