00001 // $Id: nodemold.cpp 1688 2006-08-10 12:05:20Z gerry $ 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 // NodeMould implementation. This file controls the tree node 'mould' which 00099 // currently includes envelope and perspective mould shapes. Mould creation, 00100 // rendering, deletion etc 00101 00102 // Comments 00103 // 00104 // A NodeMould contains all the usual information pertaining to tree nodes. 00105 // Various virtual functions inherited from Node are used to render and 00106 // format the node. The guts however, is the class MouldShape, which contains 00107 // the actual shape 'vector space' into which objects, normally living in 00108 // Euclidean 2d, are transformed. See the class MouldShape for more information 00109 // about these shape geometries. 00110 00111 /* 00112 */ 00113 00114 00115 #include "camtypes.h" 00116 #include "nodemold.h" 00117 #include "nodemldr.h" 00118 #include "ndmldgrp.h" 00119 #include "ndmldpth.h" 00120 //#include "mike.h" 00121 #include "moldshap.h" 00122 #include "moldenv.h" 00123 #include "moldpers.h" 00124 //#include "mario.h" 00125 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00126 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00127 //#include "range.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00128 //#include "undoop.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00129 #include "nodebmp.h" 00130 #include "nodepath.h" 00131 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00132 #include "objchge.h" 00133 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00134 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00135 #include "aw_eps.h" 00136 #include "nativeps.h" // The old style EPS native filter, used in v1.1 00137 //#include "moldtool.h" 00138 //#include "fillattr.h" // For AttrFillGeometry::RemovePerspective() - in camtypes.h [AUTOMATICALLY REMOVED] 00139 //#include "resource.h" // For _R(IDS_OK)/CANCEL 00140 //#include "will.h" 00141 //#include "tim.h" 00142 #include "contmenu.h" 00143 #include "pathedit.h" 00144 #include "moldedit.h" 00145 00146 #include "cxftags.h" 00147 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00148 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00149 //#include "camfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00150 #include "rechmld.h" 00151 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00152 #include "blobs.h" // for BlobManager. 00153 #include "slicehelper.h" 00154 00155 #include "ophist.h" 00156 00157 00158 DECLARE_SOURCE("$Revision: 1688 $"); 00159 00160 CC_IMPLEMENT_DYNAMIC( NodeMould, NodeGroup ) 00161 CC_IMPLEMENT_DYNCREATE( RecordChangeCodesAction, Action ) 00162 CC_IMPLEMENT_DYNAMIC(MouldRecordHandler, CamelotRecordHandler) 00163 00164 // Declare smart memory handling in Debug builds 00165 #define new CAM_DEBUG_NEW 00166 00167 00168 /********************************************************************************************* 00169 00170 > NodeMould::NodeMould() 00171 00172 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00173 Created: 5/12/94 00174 Purpose: This constructor creates a NodeMould linked to no other, with all status 00175 flags false and an uninitialised bounding rectangle. 00176 00177 **********************************************************************************************/ 00178 00179 NodeMould::NodeMould(): NodeGroup() 00180 { 00181 NodeMould::InitialiseVars(); 00182 } 00183 00184 00185 /*********************************************************************************************** 00186 00187 > void NodeMould::NodeMould 00188 ( 00189 Node* ContextNode, 00190 AttachNodeDirection Direction, 00191 BOOL Locked = FALSE, 00192 BOOL Mangled = FALSE, 00193 BOOL Marked = FALSE, 00194 BOOL Selected = FALSE, 00195 ) 00196 00197 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00198 Created: 5/12/94 00199 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 00200 00201 Direction: 00202 00203 Specifies the direction in which this node is to be attached to the 00204 ContextNode. The values this variable can take are as follows: 00205 00206 PREV : Attach node as a previous sibling of the context node 00207 NEXT : Attach node as a next sibling of the context node 00208 FIRSTCHILD: Attach node as the first child of the context node 00209 LASTCHILD : Attach node as a last child of the context node 00210 00211 The remaining inputs specify the status of the node: 00212 00213 Locked: Is node locked ? 00214 Mangled: Is node mangled ? 00215 Marked: Is node marked ? 00216 Selected: Is node selected ? 00217 00218 Outputs: - 00219 Returns: - 00220 Purpose: This method initialises the node and links it to ContextNode in the 00221 direction specified by Direction. All necessary tree links are 00222 updated. 00223 00224 Errors: An assertion error will occur if ContextNode is NULL 00225 00226 00227 ***********************************************************************************************/ 00228 00229 NodeMould::NodeMould(Node* ContextNode, 00230 AttachNodeDirection Direction, 00231 BOOL Locked, 00232 BOOL Mangled, 00233 BOOL Marked, 00234 BOOL Selected 00235 ):NodeGroup(ContextNode, Direction, Locked, Mangled, Marked, 00236 Selected) 00237 { 00238 NodeMould::InitialiseVars(); 00239 } 00240 00241 /********************************************************************************************* 00242 00243 > NodeMould::~NodeMould() 00244 00245 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00246 Created: 5/12/94 00247 Purpose: This destructor calls the parent class destructor and then checks whether 00248 it is necessary to delete the mould geometry class. If so the shape geometry 00249 is deleted. 00250 00251 **********************************************************************************************/ 00252 00253 NodeMould::~NodeMould() 00254 { 00255 if (pMouldGeometry != NULL) 00256 { 00257 delete pMouldGeometry; 00258 pMouldGeometry = NULL; 00259 } 00260 } 00261 00262 00263 00264 00265 /******************************************************************************************** 00266 00267 void NodeMould::InitialiseVars() 00268 00269 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00270 Created: 16/03/95 00271 Purpose: Common place to set up the classes private variables 00272 00273 ********************************************************************************************/ 00274 00275 void NodeMould::InitialiseVars() 00276 { 00277 pMouldGeometry=NULL; 00278 DetachedGeometry=FALSE; 00279 OnCC_CRC=0; 00280 OnCC_Width=0; 00281 OnCC_Height=0; 00282 RenderBlobs=TRUE; 00283 } 00284 00285 00286 00287 /******************************************************************************************** 00288 00289 > BOOL NodeMould::IsANodeMould() const 00290 00291 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00292 Created: 15/12/2000 00293 Purpose: Virtual function to determine whether this node is a NodeMould. 00294 00295 ********************************************************************************************/ 00296 BOOL NodeMould::IsANodeMould() const 00297 { 00298 return TRUE; 00299 } 00300 00301 00302 00303 /********************************************************************************************** 00304 00305 > BOOL NodeMould::CreateGeometry(MouldSpace mSpace) 00306 00307 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00308 Created: 6/12/94 00309 Inputs: mSpace = the type of mould to create. Currently use Envelope or Perspective 00310 enum values. 00311 It can also be NULL if you wish to use the shape as is. 00312 Returns: TRUE if the geometry has been created successfully. 00313 FALSE then unable to create the geometry object (out of memory) 00314 00315 Purpose: Changes the mould space used by this mould to that described by mSpace. 00316 Currently the defined spaces are 00317 MOULDSPACE_ENVELOPE 00318 MOULDSPACE_PERSPECTIVE 00319 00320 ***********************************************************************************************/ 00321 00322 BOOL NodeMould::CreateGeometry(MouldSpace mSpace) 00323 { 00324 // now build the new vector space polymorphically 00325 MouldGeometry* pNewGeom=NULL; 00326 00327 switch (mSpace) 00328 { 00329 case MOULDSPACE_ENVELOPE: 00330 { 00331 MouldEnvelope* mNewSpace = new MouldEnvelope; 00332 if (!mNewSpace) 00333 return FALSE; 00334 if (!mNewSpace->Initialise()) 00335 { 00336 delete mNewSpace; 00337 return FALSE; 00338 } 00339 pNewGeom = mNewSpace; 00340 break; 00341 } 00342 00343 case MOULDSPACE_ENVELOPE2X2: 00344 { 00345 MouldEnvelope2x2* mNewSpace = new MouldEnvelope2x2; 00346 if (!mNewSpace) 00347 return FALSE; 00348 if (!mNewSpace->Initialise()) 00349 { 00350 delete mNewSpace; 00351 return FALSE; 00352 } 00353 pNewGeom = mNewSpace; 00354 break; 00355 } 00356 00357 case MOULDSPACE_PERSPECTIVE: 00358 { 00359 MouldPerspective* mNewSpace = new MouldPerspective; 00360 if (!mNewSpace) 00361 return FALSE; 00362 pNewGeom = mNewSpace; 00363 break; 00364 } 00365 default: break; 00366 } 00367 00368 if (!pNewGeom) 00369 return FALSE; 00370 00371 // Assign the class geometry pointer the new shape 00372 // Note, we do not record the mouldspace in our class because 00373 // we dont really need to. The shape is an abstract class with 00374 // concrete geometries derived from it and hence we can call a shape 00375 // function and the run time binder will call the correct class func. 00376 00377 pMouldGeometry = pNewGeom; 00378 return TRUE; 00379 } 00380 00381 00382 00383 /******************************************************************************************** 00384 00385 BOOL NodeMould::SetGeometry(MouldGeometry* pGeometry) 00386 00387 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00388 Created: 16/03/95 00389 Purpose: Not to be used. 00390 00391 ********************************************************************************************/ 00392 00393 BOOL NodeMould::SetGeometry(MouldGeometry* pGeometry) 00394 { 00395 ERROR2IF(pGeometry==NULL, FALSE, "Null pointer passed to NodeMould::SetGeometry()"); 00396 pMouldGeometry=pGeometry; 00397 return TRUE; 00398 } 00399 00400 00401 /******************************************************************************************** 00402 00403 > virtual String NodeMould::Describe(BOOL Plural, BOOL Verbose = TRUE) 00404 00405 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00406 Created: 5/12/94 00407 Inputs: Plural: Flag indicating if the string description should be plural or 00408 singular. 00409 Outputs: - 00410 Retuns: Description of the mould node 00411 Purpose: To return a description of the Mould object in either the singular or the 00412 plural. This method is called by the DescribeRange method. 00413 00414 The description will always begin with a lower case letter. 00415 00416 ********************************************************************************************/ 00417 00418 String NodeMould::Describe(BOOL Plural, BOOL Verbose) 00419 { 00420 if (Plural) 00421 return(String(_R(IDS_MOULD_DESCRP))); 00422 else 00423 return(String(_R(IDS_MOULD_DESCRS))); 00424 }; 00425 00426 00427 00428 00429 /*********************************************************************************************** 00430 00431 > Node* NodeMould::SimpleCopy() 00432 00433 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00434 Created: 5/12/94 00435 Inputs: - 00436 Outputs: - 00437 Returns: A copy of the node, or NULL if memory has run out 00438 00439 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 00440 The function is virtual, and must be defined for all derived classes. 00441 00442 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 00443 error and the function returns NULL. 00444 00445 **********************************************************************************************/ 00446 00447 Node* NodeMould::SimpleCopy() 00448 { 00449 NodeMould* pCopyOfNode = new NodeMould(); 00450 ERROR2IF(pCopyOfNode == NULL,NULL,_R(IDE_NOMORE_MEMORY)); 00451 CopyNodeContents(pCopyOfNode); 00452 return (pCopyOfNode); 00453 } 00454 00455 00456 /*********************************************************************************************** 00457 00458 > void NodeMould::CopyNodeContents(Node* pCopyOfNode) 00459 00460 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00461 Created: 5/12/94 00462 Inputs: pCopyOfNode - The node to copy data to 00463 Outputs: - 00464 Returns: - 00465 Purpose: Copies the data from this node to pCopyOfNode by first calling the base class 00466 to get it to copy its stuff, and then copying its own stuff 00467 Scope: protected 00468 SeeAlso: NodeGroup::CopyNodeContents 00469 00470 ***********************************************************************************************/ 00471 00472 void NodeMould::CopyNodeContents(NodeMould* pCopyOfNode) 00473 { 00474 ERROR3IF(pCopyOfNode==NULL,"NodeMould::CopyNodeContents() was asked to copy into a NULL pointer"); 00475 NodeGroup::CopyNodeContents(pCopyOfNode); 00476 00477 // Make sure we copy all our personal data here 00478 pCopyOfNode->DetachedGeometry = DetachedGeometry; 00479 00480 // Need to copy the shape and adjust our pointer. 00481 MouldGeometry* pNewGeom = (MouldGeometry*) pMouldGeometry->MakeCopy(); 00482 00483 // if the shape is NULL ie we couldn't build it what do we do? 00484 if (pNewGeom) 00485 pCopyOfNode->pMouldGeometry = pNewGeom; 00486 00487 } 00488 00489 00490 /*********************************************************************************************** 00491 > void NodeMould::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00492 00493 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00494 Created: 18/12/2003 00495 Outputs: - 00496 Purpose: Polymorphically copies the contents of this node to another 00497 Errors: An assertion failure will occur if NodeCopy is NULL 00498 Scope: protected 00499 00500 ***********************************************************************************************/ 00501 00502 void NodeMould::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00503 { 00504 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 00505 ENSURE(IS_A(pNodeCopy, NodeMould), "PolyCopyNodeContents given wrong dest node type"); 00506 00507 if (IS_A(pNodeCopy, NodeMould)) 00508 CopyNodeContents((NodeMould*)pNodeCopy); 00509 } 00510 00511 00512 00513 /******************************************************************************************** 00514 00515 > virtual UINT32 NodeMould::GetNodeSize() const 00516 00517 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00518 Created: 5/12/94 00519 Inputs: - 00520 Outputs: - 00521 Returns: The size of the node in bytes 00522 Purpose: For finding the size of the node 00523 00524 SeeAlso: Node::GetSubtreeSize 00525 00526 ********************************************************************************************/ 00527 00528 UINT32 NodeMould::GetNodeSize() const 00529 { 00530 return (sizeof(NodeMould)); 00531 } 00532 00533 00534 00535 /******************************************************************************************** 00536 00537 > virtual DocRect NodeMould::GetBlobBoundingRect() 00538 00539 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00540 Created: 20/12/94 00541 Returns: DocRect - Returns the bounding rect of the path and its blobs 00542 Purpose: This calculates the bounding box of the mould and adds in the influence of 00543 the selection blobs. It does not consider if the blobs are visible or not, 00544 it just gives the bounding box that they would occupy if they were visible 00545 Note, the mould blob bounds are simply made up of the nodemouldpath bounds 00546 and thats yer lot. 00547 00548 ********************************************************************************************/ 00549 00550 DocRect NodeMould::GetBlobBoundingRect() 00551 { 00552 #if !defined(EXCLUDE_FROM_RALPH) 00553 DocRect Rect; 00554 // Get our blob bounds 00555 if (pMouldGeometry) 00556 Rect = pMouldGeometry->GetBlobBoundingRect(); 00557 00558 // Note I Should really be using NodeRenderableBounded::IncludeChildrensBoundingRects() 00559 // But sadly I cannot, simply due to the fact that it doesn't work!!! 00560 // When given a null rectangle it gets totally confused. 00561 00562 // Make sure we include the Bounds of our children 00563 NodeMould::IncludeChildrensBoundingRects(Rect); 00564 00565 // return the rectangle with the blobs included 00566 return Rect; 00567 #else 00568 return DocRect(0,0,0,0); 00569 #endif 00570 } 00571 00572 00573 00574 /******************************************************************************************** 00575 00576 > DocRect NodeMould::GetRenderBounds() 00577 00578 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00579 Created: 20/12/94 00580 Returns: DocRect - the bounding rect of the mould 00581 Purpose: Return the bounding rect of the mould. This rectangle includes only 00582 those items in the mould which are visible and hence will be invalidated 00583 by the OS. Items such as the NodeMouldGroup (which are of course invisible) 00584 do not get involved in the renderbounds 00585 00586 ********************************************************************************************/ 00587 00588 DocRect NodeMould::GetRenderBounds() 00589 { 00590 DocRect Rect; 00591 if (pMouldGeometry) 00592 Rect = pMouldGeometry->GetBlobBoundingRect(); 00593 00594 Rect = Rect.Union(GetChildrensBounds()); 00595 return Rect; 00596 } 00597 00598 00599 DocRect NodeMould::GetChildrensBounds() 00600 { 00601 DocRect Rect; 00602 NodeMould::IncludeChildrensBoundingRects(Rect); 00603 return Rect; 00604 /* DocRect Rect,BlobRect; 00605 Node* pNode = FindFirstChild(); 00606 while (pNode) 00607 { 00608 if (!(pNode->IsNodeHidden())) 00609 { 00610 if (pNode->IsNodeRenderableClass()) 00611 { 00612 if (!(pNode->IsKindOf(CC_RUNTIME_CLASS(NodeMouldGroup)))) 00613 { 00614 BlobRect=((NodeRenderable*)pNode)->GetBlobBoundingRect(); 00615 Rect=Rect.Union(BlobRect); 00616 } 00617 } 00618 } 00619 pNode=pNode->FindNext(); 00620 } 00621 return Rect;*/ 00622 } 00623 00624 00625 /******************************************************************************************** 00626 00627 > void NodeMould::IncludeChildrensBoundingRects(DocRect& BoundingRect) 00628 00629 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00630 Created: 30/01/95 00631 Outputs: BoundingRect is updated to include the childrens bounding rects. 00632 Purpose: The childrens Blob bounding rects are added to the BoundingRect. 00633 00634 ********************************************************************************************/ 00635 00636 void NodeMould::IncludeChildrensBoundingRects(DocRect& BoundingRect) 00637 { 00638 Node* pNode; 00639 DocRect BlobRect; 00640 00641 // Start scanning the children 00642 pNode = this->FindFirstChild(); 00643 while (pNode!=NULL) 00644 { 00645 if (!pNode->IsNodeHidden()) 00646 { 00647 if (pNode->IsAnObject()) 00648 { 00649 BlobRect=((NodeRenderable*)pNode)->GetBlobBoundingRect(); 00650 BoundingRect=BoundingRect.Union(BlobRect); 00651 } 00652 } 00653 pNode=pNode->FindNext(); 00654 } 00655 } 00656 00657 00658 00659 /******************************************************************************************** 00660 00661 > BOOL NodeMould::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 00662 Spread* pSpread ) 00663 00664 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00665 Created: 5/12/94 00666 Inputs: PointerPos - The Location of the mouse pointer at the time of the click 00667 Click - The type of click received (single, double, drag etc) 00668 ClickMods - The modifiers to the click (eg shift, control etc ) 00669 Returns: TRUE - if the node claims the click as its own 00670 FALSE - if it is not interested in the click 00671 Purpose: Allows the Node to respond to clicks by selecting its blobs or starting 00672 drags etc. 00673 Here we check for clicks over a moulds shape. If a blob has been clicked 00674 on we start a new drag operation to alter the shape of the mould. 00675 00676 ********************************************************************************************/ 00677 00678 BOOL NodeMould::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 00679 Spread* pSpread ) 00680 { 00681 #if !defined(EXCLUDE_FROM_RALPH) 00682 // we only handle the click if we can confirm that object blobs are being displayed. 00683 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00684 if (pBlobMgr == NULL) 00685 return FALSE; 00686 if (!pBlobMgr->GetCurrentInterest().Object) 00687 return FALSE; 00688 00689 // pass the click on to the shape handler if there is one. 00690 if (pMouldGeometry) 00691 { 00692 if (pMouldGeometry->OnClick(PointerPos, Click, ClickMods, pSpread, this)) 00693 return TRUE; 00694 } 00695 00696 // if none try the actual manifold shape itself. 00697 NodeMouldPath* pPathShape = GetPathShape(); 00698 if (pPathShape) 00699 { 00700 if (pPathShape->OnClick(PointerPos, Click, ClickMods, pSpread)) 00701 return TRUE; 00702 } 00703 #endif 00704 return FALSE; 00705 } 00706 00707 00708 /*********************************************************************************************** 00709 00710 > BOOL NodeMould::OnMouseMove(DocCoord PointerPos, Spread* pSpread, ClickModifiers ClickMods) 00711 00712 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00713 Created: 5/12/94 00714 Inputs: PointerPos - The Location of the mouse pointer 00715 Click - The type of click received (single, double, drag etc) 00716 ClickMods - The modifiers to the click (eg shift, control etc ) 00717 Outputs: - 00718 Returns: TRUE - if the node has processed this event 00719 FALSE - if not 00720 Purpose: A very unusual function to find in a node. This must exist so that the mould 00721 tool can ask the mould object what cursor to show as the mouse moves around. 00722 The function is called for each selected mould object when the mould tool is 00723 current. 00724 The nub of the problem is that a mould object can basically be made up of 00725 virtually anything. We actually need to ask the mould shape handler inside 00726 the mould object what type of cursor it wants to show and what sort of 00727 resouced message it would like to display. This cannot be determined from 00728 outside the object. 00729 00730 ***********************************************************************************************/ 00731 00732 BOOL NodeMould::OnMouseMove(DocCoord PointerPos, Spread* pSpread, ClickModifiers ClickMods, INT32* ctype, INT32* msgres) 00733 { 00734 #if !defined(EXCLUDE_FROM_RALPH) 00735 // check for movement over our mould path end points and get 00736 // the caller to set the correct status bar and cursor stuff 00737 if (OverMouldEndPoint(PointerPos,pSpread)) 00738 { 00739 *ctype=3; 00740 *msgres=3; 00741 return TRUE; 00742 } 00743 00744 // pass the mouse move on to the shape handler if there is one. 00745 if (pMouldGeometry) 00746 { 00747 if (pMouldGeometry->OnMouseMove(PointerPos, pSpread, ClickMods, ctype, msgres)) 00748 return TRUE; 00749 } 00750 00751 #endif 00752 // otherwise, nothing to do with us matey 00753 return FALSE; 00754 } 00755 00756 00757 /******************************************************************************************** 00758 00759 > void NodeMould::OverMouldEndPoint(DocCoord PointerPos, Spread* pSpread) 00760 00761 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00762 Created: 07/02/95 00763 Inputs: PointerPos = coordinate of mouse move, 00764 pSpread = pointer to spread containing coord 00765 Outputs: - 00766 Returns: TRUE if the coord is over one of the path end points. 00767 FALSE if not 00768 Purpose: This routine checks for the mouse being over end points of our mould path. 00769 00770 ********************************************************************************************/ 00771 00772 BOOL NodeMould::OverMouldEndPoint(DocCoord coord, Spread* pSpread) 00773 { 00774 // find the actual moulding path object inside ourselves. 00775 Path* pPath = GetPath(); 00776 if (pPath) 00777 { 00778 INT32 Closest=0; 00779 if (pPath->FindNearestPoint(coord, POINTFLAG_ENDPOINTS | POINTFLAG_CONTROLPOINTS, &Closest)) 00780 return TRUE; 00781 } 00782 return FALSE; 00783 } 00784 00785 00786 00787 /******************************************************************************************** 00788 00789 > virtual BOOL NodeMould::CanBecomeA(BecomeA* pBecomeA) 00790 00791 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00792 Created: 2/12/94 00793 Inputs: InkClass: The class of object 00794 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL). 00795 *pNumObects in undefined on entry 00796 Returns: TRUE if the node, or any of its children can transmogrify themselves to become 00797 an InkClass object 00798 Purpose: This function is used by the convert to shapes operation. It determines if 00799 the node or any of its children can convert themselves into an InkClass object. 00800 00801 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number 00802 of pClass objects you create. It should NOT contain any additional objects you may produce 00803 such as group objects for containing the pClass object, or attributes. 00804 00805 Also, the entry value of *pNumObjects cannot be assumed to be 0. 00806 00807 ********************************************************************************************/ 00808 00809 BOOL NodeMould::CanBecomeA(BecomeA* pBecomeA) 00810 { 00811 // The NodeMoulder can become a NodePath 00812 if (pBecomeA->BAPath()) 00813 { 00814 if (pBecomeA->IsCounting()) 00815 { 00816 // We need to count how many paths it will create 00817 // We do this by adding the values received by each child NodeMoulder 00818 NodeMoulder* pNodeMoulder = FindFirstMoulder(); 00819 while (pNodeMoulder != NULL) 00820 { 00821 pNodeMoulder->CanBecomeA(pBecomeA); // Increments count 00822 00823 pNodeMoulder = FindNextMoulder(pNodeMoulder); 00824 } 00825 } 00826 00827 return TRUE; 00828 } 00829 00830 return FALSE; 00831 } 00832 00833 00834 00835 /******************************************************************************************** 00836 00837 > virtual BOOL NodeMould::DoBecomeA(BecomeA* pBecomeA) 00838 00839 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00840 Created: 5/12/94 00841 Inputs: pBecomeA = ptr to a class that contains all the info needed to become a new 00842 type of node. 00843 Outputs: - 00844 Returns: TRUE if the object has been transformed, FALSE if we run out of memory 00845 00846 Purpose: Transforms the object into another type of object. 00847 This converts all its children, and replaces itself in the tree with a NodeGroup 00848 Errors: - 00849 SeeAlso: Node::CanBecomeA 00850 00851 ********************************************************************************************/ 00852 00853 BOOL NodeMould::DoBecomeA(BecomeA* pBecomeA) 00854 { 00855 BOOL ok; 00856 00857 switch (pBecomeA->GetReason()) 00858 { 00859 case BECOMEA_REPLACE: 00860 { 00861 // ERROR2IF(pBecomeA->GetUndoOp() == NULL,FALSE,"Trying to replace a NodeMould, but pUndoOp == NULL"); 00862 UndoableOperation* pUndoOp = pBecomeA->GetUndoOp(); 00863 00864 // If replacing the mould with shapes, hide the mould, create a group, and move all the children 00865 // so they become children of the new group node 00866 00867 NodeMoulder* pMoulder = FindFirstMoulder(); 00868 if (pMoulder!=NULL) 00869 { 00870 BOOL IsSelected = this->IsSelected(); 00871 SetSelected(FALSE); 00872 00873 // Localise only the current children so undo factors out only these 00874 AttrTypeSet AttrTypes; 00875 if (!CreateAttrSetFromChildren(AttrTypes)) 00876 return FALSE; 00877 00878 // localise common child attributes before moving objects! 00879 if (pUndoOp) 00880 { 00881 if (!pUndoOp->DoLocaliseCommonAttributes(this, FALSE, FALSE, &AttrTypes)) 00882 return FALSE; 00883 00884 if (!pUndoOp->DoLocaliseCommonAttributes(pMoulder)) 00885 return FALSE; 00886 } 00887 else 00888 { 00889 if (!LocaliseCommonAttributes(FALSE, FALSE, &AttrTypes)) 00890 return FALSE; 00891 00892 if (!pMoulder->LocaliseCommonAttributes()) 00893 return FALSE; 00894 } 00895 00896 // Pass on this message to our child ink nodes first 00897 Node* pNode = pMoulder->FindFirstChild(); 00898 while (pNode != NULL) 00899 { 00900 Node* pThisNode = pNode; 00901 pNode = pNode->FindNext(); 00902 pThisNode->DoBecomeA(pBecomeA); 00903 } 00904 00905 // Allocate a new NodeGroup node 00906 NodeGroup* pNodeGroup; 00907 ALLOC_WITH_FAIL(pNodeGroup, (new NodeGroup), pUndoOp); 00908 if (pNodeGroup == NULL) 00909 return FALSE; 00910 00911 // Insert the NodeGroup next to the NodeMould 00912 if (pUndoOp) 00913 { 00914 if (!pUndoOp->DoInsertNewNode(pNodeGroup,this,NEXT,FALSE,FALSE,FALSE,FALSE)) 00915 return FALSE; 00916 00917 // if we were selected the lets select our group 00918 if (IsSelected) 00919 { 00920 // Select the group 00921 if (!pUndoOp->DoSelectNode(pNodeGroup,FALSE)) 00922 return FALSE; 00923 } 00924 } 00925 else 00926 { 00927 pNodeGroup->AttachNode(this,NEXT); 00928 } 00929 00930 // Now move each node in turn. 00931 pNode = pMoulder->FindLastChild(); 00932 while (pNode != NULL) 00933 { 00934 // Find the next node to move before we shift up the children 00935 Node* pPrevNode = pNode->FindPrevious(); 00936 if (pNode->IsAnObject()) 00937 { 00938 if (pUndoOp) 00939 { 00940 CALL_WITH_FAIL(pUndoOp->DoMoveNode(pNode, pNodeGroup, FIRSTCHILD), pUndoOp, ok); 00941 if (!ok) 00942 return FALSE; 00943 } 00944 else 00945 { 00946 pNode->MoveNode(pNodeGroup, FIRSTCHILD); 00947 } 00948 } 00949 pNode = pPrevNode; 00950 } 00951 00952 // Karim 15/05/2000 - this new loop copies non-optimising attrs applied to 00953 // the NodeMould object, into the new group. Note that although CopyNode() 00954 // is NOT undoable, things should be fine as the insertion of the group *was*. 00955 pNode = FindLastChild(); 00956 while (pNode != NULL) 00957 { 00958 Node* pPrevNode = pNode->FindPrevious(); 00959 if ( pNode->IsAnAttribute() && 00960 !((NodeAttribute*)pNode)->ShouldBeOptimized() ) 00961 { 00962 CALL_WITH_FAIL(pNode->CopyNode(pNodeGroup, FIRSTCHILD), pUndoOp, ok) 00963 if (!ok) 00964 return FALSE; 00965 } 00966 pNode = pPrevNode; 00967 } 00968 00969 // factor up on the group. 00970 if (pUndoOp) 00971 { 00972 if (!pUndoOp->DoFactorOutCommonChildAttributes(pNodeGroup)) 00973 return FALSE; 00974 } 00975 else 00976 { 00977 if (!pNodeGroup->FactorOutCommonChildAttributes()) 00978 return FALSE; 00979 } 00980 00981 // Remove any nasty perspective fills from the result 00982 NodeMould::RemovePerspectiveFills(pNodeGroup, pUndoOp); 00983 00984 // Hide the mould node 00985 if (pUndoOp) 00986 { 00987 if (!pUndoOp->DoHideNode(this, FALSE, NULL, FALSE)) 00988 return FALSE; 00989 } 00990 else 00991 { 00992 CascadeDelete(); 00993 delete this; 00994 } 00995 } 00996 } 00997 break; 00998 00999 case BECOMEA_PASSBACK: 01000 { 01001 // Sequentially ask the children of the blend to DoBecomeA 01002 // This is all that's required because the child objects are only passing back 01003 // the new node type, and NOT replacing themselves in the tree 01004 // This also ensures the receipient gets the list of paths in render order 01005 Node* pNode = FindFirstChild(); 01006 while (pNode != NULL) 01007 { 01008 Node* pThisNode = pNode; 01009 pNode = pNode->FindNext(); 01010 if (IS_A(pThisNode,NodeMoulder)) 01011 { 01012 if (!pThisNode->DoBecomeA(pBecomeA)) 01013 return FALSE; 01014 } 01015 } 01016 } 01017 break; 01018 01019 default: 01020 ERROR3_PF(("Unknown BecomeA reason %d",pBecomeA->GetReason())); 01021 break; 01022 } 01023 01024 return TRUE; 01025 } 01026 01027 01028 01029 01030 /******************************************************************************************** 01031 01032 > void NodeMoulder::RemovePerspectiveFills(Node* pParetNode, UndoableOperation* pUndoOp) 01033 01034 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01035 Created: 31/6/95 01036 Inputs: pParentNode - a pointer to a node to start removing from 01037 pUndoOp - a pointer to the currently active undo operation. can be NULL 01038 Returns: - 01039 Purpose: This function scans the children of a given parent for perspectivised 01040 bitmap fills. It replaces these attributes with standard bitmap fill atts 01041 in order to avoid perspective bitmap fills from escaping during a make 01042 shapes 01043 01044 ********************************************************************************************/ 01045 01046 void NodeMould::RemovePerspectiveFills(Node* pParentNode, UndoableOperation* pUndoOp) 01047 { 01048 // BOOL WarnedUser = FALSE; 01049 01050 // Found the NodeMoulder, so scan it's children, looking for perspectivised Attributes 01051 Node* pMoulderChild = pParentNode->FindFirstChild(); 01052 Node* pNext; 01053 01054 while (pMoulderChild != NULL) 01055 { 01056 Node* pThisChild = pMoulderChild; 01057 pMoulderChild = pMoulderChild->FindNext(); 01058 01059 // Scan the nodes children for Perspective fills 01060 Node* pChild = pThisChild->FindFirstDepthFirst(); 01061 while (pChild) 01062 { 01063 pNext = pChild->FindNextDepthFirst(pThisChild); 01064 01065 if (pChild->IsAnAttribute() && ((NodeAttribute*)pChild)->IsAFillAttr()) 01066 { 01067 if (((AttrFillGeometry*)pChild)->IsPerspective()) 01068 { 01069 // Remove any perspectiven 01070 ((AttrFillGeometry*)pChild)->RemovePerspective(pUndoOp); 01071 } 01072 } 01073 pChild=pNext; 01074 } 01075 } 01076 } 01077 01078 01079 01080 /******************************************************************************************** 01081 01082 > BOOL NodeMould::CreateAttrSetFromChildren(AttrTypeSet& AttSet) 01083 01084 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01085 Created: 21/06/95 01086 Inputs: - 01087 Outputs: AttSet = a set of attributes which are children of the compound node 01088 Returns: TRUE - if the set was built correctly 01089 FALSE - if not 01090 Purpose: Builds a set of AttrTypeSet set of attributes from the children of a node 01091 01092 ********************************************************************************************/ 01093 01094 BOOL NodeMould::CreateAttrSetFromChildren(AttrTypeSet& AttSet) 01095 { 01096 Node* qNode = FindFirstChild(); 01097 while (qNode && qNode->IsAnAttribute()) 01098 { 01099 if (!AttSet.AddToSet(((NodeAttribute*)qNode)->GetAttributeType())) 01100 return FALSE; 01101 qNode=qNode->FindNext(); 01102 } 01103 return TRUE; 01104 } 01105 01106 01107 01108 01109 /******************************************************************************************** 01110 01111 > virtual void NodeMould::RenderObjectBlobs(RenderRegion* pRender) 01112 01113 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01114 Created: 20/12/94 01115 Inputs: pRender - The region to draw the blobs in 01116 Purpose: This renders all the blobs associated with this mould node 01117 This node doesn't do any rendering itself. All it does is ask the shape 01118 object to render itself. 01119 01120 ********************************************************************************************/ 01121 01122 void NodeMould::RenderObjectBlobs(RenderRegion* pRegion) 01123 { 01124 #if !defined(EXCLUDE_FROM_RALPH) 01125 // We need to ask the mould shape to render its edit blobs. 01126 if (!RenderBlobs) 01127 return; 01128 01129 if (pMouldGeometry) 01130 pMouldGeometry->RenderControlBlobs(pRegion); 01131 01132 // We also need to ask the mould manifold to render its blobs too. 01133 NodeMouldPath* pShape = GetPathShape(); 01134 if (pShape) 01135 pShape->RenderObjectBlobs(pRegion); 01136 #endif 01137 } 01138 01139 01140 01141 /******************************************************************************************** 01142 01143 > void NodeMould::RenderTinyBlobs(RenderRegion* pRender) 01144 01145 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01146 Created: 23/6/95 01147 Inputs: pRender - The region to render the blobs into 01148 Purpose: Draws the paths Tiny blob into the render region supplied 01149 01150 ********************************************************************************************/ 01151 01152 void NodeMould::RenderTinyBlobs(RenderRegion* pRegion) 01153 { 01154 #if !defined(EXCLUDE_FROM_RALPH) 01155 NodeMoulder* pMoulder = FindFirstMoulder(); 01156 if (pMoulder!=NULL) 01157 { 01158 Node* pNode = pMoulder->FindLastChild(); 01159 while (pNode != NULL && !pNode->IsAnObject()) 01160 { 01161 // pNode was not a ink object, so get the next one 01162 pNode = pNode->FindPrevious(); 01163 } 01164 01165 if (pNode) 01166 { 01167 // Render the tiny blob of that object 01168 ((NodeRenderableInk*)pNode)->RenderTinyBlobs(pRegion); 01169 } 01170 } 01171 #endif 01172 } 01173 01174 01175 01176 /******************************************************************************************** 01177 01178 > void NodeMould::RedrawMould() 01179 01180 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01181 Created: 16/01/95 01182 Inputs: - 01183 Purpose: Forces a redraw over the mould object 01184 01185 ********************************************************************************************/ 01186 01187 void NodeMould::RedrawMould() 01188 { 01189 Spread* pSpread = FindParentSpread(); 01190 01191 if (pSpread != NULL) 01192 { 01193 BaseDocument* pDoc = pSpread->FindOwnerDoc(); 01194 01195 if ((pDoc != NULL) && (IS_A(pDoc, Document))) 01196 { 01197 DocRect Invalid = GetBlobBoundingRect(); 01198 ((Document *) pDoc)->ForceRedraw( pSpread, Invalid, FALSE, this); 01199 } 01200 } 01201 } 01202 01203 /*********************************************************************************************** 01204 01205 > void NodeMould::ShowDebugTreeDetails() const 01206 01207 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01208 Created: 20/12/94 01209 Purpose: Displays debugging info of the tree 01210 SeeAlso: NodeRenderableInk::ShowDebugTreeDetails 01211 01212 ***********************************************************************************************/ 01213 01214 #ifdef _DEBUG 01215 void NodeMould::ShowDebugTreeDetails() const 01216 { 01217 TRACE( _T("Mould ")); 01218 // Display a bit of debugging info 01219 // For now, we will just call the base class version 01220 NodeRenderableInk::ShowDebugTreeDetails(); 01221 } 01222 #endif 01223 01224 01225 01226 01227 /******************************************************************************************** 01228 01229 > void NodeMould::GetDebugDetails( StringBase* Str ) 01230 01231 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01232 Created: 20/12/94 01233 Outputs: Str: String giving debug info about the node 01234 Purpose: For obtaining debug information about the Node 01235 01236 ********************************************************************************************/ 01237 01238 void NodeMould::GetDebugDetails( StringBase* Str ) 01239 { 01240 #ifdef _DEBUG 01241 // Call base class 01242 NodeRenderableInk::GetDebugDetails( Str ); 01243 01244 String_256 TempStr; 01245 01246 (*Str) += TEXT( "\r\nMould Data Dump\r\n" ); 01247 01248 DocRect BlobRect = GetBlobBoundingRect(); 01249 TempStr._MakeMsg( TEXT("Blob Bounding Rect :-\r\n\t#1%ld,\t#2%ld\r\n\t#3%ld,\t#4%ld\r\n"), 01250 BlobRect.lo.x, BlobRect.lo.y, BlobRect.hi.x, BlobRect.hi.y ); 01251 (*Str) += TempStr; 01252 01253 // call the mould shape debug function 01254 if (pMouldGeometry) 01255 pMouldGeometry->GetDebugDetails( Str ); 01256 #endif 01257 } 01258 01259 /******************************************************************************************** 01260 01261 > virtual void NodeMould::Transform( TransformBase& Trans ) 01262 01263 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01264 Created: 23/12/94 01265 Inputs: Trans - A transformation object 01266 Purpose: Transforms the mould object and all its children. 01267 01268 ********************************************************************************************/ 01269 01270 void NodeMould::Transform( TransformBase& Trans ) 01271 { 01272 // Transform all the children 01273 // See GroupCanTransformCached 01274 NodeGroup::Transform(Trans); 01275 01276 // once transformed get the shape controller to transform its stuff 01277 if (pMouldGeometry) 01278 { 01279 Path* pPath = GetPath(); 01280 NodeMouldGroup* pMouldGroup = FindMouldGroup(); 01281 if (pPath && pMouldGroup) 01282 { 01283 DocRect Rect = pMouldGroup->GetChildrensBounds(TRUE); 01284 pMouldGeometry->Transform(pPath, &Rect, Trans); 01285 } 01286 } 01287 } 01288 01289 01290 /******************************************************************************************** 01291 01292 > MouldSpace NodeMould::Describe() 01293 01294 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01295 Created: 23/12/94 01296 Inputs: 01297 Returns: The current mould space defined for this mould object. ie what type of 01298 mould geometry it uses, eg envelope, perspective etc. 01299 Purpose: Find out what type of geometry is defined for this mould object. 01300 01301 ********************************************************************************************/ 01302 01303 MouldSpace NodeMould::DescribeGeometry() 01304 { 01305 if (pMouldGeometry) 01306 return pMouldGeometry->Describe(); 01307 01308 return MOULDSPACE_UNDEFINED; 01309 } 01310 01311 01312 01313 /******************************************************************************************** 01314 01315 > Path* NodeMould::GetPath() 01316 01317 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01318 Created: 04/01/95 01319 Inputs: - 01320 Returns: A pointer to the path object 01321 inside the first node mould shape object 01322 inside the NodeMould! 01323 NULL if unable to find the object 01324 Purpose: A useful function to find the actual path used for moulding 01325 As this is used quite a lot its been 'function' alised. 01326 01327 ********************************************************************************************/ 01328 01329 Path* NodeMould::GetPath() 01330 { 01331 NodeMouldPath* pNodeMPath = GetPathShape(); 01332 if (pNodeMPath) 01333 return (&(pNodeMPath->InkPath)); 01334 return NULL; 01335 } 01336 01337 /******************************************************************************************** 01338 01339 > NodeMouldPath* NodeMould::GetPathShape() 01340 01341 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01342 Created: 23/12/94 01343 Inputs: - 01344 Returns: A pointer to the first node mould path object inside the NodeMould 01345 NULL if unable to find the object 01346 Purpose: A useful function to find the first node mould shape object within a NodeMould 01347 object. As this is used quite a lot its been 'function'alised. 01348 01349 ********************************************************************************************/ 01350 01351 NodeMouldPath* NodeMould::GetPathShape() 01352 { 01353 // try to find the first node moulder object 01354 Node* pNode = FindFirstChild(); 01355 ERROR2IF(pNode == NULL,NULL, "No children found in MouldObject during NodeMould::GetPathShape()"); 01356 01357 // check for the right class 01358 if (pNode->GetRuntimeClass() != CC_RUNTIME_CLASS(NodeMouldPath)) 01359 pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeMouldPath)); 01360 01361 // there's no geometry object inside this mould so we still can't do anything. 01362 ERROR2IF(pNode==NULL,NULL, "Can't find first NodeMouldPath as a child of NodeMould"); 01363 01364 return (NodeMouldPath*)pNode; 01365 } 01366 01367 01368 01369 /******************************************************************************************** 01370 01371 > NodeMoulder* NodeMould::FindFirstMoulder(BOOL errorcheck=TRUE) 01372 01373 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01374 Created: 23/12/94 01375 Inputs: 01376 Returns: A pointer to the first node moulder object inside the NodeMould 01377 NULL if unable to find the object 01378 Purpose: A useful function to find the first node moulder object within a NodeMould 01379 object. As this is used quite a lot its been 'function'alised. 01380 01381 ********************************************************************************************/ 01382 01383 NodeMoulder* NodeMould::FindFirstMoulder(BOOL errorcheck) 01384 { 01385 // try to find the first node moulder object 01386 Node* pNode = FindFirstChild(); 01387 01388 if (pNode==NULL) 01389 { 01390 if (errorcheck) 01391 ERROR2(NULL,"No children found in MouldObject during NodeMould::FindFirstMoulder()"); 01392 return NULL; 01393 } 01394 01395 // check for the right class 01396 if (pNode->GetRuntimeClass() != CC_RUNTIME_CLASS(NodeMoulder)) 01397 pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeMoulder)); 01398 01399 // there's no moulder object inside this mould so we still can't do anything. 01400 if (pNode==NULL) 01401 { 01402 if (errorcheck) 01403 ERROR2(NULL,"Can't find first NodeMoulder as a child of NodeMould"); 01404 return NULL; 01405 } 01406 01407 // do a type conversion for speed 01408 NodeMoulder* pMoulder = (NodeMoulder*)pNode; 01409 01410 return pMoulder; 01411 } 01412 01413 /******************************************************************************************** 01414 01415 > NodeMoulder* NodeMould::FindNextMoulder(NodeMoulder* pNodeMoulder) 01416 01417 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01418 Created: 11/1/96 01419 Inputs: pNodeMoulder = ptr to current node moulder 01420 Returns: A pointer to the next node moulder object inside the NodeMould 01421 NULL if unable to find the object 01422 Purpose: A useful function to find the next node moulder object within a NodeMould 01423 object. 01424 01425 ********************************************************************************************/ 01426 01427 NodeMoulder* NodeMould::FindNextMoulder(NodeMoulder* pNodeMoulder) 01428 { 01429 ERROR2IF(pNodeMoulder == NULL,NULL,"pNodeMoulder == NULL"); 01430 01431 NodeMoulder* pNextNodeMoulder = (NodeMoulder*)pNodeMoulder->FindNext(); 01432 01433 while (pNextNodeMoulder != NULL && !IS_A(pNextNodeMoulder,NodeMoulder)) 01434 pNextNodeMoulder = (NodeMoulder*)pNextNodeMoulder->FindNext(); 01435 01436 return pNextNodeMoulder; 01437 } 01438 01439 /******************************************************************************************** 01440 01441 > INT32 NodeMould::CountMoulders() 01442 01443 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01444 Created: 23/03/95 01445 Inputs: 01446 Returns: The number of moulder objects within this mould 01447 Purpose: Count the number of moulder objects which have been created within this 01448 mould. This does not include hidden moulder objects of course. 01449 01450 ********************************************************************************************/ 01451 01452 INT32 NodeMould::CountMoulders() 01453 { 01454 INT32 Count=0; 01455 Node* pNode = FindFirstChild(); 01456 ERROR2IF(pNode == NULL,0, "No children found in MouldObject during NodeMould::CountMoulders()"); 01457 while (pNode!=NULL) 01458 { 01459 // check for the right class 01460 if (pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeMoulder)) 01461 Count+=1; 01462 01463 pNode=pNode->FindNext(); 01464 } 01465 return Count; 01466 } 01467 01468 01469 /******************************************************************************************** 01470 01471 > NodeMouldGroup* NodeMould::FindMouldGroup(BOOL errorcheck=TRUE) 01472 01473 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01474 Created: 23/12/94 01475 Inputs: 01476 Returns: A pointer to the first node mould group object inside the NodeMould 01477 NULL if unable to find the object 01478 Purpose: A useful function to find the mould group node within a NodeMould 01479 object. As this is used quite a lot its been 'function'alised. 01480 01481 ********************************************************************************************/ 01482 01483 NodeMouldGroup* NodeMould::FindMouldGroup(BOOL errorcheck) 01484 { 01485 // try to find the first child node 01486 Node* pNode = FindFirstChild(); 01487 01488 if (pNode==NULL) 01489 { 01490 if (errorcheck) 01491 ERROR2(NULL,"No children found in MouldObject during NodeMould::FindMouldGroup()"); 01492 return NULL; 01493 } 01494 01495 // check for the right class 01496 if (pNode->GetRuntimeClass() != CC_RUNTIME_CLASS(NodeMouldGroup)) 01497 pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeMouldGroup)); 01498 01499 // there's no moulder object inside this mould so we still can't do anything. 01500 01501 if (pNode==NULL) 01502 { 01503 if (errorcheck) 01504 ERROR2(NULL,"Can't find first NodeMouldGroup as a child of NodeMould"); 01505 return NULL; 01506 } 01507 01508 // do a type conversion for speed 01509 NodeMouldGroup* pMouldGrp = (NodeMouldGroup*)pNode; 01510 01511 return pMouldGrp; 01512 } 01513 01514 01515 /******************************************************************************************** 01516 01517 > BOOL NodeMould::CreateAllMoulderObjects(UndoableOperation* pOp) 01518 01519 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01520 Created: 19/12/94 01521 Inputs: pOp = pointer to an operation (can be null) 01522 Returns: TRUE if all moulder objects have rebuilt themselves 01523 FALSE if one failed. 01524 Purpose: Scan through the children of a mould object, getting all NodeMoulders 01525 to regenerate their moulded objects. 01526 01527 ********************************************************************************************/ 01528 01529 BOOL NodeMould::CreateAllMoulderObjects(UndoableOperation* pOp) 01530 { 01531 // Scan inside the mould object for the first moulder 01532 NodeMoulder* pMoulder = FindFirstMoulder(); 01533 if (!pMoulder) 01534 // there's no moulder object inside this mould so we still can't do anything. 01535 return FALSE; 01536 01537 // first find the mould group 01538 NodeMouldGroup* pMouldGroup = FindMouldGroup(); 01539 if (!pMouldGroup) 01540 // there's no mould group inside this mould so we still can't do anything. 01541 return FALSE; 01542 01543 while (pMoulder) 01544 { 01545 // create moulds for this moulder 01546 if (!pMoulder->CreateMouldedObjects(pMouldGroup, pMouldGeometry, pOp)) 01547 return FALSE; 01548 // skip to the next moulder object 01549 pMoulder = (NodeMoulder*) pMoulder->FindNext(CC_RUNTIME_CLASS(NodeMoulder)); 01550 } 01551 return TRUE; 01552 } 01553 01554 01555 01556 /******************************************************************************************** 01557 01558 > NodeMoulder* NodeMould::CreateNewMoulder(UndoableOperation* pOp) 01559 01560 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01561 Created: 19/12/94 01562 Inputs: pOp = A pointer to an active operation (can be null) 01563 Returns: a pointer to the moulder object (not in the tree). 01564 NULL if failed to create this moulder. 01565 Purpose: Creates a NodeMoulder object and returns a pointer to it 01566 SeeAlso: - 01567 01568 ********************************************************************************************/ 01569 01570 NodeMoulder* NodeMould::CreateNewMoulder(UndoableOperation* pOp) 01571 { 01572 BOOL ok; 01573 01574 // first find the mould group 01575 NodeMouldGroup* pMouldGroup = FindMouldGroup(); 01576 if (!pMouldGroup) return NULL; 01577 01578 // Now create a moulder object 01579 NodeMoulder* pMoulder; 01580 ALLOC_WITH_FAIL( pMoulder, new NodeMoulder, pOp); 01581 if (!pMoulder) return NULL; 01582 01583 // get the moulder to initialise itself 01584 CALL_WITH_FAIL(pMoulder->Initialise(pMouldGroup), pOp, ok); 01585 if (!ok) 01586 { 01587 delete pMoulder; 01588 return NULL; 01589 } 01590 01591 // its built so lets return it 01592 return pMoulder; 01593 } 01594 01595 01596 /******************************************************************************************** 01597 01598 > NodeMoulder* NodeMould::AddNewMoulder( Node* pContextNode, 01599 AttachNodeDirection Direction, 01600 UndoableOperation* pOp) 01601 01602 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01603 Created: 19/12/94 01604 Inputs: pContextNode = The node to which NewNode is to be attached 01605 Direction = The direction the new node should be attached to the 01606 context node. 01607 pOp = A pointer to an active operation (can be null) 01608 Returns: a pointer to the moulder object (not in the tree). 01609 NULL if failed to create this moulder. 01610 Purpose: Creates a NodeMoulder object and sticks it in the tree at the specified 01611 position 01612 SeeAlso: - 01613 01614 ********************************************************************************************/ 01615 01616 NodeMoulder* NodeMould::AddNewMoulder( Node* pContextNode, 01617 AttachNodeDirection Direction, 01618 UndoableOperation* pOp) 01619 { 01620 BOOL ok; 01621 01622 // create a new moulder object 01623 NodeMoulder* pMoulder = CreateNewMoulder(pOp); 01624 if (pMoulder==NULL) 01625 return NULL; 01626 01627 if (pOp!=NULL) 01628 { 01629 // now insert it in the tree in an undoable way 01630 CALL_WITH_FAIL(pOp->DoInsertNewNode(pMoulder, pContextNode, Direction, FALSE, FALSE, FALSE, FALSE), pOp, ok); 01631 } 01632 else 01633 { 01634 // all right then, insert it in a none undoable way 01635 pMoulder->AttachNode(pContextNode, Direction); 01636 pMoulder->SetSelected(FALSE); 01637 ok = TRUE; 01638 } 01639 01640 // if failed get rid of what we have 01641 if (!ok) 01642 { 01643 delete pMoulder; 01644 return NULL; 01645 } 01646 01647 return pMoulder; 01648 } 01649 01650 01651 01652 01653 /******************************************************************************************** 01654 01655 > NodeMouldPath* NodeMould::CreateNewMouldShape(Path* pShape, 01656 DocRect* const pDestin, 01657 UndoableOperation* pOp) 01658 01659 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01660 Created: 19/12/94 01661 Inputs: pPath = pointer to a path to use as a shape 01662 pDestin = a rectangular area to place the shape over. 01663 If this is NULL the path is used as is. 01664 pOp = A pointer to an active operation (can be null) 01665 Returns: a pointer to the created node mould path (not in the tree) 01666 NULL if unable to create the node 01667 Purpose: Creates a node mould path object using the path pointer given and the 01668 destination rectangle described. The objects pointer is returned 01669 SeeAlso: - 01670 01671 ********************************************************************************************/ 01672 01673 NodeMouldPath* NodeMould::CreateNewMouldShape( Path* pShape, 01674 DocRect* const pDestin, 01675 UndoableOperation* pOp) 01676 { 01677 ERROR2IF(pShape==NULL, NULL, "NodeMould::CreateNewMouldShape() called with a null path"); 01678 01679 // Note, we do not record the mouldspace in our class because 01680 // we dont really need to. The shape is an abstract class with 01681 // concrete geometries derived from it and hence we can call a shape 01682 // function and the run time binder will call the correct class func. 01683 01684 BOOL ok; 01685 01686 // build the new vector space polymorphically 01687 NodeMouldPath* pNodeMPath; 01688 ALLOC_WITH_FAIL( pNodeMPath, new NodeMouldPath, pOp); 01689 if (!pNodeMPath) 01690 return NULL; 01691 01692 Path* pPath = (&(pNodeMPath->InkPath)); 01693 01694 CALL_WITH_FAIL(pPath->Initialise(pShape->GetNumCoords(), 12), pOp, ok); 01695 if (!ok) 01696 { 01697 delete pNodeMPath; 01698 return NULL; 01699 } 01700 01701 CALL_WITH_FAIL(pPath->CopyPathDataFrom(pShape), pOp, ok); 01702 if (!ok) 01703 { 01704 delete pNodeMPath; 01705 return NULL; 01706 } 01707 01708 // make sure our path has no fill bit 01709 pPath->IsFilled=FALSE; 01710 01711 if (pDestin) 01712 { 01713 // we have been given a destination rectangle to map the path shape onto, 01714 // so first we need the source bbox 01715 DocRect Source = pPath->GetBoundingRect(); 01716 01717 // Build a transform matrix and apply it to this mould 01718 Matrix Mat(Source,*pDestin); 01719 Trans2DMatrix Trans(Mat); 01720 Trans.Transform( (DocCoord*)pPath->GetCoordArray(), pPath->GetNumCoords() ); 01721 } 01722 01723 return pNodeMPath; 01724 } 01725 01726 01727 01728 /******************************************************************************************** 01729 01730 > NodeMouldPath* NodeMould::AddNewMouldShape(Path* pShape, 01731 DocRect* const pDestin, 01732 UndoableOperation* pOp) 01733 01734 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01735 Created: 19/12/94 01736 Inputs: pPath = pointer to a path to use as a shape 01737 pDestin = a rectangular area to place the shape over. 01738 If this is NULL the path is used as is. 01739 pOp = A pointer to an active operation (can be null) 01740 Returns: a pointer to the created node mould path (inserted into the tree) 01741 NULL if unable to create the node 01742 Purpose: Creates a node mould path object using the path pointer given and the 01743 destination rectangle described. The object is inserted as the first child 01744 of this node mould object and its pointer is returned 01745 SeeAlso: - 01746 01747 ********************************************************************************************/ 01748 01749 NodeMouldPath* NodeMould::AddNewMouldShape( Path* pShape, 01750 DocRect* const pDestin, 01751 UndoableOperation* pOp) 01752 { 01753 ERROR2IF(pShape==NULL, NULL, "NodeMould::AddNewMouldShape() called with a null path"); 01754 01755 NodeMouldPath* pNodeMPath = CreateNewMouldShape(pShape, pDestin, pOp); 01756 if (pNodeMPath==NULL) 01757 return NULL; 01758 01759 NodeMouldGroup* pGroup = FindMouldGroup(FALSE); 01760 NodeMoulder* pMoulder = FindFirstMoulder(FALSE); 01761 01762 Node* pContext = this; 01763 AttachNodeDirection Dir = LASTCHILD; 01764 01765 if (pMoulder!=NULL) 01766 { 01767 pContext = pMoulder; 01768 Dir = PREV; 01769 } 01770 01771 if (pGroup!=NULL) 01772 { 01773 pContext = pGroup; 01774 Dir = PREV; 01775 } 01776 01777 BOOL ok = TRUE; 01778 01779 if (pOp!=NULL) 01780 ok = pOp->DoInsertNewNode(pNodeMPath, pContext, Dir, FALSE, FALSE, FALSE, FALSE); 01781 else 01782 { 01783 pNodeMPath->AttachNode(pContext, Dir); 01784 pNodeMPath->SetSelected(FALSE); 01785 } 01786 01787 if (!ok) 01788 { 01789 delete pNodeMPath; 01790 return NULL; 01791 } 01792 01793 return pNodeMPath; 01794 } 01795 01796 01797 /******************************************************************************************** 01798 01799 > NodeMouldGroup* NodeMould::CreateNewMouldGroup(UndoableOperation* pOp) 01800 01801 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01802 Created: 19/12/94 01803 Inputs: pOp = A pointer to an active operation (can be null) 01804 Returns: a pointer to the created mould group (not in the tree) 01805 NULL if unable to create the node 01806 Purpose: Creates a MouldGroup object and returns a pointer to it 01807 SeeAlso: - 01808 01809 ********************************************************************************************/ 01810 01811 NodeMouldGroup* NodeMould::CreateNewMouldGroup(UndoableOperation* pOp) 01812 { 01813 // Create a mould group object 01814 NodeMouldGroup* pMouldGroup; 01815 ALLOC_WITH_FAIL( pMouldGroup, new NodeMouldGroup, pOp); 01816 return pMouldGroup; 01817 } 01818 01819 01820 /******************************************************************************************** 01821 01822 > NodeMouldGroup* NodeMould::AddNewMouldGroup(UndoableOperation* pOp) 01823 01824 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01825 Created: 19/12/94 01826 Inputs: pOp = A pointer to an active operation (can be null) 01827 Returns: a pointer to the created mould group (inserted into the tree) 01828 NULL if unable to create the node 01829 Purpose: Creates a MouldGroup object inside the MouldParent and moves all the 01830 objects specified by NodeList into the group. Only object which can 01831 become either a path or a nodebitmap are actually moved. 01832 SeeAlso: - 01833 01834 ********************************************************************************************/ 01835 01836 NodeMouldGroup* NodeMould::AddNewMouldGroup(UndoableOperation* pOp) 01837 { 01838 BOOL ok; 01839 01840 // Create a mould group object 01841 NodeMouldGroup* pMouldGroup = CreateNewMouldGroup(pOp); 01842 if (pMouldGroup==NULL) 01843 return NULL; 01844 01845 if (pOp!=NULL) 01846 { 01847 // Now stick the mould group inside the mould parent, but dont alter the selection 01848 CALL_WITH_FAIL(pOp->DoInsertNewNode(pMouldGroup, this, LASTCHILD, FALSE, FALSE, FALSE, FALSE), pOp, ok); 01849 } 01850 else 01851 { 01852 // all right then, insert it in a none undoable way 01853 pMouldGroup->AttachNode(this, LASTCHILD); 01854 pMouldGroup->SetSelected(FALSE); 01855 ok = TRUE; 01856 } 01857 01858 // if failed get rid of what we have 01859 if (!ok) 01860 { 01861 delete pMouldGroup; 01862 return NULL; 01863 } 01864 01865 return pMouldGroup; 01866 } 01867 01868 01869 01870 /******************************************************************************************** 01871 01872 > BOOL NodeMould::FillMouldGroup( NodeMouldGroup* pMouldGroup, 01873 List* NodeList, 01874 UndoableOperation* pOp) 01875 01876 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01877 Created: 19/12/94 01878 Inputs: NodeList = A pointer to a list of nodes to move 01879 pOp = A pointer to an active operation 01880 Returns: TRUE if filled the group 01881 NULL if unable transfer all necessary nodes 01882 Purpose: Moves all the objects specified by NodeList into the mould group. 01883 Only objects which can become either a path or a nodebitmap are actually 01884 moved. 01885 SeeAlso: - 01886 01887 ********************************************************************************************/ 01888 01889 BOOL NodeMould::FillMouldGroup( NodeMouldGroup* pMouldGroup, 01890 List* NodeList, 01891 UndoableOperation* pOp) 01892 { 01893 BOOL ok; 01894 Node* pObj; 01895 01896 // find the parent spread object 01897 Spread* pParentSpread=FindParentSpread(); 01898 if (pParentSpread==NULL) 01899 return FALSE; 01900 01901 Node* pDNode = (Node*)pMouldGroup; 01902 INT32 count = 0; 01903 01904 BecomeA PathTester(BECOMEA_TEST, CC_RUNTIME_CLASS(NodePath)); 01905 BecomeA BitmapTester(BECOMEA_TEST, CC_RUNTIME_CLASS(NodeBitmap)); 01906 01907 NodeListItem* CurItem = (NodeListItem*)(NodeList->GetHead()); 01908 while (CurItem) 01909 { 01910 pObj = CurItem->pNode; 01911 01912 if ( 01913 (pObj->CanBecomeA(&PathTester)) || 01914 (pObj->CanBecomeA(&BitmapTester)) 01915 ) 01916 { 01917 // Deselect the node first 01918 if (pObj->IsAnObject()) 01919 { 01920 CALL_WITH_FAIL(pOp->DoDeselectNode((NodeRenderableInk*)pObj,pParentSpread), pOp, ok); 01921 if (!ok) 01922 return FALSE; 01923 } 01924 CALL_WITH_FAIL(pOp->DoMoveNode(pObj, pDNode, LASTCHILD), pOp, ok); 01925 if (!ok) 01926 return FALSE; 01927 01928 count+=1; 01929 } 01930 CurItem = (NodeListItem*)(NodeList->GetNext(CurItem)); 01931 } 01932 01933 if (!pOp->DoFactorOutCommonChildAttributes(pMouldGroup)) 01934 return FALSE; 01935 01936 // remove the template attribute "names" from the MouldGroup 01937 // as if they are left in this the node group can be selected and 01938 // it should never be selected in the tree. 01939 // this should be recreated when the mould is removed - which it isn't currently 01940 Node * pNode = SliceHelper::FindNextNameNode(pMouldGroup, pMouldGroup); 01941 while (pNode) 01942 { 01943 pOp->DoHideNode(pNode, FALSE); 01944 pNode = SliceHelper::FindNextNameNode(pMouldGroup, pMouldGroup); 01945 } 01946 01947 // if there's no objects at all fail 01948 return (count>0); 01949 } 01950 01951 01952 01953 /********************************************************************************************* 01954 01955 > Node* NodeMould::HasEditableChild(CCRuntimeClass* ChildClass, Node* pPreviousChild) 01956 01957 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01958 Created: 20/3/95 01959 Inputs: ChildClass = the runtime class of the editable object 01960 pPreviousChild = a pointer to the previous editable child 01961 returned by 'this' node, NULL if this is the first 01962 call to this node. 01963 Outputs: - 01964 Returns: A node pointer, to an object which forms part of the editable surface of 01965 its parent (this node). 01966 Purpose: This function returns our edit node (the nodemouldpath) which forms part of 01967 the mould objects editable surface. 01968 01969 **********************************************************************************************/ 01970 01971 Node* NodeMould::HasEditableChild(CCRuntimeClass* ChildClass, Node* pPreviousChild) 01972 { 01973 if (ChildClass != CC_RUNTIME_CLASS(NodePath)) 01974 return NULL; 01975 01976 NodeMouldPath* pNodeMPath = GetPathShape(); 01977 // check to see if this has already been asked for once 01978 if (((Node*)pNodeMPath)==pPreviousChild) 01979 return NULL; 01980 01981 return GetPathShape(); 01982 } 01983 01984 01985 /********************************************************************************************* 01986 01987 > void NodeMould:ToggleDetachFlag() 01988 01989 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01990 Created: 20/3/95 01991 Inputs: - 01992 Returns: - 01993 Purpose: Switch the logical value of the detached mould flag inside this mould object 01994 01995 **********************************************************************************************/ 01996 01997 void NodeMould::ToggleDetachFlag() 01998 { 01999 DetachedGeometry = !DetachedGeometry; 02000 } 02001 02002 02003 02004 02005 02006 /******************************************************************************************** 02007 02008 > virtual ChangeCode NodeMould::OnChildChange(ObjChangeParam* pParam) 02009 02010 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02011 Created: 09/01/95 02012 Inputs: pParam = pointer to a object change parameter class 02013 Returns: CC_OK if we have successfully processed the change. 02014 CC_FAIL if we cannot handle this particular change and must prevent the 02015 child from continuing 02016 Purpose: An object has or is currently being edited inside our mould so we need to 02017 perform actions related to this change. The parameter block passed to us will 02018 define what to do (if we recognise it). Otherwise we will simply perform the 02019 default action of remoulding ourselves on receiving a HasChanged reason. 02020 02021 ********************************************************************************************/ 02022 02023 ChangeCode NodeMould::OnChildChange(ObjChangeParam* pParam) 02024 { 02025 #if defined(EXCLUDE_FROM_RALPH) 02026 ERROR3("NodeMould::OnChildChange being called"); 02027 return (ChangeCode)CC_OK; 02028 #else 02029 ERROR2IF(pParam==NULL,CC_FAIL,"NodeMould::OnChildChange() called with a null parameter"); 02030 02031 // check for a specific derived change type 02032 if (pParam->IS_KIND_OF(ObjChangePathEdit)) 02033 { 02034 // see if its our shape path thats being altered 02035 Node* pChangedObj = pParam->GetChangeObj(); 02036 NodeMouldPath* pShape = GetPathShape(); 02037 if (pChangedObj==pShape) 02038 return HandleMouldShapeChange((ObjChangePathEdit*)pParam); 02039 } 02040 02041 // now read the parameter block types 02042 ObjChangeType pType = pParam->GetChangeType(); 02043 ObjChangeFlags cFlags = pParam->GetChangeFlags(); 02044 ChangeCode Chge = CC_OK; 02045 02046 // otherwise its not our mould shape thats changed so 02047 // simply perform a remould 02048 if (pType==OBJCHANGE_FINISHED) 02049 { 02050 // if this change is a copy the do nothing. 02051 if (!cFlags.CopyNode) 02052 { 02053 // Node* pChangedObj = pParam->GetChangeObj(); 02054 NodeMouldPath* pShape = GetPathShape(); 02055 NodeMouldGroup* pNodeMGroup = FindMouldGroup(); 02056 UndoableOperation* UndoOp = pParam->GetOpPointer(); 02057 02058 if ((pNodeMGroup!=NULL) && (pShape!=NULL) && (UndoOp!=NULL)) 02059 { 02060 // Has the mould path changed shape? 02061 INT32 newCRC = pShape->InkPath.CalcCRC(); 02062 02063 // Have the bounds of the source objects changed? 02064 DocRect Rect = pNodeMGroup->GetChildrensBounds(FALSE); 02065 INT32 rw = Rect.Width(); 02066 INT32 rh = Rect.Height(); 02067 02068 BOOL ch = ((newCRC!=OnCC_CRC) || (rw!=OnCC_Width) || (rh!=OnCC_Height)); 02069 02070 if (ch) 02071 { 02072 if (newCRC!=OnCC_CRC) 02073 { 02074 // The mould path has changed so we better check it 02075 UINT32 errID; 02076 if (!pMouldGeometry->Validate( &(pShape->InkPath), errID )) 02077 return CC_FAIL; 02078 } 02079 02080 Chge=RecordChangeCodes(UndoOp); 02081 if (Chge==CC_OK) 02082 { 02083 // Set the new CRC. 02084 OnCC_CRC=newCRC; 02085 OnCC_Width=rw; 02086 OnCC_Height=rh; 02087 02088 Chge = StartSaveContext(UndoOp,REC_REBUILD | REC_GEOMCONTEXT); 02089 if (Chge==CC_OK) 02090 { 02091 pMouldGeometry->Define(&(pShape->InkPath),&Rect); 02092 Chge = RemouldAll(UndoOp); 02093 if (Chge==CC_OK) 02094 Chge = EndSaveContext(UndoOp,1+4); 02095 } 02096 } 02097 } 02098 } 02099 } 02100 } 02101 02102 return Chge; 02103 #endif 02104 } 02105 02106 02107 /******************************************************************************************** 02108 02109 > ChangeCode NodeMould::StartSaveContext(UndoableOperation* pUndoOp) 02110 02111 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02112 Created: 09/01/95 02113 Inputs: pUndoOp = pointer to an active undoable operation 02114 Returns: CC_OK if we have successfully saved the mould context 02115 CC_FAIL if we have failed to save the context. We've possible run out of memory 02116 Purpose: Tries to save the current state of the mould shape on the undo. If you want 02117 to edit the mould in any way you should use this function to record various 02118 parts of the mould before going ahead and changing any data. The corresponding 02119 EndSaveContext should be called after you have altered any data 02120 02121 ********************************************************************************************/ 02122 02123 ChangeCode NodeMould::StartSaveContext(UndoableOperation* pUndoOp, REC_TYPE rectype) 02124 { 02125 ChangeCode Chge=CC_OK; 02126 02127 #if !defined(EXCLUDE_FROM_RALPH) 02128 if (pUndoOp!=NULL) 02129 { 02130 // create an action to rebuild the mould 02131 // if ((rectype & REC_REBUILD) && (Chge==CC_OK)) 02132 // { 02133 // Chge = ConvertCode(StartRebuildMouldAction::DoRecord(pUndoOp, this)); 02134 // } 02135 02136 // record the current path data, ie its flags,verbs & coords 02137 if ((rectype & REC_PATHARRAYS) && (Chge==CC_OK)) 02138 { 02139 NodeMouldPath* pMouldPath=GetPathShape(); 02140 if (pMouldPath) 02141 { 02142 Path* pEditPath = &(pMouldPath->InkPath); 02143 Chge = ConvertCode(SavePathArraysAction::DoRecord(pUndoOp, pUndoOp->GetUndoActionList(), pEditPath)); 02144 } 02145 } 02146 02147 // record the current blob positions 02148 if ((rectype & REC_BLOBS) && (Chge==CC_OK)) 02149 { 02150 Spread* pSpread = FindParentSpread(); 02151 if (pMouldGeometry!=NULL) 02152 Chge=pMouldGeometry->RecordBlobs(pUndoOp, pSpread); 02153 } 02154 02155 if ((rectype & REC_GEOMETRY) && (Chge==CC_OK)) 02156 { 02157 // record the entire geometry object on the undo 02158 Chge = ConvertCode(RecordGeometryAction::DoRecord(pUndoOp,this)); 02159 } 02160 02161 // record the mould geometry context on the undo. 02162 if ((rectype & REC_GEOMCONTEXT) && (Chge==CC_OK)) 02163 { 02164 if (pMouldGeometry!=NULL) 02165 Chge=pMouldGeometry->RecordContext(pUndoOp); 02166 } 02167 } 02168 #endif 02169 return Chge; 02170 } 02171 02172 02173 /******************************************************************************************** 02174 02175 > ChangeCode NodeMould::EndSaveContext(UndoableOperation* pUndoOp) 02176 02177 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02178 Created: 09/01/95 02179 Inputs: pUndoOp = pointer to an active undoable operation 02180 NULL if none 02181 Returns: CC_OK if we have successfully saved the mould context 02182 CC_FAIL if we have failed to save the context. We've possible run out of memory 02183 Purpose: Tries to save the current state of the mould shape on the undo. 02184 02185 ********************************************************************************************/ 02186 02187 ChangeCode NodeMould::EndSaveContext(UndoableOperation* pUndoOp, REC_TYPE rectype) 02188 { 02189 ChangeCode Chge=CC_OK; 02190 #if !defined(EXCLUDE_FROM_RALPH) 02191 02192 if (pUndoOp!=NULL) 02193 { 02194 if (NodeMould::pMouldGeometry) 02195 { 02196 // if (rectype & REC_REBUILD) 02197 // { 02198 // Chge = ConvertCode(EndRebuildMouldAction::DoRecord(pUndoOp, this)); 02199 // } 02200 02201 // no revese actions are required for geometry recording or blob recording 02202 } 02203 } 02204 #endif 02205 return Chge; 02206 } 02207 02208 02209 02210 02211 /*********************************************************************************************** 02212 02213 > virtual ChangeCode NodeMould::RecordChangeCodes(UndoableOperation* pOp) 02214 02215 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02216 Created: 16/01/95 02217 Inputs: pOp = pointer to a running undoable operation 02218 Outputs: - 02219 Purpose: Record the CRC codes held within the mould object 02220 02221 ***********************************************************************************************/ 02222 02223 ChangeCode NodeMould::RecordChangeCodes(UndoableOperation* pOp) 02224 { 02225 if (pOp!=NULL) 02226 { 02227 RecordChangeCodesAction* CCodeAction; 02228 ActionCode Act; 02229 02230 // call the actions static init function to get the action going. 02231 Act = RecordChangeCodesAction::Init(pOp, pOp->GetUndoActionList(), this, (Action**)(&CCodeAction)); 02232 02233 if (Act == AC_FAIL) 02234 return CC_FAIL; 02235 if (Act == AC_NORECORD) 02236 return CC_NORECORD; 02237 } 02238 return CC_OK; 02239 } 02240 02241 02242 /*********************************************************************************************** 02243 02244 > ChangeCode NodeMould::ConvertCode(ActionCode Act) 02245 02246 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02247 Created: 16/01/95 02248 Inputs: Action code 02249 Returns: Change code 02250 Purpose: Convert a action code to a change code. 02251 02252 ***********************************************************************************************/ 02253 02254 ChangeCode NodeMould::ConvertCode(ActionCode Act) 02255 { 02256 switch (Act) 02257 { 02258 case AC_FAIL: return CC_FAIL; 02259 case AC_NORECORD: return CC_NORECORD; 02260 case AC_OK: return CC_OK; 02261 } 02262 return CC_OK; 02263 } 02264 02265 02266 02267 /******************************************************************************************** 02268 02269 > ChangeCode NodeMould::HandleMouldShapeChange(ObjChangePathEdit* pParam) 02270 02271 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02272 Created: 09/01/95 02273 Inputs: pParam = pointer to a object change parameter class 02274 Returns: CC_OK if we have successfully processed the change. 02275 CC_FAIL if we cannot handle this particular change and must prevent the 02276 child from continuing 02277 Purpose: The user is 02278 about to edit, 02279 in the action of editing, 02280 or has edited, 02281 our mould shape. 02282 We as a parent need to sort out whether they are allowed to continue. 02283 If so we need to perform various actions dependent on what stage the 02284 change is in. 02285 AboutToEdit: we need to decide whether there is a good reason to prevent 02286 the edit from taking place 02287 Editing: we need to eor our edit blobs on when necessary 02288 HasEdited: we need to perform a remould of all children. 02289 02290 ********************************************************************************************/ 02291 02292 ChangeCode NodeMould::HandleMouldShapeChange(ObjChangePathEdit* pParam) 02293 { 02294 #if defined(EXCLUDE_FROM_RALPH) 02295 ERROR3("NodeMould::HandleMouldShapeChange called"); 02296 return (ChangeCode)CC_OK; 02297 #else 02298 ObjChangeType pType = pParam->GetChangeType(); 02299 ObjChangeFlags pFlags = pParam->GetChangeFlags(); 02300 ChangeCode Chge = CC_OK; 02301 BOOL ok; 02302 02303 if (pMouldGeometry) 02304 { 02305 switch (pType) 02306 { 02307 case OBJCHANGE_STARTING: 02308 Chge=StartSaveContext(pParam->GetOpPointer(), REC_REBUILD | REC_BLOBS | REC_GEOMCONTEXT); 02309 pParam->ChangeMask.ClaimAll(); 02310 pMouldGeometry->DisableControlBlobs(); 02311 break; 02312 02313 case OBJCHANGE_RENDERCURRENTBLOBS: 02314 pMouldGeometry->RenderDragBlobs(pParam->pChangeSpread); 02315 break; 02316 02317 case OBJCHANGE_RENDERCHANGEDBLOBS: 02318 ok=pMouldGeometry->Define(pParam->pChangePath,NULL); 02319 pMouldGeometry->RenderDragBlobs(pParam->pChangeSpread); 02320 if (!ok) 02321 Chge=CC_FAIL; 02322 break; 02323 02324 case OBJCHANGE_FINISHED: 02325 { 02326 pMouldGeometry->EnableControlBlobs(); 02327 if (Chge==CC_OK) 02328 { 02329 Spread* pSpread = FindParentSpread(); 02330 Chge=pMouldGeometry->RecordBlobs(pParam->GetOpPointer(), pSpread); 02331 if (Chge==CC_OK) 02332 { 02333 Chge = RemouldAll(pParam->GetOpPointer()); 02334 if (Chge==CC_OK) 02335 Chge=EndSaveContext(pParam->GetOpPointer(), REC_REBUILD | REC_BLOBS | REC_GEOMCONTEXT); 02336 } 02337 } 02338 } 02339 break; 02340 02341 case OBJCHANGE_FAILED: 02342 pMouldGeometry->RenderDragBlobs(pParam->pChangeSpread); 02343 pMouldGeometry->EnableControlBlobs(); 02344 RedrawMould(); 02345 break; 02346 02347 default: 02348 break; 02349 } 02350 } 02351 return Chge; 02352 #endif 02353 } 02354 02355 02356 02357 02358 02359 /******************************************************************************************** 02360 02361 > ChangeCode NodeMould::RemouldAll(UndoableOperation* pUndoOp) 02362 02363 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02364 Created: 09/01/95 02365 Inputs: pUndoOp = pointer to an active undoable operation 02366 NULL if none 02367 Returns: CC_OK if we have successfully remoulded all objects 02368 CC_FAIL if we have failed to remould. We've possible run out of memory 02369 Purpose: Creates a new set of moulded objects, now the mould shape has changed 02370 02371 ********************************************************************************************/ 02372 02373 ChangeCode NodeMould::RemouldAll(UndoableOperation* pUndoOp) 02374 { 02375 #if defined(EXCLUDE_FROM_RALPH) 02376 ERROR3("NodeMould::RemouldAll called"); 02377 #else 02378 BOOL ok; 02379 02380 // if we're in detached mode, exit now. 02381 if (DetachedGeometry) 02382 return CC_OK; 02383 02384 NodeMouldGroup* pMouldGroup = FindMouldGroup(); 02385 if (pMouldGroup==NULL) 02386 return CC_FAIL; 02387 02388 NodeMoulder* pMoulder = FindFirstMoulder(); 02389 while (pMoulder!=NULL) 02390 { 02391 // Find the next moulder object 02392 Node* pNext = FindNext(CC_RUNTIME_CLASS(NodeMoulder)); 02393 02394 // Now build the moulder object 02395 NodeMoulder* pNewMoulder = AddNewMoulder(pMoulder,NEXT,pUndoOp); 02396 if (!pNewMoulder) 02397 return CC_FAIL; 02398 02399 CALL_WITH_FAIL(pUndoOp->DoHideNode(pMoulder,TRUE,NULL,FALSE), pUndoOp, ok); 02400 if (!ok) 02401 return CC_FAIL; 02402 02403 if (!pNewMoulder->CreateMouldedObjects(pMouldGroup, GetGeometry(), pUndoOp)) 02404 return CC_FAIL; 02405 02406 pMoulder=(NodeMoulder*)pNext; 02407 } 02408 02409 // now, inform all parents of a child change 02410 // go to all parents, sending child change messages 02411 Node * pParent = NULL; 02412 02413 // DMc 02414 // do the child change message 02415 ObjChangeFlags Flags; 02416 ObjChangeParam EditObjChange(OBJCHANGE_FINISHED, Flags, this, pUndoOp, OBJCHANGE_CALLEDBYOP); 02417 02418 pParent = this->FindParent(); 02419 02420 while (pParent) 02421 { 02422 pParent->OnChildChange(&EditObjChange); 02423 02424 pParent = pParent->FindParent(); 02425 } 02426 02427 // Update the selection range 02428 Camelot.UpdateSelection(); 02429 02430 #endif 02431 return CC_OK; 02432 } 02433 02434 02435 /* 02436 02437 ChangeCode NodeMould::RemouldAll(UndoableOperation* pUndoOp) 02438 { 02439 // if we're in detached mode, exit now. 02440 if (DetachedGeometry) 02441 return CC_OK; 02442 02443 NodeMouldGroup* pMouldGroup = FindMouldGroup(); 02444 NodeMoulder* pMoulder = FindFirstMoulder(); 02445 02446 if ((pMouldGroup!=NULL) && (pMoulder!=NULL)) 02447 { 02448 pMoulder->DestroyMouldedObjects(); 02449 02450 if (!pMoulder->CreateMouldedObjects(pMouldGroup, GetGeometry(), NULL)) 02451 { 02452 pMoulder->DestroyMouldedObjects(); 02453 return CC_FAIL; 02454 } 02455 } 02456 02457 return CC_OK; 02458 } 02459 */ 02460 02461 02462 02463 02464 /********************************************************************************************* 02465 02466 > void NodeMould::PreExportRender(RenderRegion* pRegion) 02467 02468 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02469 Created: 14/03/95 02470 Inputs: pRegion = ptr to the export render region to export to 02471 Outputs: 02472 Returns: 02473 Purpose: Called before this node or any of its children have been rendered to the 02474 export region. This outputs the "start mould" command. 02475 Supports ArtWorks EPS and Camelot EPS 02476 Errors: 02477 02478 **********************************************************************************************/ 02479 02480 void NodeMould::PreExportRender(RenderRegion* pRegion) 02481 { 02482 #ifdef DO_EXPORT 02483 if (pRegion->IS_KIND_OF(NativeRenderRegion)) 02484 { 02485 PreExportCAMEPS(pRegion); 02486 return; 02487 } 02488 02489 if (pRegion->IS_KIND_OF(ArtWorksEPSRenderRegion)) 02490 { 02491 PreExportAWEPS(pRegion); 02492 return; 02493 } 02494 #endif 02495 } 02496 02497 /********************************************************************************************* 02498 02499 > BOOL NodeMould::ExportRender(RenderRegion* pRegion) 02500 02501 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02502 Created: 14/03/95 02503 Inputs: pRegion = ptr to the export render region to export to 02504 Outputs: 02505 Returns: TRUE if ok, FALSE if something went wrong 02506 Purpose: Called after this node and all of its children have been rendered to the 02507 export region. This outputs the "end mould" command. 02508 Supports ArtWorks EPS and Camelot EPS 02509 Errors: 02510 02511 **********************************************************************************************/ 02512 02513 BOOL NodeMould::ExportRender(RenderRegion* pRegion) 02514 { 02515 #ifdef DO_EXPORT 02516 if (pRegion->IS_KIND_OF(NativeRenderRegion)) 02517 return PostExportCAMEPS(pRegion); 02518 02519 if (pRegion->IS_KIND_OF(ArtWorksEPSRenderRegion)) 02520 return PostExportAWEPS(pRegion); 02521 #endif 02522 return FALSE; 02523 } 02524 02525 02526 02527 void NodeMould::PreExportCAMEPS(RenderRegion* pRegion) 02528 { 02529 #ifdef DO_EXPORT 02530 MouldSpace mSpace = DescribeGeometry(); 02531 EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC(); 02532 02533 pDC->OutputValue(INT32(MOULD_EPS_VERSION)); // The current mould format flag 02534 switch (mSpace) 02535 { 02536 case MOULDSPACE_ENVELOPE: 02537 if (IsDetached()) 02538 InformWarning(_R(IDS_SAVE_WHILE_DETACHEDE), _R(IDS_OK)); 02539 pDC->OutputToken(_T("csev")); // Camelot "start envelope" token 02540 02541 break; 02542 02543 case MOULDSPACE_PERSPECTIVE: 02544 if (IsDetached()) 02545 InformWarning(_R(IDS_SAVE_WHILE_DETACHEDP), _R(IDS_OK)); 02546 pDC->OutputToken(_T("cspr")); // Camelot "start perspective" token 02547 break; 02548 02549 default: 02550 break; 02551 } 02552 pDC->OutputNewLine(); 02553 02554 // output the threshold extension token. We don't need to output this 02555 // if the threshold is still 1024 ie the old value. The importer will 02556 // default to this if there's no threshold token in the file. 02557 INT32 Threshold = GetGeometry()->GetThreshold(); 02558 if (Threshold != MOULD_V1THRESHOLD) 02559 { 02560 pDC->OutputValue((INT32)EOTAG_MOULDTHRESHOLD); 02561 pDC->OutputToken(_T("cso")); 02562 pDC->OutputNewLine(); 02563 pDC->OutputValue(Threshold); 02564 pDC->OutputToken(_T("cmth")); 02565 pDC->OutputNewLine(); 02566 pDC->OutputToken(_T("ceo")); 02567 pDC->OutputNewLine(); 02568 } 02569 #endif 02570 } 02571 02572 02573 02574 02575 BOOL NodeMould::PostExportCAMEPS(RenderRegion* pRegion) 02576 { 02577 #ifdef DO_EXPORT 02578 MouldSpace mSpace = DescribeGeometry(); 02579 EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC(); 02580 02581 switch (mSpace) 02582 { 02583 case MOULDSPACE_ENVELOPE: 02584 pDC->OutputToken(_T("ceev")); // Camelot "end envelope" token 02585 break; 02586 case MOULDSPACE_PERSPECTIVE: 02587 pDC->OutputToken(_T("cepr")); // Camelot "end perspective" token 02588 break; 02589 default: 02590 break; 02591 } 02592 pDC->OutputNewLine(); 02593 #endif 02594 02595 return TRUE; 02596 } 02597 02598 02599 void NodeMould::PreExportAWEPS(RenderRegion* pRegion) 02600 { 02601 } 02602 02603 BOOL NodeMould::PostExportAWEPS(RenderRegion* pRegion) 02604 { 02605 return TRUE; 02606 } 02607 02608 02609 02610 /******************************************************************************************** 02611 02612 > virtual BOOL NodeMould::PostImport() 02613 02614 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 02615 Created: 23/05/95 02616 Inputs: - 02617 Outputs: - 02618 Returns: TRUE/FALSE for success/failure 02619 Purpose: This function is called after a document is imported. Nodes should override 02620 this function to do any post-import processing. 02621 SeeAlso: - 02622 02623 ********************************************************************************************/ 02624 02625 BOOL NodeMould::PostImport() 02626 { 02627 // if theres already some moulded objects then fine.... 02628 if (CountMoulders()>0) 02629 return TRUE; 02630 02631 // find the created objects we need to set the geometry up 02632 NodeMouldPath* pNodeMPath = GetPathShape(); 02633 NodeMouldGroup* pNodeMGroup = FindMouldGroup(); 02634 02635 if (pNodeMGroup==NULL || pNodeMPath==NULL) 02636 return FALSE; 02637 02638 // Get the kids bounding rects 02639 DocRect Rect = pNodeMGroup->GetChildrensBounds(FALSE); 02640 // We need to set the geometry of our mould using the imported data 02641 // set the geometry using this new mould shape 02642 if (!GetGeometry()->Define(&(pNodeMPath->InkPath), &Rect)) 02643 return FALSE; 02644 02645 // Create a new moulder object 02646 NodeMoulder* pMoulder = AddNewMoulder(this, LASTCHILD, NULL); 02647 if (pMoulder==NULL) 02648 return FALSE; 02649 02650 // and finally create all the moulded objects inside the moulder 02651 if (!pMoulder->CreateMouldedObjects(pNodeMGroup, GetGeometry(), NULL)) 02652 { 02653 // Vape the whole lot. 02654 pMoulder->CascadeDelete(); 02655 return FALSE; 02656 } 02657 02658 // Force a redraw over the extent of the mould (for importing) 02659 // Document* pDoc=Document::GetSelected(); 02660 // Naughty Naughty. You cannot rely on a static (?*&$) variable to tell you 02661 // what is selected. Why not just find your parent? 02662 Spread * pSpread = FindParentSpread(); 02663 Document * pDoc = NULL; 02664 if (pSpread != NULL) 02665 pDoc = pSpread->FindParentDocument(); 02666 if (pDoc!=NULL) 02667 { 02668 DocRect Rect = pNodeMPath->GetBlobBoundingRect(); 02669 pDoc->ForceRedraw(pSpread, Rect, TRUE, this); 02670 } 02671 else 02672 ERROR3("NodeMold::PostImport() - pDoc==NULL"); 02673 02674 // Mark this nodes bounds as invalid 02675 InvalidateBoundingRect(); 02676 02677 // All is well and lovely 02678 return TRUE; 02679 } 02680 02681 02682 /******************************************************************************************** 02683 02684 > virtual BOOL NodeMould::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 02685 02686 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02687 Created: 18/7/96 02688 Inputs: pFilter = ptr to the filter to write to 02689 Returns: TRUE is a record has been written, FALSE otherwise 02690 Purpose: Writes out a records associated with this node 02691 02692 It either writes out an envelope or perspective record, depending on the geometry. 02693 02694 The only piece of data that needs to be saved out with a node mould is the 02695 error threshold. 02696 02697 ********************************************************************************************/ 02698 02699 BOOL NodeMould::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 02700 { 02701 #ifdef DO_EXPORT 02702 ERROR2IF(pFilter == NULL,FALSE,"NULL filter param"); 02703 ERROR2IF(pMouldGeometry == NULL,FALSE,"No mould geometry"); 02704 02705 UINT32 Tag = TAG_UNDEFINED; 02706 UINT32 Size = 0; 02707 02708 switch (NodeMould::DescribeGeometry()) 02709 { 02710 case MOULDSPACE_ENVELOPE: Tag = TAG_MOULD_ENVELOPE; Size = TAG_MOULD_ENVELOPE_SIZE; break; 02711 case MOULDSPACE_PERSPECTIVE: Tag = TAG_MOULD_PERSPECTIVE; Size = TAG_MOULD_PERSPECTIVE_SIZE; break; 02712 02713 default: 02714 ERROR3("Unkown mould space type"); 02715 pFilter->GotError(_R(IDE_FILE_WRITE_ERROR)); 02716 return FALSE; 02717 } 02718 02719 INT32 Threshold = pMouldGeometry->GetThreshold(); 02720 02721 CXaraFileRecord Rec(Tag,Size); 02722 02723 BOOL ok = Rec.Init(); 02724 02725 if (ok) ok = Rec.WriteINT32(Threshold); 02726 if (ok) ok = pFilter->Write(&Rec); 02727 02728 if (!ok) 02729 pFilter->GotError(_R(IDE_FILE_WRITE_ERROR)); 02730 02731 return ok; 02732 #else 02733 return FALSE; 02734 #endif 02735 } 02736 02737 //------------------------------------------------------------------ 02738 // See comments for NodeMould::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 02739 BOOL NodeMould::WritePreChildrenNative(BaseCamelotFilter* pFilter) 02740 { 02741 #ifdef DO_EXPORT 02742 return WritePreChildrenWeb(pFilter); 02743 #else 02744 return FALSE; 02745 #endif 02746 } 02747 02748 02749 02750 /******************************************************************************************** 02751 02752 > DocRect NodeMould::ValidateExtend(const ExtendParams& ExtParams) 02753 02754 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 02755 Created: 5/26/00 02756 Purpose: NodeMould uses Node's base-class implementation, as we don't want to inherit 02757 NodeGroup's extend behaviour - see Node::ValidateExtend() for details. 02758 See also: Node::ValidateExtend(). 02759 02760 ********************************************************************************************/ 02761 DocRect NodeMould::ValidateExtend(const ExtendParams& ExtParams) 02762 { 02763 return Node::ValidateExtend(ExtParams); 02764 } 02765 02766 02767 02768 /******************************************************************************************** 02769 02770 > void NodeMould::Extend(const ExtendParams& ExtParams) 02771 02772 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 02773 Created: 5/26/00 02774 Purpose: NodeMould uses Node's base-class implementation, as we don't want to inherit 02775 NodeGroup's extend behaviour - see Node::Extend() for details. 02776 See also: Node::Extend(). 02777 02778 ********************************************************************************************/ 02779 void NodeMould::Extend(const ExtendParams& ExtParams) 02780 { 02781 Node::Extend(ExtParams); 02782 02783 // once we've done the extension, we redefine our path. 02784 // I know it's bad, but I don't know what this does and I'm just copying the code 02785 // from NodeMould::Transform. This code does not cause the mould to visibly change 02786 // shape, that bit happens when the contents of the NodeMoulder are Extended. 02787 if (pMouldGeometry) 02788 { 02789 Path* pPath = GetPath(); 02790 NodeMouldGroup* pMouldGroup = FindMouldGroup(); 02791 if (pPath && pMouldGroup) 02792 { 02793 DocRect Rect = pMouldGroup->GetChildrensBounds(TRUE); 02794 pMouldGeometry->Define(pPath, &Rect); 02795 } 02796 } 02797 } 02798 02799 02800 02801 /******************************************************************************************** 02802 02803 > DocRect NodeMould::GetExtendTargetBounds(const ExtendParams& ExtParams) 02804 02805 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 02806 Created: 20/06/2000 02807 Purpose: NodeMould uses NodeRenderableBounded's base-class implementation, as we don't 02808 want to inherit NodeGroup's extend behaviour - see base class for details. 02809 See also: NodeRenderableBounded::Extend(). 02810 02811 ********************************************************************************************/ 02812 DocRect NodeMould::GetExtendTargetBounds(const ExtendParams& ExtParams) 02813 { 02814 return NodeRenderableBounded::GetExtendTargetBounds(ExtParams); 02815 } 02816 02817 02818 02819 //--------------------------------------------------------------------------------------- 02820 //--------------------------------------------------------------------------------------- 02821 //--------------------------------------------------------------------------------------- 02822 02823 /******************************************************************************************** 02824 02825 > virtual UINT32* MouldRecordHandler::GetTagList() 02826 02827 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02828 Created: 19/7/96 02829 Inputs: - 02830 Returns: Ptr to a list of tag values, terminated by CXFRH_TAG_LIST_END 02831 Purpose: Provides the record handler system with a list of records handled by this 02832 handler 02833 SeeAlso: - 02834 02835 ********************************************************************************************/ 02836 02837 UINT32* MouldRecordHandler::GetTagList() 02838 { 02839 static UINT32 TagList[] = { TAG_MOULD_ENVELOPE, 02840 TAG_MOULD_PERSPECTIVE, 02841 TAG_MOULD_GROUP, 02842 TAG_MOULD_PATH, 02843 TAG_MOULD_BOUNDS, // WEBSTER - markn 10/2/97 - Mould bounds record 02844 CXFRH_TAG_LIST_END}; 02845 02846 return (UINT32*)&TagList; 02847 } 02848 02849 /******************************************************************************************** 02850 02851 > virtual BOOL MouldRecordHandler::HandleRecord(CXaraFileRecord* pCXaraFileRecord) 02852 02853 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02854 Created: 19/7/96 02855 Inputs: pCXaraFileRecord = ptr to record to handle 02856 Returns: TRUE if handled successfuly 02857 FALSE otherwise 02858 Purpose: Handles the given record. 02859 SeeAlso: - 02860 02861 ********************************************************************************************/ 02862 02863 BOOL MouldRecordHandler::HandleRecord(CXaraFileRecord* pCXaraFileRecord) 02864 { 02865 ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL"); 02866 02867 BOOL ok = TRUE; 02868 02869 switch (pCXaraFileRecord->GetTag()) 02870 { 02871 case TAG_MOULD_ENVELOPE: 02872 case TAG_MOULD_PERSPECTIVE: 02873 ok = HandleMouldRecord(pCXaraFileRecord); 02874 break; 02875 02876 case TAG_MOULD_GROUP: 02877 ok = HandleMouldGroupRecord(pCXaraFileRecord); 02878 break; 02879 02880 case TAG_MOULD_PATH: 02881 ok = HandleMouldPathRecord(pCXaraFileRecord); 02882 break; 02883 02884 // WEBSTER - markn 10/2/97 02885 // Mould bounds record 02886 case TAG_MOULD_BOUNDS: 02887 break; 02888 02889 default: 02890 ok = FALSE; 02891 ERROR3_PF(("I don't handle records with the tag (%d)\n",pCXaraFileRecord->GetTag())); 02892 break; 02893 } 02894 02895 return ok; 02896 } 02897 02898 02899 /******************************************************************************************** 02900 02901 > BOOL MouldRecordHandler::HandleMouldRecord(CXaraFileRecord* pCXaraFileRecord) 02902 02903 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02904 Created: 19/7/96 02905 Inputs: pCXaraFileRecord = ptr to record to handle 02906 Returns: TRUE if handled successfuly 02907 FALSE otherwise 02908 Purpose: Handles the given record. 02909 The record has to be a envelope or perspective mould record 02910 SeeAlso: - 02911 02912 ********************************************************************************************/ 02913 02914 BOOL MouldRecordHandler::HandleMouldRecord(CXaraFileRecord* pCXaraFileRecord) 02915 { 02916 UINT32 Tag = pCXaraFileRecord->GetTag(); 02917 02918 ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL"); 02919 ERROR2IF(Tag != TAG_MOULD_ENVELOPE && Tag != TAG_MOULD_PERSPECTIVE,FALSE,"I don't handle this tag type"); 02920 02921 NodeMould* pMould = new NodeMould; 02922 if (pMould == NULL) 02923 return FALSE; 02924 02925 // Read in the data 02926 INT32 Threshold; 02927 BOOL ok = pCXaraFileRecord->ReadINT32(&Threshold); 02928 02929 if (ok) 02930 { 02931 MouldSpace mSpace=MOULDSPACE_UNDEFINED; 02932 02933 // Find out what type of geometry to use. 02934 switch (Tag) 02935 { 02936 case TAG_MOULD_ENVELOPE: mSpace = MOULDSPACE_ENVELOPE; break; 02937 case TAG_MOULD_PERSPECTIVE: mSpace = MOULDSPACE_PERSPECTIVE; break; 02938 default: ERROR3("Unknown geometry"); break; 02939 } 02940 02941 // Create the correct geometry. 02942 ok = pMould->CreateGeometry(mSpace); 02943 02944 if (ok) 02945 { 02946 // Find the geometry and set the threshold - then we can stick the mould node in the tree. 02947 MouldGeometry* pGeometry = pMould->GetGeometry(); 02948 if (pGeometry != NULL) 02949 { 02950 pGeometry->SetThreshold(Threshold); 02951 ok = InsertNode(pMould); 02952 } 02953 else 02954 ok = FALSE; 02955 } 02956 } 02957 02958 return ok; 02959 } 02960 02961 /******************************************************************************************** 02962 02963 > BOOL MouldRecordHandler::HandleMouldGroupRecord(CXaraFileRecord* pCXaraFileRecord) 02964 02965 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02966 Created: 19/7/96 02967 Inputs: pCXaraFileRecord = ptr to record to handle 02968 Returns: TRUE if handled successfuly 02969 FALSE otherwise 02970 Purpose: Handles the given record. 02971 The record has to be a mould group record 02972 SeeAlso: - 02973 02974 ********************************************************************************************/ 02975 02976 BOOL MouldRecordHandler::HandleMouldGroupRecord(CXaraFileRecord* pCXaraFileRecord) 02977 { 02978 ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL"); 02979 ERROR2IF(pCXaraFileRecord->GetTag() != TAG_MOULD_GROUP,FALSE,"I don't handle this tag type"); 02980 02981 NodeMouldGroup* pMouldGroup = new NodeMouldGroup; 02982 02983 if (pMouldGroup != NULL) 02984 return InsertNode(pMouldGroup); 02985 02986 return FALSE; 02987 } 02988 02989 /******************************************************************************************** 02990 02991 > BOOL MouldRecordHandler::HandleMouldPathRecord(CXaraFileRecord* pCXaraFileRecord) 02992 02993 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02994 Created: 19/7/96 02995 Inputs: pCXaraFileRecord = ptr to record to handle 02996 Returns: TRUE if handled successfuly 02997 FALSE otherwise 02998 Purpose: Handles the given record. 02999 The record has to be a mould path record 03000 SeeAlso: - 03001 03002 ********************************************************************************************/ 03003 03004 BOOL MouldRecordHandler::HandleMouldPathRecord(CXaraFileRecord* pCXaraFileRecord) 03005 { 03006 ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL"); 03007 ERROR2IF(pCXaraFileRecord->GetTag() != TAG_MOULD_PATH,FALSE,"I don't handle this tag type"); 03008 03009 BOOL ok = FALSE; 03010 03011 NodeMouldPath* pNodeMouldPath = new NodeMouldPath; 03012 03013 if (pNodeMouldPath != NULL && pNodeMouldPath->SetUpPath()) 03014 { 03015 ok = pCXaraFileRecord->ReadPath(&pNodeMouldPath->InkPath); 03016 if (ok) pNodeMouldPath->InkPath.InitialiseFlags(); // Init the path flags array to something sensible 03017 if (ok) ok = InsertNode(pNodeMouldPath); 03018 if (ok) SetLastNodePathInserted(pNodeMouldPath); // Set it as last path inserted. 03019 } 03020 03021 return ok; 03022 } 03023 03024 /******************************************************************************************** 03025 03026 > virtual void MouldRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pRecord,StringBase* pStr) 03027 03028 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 03029 Created: 19/7/96 03030 Inputs: pRecord = ptr to a record 03031 pStr = ptr to string to update 03032 Returns: - 03033 Purpose: This provides descriptions for the mould records. 03034 Errors: - 03035 SeeAlso: - 03036 03037 ********************************************************************************************/ 03038 03039 #ifdef XAR_TREE_DIALOG 03040 void MouldRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pRecord,StringBase* pStr) 03041 { 03042 if (pStr == NULL || pRecord == NULL) 03043 return; 03044 03045 TCHAR s[256]; 03046 03047 // Call base class first 03048 CamelotRecordHandler::GetRecordDescriptionText(pRecord,pStr); 03049 03050 switch (pRecord->GetTag()) 03051 { 03052 case TAG_MOULD_ENVELOPE: 03053 case TAG_MOULD_PERSPECTIVE: 03054 { 03055 INT32 Threshold; 03056 03057 pRecord->ReadINT32(&Threshold); 03058 03059 camSprintf(s,_T("Threshold = %d\r\n"),Threshold); 03060 (*pStr) += s; 03061 } 03062 break; 03063 03064 case TAG_MOULD_PATH: 03065 // Use standard base class func for describing the path textually 03066 DescribePath(pRecord,pStr); 03067 break; 03068 } 03069 } 03070 #endif 03071 03072 /******************************************************************************************** 03073 03074 > virtual BOOL NodeMould::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu) 03075 03076 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 03077 Created: 12/5/95 03078 Inputs: pSpread The spread in which things are happening 03079 PointerPos The Location of the mouse pointer at the time of the click 03080 pMenu The menu to which items should be added 03081 Returns: BOOL - TRUE if the node claims the click as its own and FALSE if it is 03082 not interested in the click 03083 Purpose: Allows the Mould object to respond to pop up menu clicks on itself. 03084 03085 ********************************************************************************************/ 03086 03087 BOOL NodeMould::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu) 03088 { 03089 //WEBSTER-ranbirr-01/12/96 03090 #ifndef WEBSTER 03091 BOOL ok = TRUE; 03092 // WEBSTER-ranbirr-01/12/96 03093 #ifndef WEBSTER 03094 03095 ok = ok && pMenu->BuildCommand(TOOL_OPTOKEN_MOULD, TRUE); 03096 // ok = ok && pMenu->BuildCommand(OPTOKEN_DETACHMOULD, FALSE); 03097 // ok = ok && pMenu->BuildCommand(OPTOKEN_ROTATEMOULD, FALSE); 03098 // ok = ok && pMenu->BuildCommand(OPTOKEN_COPYMOULD, TRUE); 03099 // ok = ok && pMenu->BuildCommand(OPTOKEN_RECTANGULARENVELOPE, FALSE); 03100 // ok = ok && pMenu->BuildCommand(OPTOKEN_RECTANGULARPERSPECTIVE, TRUE); 03101 #endif //webster 03102 03103 return ok; 03104 #else //webster 03105 return FALSE; 03106 #endif //webster 03107 } 03108 03109 03110 03111 03112 03113 /******************************************************************************************** 03114 03115 RecordChangeCodesAction::RecordChangeCodesAction() 03116 03117 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 03118 Created: 16/01/95 03119 Purpose: Constructor for the action to undo Perspective modification 03120 03121 ********************************************************************************************/ 03122 03123 RecordChangeCodesAction::RecordChangeCodesAction() 03124 { 03125 pCRCMould=NULL; 03126 CRCcode=0; 03127 CRCWidth=0; 03128 CRCHeight=0; 03129 } 03130 03131 03132 /******************************************************************************************** 03133 03134 RecordChangeCodesAction::~RecordChangeCodesAction() 03135 03136 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 03137 Created: 16/01/95 03138 Purpose: Destructor for the action to undo Perspective modification 03139 03140 ********************************************************************************************/ 03141 03142 RecordChangeCodesAction::~RecordChangeCodesAction() 03143 { 03144 } 03145 03146 03147 /******************************************************************************************** 03148 03149 > ActionCode RecordChangeCodesAction::Init(Operation* pOp, 03150 ActionList* pActionList, 03151 NodeMould* pMould, 03152 Action** NewAction) 03153 03154 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 03155 Created: 16/01/95 03156 Inputs: pOp = a pointer to the operation to which this action belongs 03157 pActionList = is the action list to which this action should be added 03158 pMould = a pointer to a NodeMould object 03159 03160 Outputs: NewAction = a pointer to a pointer to an action, allowing the function to 03161 return a pointer to the created action. 03162 Returns: ActionCode, 03163 = AC_OK if the action was created correctly 03164 = AC_NORECORD if no memory to undo/redo but go ahead anyway without undo 03165 = AC_FAIL stop the operation 03166 03167 Purpose: This is the function which creates an instance of this action. If there is 03168 no room in the undo buffer (which is determined by the base class Init 03169 function called within) the function will either return AC_NORECORD which 03170 means the operation can continue, but no undo information needs to be stored, 03171 or AC_OK which means the operation should continue AND record undo information. 03172 If the function returns AC_FAIL, there was not enough memory to record the 03173 undo information, and the user has decided not to continue with the operation. 03174 Errors: - 03175 SeeAlso: Action::Init() 03176 03177 ********************************************************************************************/ 03178 03179 ActionCode RecordChangeCodesAction::Init(Operation* pOp, 03180 ActionList* pActionList, 03181 NodeMould* pMould, 03182 Action** NewAction) 03183 { 03184 ActionCode Ac = AC_FAIL; 03185 if (pMould!=NULL) 03186 { 03187 UINT32 ActSize = sizeof(RecordChangeCodesAction); 03188 Ac = Action::Init( pOp, pActionList, ActSize, CC_RUNTIME_CLASS(RecordChangeCodesAction), NewAction); 03189 if (Ac==AC_OK) 03190 { 03191 RecordChangeCodesAction* pAct = ((RecordChangeCodesAction*)*NewAction); 03192 if (pAct) 03193 { 03194 pAct->pCRCMould = pMould; 03195 pAct->CRCcode = pMould->OnCC_CRC; 03196 pAct->CRCWidth = pMould->OnCC_Width; 03197 pAct->CRCHeight = pMould->OnCC_Height; 03198 } 03199 } 03200 } 03201 return Ac; 03202 } 03203 03204 /******************************************************************************************** 03205 03206 > ActionCode RecordChangeCodesAction::Execute() 03207 03208 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 03209 Created: 16/01/95 03210 Inputs: - 03211 Outputs: - 03212 Returns: ActionCode, 03213 = AC_OK if the action was created correctly 03214 = AC_NORECORD if no memory to undo/redo but go ahead anyway without undo 03215 = AC_FAIL stop the operation 03216 Purpose: This is the virtual function that is called when the action is executed 03217 by the Undo/Redo system. 03218 Errors: - 03219 SeeAlso: - 03220 03221 ********************************************************************************************/ 03222 03223 ActionCode RecordChangeCodesAction::Execute() 03224 { 03225 // try to create a redo record 03226 RecordChangeCodesAction* NewAction; 03227 ActionCode Ac; 03228 Ac = RecordChangeCodesAction::Init(pOperation, pOppositeActLst, pCRCMould, (Action**)(&NewAction)); 03229 03230 if (pCRCMould) 03231 { 03232 pCRCMould->OnCC_CRC = CRCcode; 03233 pCRCMould->OnCC_Width = CRCWidth; 03234 pCRCMould->OnCC_Height = CRCHeight; 03235 } 03236 03237 return Ac; 03238 }