00001 // $Id: nodemldr.cpp 1315 2006-06-14 09:51:34Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // NodeMoulder implementation. 00099 00100 /* 00101 */ 00102 00103 #include "camtypes.h" 00104 #include "nodemldr.h" 00105 //#include "mike.h" 00106 #include "nodepath.h" 00107 #include "nodebmp.h" 00108 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 #include "moldshap.h" 00110 #include "ndmldink.h" 00111 #include "ndmldgrp.h" 00112 //#include "nodeattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 #include "nativeps.h" // The old style EPS native filter, used in v1.1 00114 #include "cameleps.h" 00115 #include "aw_eps.h" 00116 //#include "oilprog.h" 00117 00118 #include "moldpers.h" // For MouldPerspecive class definition 00119 //#include "fillattr.h" // For AttrFillGeometry::MakePerspective() - in camtypes.h [AUTOMATICALLY REMOVED] 00120 00121 #include "extender.h" 00122 #include "ngcore.h" // NameGallery, for stretching functionality 00123 00124 #include "strkattr.h" 00125 #include "ophist.h" 00126 00127 DECLARE_SOURCE("$Revision: 1315 $"); 00128 00129 CC_IMPLEMENT_DYNAMIC(NodeMoulder, NodeGroup ) 00130 00131 // Declare smart memory handling in Debug builds 00132 #define new CAM_DEBUG_NEW 00133 00134 /*********************************************************************************************** 00135 00136 > NodeMoulder::NodeMoulder(Node* ContextNode, 00137 AttachNodeDirection Direction, 00138 const DocRect& BoundingRect, 00139 BOOL Locked = FALSE, 00140 BOOL Mangled = FALSE, 00141 BOOL Marked = FALSE, 00142 BOOL Selected = FALSE, 00143 BOOL Renderable = FALSE 00144 ) 00145 00146 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00147 Created: 2/12/94 00148 00149 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 00150 MonoOn Direction: MonoOff 00151 Specifies the direction in which the node is to be attached to the 00152 ContextNode. The values this variable can take are as follows: 00153 00154 PREV : Attach node as a previous sibling of the context node 00155 NEXT : Attach node as a next sibling of the context node 00156 FIRSTCHILD: Attach node as the first child of the context node 00157 LASTCHILD : Attach node as a last child of the context node 00158 00159 BoundingRect: Bounding rectangle 00160 00161 The remaining inputs specify the status of the node: 00162 00163 Locked: Is node locked ? 00164 Mangled: Is node mangled ? 00165 Marked: Is node marked ? 00166 Selected: Is node selected ? 00167 00168 Purpose: This constructor initialises the nodes flags and links it to ContextNode in the 00169 direction specified by Direction. All necessary tree links are updated. 00170 00171 Note: Initialise() must be called before the NodeMoulder is in a state in which it can be used. 00172 SeeAlso: Initialise() 00173 Errors: An assertion error will occur if ContextNode is NULL 00174 00175 ***********************************************************************************************/ 00176 00177 NodeMoulder::NodeMoulder(Node* ContextNode, 00178 AttachNodeDirection Direction, 00179 BOOL Locked, 00180 BOOL Mangled, 00181 BOOL Marked, 00182 BOOL Selected 00183 ):NodeGroup(ContextNode, Direction, Locked, Mangled, Marked, Selected ) 00184 { 00185 pProviderNode = NULL; 00186 } 00187 00188 /********************************************************************************************* 00189 00190 > NodeMoulder::NodeMoulder() 00191 00192 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00193 Created: 2/12/94 00194 Purpose: This constructor creates a NodeMoulder linked to no other with all status 00195 flags false and an uninitialized bounding rectangle. 00196 Note: Initialise() must be called before the NodeMoulder is in a state in which 00197 it can be used. 00198 SeeAlso: Initialise() 00199 00200 **********************************************************************************************/ 00201 /* Technical Notes: 00202 The default constructor is required so that SimpleCopy will work 00203 */ 00204 00205 NodeMoulder::NodeMoulder(): NodeGroup() 00206 { 00207 pProviderNode = NULL; 00208 } 00209 00210 00211 /********************************************************************************************* 00212 00213 > NodeMoulder::~NodeMoulder() 00214 00215 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00216 Created: 2/12/94 00217 Purpose: Default destructor 00218 00219 **********************************************************************************************/ 00220 00221 NodeMoulder::~NodeMoulder() 00222 { 00223 } 00224 00225 00226 /********************************************************************************************* 00227 00228 > BOOL NodeMoulder::Initialise(NodeRenderableInk* pContextNode) 00229 00230 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00231 Created: 2/12/94 00232 Inputs: pContextNode = pointer to node which will be moulded 00233 Returns: TRUE if able to initialise the moulder object 00234 FALSE if not 00235 Purpose: Initialise a moulder object with information necessary for it to perform 00236 a mould 00237 00238 **********************************************************************************************/ 00239 00240 BOOL NodeMoulder::Initialise(NodeRenderableInk* pContextNode) 00241 { 00242 ERROR2IF(pContextNode == NULL,FALSE,"pContext == NULL in NodeMoulder::Init"); 00243 pProviderNode = pContextNode; 00244 return (TRUE); 00245 } 00246 00247 00248 /******************************************************************************************** 00249 00250 > virtual String NodeMoulder::Describe(BOOL Plural, BOOL Verbose = TRUE) 00251 00252 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00253 Created: 5/12/94 00254 Inputs: Plural: Flag indicating if the string description should be plural or 00255 singular. 00256 Outputs: - 00257 Retuns: Description of the moulder node 00258 Purpose: To return a description of the Moulder object in either the singular or the 00259 plural. This method is called by the DescribeRange method. 00260 00261 The description will always begin with a lower case letter. 00262 00263 ********************************************************************************************/ 00264 00265 String NodeMoulder::Describe(BOOL Plural, BOOL Verbose) 00266 { 00267 if (Plural) 00268 return(String(_R(IDS_MOULDER_DESCRP))); 00269 else 00270 return(String(_R(IDS_MOULDER_DESCRS))); 00271 }; 00272 00273 00274 /******************************************************************************************** 00275 00276 > NodePath* NodeMoulder::CreateMouldPath( NodePath* pSourceNodePath, 00277 MouldGeometry* pGeometry 00278 UndoableOperation* pOp) 00279 00280 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00281 Created: 19/12/94 00282 Inputs pSourceNodePath = pointer to a source node path object 00283 pGeometry = pointer to a mould shape 00284 pOp = pointer to an active operation or NULL if none 00285 Outputs: 00286 Returns: a pointer to a node path if successfull. 00287 NULL if failed to create the object 00288 Purpose: Creates a new Node path object containing a moulded version of the path held 00289 within the source node path and returns a pointer to it. This can then be 00290 inserted somewhere in the tree 00291 00292 ********************************************************************************************/ 00293 00294 NodePath* NodeMoulder::CreateMouldPath( NodePath* pSourceNodePath, 00295 MouldGeometry* pGeometry, 00296 UndoableOperation* pOp) 00297 { 00298 ERROR2IF(pSourceNodePath==NULL, NULL, "CreateMouldPath called with a null source pointer"); 00299 ERROR2IF(pGeometry==NULL, NULL, "CreateMouldPath called with a null geometry pointer"); 00300 00301 BOOL ok; 00302 00303 // ok we have the source node, so find the original path and mould it 00304 Path* pSourcePath = &(pSourceNodePath->InkPath); 00305 00306 // create a node path receptor. 00307 NodePath* pDestinNodePath; 00308 ALLOC_WITH_FAIL( pDestinNodePath, new NodePath, pOp); 00309 if (!pDestinNodePath) 00310 return NULL; 00311 00312 // allocate the node path some space 00313 CALL_WITH_FAIL((pDestinNodePath->SetUpPath(12,12)),pOp,ok); 00314 if (!ok) 00315 { 00316 delete pDestinNodePath; 00317 return NULL; 00318 } 00319 00320 // create a destination path receptor for the mould 00321 Path* pDestinPath = &(pDestinNodePath->InkPath); 00322 CALL_WITH_FAIL((pGeometry->MouldPathToPath(pSourcePath, pDestinPath)),pOp,ok); 00323 if (!ok) 00324 { 00325 delete pDestinNodePath; 00326 return NULL; 00327 } 00328 00329 // Set up the fill where necessary 00330 pDestinPath->IsFilled = pSourcePath->IsFilled; 00331 00332 return pDestinNodePath; 00333 } 00334 00335 00336 00337 /******************************************************************************************** 00338 00339 > BOOL NodeMoulder::MouldPath(NodePath* pNodePath, 00340 MouldGeometry* pGeometry 00341 UndoableOperation* pOp) 00342 00343 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00344 Created: 19/12/94 00345 Inputs pNodePath = pointer to a source node path object 00346 pGeometry = pointer to a mould shape 00347 pOp = pointer to an active operation or NULL if none 00348 Outputs: 00349 Returns: TRUE if the path has been moulded correctly 00350 FALSE, then unable to mould the path, the originial is intact 00351 Purpose: This function moulds the path contained within a NodPath to itself. 00352 It will use a temp path as a mould destination and copy this back over 00353 the source when successful. 00354 00355 ********************************************************************************************/ 00356 00357 BOOL NodeMoulder::MouldPath(NodePath* pNodePath, 00358 MouldGeometry* pGeometry, 00359 UndoableOperation* pOp) 00360 { 00361 ERROR2IF(pNodePath==NULL, FALSE, "MouldPath called with a null source pointer"); 00362 ERROR2IF(pGeometry==NULL, FALSE, "MouldPath called with a null geometry pointer"); 00363 00364 // ok we have the source node, so find the original path and mould it 00365 Path* pSourcePath = &(pNodePath->InkPath); 00366 00367 // convert the source path into a destination path 00368 if (!pGeometry->MouldPathToPath(pSourcePath, pSourcePath)) 00369 return FALSE; 00370 00371 pNodePath->InvalidateBoundingRect(); 00372 return TRUE; 00373 } 00374 00375 00376 00377 /******************************************************************************************** 00378 00379 > NodeMouldBitmap* NodeMoulder::CreateMouldBitmap(NodeBitmap* pSourceNodeBlit, 00380 MouldGeometry* pGeometry, 00381 UndoableOperation* pOp) 00382 00383 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00384 Created: 19/12/94 00385 Inputs: pSourceNodeBlit = pointer to a node bitmap 00386 pGeometry = pointer to a mould shape to use for moulding 00387 pOp = pointer to an active operation or NULL if none 00388 Purpose: Creates a NodeMouldBitmap object which is used during rendering to 00389 render normal bitmaps through the mould. 00390 SeeAlso: - 00391 Notes: 00392 00393 We've found a source bitmap so we need to do something about moulding it. 00394 We either mould to a destination bitmap or create a NodeMouldBitmap node, 00395 which uses the bitmap and renders through the current mould. Eek 00396 00397 Algorithm 00398 (1) Create NodeMouldBitmap node 00399 (2) Add the source node type to it 00400 (3) Add the source node object pointer to it 00401 (4) return ok; 00402 00403 The idea here is hopefully simple. Currently bitmaps get rendered in 00404 Camelot as fill attributes. That means what really gets rendered is 00405 a rectangular path, with a fill attribute set to the bitmap. We should 00406 attempt to simulate this but use one of our manifold paths instead. So 00407 when asked to render a NodeMouldBitmap object that we create here, the 00408 render function will simply take the original rectangle, mould it and 00409 render the result with a bitmap fill. I hope. 00410 Hmm, actually this may not be the best way. We need a MouldInk object 00411 but we cannot use a pointer to NodeBitmap due to the fact that we are 00412 in trouble if we copy the whole structure to another document. 00413 00414 ********************************************************************************************/ 00415 00416 NodeMouldBitmap* NodeMoulder::CreateMouldBitmap(NodeBitmap* pSourceNodeBlit, 00417 MouldGeometry* pGeometry, 00418 UndoableOperation* pOp) 00419 { 00420 ERROR2IF(pSourceNodeBlit==NULL, NULL, "CreateMouldBitmap() called with a null source pointer"); 00421 ERROR2IF(pGeometry==NULL, NULL, "CreateMouldBitmap() called with a null geometry pointer"); 00422 00423 // ok we have the source node, so lets create a mould render object 00424 NodeMouldBitmap* pNodeMouldBitmap; 00425 ALLOC_WITH_FAIL( pNodeMouldBitmap, new NodeMouldBitmap, pOp); 00426 if (!pNodeMouldBitmap) 00427 return NULL; 00428 00429 return pNodeMouldBitmap; 00430 } 00431 00432 00433 /******************************************************************************************** 00434 00435 > BOOL NodeMoulder::DestroyMouldedObjects() 00436 00437 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00438 Created: 19/12/94 00439 Inputs: - 00440 Outputs: - 00441 Returns: TRUE if the moulder children were all destroyed successfully 00442 FALSE, if failed. 00443 Purpose: 00444 00445 ********************************************************************************************/ 00446 00447 BOOL NodeMoulder::DestroyMouldedObjects() 00448 { 00449 // first need to add a record to the undo to rebuild the 00450 // moulded objects on a fail! 00451 Node* pChild = FindFirstChild(); 00452 if (pChild!=NULL) 00453 DeleteChildren(pChild); 00454 00455 return TRUE; 00456 } 00457 00458 00459 00460 /******************************************************************************************** 00461 00462 > BOOL NodeMoulder::CreateMouldedObjects( NodeMouldGroup* pGroup, 00463 MouldGeometry* pGeometry, 00464 UndoableOperation* pOp) 00465 00466 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00467 Created: 19/12/94 00468 Inputs: pGroup = pointer to a node mould group object 00469 pGeometry = pointer to a node path shape to use for moulding 00470 pOp = pointer to an active operation or NULL if none 00471 Outputs: 00472 Returns: TRUE if all moulded objects have been created 00473 FALSE if unable to create some moulded objects 00474 Purpose: Given a pointer to a moulder object, create all the moulded children 00475 using the source objects under the nodemouldgroup object 00476 00477 ********************************************************************************************/ 00478 00479 BOOL NodeMoulder::CreateMouldedObjects(NodeMouldGroup* pGroup, MouldGeometry* pGeometry, UndoableOperation* pOp) 00480 { 00481 BOOL Success; 00482 00483 if (pOp!=NULL) 00484 Success=CreateMouldObjsWithUndo(pGroup, pGeometry, pOp); 00485 else 00486 Success=CreateMouldObjsWithoutUndo(pGroup, pGeometry); 00487 00488 return Success; 00489 } 00490 00491 00492 /******************************************************************************************** 00493 00494 > BOOL NodeMoulder::CreateMouldObjsWithUndo( NodeMouldGroup* pGroup, 00495 MouldGeometry* pGeometry, 00496 UndoableOperation* pOp) 00497 00498 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00499 Created: 19/12/94 00500 Inputs: pGroup = pointer to a node mould group object 00501 pGeometry = pointer to a node path shape to use for moulding 00502 pOp = pointer to an active operation 00503 Outputs: 00504 Returns: TRUE if all moulded objects have been created 00505 FALSE if unable to create some moulded objects 00506 Purpose: Given a pointer to a moulder object, create all the moulded children 00507 using the source objects under the nodemouldgroup object 00508 00509 ********************************************************************************************/ 00510 00511 BOOL NodeMoulder::CreateMouldObjsWithUndo(NodeMouldGroup* pGroup, MouldGeometry* pGeometry, UndoableOperation* pOp) 00512 { 00513 ERROR2IF(pGroup==NULL, FALSE, "CreateMouldedObjects() called with a null group pointer"); 00514 ERROR2IF(pGeometry==NULL, FALSE, "CreateMouldedObjects() called with a null geometry pointer"); 00515 00516 Node *pNode, *qNode; 00517 00518 // Stage 1 00519 // Copy all objects from the mould group to this new moulder object 00520 pNode = pGroup->FindFirstChild(); 00521 while (pNode) 00522 { 00523 if (!IS_A(pNode,NodeHidden)) 00524 { 00525 if (!pNode->CopyNode(this,LASTCHILD)) 00526 { 00527 CascadeDelete(); 00528 return FALSE; 00529 } 00530 } 00531 pNode=pNode->FindNext(); 00532 } 00533 00534 // Localise the current attributes. I do this because, although 00535 // most DoBecomeA() functions do their own localisation, bitmaps 00536 // see to apply AttrStrokeColour attributes to Pathified bitmaps 00537 // without localisation. This causes things like ConvertToShapes 00538 // produce MakeAttributeComplete found duplicate attr errors. 00539 if (!pOp->DoLocaliseCommonAttributes(this)) 00540 return FALSE; 00541 00542 // Stage 2 00543 // Get all objects to become paths or nodemouldbitmaps 00544 // Set up a BecomeA derived object, so that we can get everyone to become paths 00545 BecomeA ParamBecomeA(BECOMEA_REPLACE, CC_RUNTIME_CLASS(NodePath), pOp, FALSE); 00546 00547 AttrStrokeType* pStroke = NULL; 00548 00549 pNode = FindFirstChild(); 00550 while (pNode) 00551 { 00552 qNode = pNode->FindNext(); 00553 00554 // bodge to deal with variable width strokes 00555 if (pNode->IsAnObject()) 00556 { 00557 ((NodeRenderableInk*)pNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeType), (NodeAttribute**)&pStroke); 00558 if (pStroke && pStroke->HasPathProcessor()) 00559 { 00560 if (!pStroke->DoBecomeA(&ParamBecomeA, (NodeRenderableInk*)pNode)) 00561 return FALSE; 00562 } 00563 else 00564 if (!pNode->DoBecomeA(&ParamBecomeA)) 00565 return FALSE; 00566 00567 } 00568 pStroke = NULL; 00569 pNode=qNode; 00570 } 00571 00572 // As we've localised lets factor up. Make sure we do the factoring NONE globally. 00573 // We don't want to confuse any attributes. 00574 if (!pOp->DoFactorOutCommonChildAttributes(this)) 00575 return FALSE; 00576 00577 // Stage3 00578 // Process all objects, moulding each object as we go 00579 pNode = FindFirstChild(); 00580 MouldTransform Transformer(pGeometry); 00581 if (!MouldAllChildren(pNode, pGeometry, Transformer, pOp)) 00582 return FALSE; 00583 00584 // Stage4 00585 // Deselect all the naughty selected objects inside ourselves 00586 pNode = FindFirstChild(); 00587 while (pNode) 00588 { 00589 pNode->SetSelected(FALSE); 00590 pNode=pNode->FindNext(); 00591 } 00592 00593 // Stage5, make sure we know our bounds will be updated. 00594 InvalidateBoundingRect(); 00595 return TRUE; 00596 } 00597 00598 00599 00600 /******************************************************************************************** 00601 00602 > BOOL NodeMoulder::CreateMouldObjsWithoutUndo( NodeMouldGroup* pGroup, 00603 MouldGeometry* pGeometry) 00604 00605 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00606 Created: 19/12/94 00607 Inputs: pGroup = pointer to a node mould group object 00608 pGeometry = pointer to a node path shape to use for moulding 00609 Outputs: 00610 Returns: TRUE if all moulded objects have been created 00611 FALSE if unable to create some moulded objects 00612 Purpose: Given a pointer to a moulder object, create all the moulded children 00613 using the source objects under the nodemouldgroup object 00614 00615 ********************************************************************************************/ 00616 00617 BOOL NodeMoulder::CreateMouldObjsWithoutUndo(NodeMouldGroup* pGroup, MouldGeometry* pGeometry) 00618 { 00619 ERROR2IF(pGroup==NULL, FALSE, "CreateMouldedObjects() called with a null group pointer"); 00620 ERROR2IF(pGeometry==NULL, FALSE, "CreateMouldedObjects() called with a null geometry pointer"); 00621 00622 Node *pNode; 00623 00624 // Stage1 00625 // Copy the tree as shapes 00626 if (!pGroup->CopyChildrenAsShapes(this)) 00627 return FALSE; 00628 00629 // Stage2 00630 // Process all objects, moulding each object as we go 00631 pNode = FindFirstChild(); 00632 MouldTransform Transformer(pGeometry); 00633 if (!MouldAllChildren(pNode, pGeometry, Transformer, NULL)) 00634 return FALSE; 00635 00636 // Stage 3 00637 // Factor out those attributes! 00638 if (!FactorOutCommonChildAttributes(FALSE,NULL)) 00639 return FALSE; 00640 00641 // Stage3 00642 // Deselect all the naughty selected objects inside ourselves 00643 pNode = FindFirstChild(); 00644 while (pNode) 00645 { 00646 pNode->SetSelected(FALSE); 00647 pNode=pNode->FindNext(); 00648 } 00649 00650 // Stage4, make sure we know our bounds will be updated. 00651 InvalidateBoundingRect(); 00652 return TRUE; 00653 } 00654 00655 00656 00657 /******************************************************************************************** 00658 00659 > BOOL NodeMoulder::MouldAllChildren( Node* pNode, 00660 MouldGeometry* pGeometry, 00661 TransformBase& Trans, 00662 UndoableOperation* pOp) 00663 00664 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00665 Created: 22/01/95 00666 Inputs: pNode = pointer to a node to start moulding from 00667 pGeometry = pointer to a node path shape to use for moulding 00668 Trans = reference to a mould transform object 00669 pOp = pointer to an active operation or NULL if none 00670 Outputs: 00671 Returns: TRUE if all objects have been moulded 00672 FALSE if unable to mould some objects 00673 Purpose: Given a pointer to a node, begin moulding it, all its children and all 00674 its forward siblings and their children 00675 00676 ********************************************************************************************/ 00677 00678 BOOL NodeMoulder::MouldAllChildren(Node* pNode, 00679 MouldGeometry* pGeometry, 00680 TransformBase& Trans, 00681 UndoableOperation* pOp) 00682 { 00683 Node* qNode; 00684 00685 while (pNode) 00686 { 00687 if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodePath))) 00688 { 00689 // Ok, alter the path 00690 NodePath* pNodePath = (NodePath*)pNode; 00691 if (!MouldPath(pNodePath,pGeometry,pOp)) 00692 return FALSE; 00693 } 00694 else 00695 { 00696 if (pNode->IsAnAttribute()) 00697 { 00698 NodeAttribute* pAttr = (NodeAttribute*)pNode; 00699 00700 if ( pAttr->IsAFillAttr() && IS_A(pGeometry,MouldPerspective) ) 00701 { 00702 // Tell the fill attr to render perspectivised 00703 ((AttrFillGeometry*)pAttr)->MakePerspective(); 00704 } 00705 00706 pAttr->Transform(Trans); 00707 } 00708 } 00709 00710 qNode=pNode->FindFirstChild(); 00711 pNode=pNode->FindNext(); 00712 if (qNode) 00713 { 00714 if (!MouldAllChildren(qNode, pGeometry, Trans, pOp)) 00715 return FALSE; 00716 } 00717 } 00718 return TRUE; 00719 } 00720 00721 00722 00723 /* 00724 if (pList !=NULL) 00725 { 00726 // we have a moulder list so now we can start creating moulded objects 00727 BOOL ok; 00728 00729 MouldListObj* pMouldItem = pList->GetFirstMouldObj(); 00730 NodeRenderableInk* pDestinNode; 00731 00732 while (pMouldItem!=NULL) 00733 { 00734 switch (pMouldItem->GetMouldedType()) 00735 { 00736 case MOULD_PATH: 00737 { 00738 // source object is a path, so we mould to a path 00739 NodePath* pSourceNodePath = (NodePath*)(pMouldItem->GetMouldedSource()); 00740 pDestinNode = CreateMouldPath(pSourceNodePath, pGeometry, pOp); 00741 if (!pDestinNode) 00742 return FALSE; 00743 00744 if (pSourceNodePath->InkPath.IsStroked) 00745 { 00746 // This is nasty. We need to take the stroke applied to 00747 // this object and generate a path from it, which will 00748 // appear as another path in the tree. This will allow line 00749 // thicknesses etc to be transformed correctly. Can we stroke a 00750 // path to a buffer with a line attribute? Well currently I dont 00751 // really know how to do this so we'll leave it for now. 00752 00753 } 00754 00755 } 00756 break; 00757 00758 case MOULD_BITMAP: 00759 { 00760 NodeBitmap* pSourceBitmap = (NodeBitmap*)(pMouldItem->GetMouldedSource()); 00761 pDestinNode = CreateMouldBitmap(pSourceBitmap, pGeometry, pOp); 00762 if (!pDestinNode) 00763 return FALSE; 00764 } 00765 break; 00766 } 00767 00768 // Now stick the new node inside us (ie the nodemoulder) 00769 CALL_WITH_FAIL(pOp->DoInsertNewNode(pDestinNode, this, LASTCHILD, FALSE, FALSE, FALSE, FALSE), pOp, ok); 00770 if (!ok) 00771 { 00772 delete pDestinNode; 00773 return FALSE; 00774 } 00775 00776 // get the next mould item and mould it 00777 pMouldItem = pList->GetNextMouldObj(pMouldItem); 00778 } 00779 } 00780 return TRUE; 00781 } 00782 00783 */ 00784 00785 00786 00787 00788 00789 00790 00791 /*********************************************************************************************** 00792 00793 > virtual Node* NodeMoulder::SimpleCopy() 00794 00795 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00796 Created: 2/12/94 00797 Returns: Pointer to a Node 00798 Purpose: Makes a copy of all the data in the node 00799 00800 ***********************************************************************************************/ 00801 00802 Node* NodeMoulder::SimpleCopy() 00803 { 00804 // Make a new NodeMoulder and then copy things into it 00805 NodeMoulder* pCopyOfNode = new NodeMoulder(); 00806 if (pCopyOfNode) 00807 CopyNodeContents(pCopyOfNode); 00808 00809 return pCopyOfNode; 00810 } 00811 00812 00813 /*********************************************************************************************** 00814 00815 > void NodeMoulder::CopyNodeContents(NodeMoulder* pCopyOfNode) 00816 00817 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00818 Created: 2/12/94 00819 Inputs: pCopyOfNode - The node to copy data to 00820 Purpose: Copies the data in this node to pCopyOfNode by first calling the 00821 base class to get it to copy its stuff, and then copying its own stuff 00822 Scope: protected 00823 SeeAlso: NodeRenderableInk::CopyNodeContents 00824 00825 ***********************************************************************************************/ 00826 00827 void NodeMoulder::CopyNodeContents(NodeMoulder* pCopyOfNode) 00828 { 00829 NodeRenderableInk::CopyNodeContents(pCopyOfNode); 00830 // Copy contents specific to derived class here 00831 } 00832 00833 00834 /*********************************************************************************************** 00835 > void NodeMoulder::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00836 00837 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00838 Created: 18/12/2003 00839 Outputs: - 00840 Purpose: Polymorphically copies the contents of this node to another 00841 Errors: An assertion failure will occur if NodeCopy is NULL 00842 Scope: protected 00843 00844 ***********************************************************************************************/ 00845 00846 void NodeMoulder::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00847 { 00848 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 00849 ENSURE(IS_A(pNodeCopy, NodeMoulder), "PolyCopyNodeContents given wrong dest node type"); 00850 00851 if (IS_A(pNodeCopy, NodeMoulder)) 00852 CopyNodeContents((NodeMoulder*)pNodeCopy); 00853 } 00854 00855 00856 00857 /*********************************************************************************************** 00858 00859 > void NodeMoulder::ShowDebugTreeDetails() const 00860 00861 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00862 Created: 2/12/94 00863 Purpose: Displays debugging info of the tree 00864 SeeAlso: NodeRenderableInk::ShowDebugTreeDetails 00865 00866 ***********************************************************************************************/ 00867 #ifdef _DEBUG 00868 void NodeMoulder::ShowDebugTreeDetails() const 00869 { 00870 TRACE( _T("Moulder")); 00871 // Display a bit of debugging info 00872 // For now, we will just call the base class version 00873 NodeRenderableInk::ShowDebugTreeDetails(); 00874 } 00875 #endif 00876 00877 00878 00879 00880 /******************************************************************************************** 00881 00882 > void NodeMoulder::GetDebugDetails( StringBase* Str ) 00883 00884 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00885 Created: 2/12/94 00886 Outputs: Str: String giving debug info about the node 00887 Purpose: For obtaining debug information about the Node 00888 00889 ********************************************************************************************/ 00890 00891 void NodeMoulder::GetDebugDetails( StringBase* Str ) 00892 { 00893 #ifdef _DEBUG 00894 // Call base class 00895 NodeRenderableInk::GetDebugDetails( Str ); 00896 00897 String_256 TempStr; 00898 00899 (*Str) += TEXT( "\r\nMoulder Data Dump\r\n" ); 00900 00901 /* TempStr._MakeMsg( "Mould steps = #1%ld\n" 00902 "Index start = #2%ld\n" 00903 "Index end = #3%ld\n\n" 00904 "", 00905 IndexStart, 00906 IndexEnd); 00907 00908 *Str += TempStr; 00909 */ 00910 DocRect BlobRect = GetBlobBoundingRect(); 00911 TempStr._MakeMsg( TEXT("Blob Bounding Rect :-\r\n\t#1%ld,\t#2%ld\r\n\t#3%ld,\t#4%ld\r\n"), 00912 BlobRect.lo.x, BlobRect.lo.y, BlobRect.hi.x, BlobRect.hi.y ); 00913 (*Str) += TempStr; 00914 #endif 00915 } 00916 00917 00918 00919 /******************************************************************************************** 00920 00921 > virtual void NodeMoulder::Transform( TransformBase& Trans ) 00922 00923 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00924 Created: 2/12/94 00925 Inputs: Trans - The transform Object 00926 Purpose: Transforms all the paths attached to this Moulder node 00927 SeeAlso: NodeRenderableInk::Transform() 00928 00929 ********************************************************************************************/ 00930 00931 void NodeMoulder::Transform( TransformBase& Trans ) 00932 { 00933 // the moulder node bbox is now invalid 00934 InvalidateBoundingRect(); 00935 // Transform all the children 00936 // See GroupCanTransformCached() 00937 NodeGroup::Transform(Trans); 00938 } 00939 00940 00941 00942 /*********************************************************************************************** 00943 00944 > void NodeMoulder::Render(RenderRegion* pRender) 00945 00946 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00947 Created: 11/10/94 00948 Inputs: Pointer to a render region 00949 Purpose: Will render the steps of this Moulder node 00950 00951 ***********************************************************************************************/ 00952 00953 void NodeMoulder::Render(RenderRegion* pRender) 00954 { 00955 // pRender->SaveContext(); 00956 // RenderMoulderedObjs(pRender); // Only supply a render region, because we're only rendering 00957 // pRender->RestoreContext(); 00958 } 00959 00960 00961 /******************************************************************************************** 00962 00963 > DocRect NodeMoulder::GetBoundingRect(BOOL DontUseAttrs=FALSE, BOOL HitTest=FALSE) 00964 00965 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00966 Created: 2/12/94 00967 Inputs: DontUseAttrs - TRUE if we should ignore the nodes attributes. 00968 Defaults to FALSE 00969 HitTest - TRUE if being called during HitTest 00970 Returns: The nodes bounding rect 00971 Purpose: if the bounding rect is valid it is returned, if not, it is recalculated 00972 and then returned. 00973 SeeAlso: NodeMoulder::GetBlobBoundingRect 00974 00975 ********************************************************************************************/ 00976 00977 DocRect NodeMoulder::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest) 00978 { 00979 if (!IsBoundingRectValid || DontUseAttrs) 00980 { 00981 DocRect NewRect = GetChildBBox(DontUseAttrs); 00982 00983 // just return this rectangle as it is not the nodes true bounding rect 00984 if (DontUseAttrs) 00985 return NewRect; 00986 00987 // copy the new docrect into the node bounding rect 00988 BoundingRectangle = NewRect; 00989 IsBoundingRectValid = TRUE; 00990 } 00991 00992 // Return the resulting bounding rect 00993 return BoundingRectangle; 00994 } 00995 00996 00997 00998 /******************************************************************************************** 00999 01000 > DocRect NodeMoulder::GetChildBBox(BOOL DontUseAttrs) 01001 01002 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01003 Created: 6/12/94 01004 Inputs: DontUseAttrs - TRUE if we should ignore the nodes attributes. 01005 Defaults to FALSE 01006 Returns: The bounding rectangle of all the moulder children 01007 Purpose: Calculates the bounding rectangle of the children of a moulder object. 01008 It does this by scanning the child objects and merging each bounded child 01009 bbox together 01010 01011 ********************************************************************************************/ 01012 01013 DocRect NodeMoulder::GetChildBBox(BOOL DontUseAttrs) 01014 { 01015 // Find the moulders mangled object bounds 01016 DocRect Rect(0,0,0,0); 01017 Node* pNode = FindFirstChild(); 01018 while (pNode!=NULL) 01019 { 01020 // if this node is bounded, union its bounds with the others 01021 if (pNode->IsBounded()) 01022 Rect = Rect.Union(((NodeRenderableBounded*)pNode)->GetBoundingRect(DontUseAttrs)); 01023 pNode = pNode->FindNext(); 01024 } 01025 return Rect; 01026 } 01027 01028 01029 01030 01031 /******************************************************************************************** 01032 01033 > DocRect NodeMoulder::GetBlobBoundingRect() 01034 01035 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01036 Created: 2/12/94 01037 Returns: DocRect - Returns the bounding rect of the Moulder node and its blobs 01038 Purpose: Scan through the Mouldered paths finding bounding boxes of Mouldered objects 01039 01040 ********************************************************************************************/ 01041 01042 DocRect NodeMoulder::GetBlobBoundingRect() 01043 { 01044 return (GetBoundingRect()); 01045 } 01046 01047 01048 01049 01050 /******************************************************************************************** 01051 01052 > virtual UINT32 NodeMoulder::GetNodeSize() const 01053 01054 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01055 Created: 2/12/94 01056 Returns: The size of the node in bytes 01057 Purpose: For finding the size of the node 01058 SeeAlso: Node::GetSubtreeSize 01059 01060 ********************************************************************************************/ 01061 01062 UINT32 NodeMoulder::GetNodeSize() const 01063 { 01064 return (sizeof(NodeMoulder)); 01065 } 01066 01067 01068 01069 /******************************************************************************************** 01070 01071 > BOOL NodeMoulder::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 01072 Spread* pSpread ) 01073 01074 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01075 Created: 11/10/94 01076 Inputs: PointerPos - The Location of the mouse pointer at the time of the click 01077 Click - The type of click received (single, double, drag etc) 01078 ClickMods - The modifiers to the click (eg shift, control etc ) 01079 Returns: BOOL - TRUE if the node claims the click as its own and FALSE if it is 01080 not interested in the click 01081 Purpose: Allows the Node to respond to clicks by selecting its blobs or starting 01082 drags etc. 01083 01084 ********************************************************************************************/ 01085 01086 BOOL NodeMoulder::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 01087 Spread* pSpread ) 01088 { 01089 // we did not use the click, so let someone else try 01090 return FALSE; 01091 } 01092 01093 01094 /******************************************************************************************** 01095 01096 > virtual BOOL NodeMoulder::CanBecomeA(BecomeA* pBecomeA) 01097 01098 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01099 Created: 2/12/94 01100 Inputs: InkClass: The class of object 01101 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL). 01102 *pNumObects in undefined on entry 01103 Returns: TRUE if the node, or any of its children can transmogrify themselves to become 01104 an InkClass object 01105 Purpose: This function is used by the convert to shapes operation. It determines if 01106 the node or any of its children can convert themselves into an InkClass object. 01107 01108 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number 01109 of pClass objects you create. It should NOT contain any additional objects you may produce 01110 such as group objects for containing the pClass object, or attributes. 01111 01112 Also, the entry value of *pNumObjects cannot be assumed to be 0. 01113 01114 ********************************************************************************************/ 01115 01116 BOOL NodeMoulder::CanBecomeA(BecomeA* pBecomeA) 01117 { 01118 // The NodeMoulder can become a NodePath 01119 if (pBecomeA->BAPath()) 01120 { 01121 if (pBecomeA->IsCounting()) 01122 { 01123 // Count the number of NodePaths that are children of this NodeMoulder 01124 Node* pNode = FindFirstChild(); 01125 while (pNode != NULL) 01126 { 01127 pNode->CanBecomeA(pBecomeA); // Increments count 01128 01129 pNode = pNode->FindNext(); 01130 } 01131 } 01132 01133 return TRUE; 01134 } 01135 01136 return FALSE; 01137 } 01138 01139 01140 /******************************************************************************************** 01141 01142 > virtual BOOL NodeMoulder::DoBecomeA(BecomeA* pBecomeA) 01143 01144 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01145 Created: 5/12/94 01146 Inputs: pBecomeA = ptr to a class that contains all the info needed to become a new 01147 type of node. 01148 Outputs: - 01149 Returns: TRUE if the object has been transformed, FALSE if we run out of memory 01150 01151 Purpose: Transforms the object into another type of object. 01152 This converts all its children, and replaces itself in the tree with a NodeGroup 01153 Errors: - 01154 SeeAlso: Node::CanBecomeA 01155 01156 ********************************************************************************************/ 01157 01158 BOOL NodeMoulder::DoBecomeA(BecomeA* pBecomeA) 01159 { 01160 // Check for a NULL entry param 01161 ERROR2IF_PF(pBecomeA == NULL,FALSE,("NodeMoulder::DoBecomeA() called with a NULL ptr")); 01162 01163 switch (pBecomeA->GetReason()) 01164 { 01165 case BECOMEA_REPLACE: 01166 { 01167 // If replacing the moulder with shapes, hide the moulder, create a group, and move all the children 01168 // so they become children of the new group node 01169 ERROR2IF(pBecomeA->GetUndoOp() == NULL,FALSE,"Trying to replace a NodeMoulder, but pUndoOp == NULL"); 01170 UndoableOperation* pUndoOp = pBecomeA->GetUndoOp(); 01171 BOOL ok; 01172 01173 // If being repaced in the tree, deselect the node 01174 BOOL IsSelected=this->IsSelected(); 01175 SetSelected(FALSE); 01176 01177 // Pass on this message to our child ink nodes first 01178 Node* pNode = FindFirstChild(); 01179 while (pNode != NULL) 01180 { 01181 Node* pThisNode = pNode; 01182 pNode = pNode->FindNext(); 01183 pThisNode->DoBecomeA(pBecomeA); 01184 } 01185 01186 // Allocate a new NodeGroup node 01187 NodeGroup* pNodeGroup; 01188 ALLOC_WITH_FAIL(pNodeGroup, (new NodeGroup), pUndoOp); 01189 if (pNodeGroup == NULL) 01190 return FALSE; 01191 01192 // Insert the NodeGroup where the NodeMoulder used to be 01193 if (!pUndoOp->DoInsertNewNode(pNodeGroup,this,NEXT,FALSE,FALSE,FALSE,FALSE)) 01194 return FALSE; 01195 01196 // if we were selected the lets select our group 01197 if (IsSelected) 01198 { 01199 // Select the group 01200 if (!pUndoOp->DoSelectNode(pNodeGroup,FALSE)) 01201 return FALSE; 01202 } 01203 01204 // localise common child attributes before moving objects! 01205 if (!pUndoOp->DoLocaliseCommonAttributes(this)) 01206 return FALSE; 01207 01208 // Now move each node in turn. 01209 pNode = FindLastChild(); 01210 while (pNode != NULL) 01211 { 01212 // Find the next node to move before we shift up the children 01213 Node* pPrevNode = pNode->FindPrevious(); 01214 if (pNode->IsAnObject()) 01215 { 01216 CALL_WITH_FAIL(pUndoOp->DoMoveNode(pNode, pNodeGroup, FIRSTCHILD), pUndoOp, ok); 01217 if (!ok) 01218 return FALSE; 01219 } 01220 pNode = pPrevNode; 01221 } 01222 01223 // factor up on the group. 01224 if (!pUndoOp->DoFactorOutCommonChildAttributes(pNodeGroup)) 01225 return FALSE; 01226 01227 // Hide the moulder node 01228 NodeHidden* pNodeHidden; 01229 if (!pUndoOp->DoHideNode(this, FALSE, &pNodeHidden, FALSE)) 01230 return FALSE; 01231 01232 // and finally remove any nasty perspective fills from the result 01233 NodeMould::RemovePerspectiveFills(pNodeGroup, pUndoOp); 01234 01235 } 01236 break; 01237 01238 case BECOMEA_PASSBACK: 01239 { 01240 // We have been called to becomea passback on the moulder. 01241 // We cannot allow paths to be put in the tree with perspective fills 01242 // in them so we must hide the fills and replace them with standard ones 01243 // We should not do this on the clipboard however as undo/redo fails and 01244 // pasting clipboard contents wont work after! 01245 Document* pOwner = (Document*)FindOwnerDoc(); 01246 if (pOwner == NULL || pOwner->IsNotAClipboard()) 01247 NodeMould::RemovePerspectiveFills(this, pBecomeA->GetUndoOp()); 01248 01249 // Sequentially ask the children of the moulder to DoBecomeA 01250 // This is all that's required because the child objects are only passing back 01251 // the new node type, and NOT replacing themselves in the tree 01252 // This also ensures the receipient gets the list of paths in render order 01253 Node* pNode = FindFirstChild(); 01254 while (pNode != NULL) 01255 { 01256 if (!pNode->DoBecomeA(pBecomeA)) 01257 return FALSE; 01258 01259 pNode = pNode->FindNext(); 01260 } 01261 } 01262 break; 01263 01264 default: 01265 ERROR3_PF(("Unknown BecomeA reason %d",pBecomeA->GetReason())); 01266 break; 01267 } 01268 01269 01270 // If this is a Perspective Mould, then we need to ensure 01271 // that any perspective fills are removed, as it is 01272 // dangerous to allow the user to edit a shape containing 01273 // a perspectivised fill. 01274 return TRUE; 01275 } 01276 01277 01278 01279 01280 01281 01282 01283 /*********************************************************************************************** 01284 01285 > BOOL NodeMoulder::Snap(DocCoord* pDocCoord) 01286 01287 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01288 Created: 2/12/94 01289 Inputs: pDocCoord = a coord in Spread coords 01290 Outputs: 01291 Returns: TRUE - the DocCoord has been snapped . 01292 FALSE - the DocCoord has not been processed. 01293 01294 Purpose: Snaps to given coord to the nearest point on the Moulder node. 01295 Just returns FALSE currently 01296 Errors: 01297 Scope: public 01298 01299 **********************************************************************************************/ 01300 01301 //BOOL NodeMoulder::Snap(DocCoord* pDocCoord) 01302 //{ 01303 // return FALSE; 01304 //} 01305 01306 01307 01308 /******************************************************************************************** 01309 01310 > BOOL NodeMoulder::NeedsToExport(RenderRegion* pRender, BOOL VisibleLayersOnly = FALSE, 01311 BOOL CheckSelected = FALSE) 01312 01313 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01314 Created: 23/03/95 01315 Inputs: pRender - A pointer to the current export region 01316 VisibleLayersOnly - TRUE => remove nodes which are on invisible layers 01317 - FALSE => export everything 01318 CheckSelected - TRUE => we check if object selected and only export selected bjects 01319 - FALSE => we don't bother checking for selection or not 01320 Returns: TRUE => please export me. 01321 Purpose: Virtual function - this version will return FALSE for exporting to native 01322 EPS documents. We dont need the moulded objects in these docs. 01323 01324 ********************************************************************************************/ 01325 01326 BOOL NodeMoulder::NeedsToExport(RenderRegion* pRender, BOOL VisibleLayersOnly, 01327 BOOL CheckSelected) 01328 { 01329 #ifdef DO_EXPORT 01330 if (pRender==NULL) 01331 return TRUE; 01332 01333 // dont export to native documents 01334 if (pRender->IS_KIND_OF(NativeRenderRegion)) 01335 return FALSE; 01336 01337 // If we have the check selection flag on then see if this moulder node is:- 01338 // - selected or not = render it 01339 // - a child of the selection e.g. part of selected group where we are an item in the 01340 // group and hence are not directly selected but still need to be exported 01341 // - a parent of the selected item e.g. selected inside item of group and we are at the 01342 // group and hence need to include the group in the range 01343 // Otherwise just return True as this is a moulder node and always needs to be exported 01344 // unless of course some node overrides this or the test above fails. 01345 if (CheckSelected) 01346 return (IsSelected() || IsChildOfSelected() || IsParentOfSelected()); 01347 else 01348 return TRUE; 01349 #else 01350 return FALSE; 01351 #endif 01352 } 01353 01354 01355 /********************************************************************************************* 01356 01357 > void NodeMoulder::PreExportRender(RenderRegion* pRegion) 01358 01359 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01360 Created: 14/03/95 01361 Inputs: pRegion = ptr to the export render region to export to 01362 Outputs: 01363 Returns: 01364 Purpose: Called before this node or any of its children have been rendered to the 01365 export region. This outputs the "start mould destin objects" command. 01366 Supports ArtWorks EPS and Camelot EPS 01367 Errors: 01368 01369 **********************************************************************************************/ 01370 01371 void NodeMoulder::PreExportRender(RenderRegion* pRegion) 01372 { 01373 #ifdef DO_EXPORT 01374 if (pRegion->IS_KIND_OF(CamelotEPSRenderRegion)) 01375 { 01376 PreExportCAMEPS(pRegion); 01377 return; 01378 } 01379 01380 if (pRegion->IS_KIND_OF(ArtWorksEPSRenderRegion)) 01381 { 01382 PreExportAWEPS(pRegion); 01383 return; 01384 } 01385 #endif 01386 } 01387 01388 /********************************************************************************************* 01389 01390 > BOOL NodeMoulder::ExportRender(RenderRegion* pRegion) 01391 01392 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01393 Created: 14/03/95 01394 Inputs: pRegion = ptr to the export render region to export to 01395 Outputs: 01396 Returns: TRUE if ok, FALSE if something went wrong 01397 Purpose: Called after this node and all of its children have been rendered to the 01398 export region. This outputs the "end mould destin objs" command. 01399 Supports ArtWorks EPS and Camelot EPS 01400 Errors: 01401 01402 **********************************************************************************************/ 01403 01404 BOOL NodeMoulder::ExportRender(RenderRegion* pRegion) 01405 { 01406 #ifdef DO_EXPORT 01407 if (pRegion->IS_KIND_OF(CamelotEPSRenderRegion)) 01408 return PostExportCAMEPS(pRegion); 01409 01410 if (pRegion->IS_KIND_OF(ArtWorksEPSRenderRegion)) 01411 return PostExportAWEPS(pRegion); 01412 #endif 01413 return FALSE; 01414 } 01415 01416 01417 /********************************************************************************************* 01418 01419 BOOL NodeMoulder::Pre/Post ExportCAMEPS(RenderRegion* pRegion) 01420 01421 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01422 Created: 14/03/95 01423 Purpose: Export delimiter tokens for this particular object. 01424 The format is defined as 01425 csmp 01426 path description 01427 cemp 01428 01429 **********************************************************************************************/ 01430 01431 void NodeMoulder::PreExportCAMEPS(RenderRegion* pRegion) 01432 { 01433 #ifdef DO_EXPORT 01434 // Make sure this token goes out only in Native documents 01435 if (pRegion->IS_KIND_OF(NativeRenderRegion)) 01436 { 01437 EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC(); 01438 pDC->OutputToken(_T("csdo")); // Camelot "start mould destin" token 01439 pDC->OutputNewLine(); 01440 } 01441 #endif 01442 } 01443 01444 01445 BOOL NodeMoulder::PostExportCAMEPS(RenderRegion* pRegion) 01446 { 01447 #ifdef DO_EXPORT 01448 // Make sure this token goes out only in Native documents 01449 if (pRegion->IS_KIND_OF(NativeRenderRegion)) 01450 { 01451 EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC(); 01452 pDC->OutputToken(_T("cedo")); // Camelot "end mould destin" token 01453 pDC->OutputNewLine(); 01454 return TRUE; 01455 } 01456 #endif 01457 // Otherwise render as paths (e.g. in EPS) 01458 return FALSE; 01459 } 01460 01461 01462 /********************************************************************************************* 01463 01464 void NodeMoulder::Pre/Post ExportAWEPS(RenderRegion* pRegion) 01465 01466 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01467 Created: 14/03/95 01468 01469 **********************************************************************************************/ 01470 01471 void NodeMoulder::PreExportAWEPS(RenderRegion* pRegion) 01472 { 01473 } 01474 01475 BOOL NodeMoulder::PostExportAWEPS(RenderRegion* pRegion) 01476 { 01477 return FALSE; 01478 } 01479 01480 01481 01482 /******************************************************************************************** 01483 01484 > virtual BOOL NodeMoulder::AllowOp( ObjChangeParam* pParam, 01485 BOOL SetOpPermissionState = TRUE, 01486 DoPreTriggerEdit = TRUE) 01487 01488 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>; Karim 20/01/2000 01489 Created: 30/6/95 01490 Inputs: pParam - pointer to the change parameter object 01491 SetOpPermissionState - TRUE to set the Nodes permission flags 01492 DoPreTriggerEdit - if TRUE then calls NameGallery::PreTriggerEdit. 01493 *Must* be TRUE if the calling Op may make any nodes 01494 change their bounds, eg move, line width, cut. 01495 Use TRUE if unsure. 01496 01497 Returns: TRUE if the operation can proceede, FALSE to stop it 01498 Purpose: Generic AllowOp() for all moulder nodes. 01499 01500 ********************************************************************************************/ 01501 01502 BOOL NodeMoulder::AllowOp(ObjChangeParam* pParam, BOOL SetOpPermissionState, 01503 BOOL DoPreTriggerEdit) 01504 { 01505 ERROR2IF(pParam==NULL,FALSE,"Node::AllowOp() - pParam==NULL"); 01506 01507 // if not called by a child AllowOp(), ensure AllowOp() called for all nodes in compound nodes, 01508 if (pParam->GetDirection()!=OBJCHANGE_CALLEDBYCHILD) 01509 { 01510 BOOL AnyAllowed=AllowOp_AccountForCompound( pParam, 01511 SetOpPermissionState, 01512 DoPreTriggerEdit ); 01513 // if called by a parent, just pass this result back 01514 if (pParam->GetDirection()==OBJCHANGE_CALLEDBYPARENT) 01515 return AnyAllowed; 01516 } 01517 else 01518 { 01519 // clean out the calling-child ptr, so it doesn't get passed around unintentionally. 01520 pParam->SetCallingChild(NULL); 01521 } 01522 01523 // at this point we must have been called directly by the op or via a child AllowOp() 01524 01525 // decide if we allow it, we dont allow very much at the moment, the only thing you can 01526 // actually do to children of a moulder is to copy them 01527 BOOL allowed=TRUE; 01528 ObjChangeFlags Flags=pParam->GetChangeFlags(); 01529 if ((pParam->GetDirection()==OBJCHANGE_CALLEDBYCHILD) || 01530 (pParam->GetDirection()==OBJCHANGE_CALLEDBYOP)) 01531 // if (Flags.DeleteNode || Flags.ReplaceNode || Flags.MoveNode || Flags.Attribute || Flags.MultiReplaceNode || Flags.TransformNode) 01532 { 01533 pParam->SetReasonForDenial(_R(IDS_MOULD_CANT_OP_ON_CHILDREN)); 01534 allowed=FALSE; 01535 } 01536 01537 // if we allowed it, see if our parents do ... 01538 if (allowed && Parent!=NULL) 01539 { 01540 ObjChangeDirection OldDirection=pParam->GetDirection(); 01541 pParam->SetCallingChild(this); 01542 pParam->SetDirection(OBJCHANGE_CALLEDBYCHILD); 01543 allowed=Parent->AllowOp(pParam,SetOpPermissionState,DoPreTriggerEdit); 01544 pParam->SetDirection(OldDirection); 01545 } 01546 01547 // if setting permisions ... 01548 if (SetOpPermissionState) 01549 { 01550 // if allowed, mark parent accordingly, else mark child as denied and update parents 01551 if (allowed) 01552 Parent->SetOpPermission(PERMISSION_ALLOWED); 01553 else 01554 SetOpPermission(PERMISSION_DENIED,TRUE); 01555 } 01556 01557 // if we're ok so far and were asked to do a PreTriggerEdit, then 01558 // determine whether the Op may change the bounds of some nodes. 01559 // If it may, then call NameGallery::PreTriggerEdit. 01560 if (allowed && DoPreTriggerEdit) 01561 { 01562 // if the Op is non-NULL then query its MayChangeNodeBounds() method. 01563 UndoableOperation* pChangeOp = pParam->GetOpPointer(); 01564 if (pChangeOp != NULL && pChangeOp->MayChangeNodeBounds()) 01565 { 01566 if (NameGallery::Instance()) 01567 allowed = NameGallery::Instance()->PreTriggerEdit(pChangeOp, pParam, this); 01568 } 01569 } 01570 01571 // return result (directly, or indirectly via a child AllowOp()) to op 01572 return allowed; 01573 } 01574 01575 01576 /******************************************************************************************** 01577 01578 > virtual ChangeCode NodeMoulder::OnChildChange(ObjChangeParam* pParam) 01579 01580 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01581 Created: 09/01/95 01582 Inputs: pParam = pointer to a object change parameter class 01583 Returns: CC_OK if we have successfully processed the change. 01584 CC_FAIL if we cannot handle this particular change and must prevent the 01585 child from continuing 01586 Purpose: This function should be overridden in derived object classes. 01587 Composite objects can use this function to respond to one of their children 01588 undergoing a change. They should return CC_FAIL whenever they are unable to 01589 cope with the change. 01590 SeeAlso: WarnParentOfChange(); 01591 01592 ********************************************************************************************/ 01593 01594 ChangeCode NodeMoulder::OnChildChange(ObjChangeParam* pParam) 01595 { 01596 return CC_OK; 01597 } 01598 01599 /******************************************************************************************** 01600 01601 > virtual BOOL NodeMoulder::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 01602 01603 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01604 Created: 18/7/96 01605 Inputs: pFilter = ptr to the filter to write to 01606 Returns: TRUE is a record has been written, FALSE otherwise 01607 Purpose: Writes out a records associated with this node 01608 01609 NodeMoulders do NOT save anything out in the current version of Camelot. 01610 01611 ********************************************************************************************/ 01612 01613 BOOL NodeMoulder::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 01614 { 01615 return FALSE; 01616 } 01617 01618 //------------------------------------------------------------------ 01619 // See comments for NodeMoulder::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 01620 BOOL NodeMoulder::WritePreChildrenNative(BaseCamelotFilter* pFilter) 01621 { 01622 return WritePreChildrenWeb(pFilter); 01623 } 01624 01625 /******************************************************************************************** 01626 01627 > virtual BOOL NodeMoulder::CanWriteChildrenWeb(BaseCamelotFilter* pFilter) 01628 01629 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01630 Created: 18/7/96 01631 Inputs: pFilter = ptr to the filter to write to 01632 Returns: TRUE if children can be written automatically, FALSE otherwise 01633 Purpose: This allows a node to stop the filter from writing out the child nodes automatically. 01634 01635 NodeMoulders do NOT save anything out in the current version of Camelot. 01636 Therefore, none of it's children can be saved out either. 01637 01638 ********************************************************************************************/ 01639 01640 BOOL NodeMoulder::CanWriteChildrenWeb(BaseCamelotFilter* pFilter) 01641 { 01642 return FALSE; 01643 } 01644 01645 //------------------------------------------------------------------ 01646 // See comments for NodeMoulder::CanWriteChildrenNative(BaseCamelotFilter* pFilter) 01647 BOOL NodeMoulder::CanWriteChildrenNative(BaseCamelotFilter* pFilter) 01648 { 01649 return CanWriteChildrenWeb(pFilter); 01650 } 01651