nodemold.cpp

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

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