00001 // $Id: noderend.cpp 1328 2006-06-15 19:23:45Z 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 00099 // Implementation of the following classes: 00100 /* 00101 NodeRenderable 00102 NodeRenderableInk 00103 NodeRenderablePaper 00104 */ 00105 00106 /* 00107 */ 00108 00109 #include "camtypes.h" 00110 00111 DECLARE_SOURCE("$Revision: 1328 $"); 00112 00113 //#include "ccobject.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00114 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 #include "paper.h" 00116 #include "dumbnode.h" 00117 //#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00118 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00119 //#include "resource.h" 00120 //#include "simon.h" 00121 //#include "nodeattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00122 //#include "rndrgn.h" 00123 //#include "bitmapcache.h" 00124 //#include "resource.h" 00125 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00126 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00127 //#include "stockcol.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00128 //#include "rendbits.h" 00129 #include "nodepath.h" 00130 #include "noderend.h" 00131 #include "camelot.h" 00132 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00133 //#include "mario.h" // for _R(IDE_NOMORE_MORY) 00134 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00135 #include "chapter.h" 00136 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00137 #include "nodedoc.h" 00138 #include "blobs.h" 00139 #include "objreg.h" 00140 #include "layer.h" 00141 //#include "basedoc.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00142 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00143 #include "progress.h" 00144 #include "gdraw.h" 00145 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00146 #include "lineattr.h" 00147 #include "grndrgn.h" // for REAL_GDRAW 00148 #include "snap.h" 00149 #include "contmenu.h" 00150 //#include "becomea.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00151 #include "nodetext.h" 00152 #include "nodetxtl.h" 00153 #include "attrmap.h" 00154 #include "ralphdoc.h" 00155 #include "extender.h" // for ExtendParams 00156 #include "swfrndr.h" 00157 //#include "bitmapcache.h" 00158 //#include "capturemanager.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00159 #include "nodeliveeffect.h" 00160 #include "cxftags.h" 00161 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00162 00163 #include "layermsg.h" // LayerMsg::LayerReason::REDRAW_LAYER 00164 00165 //---------------------------------------------------------------------------------------------- 00166 // NodeRenderable methods 00167 00168 CC_IMPLEMENT_DYNAMIC(NodeRenderable, Node) 00169 CC_IMPLEMENT_DYNAMIC(NodeRenderableBounded, NodeRenderable) 00170 CC_IMPLEMENT_DYNAMIC(NodeRenderableInk, NodeRenderableBounded) 00171 CC_IMPLEMENT_DYNAMIC(NodeHidden, Node) 00172 CC_IMPLEMENT_MEMDUMP(CopyBecomeA, BecomeA) 00173 00174 // Declare smart memory handling in Debug builds 00175 #define new CAM_DEBUG_NEW 00176 00177 00178 /********************************************************************************************* 00179 00180 Preference: Point Radius 00181 Section: Magnetic Options 00182 Range: 0 - lots 00183 Purpose: This is the radius around a control point (such as the corner of a rectangle, 00184 or the end point in the middle of a path) that will allow other points to 00185 be magnetically attracted to it. This is measured in millipoints 00186 SeeAlso: Line Radius 00187 00188 **********************************************************************************************/ 00189 INT32 NodeRenderableBounded::MagneticPointRadius = 750*6; // 6 pixels at 96DPI 00190 00191 00192 /********************************************************************************************* 00193 00194 Preference: Line Radius 00195 Section: Magnetic Options 00196 Range: 0 - lots 00197 Purpose: This is the radius around a path (such as the edges of a rectangle, 00198 or the whole of a path) that will allow other points to 00199 be magnetically attracted to it. This is measured in millipoints 00200 SeeAlso: Point Radius 00201 00202 **********************************************************************************************/ 00203 INT32 NodeRenderableBounded::MagneticLineRadius = 750*4; // 4 pixels at 96DPI 00204 00205 00206 00207 /********************************************************************************************* 00208 00209 Preference: EnableCacheing 00210 Section: Rendering 00211 Range: 0 or 1 00212 Purpose: Enable or disable bitmap cacheing of parts of the tree during GRenderRegion 00213 rendering 00214 SeeAlso: - 00215 00216 **********************************************************************************************/ 00217 BOOL NodeRenderableBounded::bEnableCacheing = TRUE; 00218 00219 00220 /********************************************************************************************* 00221 00222 Preference: ThrottleCacheing 00223 Section: Rendering 00224 Range: 0 or 1 00225 Purpose: TRUE - Throttle cacheing to be 5% of total rendering time or less 00226 SeeAlso: - 00227 00228 **********************************************************************************************/ 00229 BOOL NodeRenderableBounded::bThrottleCacheing = TRUE; 00230 00231 00232 00233 /********************************************************************************************* 00234 00235 Preference: ShowCacheBlobs 00236 Section: Rendering 00237 Range: 0 or 1 00238 Purpose: TRUE - Show special markers when cached groups are selected 00239 SeeAlso: - 00240 00241 **********************************************************************************************/ 00242 BOOL NodeRenderableBounded::bShowCacheBlobs = FALSE; 00243 00244 00245 00246 /********************************************************************************************* 00247 00248 > NodeRenderable::NodeRenderable() 00249 00250 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00251 Created: 13/5/93 00252 Inputs: - 00253 Outputs: 00254 Returns: - 00255 00256 Purpose: This constructor creates a NodeRenderable linked to no other with all status 00257 flags false and an uninitialised bounding rectangle. 00258 00259 Errors: 00260 00261 **********************************************************************************************/ 00262 00263 00264 NodeRenderable::NodeRenderable():Node() 00265 { 00266 Flags.Renderable = TRUE; 00267 Dragged = FALSE; 00268 } 00269 00270 00271 /*********************************************************************************************** 00272 00273 > NodeRenderable::NodeRenderable( Node* ContextNode, 00274 AttachNodeDirection Direction, 00275 BOOL Locked = FALSE, 00276 BOOL Mangled = FALSE, 00277 BOOL Marked = FALSE, 00278 BOOL Selected = FALSE 00279 ) 00280 00281 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00282 Created:26/4/93 00283 00284 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 00285 00286 Direction: 00287 00288 Specifies the direction in which the node is to be attached to the 00289 ContextNode. The values this variable can take are as follows: 00290 00291 PREV : Attach node as a previous sibling of the context node 00292 NEXT : Attach node as a next sibling of the context node 00293 FIRSTCHILD: Attach node as the first child of the context node 00294 LASTCHILD : Attach node as a last child of the context node 00295 00296 The remaining inputs specify the status of the node: 00297 00298 Locked: Is node locked ? 00299 Mangled: Is node mangled ? 00300 Marked: Is node marked ? 00301 Selected: Is node selected ? 00302 00303 Outputs: - 00304 Returns: - 00305 Purpose: This method initialises the node and links it to ContextNode in the 00306 direction specified by Direction. All necessary tree links are 00307 updated. 00308 00309 Errors: An assertion error will occur if ContextNode is NULL 00310 00311 ***********************************************************************************************/ 00312 00313 NodeRenderable::NodeRenderable(Node* ContextNode, 00314 AttachNodeDirection Direction, 00315 BOOL Locked, 00316 BOOL Mangled, 00317 BOOL Marked, 00318 BOOL Selected 00319 ): Node(ContextNode, Direction, Locked, Mangled, Marked, Selected, TRUE) 00320 { 00321 } 00322 00323 00324 /******************************************************************************************** 00325 00326 > BOOL NodeRenderable::NeedsToRender( RenderRegion *pRender ) 00327 00328 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00329 Created: 07/02/94 00330 Inputs: pRender - A pointer to the current render region (NULL if none) 00331 Purpose: Virtual function - this function will indicate to the caller whether or not 00332 we want to render the given node, according to the information passed in. 00333 For this class, it always returns TRUE. 00334 SeeAlso: Node::NeedsToRender 00335 00336 ********************************************************************************************/ 00337 00338 SubtreeRenderState NodeRenderable::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip) 00339 { 00340 return SUBTREE_ROOTANDCHILDREN; // Else we allow the renderer into the subtree 00341 } 00342 00343 /******************************************************************************************** 00344 00345 > BOOL NodeRenderable::NeedsToExport(RenderRegion *pRender, BOOL VisibleLayersOnly = FALSE, 00346 BOOL CheckSelected = FALSE) 00347 00348 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00349 Created: 23/03/94 00350 Inputs: pRender - A pointer to the current export region (NULL if none) 00351 VisibleLayersOnly - TRUE => remove nodes which are on invisible layers 00352 - FALSE => export everything 00353 CheckSelected - TRUE => we check if object selected and only export selected bjects 00354 - FALSE => we don't bother checking for selection or not 00355 Returns: TRUE => we always want to export NodeRenderable objects. 00356 Purpose: Indicate that we want to export this class of nodes. 00357 SeeAlso: NodeRenderable::NeedsToRender 00358 00359 ********************************************************************************************/ 00360 00361 BOOL NodeRenderable::NeedsToExport(RenderRegion *pRender, BOOL VisibleLayersOnly, BOOL CheckSelected) 00362 { 00363 #ifdef DO_EXPORT 00364 // If we have the check selection flag on then see if this renderable node is:- 00365 // - selected or not = render it 00366 // - a child of the selection e.g. part of selected group where we are an item in the 00367 // group and hence are not directly selected but still need to be exported 00368 // - a parent of the selected item e.g. selected inside item of group and we are at the 00369 // group and hence need to include the group in the range 00370 // Otherwise just return True as this is a renderable node and always needs to be exported 00371 // unless of course some node overrides this. 00372 if (CheckSelected) 00373 return (IsSelected() || IsChildOfSelected() || IsParentOfSelected()); 00374 else 00375 return TRUE; 00376 #else 00377 return FALSE; 00378 #endif 00379 } 00380 00381 /******************************************************************************************** 00382 00383 > INT32 NodeRenderable::GetSizeOfExport(Filter *pFilter) 00384 00385 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00386 Created: 27/01/95 00387 Inputs: pFilter - the export filter that will be used. 00388 Returns: The number of nodes that will be exported (or an approximation for large 00389 objects, e.g. bitmaps). 00390 Purpose: Find out how many nodes will be exported when this node is exported. 00391 The node can use the filter to find out how it will be exported, e.g. 00392 blends should return a value that reflects whether or not intermediate 00393 shapes will be saved out, etc. Bitmaps and other large objects should 00394 return an approximation so that the progress display bar gives a smooth 00395 update. 00396 NB. This is virtual - the default implementation just returns 1 - only 00397 override if this is not accurate. 00398 SeeAlso: Node::NeedsToExport; Node::ExportRender 00399 00400 ********************************************************************************************/ 00401 00402 INT32 NodeRenderable::GetSizeOfExport(Filter*) 00403 { 00404 // Most nodes are just one node... 00405 return 1; 00406 } 00407 00408 /******************************************************************************************** 00409 00410 > BOOL NodeRenderable::IsNodeRenderableClass() 00411 00412 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00413 Created: 27/01/95 00414 Returns: TRUE => This node is an instance of NodeRenderable or a derived class. 00415 FALSE => otherwise. 00416 Purpose: Determine if a node is *derived* from the NodeRenderable class. 00417 NB. This has nothing to do with the node's renderable flag! 00418 SeeAlso: Node::IsRenderable 00419 00420 ********************************************************************************************/ 00421 00422 BOOL NodeRenderable::IsNodeRenderableClass() const 00423 { 00424 // We are a NodeRenderable, thanks. 00425 return TRUE; 00426 } 00427 00428 /******************************************************************************************** 00429 00430 > BOOL NodeRenderable::ShouldBeRendered() 00431 00432 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00433 Created: 03/07/95 00434 Returns: TRUE => This node should be rendered 00435 FALSE => this node should not be rendered. 00436 Purpose: Work out if the node should be rendered - basically all nodes except 00437 NodeRenderable nodes should be rendered. However, some NodeRenderable 00438 derived classes should not actually be rendered - for example NodeMouldGroup 00439 hides the original un-moulded objects, which should definitely *not* be 00440 rendered. 00441 This is mainly used during printing where due to complications to do with 00442 banding and transparency, we cannot use NeedsToRender() to filter out 00443 such nodes, so we use this function instead. 00444 NB. This has nothing to do with the node's renderable flag! 00445 SeeAlso: Node::IsNodeRenderable 00446 00447 ********************************************************************************************/ 00448 00449 BOOL NodeRenderable::ShouldBeRendered() const 00450 { 00451 // By default we render nodes of this class, and derived nodes. 00452 return TRUE; 00453 } 00454 00455 00456 /******************************************************************************************** 00457 00458 > virtual void NodeRenderable::Transform( TransformBase& Transform ) 00459 00460 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00461 Created: 20/10/93 00462 Inputs: Trans - The transform to apply to the objects 00463 Purpose: This is the base class verison of the transform function. 00464 This is called to move, scale, rotate etc renderable objects. 00465 Each class derived from NodeRenderableInk should write a version 00466 of this function that manipulates all the control points in 00467 the object and updates its bounding box. See NodePath for an 00468 example. 00469 00470 ********************************************************************************************/ 00471 00472 void NodeRenderable::Transform( TransformBase& Trans ) 00473 { 00474 // By default, just transform all the children 00475 TransformChildren(Trans); 00476 } 00477 00478 00479 00480 void NodeRenderable::TransformChildren(TransformBase& Trans) 00481 { 00482 // We have to go through all the child nodes of this node and Transform 00483 // all the NodeRenderable objects 00484 00485 Node* pCurrent = this -> FindFirstChild(); 00486 00487 while (pCurrent != NULL) 00488 { 00489 // Make sure it is a renderable ink object (not an attribute) 00490 if (pCurrent->IsKindOf( CC_RUNTIME_CLASS(NodeRenderable) ) ) 00491 // Transform the child node 00492 ((NodeRenderable*)pCurrent) -> Transform( Trans ); 00493 00494 // Show the hourglass 00495 if (ShowHourglass()) 00496 { 00497 ContinueSlowJob(); 00498 } 00499 00500 00501 // Find the next object in the group 00502 pCurrent = pCurrent -> FindNext(); 00503 } 00504 } 00505 00506 /******************************************************************************************** 00507 00508 > BOOL NodeRenderable::CanTransform() 00509 00510 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00511 Created: 14/04/94 00512 Returns: The base class always returns FALSE - i.e. NodeRenderables do not need to 00513 be transformed by default. 00514 Purpose: Determine whether a renderable node can be transformed - if it does not, 00515 then no undo information needs to be stored for it. 00516 SeeAlso: NodeRenderableInk::CanTransform 00517 00518 ********************************************************************************************/ 00519 00520 BOOL NodeRenderable::CanTransform() 00521 { 00522 return FALSE; 00523 } 00524 00525 00526 00527 /*********************************************************************************************** 00528 > Node* NodeRenderable::SimpleCopy() 00529 00530 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00531 Created: 28/4/93 00532 Inputs: - 00533 Outputs: 00534 Returns: A copy of the node, or NULL if memory has run out 00535 00536 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 00537 The function is virtual, and must be defined for all derived classes. 00538 00539 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 00540 error and the function returns NULL. 00541 00542 **********************************************************************************************/ 00543 00544 Node* NodeRenderable::SimpleCopy() 00545 { 00546 NodeRenderable* NodeCopy; 00547 NodeCopy = new NodeRenderable(); 00548 ERRORIF(NodeCopy == NULL, _R(IDE_NOMORE_MEMORY), NULL); 00549 CopyNodeContents(NodeCopy); 00550 return (NodeCopy); 00551 } 00552 00553 00554 /*********************************************************************************************** 00555 > void NodeRenderable::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00556 00557 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00558 Created: 18/12/2003 00559 Outputs: - 00560 Purpose: Polymorphically copies the contents of this node to another 00561 Errors: An assertion failure will occur if NodeCopy is NULL 00562 Scope: protected 00563 00564 ***********************************************************************************************/ 00565 00566 void NodeRenderable::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00567 { 00568 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 00569 ENSURE(IS_A(pNodeCopy, NodeRenderable), "PolyCopyNodeContents given wrong dest node type"); 00570 00571 if (IS_A(pNodeCopy, NodeRenderable)) 00572 CopyNodeContents(pNodeCopy); 00573 } 00574 00575 00576 00577 /*********************************************************************************************** 00578 > void NodeRenderable::CopyNodeContents(Node* NodeCopy) 00579 00580 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00581 Created: 28/4/93 00582 00583 Inputs: 00584 Outputs: A copy of this node 00585 Returns: - 00586 00587 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 00588 00589 Errors: An assertion failure will occur if NodeCopy is NULL 00590 00591 Scope: protected 00592 00593 ***********************************************************************************************/ 00594 00595 void NodeRenderable::CopyNodeContents(NodeRenderable* NodeCopy) 00596 { 00597 ENSURE(NodeCopy != NULL,"Trying to copy a node's contents into a NULL node"); 00598 Node::CopyNodeContents(NodeCopy); 00599 } 00600 00601 #if 1 //DEBUG_TREE 00602 00603 /******************************************************************************************** 00604 00605 > void* NodeRenderable::GetDebugDetails(StringBase* Str) 00606 00607 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00608 Created: 21/9/93 00609 Outputs: Str: String giving debug info about the node 00610 Purpose: For obtaining debug information about the Node 00611 00612 ********************************************************************************************/ 00613 00614 00615 void NodeRenderable::GetDebugDetails(StringBase* Str) 00616 { 00617 #if DEBUG_TREE 00618 Node::GetDebugDetails(Str); 00619 #endif 00620 } 00621 00622 #endif 00623 00624 /******************************************************************************************** 00625 00626 > virtual void NodeRenderable::RenderFillBlobs(RenderRegion* pRender) 00627 00628 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00629 Created: 21/6/94 00630 Inputs: pRender - The region to render the blobs into 00631 Purpose: This function is the base class version of a blob rendering function, so it 00632 actually does nothing. The fill blobs are the blobs rendered by fills (eg 00633 the graduated fill should draw an arrow to show the start and end positions 00634 of the fill). A node that wants to render some fill blobs should write a 00635 replacement of this function. 00636 SeeAlso: BlobManager 00637 00638 ********************************************************************************************/ 00639 00640 //void NodeRenderable::RenderFillBlobs(RenderRegion* pRender) 00641 //{ 00642 //} 00643 00644 00645 00646 /******************************************************************************************** 00647 00648 > virtual void NodeRenderable::RenderEffectBlobs(RenderRegion* pRender) 00649 00650 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00651 Created: 07/01/2005 00652 Inputs: pRender - The region to render the blobs into 00653 Purpose: This function is the base class version of a blob rendering function, so it 00654 actually does nothing. The fill blobs are the blobs rendered by fills (eg 00655 the graduated fill should draw an arrow to show the start and end positions 00656 of the fill). A node that wants to render some fill blobs should write a 00657 replacement of this function. 00658 SeeAlso: BlobManager 00659 00660 ********************************************************************************************/ 00661 00662 void NodeRenderable::RenderEffectBlobs(RenderRegion* pRender) 00663 { 00664 } 00665 00666 00667 00668 /******************************************************************************************** 00669 00670 > virtual void NodeRenderable::RenderArtisticBlobs(RenderRegion* pRender) 00671 00672 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00673 Created: 21/6/94 00674 Inputs: pRender - The region to render the blobs into 00675 Purpose: This function is the base class version of a blob rendering function, so it 00676 actually does nothing. Artistic blobs are used to display infomation about 00677 things such as pressure and other 'artistic' effects. If a node wants to 00678 render artistic blobs it should contain a version of this function 00679 SeeAlso: BlobManager 00680 00681 ********************************************************************************************/ 00682 00683 void NodeRenderable::RenderArtisticBlobs(RenderRegion* pRender) 00684 { 00685 } 00686 00687 00688 00689 00690 /******************************************************************************************** 00691 00692 > virtual void NodeRenderable::RenderObjectBlobs(RenderRegion* pRender) 00693 00694 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00695 Created: 21/6/94 00696 Inputs: pRender - The region to render the blobs into 00697 Purpose: This function is the base class version of a blob rendering function, so it 00698 actually does nothing. Object Blobs are the blobs that allow you to edit the 00699 shape of the node. For example, a path would display blobs on all its coords 00700 and a Rectangle may put a blob at each corner. 00701 SeeAlso: BlobManager 00702 00703 ********************************************************************************************/ 00704 00705 void NodeRenderable::RenderObjectBlobs(RenderRegion* pRender) 00706 { 00707 } 00708 00709 00710 00711 00712 /******************************************************************************************** 00713 00714 > virtual void NodeRenderable::RenderTinyBlobs(RenderRegion* pRender) 00715 00716 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00717 Created: 21/6/94 00718 Inputs: pRender - The region to render the blobs into 00719 Purpose: This function is the base class version of a blob rendering function, so it 00720 actually does nothing. Tiny blobs are displayed by each of the objects that 00721 is selected when in bounded region selection mode. Typically a Tiny Blob 00722 should be a single small blob. 00723 SeeAlso: BlobManager 00724 00725 ********************************************************************************************/ 00726 00727 void NodeRenderable::RenderTinyBlobs(RenderRegion* pRender) 00728 { 00729 } 00730 00731 00732 00733 /******************************************************************************************** 00734 00735 > void NodeRenderable::RenderPenBlobs(RenderRegion* pRender) 00736 00737 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00738 Created: 26/9/94 00739 Inputs: pRender - the render region to draw your blobs into 00740 Purpose: This function is the base class version of a blob rendering function, so it 00741 actually does nothing. Overide this function in each of the nodes that 00742 require Pen Blobs so draw what it needed. 00743 00744 ********************************************************************************************/ 00745 00746 void NodeRenderable::RenderPenBlobs(RenderRegion* pRender) 00747 { 00748 } 00749 00750 00751 00752 /******************************************************************************************** 00753 00754 > virtual void NodeRenderable::RenderToolObjectBlobs(RenderRegion* pRender) 00755 00756 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00757 Created: 26 March 2000 00758 Inputs: pRender the region to render the blobs into. 00759 00760 Purpose: This function is the base class version of a blob rendering function, so it 00761 actually does nothing. 00762 ToolObject blobs are displayed and used by a Node for interaction with a 00763 specific tool. They are similar to object blobs, but the big difference is 00764 that whereas object blobs are displayed regardless of the current tool 00765 (even if you can't use it to edit them), ToolObject blobs are not. The Node 00766 should always exercise final control over whether the blobs are active, 00767 depending on which tool is in use. 00768 00769 SeeAlso: BlobManager 00770 00771 ********************************************************************************************/ 00772 void NodeRenderable::RenderToolObjectBlobs(RenderRegion* pRender) 00773 { 00774 } 00775 00776 00777 00778 /******************************************************************************************** 00779 00780 > virtual DocRect NodeRenderable::GetBlobBoundingRect() 00781 00782 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00783 Created: 25/01/94 00784 Returns: DocRect - The rectangle that contains all the nodes selection blobs. 00785 Purpose: Calculates the bounding rectangle of the nodes blobs.This should always 00786 be calculated on the fly as the view scale can change without the node 00787 knowing, giving an incorrect result. 00788 00789 ********************************************************************************************/ 00790 00791 DocRect NodeRenderable::GetBlobBoundingRect() 00792 { 00793 DocRect EmptyOne(0,0,0,0); 00794 return EmptyOne; 00795 } 00796 00797 /******************************************************************************************** 00798 00799 > virtual DocRect NodeRenderable::GetUnionBlobBoundingRect(BOOL bIncludeEffects = TRUE) 00800 00801 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00802 Created: 03/02/95 00803 Returns: DocRect - The rectangle that contains all the nodes selection blobs. 00804 Purpose: This simply returns the result of GetBlobBoundingRect() as the default action 00805 for the base class 00806 00807 ********************************************************************************************/ 00808 00809 DocRect NodeRenderable::GetUnionBlobBoundingRect(BOOL bIncludeEffects) 00810 { 00811 return GetBlobBoundingRect(); 00812 } 00813 00814 00815 /******************************************************************************************** 00816 00817 > virtual void NodeRenderable::Select(BOOL Redraw) 00818 00819 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00820 Created: 21/6/94 00821 Inputs: Redraw - TRUE if you want the blobs to be redrawn for you 00822 Purpose: Selects the node 00823 00824 ********************************************************************************************/ 00825 00826 void NodeRenderable::Select(BOOL ReDraw) 00827 { 00828 // Get the blob manager to draw some blobs if needed 00829 if (!IsSelected()) 00830 { 00831 // It's possible that this node is inside a currently selected node 00832 // The rules of select inside say that a selected node cannot have 00833 // selected parents or children, so we must go deselect them. 00834 // Parents... 00835 Node* pNode = FindParent(); 00836 while (pNode && pNode->IsNodeRenderableClass()) 00837 { 00838 ((NodeRenderable*)pNode)->DeSelect(ReDraw); 00839 pNode = pNode->FindParent(); 00840 } 00841 00842 // Children... 00843 // This node can only have selected children if it's marked as the parent 00844 // of selected children. 00845 if (IsParentOfSelected()) 00846 { 00847 pNode = this->FindFirstDepthFirst(); 00848 while (pNode) 00849 { 00850 if (pNode->IsNodeRenderableClass() && pNode!=this) 00851 { 00852 ((NodeRenderable*)pNode)->DeSelect(ReDraw); 00853 } 00854 pNode = pNode->FindNextDepthFirst(this); 00855 } 00856 } 00857 00858 SetSelected(TRUE); 00859 00860 if (ReDraw) 00861 { 00862 // Find the blob manager 00863 BlobManager* BlobMgr = GetApplication()->GetBlobManager(); 00864 ENSURE( BlobMgr!=NULL, "Blob Manager unexpected not there" ); 00865 00866 // Get it to render the blobs of this node 00867 BlobMgr->RenderMyBlobsOn(NULL, FindParentSpread(), this); 00868 00869 AttrFillGeometry::LastRenderedMesh = NULL; 00870 } 00871 00872 // Make this node selected and throw away the selection cache 00873 GetApplication()->UpdateSelection(); 00874 } 00875 } 00876 00877 00878 00879 /******************************************************************************************** 00880 00881 > virtual void NodeRenderable::DeSelect(BOOL ReDraw, BOOL bDeselectChildren) 00882 00883 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00884 Created: 21/6/94 00885 Inputs: ReDraw - TRUE if you want the blobs to be redrawn for you 00886 Purpose: DeSelects the node 00887 00888 ********************************************************************************************/ 00889 00890 void NodeRenderable::DeSelect(BOOL ReDraw, BOOL bDeselectChildren) 00891 { 00892 // Get the blob manager to draw some blobs if needed 00893 if (IsSelected()) 00894 { 00895 if (ReDraw) 00896 { 00897 // Find the blob manager 00898 BlobManager* BlobMgr = GetApplication()->GetBlobManager(); 00899 ENSURE( BlobMgr!=NULL, "Blob Manager unexpected not there" ); 00900 00901 // Get it to render the blobs of this node 00902 BlobMgr->RenderMyBlobsOff(NULL, FindParentSpread(), this); 00903 00904 AttrFillGeometry::LastRenderedMesh = NULL; 00905 } 00906 00907 // Make this node selected 00908 SetSelected(FALSE); 00909 GetApplication()->UpdateSelection(); 00910 } 00911 else if (IsParentOfSelected() && bDeselectChildren) 00912 { 00913 Node* pNode = this->FindFirstDepthFirst(); 00914 while (pNode) 00915 { 00916 if (pNode->IsNodeRenderableClass() && pNode!=this) 00917 { 00918 ((NodeRenderable*)pNode)->DeSelect(ReDraw); 00919 } 00920 pNode = pNode->FindNextDepthFirst(this); 00921 } 00922 00923 GetApplication()->UpdateSelection(); 00924 } 00925 } 00926 00927 00928 00929 /******************************************************************************************** 00930 00931 > virtual BOOL NodeRenderable::CopyComponentData(BaseDocument* SrcDoc, BaseDocument* NodesDoc) 00932 00933 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00934 Created: 16/8/94 00935 Inputs: SrcDoc: The document from where this node was copied 00936 NodesDoc: The document where this node lives 00937 Outputs: - 00938 Returns: FALSE if the copy should be aborted, eg. the component data could not be 00939 copied accross because we ran out of memory. 00940 00941 Purpose: This virtual function will be called on the node after it has been copied from 00942 document SrcDoc. It should copy all neccessary DocComponent data from 00943 SrcDoc to the document where the node lives (NodesDoc). 00944 00945 Errors: - 00946 SeeAlso: DocComponent::StartComponentCopy 00947 SeeAlso: DocComponent::EndComponentCopy 00948 SeeAlso: DocComponent::AbortComponentCopy 00949 00950 00951 ********************************************************************************************/ 00952 00953 BOOL NodeRenderable::CopyComponentData(BaseDocument* SrcDoc, BaseDocument* NodesDoc) 00954 { 00955 // Do nothing in the base class 00956 return TRUE; 00957 } 00958 00959 00960 00961 /******************************************************************************************** 00962 00963 > virtual void NodeRenderable::TransformStretchObject(const ExtendParams& ExtParams) 00964 00965 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00966 Created: 01/12/1999 00967 Inputs: ExtParams description of how this object should stretch. 00968 Outputs: This node may be stretched, depending on the flags held within ExtParams. 00969 Purpose: Perform a stretch on this Node, according to the contents of ExtParams. 00970 This function does nothing unless ExtParams uses X_STRETCH or Y_STRETCH. 00971 See also: The Extender class. 00972 00973 ********************************************************************************************/ 00974 void NodeRenderable::TransformStretchObject(const ExtendParams& ExtParams) 00975 { 00976 // x-stretch - translate and stretch this Node. 00977 if (ExtParams.fExtendFlags & X_STRETCH) 00978 { 00979 Trans2DMatrix toOrigin(-ExtParams.doccScaleStart.x, 0); 00980 Matrix matStretch( FIXED16( ExtParams.xscale ), FIXED16( 1.0 ) ); 00981 Trans2DMatrix stretchX( matStretch ); 00982 Trans2DMatrix fromOrigin(ExtParams.doccScaleEnd.x, 0); 00983 Transform(toOrigin); 00984 Transform(stretchX); 00985 Transform(fromOrigin); 00986 } 00987 00988 // y-stretch - translate and stretch this Node. 00989 if (ExtParams.fExtendFlags & Y_STRETCH) 00990 { 00991 Trans2DMatrix toOrigin(0, -ExtParams.doccScaleStart.y); 00992 Matrix matStretch( FIXED16(1.0), FIXED16(ExtParams.yscale) ); 00993 Trans2DMatrix stretchY( matStretch ); 00994 Trans2DMatrix fromOrigin(0, ExtParams.doccScaleEnd.y); 00995 Transform(toOrigin); 00996 Transform(stretchY); 00997 Transform(fromOrigin); 00998 } 00999 } 01000 01001 01002 01003 /******************************************************************************************** 01004 01005 > virtual void NodeRenderable::TransformTranslateObject(const ExtendParams& ExtParams) 01006 01007 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01008 Created: 01/12/1999 01009 Inputs: ExtParams description of how this object should translate. 01010 Outputs: This node may be translated, depending on the flags held within ExtParams. 01011 Purpose: Translate this Node, according to the offsets and flags defined in ExtParams, 01012 and a reference centre, defined by NodeRenderable::FindExtendCentre(). 01013 This function does nothing unless ExtParams uses X_EXTEND or Y_EXTEND. 01014 See also: The Extender class; FindExtendCentre(). 01015 01016 ********************************************************************************************/ 01017 void NodeRenderable::TransformTranslateObject(const ExtendParams& ExtParams) 01018 { 01019 DocCoord doccCentre = FindExtendCentre(); 01020 01021 // x-extension - we move the whole Node; behaviour determined by its centre. 01022 if (ExtParams.fExtendFlags & X_EXTEND) 01023 { 01024 doccCentre.x += ExtParams.doccOffset.x; 01025 01026 // first, translate the object by the offset from start- to end- centres. 01027 Trans2DMatrix baseXoffset(ExtParams.doccOffset.x, 0); 01028 Transform(baseXoffset); 01029 01030 // slight fudge here - we only move anything if we're outside a buffer-zone around 01031 // the centre (necessary as objects can be misaligned by a millipoint or two). 01032 if (doccCentre.x > ExtParams.doccEndCentre.x + ExtParams.xincExtendBuffer) 01033 { 01034 Trans2DMatrix translateX(ExtParams.xinc, 0); 01035 Transform(translateX); 01036 } 01037 else if (doccCentre.x < ExtParams.doccEndCentre.x - ExtParams.xdecExtendBuffer) 01038 { 01039 Trans2DMatrix translateX(-ExtParams.xdec, 0); 01040 Transform(translateX); 01041 } 01042 } 01043 01044 // y-extension - we move the whole Node; behaviour determined by its centre. 01045 if (ExtParams.fExtendFlags & Y_EXTEND) 01046 { 01047 doccCentre.y += ExtParams.doccOffset.y; 01048 01049 // first, translate the object by the offset from start- to end- centres. 01050 Trans2DMatrix baseYoffset(0, ExtParams.doccOffset.y); 01051 Transform(baseYoffset); 01052 01053 // only extend if we're outside the centre's buffer-zone. 01054 if (doccCentre.y > ExtParams.doccEndCentre.y + ExtParams.yincExtendBuffer) 01055 { 01056 Trans2DMatrix translateY(0, ExtParams.yinc); 01057 Transform(translateY); 01058 } 01059 else if (doccCentre.y < ExtParams.doccEndCentre.y - ExtParams.ydecExtendBuffer) 01060 { 01061 Trans2DMatrix translateY(0, -ExtParams.ydec); 01062 Transform(translateY); 01063 } 01064 } 01065 } 01066 01067 01068 01069 /******************************************************************************************** 01070 01071 > virtual void NodeRenderable::TransformTranslateNoStretchObject(const ExtendParams& ExtParams) 01072 01073 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01074 Created: 01/12/1999 01075 Inputs: ExtParams description of how this object should translate/stretch. 01076 Outputs: This node will be translated so that extend-centre matches up with where it 01077 would be if the node were stretched. 01078 Purpose: Translate this node so that its extend-centre matches the position it would 01079 be in if the node were stretched. The node maintains its aspect ratio. 01080 This function does nothing unless ExtParams uses X_STRETCH or Y_STRETCH. 01081 See also: The Extender class; FindExtendCentre(). 01082 01083 ********************************************************************************************/ 01084 void NodeRenderable::TransformTranslateNoStretchObject(const ExtendParams& ExtParams) 01085 { 01086 DocCoord doccRef = FindExtendCentre(); 01087 01088 // x-stretch - we translate the Node by the same amount as doccRef under stretching. 01089 if (ExtParams.fExtendFlags & X_STRETCH) 01090 { 01091 Trans2DMatrix transX( ExtParams.doccScaleEnd.x - 01092 ExtParams.doccScaleStart.x, 0 ); 01093 Transform(transX); 01094 01095 // extra translation is difference between stretched and unstretched pDoccRef. 01096 INT32 deltaX = (INT32)( (ExtParams.xscale - 1.0) * 01097 (doccRef.x - ExtParams.doccScaleStart.x) ); 01098 Trans2DMatrix trans2X(deltaX, 0); 01099 Transform(trans2X); 01100 } 01101 01102 // y-stretch - we translate the Node by the same amount as doccRef under stretching. 01103 if (ExtParams.fExtendFlags & Y_STRETCH) 01104 { 01105 Trans2DMatrix transY(0, ExtParams.doccScaleEnd.y - 01106 ExtParams.doccScaleStart.y); 01107 Transform(transY); 01108 01109 // extra translation is difference between stretched and unstretched pDoccRef. 01110 INT32 deltaY = (INT32)( (ExtParams.yscale - 1.0) * 01111 (doccRef.y - ExtParams.doccScaleStart.y) ); 01112 Trans2DMatrix trans2Y(0, deltaY); 01113 Transform(trans2Y); 01114 } 01115 } 01116 01117 01118 01119 //------------------------------------------------------------------------------------------- 01120 // NodeRenderableBounded methods 01121 01122 01123 01124 /******************************************************************************************** 01125 01126 > NodeRenderableBounded::NodeRenderableBounded() 01127 01128 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01129 Created: 14/04/94 01130 Purpose: Default constructor 01131 01132 ********************************************************************************************/ 01133 01134 NodeRenderableBounded::NodeRenderableBounded():NodeRenderable() 01135 { 01136 IsBoundingRectValid = FALSE; 01137 Magnetic = FALSE; 01138 MayBeCached = FALSE; // Definitely not cached 01139 } 01140 01141 01142 /*********************************************************************************************** 01143 01144 > NodeRenderableBounded::NodeRenderableBounded( Node* ContextNode, AttachNodeDirection Direction, 01145 BOOL Locked = FALSE, BOOL Mangled = FALSE, BOOL Marked = FALSE, 01146 BOOL Selected = FALSE) 01147 01148 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01149 Created:26/4/93 01150 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 01151 Direction: Specifies the direction in which the node is to be attached to the 01152 ContextNode. The values this variable can take are as follows: 01153 PREV : Attach node as a previous sibling of the context node 01154 NEXT : Attach node as a next sibling of the context node 01155 FIRSTCHILD: Attach node as the first child of the context node 01156 LASTCHILD : Attach node as a last child of the context node 01157 The remaining inputs specify the status of the node: 01158 Locked: Is node locked ? 01159 Mangled: Is node mangled ? 01160 Marked: Is node marked ? 01161 Selected: Is node selected ? 01162 Purpose: This method initialises the node and links it to ContextNode in the 01163 direction specified by Direction. All necessary tree links are 01164 updated. 01165 Errors: An assertion error will occur if ContextNode is NULL 01166 01167 ***********************************************************************************************/ 01168 01169 NodeRenderableBounded::NodeRenderableBounded(Node* ContextNode, AttachNodeDirection Direction, 01170 BOOL Locked, BOOL Mangled, BOOL Marked, BOOL Selected 01171 ): NodeRenderable(ContextNode, Direction, Locked, Mangled, Marked, Selected) 01172 { 01173 IsBoundingRectValid = FALSE; 01174 Magnetic = FALSE; 01175 Dragged = FALSE; 01176 MayBeCached = FALSE; // Definitely not cached 01177 } 01178 01179 01180 /********************************************************************************************* 01181 01182 > NodeRenderableBounded::~NodeRenderableBounded() 01183 01184 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01185 Created: 25/06/2004 01186 Inputs: - 01187 Outputs: 01188 Returns: - 01189 01190 Purpose: Since this node is dieing make sure that any cached data associated with it 01191 is also removed... 01192 01193 Errors: 01194 01195 **********************************************************************************************/ 01196 01197 NodeRenderableBounded::~NodeRenderableBounded() 01198 { 01199 if (MayBeCached) 01200 { 01201 // There could be some cached bitmaps associated with this node 01202 CBitmapCacheKey mykey(this, 42); 01203 CBitmapCache* pBitmapCache = Camelot.GetBitmapCache(); 01204 if (pBitmapCache) 01205 { 01206 // Get rid of EVERYTHING - we are dying! 01207 pBitmapCache->RemoveAllOwnedBitmaps(mykey, FALSE, CACHEPRIORITY_PERMANENT); 01208 } 01209 } 01210 } 01211 01212 01213 /******************************************************************************************** 01214 01215 > void NodeRenderableBounded::Transform(TransformBase& Trans) 01216 01217 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01218 Created: 12/9/94 01219 Inputs: Trans - The transform 01220 Purpose: Base class transform function. 01221 01222 ********************************************************************************************/ 01223 01224 void NodeRenderableBounded::Transform(TransformBase& Trans) 01225 { 01226 // Just transform the children and invalidate the nodes bounding rect 01227 InvalidateBoundingRect(); 01228 TransformChildren(Trans); 01229 } 01230 01231 01232 01233 /******************************************************************************************** 01234 01235 > void NodeRenderableBounded::TransformChildren(TransformBase& Trans) 01236 01237 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01238 Created: 11/9/94 01239 Inputs: Trans - The transform that should be applied to all the children 01240 Purpose: Transforms the Child nodes of this node. This allows fills etc to move 01241 with the objects. 01242 01243 ********************************************************************************************/ 01244 01245 void NodeRenderableBounded::TransformChildren(TransformBase& Trans) 01246 { 01247 // We have to go through all the child nodes of this node and Transform 01248 // all the NodeRenderable objects 01249 Node* pCurrent = this -> FindFirstChild(); 01250 01251 while (pCurrent != NULL) 01252 { 01253 // Make sure it is a renderable ink object (not a hidden node) 01254 if (pCurrent->IS_KIND_OF(NodeRenderable)) 01255 { 01256 // Transform the child node 01257 ((NodeRenderable*)pCurrent)->Transform( Trans ); 01258 01259 // If this node has a bounding box then invalidate it 01260 if (pCurrent->IsBounded()) 01261 { 01262 ((NodeRenderableBounded*)pCurrent)->InvalidateBoundingRect(); 01263 } 01264 01265 // Show the hourglass 01266 if (ShowHourglass()) 01267 { 01268 ContinueSlowJob(); 01269 } 01270 } 01271 01272 // Find the next object in the group 01273 pCurrent = pCurrent -> FindNext(); 01274 } 01275 } 01276 01277 01278 01279 /******************************************************************************************** 01280 01281 > virtual DocRect NodeRenderableBounded::GetBoundingRect(BOOL DontUseAttrs=FALSE, 01282 BOOL HitTest=FALSE) 01283 01284 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01285 Created: 11/9/94 01286 Inputs: DontUseAttrs - TRUE if you want to ignore all the nodes attributes 01287 FALSE by default. 01288 HitTest - TRUE if being called during HitTest 01289 01290 Returns: The nodes bounding rectangle 01291 01292 Purpose: returns the nodes bounding rectangle. If the rectangle is valid the 01293 rectangle is simply returned, but is IsBoundingRectValid is FALSE (cos 01294 someone called InvaldateBoundingRect() on this node, or one of its 01295 children) then the bounding rect is first calculated and the flag reset, 01296 before it is returned. This is the base class version of this function 01297 and will build a bounding box out of the union of the nodes childrens 01298 bounding boxes. Your node MUST replace this function if this is not what you 01299 want it to do.... 01300 01301 ********************************************************************************************/ 01302 01303 DocRect NodeRenderableBounded::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest) 01304 { 01305 // if the bounding rect of this node is not valid then fill in something 01306 if (!IsBoundingRectValid || DontUseAttrs) 01307 { 01308 // just set it to be an empty rectangle 01309 DocRect BoundRect(0,0,0,0); 01310 01311 Node* pNode = FindFirstChild(); 01312 while (pNode!=NULL) 01313 { 01314 // Add in the bounding rect of this node with all the others 01315 if (pNode->IsBounded()) 01316 BoundRect = BoundRect.Union(((NodeRenderableBounded*)pNode)->GetBoundingRect(DontUseAttrs)); 01317 01318 // And find the next node 01319 pNode = pNode->FindNext(); 01320 } 01321 01322 if (DontUseAttrs) 01323 { 01324 // We do not want to update the cached bounding rect here 01325 return BoundRect; 01326 } 01327 01328 // Copy the unions into the nodes bounding rect param 01329 BoundingRectangle = BoundRect; 01330 01331 // mark the bounding rect as valid 01332 IsBoundingRectValid = TRUE; 01333 } 01334 01335 // and return the bounding rect 01336 return BoundingRectangle; 01337 } 01338 01339 /******************************************************************************************** 01340 01341 > virtual DocRect NodeRenderableBounded::GetUnionBlobBoundingRect(BOOL bIncludeEffects = TRUE) 01342 01343 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01344 Created: 03/02/95 01345 Returns: DocRect - The rectangle that is the union of all the nodes selection blobs 01346 and the node's bounding rectangle 01347 Purpose: This simply returns the result of GetBlobBoundingRect() as the default action 01348 for the base class 01349 01350 ********************************************************************************************/ 01351 01352 DocRect NodeRenderableBounded::GetUnionBlobBoundingRect(BOOL bIncludeEffects) 01353 { 01354 DocRect drBounds = GetBoundingRect().Union(GetBlobBoundingRect()); 01355 01356 if (!bIncludeEffects) 01357 return drBounds; 01358 01359 // Search up the effects stack 01360 // NodeRenderableBounded* pEffect = this; 01361 Node* pParent = FindParent(); 01362 while (pParent && !pParent->IsLayer()) 01363 { 01364 if (pParent->IsEffect()) 01365 drBounds = ((NodeEffect*)pParent)->GetBoundingRect().Union(((NodeEffect*)pParent)->GetBlobBoundingRect()); 01366 01367 pParent = pParent->FindParent(); 01368 } 01369 01370 return drBounds; 01371 } 01372 01373 01374 /******************************************************************************************** 01375 01376 > void NodeRenderableBounded::ValidateBoundingRect() 01377 01378 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01379 Created: 13/9/94 01380 Purpose: Marks this nodes bounding rect as valid again. You should not generally 01381 speaking be using this function. It was created so that new nodes could 01382 be sure of invalidating their parents bounding rects. DoInsertNewNode() 01383 is the only real case in which it can be used without express written 01384 permission from the UN. 01385 01386 ********************************************************************************************/ 01387 01388 void NodeRenderableBounded::ValidateBoundingRect() 01389 { 01390 IsBoundingRectValid = TRUE; 01391 } 01392 01393 01394 01395 /******************************************************************************************** 01396 01397 > void NodeRenderableBounded::InvalidateBoundingRectHelper() 01398 01399 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01400 Created: 11/9/94 01401 Scope: private 01402 Purpose: Marks the bounding rect of this node as invalid, as well as marking this nodes 01403 parents as invalid as well. Next time a nodes GetBoundingRect() function is 01404 called the bounding rect will be recalculated if needed. 01405 01406 This is the recursive helper function for NodeRenderableBounded::InvalidateBoundingRect 01407 01408 01409 SeeAlso NodeRenderableBounded::InvalidateBoundingRect 01410 01411 ********************************************************************************************/ 01412 01413 void NodeRenderableBounded::InvalidateBoundingRectHelper() 01414 { 01415 // Invalid this nodes bounding rect if we need to 01416 BoundingRectangle = DocRect(0,0,0,0); 01417 if (IsBoundingRectValid) 01418 { 01419 IsBoundingRectValid = FALSE; 01420 01421 // and invalid this nodes parents bounding rect 01422 Node* pParent = FindParent(); 01423 if (pParent!=NULL) 01424 { 01425 // Check that the tree is as expected 01426 ENSURE(pParent->IS_KIND_OF(NodeRenderableBounded), "Parent of a bounded node was not bounded"); 01427 01428 // sort of recurse up the tree invalidating the bounding rects as we go 01429 if (pParent->IsBounded()) 01430 ((NodeRenderableBounded*)pParent)->InvalidateBoundingRectHelper(); 01431 } 01432 } 01433 } 01434 01435 /******************************************************************************************** 01436 01437 > virtual void NodeRenderableBounded::InvalidateBoundingRect(BOOL InvalidateChildBounds = FALSE) 01438 01439 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> / Recursion moved to new function by Simon 01440 Created: 11/9/94 01441 Inputs: InvalidateChildBounds - When TRUE all children of the node have their 01442 bounds invalidated as well (eg. applying a line attribute to a group) 01443 01444 Purpose: Marks the bounding rect of this node as invalid, as well as marking this nodes 01445 parents as invalid as well. Next time a nodes GetBoundingRect() function is 01446 called the bounding rect will be recalculated if needed. 01447 01448 ********************************************************************************************/ 01449 01450 void NodeRenderableBounded::InvalidateBoundingRect(BOOL InvalidateChildBounds /* = FALSE */) 01451 { 01452 // Invalid this nodes bounding rect if we need to 01453 if (IsBoundingRectValid) 01454 { 01455 InvalidateBoundingRectHelper(); 01456 01457 // Removed by Simon (31/03/95) I Can't see a reason to update the selection here ! 01458 // Inform the range that it's invalid 01459 //SelRange* Selected = GetApplication()->FindSelection(); 01460 //ERROR3IF(Selected == NULL, "Where's the selection gone ?"); 01461 //Selected->UpdateBounds(); 01462 01463 if (InvalidateChildBounds) 01464 { 01465 // Invalidate the bounds of all children of the node 01466 Node* Current = FindFirstDepthFirst(); 01467 while (Current != this) 01468 { 01469 ERROR3IF (Current == NULL, "invalid NULL Current"); 01470 if (Current->IsBounded()) 01471 { 01472 if (((NodeRenderableBounded*)Current)->IsBoundingRectValid) 01473 { 01474 ((NodeRenderableBounded*)Current)->IsBoundingRectValid = FALSE; 01475 } 01476 } 01477 Current = Current->FindNextDepthFirst(this); 01478 } 01479 } 01480 01481 } 01482 } 01483 01484 01485 01486 /******************************************************************************************** 01487 01488 > virtual DocRect NodeRenderableBounded::GetEffectStackBounds(BOOL* pbFoundEffects = NULL) 01489 01490 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01491 Created: 11/07/2005 01492 Inputs: - 01493 Returns: rectangle containing bounds of topmost effect above this node 01494 Purpose: Find the bounds of any effects which might be affected by changes 01495 to this node 01496 01497 ********************************************************************************************/ 01498 01499 DocRect NodeRenderableBounded::GetEffectStackBounds(BOOL* pbFoundEffects) 01500 { 01501 DocRect drBounds = GetBoundingRect(); 01502 01503 if (pbFoundEffects) 01504 *pbFoundEffects = FALSE; 01505 01506 Node* pParent = FindParent(); 01507 while (pParent && !pParent->IsLayer()) 01508 { 01509 if (pParent->IsEffect()) 01510 { 01511 drBounds = ((NodeEffect*)pParent)->GetBoundingRect(); 01512 if (pbFoundEffects) 01513 *pbFoundEffects = TRUE; 01514 } 01515 01516 pParent = pParent->FindParent(); 01517 } 01518 01519 return drBounds; 01520 } 01521 01522 01523 01524 01525 /******************************************************************************************** 01526 01527 > BOOL NodeRenderableBounded::NeedsToRender( RenderRegion *pRender ) 01528 01529 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01530 Created: 07/02/94 01531 Inputs: pRender - A pointer to the current render region (NULL if none) 01532 Returns: TRUE => This node should be rendered, 01533 FALSE => This node does not need to be rendered. 01534 Purpose: Virtual function - this function will indicate to the caller whether or not 01535 we want to render the given node, according to the information passed in. 01536 SeeAlso: Node::NeedsToRender 01537 01538 ********************************************************************************************/ 01539 01540 SubtreeRenderState NodeRenderableBounded::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip) 01541 { 01542 if (pRender == NULL) // If no render region supplied, assume we need to be rendered 01543 return SUBTREE_ROOTANDCHILDREN; 01544 01545 // Go find out about my bounding rectangle 01546 DocRect Bounds = GetBoundingRect(); 01547 DocRect ClipRect = pRender->GetClipRect(); 01548 01549 if (bClip && !ClipRect.IsIntersectedWith(Bounds)) // If not within the clipping rect then 01550 return SUBTREE_NORENDER; // Don't render us or our children 01551 01552 // if (RenderCached(pRender, ppNextNode)) // If we can find a cached bitmap for this node and render it 01553 // return SUBTREE_NORENDER; // Then tell the renderer to move on without doing any more... 01554 01555 return SUBTREE_ROOTANDCHILDREN; // Else we must render ourselves and our children 01556 } 01557 01558 01559 01560 /******************************************************************************************** 01561 01562 > BOOL NodeRenderableBounded::IsIntersectedWith( DocRect* pClipRect ) 01563 01564 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01565 Created: 11/9/94 01566 Inputs: pClipRect 01567 Returns: TRUE if this node is intersected witht he doc rect 01568 Purpose: Determine if this node is intersected with the rectangle supplied. 01569 01570 ********************************************************************************************/ 01571 01572 BOOL NodeRenderableBounded::IsIntersectedWith( DocRect* pClipRect ) 01573 { 01574 // Go find out about my bounding rectangle 01575 DocRect Bounds = GetBoundingRect(); 01576 01577 // and return if we intersect 01578 return( pClipRect->IsIntersectedWith(Bounds)); 01579 } 01580 01581 01582 /******************************************************************************************** 01583 01584 > virtual BOOL NodeRenderableBounded::IsBounded() const 01585 01586 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01587 Created: 30/6/94 01588 Returns: TRUE 01589 Purpose: This function will return TRUE when called on NodeRenderableBounded nodes 01590 and those derived from it. 01591 SeeAlso: Node::IsBounded 01592 01593 ********************************************************************************************/ 01594 01595 /*BOOL NodeRenderableBounded::IsBounded() const 01596 { 01597 return TRUE; 01598 }*/ 01599 01600 01601 /******************************************************************************************** 01602 01603 > BOOL NodeRenderableBounded::CanTakeAttributeType(CCRuntimeClass *pAttrClass) 01604 01605 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01606 Created: 31/08/94 01607 Inputs: pAttrClass - specifies the type of attribute being enquired about. 01608 Returns: TRUE => object supports this kind of attribute. 01609 FALSE => object does not support this kind of attribute, and so it 01610 should not be applied. 01611 Purpose: Determine whether or not a bounded node can take a particular kind of 01612 attribute. This is used for various objects, e.g. bitmap objects use it 01613 to accept transparent fill geometries but not normal ones, because they 01614 are always filled with the bitmap. 01615 Base class version always returns TRUE so by default an object supports 01616 all attribute types. 01617 01618 ********************************************************************************************/ 01619 01620 BOOL NodeRenderableBounded::CanTakeAttributeType(CCRuntimeClass*) 01621 { 01622 return TRUE; 01623 } 01624 01625 /*********************************************************************************************** 01626 > Node* NodeRenderableBounded::SimpleCopy() 01627 01628 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01629 Created: 28/4/93 01630 Returns: A copy of the node, or NULL if memory has run out 01631 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 01632 The function is virtual, and must be defined for all derived classes. 01633 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 01634 error and the function returns NULL. 01635 01636 **********************************************************************************************/ 01637 01638 Node* NodeRenderableBounded::SimpleCopy() 01639 { 01640 NodeRenderableBounded* NodeCopy; 01641 NodeCopy = new NodeRenderableBounded(); 01642 ERRORIF(NodeCopy == NULL, _R(IDE_NOMORE_MEMORY), NULL); 01643 CopyNodeContents(NodeCopy); 01644 return (NodeCopy); 01645 } 01646 01647 01648 01649 /*********************************************************************************************** 01650 > void NodeRenderableBounded::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01651 01652 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01653 Created: 18/12/2003 01654 Outputs: - 01655 Purpose: Polymorphically copies the contents of this node to another 01656 Errors: An assertion failure will occur if NodeCopy is NULL 01657 Scope: protected 01658 01659 ***********************************************************************************************/ 01660 01661 void NodeRenderableBounded::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01662 { 01663 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 01664 ENSURE(pNodeCopy->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)), "PolyCopyNodeContents given wrong dest node type"); 01665 01666 if (pNodeCopy->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded))) 01667 CopyNodeContents((NodeRenderableBounded*)pNodeCopy); 01668 } 01669 01670 01671 01672 /*********************************************************************************************** 01673 > void NodeRenderableBounded::CopyNodeContents(Node* NodeCopy) 01674 01675 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01676 Created: 28/4/93 01677 Outputs: A copy of this node 01678 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 01679 Errors: An assertion failure will occur if NodeCopy is NULL 01680 Scope: protected 01681 01682 ***********************************************************************************************/ 01683 01684 void NodeRenderableBounded::CopyNodeContents(NodeRenderableBounded* NodeCopy) 01685 { 01686 ENSURE(NodeCopy != NULL,"Trying to copy a node's contents into a NULL node"); 01687 NodeRenderable::CopyNodeContents(NodeCopy); 01688 01689 // Node Bounded stuff 01690 NodeCopy->BoundingRectangle = BoundingRectangle; 01691 NodeCopy->IsBoundingRectValid = IsBoundingRectValid; 01692 01693 // The magnetic flag 01694 NodeCopy->Magnetic = Magnetic; 01695 NodeCopy->Dragged = Dragged; 01696 } 01697 01698 /******************************************************************************************** 01699 01700 > void* NodeRenderableBounded::GetDebugDetails(StringBase* Str) 01701 01702 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01703 Created: 21/9/93 01704 Outputs: Str: String giving debug info about the node 01705 Purpose: For obtaining debug information about the Node 01706 01707 ********************************************************************************************/ 01708 01709 void NodeRenderableBounded::GetDebugDetails(StringBase* Str) 01710 { 01711 #ifdef _DEBUG 01712 NodeRenderable::GetDebugDetails(Str); 01713 String_256 TempStr; 01714 01715 // Find out about the node up to date bounding rect 01716 DocRect Bounds = GetBoundingRect(); 01717 if (!Bounds.IsValid()) 01718 { 01719 TempStr = TEXT("\r\nBounding Rectangle = *INVALID*\r\n"); 01720 } 01721 else 01722 TempStr._MakeMsg(TEXT("\r\nBounding Rectangle\r\n Low(#1%ld, #2%ld)\r\n High(#3%ld, #4%ld)\r\n"), 01723 Bounds.LowCorner().x, 01724 Bounds.LowCorner().y, 01725 Bounds.HighCorner().x, 01726 Bounds.HighCorner().y); 01727 (*Str)+=TempStr; 01728 #endif 01729 } 01730 01731 /******************************************************************************************** 01732 01733 > void NodeRenderableBounded::IncludeChildrensBoundingRects(DocRect* BoundingRect) 01734 01735 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 01736 Created: 28/7/94 01737 Outputs: DocRect is updated to include Childrens Bounding Rects. 01738 Purpose: The child attribute Blob bounding rects are included in the BoundingRect. 01739 Note: re-written by Ed 25/4/95 01740 Now only includes bounds of child attrs (rather than all NodeRenderableBounded) 01741 The assumption is that no child can be selected if it's parent is, so attr 01742 blobs of child nodes cannot be visible at the same time as their parents! 01743 01744 re-written by Will 5/5/95 01745 Now uses 'FindAppliedAttributes' so it works for select inside. 01746 01747 ********************************************************************************************/ 01748 01749 void NodeRenderableBounded::IncludeChildrensBoundingRects(DocRect* pBounds) 01750 { 01751 // Ok, so this function should be defined in NodeRenderableInk, but that is 01752 // one heck of a change, so we'll just make sure we warn people if they try 01753 // something silly. 01754 ERROR3IF(!this->IS_KIND_OF(NodeRenderableInk), "IncludeChildrensBoundingRect called for non-ink node"); 01755 01756 #if !defined(EXCLUDE_FROM_RALPH) 01757 // Find the blob Manager 01758 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 01759 if (pBlobMgr==NULL) 01760 return; 01761 01762 // Since the only blobs that attributes have are Fill Blobs, 01763 // don't bother if the fill blobs are not visible 01764 BlobStyle VisibleBlobs = pBlobMgr->GetCurrentInterest(TRUE); 01765 if (VisibleBlobs.Fill) 01766 { 01767 CCAttrMap* pAttribMap = new CCAttrMap(30); 01768 if (pAttribMap == NULL) 01769 return; 01770 01771 // Now find any attributes that are applied to this node. 01772 BOOL FoundAttrs = ((NodeRenderableInk*)this)->FindAppliedAttributes(pAttribMap, 5000, NULL, FALSE); 01773 01774 if (FoundAttrs) 01775 { 01776 // iterating all (key, value) pairs 01777 for (CCAttrMap::iterator Pos = pAttribMap->GetStartPosition(); Pos != pAttribMap->GetEndPosition();) 01778 { 01779 void *pVal; 01780 CCRuntimeClass *pType; 01781 pAttribMap->GetNextAssoc(Pos,pType,pVal); 01782 01783 NodeAttribute* pAttr = (NodeAttribute*)pVal; 01784 *pBounds=pBounds->Union( pAttr->GetBlobBoundingRect() ); 01785 } 01786 } 01787 01788 delete pAttribMap; 01789 } 01790 #endif 01791 } 01792 01793 /*********************************************************************************************** 01794 01795 > BOOL NodeRenderableBounded::Snap(DocCoord* pDocCoord) 01796 01797 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01798 Created: 20/9/94 01799 Inputs: pDocCoord = a coord in Spread coords 01800 Outputs: 01801 Returns: TRUE - the DocCoord has been snapped to the path. 01802 FALSE - the DocCoord has not been processed. 01803 01804 Purpose: ALWAYS RETURNS FALSE! 01805 This is just a virtual base function intended to be overridden. 01806 Errors: 01807 Scope: public 01808 01809 **********************************************************************************************/ 01810 01811 BOOL NodeRenderableBounded::Snap(DocCoord* pDocCoord) 01812 { 01813 return (FALSE); 01814 } 01815 01816 /*********************************************************************************************** 01817 01818 > BOOL NodeRenderableBounded::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord) 01819 01820 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01821 Created: 21/9/94 01822 Inputs: pDocCoord - the rectangle to snap 01823 StartDrag - Start coord of drag 01824 EndDrag - End coord of drag 01825 Outputs: 01826 Returns: TRUE - the DocRect been snapped to the grid. 01827 FALSE - the DocRect has not been processed. 01828 01829 Purpose: ALWAYS RETURNS FALSE! 01830 This is just a virtual base function intended to be overridden. 01831 Scope: public 01832 01833 **********************************************************************************************/ 01834 01835 BOOL NodeRenderableBounded::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord) 01836 { 01837 return (FALSE); 01838 } 01839 01840 01841 01842 /******************************************************************************************** 01843 01844 > BOOL NodeRenderableBounded::SnapToCoords(DocCoord* pDocCoord) 01845 01846 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01847 Created: 21/11/94 01848 Inputs: pDocCoord - The DocCoord that needs snapping 01849 Outputs: If the function returns TRUE then pDocCoord will have been modified to 01850 snap to a significant point on the node. 01851 Returns: TRUE if the Coord was snapped. 01852 FALSE if the coord was not effected by this node 01853 Purpose: This is a form of Magnetic snapping. It Snaps the Coordinates to the 01854 Significant points around a shape. eg. It would snap to the EndPoints along 01855 a path, the centre and corners of a rectangle etc. 01856 This snapping is more powerful than the normal magnetic snapping, so that 01857 these significant points can be snapped to more easily. 01858 This is the base class version of the function and does no snapping at all. 01859 It always returns FALSE. If you want your node to make use of this sort 01860 of snapping, override this function and use the MagneticPointRadius to 01861 decide if the DocCoord is close enough to be snapped. 01862 SeeAlso: MagneticPointRadius; MagneticLineRadius; NodePath::SnapToCoords 01863 01864 ********************************************************************************************/ 01865 01866 BOOL NodeRenderableBounded::SnapToCoords(DocCoord* pDocCoord) 01867 { 01868 return FALSE; 01869 } 01870 01871 01872 /******************************************************************************************** 01873 01874 > BOOL NodeRenderableBounded::Init() 01875 01876 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01877 Created: 22/11/94 01878 Returns: TRUE if it worked, FALSE if not 01879 Purpose: Declare the preferences for the magnetic options. 01880 Now also declares the layers section rather than having a new explicit 01881 init in the layers section. 01882 01883 ********************************************************************************************/ 01884 01885 BOOL NodeRenderableBounded::Init() 01886 { 01887 #if !defined(EXCLUDE_FROM_RALPH) 01888 // Declare the section that the magnetic options will live in 01889 BOOL Worked = Camelot.DeclareSection(TEXT("Magnetic Options"), 2); 01890 01891 // declare the 2 prefs that there are 01892 if (Worked) 01893 Worked = Camelot.DeclarePref(TEXT("Magnetic Options"), TEXT("Point Radius"), 01894 &MagneticPointRadius, 0); 01895 01896 if (Worked) 01897 Worked = Camelot.DeclarePref(TEXT("Magnetic Options"), TEXT("Line Radius"), 01898 &MagneticLineRadius, 0); 01899 01900 // Declare the section that the preferences for layers will live in 01901 if (Worked) 01902 Worked = Camelot.DeclareSection(TEXT("Layers"), 2); 01903 01904 // declare the 2 prefs that there are 01905 if (Worked) 01906 Worked = Camelot.DeclarePref(TEXT("Layers"), TEXT("ActiveLayerVisibleAndEditable"), 01907 &Layer::ActiveLayerVisibleAndEditable, 0, 1); 01908 01909 if (Worked) 01910 Worked = Camelot.DeclarePref(TEXT("Layers"), TEXT("EnableLayerCacheing"), 01911 &Layer::EnableLayerCacheing, 0, 2); 01912 01913 // Declare the section that the preferences for layers will live in 01914 if (Worked) 01915 Worked = Camelot.DeclareSection(TEXT("Rendering"), 4); 01916 01917 if (Worked) 01918 Worked = Camelot.DeclarePref(TEXT("Rendering"), TEXT("Cacheing"), 01919 &bEnableCacheing, 0); 01920 01921 if (Worked) 01922 Worked = Camelot.DeclarePref(TEXT("Rendering"), TEXT("ThrottleCacheing"), 01923 &bThrottleCacheing, 0); 01924 01925 if (Worked) 01926 Worked = Camelot.DeclarePref(TEXT("Rendering"), TEXT("ShowCacheBlobs"), 01927 &bShowCacheBlobs, 0); 01928 01929 // Return if it worked or not 01930 return Worked; 01931 #else 01932 return TRUE; 01933 #endif 01934 } 01935 01936 01937 01938 /******************************************************************************************** 01939 01940 > BOOL NodeRenderableBounded::IsMagneticallyClose(DocCoord* pTestCoord, DocCoord* pOriginalCoord) 01941 01942 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01943 Created: 21/11/94 01944 Inputs: pTestCoord - the coord we are testing the original against 01945 pOriginalCoord - The Coord that we are trying to snap to the test coord 01946 Outputs: pOriginalCoord - If the 2 coords are close enough together (as defined by 01947 the MagneticPointRadius) then pOriginalCoord is changed to match pTestCoord 01948 Returns: TRUE if it snapped the original coord to the test coord 01949 Purpose: Tests to see if the 2 coordinates are close enough together to qualify as 01950 Magnetically close to each other. If they are, then pOriginalCoord is 01951 Modified to match pTestCoord and TRUE id returned. If not, then all the 01952 coords are left alone and FALSE is returned 01953 01954 ********************************************************************************************/ 01955 01956 BOOL NodeRenderableBounded::IsMagneticallyClose(DocCoord* pTest, DocCoord* pOriginal) 01957 { 01958 #if !defined(EXCLUDE_FROM_RALPH) 01959 // Find out if anything is close to this coord 01960 if ((abs(pTest->x - pOriginal->x) < CSnap::GetSnapToCoordDist()) && 01961 (abs(pTest->y - pOriginal->y) < CSnap::GetSnapToCoordDist())) 01962 { 01963 // They are close to each other 01964 // Snap the original coord to the test coord 01965 pOriginal->x = pTest->x; 01966 pOriginal->y = pTest->y; 01967 01968 // return true to indicate what has happened 01969 return TRUE; 01970 } 01971 #endif 01972 // They were not close to each other, so say so 01973 return FALSE; 01974 } 01975 01976 01977 01978 /*********************************************************************************************** 01979 01980 > BOOL NodeRenderableBounded::IsMagnetic() 01981 01982 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01983 Created: 22/9/94 01984 Inputs: - 01985 Outputs: - 01986 Returns: TRUE - the node is magnetic 01987 FALSE - the node is not magnetic 01988 01989 Purpose: Returns that magnetic state of this node 01990 Scope: public 01991 01992 **********************************************************************************************/ 01993 01994 BOOL NodeRenderableBounded::IsMagnetic() 01995 { 01996 return Magnetic; 01997 } 01998 01999 02000 /*********************************************************************************************** 02001 02002 > void NodeRenderableBounded::SetMagneticState(BOOL state) 02003 02004 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02005 Created: 22/9/94 02006 Inputs: State - TRUE to become magnetic, FALSE otherwise 02007 Outputs: - 02008 Returns: - 02009 Purpose: Allows you to set the magnetic state of this node 02010 Scope: public 02011 02012 **********************************************************************************************/ 02013 02014 void NodeRenderableBounded::SetMagneticState(BOOL state) 02015 { 02016 Magnetic = state; 02017 } 02018 02019 02020 /*********************************************************************************************** 02021 02022 > BOOL NodeRenderable::IsBeingDragged() const 02023 02024 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02025 Created: 12/12/2003 02026 Inputs: - 02027 Outputs: - 02028 Returns: TRUE - the node is being dragged 02029 02030 Purpose: Returns a flag saying whether the node is currently being dragged or not 02031 Scope: public 02032 02033 **********************************************************************************************/ 02034 02035 BOOL NodeRenderable::IsDragged() const 02036 { 02037 return Dragged; 02038 } 02039 02040 02041 /*********************************************************************************************** 02042 02043 > void NodeRenderable::SetDraggedState(BOOL bNewState, BOOL bAndChildren) 02044 02045 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02046 Created: 12/12/2003 02047 Inputs: NewState - TRUE to become magnetic, FALSE otherwise 02048 bAndChildren - Recursively set all child nodes the same way 02049 Outputs: - 02050 Returns: - 02051 Purpose: Allows you to set the dragged state of this node 02052 Scope: public 02053 02054 **********************************************************************************************/ 02055 02056 void NodeRenderable::SetDraggedState(BOOL bNewState, BOOL bAndChildren) 02057 { 02058 Dragged = bNewState; 02059 if (bAndChildren) 02060 { 02061 NodeRenderable* pNode = (NodeRenderable*)FindFirstChild(CC_RUNTIME_CLASS(NodeRenderable)); 02062 while (pNode) 02063 { 02064 pNode->SetDraggedState(bNewState, bAndChildren); 02065 pNode = (NodeRenderable*)pNode->FindNext(CC_RUNTIME_CLASS(NodeRenderable)); 02066 } 02067 } 02068 } 02069 02070 02071 /*********************************************************************************************** 02072 02073 > double NodeRenderableBounded::GetRotationAngle() 02074 02075 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02076 Created: 24/1/95 02077 Inputs: - 02078 Outputs: - 02079 Returns: The angle of rotation of the object. This ranges from PI to -PI. Zero is on 02080 the positive x-axis. (i.e. what atan2 returns) 02081 Purpose: Call this function to obtain the current angle of rotation of the node. By 02082 default this is zero. Nodes derived from NodeRenderableBounded should override 02083 this function and return the angle of rotation using their own particular method 02084 Scope: public 02085 02086 **********************************************************************************************/ 02087 02088 double NodeRenderableBounded::GetRotationAngle() 02089 { 02090 return 0.0; 02091 } 02092 02093 02094 02095 /******************************************************************************************** 02096 02097 > virtual BOOL NodeRenderableBounded::IsDifferent(Node *pOther) 02098 02099 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02100 Created: 28/2/97 02101 02102 Inputs: pOther - The node to compare this one to 02103 02104 Returns: TRUE if this is considered different from pOther, 02105 FALSE if they are the same 02106 02107 Purpose: Determine if 2 nodes are considered different. 02108 02109 Notes: **** IMPORTANT - May not function well enough for your needs! **** 02110 02111 This was written to allow the StrokeComponent class to merge stroke 02112 definitions which share identical clipart subtrees. Stroke subtrees 02113 are special in that they have had Make Shapes applied to them, and 02114 so only contain paths. Hence, I have only defined functions in 02115 Node, NodeRenderableBounded, and NodePath - most objects in the tree 02116 thus use base class functionality (are they of the same class, and 02117 do they have identical bounding boxes). This suffices for my needs, 02118 but you may need to implement this function for a lot more node 02119 types before it's of use to you. 02120 02121 ********************************************************************************************/ 02122 02123 BOOL NodeRenderableBounded::IsDifferent(Node *pOther) 02124 { 02125 // First, check with the base class - this checks the classes are the same type 02126 if (NodeRenderable::IsDifferent(pOther)) 02127 return(TRUE); 02128 02129 ERROR3IF(GetRuntimeClass() != pOther->GetRuntimeClass(), 02130 "Node::IsDifferent base class method seems to have been broken"); 02131 02132 // Now check if the bounds of the nodes are the same 02133 if (BoundingRectangle != ((NodeRenderableBounded *)pOther)->BoundingRectangle) 02134 return(TRUE); 02135 02136 return(FALSE); 02137 } 02138 02139 02140 02141 /******************************************************************************************** 02142 02143 > virtual DocRect NodeRenderableBounded::GetExtendTargetBounds(const ExtendParams& ExtParams) 02144 02145 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 02146 Created: 02/06/2000 02147 Inputs: ExtParams const ref to an ExtendParams class describing the extension. 02148 Outputs: 02149 Returns: The DocRect to treat as the bounding rect of this node when extending. 02150 Purpose: Return a DocRect which contains the bounds of this node as defined and 02151 required by the Extending mechanism. 02152 02153 We treat x- and y- directions separately, and we always return our true 02154 bounds, unless we're extending in a direction, in which case we return the 02155 bounds of our extend control points. Default behaviour for this is to 02156 use the 'bounds' of our FindExtendCentre() coord. 02157 Errors: 02158 See also: SliceHelper::BoundingNodeSize(). 02159 02160 ********************************************************************************************/ 02161 DocRect NodeRenderableBounded::GetExtendTargetBounds(const ExtendParams& ExtParams) 02162 { 02163 DocRect drBounds = GetBoundingRect(); 02164 DocCoord doccCentre = FindExtendCentre(); 02165 if (ExtParams.fExtendFlags & X_EXTEND) 02166 drBounds.lo.x = drBounds.hi.x = doccCentre.x; 02167 if (ExtParams.fExtendFlags & Y_EXTEND) 02168 drBounds.lo.y = drBounds.hi.y = doccCentre.y; 02169 02170 return drBounds; 02171 } 02172 02173 02174 02175 //---------------------------------------------------------------------------------------------- 02176 // NodeRenderableInk methods 02177 02178 02179 02180 02181 /********************************************************************************************* 02182 02183 > static BOOL NodeRenderableInk::Init() 02184 02185 Author: Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com> 02186 Created: 21/11/93 02187 Inputs: - 02188 Outputs: 02189 Returns: TRUE if worked (in fact cannot fail). 02190 Purpose: Reads preferences for NodeRenderableInk. 02191 Errors: None 02192 02193 **********************************************************************************************/ 02194 02195 BOOL NodeRenderableInk::Init() 02196 { 02197 #if !defined(EXCLUDE_FROM_RALPH) 02198 BOOL bOK = TRUE; 02199 bOK = bOK && Camelot.DeclareSection(TEXT("DebugFlags"), 10) 02200 && Camelot.DeclarePref(TEXT("DebugFlags"), TEXT("SmartClicks"), &bUseSmartClicks, FALSE, TRUE) 02201 && Camelot.DeclareSection(TEXT("Rendering"), 10) 02202 && Camelot.DeclarePref(TEXT("Rendering"), TEXT("EyeDropperAverage"), &AverageHitColour, FALSE, TRUE); 02203 02204 return bOK; 02205 #else 02206 return TRUE; 02207 #endif 02208 } 02209 02210 02211 /********************************************************************************************* 02212 02213 > NodeRenderableInk::NodeRenderableInk() 02214 02215 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02216 Created: 13/5/93 02217 Inputs: - 02218 Outputs: 02219 Returns: - 02220 02221 Purpose: This constructor creates a NodeRenderableInk linked to no other, with all status 02222 flags false, and an uninitialised bounding rectangle. 02223 02224 Errors: 02225 02226 **********************************************************************************************/ 02227 02228 NodeRenderableInk::NodeRenderableInk(): NodeRenderableBounded() 02229 { 02230 SafeToRender = FALSE; // Not safe to progressively render during importing yet (see ReadPostChildren...) 02231 MayBeCached = FALSE; // Definitely not cached 02232 } 02233 02234 /*********************************************************************************************** 02235 02236 > void NodeRenderableInk::NodeRenderableInk( 02237 Node* ContextNode, 02238 AttachNodeDirection Direction, 02239 BOOL Locked = FALSE, 02240 BOOL Mangled = FALSE, 02241 BOOL Marked = FALSE, 02242 BOOL Selected = FALSE, 02243 ) 02244 02245 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02246 Created:26/4/93 02247 02248 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 02249 02250 Direction: 02251 02252 Specifies the direction in which this node is to be attached to the 02253 ContextNode. The values this variable can take are as follows: 02254 02255 PREV : Attach node as a previous sibling of the context node 02256 NEXT : Attach node as a next sibling of the context node 02257 FIRSTCHILD: Attach node as the first child of the context node 02258 LASTCHILD : Attach node as a last child of the context node 02259 02260 The remaining inputs specify the status of the node: 02261 02262 Locked: Is node locked ? 02263 Mangled: Is node mangled ? 02264 Marked: Is node marked ? 02265 Selected: Is node selected ? 02266 02267 Outputs: - 02268 Returns: - 02269 Purpose: This method initialises the node and links it to ContextNode in the 02270 direction specified by Direction. All necessary tree links are 02271 updated. 02272 02273 Errors: An assertion error will occur if ContextNode is NULL 02274 02275 ***********************************************************************************************/ 02276 02277 NodeRenderableInk::NodeRenderableInk(Node* ContextNode, 02278 AttachNodeDirection Direction, 02279 BOOL Locked, 02280 BOOL Mangled, 02281 BOOL Marked, 02282 BOOL Selected 02283 ): 02284 NodeRenderableBounded(ContextNode, Direction, Locked, Mangled, Marked,Selected) 02285 { 02286 SafeToRender = FALSE; // Not safe to progressively render during importing yet (see ReadPostChildren...) 02287 MayBeCached = FALSE; // Definitely not cached 02288 } 02289 02290 02291 /********************************************************************************************* 02292 02293 > virtual BOOL NodeRenderableInk::IsAnObject(void) const 02294 02295 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02296 Created: 19/4/93 02297 Inputs: - 02298 Outputs: - 02299 Returns: TRUE if the node is an object i.e. a NodeRenderableInk 02300 Purpose: For determining quickly if the node is an object 02301 Errors: 02302 02303 **********************************************************************************************/ 02304 02305 BOOL NodeRenderableInk::IsAnObject() const 02306 { 02307 return TRUE; // Cos it is 02308 } 02309 02310 02311 02312 /********************************************************************************************* 02313 > virtual BOOL NodeRenderableInk::IsSetCandidate() const 02314 02315 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02316 Created: 2/10/99 02317 Returns: TRUE. 02318 Purpose: Indicates that NodeRenderableInks are candidates for membership of Attribute 02319 gallery set. 02320 **********************************************************************************************/ 02321 02322 BOOL NodeRenderableInk::IsSetCandidate() const 02323 { 02324 return TRUE; 02325 } 02326 02327 02328 02329 /******************************************************************************************** 02330 02331 > BOOL NodeRenderableInk::CanTransform() 02332 02333 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02334 Created: 14/04/94 02335 Returns: This class's implementation always returns TRUE - i.e. NodeRenderableInks 02336 should be transformed by default. 02337 Purpose: Determine whether a renderable node can be transformed - if it does not, 02338 then no undo information needs to be stored for it. 02339 SeeAlso: NodeRenderable::CanTransform 02340 02341 ********************************************************************************************/ 02342 02343 BOOL NodeRenderableInk::CanTransform() 02344 { 02345 return TRUE; 02346 } 02347 02348 02349 /******************************************************************************************** 02350 02351 > virtual BOOL NodeRenderableInk::WriteBeginChildRecordsWeb(BaseCamelotFilter* pFilter) 02352 02353 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 02354 Created: 25/10/05 02355 Inputs: pFilter = ptr to filter to write to 02356 Returns: TRUE if ok, FALSE otherwise 02357 Purpose: Begin to write out you child records, in the web format 02358 02359 The base class will write out a TAG_DOWN record, but only if it has a child ptr 02360 02361 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 02362 02363 ********************************************************************************************/ 02364 02365 BOOL NodeRenderableInk::WriteBeginChildRecordsWeb(BaseCamelotFilter* pFilter) 02366 { 02367 return(WriteBeginChildRecordsNative(pFilter)); 02368 } 02369 02370 /******************************************************************************************** 02371 02372 > virtual BOOL NodeRenderableInk::WriteBeginChildRecordsNative(BaseCamelotFilter* pFilter) 02373 02374 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 02375 Created: 25/10/05 02376 Inputs: pFilter = ptr to filter to write to 02377 Returns: TRUE if ok, FALSE otherwise 02378 Purpose: Begin to write out you child records, in the native format 02379 02380 The base class will write out a TAG_DOWN record, but only if it has a child ptr 02381 02382 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 02383 02384 ********************************************************************************************/ 02385 02386 BOOL NodeRenderableInk::WriteBeginChildRecordsNative(BaseCamelotFilter* pFilter) 02387 { 02388 BOOL bNeedDown = FALSE; 02389 BOOL ok = TRUE; 02390 02391 Node* pChild = FindFirstChild(); 02392 if (pChild != NULL) 02393 { 02394 // The node is considered to have children ONLY if at least one child is not a hidden node. 02395 if (!pChild->IsNodeHidden() || (pChild->FindNextNonHidden() != NULL)) 02396 { 02397 bNeedDown = TRUE; 02398 } 02399 } 02400 02401 BOOL bBounds = WillWriteBounds(pFilter); 02402 if (bNeedDown || bBounds) 02403 { 02404 ok = pFilter->WriteZeroSizedRecord(TAG_DOWN); 02405 if (ok && bBounds) 02406 ok = WriteBoundsRecord(pFilter); 02407 } 02408 02409 return(ok); 02410 } 02411 02412 02413 /******************************************************************************************** 02414 02415 > virtual BOOL NodeRenderableInk::WriteBoundsRecord(BaseCamelotFilter* pFilter) 02416 02417 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 02418 Created: 25/10/05 02419 Inputs: pFilter = ptr to filter to write to 02420 Returns: TRUE if ok, FALSE otherwise 02421 Purpose: Write out a record containing the bounds of this object 02422 02423 ********************************************************************************************/ 02424 02425 BOOL NodeRenderableInk::WriteBoundsRecord(BaseCamelotFilter* pFilter) 02426 { 02427 BOOL ok = TRUE; 02428 // Write out the record 02429 DocRect Rect = GetBoundingRect(); 02430 02431 CamelotFileRecord Rec(pFilter, TAG_OBJECTBOUNDS, TAG_OBJECTBOUNDS_SIZE); 02432 ok = Rec.Init(); 02433 if (ok) ok = Rec.WriteCoord(Rect.lo); 02434 if (ok) ok = Rec.WriteCoord(Rect.hi); 02435 if (ok) ok = pFilter->Write(&Rec); 02436 02437 return(ok); 02438 } 02439 02440 02441 /******************************************************************************************** 02442 02443 > virtual BOOL NodeRenderableInk::WillWriteBounds(BaseCamelotFilter* pFilter) 02444 02445 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 02446 Created: 25/10/05 02447 Inputs: pFilter = ptr to filter to write to 02448 Returns: TRUE if this node will write out a bounds record 02449 Purpose: Determines if the down/up pair need to be written 02450 02451 ********************************************************************************************/ 02452 02453 BOOL NodeRenderableInk::WillWriteBounds(BaseCamelotFilter* pFilter) 02454 { 02455 return(pFilter->GetBoundsWriteLevel() >= BWL_ALL); 02456 } 02457 02458 02459 /******************************************************************************************** 02460 02461 > virtual BOOL NodeRenderableInk::WriteEndChildRecordsWeb(BaseCamelotFilter* pFilter) 02462 02463 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02464 Created: 1/8/96 02465 Inputs: pFilter = ptr to filter to write to 02466 Returns: TRUE if ok, FALSE otherwise 02467 Purpose: Finished writing out you child records, in the web format 02468 02469 The base class will write out a TAG_UP record, but only if it has a child ptr 02470 02471 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 02472 02473 ********************************************************************************************/ 02474 02475 BOOL NodeRenderableInk::WriteEndChildRecordsWeb(BaseCamelotFilter* pFilter) 02476 { 02477 return WriteEndChildRecordsNative(pFilter); 02478 } 02479 02480 /******************************************************************************************** 02481 02482 > virtual BOOL NodeRenderableInk::WriteEndChildRecordsNative(BaseCamelotFilter* pFilter) 02483 02484 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02485 Created: 1/8/96 02486 Inputs: pFilter = ptr to filter to write to 02487 Returns: TRUE if ok, FALSE otherwise 02488 Purpose: Finished writing out you child records, in the native format 02489 02490 The base class will write out a TAG_UP record, but only if it has a child ptr 02491 02492 SeeAlso: WritePostChildrenWeb(), WritePreChildrenWeb() 02493 02494 ********************************************************************************************/ 02495 02496 BOOL NodeRenderableInk::WriteEndChildRecordsNative(BaseCamelotFilter* pFilter) 02497 { 02498 BOOL bNeedUp = WillWriteBounds(pFilter); 02499 02500 Node* pChild = FindFirstChild(); 02501 if (pChild != NULL) 02502 { 02503 // The node is considered to have children ONLY if at least one child is not a hidden node. 02504 if (!pChild->IsNodeHidden() || (pChild->FindNextNonHidden() != NULL)) 02505 bNeedUp = TRUE; 02506 } 02507 02508 if (bNeedUp) 02509 return pFilter->WriteZeroSizedRecord(TAG_UP); 02510 02511 return TRUE; 02512 } 02513 02514 02515 02516 02517 /******************************************************************************************** 02518 02519 > virtual BOOL NodeRenderableBounded::RenderCached(RenderRegion* pRender) 02520 02521 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02522 Created: 17/06/2004 02523 Returns: TRUE if the node managed to render a cached version of itself 02524 then pNextNode contains the pointer to the node to continue rendering from 02525 FALSE if the node did not render a cached version of itself and thus 02526 normal rendering is required 02527 Purpose: Protected Helper function 02528 Allow this node to render itself using cached data if it has it and for that 02529 cached data to represent an arbitrary section of the document (usually a subtree 02530 but can be more) 02531 02532 For this implementation we assume that our cached info will represent just 02533 this subtree. 02534 02535 Also start to capture the rendered info into a cached bitmap if possible 02536 SeeAlso: NodeRenderableBounded::CaptureCached 02537 02538 ********************************************************************************************/ 02539 02540 BOOL NodeRenderableBounded::RenderCached(RenderRegion* pRender) 02541 { 02542 // Standard implementation of RenderCached takes note of RenderRegion.BackmostChangedNode 02543 // and uses the global CBitmapCache object... 02544 // 02545 // First, try to find quick ways to do nothing... 02546 // If cacheing is disabled bale out now! 02547 if (!NodeRenderableBounded::bEnableCacheing) 02548 return FALSE; 02549 02550 //TRACEUSER("Phil", _T("NRB::RenderCached for %x %s\n"), this, GetRuntimeClass()->m_lpszClassName); 02551 // If the rendering quality is outline - no point showing cached bitmaps... 02552 if (pRender->RRQuality.GetFillQuality() <= Quality::Solid) 02553 return FALSE; 02554 02555 // If the rendering system is doing black and white only then we can't sensibly 02556 // produce a monochrome version of the cached bitmap... 02557 if (pRender->IsVeryMono() || pRender->IsHitDetect() || pRender->IsPrinting() || pRender->IsWrappedRender()) 02558 return FALSE; 02559 02560 CBitmapCache* pBitmapCache = Camelot.GetBitmapCache(); 02561 if (pBitmapCache==NULL) 02562 return FALSE; 02563 02564 // If this node is definitely not cached, skip the cache rendering stuff... 02565 DocRect cliprect = pRender->GetClipRect(); 02566 DocRect bounds = GetBoundingRect(); // Assure new bounds are recalced if they were invalid 02567 BOOL bRendered = FALSE; 02568 if (MayBeCached) 02569 { 02570 // If render region tells us to, then we must remove all 24BPP cached bitmaps 02571 // (Opaque bitmaps could capture parts of the tree underneath them and they could have changed. 02572 // That's what the ReleaseCache() function is telling us.) 02573 CBitmapCacheKey inky(this, pRender->GetScaledPixelWidth()); //GetScaledPixelWidthDouble? 02574 02575 Node* pBackmostChanged = pRender->GetBackmostChangedNode(); 02576 if (pBackmostChanged) 02577 { 02578 // Only delete cached opaque bitmaps if they are above the lowest 02579 // changed node in this render (keep ones that are below because they are still valid) 02580 // 02581 // (Remember that the bounds of this object should already have been checked against 02582 // the clipping rectangle before this function is called, so we will only be chucking 02583 // out cached items that intersect the clipping rect.) 02584 // 02585 if (pBackmostChanged->IsUnder(this)) 02586 { 02587 // Then we must remove all opaque bitmaps in the cache 02588 // associated with this node 02589 //TRACEUSER("Phil", _T("NRB:RenderCached release transp bitmaps %x %s\n"), this, this->GetRuntimeClass()->m_lpszClassName); 02590 BOOL bRemoved = pBitmapCache->RemoveAllOwnedBitmaps(inky, TRUE); // Only remove opaque bitmaps 02591 if (bRemoved) MayBeCached = FALSE; // assume that is some were opaque, all were (and thus all have been removed)... 02592 } 02593 } 02594 02595 // Look for a cached bitmap at the appropriate pixel size... 02596 CCachedBitmap cbmp; 02597 BOOL bFound = pBitmapCache->Lookup(inky, cbmp); 02598 if (bFound) 02599 { 02600 // If cached bitmap covers the current clipped object rect, we can use it... 02601 DocRect clippedboundrect = cliprect.Intersection(bounds); 02602 if (cbmp.GetCachedRect().ContainsRect(clippedboundrect)) 02603 { 02604 //TRACEUSER("Phil", _T("NRB::RenderCached Rendering cached bitmap for %x %s %d\n"), this, GetRuntimeClass()->m_lpszClassName, cbmp.pbmpInfo->bmiHeader.biBitCount); 02605 bRendered = pRender->RenderBits(cbmp.pbmpInfo, cbmp.pbmpBits, &cbmp.coord0, 3); 02606 } 02607 } 02608 } 02609 02610 if (bRendered) 02611 return TRUE; 02612 02613 // -------------------------------------------------------------------- 02614 // Now we must decide whether we can afford to cache this node... 02615 // 02616 02617 // If this is being (solid) dragged don't waste time trying to cache it 02618 // if (IsDragged()) 02619 // return FALSE; 02620 02621 // Any sort of drag prevents new cacheing (to keep drags running smoothly) 02622 if (Operation::GetCurrentDragOp()) 02623 return FALSE; 02624 02625 //TRACEUSER("Phil", _T("NRB:RenderCached prep capture %x %s\n"), this, this->GetRuntimeClass()->m_lpszClassName); 02626 // Do the following optimisation only on unselected nodes... 02627 if (!IsSelected()) 02628 { 02629 // This is a performance optimisation to reduce cacheing overhead... 02630 // If there are more than 2 nested captures already running, don't try another one... 02631 if (pRender->GetCaptureDepth() > 2) 02632 return FALSE; 02633 02634 // We can use cache throttling to prevent this node being cached 02635 // 02636 // If we've run out of time to do cacheing then stop now. 02637 // if (time spent cacheing thus far is >5% of total rendering time) then don't do any more 02638 // Node* pParent = FindParent(); 02639 if (NodeRenderableBounded::bThrottleCacheing && 02640 pRender->GetStoredCount()*((INT64)20) > pRender->GetTotalCount() //&& 02641 // !IsSelected() && // Selected nodes can't be throttled 02642 // pParent && // Nodes without parents can't be trottled 02643 // pParent->IsLayer() // Nodes whose parents are layers can't be throttled 02644 ) 02645 { 02646 //TRACEUSER("Phil", _T("NRB:RenderCached throttling prevents capture %x %s %I64d %I64d\n"), this, this->GetRuntimeClass()->m_lpszClassName, pRender->GetStoredCount()*(INT64)20, pRender->GetTotalCount()); 02647 return FALSE; 02648 } 02649 //TRACEUSER("Phil", _T("NRB:RenderCached throttling allows capture %x %s %I64d %I64d\n"), this, this->GetRuntimeClass()->m_lpszClassName, pRender->GetStoredCount()*(INT64)20, pRender->GetTotalCount()); 02650 } 02651 02652 #if defined(_WIN32) 02653 // If we couldn't find or render a cached bitmap then try to cache a new one 02654 // Start timing of this cacheing overhead code 02655 LARGE_INTEGER countStart; 02656 LARGE_INTEGER countEnd; 02657 QueryPerformanceCounter(&countStart); 02658 #endif 02659 02660 double ScaledPixelWidth = pRender->GetScaledPixelWidth(); 02661 02662 // Work out how much of the object we propose to capture 02663 // (This may change during the Capture if we have to fall back to 24BPP opaque capture) 02664 DocRect viewrect = cliprect; 02665 DocRect CaptureRect = bounds; 02666 02667 // Only do stuff if the cliprect is at least half the size of the object 02668 if (cliprect.Width()>(bounds.Width()/2) && cliprect.Height()>(bounds.Height()/2)) 02669 { 02670 02671 View* pView = pRender->GetRenderView(); 02672 Spread* pSpread = pRender->GetRenderSpread(); 02673 if (pView && pSpread) 02674 { 02675 viewrect = pView->GetDocViewRect(pSpread); 02676 pSpread->DocCoordToSpreadCoord(&viewrect); 02677 if (!viewrect.IsValid() || !viewrect.ContainsRect(cliprect)) 02678 viewrect = cliprect; 02679 } 02680 CaptureRect = CaptureRect.Intersection(viewrect); // Proposed capture area is obj x viewport 02681 02682 if (CaptureRect.IsValid()) 02683 { 02684 // If we're nearly going to capture the whole object 02685 // (Compare area of bounding rect with area of view rect so that bitmap sizes don't get out of control) 02686 XLONG areaBounds = (XLONG)bounds.Width()*(XLONG)bounds.Height(); 02687 XLONG area2View = (XLONG)2*(XLONG)viewrect.Width()*(XLONG)viewrect.Height(); 02688 if (areaBounds < area2View) 02689 { 02690 // Then grab the whole thing 02691 // (Bounding Rect is small enough for us to capture the whole object ignoring clipping rect) 02692 CaptureRect = bounds; 02693 } 02694 02695 // Inflate by one pixel all round to allow for anti-aliasing effects at the edges 02696 CaptureRect.Inflate((INT32)ScaledPixelWidth); 02697 02698 UINT32 flagCoverage = 0; 02699 if (CaptureRect.ContainsRect(bounds)) 02700 flagCoverage = cfFULLCOVERAGE; 02701 02702 // Only cache if it's worth it! 02703 if (CaptureRect.Width()>=ScaledPixelWidth*4 || CaptureRect.Height()>=ScaledPixelWidth*4) 02704 { 02705 // It's quicker to scan ahead looking for non-mix transparency than to find it 02706 // half way through rendering a bitmap... 02707 //TRACEUSER("Phil", _T("NRB:RenderCached start capture %x %s\n"), this, this->GetRuntimeClass()->m_lpszClassName); 02708 CaptureFlags caFlags(flagCoverage | cfPIXWIDTHSCALE | (this->ContainsNonMixTransparency(pRender) ? cfGRABRENDERED : cfCOLLAPSETOMASTER | cfUNCLIP) ); 02709 pRender->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE); 02710 } 02711 } 02712 } 02713 02714 #if defined(_WIN32) 02715 // Add up time spent doing cacheing work and store it in the render region 02716 INT64 countCacheing = pRender->GetStoredCount(); 02717 QueryPerformanceCounter(&countEnd); 02718 countCacheing += countEnd.QuadPart-countStart.QuadPart; 02719 pRender->SetStoredCount(countCacheing); 02720 #endif 02721 02722 return FALSE; 02723 } 02724 02725 02726 02727 02728 /******************************************************************************************** 02729 02730 > virtual BOOL NodeRenderableBounded::CaptureCached(RenderRegion* pRender) 02731 02732 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02733 Created: 30/06/2004 02734 Returns: TRUE if captured data was cached 02735 Purpose: Protected Helper function 02736 Use the CaptureManager to capture the results of rendering, cache them 02737 and associate them with this Ink node 02738 SeeAlso: NodeRenderableBounded::RenderCached 02739 02740 ********************************************************************************************/ 02741 02742 BOOL NodeRenderableBounded::CaptureCached(RenderRegion* pRender) 02743 { 02744 // If cacheing is disabled bale out now! 02745 if (!NodeRenderableBounded::bEnableCacheing) 02746 return FALSE; 02747 02748 Capture* pCapture = pRender->GetTopCapture(); 02749 if (pCapture==NULL) // If nothing was captured 02750 return FALSE; // Then do nothing 02751 02752 // Only stop the capture if we started it 02753 // (means we only capture whole subtrees at the mo.) 02754 if (pCapture->GetOwner()==this) 02755 { 02756 #if defined(_WIN32) 02757 LARGE_INTEGER countStart; 02758 LARGE_INTEGER countEnd; 02759 QueryPerformanceCounter(&countStart); 02760 #endif 02761 02762 // End this capture: 02763 // Blit capture to screen 02764 // Retain bitmap because we will release it ourselves only if we fail to cache it 02765 BOOL bCached = FALSE; 02766 LPBITMAPINFO lpInfo = NULL; 02767 LPBYTE lpBits = NULL; 02768 DocRect CaptureRect = GetBoundingRect(); // Set maximum size we allow 02769 BOOL bFullCoverage = pCapture->HasFullCoverage(); 02770 pRender->StopCapture(this, TRUE, FALSE, &lpInfo, &lpBits, &CaptureRect); 02771 02772 // If the capture gave us back a bitmap, try to cache it 02773 if (lpInfo && lpBits && CaptureRect.IsValid()) 02774 { 02775 // If we can't find the cache then all is lost! 02776 CBitmapCache* pBitmapCache = Camelot.GetBitmapCache(); 02777 if (pBitmapCache) 02778 { 02779 double ScaledPixelWidth = pRender->GetScaledPixelWidth(); 02780 CBitmapCacheKey inky(this, ScaledPixelWidth); //GetScaledPixelWidthDouble? 02781 02782 CCachedBitmap cbmp; 02783 02784 cbmp.pbmpBits = lpBits; 02785 cbmp.pbmpInfo = lpInfo; 02786 cbmp.SetCachedRect(CaptureRect); 02787 cbmp.nPriority = CACHEPRIORITY_TEMPBITMAP_LOW; 02788 cbmp.bFullCoverage = bFullCoverage; 02789 02790 if (cbmp.IsValid()) 02791 { 02792 //TRACEUSER("Phil", _T("NRB:CaptureCached %x %s\n"), this, this->GetRuntimeClass()->m_lpszClassName); 02793 pBitmapCache->StoreBitmap(inky, cbmp); 02794 MayBeCached = TRUE; 02795 bCached = TRUE; 02796 } 02797 } 02798 } 02799 02800 // If we failed to cache the captured bitmap then release it 02801 if (lpInfo!=NULL && lpBits!=NULL && !bCached) 02802 { 02803 FreeDIB(lpInfo, lpBits, NULL, FALSE); 02804 } 02805 02806 INT64 countCacheing = pRender->GetStoredCount(); 02807 #if defined(_WIN32) 02808 QueryPerformanceCounter(&countEnd); 02809 countCacheing += countEnd.QuadPart-countStart.QuadPart; 02810 #endif 02811 pRender->SetStoredCount(countCacheing); 02812 02813 } 02814 02815 return TRUE; 02816 } 02817 02818 02819 02820 02821 /******************************************************************************************** 02822 02823 > virtual BOOL NodeRenderableBounded::ReleaseCached(BOOL bAndParents = TRUE, 02824 BOOL bAndChildren = TRUE, 02825 BOOL bSelf = TRUE, 02826 BOOL bAndDerived = TRUE) 02827 02828 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02829 Created: 30/06/2004 02830 Returns: TRUE if captured data was cached 02831 Purpose: Protected Helper function 02832 Use the CaptureManager to capture the results of rendering, cache them 02833 and associate them with this Ink node 02834 SeeAlso: NodeRenderableInk::RenderCached, CaptureCached 02835 02836 ********************************************************************************************/ 02837 02838 BOOL NodeRenderableBounded::ReleaseCached(BOOL bAndParents, BOOL bAndChildren, BOOL bSelf, BOOL bAndDerived) 02839 { 02840 if (MayBeCached) 02841 { 02842 BOOL bRemoveOpaqueBitmapsOnly = IsDragged(); // If we're being dragged, only remove opaque bmps 02843 BOOL bDidRemoveSome = FALSE; 02844 CBitmapCache* pBitmapCache = Camelot.GetBitmapCache(); 02845 if (pBitmapCache!=NULL && bSelf) 02846 { 02847 CBitmapCacheKey inky(this, 42); 02848 bDidRemoveSome = pBitmapCache->RemoveAllOwnedBitmaps(inky, bRemoveOpaqueBitmapsOnly); 02849 } 02850 02851 if (bDidRemoveSome && !bRemoveOpaqueBitmapsOnly) // If we know we removed all cached bitmaps 02852 MayBeCached = FALSE; // Then we can clear our maybe flag to optimise rendering 02853 } 02854 02855 // If we should release our children's caches as well... 02856 if (bAndChildren) 02857 { 02858 Node* pChild = FindFirstChild(); 02859 while (pChild) 02860 { 02861 if (pChild->IsBounded()) 02862 ((NodeRenderableBounded*)pChild)->ReleaseCached(FALSE, TRUE, TRUE, TRUE); 02863 02864 pChild = pChild->FindNext(); 02865 } 02866 } 02867 02868 // If I can't be cached, neither can my parent... 02869 if (bAndParents && FindParent() && FindParent()->IsBounded()) 02870 ((NodeRenderableBounded*)FindParent())->ReleaseCached(TRUE, FALSE, TRUE, TRUE); 02871 02872 return TRUE; 02873 } 02874 02875 02876 02877 02878 /******************************************************************************************** 02879 02880 > virtual void NodeRenderableBounded::CopyCached(NodeRenderableBounded* pCopyOfNode, double dRes, INT32 maxOption = 0) 02881 02882 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02883 Created: 22/10/2004 02884 Returns: - 02885 Purpose: Copy fixed res cached bitmaps associated with this node to be associated 02886 with the specified new node 02887 SeeAlso: NodeRenderableInk::RenderCached, CaptureCached 02888 02889 ********************************************************************************************/ 02890 02891 void NodeRenderableBounded::CopyCached(NodeRenderableBounded* pCopyOfNode, double dRes, INT32 maxOption) 02892 { 02893 CBitmapCache* pBitmapCache = Camelot.GetBitmapCache(); 02894 02895 INT32 i = 0; 02896 for (i = 0; i<=maxOption; i++) 02897 { 02898 // Copy the cached bitmap 02899 CCachedBitmap cbmp; 02900 CBitmapCacheKey inky(this, dRes, i); 02901 CBitmapCacheKey inkycopy(pCopyOfNode, dRes, i); 02902 BOOL bFound = pBitmapCache->Lookup(inky, cbmp); 02903 if (bFound) 02904 { 02905 cbmp = cbmp.Copy(); 02906 pBitmapCache->StoreBitmap(inkycopy, cbmp); 02907 } 02908 } 02909 pCopyOfNode->MayBeCached = TRUE; 02910 } 02911 02912 02913 02914 02915 /******************************************************************************************** 02916 02917 > virtual void NodeRenderableBounded::CopyCached(NodeRenderableBounded* pCopyOfNode) 02918 02919 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02920 Created: 22/10/2004 02921 Returns: - 02922 Purpose: Copy all cached bitmaps associated with this node to be associated 02923 with the specified new node 02924 SeeAlso: NodeRenderableInk::RenderCached, CaptureCached 02925 02926 ********************************************************************************************/ 02927 02928 void NodeRenderableBounded::CopyCached(NodeRenderableBounded* pCopyOfNode) 02929 { 02930 CBitmapCache* pBitmapCache = Camelot.GetBitmapCache(); 02931 02932 CBitmapCacheKey inky(this, 42); 02933 CCacheKeyMap::iterator pos = pBitmapCache->GetStartPosition(); 02934 CCachedBitmap abitmap = pBitmapCache->FindNextOwnedBitmap(pos, inky); 02935 pCopyOfNode->MayBeCached = FALSE; 02936 while (abitmap.IsValid()) 02937 { 02938 CCachedBitmap copybitmap = abitmap.Copy(); 02939 CBitmapCacheKey copyinky(inky); 02940 copyinky.SetOwner(pCopyOfNode); 02941 pBitmapCache->StoreBitmap(copyinky, copybitmap); 02942 02943 pCopyOfNode->MayBeCached = TRUE; 02944 02945 abitmap = pBitmapCache->FindNextOwnedBitmap(pos, inky); 02946 } 02947 } 02948 02949 02950 02951 02952 /******************************************************************************************** 02953 02954 > virtual void NodeRenderableBounded::TransformCached(TransformBase& Trans, double dTestPixelWidth) 02955 02956 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02957 Created: 22/10/2004 02958 Inputs: Trans - Transformation 02959 dPixelWidth - PixelWidth to be tested specifically to control Trans.bHaveTransformedCached 02960 Returns: - 02961 Purpose: Transform all the cached bitmaps associated with this node 02962 SeeAlso: NodeRenderableInk::RenderCached, CaptureCached 02963 02964 ********************************************************************************************/ 02965 02966 void NodeRenderableBounded::TransformCached(TransformBase& Trans, double dTestPixelWidth) 02967 { 02968 // If cacheing is disabled bale out now! 02969 if (!NodeRenderableBounded::bEnableCacheing) 02970 { 02971 MayBeCached = FALSE; 02972 Trans.bHaveTransformedCached = FALSE; 02973 Trans.bTransformYourChildren = TRUE; 02974 return; 02975 } 02976 02977 CBitmapCache* pBitmapCache = Camelot.GetBitmapCache(); 02978 02979 CBitmapCacheKey inky(this, 42); 02980 CCacheKeyMap::iterator pos = pBitmapCache->GetStartPosition(); 02981 CCachedBitmap abitmap = pBitmapCache->FindNextOwnedBitmap(pos, inky); 02982 MayBeCached = abitmap.IsValid(); // Update MayBeCached here because we can 02983 BOOL bTransformedTested = FALSE; 02984 while (abitmap.IsValid()) 02985 { 02986 abitmap.Transform(Trans); 02987 pBitmapCache->StoreBitmap(inky, abitmap); 02988 02989 if (inky.GetPixelWidth() == dTestPixelWidth && abitmap.IsTransparent()) 02990 bTransformedTested = TRUE; 02991 02992 abitmap = pBitmapCache->FindNextOwnedBitmap(pos, inky); 02993 } 02994 02995 // We can only continue to transform cached things if all our bitmaps are transparent (32BPP) 02996 // And if we actually had some cached data to transform 02997 if (!bTransformedTested) 02998 { 02999 Trans.bHaveTransformedCached = FALSE; 03000 Trans.bTransformYourChildren = TRUE; 03001 } 03002 } 03003 03004 03005 03006 03007 /******************************************************************************************** 03008 03009 > virtual void NodeRenderableBounded::RenderEffectAttributes(RenderRegion* pRegion) 03010 03011 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03012 Created: 05/01/2005 03013 Returns: - 03014 Purpose: Render any effect attributes attached to this node 03015 SeeAlso: - 03016 03017 ********************************************************************************************/ 03018 03019 void NodeRenderableBounded::RenderEffectAttributes(RenderRegion* pRegion) 03020 { 03021 Node* pNode = FindLastChild(CC_RUNTIME_CLASS(NodeRenderableBounded)); 03022 while (pNode) 03023 { 03024 pNode = pNode->FindNext(); 03025 if (pNode && pNode->IsAnAttribute()) 03026 { 03027 pNode->Render(pRegion); 03028 } 03029 } 03030 } 03031 03032 03033 03034 03035 /******************************************************************************************** 03036 03037 > virtual void NodeRenderableInk::RenderEorDrag( RenderRegion* pRender ) 03038 03039 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03040 Created: 22/10/93 03041 Inputs: pRender - A pointer to a render region to draw in 03042 Purpose: Each class derived from NodeRenderableInk should write a version 03043 of this member function. In most cases it will be the same as the 03044 Render() member function but some of the nodes (such as groups) 03045 need to perform special actions. The function is for drawing the 03046 object while it is being dragged about by the selector tool. It 03047 should do this with an effective wysiwyg level of 0 so that the 03048 drawing is fast. 03049 03050 ********************************************************************************************/ 03051 03052 void NodeRenderableInk::RenderEorDrag( RenderRegion* pRender ) 03053 { 03054 // This function does nothing. It is a virtual function and should be replaced by 03055 // derived class versions of it 03056 } 03057 03058 03059 /******************************************************************************************** 03060 03061 > void NodeRenderableInk::RenderEorDragChildren(RenderRegion * pRender) 03062 03063 Author: David_McClarnon (Xara Group Ltd) <camelotdev@xara.com> 03064 Created: 19/1/2000 03065 Inputs: pRender - Render region to use 03066 03067 Purpose: Recursively calls RenderEorDrag for all children of this node, 03068 ignoring nodes which have ChildrenAreEorDragRenderedByMe() returning TRUE 03069 SeeAlso: NodeRenderableInk::RenderEorDrag, 03070 NodeRenderableInk::ChildrenAreEorDragRenderedByMe 03071 03072 ********************************************************************************************/ 03073 void NodeRenderableInk::RenderEorDragChildren(RenderRegion * pRender) 03074 { 03075 Node * pNode = FindFirstChild(); 03076 03077 while (pNode) 03078 { 03079 if (pNode->IsAnObject()) 03080 { 03081 if (pNode->IsCompound()) 03082 { 03083 if (((NodeRenderableInk *)pNode)->ChildrenAreEorDragRenderedByMe()) 03084 { 03085 // just render this node 03086 ((NodeRenderableInk *)pNode)->RenderEorDrag(pRender); 03087 } 03088 else 03089 { 03090 ((NodeRenderableInk *)pNode)->RenderEorDragChildren(pRender); 03091 ((NodeRenderableInk *)pNode)->RenderEorDrag(pRender); 03092 } 03093 } 03094 else 03095 { 03096 ((NodeRenderableInk *)pNode)->RenderEorDrag(pRender); 03097 } 03098 } 03099 03100 pNode = pNode->FindNext(); 03101 } 03102 } 03103 03104 /******************************************************************************************** 03105 03106 > void NodeRenderableInk::ClearSubSelection( BOOL ReDraw ) 03107 03108 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03109 Created: 4/11/93 03110 Inputs: ReDraw - TRUE if the selection should be redrawn 03111 Purpose: Goes through the object and clears the selection state of all its blobs. eg 03112 a selected path has blobs and each of these blobs can be selected. This 03113 clears the blobs selection BUT not the objects selection! 03114 03115 ********************************************************************************************/ 03116 03117 void NodeRenderableInk::ClearSubSelection( BOOL ReDraw ) 03118 { 03119 // Base class does nothing 03120 } 03121 03122 03123 /******************************************************************************************** 03124 03125 > void NodeRenderableInk::RenderFillBlobs(RenderRegion* pRender) 03126 03127 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03128 Created: 24/6/94 03129 Inputs: pRender - The region to render the blobs into 03130 Purpose: Draws the Fill blobs of an ink object. It does this by calling all the 03131 attributes that are its immediate children and asking them to render their 03132 Fill Blobs. If any of them happen to be items such as Graduated fills, then 03133 blobs will appear 03134 03135 ********************************************************************************************/ 03136 03137 //void NodeRenderableInk::RenderFillBlobs(RenderRegion* pRender) 03138 //{ 03139 //} 03140 03141 void NodeRenderableInk::RenderAppliedFillBlobs(RenderRegion* pRender) 03142 { 03143 #if !defined(EXCLUDE_FROM_RALPH) 03144 CCAttrMap* pAttribMap = new CCAttrMap(30); 03145 if (pAttribMap == NULL) 03146 return; 03147 03148 // Find the topmost effect applied to this node 03149 // So that we can test whether it has preferential effect attributes 03150 Node* pEffectNode = FindParent(); 03151 NodeEffect* pTopEffectNode = NULL; 03152 while (pEffectNode && pEffectNode->IsEffect()) 03153 { 03154 // BODGE! we happen to know that shadow controllers can't have effect attrs applied to them 03155 // Would be better of there were some nice way to ask effect nodes about this. 03156 if (!pEffectNode->IsAShadowController()) 03157 pTopEffectNode = (NodeEffect*)pEffectNode; 03158 pEffectNode = pEffectNode->FindParent(); 03159 } 03160 03161 // Now find any attributes that are applied to this node. 03162 BOOL FoundAttrs = FindAppliedAttributes(pAttribMap, 5000, NULL, FALSE); 03163 03164 if (FoundAttrs) 03165 { 03166 // iterating all (key, value) pairs 03167 for (CCAttrMap::iterator Pos = pAttribMap->GetStartPosition(); Pos != pAttribMap->GetEndPosition();) 03168 { 03169 CCRuntimeClass *pType; 03170 void *pVal; 03171 pAttribMap->GetNextAssoc(Pos,pType,pVal); 03172 NodeAttribute* pAttr = (NodeAttribute*)pVal; 03173 03174 // Only render fill blobs for the applied attribute if it can't 03175 // be overridden by a preferential effect attribute above... 03176 if (pTopEffectNode==NULL || (pTopEffectNode!=NULL && !pTopEffectNode->IsValidEffectAttr(pAttr))) 03177 pAttr->RenderFillBlobs(pRender); 03178 } 03179 } 03180 03181 delete pAttribMap; 03182 #endif 03183 } 03184 03185 03186 /******************************************************************************************** 03187 03188 > void NodeRenderableInk::RenderEffectBlobs(RenderRegion* pRender) 03189 03190 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03191 Created: 07/01/2005 03192 Inputs: pRender - The region to render the blobs into 03193 Purpose: Draws the Effect blobs of an ink object. It does this by calling all the 03194 attributes that are its immediate children and asking them to render their 03195 Fill Blobs. If any of them happen to be items such as Graduated fills, then 03196 blobs will appear 03197 03198 ********************************************************************************************/ 03199 03200 void NodeRenderableInk::RenderEffectBlobs(RenderRegion* pRender) 03201 { 03202 #if !defined(EXCLUDE_FROM_RALPH) 03203 Node* pEffectNode = FindParent(); 03204 Node* pTopEffectNode = NULL; 03205 03206 while (pEffectNode && pEffectNode->IsEffect()) 03207 { 03208 // BODGE! we happen to know that shadow controllers can't have effect attrs applied to them 03209 // Would be better of there were some nice way to ask effect nodes about this. 03210 if (!pEffectNode->IsAShadowController()) 03211 pTopEffectNode = pEffectNode; 03212 pEffectNode = pEffectNode->FindParent(); 03213 } 03214 03215 if (pTopEffectNode && pTopEffectNode->IsBounded()) 03216 { 03217 if (pTopEffectNode!=this) 03218 ((NodeRenderableBounded*)pTopEffectNode)->RenderEffectBlobs(pRender); 03219 03220 // Allow any effect attributes to render their blobs... 03221 NodeAttribute* pAttr = (NodeAttribute*)pTopEffectNode->FindLastChild(CC_RUNTIME_CLASS(NodeAttribute)); 03222 while (pAttr && pAttr->IsEffectAttribute()) 03223 { 03224 pAttr->RenderFillBlobs(pRender); 03225 03226 pAttr = (NodeAttribute*)pAttr->FindPrevious(CC_RUNTIME_CLASS(NodeAttribute)); 03227 } 03228 } 03229 #endif 03230 } 03231 03232 03233 /******************************************************************************************** 03234 03235 > void NodeRenderableInk::RenderArtisticBlobs(RenderRegion* pRender) 03236 03237 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03238 Created: 24/6/94 03239 Inputs: pRender - The region to render the blobs into 03240 Purpose: Draws the Artistic blobs of an ink object. It does this by calling all the 03241 attributes that are its immediate children and asking them to render their 03242 Artistic Blobs. If any of them happen to be items such as Pressure attributes 03243 or some other artistic effect then blobs will appear. 03244 03245 ********************************************************************************************/ 03246 03247 void NodeRenderableInk::RenderArtisticBlobs(RenderRegion* pRender) 03248 { 03249 #if !defined(EXCLUDE_FROM_RALPH) 03250 CCAttrMap* pAttribMap = new CCAttrMap(30); 03251 if (pAttribMap == NULL) 03252 return; 03253 03254 // Now find any attributes that are applied to this node. 03255 BOOL FoundAttrs = FindAppliedAttributes(pAttribMap); 03256 03257 if (FoundAttrs) 03258 { 03259 // iterating all (key, value) pairs 03260 for (CCAttrMap::iterator Pos = pAttribMap->GetStartPosition(); Pos != pAttribMap->GetEndPosition();) 03261 { 03262 CCRuntimeClass *pType; 03263 void *pVal; 03264 pAttribMap->GetNextAssoc(Pos,pType,pVal); 03265 03266 NodeAttribute* pAttr = (NodeAttribute*)pVal; 03267 pAttr->RenderArtisticBlobs(pRender); 03268 } 03269 } 03270 03271 delete pAttribMap; 03272 #endif 03273 } 03274 03275 03276 03277 03278 /*********************************************************************************************** 03279 > Node* NodeRenderableInk::SimpleCopy() 03280 03281 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03282 Created: 28/4/93 03283 Returns: A copy of the node, or NULL if memory runs out 03284 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 03285 The function is virtual, and must be defined for all derived classes. 03286 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 03287 error and the function returns NULL. 03288 Scope: protected 03289 **********************************************************************************************/ 03290 03291 Node* NodeRenderableInk::SimpleCopy() 03292 { 03293 NodeRenderableInk* NodeCopy; 03294 NodeCopy = new NodeRenderableInk(); 03295 if (NodeCopy) 03296 NodeRenderableBounded::CopyNodeContents(NodeCopy); 03297 return (NodeCopy); 03298 } 03299 03300 03301 /******************************************************************************************** 03302 03303 > virtual BOOL NodeRenderableInk::OnClick( DocCoord PointerPos, ClickType Click, 03304 ClickModifiers ClickMods ) 03305 03306 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03307 Created: 13/10/93 03308 Inputs: PointerPos - The Location of the mouse pointer at the time of the click 03309 Click - The type of click received (single, double, drag etc) 03310 ClickMods - The modifiers to the click (eg shift, control etc ) 03311 Returns: BOOL - TRUE if the node claims the click as its own and FLASE if it is 03312 not interested in the click 03313 Purpose: Allows the Node to respond to clicks by selecting its blobs or starting 03314 drags etc. 03315 03316 This function should be overridden in the all the NodeRenderableInk classes 03317 so that this verion never gets called. Eg the NodePath class might claim 03318 the click if it happened over one of its unselected blobs. 03319 03320 Karim 07/04/2000 03321 With the advent of ToolObject blobs, this method can now be called when 03322 Object blobs are not showing. What this means is that when this method is 03323 called, you should *check* that conditions are right for you to respond. 03324 eg if BlobManager's current interest does not include Object blobs, you 03325 may not want to do anything. 03326 03327 ********************************************************************************************/ 03328 03329 BOOL NodeRenderableInk::OnClick( DocCoord PointerPos, ClickType Click, 03330 ClickModifiers ClickMods, Spread *pSpread ) 03331 { 03332 // we do not want to claim the click, so return FALSE 03333 return FALSE; 03334 } 03335 03336 03337 03338 03339 /******************************************************************************************** 03340 03341 > virtual BOOL NodeRenderableInk::OnBlobPopUp(Spread* pSpread, 03342 DocCoord PointerPos, 03343 ContextMenu* pMenu 03344 ) 03345 03346 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03347 Created: 09/04/95 03348 Inputs: pSpread The spread in which the action's occuring 03349 PointerPos The Location of the mouse pointer at the time of the click 03350 pMenu The menu to which items should be added 03351 Returns: BOOL - TRUE if the node claims the click as its own and FALSE if it is 03352 not interested in the click 03353 Purpose: Allows the Node to respond to popup menu clicks by adding items to the popup 03354 menu if required. It also allows the node to prevent the menu appearing at all! 03355 This functions should be overridden in the all the NodeRenderableInk classes 03356 so that this verion never gets called. Eg the NodePath class might claim 03357 the click if it happened over one of its blobs. 03358 03359 ********************************************************************************************/ 03360 03361 03362 BOOL NodeRenderableInk::OnBlobPopUp(Spread* pSpread, 03363 DocCoord PointerPos, 03364 ContextMenu* pMenu 03365 ) 03366 { 03367 // we do not want to claim the click, so return FALSE 03368 return FALSE; 03369 } 03370 03371 03372 03373 03374 /******************************************************************************************** 03375 03376 > virtual BOOL NodeRenderableInk::OnNodePopUp(Spread* pSpread, 03377 DocCoord PointerPos, 03378 ContextMenu* pMenu 03379 ) 03380 03381 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03382 Created: 09/04/95 03383 Inputs: pSpread The spread in which the action's occuring 03384 PointerPos The Location of the mouse pointer at the time of the click 03385 pMenu The menu to which items should be added 03386 Returns: BOOL - TRUE if the node claims the click as its own and FALSE if it is 03387 not interested in the click 03388 Purpose: Allows the Node to respond to popup menu clicks by adding items to the popup 03389 menu if required. It also allows the node to prevent the menu appearing at all! 03390 This functions should be overridden in the all the NodeRenderableInk classes 03391 so that this verion never gets called. Eg the NodePath class might claim 03392 the click if it happened over one of its blobs. 03393 03394 ********************************************************************************************/ 03395 03396 03397 BOOL NodeRenderableInk::OnNodePopUp(Spread* pSpread, 03398 DocCoord PointerPos, 03399 ContextMenu* pMenu 03400 ) 03401 { 03402 // we do not want to claim the click, so return FALSE 03403 return FALSE; 03404 } 03405 03406 03407 03408 03409 /******************************************************************************************** 03410 03411 > BOOL NodeRenderableInk::CalculatePathBoundingRect(Path& BoundPath, BOOL DontUseAttrs, 03412 DocRect* pRect) 03413 03414 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03415 Created: 19/9/94 03416 Inputs: BoundPath - The path to calculate the bounding rectangle of 03417 DontUseAtrrs - TRUE if we do not want to apply the attributes to the path 03418 when calculating its bounds 03419 Outputs: pRect - Will hold the paths bounding rect if everything worked 03420 Returns: TRUE if it worked, FALSE if it failed 03421 Purpose: Calculates the bounding rectangle of a path using GDraw. It will optionally 03422 go and find all the attributes that are applied to the path and tell GDraw 03423 about these as well (this is the normal way of using it) 03424 It can make up sone default attributes if needed as well. This will assume 03425 that the path is to be stroked as thin as possible. 03426 Errors: GDraw can fail when calculating bounding rects, so beware 03427 SeeAlso: NodeRenderableBounded::GetBoundingRect 03428 03429 ********************************************************************************************/ 03430 03431 BOOL NodeRenderableInk::CalculatePathBoundingRect(Path& BoundPath, 03432 BOOL DontUseAttrs, DocRect* pRect) 03433 { 03434 // Check and initialise output. 03435 ERROR3IF(pRect == 0, "NodeRenderableInk::CalculatePathBoundingRect: null output"); 03436 pRect->MakeEmpty(); 03437 03438 // Something to put the new bounding rect into 03439 DocRect NewBoundingRect; 03440 BOOL GDrawResult = TRUE; 03441 GDrawContext *GD = GRenderRegion::GetStaticDrawContext(); 03442 03443 if (GD == NULL) 03444 return(FALSE); 03445 03446 // do we need to use the attrs 03447 if (DontUseAttrs) 03448 { 03449 // here we are not interested in the attributes 03450 // Find out what the paths bounding rect is now 03451 RECT rectTmp; 03452 GDrawResult = GD->CalcStrokeBBox((POINT*)BoundPath.GetCoordArray(), 03453 BoundPath.GetVerbArray(), BoundPath.GetNumCoords(), 03454 &rectTmp, 03455 BoundPath.IsFilled, 0, CAPS_ROUND, JOIN_ROUND, NULL); 03456 if ( rectTmp.left>rectTmp.right || rectTmp.top>rectTmp.bottom ) 03457 return false; 03458 NewBoundingRect = DocRect( rectTmp.left, rectTmp.top, rectTmp.right, rectTmp.bottom ); 03459 } 03460 else 03461 { 03462 // First find all attributes applied to this node... 03463 // 30 is a default value - this will grow if it needs more space 03464 CCAttrMap AttribMap(30); 03465 if (FindAppliedAttributes(&AttribMap)) 03466 { 03467 void* pLineColour = NULL; 03468 AttribMap.Lookup( CC_RUNTIME_CLASS(AttrStrokeColour),pLineColour); 03469 03470 if (pLineColour && (*((AttrStrokeColour*)pLineColour)->GetStartColour() == COLOUR_NONE) || 03471 !BoundPath.IsStroked) 03472 { 03473 // This path is not stroked, so we won't bother with any of the attributes 03474 // applied to it 03475 RECT rectTmp; 03476 GDrawResult = GD->CalcStrokeBBox((POINT*)BoundPath.GetCoordArray(), 03477 BoundPath.GetVerbArray(), BoundPath.GetNumCoords(), 03478 &rectTmp, 03479 BoundPath.IsFilled, 0, CAPS_ROUND, JOIN_ROUND, NULL); 03480 if ( rectTmp.left>rectTmp.right || rectTmp.top>rectTmp.bottom ) 03481 return false; 03482 NewBoundingRect = DocRect( rectTmp.left, rectTmp.top, rectTmp.right, rectTmp.bottom ); 03483 03484 } 03485 else 03486 { 03487 // Extract the info we need from the applied attributes 03488 void* pLineWidth = NULL; 03489 AttribMap.Lookup( CC_RUNTIME_CLASS(AttrLineWidth),pLineWidth); 03490 ENSURE(pLineWidth,"NodePath::GetBoundingRect can't find LineWidth"); 03491 03492 // if we did not get a line width, fail 03493 if (!pLineWidth) 03494 return FALSE; 03495 03496 // The Start cap 03497 void* pStartCap = NULL; 03498 AttribMap.Lookup( CC_RUNTIME_CLASS(AttrStartCap),pStartCap); 03499 #ifdef _DEBUG 03500 if (pStartCap == 0) 03501 TRACE( _T("NodeRenderableInk::CalculatePathBoundingRect: can't find StartCap\n")); 03502 #endif 03503 03504 // The join style 03505 void* pJoinType = NULL; 03506 AttribMap.Lookup( CC_RUNTIME_CLASS(AttrJoinType),pJoinType); 03507 #ifdef _DEBUG 03508 if (pJoinType == 0) 03509 TRACE( _T("NodeRenderableInk::CalculatePathBoundingRect: can't find JoinType\n")); 03510 #endif 03511 if(pStartCap != NULL && pJoinType != NULL && pLineWidth != NULL) 03512 { 03513 // Now pass those values to Gavin along with the path for a bounds calculation 03514 RECT rectTmp; 03515 GDrawResult = GD->CalcStrokeBBox((POINT*)BoundPath.GetCoordArray(), 03516 BoundPath.GetVerbArray(), BoundPath.GetNumCoords(), 03517 &rectTmp, 03518 BoundPath.IsFilled, 03519 ((AttrLineWidth*)pLineWidth)->Value.LineWidth, 03520 (CapStyles)((AttrStartCap*)pStartCap)->Value.StartCap, 03521 (JoinStyles)((AttrJoinType*)pJoinType)->Value.JoinType, 03522 NULL //Pointer to dash pattern attribute 03523 ); 03524 if ( rectTmp.left>rectTmp.right || rectTmp.top>rectTmp.bottom ) 03525 return false; 03526 NewBoundingRect = DocRect( rectTmp.left, rectTmp.top, rectTmp.right, rectTmp.bottom ); 03527 } 03528 } 03529 } 03530 } 03531 03532 // Make sure Gavin did not screw up. 03533 if (!NewBoundingRect.IsValid()) 03534 // Set it to TRUE, as this means it went wrong in Gavin Talk. 03535 GDrawResult = TRUE; 03536 03537 // see if GDraw worked (It returns FALSE when it works!) 03538 if (GDrawResult == FALSE) 03539 { 03540 // update the rectangle 03541 *pRect = NewBoundingRect; 03542 return TRUE; 03543 } 03544 03545 // to get here, something must have failed 03546 return FALSE; 03547 } 03548 03549 03550 03551 03553 // Selection Members 03554 03555 /******************************************************************************************** 03556 03557 > void NodeRenderableInk::DeselectAll(BOOL RenderBlobs = TRUE, BOOL InformImmediate = TRUE) 03558 03559 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 03560 Created: 15/9/93 03561 Inputs: RenderBlobs: Should blobs be rendered 03562 InformImmediate - TRUE if the SelChanged message should be broadcast immediatly 03563 FALSE if it should be saved until the end of the operation 03564 Purpose: Deselects all the selected objects in the tree, leaving camelot with 03565 nothing selected. It also removes the EORed blobs of the objects that 03566 were selected at the time of the call 03567 03568 ********************************************************************************************/ 03569 03570 void NodeRenderableInk::DeselectAll(BOOL RenderBlobs, BOOL InformImmediate) 03571 { 03572 // Find the selected objects in the tree; 03573 SelRange* Selected = GetApplication()->FindSelection(); 03574 ENSURE( Selected!=NULL, "Selection object is null in DeselectAll()"); 03575 03576 // Find first selected node 03577 Node* pFirstSelectedNode = Selected->FindFirst(); 03578 03579 // If there is a selection, EOR blobs off, deselect nodes, and inform everybody 03580 if (pFirstSelectedNode != NULL) 03581 { 03582 // Go though and render all the EOR blobs off the screen 03583 if (RenderBlobs) 03584 { 03585 // Find the Blob Manager 03586 BlobManager* BlobMgr = GetApplication()->GetBlobManager(); 03587 ENSURE( BlobMgr!=NULL, "Blob Manager unexpectedly not there."); 03588 03589 // Render all the blobs 03590 BlobMgr->RenderOff(NULL, pFirstSelectedNode->FindParentSpread()); 03591 } 03592 03593 // and clear the object selection 03594 Node* pNode = pFirstSelectedNode; 03595 while(pNode) 03596 { 03597 // Deselect the object 03598 //ENSURE( pNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderable)), "Selected Node not renderable"); 03599 //((NodeRenderable*)pNode)->DeSelect(FALSE); 03600 if (pNode->IsNodePath()) 03601 ((NodePath*)pNode)->InkPath.ClearSubSelection(); 03602 03603 /* 03604 // DMc 03605 // Deselect all nodes under node 03606 Node * pSubNode = pNode->FindFirstDepthFirst(); 03607 03608 while (pSubNode) 03609 { 03610 pSubNode->SetSelected(FALSE); 03611 03612 if (pSubNode->IsNodePath()) 03613 { 03614 ((NodePath*)pSubNode)->InkPath.ClearSubSelection(); 03615 } 03616 03617 pSubNode = pSubNode->FindNextDepthFirst(pNode); 03618 } 03619 */ 03620 03621 // Deselect the node itself 03622 pNode->SetSelected(FALSE); 03623 03624 // Find the next node 03625 pNode = Selected->FindNext(pNode); 03626 } 03627 03628 // Selection cache is no longer valid, so update and tell everyone that it has changed 03629 Selected->Update(InformImmediate); 03630 } 03631 } 03632 03633 /******************************************************************************************** 03634 03635 > NodeRenderableInk::DeselectAllOnLayer(Layer* Layer) 03636 03637 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03638 Created: 21/1/94 03639 Inputs: Layer: The layer on which to deselect objects 03640 Purpose: Same as DeselectAll except that it only deselects objects on Layer 03641 SeeAlso: NodeRenderableInk::DeselectAll 03642 03643 ********************************************************************************************/ 03644 03645 void NodeRenderableInk::DeselectAllOnLayer(Layer* Layer) 03646 { 03647 #if !defined(EXCLUDE_FROM_RALPH) 03648 ERROR3IF(Layer == NULL,"Layer == NULL"); 03649 if (Layer == NULL) return; 03650 03651 ERROR3IF(Layer->FindParent() == NULL,"Layer has no parent"); 03652 if (Layer->FindParent() == NULL) return; 03653 03654 ERROR3IF(!IS_A(Layer->FindParent(),Spread),"The parent of a layer was not a spread"); 03655 if (!IS_A(Layer->FindParent(),Spread)) return; 03656 03657 // if the layer has no children, return immediately (otherwise the range screws things up by 03658 // giving nodes from other layers to deselect) - MarkN 11/1/95 03659 if (Layer->FindFirstChild() == NULL) return; 03660 03661 // Find the layer's spread 03662 Spread *pSpread = (Spread*)Layer->FindParent(); 03663 03664 // Set up a range of the selected object in this layer 03665 // RangeControl rc = { TRUE, FALSE }; 03666 Range SelectedRange(Layer->FindFirstChild(),NULL,RangeControl(TRUE,FALSE)); 03667 Node* CurrentNode = SelectedRange.FindFirst(); 03668 03669 // See if there was anything selected in the first place 03670 if (CurrentNode != NULL) 03671 { 03672 // Go and find the Blob Manager 03673 BlobManager* BlobMgr = GetApplication()->GetBlobManager(); 03674 ENSURE( BlobMgr!=NULL, "There is no blob manager - Impossible!"); 03675 if (BlobMgr==NULL) return; 03676 03677 // Go through all the regions and rub out all the blobs 03678 RenderRegion* pRegion = DocView::RenderOnTop( NULL, pSpread, ClippedEOR ); 03679 while (pRegion) 03680 { 03681 // Find out the rect for this render region 03682 DocRect Rect = pRegion->GetRegionRect(); 03683 if ( (Rect.IsValid()) && (!Rect.IsEmpty()) ) 03684 { 03685 // Find the first node in the selection range 03686 CurrentNode = SelectedRange.FindFirst(); 03687 03688 // Find all the selected nodes in the tree 03689 while (CurrentNode != NULL) 03690 { 03691 // Rub the blobs off the screen for this node in this region 03692 ENSURE( CurrentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderable)), "Node was not renderbale"); 03693 BlobMgr->RenderMyBlobs(&Rect, pSpread, (NodeRenderable*)CurrentNode); 03694 03695 // Find the next selected object on the layer 03696 CurrentNode = SelectedRange.FindNext(CurrentNode); 03697 } 03698 } 03699 03700 // Thats all the bits deselected for that render region, give me the next one please 03701 pRegion = DocView::GetNextOnTop( NULL ); 03702 } 03703 03704 // Now go though the selected nodes on the layer and deselect them 03705 CurrentNode = SelectedRange.FindFirst(); 03706 while (CurrentNode != NULL) 03707 { 03708 // Make it unselected 03709 //((NodeRenderable*)CurrentNode)->DeSelect( FALSE ); 03710 CurrentNode->SetSelected(FALSE); 03711 03712 // and find the next one 03713 CurrentNode = SelectedRange.FindNext(CurrentNode); 03714 } 03715 03716 // Selection cache is no longer valid 03717 GetApplication()->Selection->Update(TRUE); 03718 } 03719 #endif 03720 } 03721 03722 03723 03724 /******************************************************************************************** 03725 > void NodeRenderableInk::SelectAllInRect(DocRect Rect, Spread* pSpread, 03726 NodeRenderableInk::SelStateAction st = SET) 03727 03728 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> / JustinF 03729 Created: 15/9/93 03730 Inputs: Rect - The Rectangle to act as a bounding box for the selection 03731 Spread - The spread on which to select the objects 03732 st - either CLEAR, SET, or TOGGLE, which is what should be done to 03733 the selection state of each object within the rectangle. 03734 Purpose: Selects all the objects that are wholly inside the supplied rectangle. 03735 It will draw in all the EORed blobs of the objects that it selects/deselects. 03736 rewritten by Simon so that objects on locked layers do not get selected 03737 also more optimal. 03738 (st parameter etc added by JCF 1.11.94) 03739 SeeAlso: NodeRenderableInk::DeselectAll 03740 ********************************************************************************************/ 03741 03742 void NodeRenderableInk::SelectAllInRect(DocRect Rect, Spread* pSpread, 03743 NodeRenderableInk::SelStateAction st) 03744 { 03745 // Make sure we are not being told garbage 03746 ERROR3IF(pSpread == NULL, "No spread in NodeRenderableInk::SelectAllInRect"); 03747 ERROR3IF(pSpread->FindFirstLayer() == NULL, "No layer in NodeRenderableInk::SelectAllInRect"); 03748 03749 03750 // Make all objects on modifiable layers within the given bounding box selected or 03751 // whatever. 03752 for (Layer* pLayer = pSpread->FindFirstLayer(); 03753 pLayer != NULL; 03754 pLayer = pLayer->FindNextLayer()) 03755 { 03756 if (!pLayer->IsLocked() && pLayer->IsVisible() && 03757 pLayer->GetBoundingRect().IsIntersectedWith(Rect)) 03758 { 03759 // The current layer is not locked so select all objects which intersect 03760 // with rect 03761 /* Range rng(pLayer->FindFirstChild(), NULL, RangeControl(TRUE, TRUE)); 03762 for (Node* pNode = rng.FindFirst(); 03763 pNode != NULL; 03764 pNode = rng.FindNext(pNode)) 03765 { 03766 // make sure it is a Renderable Ink Node 03767 if (pNode->IsAnObject()) 03768 { 03769 ((NodeRenderableInk*)pNode)->SelectInRect(Rect, st); 03770 } 03771 } 03772 */ 03773 Node* pNode = pLayer->FindFirstChild(); 03774 while (pNode) 03775 { 03776 // make sure it is a Renderable Ink Node 03777 if (pNode->IsAnObject()) 03778 { 03779 ((NodeRenderableInk*)pNode)->SelectInRect(Rect, st); 03780 } 03781 03782 pNode = pNode->FindNext(); 03783 } 03784 03785 } 03786 } 03787 03788 // Update the selection cache 03789 GetApplication()->UpdateSelection(); 03790 } 03791 03792 03793 03794 /******************************************************************************************** 03795 03796 > virtual void NodeRenderableInk::SelectInRect(const DocRect& Rect, SelStateAction st) 03797 03798 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03799 Created: 14 April 2000 03800 Inputs: Rect const reference to the bounding rect to use. 03801 st the selection state, ie SET/TOGGLE/CLEAR. 03802 Outputs: This node may have its selection status changed, depending on the inputs. 03803 03804 Purpose: Helper method for the static fn SelectAllInRect() used by marquee select. 03805 This method changes the selection state of this node according to the given 03806 bounding rectangle and sel-state action. Most nodes will want to use the 03807 default behaviour, which is to select themselves if their bounds lie within 03808 the given bounding rectangle. If you want to do something special with the 03809 marquee select, then override this method. 03810 03811 Notes: This method is meant to be called solely from SelectAllInRect() - if you wish 03812 to call it from elsewhere, it *may* work as you expect, but it is a good idea 03813 that you check your assumptions on what preconditions are necessary. 03814 03815 Errors: ERROR3 in DEBUG if st holds an invalid state. 03816 See also: SelectAllInRect(). 03817 03818 ********************************************************************************************/ 03819 void NodeRenderableInk::SelectInRect(const DocRect& Rect, SelStateAction st) 03820 { 03821 // ok, check whether we lie within the given rect. 03822 if (Rect.ContainsRect(GetBoundingRect())) 03823 { 03824 switch (st) 03825 { 03826 case CLEAR: 03827 DeSelect(TRUE); 03828 break; 03829 03830 case SET: 03831 Select(TRUE); 03832 break; 03833 03834 case TOGGLE: 03835 if (IsSelected()) 03836 DeSelect(TRUE); 03837 else 03838 Select(TRUE); 03839 break; 03840 03841 default: 03842 ERROR3("NodeRenderableInk::SelectInRect; Unknown SelStateAction!\n"); 03843 break; 03844 } 03845 } 03846 } 03847 03848 03849 03850 /******************************************************************************************** 03851 03852 > void NodeRenderableInk::RedrawObject() 03853 03854 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03855 Created: 11/11/93 03856 Purpose: Invalidates the Bounding rectangle of the node, causing it to be redrawn. 03857 03858 ********************************************************************************************/ 03859 03860 void NodeRenderableInk::RedrawObject() 03861 { 03862 // Find this nodes parent spread 03863 Spread* pSpread = FindParentSpread(); 03864 03865 // Find the owner document (could do it on this node, but leaping to spread 03866 // directly is slighlt quicker). 03867 BaseDocument *pDoc = pSpread->FindOwnerDoc(); 03868 03869 if ((pSpread != NULL) && (pDoc != NULL)) 03870 { 03871 // Invalidate region (if we're in a real document) 03872 if (IS_A(pDoc, Document)) 03873 ((Document *) pDoc)->ForceRedraw(pSpread, GetBoundingRect(), FALSE, this); 03874 else 03875 // Not in a real document - ought to complain. 03876 // (If this ERROR3 proves to be a problem then could be removed - Tim) 03877 ERROR3("Trying to redraw an object that is in a BaseDocument!"); 03878 } 03879 } 03880 03881 03882 03883 /******************************************************************************************** 03884 03885 > void NodeRenderableInk::ApplyAttributeToObject(NodeAttribute* Attribute, BOOL Redraw); 03886 03887 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03888 Created: 11/11/93 03889 Inputs: Attribute: The Attribute to apply to the object 03890 Redraw: Flag indicating if the object should be redrawn after the attribute is 03891 added. 03892 Outputs: - 03893 Returns: - 03894 Purpose: Applys Attribute to the selected node and then if Redraw is TRUE it 03895 redraws the node. 03896 Errors: - 03897 SeeAlso: - 03898 03899 ********************************************************************************************/ 03900 03901 void NodeRenderableInk::ApplyAttributeToObject(NodeAttribute* Attribute, BOOL Redraw) 03902 { 03903 Attribute->AttachNode(this, FIRSTCHILD); 03904 if (Redraw) 03905 RedrawObject(); // Redraw the node 03906 } 03907 03908 /*********************************************************************************************** 03909 03910 > BOOL NodeRenderableInk::ApplyAttributes(CCAttrMap* pAttribMap) 03911 03912 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 03913 Created: 16/1/95 03914 Inputs: pAttribMap = ptr to the attributes to apply to this node 03915 RequiredAttrsOnly = TRUE is attrs should only be applied if object requires them 03916 as determined by the func RequiresAttrib() 03917 Outputs: - 03918 Returns: TRUE if successful, FALSE otherwise 03919 Purpose: This generates copies of all the attributes in the map, and applies them to 03920 this node. 03921 03922 If RequiredAttrsOnly is TRUE, then only the attrs in the map that are required 03923 by the node are applied. RequiresAttrib() works this out for us. 03924 03925 ***********************************************************************************************/ 03926 03927 BOOL NodeRenderableInk::ApplyAttributes(CCAttrMap* pAttribMap,BOOL RequiredAttrsOnly) 03928 { 03929 if (pAttribMap == NULL) return FALSE; 03930 03931 BOOL ApplyAttr = TRUE; 03932 03933 // iterating all (key, value) pairs 03934 for (CMapPtrToPtr::iterator Pos = pAttribMap->GetStartPosition(); Pos!=pAttribMap->GetEndPosition();) 03935 { 03936 CCRuntimeClass* pType; 03937 void* pVal; 03938 03939 pAttribMap->GetNextAssoc(Pos,pType,pVal); 03940 03941 NodeAttribute* pNodeAttr = (NodeAttribute *)pVal; 03942 03943 if (pNodeAttr->CanBeAppliedToObject()) 03944 { 03945 if (RequiredAttrsOnly) 03946 ApplyAttr = RequiresAttrib(pNodeAttr); 03947 03948 if (ApplyAttr) 03949 { 03950 Node* pNode = pNodeAttr->SimpleCopy(); 03951 if (pNode != NULL) 03952 { 03953 pNode->AttachNode(this,FIRSTCHILD); 03954 // Ilan 03955 // Supply nodes geometry to attributes which require it 03956 ((NodeAttribute*)pNode)->LinkToGeometry(this); 03957 } 03958 } 03959 } 03960 } 03961 03962 // This will remove all the redundant attributes that have been attached to the node 03963 NormaliseAttributes(); 03964 03965 return TRUE; 03966 } 03967 03968 03969 /******************************************************************************************** 03970 03971 > virtual BOOL NodeRenderableInk::RequiresAttrib(CCRuntimeClass* AttribType, 03972 BOOL Search = FALSE) 03973 03974 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03975 Created: 6/7/94 03976 Inputs: AttribType: The type of the attribute 03977 03978 Search: This flag only applies to compound objects. It specifies 03979 if we should search the compound to find out if any child 03980 requires the attribute. By default time is considered more 03981 important than truth and TRUE is returned on compound objects. 03982 03983 Returns: The answer to this question 03984 Purpose: To determine if the node requires attribute AttribType to render itself 03985 03986 ********************************************************************************************/ 03987 03988 BOOL NodeRenderableInk::RequiresAttrib(CCRuntimeClass* AttribType, 03989 BOOL Search /* = FALSE */) 03990 { 03991 List* ReqdAttribList; 03992 03993 if (!IsCompound()) 03994 { 03995 // Obtain the list of required attributes for this node 03996 ReqdAttribList = ObjectRegistry::GetRequiredAttribs(GetRuntimeClass()); 03997 //Is AttribClass in the list ? 03998 NodeAttributeClassItem* AttrClassItem = (NodeAttributeClassItem*)(ReqdAttribList->GetHead()); 03999 04000 while (AttrClassItem != NULL) 04001 { 04002 if (AttrClassItem->AttributeClass == AttribType) 04003 { 04004 return TRUE; 04005 } 04006 AttrClassItem = (NodeAttributeClassItem*)(ReqdAttribList->GetNext(AttrClassItem)); 04007 } 04008 } 04009 else 04010 { 04011 if (Search) 04012 { 04013 // Ask the kids if they require the attribute (they will ask their kids etc.) 04014 Node* pChild = FindFirstChild(); 04015 NodeRenderableInk* pChildObject; 04016 while (pChild) 04017 { 04018 if (pChild->IsAnObject()) 04019 { 04020 pChildObject = (NodeRenderableInk*)pChild; 04021 if (pChildObject->RequiresAttrib(AttribType, Search)) 04022 return TRUE; 04023 } 04024 pChild = pChild->FindNext(); 04025 } 04026 } 04027 else 04028 return TRUE; // Assume the compound requires the attribute 04029 } 04030 return FALSE; // Not found (!IsCompound || IsCompound && Search cases ) 04031 } 04032 04033 04034 /******************************************************************************************** 04035 04036 > virtual BOOL NodeRenderableInk::CanAttrBeAppliedToMe(CCRuntimeClass* AttrType) 04037 04038 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04039 Created: 7/6/95 04040 Inputs: AttrType: The type of the attribute. It is a type, rather than an 04041 instance because this function needs to be called from the Localise/Factor out 04042 routines which operate on attribute types. 04043 04044 Returns: TRUE if an attribute of AttrType can be applied to this object, 04045 FALSE otherwise. 04046 04047 Purpose: This fn is not to be confused with RequiresAttrib, it determines if an 04048 attribute of type AttrType can be directly applied to this object. The 04049 object is assumed to Require the attribute. 04050 04051 The base class fn returns TRUE. 04052 04053 Certain attributes cannot be directly applied to specific nodes (even though 04054 they require the attribute to render). eg. LineSpacing attributes cannot 04055 be applied to text character objects. 04056 04057 This function is called by the GetObjectToApplyTo virtual function. 04058 04059 Errors: - 04060 SeeAlso: NodeRenderableInk::GetObjectToApplyTo 04061 04062 ********************************************************************************************/ 04063 04064 BOOL NodeRenderableInk::CanAttrBeAppliedToMe(CCRuntimeClass* AttrType) 04065 { 04066 return TRUE; 04067 } 04068 04069 04070 /******************************************************************************************** 04071 04072 > virtual NodeRenderableInk* NodeRenderableInk::GetObjectToApplyTo(CCRuntimeClass* AttrType) 04073 04074 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04075 Created: 7/6/95 04076 04077 Inputs: AttrType: The type of the attribute. It is a type, rather than an 04078 instance because this function needs to be called from the Localise/Factor out 04079 routines which operate on attribute types. 04080 04081 Returns: A pointer to an object that the attribute should be applied to. It returns 04082 NULL if there is no such object. 04083 04084 Purpose: Before applying an attribute to an object this function should be called to return 04085 the actual object the attribute should be applied to. 04086 04087 This base class function calls CanBeAppliedToMe, and if the object says No 04088 then it tries it's parent etc. This system works for Line based text attributes 04089 which should never be applied to text characters. 04090 04091 However if in future we meet a situation where things need to be done differently 04092 then this function can be overloaded. 04093 04094 Errors: - 04095 SeeAlso: NodeRenderableInk::CanAttrBeAppliedToMe 04096 04097 ********************************************************************************************/ 04098 04099 NodeRenderableInk* NodeRenderableInk::GetObjectToApplyTo(CCRuntimeClass* AttrType) 04100 { 04101 Node* pParent; 04102 NodeRenderableInk* pCurrentObject = this; 04103 do 04104 { 04105 if (pCurrentObject->CanAttrBeAppliedToMe(AttrType)) 04106 { 04107 // if applying line level attr, force it to be the first line of the paragraph 04108 if (IS_A(pCurrentObject,TextLine) && TextLine::IsAttrTypeLineLevel(AttrType)) 04109 pCurrentObject = ((TextLine*)pCurrentObject)->FindFirstLineOfParagraph(); 04110 break; 04111 } 04112 04113 // ok try the parent then 04114 pParent = pCurrentObject->FindParent(); 04115 if (pParent && (pParent->IsAnObject())) 04116 { 04117 pCurrentObject = (NodeRenderableInk*)pParent; 04118 } 04119 else 04120 { 04121 pCurrentObject = NULL; // No more to try 04122 } 04123 } while (pCurrentObject); 04124 04125 04126 return pCurrentObject; 04127 } 04128 04129 04130 /******************************************************************************************** 04131 04132 > virtual BOOL NodeRenderableInk::RequiresAttrib(NodeAttribute* pAttr, 04133 BOOL Search = FALSE) 04134 04135 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04136 Created: 6/7/94 04137 Inputs: pAttr: An attribute 04138 Search: This flag only applies to compound objects. It specifies 04139 if we should search the compound to find out if any child 04140 requires the attribute. By default time is considered more 04141 important than truth, and TRUE is returned on compound objects. 04142 Returns: The answer to this question 04143 Purpose: To determine if the node requires the pAttr to render itself 04144 04145 ********************************************************************************************/ 04146 04147 BOOL NodeRenderableInk::RequiresAttrib(NodeAttribute* pAttr, 04148 BOOL Search /*= FALSE*/) 04149 { 04150 CCRuntimeClass* AttribType = pAttr->GetAttributeType(); 04151 // Call fn which takes type 04152 return RequiresAttrib(AttribType, Search); 04153 } 04154 04155 /******************************************************************************************** 04156 04157 > virtual CCRuntimeClass* NodeRenderableInk::GetCurrentAttribGroup() 04158 04159 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04160 Created: 6/4/95 04161 Returns: The default attribute group (NodeRenderableInk) 04162 Purpose: Every Ink object has an associated current attribute group, If an attribute 04163 is applied to the object, and it needs to become current then the attribute 04164 group specified will get updated. 04165 04166 ********************************************************************************************/ 04167 04168 CCRuntimeClass* NodeRenderableInk::GetCurrentAttribGroup() 04169 { 04170 return (CC_RUNTIME_CLASS(NodeRenderableInk)); 04171 } 04172 04173 04174 04175 /******************************************************************************************** 04176 04177 > NodeAttribute* NodeRenderableInk::GetChildAttrOfType(CCRuntimeClass* ReqdAttrib) 04178 04179 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04180 Created: 3/8/94 04181 Inputs: - 04182 Outputs: - 04183 Returns: If the node has an attribute with TYPE ReqdType then a pointer to the 04184 attribute, else NULL. 04185 Purpose: Scans the child attribute block of the node for an attribute with type 04186 ReqdAttrib. 04187 Errors: - 04188 SeeAlso: NodeAttribute::GetAttributeType 04189 04190 ********************************************************************************************/ 04191 04192 NodeAttribute* NodeRenderableInk::GetChildAttrOfType(CCRuntimeClass* ReqdAttrib) 04193 { 04194 /* Node* Current = FindFirstChild(); 04195 while (Current != NULL) 04196 { 04197 if (Current->IsAnAttribute()) 04198 { 04199 if (((NodeAttribute*)Current)->GetAttributeType() == ReqdAttrib) 04200 { 04201 return ((NodeAttribute*)Current); 04202 } 04203 } 04204 else 04205 { 04206 if (Current->IsAnObject()) // Check for end of attribute block 04207 { 04208 return NULL; 04209 } 04210 } 04211 Current = Current->FindNext(); 04212 } 04213 return NULL; // Not found 04214 */ 04215 // It's important to do this scan in reverse render order so that closer scoped 04216 // attributes are found first. This helps report effect attributes correctly 04217 Node* Current = FindLastChild(); 04218 while (Current != NULL) 04219 { 04220 if (Current->IsAnAttribute()) 04221 { 04222 if (((NodeAttribute*)Current)->GetAttributeType() == ReqdAttrib) 04223 { 04224 NodeAttribute* pAttr = (NodeAttribute*)Current; 04225 if (pAttr->IsEffectAttribute() == IsValidEffectAttr(pAttr)) 04226 return pAttr; 04227 } 04228 } 04229 Current = Current->FindPrevious(); 04230 } 04231 return NULL; // Not found 04232 04233 } 04234 04235 /******************************************************************************************** 04236 04237 > BOOL NodeRenderableInk::HasAttrTypesOn(NodeRenderableInk* Object) 04238 04239 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04240 Created: 12/6/95 04241 Purpose: This function returns TRUE if the set of Object's child attribute types are 04242 a subset of this objects child attribute types. 04243 04244 ********************************************************************************************/ 04245 04246 BOOL NodeRenderableInk::HasAttrTypesOn(NodeRenderableInk* Object) 04247 { 04248 AttrTypeSet OurAttrs; 04249 AttrTypeSet ObjectsAttrs; 04250 04251 if (!AddChildAttrTypesToSet(&OurAttrs)) 04252 return FALSE; 04253 04254 if (!(Object->AddChildAttrTypesToSet(&ObjectsAttrs))) 04255 return FALSE; 04256 04257 AttrTypeItem* pObjectsAttr = (AttrTypeItem*)ObjectsAttrs.GetHead(); 04258 04259 CCRuntimeClass* AttrType; 04260 while (pObjectsAttr) 04261 { 04262 AttrType = pObjectsAttr->AttributeType; 04263 if (!(OurAttrs.InSet(AttrType))) 04264 return FALSE; // sets are different 04265 pObjectsAttr = (AttrTypeItem*) ObjectsAttrs.GetNext(pObjectsAttr); 04266 } 04267 04268 return TRUE; 04269 } 04270 04271 04272 /******************************************************************************************** 04273 04274 > NodeAttribute* NodeRenderableInk::FindAppliedAttribute(CCRuntimeClass* AttribType, BOOL bExcludeChildAttrs = FALSE, BOOL bStrict = TRUE) 04275 04276 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 04277 Created: 27/4/95 04278 Inputs: - 04279 Outputs: - 04280 Returns: The attribute of type 'AttribType' applied to this node. 04281 Purpose: Finds the attribute of type 'AttribType' applied to this node. 04282 Errors: - 04283 SeeAlso: NodeRenderableInk::FindAppliedAttributes 04284 04285 ********************************************************************************************/ 04286 04287 BOOL NodeRenderableInk::FindAppliedAttribute(CCRuntimeClass* AttribType, NodeAttribute** ppAttr, BOOL bStrict) 04288 { 04289 NodeAttribute* pAttr = FindAppliedAttribute(AttribType, FALSE, bStrict); 04290 if (ppAttr) *ppAttr = pAttr; 04291 return (pAttr!=NULL); 04292 } 04293 04294 NodeAttribute* NodeRenderableInk::FindAppliedAttribute(CCRuntimeClass* AttribType, BOOL bExcludeChildAttrs, BOOL bStrict) 04295 { 04296 // Made more efficient by Simon 09/06/95 04297 // *pAttrFound = ScanForNearestAttrib(AttribType, TRUE); 04298 // if (*pAttrFound) 04299 // return TRUE; 04300 // else 04301 // return FALSE; 04302 04303 // Restored 06/01/2005 by Phil 04304 // FindFirst/PrevAppliedAttr have been made more efficient 04305 // And let's try to only have ONE way of scanning for applied attributes so we only 04306 // have to deal with ONE set of bugs... 04307 // 04308 // 04309 // Repeat the following loop for all attributes we encounter in the tree. 04310 NodeAttribute* pAttrib = NULL; 04311 if (bExcludeChildAttrs) 04312 pAttrib = NodeAttribute::FindPrevAppliedAttr(this); 04313 else 04314 pAttrib = NodeAttribute::FindFirstAppliedAttr(this); 04315 04316 while (pAttrib) 04317 { 04318 if (pAttrib->GetAttributeType() == AttribType) 04319 { 04320 // If the attr is an effect attr 04321 // and it is in my child list 04322 // and I don't allow this type of attr to be an effect 04323 // Then continue looking 04324 // Else return it 04325 // if (!(pAttrib->FindParent()==this && pAttrib->IsEffectAttribute() && !this->IsValidEffectAttr(pAttrib))) 04326 // return pAttrib; 04327 if (pAttrib->FindParent()!=this) 04328 return pAttrib; 04329 04330 if (bStrict) 04331 { 04332 if (pAttrib->IsEffectAttribute() == this->IsValidEffectAttr(pAttrib)) 04333 return pAttrib; 04334 } 04335 else 04336 if (!(pAttrib->IsEffectAttribute() && !this->IsValidEffectAttr(pAttrib))) 04337 return pAttrib; 04338 } 04339 04340 pAttrib = NodeAttribute::FindPrevAppliedAttr(pAttrib); 04341 } 04342 04343 return NULL; 04344 } 04345 04346 04347 /******************************************************************************************** 04348 04349 > void NodeRenderableInk::DeleteAppliedAttributes() 04350 04351 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04352 Created: 31/5/95 04353 Inputs: - 04354 Outputs: - 04355 Returns: - 04356 Purpose: This function deletes all child attributes from the node which have the same 04357 type and value as the attributes applied above the child level. It is useful for 04358 Attribute optimisation work. 04359 04360 Errors: - 04361 SeeAlso: - 04362 04363 ********************************************************************************************/ 04364 04365 void NodeRenderableInk::DeleteAppliedAttributes() 04366 { 04367 Node* pChild = FindFirstChild(); 04368 Node* pFirstChild = pChild; 04369 04370 // Temporarily unlink the children so that we can easily find applied attributes which 04371 // exclude the child attribs 04372 Child = NULL; 04373 04374 NodeAttribute* pAppliedAttr; 04375 NodeAttribute* pChildAttr; 04376 while (pChild != NULL) 04377 { 04378 if (pChild->IsAnAttribute()) 04379 { 04380 pChildAttr = (NodeAttribute*)pChild; 04381 if (FindAppliedAttribute((pChildAttr->GetAttributeType()), &pAppliedAttr)) 04382 { 04383 if (pAppliedAttr) 04384 { 04385 // Test to see if the attributes have the same value 04386 if ((IS_SAME_CLASS(pAppliedAttr, pChildAttr ))) 04387 { 04388 if ((*pAppliedAttr)==(*pChildAttr)) 04389 { 04390 pChildAttr->CascadeDelete(); // Delete the attribute 04391 delete pChildAttr; 04392 } 04393 } 04394 } 04395 04396 } 04397 } 04398 pChild = pChild->FindNext(); 04399 } 04400 // Restore the children 04401 pChild = pFirstChild; 04402 } 04403 04405 // the object. 04406 04407 /******************************************************************************************** 04408 04409 > BOOL NodeRenderableInk::AddChildAttrTypesToSet(AttrTypeSet* pAttrTypeSet) 04410 04411 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04412 Created: 1/6/95 04413 Inputs: - 04414 Outputs: pAttrTypeSet: The attribute types of all this nodes attributes are added to 04415 this set. 04416 Returns: FALSE if we run out of memory 04417 Purpose: This function adds the attribute types of all this nodes attributes to the 04418 AttrTypeSet. 04419 04420 If you are adding an object, which has localised attributes, to a compound node 04421 then this function is useful. The attrTypeSet will contain those attributes 04422 that need to be localised on the compound before the object is added, and those 04423 that need to be factored out after. 04424 04425 Errors: - 04426 SeeAlso: - 04427 04428 ********************************************************************************************/ 04429 04430 BOOL NodeRenderableInk::AddChildAttrTypesToSet(AttrTypeSet* pAttrTypeSet) 04431 { 04432 Node* pChild; 04433 // Create a set of the caret's attribute types 04434 for (pChild = FindFirstChild(); 04435 pChild; 04436 pChild = pChild->FindNext()) 04437 { 04438 if (pChild->IsAnAttribute()) 04439 { 04440 // Add the attribute's type to the CaretsAttrTypes set 04441 if (!(pAttrTypeSet->AddToSet(((NodeAttribute*)pChild)->GetAttributeType()))) 04442 return FALSE; // out of mem 04443 } 04444 } 04445 return TRUE; 04446 } 04447 04448 /*********************************************************************************************** 04449 04450 > BOOL NodeRenderableInk::CopyChildrenAsShapes(Node* pDestin) 04451 04452 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 04453 Created: 24/05/95 04454 Inputs: pDestin = a pointer to a tree node to place the shapes. 04455 Outputs: - 04456 Returns: TRUE if a copy of the children of this parent has been taken 04457 FALSE if failed. 04458 Purpose: This function scans through all children of this object and asks them 04459 to convert themselves to shapes. The shapes are placed as children of the 04460 destination node. If the routine fails, all children of the destination will 04461 automatically be removed. 04462 04463 ***********************************************************************************************/ 04464 04465 BOOL NodeRenderableInk::CopyChildrenAsShapes(Node* pDestin) 04466 { 04467 ERROR2IF(pDestin==NULL,FALSE,"pDestin==NULL in CopyChildrenAsShapes"); 04468 04469 // ok lets get the subtree to become a bunch of nodepaths 04470 CopyBecomeA ParamBecomeA(BECOMEA_PASSBACK, 04471 CC_RUNTIME_CLASS(NodePath), 04472 NULL); 04473 04474 // Set the context node 04475 ParamBecomeA.SetContextNode(pDestin); 04476 04477 // now scan the children and get them to do their stuff 04478 Node* pNode = FindFirstChild(); 04479 while (pNode!=NULL) 04480 { 04481 if (pNode->CanBecomeA(&ParamBecomeA)) 04482 { 04483 if (!pNode->DoBecomeA(&ParamBecomeA)) 04484 { 04485 pDestin->CascadeDelete(); 04486 return FALSE; 04487 } 04488 } 04489 04490 pNode=pNode->FindNext(); 04491 } 04492 04493 return TRUE; 04494 } 04495 04496 04497 /******************************************************************************************** 04498 04499 > BOOL CopyBecomeA::PassBack(NodeRenderableInk* pNewNode, 04500 NodeRenderableInk* pCreatedByNode, 04501 CCAttrMap* pAttrMap) 04502 04503 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 04504 Created: 24/05/95 04505 Inputs: pNewNode = ptr to new generated node (should be a NodePath) 04506 pCreatedByNode = ptr to the node that generated this NodePath 04507 pAttrMap = ptr attr map (NULL means get attrs applied to pCreatedByNode) 04508 Outputs: - 04509 Returns: - 04510 Purpose: This is the func that receives the NodePaths generated by the last node asked 04511 to do becomea, it is a helper function associated with CopyChildrenAsShapes 04512 04513 ********************************************************************************************/ 04514 04515 BOOL CopyBecomeA::PassBack(NodeRenderableInk* pNewNode, NodeRenderableInk* pCreatedByNode, CCAttrMap* pAttrMap) 04516 { 04517 ERROR2IF(pNewNode==NULL,FALSE,"pNewNode==NULL"); 04518 ERROR2IF(pCreatedByNode==NULL,FALSE,"pCreateByNode==NULL"); 04519 ERROR2IF(pContextNode == NULL,FALSE,"The context node is NULL!!!"); 04520 04521 // Insert the new NodePath into the tree 04522 pNewNode->AttachNode(pContextNode,LASTCHILD); 04523 04524 if (pAttrMap!=NULL) 04525 { 04526 // Apply all the attributes to the new path 04527 BOOL ok = pNewNode->ApplyAttributes(pAttrMap); 04528 04529 /* 04530 // iterating all (key, value) pairs 04531 for (CCAttrMap::iterator Pos = pAttrMap->GetStartPosition(); Pos != NULL;) 04532 { 04533 void *pType, *pVal; 04534 pAttrMap->GetNextAssoc(Pos,pType,pVal); 04535 NodeAttribute* pNodeAttr = (NodeAttribute *)pVal; 04536 delete pNodeAttr; 04537 } 04538 */ 04539 pAttrMap->DeleteAttributes(); // Delete the returned attrs, they're not needed 04540 delete pAttrMap; 04541 return ok; 04542 } 04543 else 04544 { 04545 // We need to get the attributes from the creater node. 04546 CCAttrMap AppliedAtts(30); 04547 if (!pCreatedByNode->FindAppliedAttributes(&AppliedAtts)) 04548 return FALSE; 04549 04550 if (!pNewNode->ApplyAttributes(&AppliedAtts)) 04551 return FALSE; 04552 } 04553 04554 return TRUE; 04555 } 04556 04557 04558 04559 BOOL NodeRenderableInk::ReadPostChildrenWeb(BaseCamelotFilter* pFilter) 04560 { 04561 SafeToRender = NodeRenderableBounded::ReadPostChildrenWeb(pFilter); 04562 return SafeToRender; 04563 } 04564 04565 BOOL NodeRenderableInk::ReadPostChildrenNative(BaseCamelotFilter* pFilter) 04566 { 04567 return ReadPostChildrenWeb(pFilter); 04568 } 04569 04570 BOOL NodeRenderableInk::AreYouSafeToRender() 04571 { 04572 return SafeToRender; 04573 } 04574 04575 04576 /******************************************************************************************** 04577 04578 > virtual BOOL NodeRenderableInk::SetParentLayerAsEdited() 04579 04580 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 04581 Created: 31/7/97 04582 Returns: True if worked ok, False otherwise 04583 Purpose: Mark parent layer as edited. If an ink object as something done to it which 04584 changes its appearance then we need to mark the parent layer as edited. 04585 In this class we actually do the work as these are visible objects in the tree. 04586 04587 ********************************************************************************************/ 04588 04589 BOOL NodeRenderableInk::SetParentLayerAsEdited() 04590 { 04591 // New 31/7/97 Neville 04592 // Mark the parent layer as edited as something has changed on it 04593 Layer * pLayer = (Layer*) FindParent(CC_RUNTIME_CLASS(Layer)); 04594 if (pLayer) 04595 { 04596 // Note that this layer has been edited 04597 pLayer->SetEdited(TRUE); 04598 #ifdef _DEBUG 04599 // Tell the frame gallery to update its display of the frame 04600 BROADCAST_TO_ALL(LayerMsg(pLayer, LayerMsg::REDRAW_LAYER)); 04601 #endif 04602 } 04603 04604 return TRUE; 04605 } 04606 04607 04608 04609 /******************************************************************************************** 04610 04611 > virtual BOOL NodeRenderableInk::IsSeeThrough(BOOL CheckIndirectAttrs) 04612 04613 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 04614 Created: 13 September 2000 04615 04616 Inputs: CheckIndirectAttrs whether or not to test those attributes applied 04617 to us living somewhere above us in the tree. 04618 04619 Returns: TRUE if you can still see some of the background after rendering the tree 04620 rooted at this node. 04621 04622 Purpose: Determines whether this node is see through or not. 04623 See through in this case does not necessarily mean transparent - eg we could 04624 be a no-colour-fill rectangle. This test is useful if you're going to render 04625 into a bitmap, which will then be post-processed and plonked on the document 04626 (eg Feathering). This way, you can hopefully avoid any performance hit from 04627 unnecessary rendering into an alpha-channel bitmap. 04628 04629 Notes: You should only need to set CheckIndirectAttrs when calling this fn 04630 on a sub-tree root-node. The recursive calls made by this fn pass FALSE, 04631 as we only need to check indirectly applied attrs once for a sub-tree. 04632 04633 ********************************************************************************************/ 04634 BOOL NodeRenderableInk::IsSeeThrough(BOOL CheckIndirectAttrs) 04635 { 04636 // we do the searches in this order: 04637 // 04638 // 1. any attrs applied to us (not recursive). 04639 // 2. ask any non-attribute children if they are see-through (recursive). 04640 // 04641 // we finish the search as soon as we get a positive result. 04642 04643 BOOL bIsSeeThrough = FALSE; 04644 04645 // 1. Check our indirectly-applied attributes. 04646 if (CheckIndirectAttrs) 04647 { 04648 CCAttrMap* pAttrMap = CCAttrMap::MakeAppliedAttrMap(this); 04649 if (pAttrMap != NULL) 04650 { 04651 bIsSeeThrough = pAttrMap->IsSeeThrough(); 04652 delete pAttrMap; 04653 } 04654 } 04655 04656 // 2. Check all our NodeRenderable children. 04657 // Note that if we've checked indirect attrs, 04658 // then we needn't bother re-testing any attributes. 04659 for (Node* pKid = FindFirstChild(); 04660 pKid != NULL && !bIsSeeThrough; 04661 pKid = pKid->FindNext() ) 04662 { 04663 if (pKid->IsNodeRenderableClass()) 04664 { 04665 if (CheckIndirectAttrs && pKid->IsAnAttribute()) 04666 { 04667 // do nothing. 04668 } 04669 else 04670 { 04671 bIsSeeThrough = ((NodeRenderable*)pKid)->IsSeeThrough(FALSE); 04672 } 04673 } 04674 } 04675 04676 return bIsSeeThrough; 04677 } 04678 04679 04680 04681 04682 /******************************************************************************************** 04683 04684 > virtual BOOL NodeRenderableBounded::ContainsNonMixTransparency(RenderRegion* pRegion) 04685 04686 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 04687 Created: 07/08/2004 04688 Inputs: - 04689 Returns: TRUE - The node contains non-mix transparency attributes 04690 FALSE - It doesn't 04691 Purpose: Find out whether this node's subtree contains non-mix transparency. 04692 Useful for optimising cacheing because while you want things to be cached 04693 as 32BPP RGBT bitmaps most of the time, non-mix transparencies can't 04694 be captured that way and so some work ahs to be done to transform down 04695 to a 24BPP RGB bitmap - better to avoid that by calling this function. 04696 04697 ********************************************************************************************/ 04698 04699 BOOL NodeRenderableBounded::ContainsNonMixTransparency(RenderRegion* pRegion) 04700 { 04701 for (Node* pKid = FindFirstDepthFirst(); 04702 pKid != NULL; 04703 pKid = pKid->FindNextDepthFirst(this) ) 04704 { 04705 if (pKid->IsAnAttribute() && ((NodeAttribute*)pKid)->IsATranspFill()) 04706 { 04707 AttrFillGeometry* pTransAttr = (AttrFillGeometry*) pKid; 04708 UINT32 ttype = pTransAttr->GetTranspType(); 04709 ERROR3IF(ttype<TT_NoTranspType || ttype>TT_MAX, "Someone's trying to set an unknown transp type!"); 04710 04711 // if (!(ttype==TT_NoTranspType || ttype==TT_Mix)) 04712 if (!pRegion->TranspTypeIsRGBTCompatible(ttype)) 04713 return TRUE; 04714 } 04715 } 04716 04717 return FALSE; 04718 } 04719 04720 04721 04722 04723 /******************************************************************************************** 04724 04725 > virtual BOOL NodeRenderableInk::ExportRender ( RenderRegion *pRender ) 04726 04727 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 04728 Created: 7/11/00 04729 Inputs: pRender - A pointer to the render region being used for the export. 04730 Returns: TRUE - The node was exported using this function. 04731 FALSE - There is no custom export code for this node type. 04732 Purpose: Custom export code for nodes derived from NodeRenderableInk. So far there is 04733 only code for the VectorFileRenderRegion (which is a superclass for the EPS, 04734 CMX, and Flash render regions) to allow for the export of stroked shapes. 04735 04736 ********************************************************************************************/ 04737 04738 BOOL NodeRenderableInk::ExportRender ( RenderRegion *pRender ) 04739 { 04740 // The return value. 04741 BOOL Result = FALSE; 04742 04743 // Is this a FlashRenderRegion? 04744 if ( pRender->IsKindOf ( CC_RUNTIME_CLASS ( FlashRenderRegion ) ) ) 04745 { 04746 // Cast the render region pointer to be a pointer to a vector file render region. 04747 FlashRenderRegion *pFlash = static_cast<FlashRenderRegion*> ( pRender ); 04748 04749 // Call the appropriate method in the vector file render region class. 04750 Result = pFlash->ExportRenderableNode ( this ); 04751 } 04752 04753 return Result; 04754 } 04755 04756 //------------------------------------------------------------------------------------------ 04757 //NodeHidden methods 04758 04759 04760 04761 /******************************************************************************************** 04762 04763 > NodeHidden::NodeHidden(Node* HiddenNode) 04764 04765 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04766 Created: 13/9/93 04767 Inputs: - 04768 Outputs: - 04769 Returns: - 04770 Purpose: NodeHidden constructor which hides HiddenNode 04771 Errors: - 04772 SeeAlso: - 04773 04774 ********************************************************************************************/ 04775 04776 NodeHidden::NodeHidden(Node* HiddenNode): Node() 04777 { 04778 ENSURE(HiddenNode != NULL, "Trying to hide a NULL node"); 04779 HiddenNd = HiddenNode; // Point to the node which is to be hidden 04780 HiddenNode->IncHiddenCnt(); // Increase the count of the number of NodeHidden nodes which point 04781 // to the node being hidden. 04782 04783 TAG tag = HiddenNd->GetTag(); // Copy tag so we can preserve it after the unlink from tree 04784 04785 AttachNode(HiddenNode, NEXT); 04786 HiddenNode->UnlinkNodeFromTree(); // Hide the node 04787 04788 // Alert ! 04789 // This is a bit scary but when doing things like complex deletions we need to find 04790 // the parent of the hidden node when trying to factor out. I hope that this 04791 // doesn't break to much !. 04792 //HiddenNode->Parent = this; 04793 04794 HiddenNd->Tag = tag; // Ensure the unlinked node has a preserved tag 04795 } 04796 04797 04798 /******************************************************************************************** 04799 04800 > Node* NodeHidden::ShowNode() 04801 04802 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04803 Created: 13/9/93 04804 Inputs: - 04805 Outputs: - 04806 Returns: A pointer to the unhidden node 04807 Purpose: This static method will relink the hidden node into the tree. this 04808 will be deleted. 04809 Errors: - 04810 SeeAlso: - 04811 04812 ********************************************************************************************/ 04813 04814 Node* NodeHidden::ShowNode() 04815 { 04816 Node* ShowNode = HiddenNd; // Pointer to hidden node 04817 04818 //---------------------------------------------------------------------------- 04819 // Relink the hidden node into the tree at the same position as the NodeHidden 04820 04821 TAG tag = ShowNode->GetTag(); // Get the original tag 04822 ShowNode->AttachNode(this, NEXT); 04823 ShowNode->Tag = tag; // Restore tag value after relinking node into the tree 04824 04825 ShowNode->DecHiddenCnt(); // this hidden node no longer reffers to the node. 04826 CascadeDelete(); // Unlinks only the HideNode (It never has any children) 04827 delete (this); 04828 return ShowNode; 04829 } 04830 04831 /*********************************************************************************************** 04832 > Node* NodeHidden::SimpleCopy() 04833 04834 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04835 Created: 28/4/93 04836 Inputs: - 04837 Outputs: 04838 Returns: - 04839 04840 Purpose: Causes an ENSURE failure. A hidden node should never be copied 04841 04842 Errors: 04843 04844 **********************************************************************************************/ 04845 04846 Node* NodeHidden::SimpleCopy() 04847 { 04848 ENSURE(FALSE, "NodeHidden invalid SimpleCopy called"); 04849 return NULL; 04850 } 04851 04852 04853 /******************************************************************************************** 04854 04855 > virtual UINT32 NodeHidden::GetNodeSize() const 04856 04857 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 04858 Created: 6/10/93 04859 Inputs: - 04860 Outputs: - 04861 Returns: The size of the node in bytes (this is the size of the NodeHidden only, it 04862 does not include the size of the hidden subtree). 04863 04864 Purpose: For finding the size of the node 04865 04866 SeeAlso: Node::GetSubtreeSize 04867 04868 ********************************************************************************************/ 04869 04870 UINT32 NodeHidden::GetNodeSize() const 04871 { 04872 return (sizeof(NodeHidden)); 04873 } 04874 04875 /******************************************************************************************** 04876 04877 > BOOL NodeHidden::IsNodeHidden() 04878 04879 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com> 04880 Created: 13/02/95 04881 Returns: TRUE => This node is an instance of NodeHidden or a derived class. 04882 FALSE => otherwise. 04883 Purpose: Determine if a node is *derived* from the NodeHidden class. 04884 04885 ********************************************************************************************/ 04886 04887 BOOL NodeHidden::IsNodeHidden() const 04888 { 04889 return TRUE; 04890 } 04891 04892 04893 /******************************************************************************************** 04894 04895 > virtual BOOL NodeHidden::IsOrHidesAnAttribute() const 04896 04897 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 04898 Created: 12/6/95 04899 Returns: TRUE if this Hidden Node hides an Attribute, FALSE otherwise 04900 Purpose: Enables to determine if this node is an Attribute or is hiding an attribute 04901 04902 ********************************************************************************************/ 04903 04904 BOOL NodeHidden::IsOrHidesAnAttribute() const 04905 { 04906 // if it is NULL, then its not an attribute 04907 if (HiddenNd==NULL) 04908 return FALSE; 04909 04910 // see if it is an attribute 04911 return (HiddenNd->IsAnAttribute()); 04912 }