noderend.cpp

Go to the documentation of this file.
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 }

Generated on Sat Nov 10 03:46:06 2007 for Camelot by  doxygen 1.4.4