00001 // $Id: nodecomp.cpp 1385 2006-06-28 16:48:01Z 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 00099 /* 00100 */ 00101 00102 #include "camtypes.h" 00103 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00104 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00105 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 //#include "nodecomp.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 #include "objchge.h" 00108 00109 // Resource headers 00110 //#include "resource.h" 00111 00112 // operation headers 00113 #include "ophist.h" 00114 #include "transop.h" 00115 #include "attrappl.h" 00116 00117 // attribute headers 00118 #include "lineattr.h" 00119 //#include "txtattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00120 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00121 #include "attrbev.h" 00122 #include "cutop.h" 00123 #include "nodetxts.h" 00124 #include "nodetext.h" 00125 #include "opbevel.h" 00126 #include "textops.h" 00127 #include "blobs.h" 00128 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00129 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00130 #include "nodebldr.h" 00131 #include "blendatt.h" 00132 //#include "mario.h" 00133 #include "pathops.h" 00134 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00135 00136 DECLARE_SOURCE( "$Revision: 1385 $" ); 00137 00138 CC_IMPLEMENT_DYNCREATE(CompoundNodeTreeFactory, CCObject) 00139 CC_IMPLEMENT_DYNCREATE(NodeCompound, NodeRenderableInk) 00140 00141 // Declare smart memory handling in Debug builds 00142 #define new CAM_DEBUG_NEW 00143 00144 // static variables that are used by the blending system when blending compound nodes .... 00145 00146 NodeCompound* NodeCompound::shadowThisNode = NULL; 00147 NodeCompound* NodeCompound::shadowDeleteThis = NULL; 00148 00149 List* NodeCompound::blndConsBecomeAShadows = NULL; // list of shadow controllers that were generated when blending (internally via PASSBACK) 00150 List* NodeCompound::blndConsBecomeABevels = NULL; // list of bevel controllers that were generated when blending (internally via PASSBACK) 00151 List* NodeCompound::blndConsBecomeAContours = NULL; // list of contour controllers that were generated when blending (internally via PASSBACK) 00152 00153 BOOL NodeCompound::isForPrinting = FALSE; 00154 00155 #ifdef _DEBUG 00156 00157 INT32 NodeCompound::shadowLastID = 0; 00158 INT32 NodeCompound::bevelLastID = 0; 00159 INT32 NodeCompound::contourLastID = 0; 00160 00161 INT32 NodeCompound::shadowLastBecomeAID = 0; 00162 INT32 NodeCompound::bevelLastBecomeAID = 0; 00163 INT32 NodeCompound::contourLastBecomeAID = 0; 00164 00165 #endif 00166 00167 /*********************************************************************************************** 00168 00169 > NodeCompound::NodeCompound(Node* ContextNode, 00170 AttachNodeDirection Direction, 00171 const DocRect& BoundingRect, 00172 BOOL Locked = FALSE, 00173 BOOL Mangled = FALSE, 00174 BOOL Marked = FALSE, 00175 BOOL Selected = FALSE, 00176 BOOL Renderable = FALSE 00177 ) 00178 00179 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00180 Created: 11/5/99 00181 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 00182 MonoOn Direction: MonoOff 00183 Specifies the direction in which the node is to be attached to the 00184 ContextNode. The values this variable can take are as follows: 00185 00186 PREV : Attach node as a previous sibling of the context node 00187 NEXT : Attach node as a next sibling of the context node 00188 FIRSTCHILD: Attach node as the first child of the context node 00189 LASTCHILD : Attach node as a last child of the context node 00190 00191 BoundingRect: Bounding rectangle 00192 00193 The remaining inputs specify the status of the node: 00194 00195 Locked: Is node locked ? 00196 Mangled: Is node mangled ? 00197 Marked: Is node marked ? 00198 Selected: Is node selected ? 00199 00200 Purpose: This constructor initialises the nodes flags and links it to ContextNode in the 00201 direction specified by Direction. All neccesary tree links are updated. 00202 Note: SetUpShape() must be called before the NodeRegularShape is in a state in which 00203 it can be used. 00204 SeeAlso: NodeRegularShape::SetUpShape 00205 Errors: An ENSURE will occur if ContextNode is NULL 00206 00207 ***********************************************************************************************/ 00208 NodeCompound::NodeCompound(Node* ContextNode, 00209 AttachNodeDirection Direction, 00210 BOOL Locked, 00211 BOOL Mangled, 00212 BOOL Marked, 00213 BOOL Selected 00214 ) : NodeRenderableInk(ContextNode, Direction, Locked, Mangled, Marked, Selected ) 00215 { 00216 m_DPI = 96.0; 00217 m_bPrinting = FALSE; 00218 00219 // blending attributes 00220 m_bBlendStartNode = FALSE; 00221 m_bBlendEndNode = FALSE; 00222 m_pBlendCreatedByNode = NULL; 00223 } 00224 00225 /********************************************************************************************* 00226 00227 > NodeCompound::NodeCompound() 00228 00229 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00230 Created: 11/5/99 00231 Purpose: 00232 Note: 00233 SeeAlso: 00234 00235 **********************************************************************************************/ 00236 NodeCompound::NodeCompound() : NodeRenderableInk() 00237 { 00238 m_DPI = 96.0; 00239 m_bPrinting = FALSE; 00240 m_bBlendStartNode = FALSE; 00241 m_bBlendEndNode = FALSE; 00242 m_pBlendCreatedByNode = NULL; 00243 } 00244 00245 /********************************************************************************************* 00246 00247 > NodeCompound::~NodeCompound() 00248 00249 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00250 Created: 11/5/99 00251 Purpose: Destructor 00252 Note: 00253 SeeAlso: 00254 00255 **********************************************************************************************/ 00256 NodeCompound::~NodeCompound() 00257 { 00258 00259 } 00260 00261 /********************************************************************************************* 00262 00263 > ChangeCode NodeCompound::OnChildChange(ObjChangeParam* pParam) 00264 00265 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00266 Created: 11/5/99 00267 Purpose: Processes child change messages 00268 Note: 00269 SeeAlso: 00270 00271 **********************************************************************************************/ 00272 ChangeCode NodeCompound::OnChildChange(ObjChangeParam* pParam) 00273 { 00274 if (IsNodeHidden()) 00275 return CC_OK; 00276 00277 ERROR2IF(pParam == NULL,CC_FAIL,"pParam == NULL"); 00278 00279 BOOL bRegen = TRUE; 00280 BOOL bCache = FALSE; 00281 00282 // Node * pChild = NULL; 00283 00284 // Node * pThis = this; 00285 00286 // Node * pNextChild = NULL; 00287 00288 UndoableOperation* pOp = NULL; 00289 if (pParam->GetOpPointer()) 00290 { 00291 if (pParam->GetOpPointer()->IsKindOf(CC_RUNTIME_CLASS(UndoableOperation))) 00292 { 00293 pOp = pParam->GetOpPointer(); 00294 } 00295 } 00296 00297 // CCRuntimeClass * pClass = NULL; 00298 00299 // ActionList * pActionList = NULL; 00300 00301 // Action *pAction = NULL; 00302 00303 // BOOL bDelete = FALSE; 00304 // INT32 NumChildrenThatNeedMe = 0; 00305 00306 // the last code failled to give a spread for nodes recently divorced 00307 Spread * pSpread = Document::GetSelectedSpread(); //(Spread *)FindParent(CC_RUNTIME_CLASS(Spread)); 00308 ERROR2IF(pSpread==NULL, CC_FAIL, "Can't find selected spread"); 00309 00310 List TextNodeList; 00311 NodeListItem * pItem = NULL; 00312 00313 DocRect Bounds = BoundingRectangle; 00314 00315 BlobManager* BlobMgr = GetApplication()->GetBlobManager(); 00316 INT32 BlobSize = 0; 00317 00318 if (!pOp && pParam->GetChangeType() == OBJCHANGE_FINISHED && 00319 pParam->GetDirection() == OBJCHANGE_CALLEDBYCHILD && 00320 pParam->GetChangeFlags().RegenerateNode) 00321 { 00322 RegenerateNode(NULL, FALSE, FALSE); 00323 return CC_OK; 00324 } 00325 00326 if (BlobMgr) 00327 { 00328 BlobSize = BlobMgr->GetBlobSize(); 00329 } 00330 00331 if (pParam->GetChangeType() == OBJCHANGE_STARTING) 00332 { 00333 00334 } 00335 else if (pParam->GetChangeType() == OBJCHANGE_FINISHED) 00336 { 00337 if (pParam->GetChangeFlags().DeleteNode) 00338 { 00339 TRACEUSER( "DavidM", _T("Delete node\n")); 00340 } 00341 00342 if (pOp != NULL) 00343 { 00344 // Ok! Tell all my children to regenerate (in some cases !) 00345 00346 // check for ops which we do nothing with 00347 if (pOp->IsKindOf(CC_RUNTIME_CLASS(TransOperation)) && 00348 !pOp->IS_KIND_OF(OpMovePathPoint)) 00349 { 00350 // ok, we have a transform operation 00351 TRACEUSER( "DavidM", _T("Transform operation!")); 00352 00353 if (((TransOperation *)pOp)->GetCurrentMatrix().IsTranslation()) 00354 { 00355 // find out if the selected object is a child of myself 00356 Range Sel(*(GetApplication()->FindSelection())); 00357 00358 Node * pNode = Sel.FindFirst(FALSE); 00359 00360 bRegen = TRUE; 00361 00362 while (pNode && bRegen) 00363 { 00364 if (pNode->FindParent()) 00365 { 00366 if (pNode->FindParent()->ShouldITransformWithChildren()) 00367 { 00368 bRegen = FALSE; 00369 } 00370 } 00371 00372 pNode = Sel.FindNext(pNode, FALSE); 00373 } 00374 } 00375 else 00376 { 00377 // re-format all text nodes under me 00378 ReleaseCached(); 00379 pOp->DoInvalidateRegion(pSpread, BoundingRectangle); 00380 00381 BevelTools::GetAllNodesUnderNode(this, &TextNodeList, 00382 CC_RUNTIME_CLASS(TextStory)); 00383 00384 pItem = (NodeListItem *)TextNodeList.GetHead(); 00385 00386 while (pItem) 00387 { 00388 if (pItem->pNode) 00389 { 00390 PrePostTextAction::DoFormatStory(pOp, (TextStory *) pItem->pNode, TRUE); 00391 } 00392 00393 pItem = (NodeListItem *)TextNodeList.GetNext(pItem); 00394 } 00395 00396 TextNodeList.DeleteAll(); 00397 00398 bRegen = TRUE; 00399 bCache = FALSE; 00400 } 00401 } 00402 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpApplyAttrib))) 00403 { 00404 // has there been a change which causes a geometry change ? 00405 // if so, we need to regen 00406 CCRuntimeClass * pClass = ((OpApplyAttrib *)pOp)->GetValueChangeType(); 00407 00408 if (pClass) 00409 { 00410 if (pClass->IsKindOf(CC_RUNTIME_CLASS(AttrTxtBase)) || 00411 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrBevelIndent)) || 00412 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrTranspFillGeometry)) || 00413 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrLineWidth)) || 00414 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeColour)) || 00415 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrStartCap)) || 00416 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrStartArrow)) || 00417 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrDashPattern)) || 00418 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrEndArrow)) || 00419 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrJoinType)) || 00420 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeColourChange)) || 00421 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeTranspChange)) || 00422 pClass->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeTranspTypeChange)) 00423 ) 00424 { 00425 bRegen = TRUE; 00426 } 00427 else 00428 { 00429 bRegen = FALSE; 00430 00431 } 00432 } 00433 } 00434 // this operation is called for changes in fills (e.g. dragging a linear fill blob, 00435 // and then dropping it 00436 // we need to stop regeneration for normal fills, but regen for transparency fills 00437 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpReplaceAttributes))) 00438 { 00439 // find out the op name 00440 String_256 OpName; 00441 00442 // don't do colour fills, but do transparent fills 00443 NodeAttribute * pAttr = ((OpReplaceAttributes *)pOp)->GetAttribute(); 00444 00445 if (pAttr) 00446 { 00447 if (pAttr->IsAFillAttr()) 00448 { 00449 bRegen = FALSE; 00450 } 00451 00452 if (pAttr->IsATranspFill()) 00453 { 00454 bRegen = TRUE; 00455 } 00456 00457 } 00458 } 00459 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpDelete))) 00460 { 00461 bRegen = FALSE; 00462 } 00463 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpCopy))) 00464 { 00465 bRegen = FALSE; 00466 } 00467 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpCut))) 00468 { 00469 bRegen = FALSE; 00470 } 00471 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpPaste))) 00472 { 00473 bRegen = FALSE; 00474 } 00475 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpTextFormat))) 00476 { 00477 // indicates a change in the text (e.g. the user has typed in) 00478 // find out if my children have all disappeared 00479 // invalidate and hide me 00480 Bounds.lo.x = BoundingRectangle.lo.x - BlobSize; 00481 Bounds.lo.y = BoundingRectangle.lo.y - BlobSize; 00482 Bounds.hi.x = BoundingRectangle.hi.x + BlobSize; 00483 Bounds.hi.y = BoundingRectangle.hi.y + BlobSize; 00484 00485 ReleaseCached(); 00486 pOp->DoInvalidateRegion(pSpread, Bounds); 00487 00488 // regen if we've still got a valid interior 00489 if (GetInsideBoundingRect().IsEmpty()) 00490 { 00491 bRegen = FALSE; 00492 } 00493 else 00494 { 00495 bRegen = TRUE; 00496 } 00497 00498 bCache = TRUE; 00499 } 00500 else if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpDeleteTextStory))) 00501 { 00502 // indicates that a text story has been deleted - so if my inside 00503 // bounding rect is empty then hide me 00504 if (GetInsideBoundingRect().IsEmpty()) 00505 { 00506 // hide me ! 00507 pOp->DoHideNode(this, TRUE, NULL, TRUE); 00508 bRegen = FALSE; 00509 } 00510 } 00511 else 00512 { 00513 // regen for all other ops 00514 bRegen = TRUE; 00515 } 00516 00517 if (bRegen) 00518 { 00519 // Document * pDoc = Document::GetCurrent(); 00520 00521 pOp->DoInvalidateRegion(pSpread, Bounds); // Invalidate original bounds 00522 00523 BOOL bDidRegen = RegenerateNode(pOp, bCache, FALSE); // ForceRedraw is called internally by RegenerateNode... 00524 00525 if (bDidRegen) 00526 { 00527 ReleaseCached(); 00528 pOp->DoInvalidateRegion(pSpread, GetBoundingRect()); 00529 } 00530 } 00531 } 00532 else 00533 { 00534 // were being called by with a pOp of NULL (i.e. the change is occuring 00535 // in a none undoable way) 00536 00537 // NOTE: we need to regenerate here as well, because we will be called with 00538 // a pOp of NULL when being called through OpRepeatApplyAttribToSelected .... 00539 00540 // Document * pDoc = Document::GetCurrent(); 00541 00542 RegenerateNode(NULL, bCache, FALSE); // ForceRedraw is called internally by RegenerateNode... 00543 00544 // we should also probably check whether it really is OpRepeatApplyAttribToSelected 00545 // that is causing this block of code to execute (BUT, there is no way of doing this!) 00546 } 00547 } 00548 00549 // exit (bearing in mind this has probably been called by my inherited classes) 00550 return NodeRenderableInk::OnChildChange(pParam); 00551 } 00552 00553 /********************************************************************************************* 00554 00555 > BOOL NodeCompound::RegenChildren() 00556 00557 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00558 Created: 11/5/99 00559 Purpose: Calls all the regenerate functions on all children (bottom to top) 00560 Note: 00561 SeeAlso: 00562 00563 **********************************************************************************************/ 00564 /* 00565 BOOL NodeCompound::RegenChildren(UndoableOperation * pOp) 00566 { 00567 // runs through all children doing a regeneration 00568 RegenerateNode(pOp); 00569 00570 return TRUE; 00571 } 00572 */ 00573 00574 /********************************************************************************************* 00575 00576 > BOOL NodeCompound::RegenerateNode(Node * pNode, UndoableOperation * pOp) 00577 00578 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00579 Created: 11/5/99 00580 Purpose: Recursive function to regenerate all nodes 00581 Note: 00582 SeeAlso: 00583 00584 **********************************************************************************************/ 00585 /* 00586 BOOL NodeCompound::RegenerateNode(Node * pNode, UndoableOperation * pOp) 00587 { 00588 Node * pChildNode = pNode->FindFirstChild(); 00589 00590 while (pChildNode) 00591 { 00592 if (!RegenerateNode(pChildNode, pOp)) 00593 return FALSE; 00594 00595 pChildNode = pChildNode->FindNext(); 00596 } 00597 00598 return pNode->RegenerateNode(pOp); 00599 } 00600 */ 00601 00602 00603 00604 /******************************************************************************************** 00605 00606 > void NodeCompound::SetSelected(BOOL Status) 00607 00608 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00609 Created: 17/07/2000 00610 Inputs: Status whether we should become selected or deselected. 00611 00612 Outputs: If (Status) then all children are selected. 00613 00614 Purpose: Selects this node. 00615 Note that in most cases you'll want to call Select() or DeSelect(), which 00616 are virtual methods in NodeRenderable. 00617 00618 This override of Node::SetSelected() contains special case code for the 00619 usual suspects - shadows, bevels and contours - which sometimes behave like 00620 groups, but try to fool the user into thinking they aren't. Any attempt to 00621 select NodeBevelController or its sisters of murphy will result in their 00622 *children* being selected instead. 00623 00624 It's generally better to use Ranges with PromoteToParent to do rendering 00625 and similar with these nodes - eg to iterate over the selection, don't step 00626 through the tree, querying each node - use a SelRange instead. It should 00627 be quicker, and you can choose to have controller nodes automatically 00628 included. 00629 00630 ********************************************************************************************/ 00631 void NodeCompound::SetSelected(BOOL Status) 00632 { 00633 // normal nodes get a normal set-selected. 00634 if (PromoteHitTestOnChildrenToMe() || !Status) 00635 Node::SetSelected(Status); 00636 00637 // contour, bevel & shadow controller nodes instead 00638 // select all of their ink-children (arbitrary). 00639 // NOTE - doesn't happen if Status is FALSE. 00640 else 00641 { 00642 Node* pKid = FindFirstChild(); 00643 while (pKid != NULL) 00644 { 00645 if (pKid->IsAnObject()) 00646 ((NodeRenderableInk*)pKid)->SetSelected(Status); 00647 00648 pKid = pKid->FindNext(); 00649 } 00650 } 00651 } 00652 00653 // Karim 17/07/2000 - I left these in for a while in case I needed to implement them within 00654 // this class. It seems like I don't, so they should probably be removed at some point. 00655 // This will cause a large rebuild due to their declarations in nodecomp.h . 00656 // Simon 9/8/2000 - The controllers (bev/shadow/contour) never want to be drawn so dont try it matey 00657 void NodeCompound::Select(BOOL ReDraw) 00658 { 00659 NodeRenderableInk::Select(ReDraw && PromoteHitTestOnChildrenToMe()); 00660 } 00661 00662 void NodeCompound::DeSelect(BOOL ReDraw, BOOL bDeselectChildren) 00663 { 00664 NodeRenderableInk::DeSelect(ReDraw && PromoteHitTestOnChildrenToMe(), bDeselectChildren); 00665 } 00666 00667 00668 00669 /******************************************************************************************** 00670 00671 > virtual DocRect NodeCompound::GetInsideBoundingRect() 00672 00673 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00674 Created: 21/6/99 00675 Inputs: 00676 Purpose: Gets the bounding rectangle of all nodes under me, except for the 'needs 00677 parent' nodes 00678 SeeAlso: 00679 00680 ********************************************************************************************/ 00681 DocRect NodeCompound::GetInsideBoundingRect() 00682 { 00683 Node * pNode = FindFirstChild(); 00684 00685 DocRect dr; 00686 00687 while (pNode) 00688 { 00689 if (pNode->IsAnObject()) 00690 { 00691 if (!pNode->NeedsParent(NULL)) 00692 { 00693 dr = dr.Union(((NodeRenderableInk *)pNode)->GetBoundingRect(FALSE, FALSE)); 00694 } 00695 } 00696 00697 pNode = pNode->FindNext(); 00698 } 00699 00700 return dr; 00701 } 00702 00703 /******************************************************************************************** 00704 00705 > void NodeCompound::PreInformParentsOfRegenerate() 00706 00707 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00708 Created: 6/9/99 00709 Inputs: None 00710 Purpose: Informs all parents of a regeneration of the node 00711 Notes: Call after the RegenerateNode function in each compound node 00712 SeeAlso: 00713 00714 ********************************************************************************************/ 00715 void NodeCompound::PreInformParentsOfRegenerate() 00716 { 00717 ObjChangeFlags flgs; 00718 flgs.RegenerateNode = TRUE; 00719 00720 ObjChangeParam OP(OBJCHANGE_STARTING, flgs, this, NULL, OBJCHANGE_CALLEDBYCHILD); 00721 00722 Node * pParent = FindParent(); 00723 00724 while (pParent) 00725 { 00726 pParent->OnChildChange(&OP); 00727 00728 pParent = pParent->FindParent(); 00729 } 00730 00731 return; 00732 } 00733 00734 /******************************************************************************************** 00735 00736 > virtual void NodeCompound::PostInformParentsOfRegenerate() 00737 00738 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00739 Created: 6/9/99 00740 Inputs: None 00741 Purpose: Informs all parents of a regeneration of the node 00742 Notes: Call after the RegenerateNode function in each compound node 00743 SeeAlso: 00744 00745 ********************************************************************************************/ 00746 void NodeCompound::PostInformParentsOfRegenerate() 00747 { 00748 ObjChangeFlags flgs; 00749 flgs.RegenerateNode = TRUE; 00750 00751 ObjChangeParam OP(OBJCHANGE_FINISHED, flgs, this, NULL, OBJCHANGE_CALLEDBYCHILD); 00752 00753 Node * pParent = FindParent(); 00754 00755 while (pParent) 00756 { 00757 if (pParent->IsAnObject()) 00758 { 00759 pParent->OnChildChange(&OP); 00760 } 00761 00762 pParent = pParent->FindParent(); 00763 } 00764 00765 return; 00766 } 00767 00768 /******************************************************************************************** 00769 00770 > NodeCompound * NodeCompound::FindAssociatedBlendNode(BlendNodeParam * pParam) 00771 00772 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00773 Created: 5/3/2000 00774 Inputs: The blend node param (see blender & blendatt.h) 00775 Returns: The node compound that has been found 00776 Purpose: Gets the associated compound node I am to blend to, in the end blend path 00777 structure in the blend node param 00778 NULL if non found 00779 Notes: Only applies to blends 00780 Use in conjunction with overrided Blend functions in derived classes 00781 SeeAlso: 00782 00783 ********************************************************************************************/ 00784 NodeCompound * NodeCompound::FindAssociatedBlendNode(BlendNodeParam * pParam) 00785 { 00786 // count how many parents I have 00787 Node * pParent = FindParent(); 00788 00789 UINT32 NumParents = 0; 00790 UINT32 NumSameNodesAbove = 0; 00791 00792 while (pParent) 00793 { 00794 if (pParent->GetRuntimeClass() == this->GetRuntimeClass()) 00795 { 00796 NumSameNodesAbove++; 00797 } 00798 00799 NumParents ++; 00800 pParent = pParent->FindParent(); 00801 } 00802 00803 UINT32 NumSameNodesBelow = 0; 00804 00805 Node * pChild = FindFirstChild(CC_RUNTIME_CLASS(NodeCompound)); 00806 00807 while (pChild) 00808 { 00809 if (pChild->GetRuntimeClass() == this->GetRuntimeClass()) 00810 { 00811 NumSameNodesBelow ++; 00812 } 00813 00814 pChild = pChild->FindFirstChild(CC_RUNTIME_CLASS(NodeCompound)); 00815 } 00816 00817 // thus deduce how many similar nodes to myself are in the tree (including myself) 00818 UINT32 NumSameNodesInStartTree = NumSameNodesAbove + NumSameNodesBelow + 1; 00819 00820 // ok, lets search the end node for similar nodes 00821 Node * pEndNode = pParam->GetEndBlendPath()->GetBlendNode(); 00822 00823 // if the end node isn't a compound node, then I can't find anything 00824 if (!pEndNode->IsCompoundClass()) 00825 return NULL; 00826 00827 // find the node with the closest number of parents to mine 00828 Node * pEndNodeStep = pEndNode; 00829 00830 // build a list of all similar nodes in the end tree 00831 List EndNodeList; 00832 00833 NodeListItem * pItem = NULL; 00834 00835 while (pEndNodeStep) 00836 { 00837 if (pEndNodeStep->GetRuntimeClass() == this->GetRuntimeClass()) 00838 { 00839 pItem = new NodeListItem(pEndNodeStep); 00840 ERRORIF(pItem == NULL, _R(IDE_NOMORE_MEMORY), NULL); 00841 00842 EndNodeList.AddTail(pItem); 00843 } 00844 00845 pEndNodeStep = pEndNodeStep->FindFirstChild(CC_RUNTIME_CLASS(NodeCompound)); 00846 } 00847 00848 // ok, now we have a list of nodes we have found in the end node list, 00849 // and we know how many exist above me in the start node list 00850 // therefore, pick a node in the list to match to 00851 if (EndNodeList.IsEmpty()) 00852 { 00853 // can't match to any ! 00854 return NULL; 00855 } 00856 00857 NodeCompound * pRetnNode = NULL; 00858 00859 if (NumSameNodesInStartTree == EndNodeList.GetCount()) 00860 { 00861 // 1 to 1 relationship therefore easy ! 00862 UINT32 Count = 0; 00863 00864 pItem = (NodeListItem *)EndNodeList.GetHead(); 00865 00866 while (pItem) 00867 { 00868 if (Count == NumSameNodesAbove) 00869 { 00870 // get the node to return 00871 pRetnNode = (NodeCompound *)pItem->pNode; 00872 00873 EndNodeList.DeleteAll(); 00874 00875 return pRetnNode; 00876 } 00877 } 00878 00879 ERROR3("Number of nodes in list isn't the same as the number of nodes in start tree"); 00880 EndNodeList.DeleteAll(); 00881 return NULL; 00882 } 00883 00884 EndNodeList.DeleteAll(); 00885 00886 // many to one and one to many relations are not implemented yet 00887 return NULL; 00888 } 00889 00890 /******************************************************************************************** 00891 00892 > virtual NodeRenderableInk * NodeCompound::GetNodeToBlend() 00893 00894 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 00895 Created: 6/9/99 00896 Inputs: None 00897 Purpose: Gets the blend node inside of this compound node 00898 Notes: Only applies to blends 00899 SeeAlso: 00900 00901 ********************************************************************************************/ 00902 NodeRenderableInk * NodeCompound::GetNodeToBlend() 00903 { 00904 Node * pChild = FindFirstChild(); 00905 00906 while (pChild) 00907 { 00908 if (pChild->IsAnObject()) 00909 { 00910 if (!pChild->NeedsParent(NULL)) 00911 { 00912 // we've found it 00913 if (pChild->IsCompoundClass()) 00914 { 00915 return ((NodeCompound*)pChild)->GetNodeToBlend(); 00916 } 00917 00918 return (NodeRenderableInk*)pChild; 00919 } 00920 } 00921 00922 pChild = pChild->FindNext(); 00923 } 00924 00925 // failure ! 00926 return NULL; 00927 } 00928 00929 00930 00931 /********************************************************************************************* 00932 00933 > BOOL NodeCompound::AllocBlendConsList (ListType listType) 00934 00935 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 00936 Created: 22/6/2000 00937 Inputs: The type of list to allocate 00938 Outputs: 00939 Returns: - 00940 00941 Purpose: Allocates the relevant list 00942 00943 Errors: If the blendConstructedCompoundChildren list has already been allocated. 00944 00945 **********************************************************************************************/ 00946 00947 BOOL NodeCompound::AllocBlendConsList (ListType listType) 00948 { 00949 #ifdef _DEBUG 00950 List* accessList = InitListPtr (listType); 00951 if (accessList != NULL) 00952 { 00953 ERROR3IF (accessList->GetCount () > 0, "Trying to re-allocate a list that still has items in it!"); 00954 } 00955 #endif 00956 00957 switch (listType) 00958 { 00959 case LT_BECOMEA_SHADOWSLIST: 00960 blndConsBecomeAShadows = new List; 00961 break; 00962 case LT_BECOMEA_BEVELSLIST: 00963 blndConsBecomeABevels = new List; 00964 break; 00965 case LT_BECOMEA_CONTOURSLIST: 00966 blndConsBecomeAContours = new List; 00967 break; 00968 default: 00969 ERROR3 ("NodeCompound::AllocBlendConsList - You wan't what??? !!!"); 00970 return (TRUE); 00971 } 00972 00973 return (TRUE); 00974 } 00975 00976 /********************************************************************************************* 00977 00978 > BOOL NodeCompound::AllocatedBlendConsList (ListType listType) 00979 00980 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 00981 Created: 22/6/2000 00982 Inputs: The type of list to check 00983 Outputs: 00984 Returns: TRUE if list is not empty, FALSE otherwise 00985 00986 Purpose: Determins whether blending has generated intermediate compound nodes 00987 00988 Errors: - 00989 00990 **********************************************************************************************/ 00991 00992 BOOL NodeCompound::AllocatedBlendConsList (ListType listType) 00993 { 00994 List* accessList = InitListPtr (listType); 00995 00996 if (accessList == NULL) 00997 { 00998 return (FALSE); 00999 } 01000 else 01001 { 01002 if (accessList->GetCount () > 0) 01003 { 01004 return (TRUE); 01005 } 01006 } 01007 01008 return (FALSE); 01009 } 01010 01011 /********************************************************************************************* 01012 01013 > BOOL NodeCompound::KillBlendConsList (ListType listType, BOOL killAll) 01014 01015 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 01016 Created: 22/6/2000 01017 Inputs: The type of list that we are killing 01018 killAll - do we kill all items in the list, or just the ones that are a part 01019 of the current document? 01020 Outputs: 01021 Returns: TRUE if success, FALSE otherwise 01022 01023 Purpose: Clears out the list of nodes that were generated when blending compound nodes. 01024 01025 Errors: ERROR3IF the list == NULL 01026 01027 **********************************************************************************************/ 01028 01029 BOOL NodeCompound::KillBlendConsList (ListType listType, BOOL killAll, BOOL isPrinting) 01030 { 01031 List* accessList = InitListPtr (listType); 01032 01033 ERROR3IF(accessList == NULL, "KillBlendConsList (): Trying to delete an empty list! - fruitless function call!"); 01034 01035 NodeListItemWithDocPtr* pCurrent = (NodeListItemWithDocPtr*) accessList->GetHead (); 01036 01037 if (!killAll) 01038 { 01039 if (!isPrinting) 01040 { 01041 // user has closed a document - clear out any data that was required for rendering 01042 01043 Document* pCurrentDoc = Document::GetCurrent (); 01044 01045 ERROR3IF (pCurrentDoc == NULL, "No current document!"); 01046 01047 while (pCurrent) 01048 { 01049 if (pCurrent->pOwner == pCurrentDoc) 01050 { 01051 NodeListItemWithDocPtr* pNext = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01052 01053 NodeListItemWithDocPtr* markedForDelete = (NodeListItemWithDocPtr*) accessList->RemoveItem (pCurrent); 01054 01055 markedForDelete->pNode->CascadeDelete (); 01056 delete (markedForDelete->pNode); 01057 01058 pCurrent = pNext; 01059 } 01060 else 01061 { 01062 // the node is NOT linked to the current document - so we can't delete it .... 01063 01064 pCurrent = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01065 } 01066 } 01067 } 01068 else 01069 { 01070 // were printing .... 01071 01072 while (pCurrent) 01073 { 01074 if (pCurrent->isForPrinting) 01075 { 01076 NodeListItemWithDocPtr* pNext = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01077 01078 NodeListItemWithDocPtr* markedForDelete = (NodeListItemWithDocPtr*) accessList->RemoveItem (pCurrent); 01079 01080 markedForDelete->pNode->CascadeDelete (); 01081 delete (markedForDelete->pNode); 01082 01083 pCurrent = pNext; 01084 } 01085 else 01086 { 01087 // the node was not generated for printing - so we can't delete it .... 01088 01089 pCurrent = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01090 } 01091 } 01092 } 01093 } 01094 else 01095 { 01096 // camelot is dying - clear out all data .... 01097 01098 while (pCurrent) 01099 { 01100 pCurrent->pNode->CascadeDelete (); 01101 delete (pCurrent->pNode); 01102 01103 pCurrent = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01104 } 01105 01106 accessList->DeleteAll (); 01107 delete (accessList); 01108 01109 accessList = NULL; 01110 01111 switch (listType) 01112 { 01113 case LT_BECOMEA_SHADOWSLIST: 01114 blndConsBecomeAShadows = NULL; 01115 break; 01116 case LT_BECOMEA_BEVELSLIST: 01117 blndConsBecomeABevels = NULL; 01118 break; 01119 case LT_BECOMEA_CONTOURSLIST: 01120 blndConsBecomeAContours = NULL; 01121 break; 01122 default: 01123 ERROR3 ("NodeCompound::AllocBlendConsList - You wan't what??? !!!"); 01124 return (FALSE); 01125 } 01126 } 01127 01128 return (TRUE); 01129 } 01130 01131 /********************************************************************************************* 01132 01133 > BOOL NodeCompound::KillBlendConsListItem (ListType listType, NodeBlend* nodeBlend) 01134 01135 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 01136 Created: 22/6/2000 01137 Inputs: The type of list that we are killing, the blend that the item is associated with 01138 Outputs: 01139 Returns: TRUE if success, FALSE otherwise 01140 01141 Purpose: Clears out the list of nodes that were generated when blending compound nodes 01142 which are associated (i.e. created) with the supplied NodeBlend 01143 01144 NOTE: The associated blend node is set by calling NodeCompound::SetBlenderNode () 01145 01146 Errors: ERROR3IF the list == NULL 01147 01148 **********************************************************************************************/ 01149 01150 BOOL NodeCompound::KillBlendConsListItem (ListType listType, NodeBlend* nodeBlend) 01151 { 01152 List* accessList = InitListPtr (listType); 01153 01154 ERROR3IF(accessList == NULL, "KillBlendConsList (): Trying to delete an empty list! - fruitless function call!"); 01155 01156 NodeListItemWithDocPtr* pCurrent = (NodeListItemWithDocPtr*) accessList->GetHead (); 01157 01158 while (pCurrent) 01159 { 01160 if (pCurrent->pNode->IsCompoundClass()) 01161 { 01162 NodeCompound* ptrGroup = (NodeCompound*) pCurrent->pNode; 01163 NodeBlend* ptrBlender = (NodeBlend*) ptrGroup->GetBlenderNode(); 01164 01165 if (ptrBlender == nodeBlend) 01166 { 01167 NodeListItemWithDocPtr* pNext = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01168 01169 NodeListItemWithDocPtr* markedForDelete = (NodeListItemWithDocPtr*) accessList->RemoveItem (pCurrent); 01170 01171 markedForDelete->pNode->CascadeDelete (); 01172 delete (markedForDelete->pNode); 01173 01174 pCurrent = pNext; 01175 } 01176 else 01177 { 01178 pCurrent = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01179 } 01180 } 01181 else 01182 { 01183 pCurrent = (NodeListItemWithDocPtr*) accessList->GetNext (pCurrent); 01184 } 01185 } 01186 01187 return (TRUE); 01188 } 01189 01190 /********************************************************************************************* 01191 01192 > BOOL NodeCompound::KillAllBlendBecomeAConsLists (BOOL killAll = FALSE) 01193 01194 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 01195 Created: 29/6/2000 01196 Inputs: killAll - do we kill all items in the list, or just the ones that are a part 01197 of the current document? 01198 Outputs: 01199 Returns: TRUE if success, FALSE otherwise 01200 01201 Purpose: Clears out the list of nodes that were generated when blending compound nodes 01202 (that were instructed to DOBECOMEA). 01203 01204 Errors: 01205 01206 **********************************************************************************************/ 01207 01208 BOOL NodeCompound::KillAllBlendBecomeAConsLists (BOOL killAll /*= FALSE*/, BOOL isPrinting /*= FALSE*/) 01209 { 01210 if (NodeCompound::AllocatedBlendConsList (LT_BECOMEA_BEVELSLIST)) 01211 { 01212 NodeCompound::KillBlendConsList (LT_BECOMEA_BEVELSLIST, killAll, isPrinting); 01213 } 01214 01215 if (NodeCompound::AllocatedBlendConsList (LT_BECOMEA_CONTOURSLIST)) 01216 { 01217 NodeCompound::KillBlendConsList (LT_BECOMEA_CONTOURSLIST, killAll, isPrinting); 01218 } 01219 01220 if (NodeCompound::AllocatedBlendConsList (LT_BECOMEA_SHADOWSLIST)) 01221 { 01222 NodeCompound::KillBlendConsList (LT_BECOMEA_SHADOWSLIST, killAll, isPrinting); 01223 } 01224 01225 return (TRUE); 01226 } 01227 01228 /********************************************************************************************* 01229 01230 > BOOL NodeCompound::KillAllBlendBecomeAConsListItem () 01231 01232 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 01233 Created: 29/6/2000 01234 Inputs: The blend that the item is associated with 01235 Outputs: 01236 Returns: TRUE if success, FALSE otherwise 01237 01238 Purpose: Clears out the list of nodes (dobecomea) that were generated when blending 01239 compound nodes which are associated (i.e. created) with the supplied NodeBlend 01240 01241 NOTE: The associated blend node is set by calling NodeCompound::SetBlenderNode () 01242 01243 **********************************************************************************************/ 01244 01245 BOOL NodeCompound::KillAllBlendBecomeAConsListItem (NodeBlend* associatedWith) 01246 { 01247 if (NodeCompound::AllocatedBlendConsList (LT_BECOMEA_BEVELSLIST)) 01248 { 01249 TRACEUSER( "ChrisS", _T("Invoking delete all on CALLBACK BEVELS\n") ); 01250 NodeCompound::KillBlendConsListItem (LT_BECOMEA_BEVELSLIST, associatedWith); 01251 } 01252 01253 if (NodeCompound::AllocatedBlendConsList (LT_BECOMEA_CONTOURSLIST)) 01254 { 01255 TRACEUSER ("ChrisS", _T("Invoking delete all on CALLBACK CONTOURS\n") ); 01256 NodeCompound::KillBlendConsListItem (LT_BECOMEA_CONTOURSLIST, associatedWith); 01257 } 01258 01259 // shadows MUST be deleted last (cause they could be shadowing a bevel, and if we 01260 // calls cascade delete on the shadow then this also deletes the bevel (leaving the 01261 // bevels list bevel vaped - but the list reference to it still valid). 01262 01263 if (NodeCompound::AllocatedBlendConsList (LT_BECOMEA_SHADOWSLIST)) 01264 { 01265 TRACEUSER ("ChrisS", _T("Invoking delete all on CALLBACK SHADOWS\n") ); 01266 NodeCompound::KillBlendConsListItem (LT_BECOMEA_SHADOWSLIST, associatedWith); 01267 } 01268 01269 return (TRUE); 01270 } 01271 01272 /********************************************************************************************* 01273 01274 > BOOL NodeCompound::BlendConsListInsert (ListType listType, Node* insertNode) 01275 01276 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 01277 Created: 22/6/2000 01278 Inputs: The type of list to insert into, and the node to be inserted 01279 Outputs: 01280 Returns: TRUE 01281 01282 Purpose: Inserts a blends intermediate node into our list. This is necessary so that 01283 they may be deleted at the correct time. 01284 01285 Errors: ERROR3IF insertItem == NULL, ERROR3IF list == NULL 01286 01287 **********************************************************************************************/ 01288 01289 BOOL NodeCompound::BlendConsListInsert (ListType listType, Node* insertNode) 01290 { 01291 ERROR3IF(insertNode == NULL, "BlendConsListInsert (): Trying to insert a NULL item into a list!"); 01292 01293 List* accessList = InitListPtr (listType); 01294 01295 ERROR3IF(accessList == NULL, "BlendConsListInsert (): Trying to insert item into a list which is NULL!"); 01296 01297 NodeListItemWithDocPtr* pInsert = new NodeListItemWithDocPtr (); 01298 01299 if (pInsert) // and insert into the paths list .... 01300 { 01301 pInsert->pNode = insertNode; 01302 pInsert->pOwner = Document::GetCurrent (); 01303 pInsert->isForPrinting = isForPrinting; 01304 accessList->AddHead (pInsert); 01305 01306 TRACEUSER ("ChrisS", _T("Blend constructed list just inserted a node\n") ); 01307 } 01308 01309 return (TRUE); 01310 } 01311 01312 01313 01314 01315 /********************************************************************************************* 01316 01317 > List* NodeCompound::InitListPtr (ListType listType) 01318 01319 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 01320 Created: 22/6/2000 01321 Inputs: The type of list to retrieve 01322 Outputs: 01323 Returns: Ptr to the relevant list 01324 01325 Purpose: Returns a ptr to the relevant list of nodes (that when allocated when blending). 01326 01327 Errors: - 01328 01329 **********************************************************************************************/ 01330 01331 List* NodeCompound::InitListPtr (ListType listType) 01332 { 01333 List* list = NULL; 01334 01335 switch (listType) 01336 { 01337 case LT_BECOMEA_SHADOWSLIST: 01338 list = blndConsBecomeAShadows; 01339 break; 01340 case LT_BECOMEA_BEVELSLIST: 01341 list = blndConsBecomeABevels; 01342 break; 01343 case LT_BECOMEA_CONTOURSLIST: 01344 list = blndConsBecomeAContours; 01345 break; 01346 default: 01347 list = NULL; 01348 } 01349 01350 return (list); 01351 } 01352 01353 01354 01355 01356 /******************************************************************************************** 01357 01358 > virtual INT32 NodeCompound::EstimateNodeComplexity(OpParam* details) 01359 01360 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 01361 Created: 6/09/2000 01362 Inputs: details any data that should be used for the calculation 01363 Outputs: - 01364 Returns: an estimate of the nodes complexity 01365 Purpose: This function estimates a complexity value for the node. The complexity 01366 value is based upon the total length of all paths in the node. 01367 See Also: OpBlendNodes::DeterminBlendObjectsProcessorHit () 01368 01369 ********************************************************************************************/ 01370 01371 INT32 NodeCompound::EstimateNodeComplexity(OpParam* details) 01372 { 01373 INT32 total = 0; 01374 01375 // Call DoBecomeA on all the group's children 01376 Node* Current = FindFirstChild(); 01377 Node* Next; 01378 01379 while (Current != NULL) 01380 { 01381 Next = Current->FindNext(); 01382 total += Current->EstimateNodeComplexity (details); 01383 Current = Next; 01384 } 01385 01386 return (total); 01387 } 01388 01389 01390 01391 01392 /******************************************************************************************** 01393 01394 > virtual BOOL NodeCompound::HasVisibleChildren() const 01395 01396 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01397 Created: 01/04/2005 01398 Inputs: - 01399 Outputs: - 01400 Returns: TRUE if this compound is empty and can thus be deleted or hidden without 01401 the user seeing any difference 01402 Purpose: Determine whether this compound node is really doing anything useful 01403 01404 ********************************************************************************************/ 01405 01406 BOOL NodeCompound::HasVisibleChildren() const 01407 { 01408 if (!this->IsRenderable()) 01409 return FALSE; 01410 01411 Node* pChild = FindFirstChild(); 01412 while (pChild) 01413 { 01414 if (pChild->IsAnObject() && pChild->IsRenderable()) 01415 { 01416 if (!pChild->NeedsParent((Node*)this)) 01417 return TRUE; 01418 } 01419 01420 pChild = pChild->FindNext(); 01421 } 01422 01423 return FALSE; 01424 } 01425 01426 01427 01428 01429 /******************************************************************************************** 01430 01431 > DocRect NodeCompound::GetExtendTargetBounds(const ExtendParams& ExtParams) 01432 01433 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01434 Created: 02/06/2000 01435 Inputs: ExtParams const ref to an ExtendParams class describing the extension. 01436 Outputs: 01437 Returns: The DocRect to treat as the bounding rect of this node when extending. 01438 Purpose: Return a DocRect which contains the bounds of this node as defined and 01439 required by the Extending mechanism. 01440 01441 We treat x- and y- directions separately, and we always return our true 01442 bounds, unless we're extending in a direction, in which case we return the 01443 bounds of our extend control points, which currently means the union of the 01444 ExtendTargetBounds of our children. 01445 01446 Notes: Note that we're assuming that we always have kids. No kids => pear-shapey. 01447 01448 See also: SliceHelper::BoundingNodeSize(). 01449 01450 ********************************************************************************************/ 01451 DocRect NodeCompound::GetExtendTargetBounds(const ExtendParams& ExtParams) 01452 { 01453 DocRect drBounds(0, 0, 0, 0); 01454 Node* pKid = FindFirstChild(); 01455 while (pKid != NULL) 01456 { 01457 if (pKid->IsAnObject()) 01458 drBounds = drBounds.Union(((NodeRenderableInk*)pKid)->GetExtendTargetBounds(ExtParams)); 01459 } 01460 01461 return drBounds; 01462 } 01463 01464 01465 01466 01467 /******************************************************************************************** 01468 01469 > virtual String_32& NodeCompound::GetName() 01470 01471 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01472 Created: 29/6/94 01473 Inputs: - 01474 Outputs: - 01475 Returns: The name of the group 01476 Purpose: This routine is used to obtain the name of a group 01477 Errors: - 01478 SeeAlso: - 01479 01480 ********************************************************************************************/ 01481 01482 String_32& NodeCompound::GetName() 01483 { 01484 return CompoundName; 01485 } 01486 01487 /******************************************************************************************** 01488 01489 > virtual void SetName(String_32& Name) 01490 01491 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01492 Created: 29/6/94 01493 Inputs: Name: The new group name 01494 Outputs: - 01495 Returns: - 01496 Purpose: For setting the group's name 01497 Errors: - 01498 SeeAlso: - 01499 01500 ********************************************************************************************/ 01501 01502 void NodeCompound::SetName(String_32& Name) 01503 { 01504 CompoundName = Name; 01505 } 01506 01507 01508 01509 /******************************************************************************************** 01510 01511 > virtual BOOL NodeCompound::AllowOp_AccountForCompound(ObjChangeParam* pParam, 01512 BOOL SetOpPermissionState, 01513 BOOL DoPreTriggerEdit) 01514 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01515 Created: 24/10/2000 01516 Inputs: pParam information about the requested change, eg which Op. 01517 SetOpPermissionState whether flags should be set ready for OnChildChange. 01518 DoPreTriggerEdit if TRUE then NameGallery::PreTriggerEdit is called. 01519 *Must* be TRUE if the calling Op may make any nodes 01520 change their bounds, eg move, line width, cut. 01521 Use TRUE if unsure. 01522 01523 Returns: TRUE if ANY of the objects in the compound node have allowed the op. 01524 01525 Purpose: Overrides Node::AllowOp_AccountForCompound - see definition of that function 01526 for a general explanation. 01527 01528 Controller nodes need to inform all of their other children whenever one 01529 child is queried via AllowOp. This is because unlike a normal group, editing 01530 one child may well affect its siblings, who must be informed of the edit. 01531 01532 See Also: Node::AllowOp, Node::AllowOp_AccountForCompound 01533 01534 Notes: Karim 20/12/2000 01535 Added the OpTextFormat bodge for feathers on bevelled text - sorry! 01536 01537 ********************************************************************************************/ 01538 BOOL NodeCompound::AllowOp_AccountForCompound(ObjChangeParam* pParam, 01539 BOOL SetOpPermissionState, 01540 BOOL DoPreTriggerEdit) 01541 { 01542 BOOL AnyAllowed = FALSE; 01543 01544 Node* pCallingChild = (pParam->GetDirection() == OBJCHANGE_CALLEDBYCHILD) ? 01545 pParam->GetCallingChild() : NULL; 01546 pParam->SetCallingChild(NULL); 01547 01548 ObjChangeFlags Flags = pParam->GetChangeFlags(); 01549 UndoableOperation* pChangeOp = pParam->GetOpPointer(); 01550 01551 if( Flags.Attribute || 01552 Flags.TransformNode || 01553 Flags.RegenerateNode || 01554 ( pChangeOp != NULL 01555 && pChangeOp->IS_KIND_OF( OpTextUndoable ) 01556 ) ) 01557 { 01558 01559 ObjChangeDirection OldDirection = pParam->GetDirection(); 01560 pParam->SetDirection(OBJCHANGE_CALLEDBYPARENT); 01561 Node* pNode = FindFirstChild(); 01562 01563 BOOL InformGeomLinkedAttrs = SetOpPermissionState && 01564 pChangeOp != NULL && 01565 pChangeOp->MayChangeNodeBounds(); 01566 01567 while (pNode != NULL) 01568 { 01569 if (pNode != pCallingChild) 01570 { 01571 if (pNode->IsAnObject()) 01572 AnyAllowed |= pNode->AllowOp(pParam, SetOpPermissionState, DoPreTriggerEdit); 01573 else 01574 { 01575 if (pNode->IsAnAttribute() && ((NodeAttribute*)pNode)->IsLinkedToNodeGeometry()) 01576 if (InformGeomLinkedAttrs) 01577 ((NodeAttribute*)pNode)->LinkedNodeGeometryHasChanged(pChangeOp); 01578 } 01579 } 01580 01581 pNode = pNode->FindNext(); 01582 } 01583 01584 pParam->SetDirection(OldDirection); 01585 } 01586 01587 // if setting flags and any child allowed it, set this permission allowed 01588 if (SetOpPermissionState && AnyAllowed) 01589 SetOpPermission(PERMISSION_ALLOWED); 01590 01591 return AnyAllowed; 01592 } 01593 01594 01595 01596 01597 /******************************************************************************************** 01598 01599 > virtual BOOL NodeCompound::CanBecomeA(BecomeA* pBecomeA) 01600 01601 01602 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01603 Created: 29/4/94 01604 Inputs: InkClass: The class of object 01605 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL). 01606 *pNumObects in undefined on entry 01607 Outputs: - 01608 Returns: TRUE if the node, or any of its children can transmogrify themselves to become 01609 an InkClass object 01610 01611 Purpose: This function is used by the convert to shapes operation. It determines if 01612 the node or any of its children can convert themselves into an InkClass object. 01613 01614 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number 01615 of pClass objects you create. It should NOT contain any additional objects you may produce 01616 such as group objects for containing the pClass object, or attributes. 01617 01618 Also, the entry value of *pNumObjects cannot be assumed to be 0. 01619 01620 Errors: - 01621 01622 ********************************************************************************************/ 01623 01624 BOOL NodeCompound::CanBecomeA(BecomeA* pBecomeA) 01625 { 01626 BOOL bOK=FALSE; 01627 01628 Node* Current = FindFirstChild(); 01629 while (Current != NULL) 01630 { 01631 if (Current->CanBecomeA(pBecomeA)) // Increments count 01632 { 01633 bOK = TRUE; 01634 if (!pBecomeA->IsCounting()) 01635 return TRUE; // Don't want total, so return now 01636 } 01637 01638 Current = Current->FindNext(); 01639 } 01640 01641 return bOK; 01642 } 01643 01644 01645 /******************************************************************************************** 01646 01647 > virtual BOOL NodeCompound::DoBecomeA(BecomeA* pBecomeA) 01648 01649 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (and Markn) 01650 Created: 29/4/94 01651 Inputs: pBecomeA = ptr to a class that contains all the info needed to become a new 01652 type of node. 01653 Outputs: - 01654 Returns: TRUE if the object has been transformed, FALSE if we run out of memory 01655 01656 Purpose: Transforms the object into another type of object. 01657 Note: changed 7/10/94 by MarkN to take the pBecomeA param, so that more data could be passed 01658 to these functions in the future without causing massive rebuilds due to the editing of 01659 node.h 01660 01661 14/6/95 (Markn): This now localises attributes before calling it's children, then factors them out 01662 at the end. This is so that common attrs trickle down to ALL leaf nodes, no matter how deep 01663 they may be. This is important when a child node is a blend, because the action of DoBecomeA() 01664 in the blend's case creates new child attrs for the path it creates, hence making any common 01665 attrs illegal. 01666 Errors: - 01667 SeeAlso: Node::CanBecomeA 01668 01669 ********************************************************************************************/ 01670 01671 BOOL NodeCompound::DoBecomeA(BecomeA* pBecomeA) 01672 { 01673 ERROR2IF(pBecomeA == NULL,FALSE,"NULL BecomeA ptr"); 01674 01675 UndoableOperation* pOp = pBecomeA->GetUndoOp(); 01676 BOOL ok; 01677 01678 if (pBecomeA->GetReason() == BECOMEA_REPLACE) 01679 { 01680 // ERROR2IF(pBecomeA->GetUndoOp() == NULL,FALSE,"Trying to replace a NodeGroup, but pUndoOp == NULL"); 01681 01682 // Make all attrs children of the child nodes 01683 if (pOp) 01684 ok = pOp->DoLocaliseCommonAttributes(this); 01685 else 01686 ok = LocaliseCommonAttributes(); 01687 if (!ok) 01688 return FALSE; 01689 } 01690 01691 // Call DoBecomeA on all the group's children 01692 Node* Current = FindFirstChild(); 01693 Node* Next; 01694 01695 while (Current != NULL) 01696 { 01697 Next = Current->FindNext(); 01698 if(!(Current->DoBecomeA(pBecomeA))) 01699 { 01700 return FALSE; // Out of memory 01701 } 01702 Current = Next; 01703 } 01704 01705 if (pBecomeA->GetReason() == BECOMEA_REPLACE) 01706 { 01707 // ERROR2IF(pBecomeA->GetUndoOp() == NULL,FALSE,"Trying to replace a NodeGroup, but pUndoOp == NULL"); 01708 01709 // Factor out the attrs (needed after a call to DoLocaliseCommonAttributes 01710 if (pOp) 01711 ok = pOp->DoFactorOutCommonChildAttributes(this); 01712 else 01713 ok = FactorOutCommonChildAttributes(); 01714 if (!ok) 01715 return FALSE; 01716 } 01717 01718 return TRUE; 01719 } 01720 01721 01722 01723 /******************************************************************************************** 01724 01725 > virtual NodeGroup* NodeCompound::BecomeAGroup(UndoableOperation* pUndoOp) 01726 01727 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01728 Created: 20/07/2000 01729 01730 Inputs: pUndoOp ptr to an Op to use for all the undoable bits. 01731 01732 Outputs: This node is converted into a group. 01733 01734 Returns: A pointer to the new group node if successful, 01735 NULL otherwise. 01736 01737 Purpose: This method is for the convenience of any compound node descended from 01738 NodeGroup. It 'changes' the node into a group by following these steps: 01739 * Attributes are undoably localised on this node. 01740 * A group node is created. 01741 * All children of this node are undoably moved under the group node. 01742 * The group is undoably inserted into the tree as the next sibling. 01743 * Attributes are undoably factored out on the group node. 01744 * This node is undoably hidden. 01745 01746 Notes: The group's selection state is maintained - if this node is selected now, 01747 then the new group will be selected - although this may not be enough 01748 for some nodes, eg NodeShadowController et al. 01749 01750 Although calling this method on a normal NodeGroup should have no visible 01751 effect, it *is* wasteful of time and memory. So DON'T call this method 01752 on a plain NodeGroup! 01753 01754 Errors: We require a valid Op ptr, so will ERROR3 and return FALSE 01755 if we don't get one (maybe this should be an ERROR2). 01756 01757 ********************************************************************************************/ 01758 NodeGroup* NodeCompound::BecomeAGroup(UndoableOperation* pUndoOp) 01759 { 01760 // we can't do a thing without an Op... 01761 // if (pUndoOp == NULL) 01762 // { 01763 // ERROR3("NodeGroup::BecomeAGroup; NULL Op pointer!"); 01764 // return NULL; 01765 // } 01766 01767 // localise any attributes into our children, to ensure that none of our direct children 01768 // are attributes. we do this because we'll be moving all our children, and directly 01769 // moving attrs is forbidden (see DoMoveNode() for more info). 01770 BOOL ok; 01771 01772 if (pUndoOp) 01773 ok = pUndoOp->DoLocaliseCommonAttributes(this); 01774 else 01775 ok = LocaliseCommonAttributes(FALSE, FALSE, NULL); 01776 01777 // create the new group node for our children. 01778 NodeGroup* pGroup = NULL; 01779 if (ok) 01780 { 01781 ALLOC_WITH_FAIL(pGroup, new NodeGroup, pUndoOp); 01782 ok = (pGroup != NULL); 01783 } 01784 01785 // insert the new group into the tree as our right-sibling. 01786 if (ok) 01787 { 01788 if (pUndoOp) 01789 ok = pUndoOp->DoInsertNewNode(pGroup, this, NEXT, TRUE, FALSE, IsSelected(), FALSE); 01790 else 01791 pGroup->AttachNode(this, NEXT, FALSE, FALSE); 01792 } 01793 01794 // move all our children into the new group. 01795 // some of our children may be non-optimisable attributes, which DoMoveNode() won't move. 01796 // In these cases, we non-undoably put copies of them under the new group node (which is 01797 // undoably inserted anyway, so the non-undoable stuff should be ok). 01798 if (ok) 01799 { 01800 Node* pNextKid = NULL; 01801 Node* pThisKid = FindFirstChild(); 01802 while (ok && pThisKid != NULL) 01803 { 01804 pNextKid = pThisKid->FindNext(); 01805 01806 if (pThisKid->IsAnObject()) 01807 { 01808 if (pUndoOp) 01809 { 01810 CALL_WITH_FAIL(pUndoOp->DoMoveNode(pThisKid, pGroup, LASTCHILD), pUndoOp, ok) 01811 } 01812 else 01813 { 01814 pThisKid->MoveNode(pGroup, LASTCHILD); 01815 } 01816 if (ok && pThisKid->IsSelected()) 01817 pGroup->SetParentOfSelected(TRUE); 01818 } 01819 else if ( pThisKid->IsAnAttribute() && 01820 !((NodeAttribute*)pThisKid)->ShouldBeOptimized() ) 01821 CALL_WITH_FAIL(pThisKid->CopyNode(pGroup, LASTCHILD), pUndoOp, ok) 01822 01823 pThisKid = pNextKid; 01824 } 01825 } 01826 01827 // factor out attributes on the new group - this matches the localise call up top. 01828 if (ok) 01829 { 01830 if (pUndoOp) 01831 ok = pUndoOp->DoFactorOutCommonChildAttributes(pGroup); 01832 else 01833 ok = pGroup->FactorOutCommonChildAttributes(); 01834 } 01835 01836 // invalidate the group's bounding box. 01837 if (ok) pGroup->InvalidateBoundingRect(); 01838 01839 // finally, hide ourself. 01840 if (ok) 01841 { 01842 if (pUndoOp) 01843 ok = pUndoOp->DoHideNode(this, TRUE); 01844 else 01845 { 01846 CascadeDelete(); 01847 delete this; // Scary! 01848 } 01849 } 01850 01851 return ok ? pGroup : NULL; 01852 } 01853 01854 01855 01856 01857 /******************************************************************************************** 01858 01859 > virtual NodeRenderableInk* NodeCompound::GetInkNodeFromController() const 01860 01861 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01862 Created: 16/10/2000 01863 Inputs: - 01864 Outputs: - 01865 Returns: The ink node that is used by bevels, shadows and contours 01866 Purpose: If we had a Controller node inherited class from NodeGroup then this 01867 function really belongs there. But we don't, so this function only 01868 returns anything if your node also returns TRUE to IsAController(). 01869 If so it will return the node that is shadowed, bevelled or contoured. 01870 01871 SeeAlso: 01872 01873 ********************************************************************************************/ 01874 01875 NodeRenderableInk* NodeCompound::GetInkNodeFromController() const 01876 { 01877 return NULL; 01878 } 01879 01880 01881 01882 01883 /******************************************************************************************** 01884 01885 > DocRect NodeCompound::GetChildBoundingRect(BOOL bIncludeAttrs = TRUE) 01886 01887 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01888 Created: 21/09/2004 01889 Returns: The bounding box of the children of the live effect 01890 Purpose: Get the bounding rect of the children without updating BOundingRectangle 01891 or IsBOundingRectValid for this node... 01892 01893 ********************************************************************************************/ 01894 01895 DocRect NodeCompound::GetChildBoundingRect(BOOL bIncludeAttrs) 01896 { 01897 // just set it to be an empty rectangle 01898 DocRect BoundRect(0,0,0,0); 01899 01900 Node* pNode = FindFirstChild(); 01901 while (pNode!=NULL) 01902 { 01903 // Add in the bounding rect of this node with all the others 01904 if (pNode->IsBounded()) 01905 BoundRect = BoundRect.Union(((NodeRenderableBounded*)pNode)->GetBoundingRect(!bIncludeAttrs)); 01906 01907 // And find the next node 01908 pNode = pNode->FindNext(); 01909 } 01910 01911 return BoundRect; 01912 } 01913 01914 01915 01916 01917 /******************************************************************************************** 01918 01919 > virtual BOOL NodeCompound::HasEffectAttrs() const 01920 01921 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01922 Created: 11/01/2005 01923 Returns: TRUE if the node has effect attributes 01924 FALSE otherwise 01925 Purpose: Detect Effect Attributes 01926 01927 ********************************************************************************************/ 01928 01929 BOOL NodeCompound::HasEffectAttrs() const 01930 { 01931 Node* pn = FindLastChild(); 01932 while (pn && !pn->IsBounded()) 01933 { 01934 if (pn->IsAnAttribute() && ((NodeAttribute*)pn)->IsEffectAttribute()) 01935 return TRUE; 01936 01937 pn = pn->FindPrevious(); 01938 } 01939 return FALSE; 01940 } 01941 01942 01943 01944 01945 /******************************************************************************************** 01946 01947 > virtual BOOL NodeCompound::ContainsEffects() const 01948 01949 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01950 Created: 17/08/2005 01951 Returns: TRUE if the node contains effects nodes 01952 FALSE otherwise 01953 Purpose: Detect Effects 01954 01955 ********************************************************************************************/ 01956 01957 BOOL NodeCompound::ContainsEffects() const 01958 { 01959 Node* pn = FindFirstChild(); 01960 while (pn) 01961 { 01962 if (pn->IsEffect()) 01963 return TRUE; 01964 01965 if (pn->IsCompoundClass() && ((NodeCompound*)pn)->ContainsEffects()) 01966 return TRUE; 01967 01968 pn = pn->FindNext(); 01969 } 01970 01971 return FALSE; 01972 } 01973 01974 01975 01976 01977 /******************************************************************************************** 01978 01979 > void NodeCompound::TransformEffectAttrs(TransformBase& Trans) 01980 01981 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01982 Created: 30/06/2005 01983 Inputs: Trans - The transform that should be applied to all the children 01984 Purpose: Transforms the Child nodes of this node. This allows fills etc to move 01985 with the objects. 01986 01987 ********************************************************************************************/ 01988 01989 void NodeCompound::TransformEffectAttrs(TransformBase& Trans) 01990 { 01991 // Find all Effect Attributes (in subtree after last bounded node 01992 // and transform them. 01993 Node* pn = FindLastChild(); 01994 while (pn && !pn->IsBounded()) 01995 { 01996 if (pn->IsAnAttribute() && ((NodeAttribute*)pn)->IsEffectAttribute()) 01997 ((NodeAttribute*)pn)->Transform( Trans ); 01998 01999 pn = pn->FindPrevious(); 02000 } 02001 } 02002 02003 02004