opcntr.cpp

Go to the documentation of this file.
00001 // $Id: opcntr.cpp 1754 2006-09-15 16:01:48Z phil $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // Implementation of the Contour operations
00100 
00101 #include "camtypes.h"
00102 //#include "selop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00103 #include "opcntr.h"
00104 //#include "cntres.h"
00105 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "nodecomp.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "nodecntr.h"
00110 #include "ncntrcnt.h"
00111 #include "progress.h"
00112 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #include "lineattr.h"
00116 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "attrval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 #include "nodepath.h"
00120 #include "attrmap.h"
00121 #include "gclips.h"
00122 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "opbevel.h"
00124 #include "nodecont.h"
00125 #include "objchge.h"
00126 #include "blndtool.h"
00127 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 #include "nodebldr.h"
00129 #include "ppbevel.h"    //  for bevel helpers
00130 #include "fitcurve.h"
00131 #include "rsmooth.h"
00132 #include "nodeblnd.h"
00133 #include "brshattr.h"
00134 #include "strkattr.h"
00135 #include "pbecomea.h"
00136 #include "slicehelper.h"
00137 //#include "simon.h"            // for "no objects selected" Description string
00138 #include "ppstroke.h"
00139 #include "brshbeca.h"
00140 #include "ophist.h"
00141 
00142 CC_IMPLEMENT_DYNCREATE(CreateContourParam, OpParam)
00143 CC_IMPLEMENT_DYNCREATE(OpCreateContour, SelOperation)
00144 CC_IMPLEMENT_DYNCREATE(OpChangeContourWidth, UndoableOperation)
00145 CC_IMPLEMENT_DYNCREATE(OpRemoveContour, SelOperation)
00146 CC_IMPLEMENT_DYNCREATE(RegenerateContourAction, Action)
00147 CC_IMPLEMENT_DYNCREATE(ChangeContourWidthAction, Action)
00148 CC_IMPLEMENT_DYNCREATE(ChangeContourToOuterAction, Action)
00149 CC_IMPLEMENT_DYNCREATE(ChangeContourToInnerAction, Action)
00150 CC_IMPLEMENT_DYNCREATE(OpChangeContourToInner, SelOperation)
00151 CC_IMPLEMENT_DYNCREATE(OpChangeContourToOuter, SelOperation)
00152 CC_IMPLEMENT_DYNCREATE(OpChangeContourSteps, SelOperation)
00153 CC_IMPLEMENT_DYNCREATE(ChangeContourStepsAction, Action)
00154 CC_IMPLEMENT_DYNCREATE(OpChangeContourColourType, SelOperation)
00155 CC_IMPLEMENT_DYNCREATE(ChangeContourColourTypeAction, Action)
00156 CC_IMPLEMENT_DYNCREATE(OpChangeContourAttributeProfile, SelOperation)
00157 CC_IMPLEMENT_DYNCREATE(ChangeContourAttributeProfileAction, Action)
00158 CC_IMPLEMENT_DYNCREATE(OpChangeContourObjectProfile, SelOperation)
00159 CC_IMPLEMENT_DYNCREATE(ChangeContourObjectProfileAction, Action)
00160 CC_IMPLEMENT_DYNCREATE(OpChangeContourStepDistance, SelOperation)
00161 CC_IMPLEMENT_DYNCREATE(OpConvertPathToShapes, SelOperation)
00162 CC_IMPLEMENT_DYNCREATE(OpToggleContourInsetPath, SelOperation)
00163 CC_IMPLEMENT_DYNCREATE(ToggleInsetPathAction, Action)
00164 
00165 DECLARE_SOURCE( "$Revision: 1754 $" );
00166 
00167 #define new CAM_DEBUG_NEW
00168 
00171 // Contour ops implementation
00172 
00173 /********************************************************************************************
00174 >   OpCreateContour::OpCreateContour()
00175 
00176     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00177     Created:    12/8/99
00178     Purpose:    Constructor.
00179 ********************************************************************************************/
00180 OpCreateContour::OpCreateContour()
00181 {
00182     //TRACEUSER( "MarkH", _T("Just Made a OpCreateContour Class!\n"));
00183 }
00184 
00185 
00186 
00187 /********************************************************************************************
00188 >   OpCreateContour::~OpCreateContour()
00189 
00190     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00191     Created:    12/8/99
00192     Purpose:    Destructor.
00193 ********************************************************************************************/
00194 OpCreateContour::~OpCreateContour()
00195 {
00196     //TRACEUSER( "MarkH", _T("Just Killed OpCreateContour Class!!!\n"));
00197 }
00198 
00199 
00200 
00201 /********************************************************************************************
00202 >   virtual void OpCreateContour::Do(OpDescriptor *pOpDesc)
00203 
00204     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00205     Created:    12/8/99
00206     Inputs:     pOpDesc - OpDescriptor - unused
00207     Outputs:    -
00208     Returns:    -
00209     Purpose:    The do function.  Applys a Bevel to the selection in the current document
00210 ********************************************************************************************/
00211 void OpCreateContour::Do(OpDescriptor *pOpDesc)
00212 {
00213     End();
00214 }
00215 
00216 
00217 /********************************************************************************************
00218 >   void OpCreateContour::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
00219 
00220     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00221     Created:    12/8/99
00222     Inputs:     
00223     Outputs:    -
00224     Returns:    -
00225     Purpose:    Applys a Bevel to the selected node after a mouse click
00226 ********************************************************************************************/
00227 
00228 void OpCreateContour::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
00229 {
00230     DoStartSelOp(TRUE, TRUE);
00231     ObjChangeFlags cFlags;
00232     cFlags.RegenerateNode = TRUE;
00233     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
00234 
00235     String_64 StatusString;
00236     StatusString.Load(_R(IDS_CONTOUR_CREATE_STATUS_STRING));
00237 
00238     BeginSlowJob(-1, TRUE, &StatusString);
00239 
00240     String_256 s(StatusString);
00241     GetApplication()->UpdateStatusBarText(&s, FALSE);
00242 
00243     CreateContourParam * pCCP = (CreateContourParam *)pParam;
00244 
00245     List * pNodeList = pCCP->m_pNodeList;
00246 
00247     // first, remove all contours from the list
00248     List ContourList;
00249 
00250     NodeListItem * pItem = (NodeListItem *)pNodeList->GetHead();
00251     NodeListItem * pContourItem = NULL;
00252 
00253     BOOL ok = TRUE;
00254 
00255     NodeHidden * pHidden = NULL;
00256 
00257     while (pItem)
00258     {
00259         BevelTools::GetAllNodesUnderNode(pItem->pNode, &ContourList, CC_RUNTIME_CLASS(NodeContourController));
00260         
00261         if (!ContourList.IsEmpty())
00262         {
00263             TRACEUSER( "DavidM", _T("Found non-empty contour list\n"));
00264             pContourItem = (NodeListItem *)ContourList.GetHead();
00265             
00266             while (pContourItem)
00267             {
00268                 // remove the contour node, and promote all children
00269                 // invalidate the node
00270                 if (ok)
00271                     ok = DoInvalidateNodeRegion((NodeRenderableInk *)pContourItem->pNode, TRUE);
00272 
00273                 // factor out the child attributes
00274                 if (ok)
00275                     ok = DoLocaliseCommonAttributes((NodeRenderableInk *)pContourItem->pNode, TRUE);
00276                 
00277                 // now, move all child nodes upwards (except for the 'needs parent' nodes)
00278                 Node * pChild = pContourItem->pNode->FindFirstChild();
00279                 Node * pNextChild = NULL;
00280                 
00281                 while (pChild)
00282                 {
00283                     pNextChild = pChild->FindNext();
00284                     if (ok && !pChild->NeedsParent(pContourItem->pNode) && !pChild->IsAnAttribute())
00285                         ok = DoMoveNode(pChild, pContourItem->pNode, PREV);
00286                     
00287                     pChild = pNextChild;
00288                 }
00289                 
00290                 
00291                 // hide the original node
00292                 if (ok)
00293                     ok = DoHideNode(pContourItem->pNode, TRUE, &pHidden, FALSE);
00294                 
00295                 // move on
00296                 pContourItem = (NodeListItem *)ContourList.GetNext(pContourItem);
00297             }
00298             
00299             ContourList.DeleteAll();
00300 
00301             if (ok)
00302                 ok = DoFactorOutCommonChildAttributes((NodeRenderableInk *)pItem->pNode);
00303         }
00304         
00305         pItem = (NodeListItem *)pNodeList->GetNext(pItem);
00306     }
00307 
00308     pItem = (NodeListItem *)pNodeList->GetHead();
00309 
00310 //  CCAttrMap * pAttrMap = NULL;
00311     AttrLineWidth * pLineWidthAttr = NULL;
00312     AttrStrokeColour * pStrokeColourAttr = NULL;
00313 //  AttrStartArrow * pAttrStartArrow = NULL;
00314 //  AttrEndArrow * pAttrEndArrow = NULL;
00315 //  FlatFillAttribute * pFillAttr = NULL;
00316 //  StrokeColourAttribute * pStrokeAttr = NULL;
00317 //  NodeAttribute * pAttr = NULL;
00318 
00319     DocColour StrokeColour;
00320     MILLIPOINT LineWidth = 0;
00321 //  INT32 Red = 0;
00322 //  INT32 Blue = 0;
00323 //  INT32 Green = 0;
00324 
00325     Path ArrowPath;
00326     ArrowPath.Initialise();
00327 
00328     while (pItem && ok)
00329     {
00330         if (pItem->pNode->IsNodePath() && pItem->pNode->AllowOp(&ObjChange))
00331         {
00332             // for all closed paths in the selection, copy their stroke attribute
00333             // colour as a fill attribute
00334             NodePath * pPathNode = (NodePath *)pItem->pNode;
00335 
00336             // find out if the path is closed
00337             if (!pPathNode->InkPath.IsSubPathClosed(0))
00338             {
00339                 // first, localise all the common attributes
00340                 if (ok)
00341                     ok = DoLocaliseForAttrChange(pPathNode, (AttrTypeSet *)NULL, (ObjectSet *)NULL);
00342                 
00343                 // get the line width & the stroke colour out of the node
00344                 pLineWidthAttr = (AttrLineWidth *)pPathNode->FindFirstChild(CC_RUNTIME_CLASS(AttrLineWidth));
00345                 pStrokeColourAttr = (AttrStrokeColour *)pPathNode->FindFirstChild(CC_RUNTIME_CLASS(AttrStrokeColour));
00346 
00347                 if (pLineWidthAttr)
00348                     LineWidth = pLineWidthAttr->Value.LineWidth;
00349 
00350                 if (pStrokeColourAttr)
00351                     StrokeColour = pStrokeColourAttr->Value.Colour;
00352 
00353                 // eliminate all fills from this node
00354                 if (ok)
00355                     ok = DoRemoveAttrTypeFromSubtree(pPathNode, CC_RUNTIME_CLASS(AttrFillGeometry));
00356 
00357                 // create a new flat fill attribute & apply it to this node
00358                 AttrFlatColourFill * pFlatFill = NULL;
00359                 ALLOC_WITH_FAIL(pFlatFill, new AttrFlatColourFill, this);
00360 
00361                 pFlatFill->SetStartColour(&StrokeColour);
00362 
00363                 if (ok)
00364                 {
00365                     // [Phil, 17-09-2005]
00366                     // NO!
00367                     // Geez, DMc, you can't cast an AttrFlatColourFill* to a NodeRenderableBounded*!
00368                     // That means that you can't call DoInsertNewNode, so we have to do the same thing
00369                     // in essence directly...
00370                     //                  ok = DoInsertNewNode((NodeRenderableBounded *)pFlatFill, pPathNode,
00371                     //                      FIRSTCHILD, FALSE, FALSE, FALSE, FALSE);
00372                     pFlatFill->AttachNode(pPathNode, FIRSTCHILD);
00373                     HideNodeAction* UndoHideNodeAction;
00374                     if (HideNodeAction::Init(this, this->GetUndoActions(), pFlatFill, TRUE, (Action**)(&UndoHideNodeAction))
00375                             == AC_FAIL)
00376                     {
00377                         pFlatFill->CascadeDelete();
00378                         delete pFlatFill;
00379                         pFlatFill = FALSE;
00380                         FailAndExecute();
00381                         End();
00382                         return;
00383                     }
00384                 }
00385 
00386                 // factor out all the attributes
00387                 if (ok)
00388                     ok = DoFactorOutAfterAttrChange(pPathNode, (AttrTypeSet *)NULL);
00389             }
00390         }
00391 
00392         pItem = (NodeListItem *)pNodeList->GetNext(pItem);
00393     }
00394 
00395     if (!ok)
00396     {
00397         FailAndExecute();
00398         End();
00399         return;
00400     }
00401 
00402     // have we any shadow nodes present ?
00403     // if so, build a new list
00404     pItem = (NodeListItem *)pNodeList->GetHead();
00405     NodeListItem * pNewItem = NULL;
00406     Node * pNode = NULL;
00407     Node * pShadowNode = NULL;
00408 
00409     List ListToContour;
00410 
00411     while (pItem)
00412     {
00413         // find out if any parents are shadow controllers
00414         pNode = pItem->pNode;
00415         pShadowNode = NULL;
00416         
00417         while (pNode)
00418         {
00419             if (pNode->IS_KIND_OF(NodeShadowController))
00420                 pShadowNode = pNode; // we've found a shadow controller node
00421 
00422             pNode = pNode->FindParent();
00423         }
00424 
00425         // do we have a shadow node ? if so, make all non-needs parent children
00426         // be contoured
00427         if (pShadowNode)
00428         {
00429             // first, localise all attributes
00430             DoLocaliseCommonAttributes((NodeShadowController *)pShadowNode, TRUE);          
00431 
00432             // add children to the contour list
00433             pNode = pShadowNode->FindFirstChild();
00434             
00435             while (pNode)
00436             {
00437                 if (!pNode->NeedsParent(pShadowNode))
00438                 {
00439                     if (pNode->IsAnObject())
00440                     {
00441                         ALLOC_WITH_FAIL(pNewItem, new NodeListItem(pNode), this);
00442                         ListToContour.AddTail(pNewItem);
00443                     }
00444                 }
00445 
00446                 pNode = pNode->FindNext();
00447             }
00448         }
00449         else
00450         {
00451             ALLOC_WITH_FAIL(pNewItem, new NodeListItem(pItem->pNode), this);
00452             ListToContour.AddTail(pNewItem);
00453         }
00454 
00455         pItem = (NodeListItem *)pNodeList->GetNext(pItem);
00456     }
00457     
00458     // create the tree factory
00459     ContourNodeTreeFactory * pFactory = NULL;
00460     ALLOC_WITH_FAIL(pFactory, new ContourNodeTreeFactory, this);
00461 
00462     pFactory->SetNumberOfSteps(pCCP->m_Steps);
00463     pFactory->SetWidth(pCCP->m_Width);
00464     pFactory->SetInsetPathFlag(pCCP->m_bInsetPath);
00465 
00466     List SingleNodeList;
00467 
00468     // handle each node individually
00469     pItem = (NodeListItem *)ListToContour.GetHead();
00470 
00471     NodeBlender * pBlender = NULL;
00472 
00473     while (pItem)
00474     {
00475         ALLOC_WITH_FAIL(pNewItem, new NodeListItem(pItem->pNode), this);
00476 
00477         SingleNodeList.AddTail(pNewItem);
00478         
00479         NodeContourController * pContourNode = (NodeContourController *)pFactory->CreateNode(&SingleNodeList, this);
00480 
00481         SingleNodeList.DeleteAll();
00482         
00483         // do we have a parent shadow node ? if so, regenerate 
00484         if (!pContourNode)
00485         {
00486             FailAndExecute();
00487             End();
00488             ListToContour.DeleteAll();
00489             
00490             return;
00491         }
00492 
00493         // check for a blend needing to be re-initialised
00494         pBlender = (NodeBlender *)pContourNode->FindNext(CC_RUNTIME_CLASS(NodeBlender));
00495 
00496         if (pBlender)
00497         {
00498             if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), pBlender, TRUE, TRUE) != AC_OK)
00499                 ERROR2RAW("Couldn't Initialise blend action");
00500 
00501             pBlender->Reinit(pContourNode,  pBlender->GetNodeEnd(), FALSE);
00502         }
00503         else
00504         {
00505             pBlender = (NodeBlender *)pContourNode->FindPrevious(CC_RUNTIME_CLASS(NodeBlender));
00506 
00507             if (pBlender)
00508             {
00509                 if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), pBlender, TRUE, TRUE) != AC_OK)
00510                     ERROR2RAW("Couldn't Initialise blend action");
00511                     
00512                 pBlender->Reinit(pBlender->GetNodeStart(),  pContourNode, FALSE);
00513             }
00514         }
00515 
00516         if (pBlender)
00517         {
00518             NodeBlend* ptrBlend = (NodeBlend*) pBlender->FindParent ();
00519 
00520             ERROR3IF (!IS_A (ptrBlend, NodeBlend), "NodeBlend is not a NodeBlend!");
00521 
00522             BOOL done = FALSE;
00523             NodeBlender* ptrNode = ptrBlend->FindFirstBlender ();
00524 
00525             while (!done)
00526             {
00527                 if (ptrNode != pBlender)
00528                 {
00529                     if (ptrNode->GetNodeStart () == pItem->pNode)
00530                     {
00531                         if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), ptrNode, TRUE, TRUE) != AC_OK)
00532                             ERROR2RAW("Couldn't Initialise blend action");
00533 
00534                         if (pContourNode)
00535                             ptrNode->Reinit(pContourNode, NULL, FALSE);
00536                     }
00537                     if (ptrNode->GetNodeEnd () == pItem->pNode)
00538                     {
00539                         if (InitBlendAction::InitOnBlender(this, GetUndoActionList(),  ptrNode, TRUE, TRUE) != AC_OK)
00540                             ERROR2RAW("Couldn't Initialise blend action");
00541 
00542                         if (pContourNode)
00543                             ptrNode->Reinit(NULL, pContourNode, FALSE);
00544                     }
00545                 }
00546 
00547                 ptrNode = ptrBlend->FindNextBlender (ptrNode);
00548 
00549                 if (!ptrNode)
00550                     done = TRUE;
00551             }
00552         }
00553         
00554         pNode = pContourNode->FindParent();
00555         
00556         while (pNode)
00557         {
00558             pNode->AllowOp(&ObjChange);
00559             pNode = pNode->FindParent();
00560         }
00561 
00562         // deselect all nodes under the contour node, and select all original nodes
00563         if (!pCCP->m_bInsetPath)
00564         {
00565             pNode = pContourNode->FindFirstChild();
00566             pContourNode->SetSelected(FALSE);
00567             
00568             while (pNode)
00569             {
00570                 if (pNode->IsAnObject() && !pNode->NeedsParent(NULL))
00571                     pNode->SetSelected(TRUE);
00572                 
00573                 pNode = pNode->FindNext();
00574             }
00575         }
00576         else
00577         {
00578             NodeContour* pContour = pContourNode->GetContourNode();
00579             ERROR3IF(!pContour,"Failed to get the contour node from the controller node!");
00581             NodeRenderableInk* pChild = pContourNode->FindFirstChildInk();
00582             CCAttrMap AttrMap;
00583             
00584             if(pChild)
00585                 ((NodeRenderableInk *)pChild)->FindAppliedAttributes(&AttrMap);
00586 
00587             DoInvalidateNodeRegion(pContourNode,FALSE);
00588 
00589             // Create the DoBecomeA Function and call it on the controller
00590             BecomeA BecomeAReplace(BECOMEA_REPLACE, CC_RUNTIME_CLASS(NodePath), this, FALSE);
00591             pContour->DoBecomeA(&BecomeAReplace);
00592 
00593             // Now get the relavent path from the group of path nodes
00594             NodePath* pPathToCopy = NULL;
00595 
00596             if(pContourNode->IsContourAnOuterContour())
00597                 pPathToCopy = (NodePath*)pContourNode->FindFirstChild(CC_RUNTIME_CLASS(NodePath));
00598             else
00599                 pPathToCopy = (NodePath*)pContourNode->FindLastChild(CC_RUNTIME_CLASS(NodePath));
00600 
00601             // pPathToCopy may be NULL if the inset contour operation reduced the input paths
00602             // to nothingness...
00603             if (pPathToCopy)
00604             {
00605                 // Create and initialize a new NodePath to hold the inset path!
00606                 NodePath* pNewPath;
00607                 ALLOC_WITH_FAIL(pNewPath, new NodePath, this);
00608                 pNewPath->InkPath.Initialise();
00609     
00610                 pNewPath->InkPath.CloneFrom(pPathToCopy->InkPath);
00611     
00612                 // now Initialize the flag array with the new Path and insert it after the group node!
00613                 pNewPath->InkPath.InitialiseFlags(0, pNewPath->InkPath.GetNumCoords());
00614                 DoInsertNewNode(pNewPath, pContourNode, NEXT, TRUE, FALSE, TRUE, TRUE);
00615     
00616                 pNewPath->InkPath.IsFilled = TRUE;
00617     
00618                 // Make sure we have the correct attributes applied to our new path and make it selected!
00619                 AttrMap.ApplyAttributesToNode(pNewPath);
00620                 pNewPath->NormaliseAttributes();
00621                 
00622                 pNewPath->SetSelected(TRUE);
00623             }
00624             
00625             DoHideNode(pContourNode, TRUE, &pHidden, TRUE);
00627 /*
00628             pContourNode->SetSelected(FALSE);
00629             pContour->SetSelected(TRUE);
00630 
00631             // do a do become a for the contour node
00632             BecomeA BecomeAReplace(BECOMEA_REPLACE, CC_RUNTIME_CLASS(NodePath), this, FALSE);
00633             pContourNode->DoBecomeA(&BecomeAReplace);
00634 */
00635         }
00636 
00637         SliceHelper::AddNamesToController(this,pContourNode);
00638 
00639         pItem = (NodeListItem *)ListToContour.GetNext(pItem);
00640     }
00641         
00642     ListToContour.DeleteAll();
00643 
00644     delete pFactory;
00645     pFactory = NULL;
00646 
00647     ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
00648     UpdateChangedNodes(&ObjChange, Document::GetSelectedSpread());
00649 
00650     GetApplication()->UpdateSelection();
00651     
00652     End();
00653 }
00654 
00655 /********************************************************************************************
00656 
00657 >   BOOL OpCreateContour::Declare()
00658 
00659     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00660     Created:    16/11/94                                                                        
00661     Returns:    TRUE if all went OK, False otherwise
00662     Purpose:    Adds the operation to the list of all known operations
00663 
00664 ********************************************************************************************/
00665 BOOL OpCreateContour::Declare()
00666 {
00667     return (RegisterOpDescriptor(
00668                                 0, 
00669                                 _R(IDS_CREATECONTOUROP),
00670                                 CC_RUNTIME_CLASS(OpCreateContour), 
00671                                 OPTOKEN_CREATECONTOUR,
00672                                 OpCreateContour::GetState));
00673 
00674 }
00675 
00676 
00677 
00678 /********************************************************************************************
00679 
00680 >   OpState OpCreateContour::GetState(String_256* Description, OpDescriptor*)
00681 
00682     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00683     Created:    16/11/94
00684     Outputs:    -
00685     Returns:    Ungreyed, Unticked
00686     Purpose:    Find out the state of the new regular shape at the specific time
00687 
00688 ********************************************************************************************/
00689 OpState OpCreateContour::GetState(String_256* Description, OpDescriptor*)
00690 {
00691     OpState Blobby;
00692 
00693     if (Description)
00694         Description->Load(_R(IDS_CONTOUR_CREATE_STATUS_STRING));
00695     
00696     return Blobby;
00697 }
00698 
00705 // Bevel ops implementation
00706 
00707 /********************************************************************************************
00708 >   OpRemoveContour::OpRemoveContour()
00709 
00710     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00711     Created:    12/8/99
00712     Purpose:    Constructor.
00713 ********************************************************************************************/
00714 OpRemoveContour::OpRemoveContour()
00715 {
00716     //TRACEUSER( "MarkH", _T("Just Made a OpRemoveContour Class!\n"));
00717 }
00718 
00719 
00720 
00721 /********************************************************************************************
00722 >   OpRemoveContour::~OpRemoveContour()
00723 
00724     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00725     Created:    12/8/99
00726     Purpose:    Destructor.
00727 ********************************************************************************************/
00728 OpRemoveContour::~OpRemoveContour()
00729 {
00730     //TRACEUSER( "MarkH", _T("Just Killed OpRemoveContour Class!!!\n"));
00731 }
00732 
00733 
00734 
00735 /********************************************************************************************
00736 >   virtual void OpRemoveContour::Do(OpDescriptor *pOpDesc)
00737 
00738     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00739     Created:    12/8/99
00740     Inputs:     pOpDesc - OpDescriptor - unused
00741     Outputs:    -
00742     Returns:    -
00743     Purpose:    The do function.  Applys a Bevel to the selection in the current document
00744 ********************************************************************************************/
00745 void OpRemoveContour::Do(OpDescriptor *pOpDesc)
00746 {
00747     // CGS:  (13/7/2000)  I have ammended this function to take into account multiple NodeBlends
00748     // since the contour may be part of more than one blend!
00749     
00750     // get all the contour nodes
00751     DoStartSelOp(TRUE, TRUE);
00752     ObjChangeFlags cFlags;
00753     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
00754 
00755     String_64 s(_T("Removing contour - please wait"));
00756     BeginSlowJob(-1, TRUE, &s);
00757 
00758     List NodeList;
00759     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController), TRUE);
00760 
00761     //List BlendList;
00762     //BevelTools::BuildListOfSelectedNodes(&BlendList, CC_RUNTIME_CLASS(NodeBlender), TRUE);
00763 
00764     // run through these nodes, eliminating them
00765     NodeListItem * pItem = (NodeListItem *)NodeList.GetHead();
00766 
00767     Node * pChildNode = NULL;
00768     Node * pNextNode = NULL;
00769     NodeHidden * pHidden = NULL;
00770 
00771     Node * pParent = NULL;
00772 
00773     BOOL ok = TRUE;
00774 
00775     NodeContourController * pControl = NULL;
00776 
00777     NodeBlender * pBlender = NULL;
00778     BOOL bBlendBefore = FALSE;
00779     BOOL bBlendAfter = FALSE;
00780 
00781     // for blends
00782     NodeRenderableInk *pRenderableNode = NULL;
00783 
00784     while (pItem)
00785     {
00786         pControl = (NodeContourController *)pItem->pNode;
00787 
00788         // try to find a blender node, as if there's one present we
00789         // need to reinitialise it
00790         pBlender = (NodeBlender *)pControl->FindNext(CC_RUNTIME_CLASS(NodeBlender));
00791 
00792         bBlendBefore = FALSE;
00793         bBlendAfter = FALSE;
00794         if (pBlender)
00795         {
00796             bBlendBefore = TRUE;
00797         }
00798         else
00799         {
00800             pBlender = (NodeBlender *)pControl->FindPrevious(CC_RUNTIME_CLASS(NodeBlender));
00801 
00802             if (pBlender)
00803             {
00804                 bBlendAfter = TRUE;
00805             }
00806         }
00807         
00808         // get the parent for child change messaging
00809         pParent = pControl->FindParent();
00810 
00811         // invalidate the region
00812         if (ok)
00813             ok = DoInvalidateNodeRegion(pControl, TRUE);
00814         
00815         // factor out the common child attributes
00816         if (ok)
00817             ok = DoLocaliseCommonAttributes(pControl, TRUE);
00818 
00819         if (ok)
00820             SliceHelper::RemoveNamesFromController(this,pControl);
00821 
00822         pChildNode = pControl->FindFirstChild();
00823 
00824         // move all nodes to being siblings of the controller node, except for the
00825         // contour node itself
00826         while (pChildNode)
00827         {
00828             pNextNode = pChildNode->FindNext();
00829 
00830             if (pChildNode->IsAnObject() && !pChildNode->IS_KIND_OF(NodeContour))
00831             {
00832                 if (ok)
00833                 {
00834                     ok = DoMoveNode(pChildNode, pControl, PREV);
00835                 }
00836 
00837                 if (ok)
00838                     ok = DoSelectNode((NodeRenderableInk *)pChildNode);
00839 
00840                 if (ok)
00841                     ok = DoFactorOutAfterAttrChange((NodeRenderableInk *)pChildNode, 
00842                                                     (AttrTypeSet *)NULL);
00843             }
00844 
00845             pChildNode = pNextNode;
00846         }
00847 
00848         pParent = pControl->FindParent();
00849 
00850         // agh why do i have to mess with a list just to add this action into the undo list?
00851         List ContList;
00852         NodeListItem * pActionItem = NULL;
00853         RegenerateContourAction* pRegenAction = NULL;
00854         ALLOC_WITH_FAIL(pActionItem, new NodeListItem, this);
00855 
00856         pActionItem->pNode = pControl;
00857         ContList.AddTail(pActionItem);
00858 
00859         RegenerateContourAction::Init(this, GetUndoActionList(),&ContList,&pRegenAction, TRUE);
00860 
00861         ContList.DeleteAll();
00862 
00863         // now, hide the controller node
00864         if (ok)
00865             ok = DoHideNode(pControl, TRUE, &pHidden, FALSE);
00866 
00867         // reinit the blends (if necessary)
00868         if (ok)
00869         {
00870             if (bBlendBefore)
00871             {
00872                 if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), pBlender, TRUE, TRUE) != AC_OK)
00873                 {
00874                     ERROR2RAW("Couldn't Initialise blend action");
00875                 }
00876 
00877                 // reinit the node
00878                 pRenderableNode = (NodeRenderableInk *)pBlender->FindPrevious(CC_RUNTIME_CLASS(NodeRenderableInk)); 
00879                     
00880                 if (pRenderableNode)
00881                 {
00882                     pBlender->Reinit(pRenderableNode,   pBlender->GetNodeEnd(), FALSE);
00883                 }
00884             }
00885             else if (bBlendAfter)
00886             {
00887                 if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), pBlender, TRUE, TRUE) != AC_OK)
00888                 {
00889                     ERROR2RAW("Couldn't Initialise blend action");
00890                 }
00891 
00892                 // reinit the node
00893                 pRenderableNode = (NodeRenderableInk *)pBlender->FindNext(CC_RUNTIME_CLASS(NodeRenderableInk)); 
00894                     
00895                 if (pRenderableNode)
00896                 {
00897                     pBlender->Reinit(pBlender->GetNodeStart(), pRenderableNode, FALSE);
00898                 }
00899             }
00900 
00901             if (pBlender)
00902             {
00903                 NodeBlend* ptrBlend = (NodeBlend*) pBlender->FindParent ();
00904 
00905                 ERROR3IF (!IS_A (ptrBlend, NodeBlend), "NodeBlend is not a NodeBlend!");
00906 
00907                 BOOL done = FALSE;
00908                 NodeBlender* ptrNode = ptrBlend->FindFirstBlender ();
00909 
00910                 while (!done)
00911                 {
00912                     if (ptrNode != pBlender)
00913                     {
00914                         if (ptrNode->GetNodeStart () == pControl)
00915                         {
00916                             if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), ptrNode, TRUE, TRUE) != AC_OK)
00917                             {
00918                                 ERROR2RAW("Couldn't Initialise blend action");
00919                             }
00920                             
00921                             if (pRenderableNode)
00922                             {
00923                                 ptrNode->Reinit(pRenderableNode, NULL, FALSE);
00924                             }
00925                         }
00926                         if (ptrNode->GetNodeEnd () == pControl)
00927                         {
00928                             if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), ptrNode, TRUE, TRUE) != AC_OK)
00929                             {
00930                                 ERROR2RAW("Couldn't Initialise blend action");
00931                             }
00932 
00933                             if (pRenderableNode)
00934                             {
00935                                 ptrNode->Reinit(NULL, pRenderableNode, FALSE);
00936                             }
00937                         }
00938                     }
00939 
00940                     ptrNode = ptrBlend->FindNextBlender (ptrNode);
00941 
00942                     if (!ptrNode)
00943                     {
00944                         done = TRUE;
00945                     }
00946                 }
00947             }
00948         }
00949             
00950         // Karim 19/07/2000
00951         // the parent's bounds will have changed, so tell them so.
00952         if (pParent->IsBounded())       // paranoia code - this is always true.
00953             ((NodeRenderableBounded*)pParent)->InvalidateBoundingRect();
00954 
00955         // update all the changed nodes on the parent of the contour
00956 //      ObjChangeFlags flgs(FALSE, FALSE, FALSE, TRUE);
00957 //      flgs.RegenerateNode = TRUE;
00958 //      ObjChangeParam OP(OBJCHANGE_FINISHED, flgs, NULL, this, OBJCHANGE_CALLEDBYOP);
00959 
00960         while (pParent)
00961         {
00962             pParent->AllowOp(&ObjChange);
00963 //          pParent->OnChildChange(&OP);
00964 
00965             pParent = pParent->FindParent();
00966         }
00967 
00968         // go onto the next item
00969         pItem = (NodeListItem *)NodeList.GetNext(pItem);
00970         
00971     }
00972 
00973     NodeList.DeleteAll();
00974 
00975     if (!ok)
00976     {
00977         FailAndExecute();
00978     }
00979 
00980     ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
00981     UpdateChangedNodes(&ObjChange, Document::GetSelectedSpread());
00982 
00983     GetApplication()->UpdateSelection();
00984 
00985     End();
00986 }
00987 
00988 
00989 /********************************************************************************************
00990 >   void OpRemoveContour::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
00991 
00992     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00993     Created:    12/8/99
00994     Inputs:     
00995     Outputs:    -
00996     Returns:    -
00997     Purpose:    Applys a Bevel to the selected node after a mouse click
00998 ********************************************************************************************/
00999 
01000 void OpRemoveContour::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
01001 {
01002     End();
01003 }
01004 
01005 /********************************************************************************************
01006 
01007 >   BOOL OpRemoveContour::Declare()
01008 
01009     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01010     Created:    16/11/94                                                                        
01011     Returns:    TRUE if all went OK, False otherwise
01012     Purpose:    Adds the operation to the list of all known operations
01013 
01014 ********************************************************************************************/
01015 BOOL OpRemoveContour::Declare()
01016 {
01017     return (RegisterOpDescriptor(
01018                                 0, 
01019                                 _R(IDS_REMOVECONTOUROP),
01020                                 CC_RUNTIME_CLASS(OpRemoveContour), 
01021                                 OPTOKEN_REMOVECONTOUR,
01022                                 OpRemoveContour::GetState,
01023                                 0,
01024                                 _R(IDBBL_REMOVECONTOUR),
01025                                 0));
01026 
01027 }
01028 
01029 
01030 
01031 /********************************************************************************************
01032 
01033 >   OpState OpRemoveContour::GetState(String_256* Description, OpDescriptor*)
01034 
01035     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01036     Created:    16/11/94
01037     Outputs:    -
01038     Returns:    Ungreyed, Unticked
01039     Purpose:    Find out the state of the new regular shape at the specific time
01040 
01041 ********************************************************************************************/
01042 OpState OpRemoveContour::GetState(String_256* Description, OpDescriptor*)
01043 {
01044     OpState State(FALSE,TRUE); // It's not ticked, but it is greyed by default
01045     
01046     // Get an ObjChangeParam ready so we can tell the selected blend's parents what we hope to do 
01047     // to the blend (i.e. replace it with other nodes).
01048     ObjChangeFlags cFlags;
01049     cFlags.MultiReplaceNode = TRUE;
01050     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,NULL);
01051 
01052 //  BOOL Denied = FALSE;
01053     List NodeList;
01054     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController), TRUE);
01055 
01056     if (NodeList.IsEmpty())
01057     {
01058         State.Greyed = TRUE;
01059     }
01060     else
01061     {
01062         State.Greyed = FALSE;
01063     }
01064 
01065     NodeList.DeleteAll();
01066 
01067     UINT32 IDS = 0;
01068     
01069 
01070     if (IDS == 0)
01071         IDS = _R(IDS_REMOVECONTOUR);
01072 
01073     *Description = String_256(IDS);
01074 
01075     return State;
01076 }
01077 
01079 // RegenerateContourAction class implementation
01080 /********************************************************************************************
01081 
01082 >   RegenerateContourAction::RegenerateContourAction()
01083 
01084     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
01085     Created:    07/01/97
01086     Inputs:     -
01087     Outputs:    -
01088     Returns:    -
01089     Purpose:    Constructor for the action
01090     Errors:     -
01091     SeeAlso:    -
01092 
01093 ********************************************************************************************/
01094 
01095 RegenerateContourAction::RegenerateContourAction()
01096 {
01097     m_pNodes = NULL;
01098     m_bCache = FALSE;
01099 }
01100 
01101 
01102 /********************************************************************************************
01103 
01104 >   ActionCode RegenerateContourAction::Init(   Operation*  pOp,
01105                                                 ActionList* pActionList,
01106                                                 List * pNodes
01107                                                 ChangePositionShadowXAction**   ppNewAction);
01108 
01109     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01110     Created:    17/3/99
01111     Inputs:     pOp             = ptr to the operation to which this action belongs
01112                 pActionList     =  ptr to action list to which this action should be added
01113                 pNodes          = ptr to node list containing the NodeBevel nodes to be 
01114                                   regenerated   
01115     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
01116                                   a pointer to the created action
01117     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01118     Purpose:    This is the function which creates an instance of this action. If there is no room 
01119                 in the undo buffer (which is determined by the base class Init function called within)
01120                 the function will either return AC_NO_RECORD which means the operation can continue, 
01121                 but no undo information needs to be stored, or AC_OK which means the operation should
01122                 continue AND record undo information. If the function returns AC_FAIL, there was not 
01123                 enough memory to record the undo information, and the user has decided not to continue
01124                 with the operation.
01125     Errors:     -
01126     SeeAlso:    Action::Init()
01127 
01128 ********************************************************************************************/
01129 
01130 
01131 
01132 ActionCode RegenerateContourAction::Init(Operation* pOp,
01133                                         ActionList* pActionList,
01134                                         List * pNodes,
01135                                         RegenerateContourAction** ppNewAction,
01136                                         BOOL bCache)
01137 {
01138     UINT32 ActSize = sizeof(RegenerateContourAction);
01139     
01140     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(RegenerateContourAction),(Action**)ppNewAction);
01141 
01142     // make a copy of the node list
01143     List * pCopyList = NULL;
01144     ALLOC_WITH_FAIL(pCopyList, new List, pOp);
01145     NodeListItem * pItem = (NodeListItem *)pNodes->GetHead();
01146     NodeListItem * pCopyItem = NULL;
01147 
01148     while (pItem)
01149     {
01150         ALLOC_WITH_FAIL(pCopyItem, new NodeListItem, pOp);
01151         pCopyItem->pNode = pItem->pNode;
01152         
01153         pCopyList->AddTail(pCopyItem);
01154 
01155         pItem = (NodeListItem *)pNodes->GetNext(pItem);
01156     }
01157 
01158     (*ppNewAction)->m_pNodes = pCopyList;
01159     (*ppNewAction)->m_bCache = bCache;
01160 
01161     pItem = (NodeListItem *)pNodes->GetHead();
01162 
01163     DocView * pView = DocView::GetCurrent();
01164 
01165     Document * pDoc = Document::GetCurrent();
01166 
01167     DocRect dr;
01168 
01169     if (Ac != AC_FAIL)
01170     {
01171         while (pItem)
01172         {
01173             if (pItem->pNode && !pItem->pNode->IsNodeHidden() && pItem->pNode->FindParent()!=NULL)
01174             {
01175                 dr = dr.Union(((NodeRenderableBounded *)pItem->pNode)->GetBoundingRect());
01176                 
01177                 if (pView && bCache)
01178                 {
01179                     GetApplication()->AddNodeToRegenList(pItem->pNode);
01180                 }
01181                 else
01182                 {
01183                     ((NodeContourController *)(pItem->pNode))->RegenerateNode(NULL, FALSE);
01184                 }
01185 
01186                 dr = dr.Union(((NodeRenderableBounded *)pItem->pNode)->GetBoundingRect());
01187             }
01188             ((NodeRenderableInk*)pItem->pNode)->ReleaseCached();
01189     
01190             pItem = (NodeListItem *)pNodes->GetNext(pItem);
01191         }
01192 
01193         if (pDoc)
01194         {
01195             if (Document::GetSelectedSpread())
01196             {
01197                 pDoc->ForceRedraw(Document::GetSelectedSpread(), 
01198                     dr);
01199             }
01200         }
01201     }
01202 
01203     (*ppNewAction)->m_OldRect = dr;
01204 
01205     // move my action to the head of the list
01206     // I have a problem, for certain ops we need to do the following, BUT for others
01207     // we don't (otherwise access violations occur).  um?
01208     pActionList->RemoveItem(*ppNewAction);
01209     pActionList->AddHead(*ppNewAction);
01210 
01211     return Ac;
01212 }
01213 
01214 /********************************************************************************************
01215 
01216 >   ActionCode RegenerateContourAction::Execute();
01217 
01218     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01219     Created:    17/3/99
01220     Inputs:     -
01221     Outputs:    -
01222     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01223     Purpose:    Executes the action.  Causes a regen of all bevels nodes in the action's list
01224     Errors:     -
01225     SeeAlso:    Action::Init()
01226 
01227 ********************************************************************************************/
01228 
01229 ActionCode RegenerateContourAction::Execute()
01230 {
01231     ActionCode Act;
01232     RegenerateContourAction* pAction;
01233     
01234     Act = RegenerateContourAction::Init(pOperation, 
01235                                         pOppositeActLst,
01236                                         m_pNodes,
01237                                         &pAction,
01238                                         m_bCache);
01239 
01240     if (Act != AC_FAIL)
01241     {
01242     }
01243 
01244     return Act;
01245 }
01246 
01247 RegenerateContourAction::~RegenerateContourAction()
01248 {
01249     if (m_pNodes)
01250     {
01251         m_pNodes->DeleteAll();
01252         delete m_pNodes;
01253     }
01254 }
01255 
01257 // Contour ops implementation
01258 
01259 /********************************************************************************************
01260 >   OpChangeContourWidth::OpChangeContourWidth()
01261 
01262     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01263     Created:    12/8/99
01264     Purpose:    Constructor.
01265 ********************************************************************************************/
01266 OpChangeContourWidth::OpChangeContourWidth()
01267 {
01268     //TRACEUSER( "MarkH", _T("Just Made a OpChangeContourWidth Class!\n"));
01269 }
01270 
01271 
01272 
01273 /********************************************************************************************
01274 >   OpChangeContourWidth::~OpChangeContourWidth()
01275 
01276     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01277     Created:    12/8/99
01278     Purpose:    Destructor.
01279 ********************************************************************************************/
01280 OpChangeContourWidth::~OpChangeContourWidth()
01281 {
01282     //TRACEUSER( "MarkH", _T("Just Killed OpChangeContourWidth Class!!!\n"));
01283 }
01284 
01285 
01286 
01287 /********************************************************************************************
01288 >   virtual void OpChangeContourWidth::Do(OpDescriptor *pOpDesc)
01289 
01290     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01291     Created:    12/8/99
01292     Inputs:     pOpDesc - OpDescriptor - unused
01293     Outputs:    -
01294     Returns:    -
01295     Purpose:    The do function.  Applys a Bevel to the selection in the current document
01296 ********************************************************************************************/
01297 void OpChangeContourWidth::Do(OpDescriptor *pOpDesc)
01298 {
01299     End();
01300 }
01301 
01302 
01303 /********************************************************************************************
01304 >   void OpChangeContourWidth::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
01305 
01306     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01307     Created:    12/8/99
01308     Inputs:     
01309     Outputs:    -
01310     Returns:    -
01311     Purpose:    Applys a Bevel to the selected node after a mouse click
01312 ********************************************************************************************/
01313 
01314 void OpChangeContourWidth::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
01315 {
01316     // first, begin the operation
01317     ObjChangeFlags cFlags;
01318     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
01319 
01320     String_64 StatusString;
01321     StatusString.Load(_R(IDS_CONTOUR_CREATE_STATUS_STRING));
01322 
01323     BeginSlowJob(-1, TRUE, &StatusString);
01324 
01325     ChangeContourWidthParam * pCCW = (ChangeContourWidthParam *)pParam;
01326 
01327     // fire off an action
01328     ChangeContourWidthAction * pAction = NULL;
01329 
01330     if (ChangeContourWidthAction::Init(this, this->GetUndoActionList(), pCCW->m_pNodes, pCCW->m_Width,
01331         pCCW->m_bKeepDirection, &pAction) != AC_OK)
01332     {
01333         FailAndExecute();
01334         return;
01335     }
01336 
01337     // do the child change messages
01338     NodeListItem * pItem = (NodeListItem *)pCCW->m_pNodes->GetHead();
01339 
01340     Node * pNode = NULL;
01341 
01342     ObjChangeFlags flgs(FALSE, FALSE, FALSE, TRUE);
01343     Node * pContourNode = NULL;
01344     Node * pInsertNode  = NULL;
01345 
01346     BOOL ok = TRUE;
01347 
01348     while (pItem)
01349     {
01350         // move all contour nodes in the list appropriately
01351         if (!pCCW->m_bKeepDirection)
01352         {
01353             pContourNode = pItem->pNode->FindFirstChild(CC_RUNTIME_CLASS(NodeContour));
01354 
01355             if (pContourNode)
01356                 pContourNode->AllowOp(&ObjChange);
01357 
01358             if (pCCW->m_Width < 0)
01359             {
01360                 // outer contour nodes come before the nodes they are contouring
01361                 
01362                 pInsertNode = pItem->pNode->FindFirstChild(CC_RUNTIME_CLASS(NodeRenderableInk));
01363                 
01364                 if (pInsertNode != pContourNode)
01365                 {
01366                     if (ok)
01367                         ok = DoMoveNode(pContourNode, pInsertNode, PREV);
01368                 }
01369             }
01370             else
01371             {
01372                 // inner contour nodes come after the nodes they are contouring
01373                 
01374                 pInsertNode = pItem->pNode->FindLastChild(CC_RUNTIME_CLASS(NodeRenderableInk));
01375                 
01376                 if (pInsertNode != pContourNode)
01377                 {
01378                     if (ok)
01379                         ok = DoMoveNode(pContourNode, pInsertNode, NEXT);
01380                 }
01381             }
01382         }
01383             
01384         pNode = pItem->pNode->FindParent();
01385 
01386         // Ilan 7/5/00
01387         // Inform geom linked attrs of the change. Nb outside the normal AllowOp mechanism
01388         NodeAttribute* pNA = pItem->pNode->FindFirstGeometryLinkedAttr();
01389         while(pNA)
01390         {
01391             pNA->LinkedNodeGeometryHasChanged(this);
01392             pNA = pNA->FindNextGeometryLinkedAttr();
01393         }
01394 
01395         while (pNode)
01396         {
01397             //ObjChangeParam OP(OBJCHANGE_FINISHED, flgs, pNode, this, OBJCHANGE_CALLEDBYOP);
01398 
01399             if (pNode->IsAnObject())
01400             {
01401                 //pNode->OnChildChange(&OP);
01402                 pNode->AllowOp(&ObjChange);
01403             }
01404 
01405             pNode = pNode->FindParent();
01406         }
01407 
01408         pItem = (NodeListItem *)pCCW->m_pNodes->GetNext(pItem);
01409     }
01410 
01411     ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
01412     UpdateChangedNodes(&ObjChange, Document::GetSelectedSpread());
01413 
01414     End();
01415 }
01416 
01417 /********************************************************************************************
01418 
01419 >   BOOL OpChangeContourWidth::Declare()
01420 
01421     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01422     Created:    16/11/94                                                                        
01423     Returns:    TRUE if all went OK, False otherwise
01424     Purpose:    Adds the operation to the list of all known operations
01425 
01426 ********************************************************************************************/
01427 BOOL OpChangeContourWidth::Declare()
01428 {
01429     return (RegisterOpDescriptor(
01430                                 0, 
01431                                 _R(IDS_CHANGECONTOURWIDTHOP),
01432                                 CC_RUNTIME_CLASS(OpChangeContourWidth), 
01433                                 OPTOKEN_CHANGECONTOURWIDTH,
01434                                 OpChangeContourWidth::GetState));
01435 
01436 }
01437 
01438 
01439 
01440 /********************************************************************************************
01441 
01442 >   OpState OpChangeContourWidth::GetState(String_256* Description, OpDescriptor*)
01443 
01444     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01445     Created:    16/11/94
01446     Outputs:    -
01447     Returns:    Ungreyed, Unticked
01448     Purpose:    Find out the state of the new regular shape at the specific time
01449 
01450 ********************************************************************************************/
01451 OpState OpChangeContourWidth::GetState(String_256* Description, OpDescriptor*)
01452 {
01453     OpState Blobby;
01454     
01455     return Blobby;
01456 }
01457 
01458 /********************************************************************************************
01459 
01460 >   void OpChangeContourWidth::GetOpName(String_256 *pName)
01461 
01462     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01463     Created:    25/11/99
01464     Outputs:    -
01465     Returns:    The name of the op
01466     Purpose:    Returns the name of this op
01467 
01468 ********************************************************************************************/
01469 void OpChangeContourWidth::GetOpName(String_256 *pName)
01470 {
01471     if (pName)
01472         pName->Load(_R(IDS_CHANGECONTOURWIDTHOPNAME));
01473 }
01474 
01475 
01477 // ChangeContourWidthAction class implementation
01478 /********************************************************************************************
01479 
01480 >   ChangeContourWidthAction::ChangeContourWidthAction()
01481 
01482     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
01483     Created:    07/01/97
01484     Inputs:     -
01485     Outputs:    -
01486     Returns:    -
01487     Purpose:    Constructor for the action
01488     Errors:     -
01489     SeeAlso:    -
01490 
01491 ********************************************************************************************/
01492 
01493 ChangeContourWidthAction::ChangeContourWidthAction()
01494 {
01495 
01496 }
01497 
01498 
01499 /********************************************************************************************
01500 
01501 >   ActionCode ChangeContourWidthAction::Init(  Operation*  pOp,
01502                                                 ActionList* pActionList,
01503                                                 List * pNodes
01504                                                 ChangePositionShadowXAction**   ppNewAction);
01505 
01506     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01507     Created:    17/3/99
01508     Inputs:     pOp             = ptr to the operation to which this action belongs
01509                 pActionList     =  ptr to action list to which this action should be added
01510                 pNodes          = ptr to node list containing the NodeBevel nodes to be 
01511                                   addressed
01512                 NewWidth        = the new width to set all nodes in the list to
01513                 bKeepDirection  = Whether to keep the direction (either inner or outer) when
01514                                   setting the widths, or just to take the width as passed in
01515     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
01516                                   a pointer to the created action
01517     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01518     Purpose:    This is the function which creates an instance of this action. If there is no room 
01519                 in the undo buffer (which is determined by the base class Init function called within)
01520                 the function will either return AC_NO_RECORD which means the operation can continue, 
01521                 but no undo information needs to be stored, or AC_OK which means the operation should
01522                 continue AND record undo information. If the function returns AC_FAIL, there was not 
01523                 enough memory to record the undo information, and the user has decided not to continue
01524                 with the operation.
01525     Errors:     -
01526     SeeAlso:    Action::Init()
01527 
01528 ********************************************************************************************/
01529 
01530 
01531 
01532 ActionCode ChangeContourWidthAction::Init(Operation* pOp,
01533                                         ActionList* pActionList,
01534                                         List * pNodes,
01535                                         MILLIPOINT NewWidth,
01536                                         BOOL bKeepDirection,
01537                                         ChangeContourWidthAction** ppNewAction)
01538 {
01539     if (bKeepDirection && NewWidth < 0)
01540     {
01541         ERROR3("Can't keep the direction when the width is < 0");
01542         return AC_FAIL;
01543     }
01544     
01545     UINT32 ActSize = sizeof(ChangeContourWidthAction);
01546     
01547     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(ChangeContourWidthAction),(Action**)ppNewAction);
01548 
01549     NodeListItem * pItem = NULL;
01550     NodeListItem * pNewItem = NULL;
01551 
01552     ContourWidthListItem * pNewWidthItem = NULL;
01553 
01554     Document * pDoc = Document::GetCurrent();
01555 
01556     NodeContourController * pContour = NULL;
01557 
01558     MILLIPOINT MaxWidth = 0;
01559 
01560     if (Ac == AC_OK)
01561     {
01562         // make a copy of the node list
01563         pItem = (NodeListItem *)pNodes->GetHead();
01564 
01565         while (pItem)
01566         {
01567             // store the node, and its old width value
01568             pContour = (NodeContourController *)pItem->pNode;
01569 
01570             ALLOC_WITH_FAIL(pNewItem, new NodeListItem(pContour), pOp);
01571             ALLOC_WITH_FAIL(pNewWidthItem, new ContourWidthListItem(pContour->GetWidth()), pOp);
01572 
01573             // invalidate the old rect
01574             if (pDoc)
01575             {
01576                 pDoc->ForceRedraw(pContour->FindParentSpread(), pContour->GetBoundingRect(FALSE, FALSE),
01577                     FALSE, pContour);
01578             }
01579 
01580             // regenerate the node
01581             if (NewWidth != 0)
01582             {
01583                 // set the contour controller's new width
01584                 if (!bKeepDirection)
01585                 {
01586                     if (NewWidth > 0)
01587                     {
01588                         MaxWidth = ContourNodePathProcessor::GetMaxInnerContourWidth(pContour);
01589 
01590                         if (NewWidth > MaxWidth)
01591                         {
01592                             pContour->SetWidth(MaxWidth);
01593                         }
01594                         else
01595                         {
01596                             pContour->SetWidth(NewWidth);
01597                         }
01598                     }
01599                     else
01600                     {
01601                         pContour->SetWidth(NewWidth);
01602                     }                   
01603                 }
01604                 else
01605                 {
01606                     if (pContour->GetWidth() < 0)
01607                     {
01608                         pContour->SetWidth(-NewWidth);
01609                     }
01610                     else
01611                     {
01612                         MaxWidth = ContourNodePathProcessor::GetMaxInnerContourWidth(pContour);
01613 
01614                         if (NewWidth > MaxWidth)
01615                         {
01616                             pContour->SetWidth(MaxWidth);
01617                         }
01618                         else
01619                         {
01620                             pContour->SetWidth(NewWidth);
01621                         }
01622                     }
01623                 }
01624 
01625                 pContour->RegenerateNode(NULL, FALSE);
01626             }
01627 
01628             // invalidate the new rect
01629             if (pDoc)
01630             {
01631                 pDoc->ForceRedraw(pContour->FindParentSpread(), pContour->GetBoundingRect(FALSE, FALSE),
01632                     FALSE, pContour);
01633             }
01634 
01635             // add the items to the lists
01636             (*ppNewAction)->m_Nodes.AddTail(pNewItem);
01637             (*ppNewAction)->m_WidthList.AddTail(pNewWidthItem);
01638 
01639             pItem = (NodeListItem *)pNodes->GetNext(pItem);
01640         }
01641     }
01642     
01643     return Ac;
01644 }
01645 
01646 /********************************************************************************************
01647 
01648 >   ActionCode ChangeContourWidthAction::Execute();
01649 
01650     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01651     Created:    17/3/99
01652     Inputs:     -
01653     Outputs:    -
01654     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01655     Purpose:    Executes the action.  Causes a regen of all bevels nodes in the action's list
01656     Errors:     -
01657     SeeAlso:    Action::Init()
01658 
01659 ********************************************************************************************/
01660 
01661 ActionCode ChangeContourWidthAction::Execute()
01662 {
01663     ChangeContourWidthAction * pNewAction = NULL;
01664 
01665     // first, initialise an action to restore all the current widths in my list
01666     ActionCode Ac = ChangeContourWidthAction::Init(pOperation,
01667                                                    pOppositeActLst,
01668                                                    &m_Nodes,
01669                                                    0, // tell the action not to regen - I'm 
01670                                                    FALSE,  // going to do that
01671                                                    &pNewAction);
01672 
01673     NodeListItem * pItem = NULL;
01674     NodeContourController * pContour = NULL;
01675     ContourWidthListItem * pWidthItem = NULL;
01676 
01677     Document * pDoc = Document::GetCurrent();
01678 
01679     if (Ac == AC_OK)
01680     {
01681         // run through my lists resetting the original widths back to what they were
01682         pItem = (NodeListItem *)m_Nodes.GetHead();
01683         pWidthItem = (ContourWidthListItem *)m_WidthList.GetHead();
01684 
01685         while (pItem && pWidthItem)
01686         {
01687             pContour = (NodeContourController *)pItem->pNode;
01688 
01689             // invalidate the old rect
01690             if (pDoc)
01691             {
01692                 pDoc->ForceRedraw(pContour->FindParentSpread(), 
01693                     pContour->GetBoundingRect(FALSE, FALSE),
01694                     FALSE, pContour);
01695             }
01696 
01697             // restore the width of the node, and regenerate
01698             pContour->SetWidth(pWidthItem->m_Width);
01699 
01700             pContour->RegenerateNode(NULL, FALSE);
01701 
01702             // invalidate the new rect
01703             if (pDoc)
01704             {
01705                 pDoc->ForceRedraw(pContour->FindParentSpread(), 
01706                     pContour->GetBoundingRect(FALSE, FALSE),
01707                     FALSE, pContour);
01708             }
01709 
01710             pItem = (NodeListItem *)m_Nodes.GetNext(pItem);
01711             pWidthItem = (ContourWidthListItem *)m_WidthList.GetNext(pWidthItem);
01712         }
01713     }
01714     
01715     return Ac;
01716 }
01717 
01718 ChangeContourWidthAction::~ChangeContourWidthAction()
01719 {
01720     m_Nodes.DeleteAll();
01721     m_WidthList.DeleteAll();
01722 }
01723 
01725 // ChangeContourToOuterAction class implementation
01726 /********************************************************************************************
01727 
01728 >   ChangeContourToOuterAction::ChangeContourToOuterAction()
01729 
01730     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
01731     Created:    07/01/97
01732     Inputs:     -
01733     Outputs:    -
01734     Returns:    -
01735     Purpose:    Constructor for the action
01736     Errors:     -
01737     SeeAlso:    -
01738 
01739 ********************************************************************************************/
01740 
01741 ChangeContourToOuterAction::ChangeContourToOuterAction()
01742 {
01743     m_LastWidth = 0;
01744 
01745 }
01746 
01747 
01748 /********************************************************************************************
01749 
01750 >   ActionCode ChangeContourToOuterAction::Init(    Operation*  pOp,
01751                                                 ActionList* pActionList,
01752                                                 List * pNodes
01753                                                 ChangePositionShadowXAction**   ppNewAction);
01754 
01755     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01756     Created:    17/3/99
01757     Inputs:     pOp             = ptr to the operation to which this action belongs
01758                 pActionList     =  ptr to action list to which this action should be added
01759                 pNodes          = ptr to node list containing the NodeBevel nodes to be 
01760                                   regenerated   
01761     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
01762                                   a pointer to the created action
01763     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01764     Purpose:    This is the function which creates an instance of this action. If there is no room 
01765                 in the undo buffer (which is determined by the base class Init function called within)
01766                 the function will either return AC_NO_RECORD which means the operation can continue, 
01767                 but no undo information needs to be stored, or AC_OK which means the operation should
01768                 continue AND record undo information. If the function returns AC_FAIL, there was not 
01769                 enough memory to record the undo information, and the user has decided not to continue
01770                 with the operation.
01771     Errors:     -
01772     SeeAlso:    Action::Init()
01773 
01774 ********************************************************************************************/
01775 
01776 
01777 
01778 ActionCode ChangeContourToOuterAction::Init(Operation* pOp,
01779                                         ActionList* pActionList,
01780                                         NodeContourController * pController,
01781                                         ChangeContourToOuterAction** ppNewAction)
01782 {
01783     UINT32 ActSize = sizeof(ChangeContourToOuterAction);
01784     
01785     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(ChangeContourToOuterAction),(Action**)ppNewAction);
01786 
01787     if (Ac == AC_OK)
01788     {
01789         (*ppNewAction)->m_pContour = pController;
01790         (*ppNewAction)->m_LastWidth = pController->GetWidth();
01791     }
01792 
01793     return Ac;
01794 }
01795 
01796 /********************************************************************************************
01797 
01798 >   ActionCode ChangeContourToOuterAction::Execute();
01799 
01800     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01801     Created:    17/3/99
01802     Inputs:     -
01803     Outputs:    -
01804     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01805     Purpose:    Executes the action.  Causes a regen of all bevels nodes in the action's list
01806     Errors:     -
01807     SeeAlso:    Action::Init()
01808 
01809 ********************************************************************************************/
01810 
01811 ActionCode ChangeContourToOuterAction::Execute()
01812 {
01813     ChangeContourToOuterAction * pNewAction = NULL;
01814 
01815     // first, initialise an action to restore all the current widths in my list
01816     ActionCode Ac = ChangeContourToOuterAction::Init(pOperation,
01817                                                    pOppositeActLst,
01818                                                    m_pContour,
01819                                                    &pNewAction);
01820 
01821     Document * pDoc = Document::GetCurrent();
01822 
01823     if (Ac == AC_OK)
01824     {
01825         if (pDoc)
01826             pDoc->ForceRedraw(m_pContour->FindParentSpread(), m_pContour->GetBoundingRect(), FALSE, m_pContour);
01827 
01828         m_pContour->SetWidth(m_LastWidth);
01829         m_pContour->RegenerateNode(NULL, FALSE);
01830 
01831         if (pDoc)
01832             pDoc->ForceRedraw(m_pContour->FindParentSpread(), m_pContour->GetBoundingRect(), FALSE, m_pContour);
01833     }
01834 
01835     return Ac;
01836 }
01837 
01838 ChangeContourToOuterAction::~ChangeContourToOuterAction()
01839 {
01840     
01841 }
01842 
01844 // ChangeContourToInnerAction class implementation
01845 /********************************************************************************************
01846 
01847 >   ChangeContourToInnerAction::ChangeContourToInnerAction()
01848 
01849     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
01850     Created:    07/01/97
01851     Inputs:     -
01852     Outputs:    -
01853     Returns:    -
01854     Purpose:    Constructor for the action
01855     Errors:     -
01856     SeeAlso:    -
01857 
01858 ********************************************************************************************/
01859 
01860 ChangeContourToInnerAction::ChangeContourToInnerAction()
01861 {
01862     m_LastWidth = 0;
01863 
01864 }
01865 
01866 
01867 /********************************************************************************************
01868 
01869 >   ActionCode ChangeContourToInnerAction::Init(    Operation*  pOp,
01870                                                 ActionList* pActionList,
01871                                                 List * pNodes
01872                                                 ChangePositionShadowXAction**   ppNewAction);
01873 
01874     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01875     Created:    17/3/99
01876     Inputs:     pOp             = ptr to the operation to which this action belongs
01877                 pActionList     =  ptr to action list to which this action should be added
01878                 pNodes          = ptr to node list containing the NodeBevel nodes to be 
01879                                   regenerated   
01880     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
01881                                   a pointer to the created action
01882     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01883     Purpose:    This is the function which creates an instance of this action. If there is no room 
01884                 in the undo buffer (which is determined by the base class Init function called within)
01885                 the function will either return AC_NO_RECORD which means the operation can continue, 
01886                 but no undo information needs to be stored, or AC_OK which means the operation should
01887                 continue AND record undo information. If the function returns AC_FAIL, there was not 
01888                 enough memory to record the undo information, and the user has decided not to continue
01889                 with the operation.
01890     Errors:     -
01891     SeeAlso:    Action::Init()
01892 
01893 ********************************************************************************************/
01894 
01895 
01896 
01897 ActionCode ChangeContourToInnerAction::Init(Operation* pOp,
01898                                         ActionList* pActionList,
01899                                         NodeContourController * pController,
01900                                         ChangeContourToInnerAction** ppNewAction)
01901 {
01902     UINT32 ActSize = sizeof(ChangeContourToInnerAction);
01903 
01904     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(ChangeContourToInnerAction),(Action**)ppNewAction);
01905 
01906     if (Ac == AC_OK)
01907     {
01908         (*ppNewAction)->m_pContour = pController;
01909         (*ppNewAction)->m_LastWidth = pController->GetWidth();
01910     }
01911 
01912     return Ac;
01913 }
01914 
01915 /********************************************************************************************
01916 
01917 >   ActionCode ChangeContourToInnerAction::Execute();
01918 
01919     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01920     Created:    17/3/99
01921     Inputs:     -
01922     Outputs:    -
01923     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
01924     Purpose:    Executes the action.  Causes a regen of all bevels nodes in the action's list
01925     Errors:     -
01926     SeeAlso:    Action::Init()
01927 
01928 ********************************************************************************************/
01929 
01930 ActionCode ChangeContourToInnerAction::Execute()
01931 {
01932     ChangeContourToInnerAction * pNewAction = NULL;
01933 
01934     // first, initialise an action to restore all the current widths in my list
01935     ActionCode Ac = ChangeContourToInnerAction::Init(pOperation,
01936                                                    pOppositeActLst,
01937                                                    m_pContour,
01938                                                    &pNewAction);
01939 
01940     Document * pDoc = Document::GetCurrent();
01941 
01942     if (Ac == AC_OK)
01943     {
01944         if (pDoc)
01945             pDoc->ForceRedraw(m_pContour->FindParentSpread(), m_pContour->GetBoundingRect(), FALSE, m_pContour);
01946 
01947         m_pContour->SetWidth(m_LastWidth);
01948         m_pContour->RegenerateNode(NULL, FALSE);
01949 
01950         if (pDoc)
01951             pDoc->ForceRedraw(m_pContour->FindParentSpread(), m_pContour->GetBoundingRect(), FALSE, m_pContour);
01952     }
01953 
01954     return Ac;
01955 }
01956 
01957 ChangeContourToInnerAction::~ChangeContourToInnerAction()
01958 {
01959     
01960 }
01961 
01963 // OpChangeContourToInner class
01964 
01965 /********************************************************************************************
01966 >   OpChangeContourWidth::OpChangeContourWidth()
01967 
01968     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01969     Created:    12/8/99
01970     Purpose:    Constructor.
01971 ********************************************************************************************/
01972 OpChangeContourToInner::OpChangeContourToInner()
01973 {
01974     //TRACEUSER( "MarkH", _T("Just Made a OpChangeContourWidth Class!\n"));
01975 }
01976 
01977 
01978 
01979 /********************************************************************************************
01980 >   OpChangeContourToInner::~OpChangeContourToInner()
01981 
01982     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01983     Created:    12/8/99
01984     Purpose:    Destructor.
01985 ********************************************************************************************/
01986 OpChangeContourToInner::~OpChangeContourToInner()
01987 {
01988     //TRACEUSER( "MarkH", _T("Just Killed OpChangeContourToInner Class!!!\n"));
01989 }
01990 
01991 
01992 
01993 /********************************************************************************************
01994 >   virtual void OpChangeContourToInner::Do(OpDescriptor *pOpDesc)
01995 
01996     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01997     Created:    12/8/99
01998     Inputs:     pOpDesc - OpDescriptor - unused
01999     Outputs:    -
02000     Returns:    -
02001     Purpose:    The do function.  Applys a Bevel to the selection in the current document
02002 ********************************************************************************************/
02003 void OpChangeContourToInner::Do(OpDescriptor *pOpDesc)
02004 {
02005     TRACEUSER( "DavidM", _T("OpChangeContourToInner - Do !\n"));
02006     BeginSlowJob(-1, TRUE);
02007     DoStartSelOp(TRUE, TRUE);
02008 
02009     // get all the contour nodes in the selection
02010     List ContourList;
02011 
02012     BevelTools::BuildListOfSelectedNodes(&ContourList, CC_RUNTIME_CLASS(NodeContourController),
02013         TRUE);
02014 
02015     NodeListItem * pItem = (NodeListItem *)ContourList.GetHead();
02016 
02017     ChangeContourToInnerAction * pAction = NULL;
02018 
02019     NodeContourController * pControl = NULL;
02020 
02021     BOOL ok = TRUE;
02022 
02023     Document * pDoc = Document::GetCurrent();
02024 
02025     // set up the object changed param
02026     ObjChangeFlags flgs(FALSE, FALSE, FALSE, TRUE);
02027     flgs.RegenerateNode = TRUE;
02028     ObjChangeParam MyObjChangeParam(OBJCHANGE_FINISHED, flgs, NULL, this, OBJCHANGE_CALLEDBYOP);
02029 
02030     Node * pParent = NULL;
02031 
02032     // run through the list, changing all widths to be positive
02033     while (pItem && ok)
02034     {
02035         if (pItem->pNode)
02036         {
02037             pControl = (NodeContourController *)pItem->pNode;
02038 
02039             if (pControl->GetWidth() < 0)
02040             {
02041                 // redraw the node
02042                 if (pDoc)
02043                     pDoc->ForceRedraw(pControl->FindParentSpread(), pControl->GetBoundingRect(), FALSE, pControl);
02044 
02045                 // and invalidate all parents' rectangles
02046                 pParent = pControl->FindParent();
02047                 pControl->ReleaseCached();      // Associated with DoInvalidateRegion, does parents itself
02048 
02049                 while (pParent)
02050                 {
02051                     if (pParent->IsAnObject())
02052                     {
02053                         DoInvalidateRegion(pParent->FindParentSpread(), ((NodeRenderableInk *)pParent)->GetBoundingRect());
02054                     }
02055 
02056                     pParent = pParent->FindParent();
02057                 }               
02058 
02059                 // check for maximum width
02060                 MILLIPOINT MaxWidth = 
02061                     ContourNodePathProcessor::GetMaxInnerContourWidth(pControl);
02062 
02063                 if (ChangeContourToInnerAction::Init(this, this->GetUndoActionList(),
02064                     pControl, &pAction) != AC_OK)
02065                 {
02066                     ok = FALSE;
02067                 }
02068 
02069                 // set the width to positive
02070                 pControl->SetWidth(-pControl->GetWidth());
02071 
02072                 if (pControl->GetWidth() > MaxWidth)
02073                     pControl->SetWidth(MaxWidth);
02074 
02075                 // move the node
02076                 if (ok)
02077                 {
02078                     Node * pContourNode = pControl->FindFirstChild(CC_RUNTIME_CLASS(NodeContour));
02079 
02080                     if (pContourNode)
02081                     {
02082                         Node * pInsertNode = pControl->FindLastChild(CC_RUNTIME_CLASS(NodeRenderableInk));
02083 
02084                         if (pInsertNode != pContourNode)
02085                             ok = DoMoveNode(pContourNode, pInsertNode, NEXT);
02086                     }
02087                 }
02088 
02089                 // regenerate the node
02090                 pControl->RegenerateNode(NULL, FALSE);
02091 
02092                 // Ilan 7/5/00
02093                 // Inform geom linked attrs of the change. Nb outside the normal AllowOp mechanism
02094                 NodeAttribute* pNA = pControl->FindFirstGeometryLinkedAttr();
02095                 while(pNA)
02096                 {
02097                     pNA->LinkedNodeGeometryHasChanged(this);
02098                     pNA = pNA->FindNextGeometryLinkedAttr();
02099                 }
02100 
02101                 // redraw the node
02102                 if (pDoc)
02103                     pDoc->ForceRedraw(pControl->FindParentSpread(), pControl->GetBoundingRect(), FALSE, pControl);
02104             }
02105         }
02106 
02107         pItem = (NodeListItem *)ContourList.GetNext(pItem);
02108     }
02109 
02110     ContourList.DeleteAll();
02111 
02112     if (!ok)
02113     {
02114         FailAndExecute();
02115         End();
02116         return;
02117     }
02118     
02119     End();
02120 }
02121 
02122 
02123 /********************************************************************************************
02124 >   void OpChangeContourToInner::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
02125 
02126     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02127     Created:    12/8/99
02128     Inputs:     
02129     Outputs:    -
02130     Returns:    -
02131     Purpose:    Changes all contours in the selection to inner contours
02132 ********************************************************************************************/
02133 
02134 void OpChangeContourToInner::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
02135 {
02136     // first, begin the operation
02137     BeginSlowJob(-1, TRUE);
02138     DoStartSelOp(TRUE, TRUE);
02139 
02140 
02141     
02142     End();
02143 }
02144 
02145 /********************************************************************************************
02146 
02147 >   BOOL OpChangeContourToInner::Declare()
02148 
02149     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02150     Created:    16/11/94                                                                        
02151     Returns:    TRUE if all went OK, False otherwise
02152     Purpose:    Adds the operation to the list of all known operations
02153 
02154 ********************************************************************************************/
02155 BOOL OpChangeContourToInner::Declare()
02156 {
02157     return (RegisterOpDescriptor(
02158                                 0, 
02159                                 _R(IDS_OP_CONTOURINNER),
02160                                 CC_RUNTIME_CLASS(OpChangeContourToInner), 
02161                                 OPTOKEN_CHANGECONTOUR_INNER,
02162                                 OpChangeContourToInner::GetState,
02163                                 0,
02164                                 _R(IDBBL_CONTOURINNER)
02165                                 ));
02166 
02167 }
02168 
02169 
02170 
02171 /********************************************************************************************
02172 
02173 >   OpState OpChangeContourToInner::GetState(String_256* Description, OpDescriptor*)
02174 
02175     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02176     Created:    16/11/94
02177     Outputs:    -
02178     Returns:    Ungreyed, Unticked
02179     Purpose:    Find out the state of the new regular shape at the specific time
02180 
02181 ********************************************************************************************/
02182 OpState OpChangeContourToInner::GetState(String_256* Description, OpDescriptor*)
02183 {
02184     OpState Blobby;
02185 
02186     TRACEUSER( "DavidM", _T("OpChangeContourToInner - get state !\n"));
02187 
02188     if (Description)
02189     {
02190         Description->Load(_R(IDS_CONTOURINNEROPNAME));
02191     }
02192 
02193     return Blobby;
02194 }
02195 
02197 // OpChangeContourToOuter class
02198 
02199 /********************************************************************************************
02200 >   OpChangeContourWidth::OpChangeContourWidth()
02201 
02202     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02203     Created:    12/8/99
02204     Purpose:    Constructor.
02205 ********************************************************************************************/
02206 OpChangeContourToOuter::OpChangeContourToOuter()
02207 {
02208     //TRACEUSER( "MarkH", _T("Just Made a OpChangeContourWidth Class!\n"));
02209 }
02210 
02211 
02212 
02213 /********************************************************************************************
02214 >   OpChangeContourToOuter::~OpChangeContourToOuter()
02215 
02216     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02217     Created:    12/8/99
02218     Purpose:    Destructor.
02219 ********************************************************************************************/
02220 OpChangeContourToOuter::~OpChangeContourToOuter()
02221 {
02222     //TRACEUSER( "MarkH", _T("Just Killed OpChangeContourToOuter Class!!!\n"));
02223 }
02224 
02225 
02226 
02227 /********************************************************************************************
02228 >   virtual void OpChangeContourToOuter::Do(OpDescriptor *pOpDesc)
02229 
02230     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02231     Created:    12/8/99
02232     Inputs:     pOpDesc - OpDescriptor - unused
02233     Outputs:    -
02234     Returns:    -
02235     Purpose:    Changes all contours in the selection to outer contours
02236 ********************************************************************************************/
02237 void OpChangeContourToOuter::Do(OpDescriptor *pOpDesc)
02238 {
02239     TRACEUSER( "DavidM", _T("OpChangeContourToOuter - Do !\n"));
02240     BeginSlowJob(-1, TRUE);
02241     DoStartSelOp(TRUE, TRUE);
02242 
02243     // get all the contour nodes in the selection
02244     List ContourList;
02245 
02246     BevelTools::BuildListOfSelectedNodes(&ContourList, CC_RUNTIME_CLASS(NodeContourController),
02247         TRUE);
02248 
02249     NodeListItem * pItem = (NodeListItem *)ContourList.GetHead();
02250 
02251     ChangeContourToOuterAction * pAction = NULL;
02252 
02253     NodeContourController * pControl = NULL;
02254 
02255     BOOL ok = TRUE;
02256 
02257     // set up the object changed param
02258     ObjChangeFlags flgs(FALSE, FALSE, FALSE, TRUE);
02259     flgs.RegenerateNode = TRUE;
02260     ObjChangeParam MyObjChangeParam(OBJCHANGE_FINISHED, flgs, NULL, this, OBJCHANGE_CALLEDBYOP);
02261 
02262     Node * pParent = NULL;
02263 
02264     Document * pDoc = Document::GetCurrent();
02265 
02266     // run through the list, changing all widths to be positive
02267     while (pItem && ok)
02268     {
02269         if (pItem->pNode)
02270         {
02271             pControl = (NodeContourController *)pItem->pNode;
02272 
02273             if (pControl->GetWidth() > 0)
02274             {
02275                 // redraw the node
02276                 if (pDoc)
02277                     pDoc->ForceRedraw(pControl->FindParentSpread(), pControl->GetBoundingRect(), FALSE, pControl);
02278 
02279                 // invalidate the parents
02280                 pParent = pControl->FindParent();
02281                 pControl->ReleaseCached();      // Associated with DoInvalidateRegion, does parents itself
02282 
02283                 while (pParent)
02284                 {
02285                     if (pParent->IsAnObject())
02286                     {
02287                         DoInvalidateRegion(pParent->FindParentSpread(), ((NodeRenderableInk *)pParent)->GetBoundingRect());
02288                     }
02289 
02290                     pParent = pParent->FindParent();
02291                 }           
02292 
02293                 if (ChangeContourToOuterAction::Init(this, this->GetUndoActionList(),
02294                     pControl, &pAction) != AC_OK)
02295                 {
02296                     ok = FALSE;
02297                 }
02298 
02299                 // set the width to negative
02300                 pControl->SetWidth(-pControl->GetWidth());
02301 
02302                 // move the node
02303                 if (ok)
02304                 {
02305                     Node * pContourNode = pControl->FindFirstChild(CC_RUNTIME_CLASS(NodeContour));
02306 
02307                     if (pContourNode)
02308                     {
02309                         Node * pInsertNode = pControl->FindFirstChild(CC_RUNTIME_CLASS(NodeRenderableInk));
02310 
02311                         if (pInsertNode != pContourNode)
02312                             ok = DoMoveNode(pContourNode, pInsertNode, PREV);
02313                     }
02314                 }
02315 
02316 
02317                 // regenerate the node
02318                 pControl->RegenerateNode(NULL, FALSE);
02319 
02320                 // Ilan 7/5/00
02321                 // Inform geom linked attrs of the change. Nb outside the normal AllowOp mechanism
02322                 NodeAttribute* pNA = pControl->FindFirstGeometryLinkedAttr();
02323                 while(pNA)
02324                 {
02325                     pNA->LinkedNodeGeometryHasChanged(this);
02326                     pNA = pNA->FindNextGeometryLinkedAttr();
02327                 }
02328 
02329                 // redraw the node
02330                 if (pDoc)
02331                     pDoc->ForceRedraw(pControl->FindParentSpread(), pControl->GetBoundingRect(), FALSE, pControl);
02332             }
02333         }
02334 
02335         pItem = (NodeListItem *)ContourList.GetNext(pItem);
02336     }
02337 
02338     ContourList.DeleteAll();
02339 
02340     if (!ok)
02341     {
02342         FailAndExecute();
02343         End();
02344         return;
02345     }
02346     
02347     End();
02348 }
02349 
02350 
02351 /********************************************************************************************
02352 >   void OpChangeContourToOuter::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
02353 
02354     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02355     Created:    12/8/99
02356     Inputs:     
02357     Outputs:    -
02358     Returns:    -
02359     Purpose:    Applys a Bevel to the selected node after a mouse click
02360 ********************************************************************************************/
02361 
02362 void OpChangeContourToOuter::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
02363 {
02364     // first, begin the operation
02365     BeginSlowJob(-1, TRUE);
02366     
02367     End();
02368 }
02369 
02370 /********************************************************************************************
02371 
02372 >   BOOL OpChangeContourToOuter::Declare()
02373 
02374     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02375     Created:    16/11/94                                                                        
02376     Returns:    TRUE if all went OK, False otherwise
02377     Purpose:    Adds the operation to the list of all known operations
02378 
02379 ********************************************************************************************/
02380 BOOL OpChangeContourToOuter::Declare()
02381 {
02382     return (RegisterOpDescriptor(
02383                                 0, 
02384                                 _R(IDS_OP_CONTOUROUTER),
02385                                 CC_RUNTIME_CLASS(OpChangeContourToOuter), 
02386                                 OPTOKEN_CHANGECONTOUR_OUTER,
02387                                 OpChangeContourToOuter::GetState,
02388                                 0,
02389                                 _R(IDBBL_CONTOUROUTER)
02390                                 ));
02391 
02392 }
02393 
02394 
02395 
02396 /********************************************************************************************
02397 
02398 >   OpState OpChangeContourToOuter::GetState(String_256* Description, OpDescriptor*)
02399 
02400     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02401     Created:    16/11/94
02402     Outputs:    -
02403     Returns:    Ungreyed, Unticked
02404     Purpose:    Find out the state of the new regular shape at the specific time
02405 
02406 ********************************************************************************************/
02407 OpState OpChangeContourToOuter::GetState(String_256* Description, OpDescriptor*)
02408 {
02409     OpState Blobby;
02410 
02411     if (Description)
02412     {
02413         Description->Load(_R(IDS_CONTOUROUTEROPNAME));
02414     }
02415     
02416     return Blobby;
02417 }
02418 
02420 //  OpChangeContourSteps
02421 //
02422 // Changes the number of steps of all the selected blends
02423 
02424 
02425 /********************************************************************************************
02426 
02427 >   void OpChangeContourSteps::DoWithParam(OpDescriptor*,OpParam* pOpParam)
02428 
02429     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02430     Created:    7/11/94
02431     Returns:    -
02432     Purpose:    This changes all the selected blend objects to have pOpParam->Param1 number of steps
02433 
02434 ********************************************************************************************/
02435 
02436 void OpChangeContourSteps::DoWithParam(OpDescriptor*,OpParam* pOpParam)
02437 {
02438     ERROR3IF(pOpParam == NULL,"NULL OpParam ptr");
02439     if (pOpParam == NULL) return;
02440 
02441     List NodeList;
02442     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeRenderableInk));
02443 
02444     NodeListItem *pItem = NULL;
02445 
02446     BOOL ok = !NodeList.IsEmpty();
02447 
02448     if (ok) ok = DoStartSelOp(FALSE,FALSE);
02449 
02450     if (ok)
02451     {
02452         // The new number of steps is in pOpParam->Param1 of the 
02453         UINT32 NewNumSteps = UINT32(pOpParam->Param1);
02454         pItem = (NodeListItem *)NodeList.GetHead();
02455 
02456         Node* pSelNode = NULL;
02457 
02458         if (pItem)
02459         {
02460             pSelNode = pItem->pNode;
02461         }
02462 
02463         while (pSelNode != NULL && ok)
02464         {
02465             Node* pNode = pSelNode;
02466 
02467             pItem = (NodeListItem *)NodeList.GetNext(pItem);
02468 
02469             if (pItem)
02470             {
02471                 pSelNode = pItem->pNode;
02472             }
02473             else
02474             {
02475                 pSelNode = NULL;
02476             }
02477 
02478             if (pNode->IS_KIND_OF(NodeContourController))
02479             {
02480                 // We now have a selected blend node so:
02481                 //  Invalidate the node's region
02482                 //  Store the current number of blend steps in an undo actiom
02483                 //  Change the number of steps to NewNumSteps
02484             
02485                 NodeRenderableInk * pInk = (NodeRenderableInk *)pNode;
02486 
02487                 UINT32 NumSteps = 0;
02488                 double DistanceEntered = 0.0;
02489                 NumSteps = ((NodeContourController *)pNode)->GetNumberOfSteps();
02490                 DistanceEntered = 0.0;
02491                 
02492                 ChangeContourStepsAction* pAction;
02493 
02494                 // Ask the node if it's ok to do the op
02495                 ObjChangeFlags cFlags;
02496                 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
02497                 ok = pInk->AllowOp(&ObjChange);
02498 
02499                 if (ok) ok = DoInvalidateNodeRegion(pInk,TRUE,FALSE);
02500                 if (ok) ok = (InvalidateBoundsAction::Init(this,&UndoActions,pInk,TRUE) != AC_FAIL);
02501                 if (ok) ok = ChangeContourStepsAction::Init(this,&UndoActions,pInk,NumSteps, DistanceEntered, &pAction) != AC_FAIL;
02502                 
02503                 if (ok)
02504                 {
02505                     ((NodeContourController *)pNode)->SetNumberOfSteps(NewNumSteps);
02506                     pNode->RegenerateNode(NULL, FALSE);
02507                 }
02508                 
02509                 if (ok) ok = DoInvalidateNodeRegion(pInk,TRUE,FALSE);
02510                 if (ok) ok = (InvalidateBoundsAction::Init(this,&UndoActions,pInk,TRUE) != AC_FAIL);
02511             }
02512         }
02513     }
02514 
02515     NodeList.DeleteAll();
02516 
02517     if (ok) 
02518     {
02519         
02520     }
02521     else
02522         FailAndExecute();
02523 
02524     End();
02525 }
02526 
02527 /********************************************************************************************
02528 
02529 >   BOOL OpChangeContourSteps::Declare()
02530 
02531     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02532     Created:    7/11/94
02533     Returns:    TRUE if all went OK, FALSE otherwise
02534     Purpose:    Adds the operation to the list of all known operations
02535 
02536 ********************************************************************************************/
02537 
02538 BOOL OpChangeContourSteps::Declare()
02539 {
02540     return (RegisterOpDescriptor(
02541                                 0, 
02542                                 0,
02543                                 CC_RUNTIME_CLASS(OpChangeContourSteps), 
02544                                 OPTOKEN_CHANGECONTOURSTEPS,
02545                                 OpChangeContourSteps::GetState,
02546                                 0,  /* help ID */
02547                                 0,  /* bubble ID */
02548                                 0   /* bitmap ID */
02549                                 ));
02550 }
02551 
02552 
02553 /********************************************************************************************
02554 
02555 >   static OpState OpChangeContourSteps::GetState(String_256* Description, OpDescriptor*)
02556 
02557     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02558     Created:    7/11/94
02559     Outputs:    Description - GetState fills this string with an approriate description
02560                 of the current state of the operation 
02561     Returns:    The state of the operation, so that menu items (ticks and greying) can be
02562                 done properly
02563     Purpose:    Find out the state of the operation at the specific time
02564 
02565 ********************************************************************************************/
02566 
02567 OpState OpChangeContourSteps::GetState(String_256* Description, OpDescriptor*)
02568 {
02569     OpState State(FALSE,TRUE); // It's not ticked, but it is greyed by default
02570     
02571     // DMc - to test for bevels & contours
02572     // are there any contour nodes in the selection
02573     List NodeList;
02574     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
02575 
02576     if (!NodeList.IsEmpty())
02577     {
02578         State.Greyed = FALSE;
02579     }
02580 
02581     NodeList.DeleteAll();
02582 
02583     if (State.Greyed)
02584         *Description = String_256(_R(IDS_CONTOURSTEPS));
02585     else
02586         *Description = String_256(_R(IDS_CONTOURSTEPS));
02587 
02588     return State;
02589 }
02590 
02591 /********************************************************************************************
02592 
02593 >   virtual void OpChangeContourSteps::GetOpName(String_256* OpName) 
02594 
02595     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02596     Created:    7/11/94
02597     Inputs:     -
02598     Outputs:    The undo string for the operation
02599     Returns:    
02600     Purpose:    The GetOpName fn is overridden so that we return back a description 
02601                 appropriate to the type of attribute that the operation applies. 
02602     Errors:     -
02603     SeeAlso:    -
02604 
02605 ********************************************************************************************/
02606 
02607 void OpChangeContourSteps::GetOpName(String_256* OpName) 
02608 { 
02609     *OpName = String_256(_R(IDS_CONTOURSTEPS_UNDO));
02610 }  
02611 
02612 
02613 
02614 //------------------------------------------------------------------------------------------------
02615 //------------------------------------------------------------------------------------------------
02616 //------------------------------------------------------------------------------------------------
02617 // The ChangeContourStepsAction class
02618 
02619 /********************************************************************************************
02620 
02621 >   ChangeContourStepsAction::ChangeContourStepsAction()
02622 
02623     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02624     Created:    7/11/94
02625     Inputs:     -
02626     Outputs:    -
02627     Returns:    -
02628     Purpose:    Constructor for the action
02629     Errors:     -
02630     SeeAlso:    -
02631 
02632 ********************************************************************************************/
02633 
02634 ChangeContourStepsAction::ChangeContourStepsAction()
02635 {
02636     pNodeBlend  = NULL;
02637     OldNumSteps = 0;
02638 }
02639 
02640 
02641 /********************************************************************************************
02642 
02643 >   ActionCode ChangeContourStepsAction::Init(  Operation*  pOp,
02644                                                 ActionList* pActionList,
02645                                                 NodeBlend*  pThisNodeBlend,
02646                                                 UINT32      NumSteps,
02647                                                 ChangeContourStepsAction**  ppNewAction);
02648 
02649     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02650     Created:    7/11/94
02651     Inputs:     pOp             = ptr to the operation to which this action belongs
02652                 pActionList     =  ptr to action list to which this action should be added
02653                 pThisNodeBlend  = ptr to NodeBlend to change 
02654                 NumSteps        = Num steps to applied to pThisNodeBlend
02655     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
02656                                   a pointer to the created action
02657     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02658     Purpose:    This is the function which creates an instance of this action. If there is no room 
02659                 in the undo buffer (which is determined by the base class Init function called within)
02660                 the function will either return AC_NO_RECORD which means the operation can continue, 
02661                 but no undo information needs to be stored, or AC_OK which means the operation should
02662                 continue AND record undo information. If the function returns AC_FAIL, there was not 
02663                 enough memory to record the undo information, and the user has decided not to continue
02664                 with the operation.
02665     Errors:     -
02666     SeeAlso:    Action::Init()
02667 
02668 ********************************************************************************************/
02669 
02670 
02671 
02672 ActionCode ChangeContourStepsAction::Init(Operation* pOp,
02673                                         ActionList* pActionList,
02674                                         Node* pThisNodeBlend,
02675                                         UINT32 NumSteps,
02676                                         double DistanceEntered,
02677                                         ChangeContourStepsAction** ppNewAction)
02678 {
02679     UINT32 ActSize = sizeof(ChangeContourStepsAction);
02680 
02681     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(ChangeContourStepsAction),(Action**)ppNewAction);
02682 
02683     if (Ac != AC_FAIL)
02684     {
02685         (*ppNewAction)->pNodeBlend  = pThisNodeBlend;
02686         (*ppNewAction)->OldNumSteps = NumSteps;
02687         (*ppNewAction)->OldDistanceEntered = DistanceEntered;
02688     }
02689 
02690     return Ac;
02691 }
02692 
02693 /********************************************************************************************
02694 
02695 >   ActionCode ChangeContourStepsAction::Execute();
02696 
02697     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02698     Created:    7/11/94
02699     Inputs:     -
02700     Outputs:    -
02701     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02702     Purpose:    Executes the action.  This will reset the num blend steps in pThisNodeBlend to OldNumSteps,
02703                 after creating another action to record the current num steps of pThisNodeBlend
02704     Errors:     -
02705     SeeAlso:    Action::Init()
02706 
02707 ********************************************************************************************/
02708 
02709 ActionCode ChangeContourStepsAction::Execute()
02710 {
02711     ActionCode Act;
02712     ChangeContourStepsAction* pAction;
02713 
02714     UINT32 NumSteps = 0;
02715     double DistanceEntered = 0.0;
02716 
02717     NumSteps = ((NodeContourController *)pNodeBlend)->GetNumberOfSteps();
02718 
02719     Act = ChangeContourStepsAction::Init(   pOperation, 
02720                                         pOppositeActLst,
02721                                         pNodeBlend,
02722                                         NumSteps,
02723                                         DistanceEntered,
02724                                         &pAction);
02725     if (Act != AC_FAIL)
02726     {
02727         ((NodeContourController *)pNodeBlend)->SetNumberOfSteps(OldNumSteps);
02728         pNodeBlend->RegenerateNode(NULL, FALSE);
02729     }
02730 
02731     return Act;
02732 }
02733 
02734 ChangeContourStepsAction::~ChangeContourStepsAction()
02735 {
02736 }
02737 
02739 //  OpChangeContourColourType
02740 //
02741 // Changes the number of steps of all the selected blends
02742 
02743 
02744 /********************************************************************************************
02745 
02746 >   void OpChangeContourColourType::DoWithParam(OpDescriptor*,OpParam* pOpParam)
02747 
02748     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02749     Created:    7/11/94
02750     Returns:    -
02751     Purpose:    This changes all the selected blend objects to have pOpParam->Param1 number of steps
02752 
02753 ********************************************************************************************/
02754 
02755 void OpChangeContourColourType::DoWithParam(OpDescriptor*,OpParam* pOpParam)
02756 {
02757     ERROR3IF(pOpParam == NULL,"NULL OpParam ptr");
02758     if (pOpParam == NULL) return;
02759 
02760     DoStartSelOp(TRUE, TRUE);
02761     BeginSlowJob(-1, TRUE);
02762 
02763     List NodeList;
02764     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
02765 
02766     NodeListItem * pItem = (NodeListItem *)NodeList.GetHead();
02767 
02768     NodeContourController * pController = NULL;
02769 
02770     BOOL ok = TRUE;
02771 
02772     Node * pParent = NULL;
02773 
02774     while (pItem && ok)
02775     {
02776         pController = (NodeContourController *)pItem->pNode;
02777 
02778         ChangeContourColourTypeAction *pAction = NULL;
02779 
02780         if (ChangeContourColourTypeAction::Init(this, GetUndoActionList(), pController, (ColourBlendType)(INT32)(pOpParam->Param1),
02781             &pAction) != AC_OK)
02782         {
02783             FailAndExecute();
02784             End();
02785             return;
02786         }
02787 
02788         if (ok)
02789             ok = DoInvalidateNodeRegion(pController, TRUE);
02790 
02791         if (ok)
02792         {
02793             pParent = pController->FindParent();
02794 
02795             while (pParent)
02796             {
02797                 ObjChangeFlags flgs;
02798                 ObjChangeParam OP(OBJCHANGE_FINISHED, flgs, NULL, this, OBJCHANGE_CALLEDBYOP);
02799 
02800                 pParent->OnChildChange(&OP);
02801 
02802                 pParent = pParent->FindParent();
02803             }
02804         }       
02805 
02806         pItem = (NodeListItem *)NodeList.GetNext(pItem);
02807     }
02808 
02809     NodeList.DeleteAll();
02810 
02811     // Inform the effected parents of the change
02812     if (ok)
02813     {
02814         End();
02815     }
02816     else
02817     {
02818         FailAndExecute();
02819         End();
02820     }
02821 }
02822 
02823 /********************************************************************************************
02824 
02825 >   BOOL OpChangeContourColourType::Declare()
02826 
02827     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02828     Created:    7/11/94
02829     Returns:    TRUE if all went OK, FALSE otherwise
02830     Purpose:    Adds the operation to the list of all known operations
02831 
02832 ********************************************************************************************/
02833 
02834 BOOL OpChangeContourColourType::Declare()
02835 {
02836     return (RegisterOpDescriptor(
02837                                 0, 
02838                                 0,
02839                                 CC_RUNTIME_CLASS(OpChangeContourColourType), 
02840                                 OPTOKEN_CHANGECONTOURCOLOURTYPE,
02841                                 OpChangeContourColourType::GetState,
02842                                 0,  /* help ID */
02843                                 0,  /* bubble ID */
02844                                 0   /* bitmap ID */
02845                                 ));
02846 }
02847 
02848 
02849 /********************************************************************************************
02850 
02851 >   static OpState OpChangeContourColourType::GetState(String_256* Description, OpDescriptor*)
02852 
02853     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02854     Created:    7/11/94
02855     Outputs:    Description - GetState fills this string with an approriate description
02856                 of the current state of the operation 
02857     Returns:    The state of the operation, so that menu items (ticks and greying) can be
02858                 done properly
02859     Purpose:    Find out the state of the operation at the specific time
02860 
02861 ********************************************************************************************/
02862 
02863 OpState OpChangeContourColourType::GetState(String_256* Description, OpDescriptor*)
02864 {
02865     OpState State(FALSE,TRUE); // It's not ticked, but it is greyed by default
02866     
02867     // DMc - to test for bevels & contours
02868     // are there any contour nodes in the selection
02869     List NodeList;
02870     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
02871 
02872     if (!NodeList.IsEmpty())
02873     {
02874         State.Greyed = FALSE;
02875     }
02876 
02877     NodeList.DeleteAll();
02878 
02879     if (State.Greyed)
02880         *Description = String_256(_R(IDS_CONTOURCOLOURTYPE));
02881     else
02882         *Description = String_256(_R(IDS_CONTOURCOLOURTYPE));
02883 
02884     return State;
02885 }
02886 
02887 /********************************************************************************************
02888 
02889 >   virtual void OpChangeContourColourType::GetOpName(String_256* OpName) 
02890 
02891     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02892     Created:    7/11/94
02893     Inputs:     -
02894     Outputs:    The undo string for the operation
02895     Returns:    
02896     Purpose:    The GetOpName fn is overridden so that we return back a description 
02897                 appropriate to the type of attribute that the operation applies. 
02898     Errors:     -
02899     SeeAlso:    -
02900 
02901 ********************************************************************************************/
02902 
02903 void OpChangeContourColourType::GetOpName(String_256* OpName) 
02904 { 
02905     *OpName = String_256(_R(IDS_CONTOURCOLOURTYPE));
02906 }  
02907 
02908 
02909 
02910 //------------------------------------------------------------------------------------------------
02911 //------------------------------------------------------------------------------------------------
02912 //------------------------------------------------------------------------------------------------
02913 // The ChangeContourColourTypeAction class
02914 
02915 /********************************************************************************************
02916 
02917 >   ChangeContourColourTypeAction::ChangeContourColourTypeAction()
02918 
02919     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02920     Created:    7/11/94
02921     Inputs:     -
02922     Outputs:    -
02923     Returns:    -
02924     Purpose:    Constructor for the action
02925     Errors:     -
02926     SeeAlso:    -
02927 
02928 ********************************************************************************************/
02929 
02930 ChangeContourColourTypeAction::ChangeContourColourTypeAction()
02931 {
02932     m_pNode = NULL;
02933 }
02934 
02935 
02936 /********************************************************************************************
02937 
02938 >   ActionCode ChangeContourColourTypeAction::Init(     Operation*  pOp,
02939                                                 ActionList* pActionList,
02940                                                 NodeBlend*  pThisNodeBlend,
02941                                                 UINT32      NumSteps,
02942                                                 ChangeContourColourTypeAction**     ppNewAction);
02943 
02944     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02945     Created:    7/11/94
02946     Inputs:     pOp             = ptr to the operation to which this action belongs
02947                 pActionList     =  ptr to action list to which this action should be added
02948                 pThisNodeBlend  = ptr to NodeBlend to change 
02949                 NumSteps        = Num steps to applied to pThisNodeBlend
02950     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
02951                                   a pointer to the created action
02952     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02953     Purpose:    This is the function which creates an instance of this action. If there is no room 
02954                 in the undo buffer (which is determined by the base class Init function called within)
02955                 the function will either return AC_NO_RECORD which means the operation can continue, 
02956                 but no undo information needs to be stored, or AC_OK which means the operation should
02957                 continue AND record undo information. If the function returns AC_FAIL, there was not 
02958                 enough memory to record the undo information, and the user has decided not to continue
02959                 with the operation.
02960     Errors:     -
02961     SeeAlso:    Action::Init()
02962 
02963 ********************************************************************************************/
02964 
02965 
02966 
02967 ActionCode ChangeContourColourTypeAction::Init( Operation* pOp,
02968                             ActionList* pActionList,
02969                             NodeContourController* pThisNodeContour,
02970                             ColourBlendType type,
02971                             ChangeContourColourTypeAction** NewAction)
02972 {
02973     UINT32 ActSize = sizeof(ChangeContourColourTypeAction);
02974 
02975     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,
02976         CC_RUNTIME_CLASS(ChangeContourColourTypeAction),(Action**)NewAction);
02977 
02978     Document * pDoc = Document::GetCurrent();
02979 
02980     if (Ac != AC_FAIL)
02981     {
02982         (*NewAction)->m_pNode  = pThisNodeContour;
02983         (*NewAction)->m_OldType = pThisNodeContour->GetColourBlendType();
02984         pThisNodeContour->SetColourBlendType(type);     
02985 
02986         // redraw the contour
02987         if (pDoc)
02988         {
02989             pDoc->ForceRedraw(pThisNodeContour->FindParentSpread(), 
02990                 pThisNodeContour->GetBoundingRect(), FALSE, pThisNodeContour);
02991         }
02992     }
02993 
02994     return Ac;
02995 }
02996 
02997 /********************************************************************************************
02998 
02999 >   ActionCode ChangeContourColourTypeAction::Execute();
03000 
03001     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03002     Created:    7/11/94
03003     Inputs:     -
03004     Outputs:    -
03005     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
03006     Purpose:    Executes the action.  This will reset the num blend steps in pThisNodeBlend to OldNumSteps,
03007                 after creating another action to record the current num steps of pThisNodeBlend
03008     Errors:     -
03009     SeeAlso:    Action::Init()
03010 
03011 ********************************************************************************************/
03012 
03013 ActionCode ChangeContourColourTypeAction::Execute()
03014 {
03015     ChangeContourColourTypeAction * pAction = NULL;
03016     
03017     ActionCode Act = ChangeContourColourTypeAction::Init(   pOperation, 
03018                                         pOppositeActLst,
03019                                         m_pNode,
03020                                         m_OldType,
03021                                         &pAction);
03022     if (Act != AC_FAIL)
03023     {
03024         
03025     }
03026 
03027     return Act;
03028 }
03029 
03030 ChangeContourColourTypeAction::~ChangeContourColourTypeAction()
03031 {
03032 }
03033 
03034 
03035 //------------------------------------------------------------------------------------------------
03036 //------------------------------------------------------------------------------------------------
03037 //------------------------------------------------------------------------------------------------
03038 // The ChangeContourAttributeProfileAction class
03039 
03040 /********************************************************************************************
03041 
03042 >   ChangeContourAttributeProfileAction::ChangeContourAttributeProfileAction()
03043 
03044     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03045     Created:    7/11/94
03046     Inputs:     -
03047     Outputs:    -
03048     Returns:    -
03049     Purpose:    Constructor for the action
03050     Errors:     -
03051     SeeAlso:    -
03052 
03053 ********************************************************************************************/
03054 
03055 ChangeContourAttributeProfileAction::ChangeContourAttributeProfileAction()
03056 {
03057     m_pNode = NULL;
03058 }
03059 
03060 
03061 /********************************************************************************************
03062 
03063 >   ActionCode ChangeContourAttributeProfileAction::Init(   Operation*  pOp,
03064                                                 ActionList* pActionList,
03065                                                 NodeBlend*  pThisNodeBlend,
03066                                                 UINT32      NumSteps,
03067                                                 ChangeContourAttributeProfileAction**   ppNewAction);
03068 
03069     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03070     Created:    7/11/94
03071     Inputs:     pOp             = ptr to the operation to which this action belongs
03072                 pActionList     =  ptr to action list to which this action should be added
03073                 pThisNodeBlend  = ptr to NodeBlend to change 
03074                 NumSteps        = Num steps to applied to pThisNodeBlend
03075     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
03076                                   a pointer to the created action
03077     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
03078     Purpose:    This is the function which creates an instance of this action. If there is no room 
03079                 in the undo buffer (which is determined by the base class Init function called within)
03080                 the function will either return AC_NO_RECORD which means the operation can continue, 
03081                 but no undo information needs to be stored, or AC_OK which means the operation should
03082                 continue AND record undo information. If the function returns AC_FAIL, there was not 
03083                 enough memory to record the undo information, and the user has decided not to continue
03084                 with the operation.
03085     Errors:     -
03086     SeeAlso:    Action::Init()
03087 
03088 ********************************************************************************************/
03089 
03090 
03091 
03092 ActionCode ChangeContourAttributeProfileAction::Init( Operation* pOp,
03093                             ActionList* pActionList,
03094                             NodeContourController* pThisNodeContour,
03095                             CProfileBiasGain Profile,
03096                             ChangeContourAttributeProfileAction** NewAction)
03097 {
03098     UINT32 ActSize = sizeof(ChangeContourAttributeProfileAction);
03099 
03100     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,
03101         CC_RUNTIME_CLASS(ChangeContourAttributeProfileAction),(Action**)NewAction);
03102 
03103     Document * pDoc = Document::GetCurrent();
03104 
03105     if (Ac != AC_FAIL)
03106     {
03107         (*NewAction)->m_pNode  = pThisNodeContour;
03108         (*NewAction)->m_Profile = pThisNodeContour->GetAttrProfile();
03109 
03110         // change the profile & regen
03111         pThisNodeContour->SetAttrProfile(Profile);
03112         pThisNodeContour->RegenerateNode(NULL, FALSE);
03113     
03114         // redraw the contour
03115         if (pDoc)
03116         {
03117             pDoc->ForceRedraw(pThisNodeContour->FindParentSpread(), 
03118                 pThisNodeContour->GetBoundingRect(), FALSE, pThisNodeContour);
03119         }
03120     }
03121 
03122     return Ac;
03123 }
03124 
03125 
03126 
03127 /********************************************************************************************
03128 
03129 >   void ChangeContourAttributeProfileAction::ChangeAttributeProfileWithNoUndo (CProfileBiasGain &Profile)
03130 
03131     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
03132     Created:    24/2/2000
03133     Inputs:     Profile - the profile that is to be applied directly (i.e.  applied with no undo)
03134     Purpose:    When applying contour (attribute) profiles, we only want to generate one bit of undo information.
03135                 This function allows us to meet this requirement (the one bit of undo information
03136                 is generated via OpChangeContourAttributeProfile::DoWithParam ()).  This function is ONLY
03137                 called from within ContourInfoBarOp::ChangeProfile () - after
03138                 OpChangeContourAttributeProfile::DoWithParam () has been called.
03139     Errors:     -
03140     SeeAlso:    SoftShadowInfoBarOp::ChangeProfile (), OpChangeContourAttributeProfile::DoWithParam ().
03141 
03142 ********************************************************************************************/
03143 
03144 void ChangeContourAttributeProfileAction::ChangeAttributeProfileWithNoUndo (CProfileBiasGain &Profile)
03145 {
03146     BeginSlowJob(-1, TRUE);
03147     
03148     List NodeList;
03149     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
03150 
03151     NodeListItem * pItem = (NodeListItem *)NodeList.GetHead();
03152 
03153     NodeContourController * pController = NULL;
03154 
03155 //  Node * pParent = NULL;
03156 
03157 //  ChangeContourObjectProfileAction * pAction= NULL;
03158 
03159     Document * pDoc = Document::GetCurrent();
03160 
03161     while (pItem)
03162     {
03163         pController = (NodeContourController *)pItem->pNode;
03164 
03165         // change the profile & regen
03166         pController->SetAttrProfile(Profile);
03167         pController->RegenerateNode(NULL, FALSE);
03168     
03169         // redraw the contour
03170         if (pDoc)
03171         {
03172             pDoc->ForceRedraw(pController->FindParentSpread(), 
03173                 pController->GetBoundingRect(), FALSE, pController);
03174         }
03175     
03176         pItem = (NodeListItem *)NodeList.GetNext(pItem);
03177     }
03178 
03179     NodeList.DeleteAll();
03180 
03181     EndSlowJob ();
03182 
03183     if (pDoc->GetOpHistory ().CanRedo ())
03184     {
03185         // then we need to clear out the redo information - since we are now 'before' it ....
03186         pDoc->GetOpHistory ().DeleteRedoableOps ();
03187 
03188         // and update the state of things ....
03189         DialogBarOp::SetSystemStateChanged();
03190         DialogBarOp::UpdateStateOfAllBars();
03191     }
03192 }
03193 
03194 /********************************************************************************************
03195 
03196 >   ActionCode ChangeContourAttributeProfileAction::Execute();
03197 
03198     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03199     Created:    7/11/94
03200     Inputs:     -
03201     Outputs:    -
03202     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
03203     Purpose:    Executes the action.  This will reset the num blend steps in pThisNodeBlend to OldNumSteps,
03204                 after creating another action to record the current num steps of pThisNodeBlend
03205     Errors:     -
03206     SeeAlso:    Action::Init()
03207 
03208 ********************************************************************************************/
03209 
03210 ActionCode ChangeContourAttributeProfileAction::Execute()
03211 {
03212     ChangeContourAttributeProfileAction * pAction = NULL;
03213     
03214     ActionCode Act = ChangeContourAttributeProfileAction::Init( pOperation, 
03215                                         pOppositeActLst,
03216                                         m_pNode,
03217                                         m_Profile,
03218                                         &pAction);
03219     if (Act != AC_FAIL)
03220     {
03221         
03222     }
03223 
03224     return Act;
03225 }
03226 
03227 ChangeContourAttributeProfileAction::~ChangeContourAttributeProfileAction()
03228 {
03229 }
03230 
03232 //  OpChangeContourColourType
03233 //
03234 // Changes the number of steps of all the selected blends
03235 
03236 
03237 /********************************************************************************************
03238 
03239 >   void OpChangeContourAttributeProfile::DoWithParam(OpDescriptor*,OpParam* pOpParam)
03240 
03241     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03242     Created:    7/11/94
03243     Returns:    -
03244     Purpose:    This changes all the selected blend objects to have pOpParam->Param1 number of steps
03245 
03246 ********************************************************************************************/
03247 
03248 void OpChangeContourAttributeProfile::DoWithParam(OpDescriptor*,OpParam* pOpParam)
03249 {
03250     ERROR3IF(pOpParam == NULL,"NULL OpParam ptr");
03251     if (pOpParam == NULL) return;
03252 
03253     BOOL ok = TRUE;
03254 
03255     ChangeContourProfileParam * pCParam = (ChangeContourProfileParam *)pOpParam;
03256 
03257     DoStartSelOp(TRUE, TRUE);
03258     BeginSlowJob(-1, TRUE);
03259     
03260     List NodeList;
03261     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
03262 
03263     NodeListItem * pItem = (NodeListItem *)NodeList.GetHead();
03264 
03265     NodeContourController * pController = NULL;
03266 
03267 //  Node * pParent = NULL;
03268 
03269     ChangeContourAttributeProfileAction * pAction= NULL;
03270 
03271     while (pItem && ok)
03272     {
03273         pController = (NodeContourController *)pItem->pNode;
03274 
03275         ChangeContourAttributeProfileAction::Init(this, this->GetUndoActionList(), 
03276             pController, pCParam->m_Profile, &pAction);
03277     
03278         pItem = (NodeListItem *)NodeList.GetNext(pItem);
03279     }
03280 
03281     NodeList.DeleteAll();
03282 
03283     // Inform the effected parents of the change
03284     if (ok)
03285     {
03286         End();
03287     }
03288     else
03289     {
03290         FailAndExecute();
03291         End();
03292     }
03293 }
03294 
03295 /********************************************************************************************
03296 
03297 >   BOOL OpChangeContourAttributeProfile::Declare()
03298 
03299     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03300     Created:    7/11/94
03301     Returns:    TRUE if all went OK, FALSE otherwise
03302     Purpose:    Adds the operation to the list of all known operations
03303 
03304 ********************************************************************************************/
03305 
03306 BOOL OpChangeContourAttributeProfile::Declare()
03307 {
03308     return (RegisterOpDescriptor(
03309                                 0, 
03310                                 _R(IDS_CHANGECONTOURATTRIBUTEPROFILE),
03311                                 CC_RUNTIME_CLASS(OpChangeContourAttributeProfile), 
03312                                 OPTOKEN_CHANGECONTOURATTRPROFILE,
03313                                 OpChangeContourAttributeProfile::GetState,
03314                                 0,  /* help ID */
03315                                 0,  /* bubble ID */
03316                                 0   /* bitmap ID */
03317                                 ));
03318 }
03319 
03320 
03321 /********************************************************************************************
03322 
03323 >   static OpState OpChangeContourAttributeProfile::GetState(String_256* Description, OpDescriptor*)
03324 
03325     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03326     Created:    7/11/94
03327     Outputs:    Description - GetState fills this string with an approriate description
03328                 of the current state of the operation 
03329     Returns:    The state of the operation, so that menu items (ticks and greying) can be
03330                 done properly
03331     Purpose:    Find out the state of the operation at the specific time
03332 
03333 ********************************************************************************************/
03334 
03335 OpState OpChangeContourAttributeProfile::GetState(String_256* Description, OpDescriptor*)
03336 {
03337     OpState State(FALSE,TRUE); // It's not ticked, but it is greyed by default
03338     
03339     // DMc - to test for bevels & contours
03340     // are there any contour nodes in the selection
03341     List NodeList;
03342     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
03343 
03344     if (!NodeList.IsEmpty())
03345     {
03346         State.Greyed = FALSE;
03347     }
03348 
03349     NodeList.DeleteAll();
03350 
03351     return State;
03352 }
03353 
03354 /********************************************************************************************
03355 
03356 >   virtual void OpChangeContourAttributeProfile::GetOpName(String_256* OpName) 
03357 
03358     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03359     Created:    7/11/94
03360     Inputs:     -
03361     Outputs:    The undo string for the operation
03362     Returns:    
03363     Purpose:    The GetOpName fn is overridden so that we return back a description 
03364                 appropriate to the type of attribute that the operation applies. 
03365     Errors:     -
03366     SeeAlso:    -
03367 
03368 ********************************************************************************************/
03369 
03370 void OpChangeContourAttributeProfile::GetOpName(String_256* OpName) 
03371 { 
03372     *OpName = String_256(_R(IDS_CONTOURCOLOURTYPE));
03373 }  
03374 
03375 //------------------------------------------------------------------------------------------------
03376 //------------------------------------------------------------------------------------------------
03377 //------------------------------------------------------------------------------------------------
03378 // The ChangeContourObjectProfileAction class
03379 
03380 /********************************************************************************************
03381 
03382 >   ChangeContourObjectProfileAction::ChangeContourObjectProfileAction()
03383 
03384     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03385     Created:    7/11/94
03386     Inputs:     -
03387     Outputs:    -
03388     Returns:    -
03389     Purpose:    Constructor for the action
03390     Errors:     -
03391     SeeAlso:    -
03392 
03393 ********************************************************************************************/
03394 
03395 ChangeContourObjectProfileAction::ChangeContourObjectProfileAction()
03396 {
03397     m_pNode = NULL;
03398 }
03399 
03400 
03401 /********************************************************************************************
03402 
03403 >   ActionCode ChangeContourObjectProfileAction::Init(  Operation*  pOp,
03404                                                 ActionList* pActionList,
03405                                                 NodeBlend*  pThisNodeBlend,
03406                                                 UINT32      NumSteps,
03407                                                 ChangeContourObjectProfileAction**  ppNewAction);
03408 
03409     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03410     Created:    7/11/94
03411     Inputs:     pOp             = ptr to the operation to which this action belongs
03412                 pActionList     =  ptr to action list to which this action should be added
03413                 pThisNodeBlend  = ptr to NodeBlend to change 
03414                 NumSteps        = Num steps to applied to pThisNodeBlend
03415     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
03416                                   a pointer to the created action
03417     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
03418     Purpose:    This is the function which creates an instance of this action. If there is no room 
03419                 in the undo buffer (which is determined by the base class Init function called within)
03420                 the function will either return AC_NO_RECORD which means the operation can continue, 
03421                 but no undo information needs to be stored, or AC_OK which means the operation should
03422                 continue AND record undo information. If the function returns AC_FAIL, there was not 
03423                 enough memory to record the undo information, and the user has decided not to continue
03424                 with the operation.
03425     Errors:     -
03426     SeeAlso:    Action::Init()
03427 
03428 ********************************************************************************************/
03429 
03430 
03431 
03432 ActionCode ChangeContourObjectProfileAction::Init( Operation* pOp,
03433                             ActionList* pActionList,
03434                             NodeContourController* pThisNodeContour,
03435                             CProfileBiasGain Profile,
03436                             ChangeContourObjectProfileAction** NewAction)
03437 {
03438     UINT32 ActSize = sizeof(ChangeContourObjectProfileAction);
03439 
03440     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,
03441         CC_RUNTIME_CLASS(ChangeContourObjectProfileAction),(Action**)NewAction);
03442 
03443     Document * pDoc = Document::GetCurrent();
03444 
03445     if (Ac != AC_FAIL)
03446     {
03447         (*NewAction)->m_pNode  = pThisNodeContour;
03448         (*NewAction)->m_Profile = pThisNodeContour->GetObjectProfile();
03449 
03450         // change the profile & regen
03451         pThisNodeContour->SetObjectProfile(Profile);
03452         pThisNodeContour->RegenerateNode(NULL, FALSE);
03453     
03454         // redraw the contour
03455         if (pDoc)
03456         {
03457             pDoc->ForceRedraw(pThisNodeContour->FindParentSpread(), 
03458                 pThisNodeContour->GetBoundingRect(), FALSE, pThisNodeContour);
03459         }
03460     }
03461 
03462     return Ac;
03463 }
03464 
03465 
03466 
03467 /********************************************************************************************
03468 
03469 >   void ChangeContourObjectProfileAction::ChangeObjectProfileWithNoUndo (CProfileBiasGain &Profile)
03470 
03471     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
03472     Created:    24/2/2000
03473     Inputs:     Profile - the profile that is to be applied directly (i.e.  applied with no undo)
03474     Purpose:    When applying contour (object) profiles, we only want to generate one bit of undo information.
03475                 This function allows us to meet this requirement (the one bit of undo information
03476                 is generated via OpChangeContourObjectProfile::DoWithParam ()).  This function is ONLY
03477                 called from within ContourInfoBarOp::ChangeProfile () - after
03478                 OpChangeContourObjectProfile::DoWithParam () has been called.
03479     Errors:     -
03480     SeeAlso:    SoftShadowInfoBarOp::ChangeProfile (), OpChangeContourObjectProfile::DoWithParam ().
03481 
03482 ********************************************************************************************/
03483 
03484 void ChangeContourObjectProfileAction::ChangeObjectProfileWithNoUndo (CProfileBiasGain &Profile)
03485 {
03486     BeginSlowJob(-1, TRUE);
03487     
03488     List NodeList;
03489     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
03490 
03491     NodeListItem * pItem = (NodeListItem *)NodeList.GetHead();
03492 
03493     NodeContourController * pController = NULL;
03494 
03495 //  Node * pParent = NULL;
03496 
03497 //  ChangeContourObjectProfileAction * pAction= NULL;
03498 
03499     Document * pDoc = Document::GetCurrent();
03500 
03501     while (pItem)
03502     {
03503         pController = (NodeContourController *)pItem->pNode;
03504 
03505         // change the profile & regen
03506         pController->SetObjectProfile(Profile);
03507         pController->RegenerateNode(NULL, FALSE);
03508     
03509         // redraw the contour
03510         if (pDoc)
03511         {
03512             pDoc->ForceRedraw(pController->FindParentSpread(), 
03513                 pController->GetBoundingRect(), FALSE, pController);
03514         }
03515     
03516         pItem = (NodeListItem *)NodeList.GetNext(pItem);
03517     }
03518 
03519     NodeList.DeleteAll();
03520 
03521     EndSlowJob ();
03522 
03523     if (pDoc->GetOpHistory ().CanRedo ())
03524     {
03525         // then we need to clear out the redo information - since we are now 'before' it ....
03526         pDoc->GetOpHistory ().DeleteRedoableOps ();
03527 
03528         // and update the state of things ....
03529         DialogBarOp::SetSystemStateChanged();
03530         DialogBarOp::UpdateStateOfAllBars();
03531     }
03532 }
03533 
03534 /********************************************************************************************
03535 
03536 >   ActionCode ChangeContourObjectProfileAction::Execute();
03537 
03538     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03539     Created:    7/11/94
03540     Inputs:     -
03541     Outputs:    -
03542     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
03543     Purpose:    Executes the action.  This will reset the num blend steps in pThisNodeBlend to OldNumSteps,
03544                 after creating another action to record the current num steps of pThisNodeBlend
03545     Errors:     -
03546     SeeAlso:    Action::Init()
03547 
03548 ********************************************************************************************/
03549 
03550 ActionCode ChangeContourObjectProfileAction::Execute()
03551 {
03552     ChangeContourObjectProfileAction * pAction = NULL;
03553     
03554     ActionCode Act = ChangeContourObjectProfileAction::Init(    pOperation, 
03555                                         pOppositeActLst,
03556                                         m_pNode,
03557                                         m_Profile,
03558                                         &pAction);
03559     if (Act != AC_FAIL)
03560     {
03561         
03562     }
03563 
03564     return Act;
03565 }
03566 
03567 ChangeContourObjectProfileAction::~ChangeContourObjectProfileAction()
03568 {
03569 }
03570 
03571 /********************************************************************************************
03572 
03573 >   void OpChangeContourObjectProfile::DoWithParam(OpDescriptor*,OpParam* pOpParam)
03574 
03575     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03576     Created:    7/11/94
03577     Returns:    -
03578     Purpose:    This changes all the selected blend objects to have pOpParam->Param1 number of steps
03579 
03580 ********************************************************************************************/
03581 
03582 void OpChangeContourObjectProfile::DoWithParam(OpDescriptor*,OpParam* pOpParam)
03583 {
03584     ERROR3IF(pOpParam == NULL,"NULL OpParam ptr");
03585     if (pOpParam == NULL) return;
03586 
03587     BOOL ok = TRUE;
03588 
03589     ChangeContourProfileParam * pCParam = (ChangeContourProfileParam *)pOpParam;
03590 
03591     DoStartSelOp(TRUE, TRUE);
03592     BeginSlowJob(-1, TRUE);
03593     
03594     List NodeList;
03595     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
03596 
03597     NodeListItem * pItem = (NodeListItem *)NodeList.GetHead();
03598 
03599     NodeContourController * pController = NULL;
03600 
03601 //  Node * pParent = NULL;
03602 
03603     ChangeContourObjectProfileAction * pAction= NULL;
03604 
03605     while (pItem && ok)
03606     {
03607         pController = (NodeContourController *)pItem->pNode;
03608 
03609         ChangeContourObjectProfileAction::Init(this, this->GetUndoActionList(), 
03610             pController, pCParam->m_Profile, &pAction);
03611     
03612         pItem = (NodeListItem *)NodeList.GetNext(pItem);
03613     }
03614 
03615     NodeList.DeleteAll();
03616 
03617     // Inform the effected parents of the change
03618     if (ok)
03619     {
03620         End();
03621     }
03622     else
03623     {
03624         FailAndExecute();
03625         End();
03626     }
03627 }
03628 
03629 /********************************************************************************************
03630 
03631 >   BOOL OpChangeContourObjectProfile::Declare()
03632 
03633     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03634     Created:    7/11/94
03635     Returns:    TRUE if all went OK, FALSE otherwise
03636     Purpose:    Adds the operation to the list of all known operations
03637 
03638 ********************************************************************************************/
03639 
03640 BOOL OpChangeContourObjectProfile::Declare()
03641 {
03642     return (RegisterOpDescriptor(
03643                                 0, 
03644                                 _R(IDS_CHANGECONTOUROBJECTPROFILE),
03645                                 CC_RUNTIME_CLASS(OpChangeContourObjectProfile), 
03646                                 OPTOKEN_CHANGECONTOUROBJPROFILE,
03647                                 OpChangeContourObjectProfile::GetState,
03648                                 0,  /* help ID */
03649                                 0,  /* bubble ID */
03650                                 0   /* bitmap ID */
03651                                 ));
03652 }
03653 
03654 
03655 /********************************************************************************************
03656 
03657 >   static OpState OpChangeContourObjectProfile::GetState(String_256* Description, OpDescriptor*)
03658 
03659     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03660     Created:    7/11/94
03661     Outputs:    Description - GetState fills this string with an approriate description
03662                 of the current state of the operation 
03663     Returns:    The state of the operation, so that menu items (ticks and greying) can be
03664                 done properly
03665     Purpose:    Find out the state of the operation at the specific time
03666 
03667 ********************************************************************************************/
03668 
03669 OpState OpChangeContourObjectProfile::GetState(String_256* Description, OpDescriptor*)
03670 {
03671     OpState State(FALSE,TRUE); // It's not ticked, but it is greyed by default
03672     
03673     // DMc - to test for bevels & contours
03674     // are there any contour nodes in the selection
03675     List NodeList;
03676     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
03677 
03678     if (!NodeList.IsEmpty())
03679     {
03680         State.Greyed = FALSE;
03681     }
03682 
03683     NodeList.DeleteAll();
03684 
03685     return State;
03686 }
03687 
03688 /********************************************************************************************
03689 
03690 >   virtual void OpChangeContourObjectProfile::GetOpName(String_256* OpName) 
03691 
03692     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03693     Created:    7/11/94
03694     Inputs:     -
03695     Outputs:    The undo string for the operation
03696     Returns:    
03697     Purpose:    The GetOpName fn is overridden so that we return back a description 
03698                 appropriate to the type of attribute that the operation applies. 
03699     Errors:     -
03700     SeeAlso:    -
03701 
03702 ********************************************************************************************/
03703 
03704 void OpChangeContourObjectProfile::GetOpName(String_256* OpName) 
03705 { 
03706     *OpName = String_256(_R(IDS_CONTOURCOLOURTYPE));
03707 }  
03708 
03710 //  OpChangeContourStepDistance
03711 //
03712 // Changes the number of steps of all the selected blends
03713 
03714 
03715 /********************************************************************************************
03716 
03717 >   void OpChangeContourStepDistance::DoWithParam(OpDescriptor*,OpParam* pOpParam)
03718 
03719     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03720     Created:    7/11/94
03721     Returns:    -
03722     Purpose:    This changes all the selected blend objects to have pOpParam->Param1 number of steps
03723 
03724 ********************************************************************************************/
03725 
03726 void OpChangeContourStepDistance::DoWithParam(OpDescriptor*,OpParam* pOpParam)
03727 {
03728     ERROR3IF(pOpParam == NULL,"NULL OpParam ptr");
03729     if (pOpParam == NULL) return;
03730 
03731     List NodeList;
03732     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeRenderableInk));
03733 
03734     NodeListItem *pItem = NULL;
03735 
03736     BOOL ok = !NodeList.IsEmpty();
03737 
03738     if (ok) ok = DoStartSelOp(FALSE,FALSE);
03739 
03740     if (ok)
03741     {
03742         // The new number of steps is in pOpParam->Param1 of the 
03743         INT32 NewStepDistance = INT32(pOpParam->Param1);
03744         pItem = (NodeListItem *)NodeList.GetHead();
03745 
03746         Node* pSelNode = NULL;
03747 
03748         if (pItem)
03749         {
03750             pSelNode = pItem->pNode;
03751         }
03752 
03753         while (pSelNode != NULL && ok)
03754         {
03755             Node* pNode = pSelNode;
03756 
03757             pItem = (NodeListItem *)NodeList.GetNext(pItem);
03758 
03759             if (pItem)
03760             {
03761                 pSelNode = pItem->pNode;
03762             }
03763             else
03764             {
03765                 pSelNode = NULL;
03766             }
03767 
03768             if (pNode->IS_KIND_OF(NodeContourController))
03769             {
03770                 // We now have a selected blend node so:
03771                 //  Invalidate the node's region
03772                 //  Store the current number of blend steps in an undo actiom
03773                 //  Change the number of steps to NewNumSteps
03774             
03775                 NodeRenderableInk * pInk = (NodeRenderableInk *)pNode;
03776 
03777                 UINT32 NumSteps = 0;
03778                 double DistanceEntered = 0.0;
03779                 NumSteps = ((NodeContourController *)pNode)->GetNumberOfSteps();
03780                 DistanceEntered = 0.0;
03781                 
03782                 ChangeContourStepsAction* pAction;
03783 
03784                 // Ask the node if it's ok to do the op
03785                 ObjChangeFlags cFlags;
03786                 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
03787                 ok = pInk->AllowOp(&ObjChange);
03788 
03789                 if (ok) ok = DoInvalidateNodeRegion(pInk,TRUE,FALSE);
03790                 if (ok) ok = (InvalidateBoundsAction::Init(this,&UndoActions,pInk,TRUE) != AC_FAIL);
03791                 if (ok) ok = ChangeContourStepsAction::Init(this,&UndoActions,pInk,NumSteps, DistanceEntered, &pAction) != AC_FAIL;
03792                 
03793                 if (ok)
03794                 {
03795                     if (abs(((NodeContourController *)pNode)->GetWidth()) < NewStepDistance * 2)
03796                     {
03797                         ((NodeContourController *)pNode)->SetNumberOfSteps(0);
03798                     }
03799                     else
03800                     {
03801                         ((NodeContourController *)pNode)->SetNumberOfSteps(
03802                             (abs(((NodeContourController *)pNode)->GetWidth()) / NewStepDistance) - 1);
03803                     }
03804                     pNode->RegenerateNode(NULL, FALSE);
03805                 }
03806                 
03807                 if (ok) ok = DoInvalidateNodeRegion(pInk,TRUE,FALSE);
03808                 if (ok) ok = (InvalidateBoundsAction::Init(this,&UndoActions,pInk,TRUE) != AC_FAIL);
03809             }
03810         }
03811     }
03812 
03813     NodeList.DeleteAll();
03814 
03815     if (ok) 
03816     {
03817         // Inform the effected parents of the change
03818         ObjChangeFlags cFlags;
03819         ObjChangeParam ObjChange(OBJCHANGE_FINISHED,cFlags,NULL,this);
03820         UpdateChangedNodes(&ObjChange);
03821     }
03822     else
03823         FailAndExecute();
03824 
03825     End();
03826 }
03827 
03828 /********************************************************************************************
03829 
03830 >   BOOL OpChangeContourStepDistance::Declare()
03831 
03832     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03833     Created:    7/11/94
03834     Returns:    TRUE if all went OK, FALSE otherwise
03835     Purpose:    Adds the operation to the list of all known operations
03836 
03837 ********************************************************************************************/
03838 
03839 BOOL OpChangeContourStepDistance::Declare()
03840 {
03841     return (RegisterOpDescriptor(
03842                                 0, 
03843                                 0,
03844                                 CC_RUNTIME_CLASS(OpChangeContourStepDistance), 
03845                                 OPTOKEN_CHANGECONTOURSTEPDISTANCE,
03846                                 OpChangeContourStepDistance::GetState,
03847                                 0,  /* help ID */
03848                                 0,  /* bubble ID */
03849                                 0   /* bitmap ID */
03850                                 ));
03851 }
03852 
03853 
03854 /********************************************************************************************
03855 
03856 >   static OpState OpChangeContourStepDistance::GetState(String_256* Description, OpDescriptor*)
03857 
03858     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03859     Created:    7/11/94
03860     Outputs:    Description - GetState fills this string with an approriate description
03861                 of the current state of the operation 
03862     Returns:    The state of the operation, so that menu items (ticks and greying) can be
03863                 done properly
03864     Purpose:    Find out the state of the operation at the specific time
03865 
03866 ********************************************************************************************/
03867 
03868 OpState OpChangeContourStepDistance::GetState(String_256* Description, OpDescriptor*)
03869 {
03870     OpState State(FALSE,TRUE); // It's not ticked, but it is greyed by default
03871     
03872     // DMc - to test for bevels & contours
03873     // are there any contour nodes in the selection
03874     List NodeList;
03875     BevelTools::BuildListOfSelectedNodes(&NodeList, CC_RUNTIME_CLASS(NodeContourController));
03876 
03877     if (!NodeList.IsEmpty())
03878     {
03879         State.Greyed = FALSE;
03880     }
03881 
03882     NodeList.DeleteAll();
03883 
03884     if (State.Greyed)
03885         *Description = String_256(_R(IDS_CONTOURSTEPS));
03886     else
03887         *Description = String_256(_R(IDS_CONTOURSTEPS));
03888 
03889     return State;
03890 }
03891 
03892 /********************************************************************************************
03893 
03894 >   virtual void OpChangeContourStepDistance::GetOpName(String_256* OpName) 
03895 
03896     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03897     Created:    7/11/94
03898     Inputs:     -
03899     Outputs:    The undo string for the operation
03900     Returns:    
03901     Purpose:    The GetOpName fn is overridden so that we return back a description 
03902                 appropriate to the type of attribute that the operation applies. 
03903     Errors:     -
03904     SeeAlso:    -
03905 
03906 ********************************************************************************************/
03907 
03908 void OpChangeContourStepDistance::GetOpName(String_256* OpName) 
03909 { 
03910     *OpName = String_256(_R(IDS_CONTOURSTEPS_UNDO));
03911 }  
03912 
03914 // OpConvertPathToShapes class
03915 
03916 /********************************************************************************************
03917 
03918 >   BOOL OpConvertPathToShapes::Declare()
03919 
03920     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03921     Created:    10/2/2000
03922     Returns:    TRUE if all went OK, False otherwise
03923     Purpose:    Adds the operation to the list of all known operations
03924 
03925 ********************************************************************************************/
03926 BOOL OpConvertPathToShapes::Declare()
03927 {
03928     return (RegisterOpDescriptor(
03929                                 0, 
03930                                 _R(IDS_CONVERTPATHTOSHAPES),
03931                                 CC_RUNTIME_CLASS(OpConvertPathToShapes), 
03932                                 OPTOKEN_CONVERTPATHTOSHAPES,
03933                                 OpConvertPathToShapes::GetState));
03934 
03935 }
03936 
03937 /********************************************************************************************
03938 
03939 >   OpState OpConvertPathToShapes::GetState(String_256* Description, OpDescriptor*);
03940 
03941     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03942     Created:    10/2/2000
03943     Returns:    TRUE if all went OK, False otherwise
03944     Purpose:    Gets the state of the operation
03945 
03946 ********************************************************************************************/
03947 OpState OpConvertPathToShapes::GetState(String_256* Description, OpDescriptor*)
03948 {
03949     OpState Blobby;
03950 
03951     // do greyed for no selection
03952     Range * pSel = GetApplication()->FindSelection();
03953 
03954     Blobby.Greyed = FALSE;
03955 
03956     if (!pSel)
03957     {
03958         Blobby.Greyed = TRUE;
03959         return Blobby;
03960     }
03961 
03962     // If there is nothing selected, grey the item and give a reason.
03963     if (pSel->IsEmpty())
03964     {
03965         Blobby.Greyed = TRUE;
03966         *Description = String_256 (_R(IDS_NO_OBJECTS_SELECTED));
03967         return Blobby;
03968     }
03969     
03970     // run through the range finding out if any nodes have promote hit test on
03971     // children to me set in their parents, or are needs parent nodes
03972     Node * pNode = pSel->FindFirst();
03973     Node * pSubNode = NULL;
03974     Node * pParent = NULL;
03975     
03976     while (pNode && Blobby.Greyed == FALSE)
03977     {
03978         if (pNode->NeedsParent(NULL))
03979         {
03980             Blobby.Greyed = TRUE;
03981             break;
03982         }
03983         
03984         pParent = pNode->FindParent();
03985         
03986         while (pParent)
03987         {
03988             if (pParent->ShouldITransformWithChildren())
03989             {
03990                 Blobby.Greyed = TRUE;
03991                 break;
03992             }
03993             
03994             pParent = pParent->FindParent();
03995         }
03996 
03997         // check all nodes under this node too
03998         pSubNode = pNode->FindFirstDepthFirst();
03999 
04000         while (pSubNode && pSubNode != pNode)
04001         {
04002             if (pSubNode->NeedsParent(NULL) ||
04003                 pSubNode->ShouldITransformWithChildren())
04004             {
04005                 Blobby.Greyed = TRUE;
04006                 break;
04007             }
04008 
04009             pSubNode = pSubNode->FindNextDepthFirst(pNode);
04010         }
04011         
04012         pNode = pSel->FindNext(pNode);
04013     }
04014 
04015     return Blobby;
04016 }
04017 
04018 /********************************************************************************************
04019 
04020 >   void OpConvertPathToShapes::Do(OpDescriptor * pDesc)
04021 
04022     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04023     Created:    10/2/2000
04024     Returns:    
04025     Purpose:    Does the operation
04026 
04027 ********************************************************************************************/
04028 void OpConvertPathToShapes::Do(OpDescriptor * pDesc)
04029 {
04030     // run through the sel range, dealing with every node
04031     DoStartSelOp(TRUE, TRUE, TRUE, TRUE);
04032 
04033     Range * pSel = GetApplication()->FindSelection();
04034 
04035     if (!pSel)
04036     {
04037         FailAndExecute();
04038         End();
04039         return;
04040     }
04041 
04042     Node * pNode = pSel->FindFirst();
04043     Node * pNextNode = NULL;
04044 
04045     while (pNode)
04046     {
04047         // must get the next node first since the geometry will change
04048         pNextNode = pSel->FindNext(pNode);
04049 
04050         if (pNode->IsAnObject())
04051         {       
04052             if (!ConvertPathToShapes(this, (NodeRenderableInk *)pNode))
04053             {
04054                 FailAndExecute();
04055                 End();
04056                 return;
04057             }
04058         }
04059 
04060         pNode = pNextNode;      
04061     }
04062 
04063     End();
04064 }
04065 
04066 /********************************************************************************************
04067 
04068 >   void OpConvertPathToShapes::GetOpName(String_256* OpName)
04069 
04070     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04071     Created:    10/2/2000
04072     Returns:    
04073     Purpose:    Gets the op's name
04074 
04075 ********************************************************************************************/
04076 void OpConvertPathToShapes::GetOpName(String_256* OpName)
04077 {
04078     if (OpName)
04079     {
04080         OpName->Load(_R(IDS_CONVERTPATHTOSHAPES));
04081     }
04082 }
04083 
04084 /********************************************************************************************
04085 
04086 >   static BOOL OpConvertPathToShapes::ConvertPathToShapes(OpConvertPathToShapes* pOp, NodeRenderableInk* pInk)
04087 
04088     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04089     Created:    10/2/2000
04090     Inputs:     pOp  - pointer to the op doing this (can be NULL for external use)
04091                 pInk - the node to convert 
04092     Returns:    TRUE for success, FALSE for failure
04093     Purpose:    Does the convert
04094 
04095                 DY 28/11/2000 Some serious changes have taken place now, in order to deal 
04096                 with groups of objects containing brushes or strokes.  Basically the following can 
04097                 occur:
04098 
04099                 - pInk is a single ink object with a brush or stroke attribute, in which case it
04100                 is dealt with indiviually in ConvertBrush/Stroke.
04101                 - pInk is an ink object with no brush or stroke attribute - basically the old case, 
04102                 here we simply sum the paths of pInk and make a new shape out of them.
04103                 - pInk is a group containing any combination of normal shapes, brushed or stroked shapes.
04104                 This is the difficult case, basically the ConvertPathToShapesBecomeA passback function
04105                 will store converted brushes and strokes under a group context node (though there is one
04106                 exception to this, where there are no brushes), and stores the summed paths of 
04107                 any normal shapes.  We then extract these and put them all under one new group.
04108 
04109 ********************************************************************************************/
04110 
04111 BOOL OpConvertPathToShapes::ConvertPathToShapes(OpConvertPathToShapes* pOp, NodeRenderableInk* pInk)
04112 {
04113 //  UINT32 NumObjs = 0;
04114 
04115     // first, find out whether we have a non-transparent line attribute
04116 
04117     // if we do, then lets not do anything.
04118 
04119     // BUT, if we do; then lets get on a do some funky stuff ....
04120     // i.e. make the line colour into the fill colour for this node
04121 
04122     AttrStrokeColour * pColour = NULL;
04123     
04124     pInk->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), 
04125         (NodeAttribute **)(&pColour));
04126 
04127     ConvertPathToShapesBecomeA MyBecomeA(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), pOp, FALSE);
04128 
04129     if (pColour)
04130     {
04131         StrokeColourAttribute * pAttrVal = (StrokeColourAttribute *)pColour->GetAttributeValue();
04132         
04133         if (pAttrVal->Colour.IsTransparent ())
04134         {
04135             return TRUE;
04136         }
04137         if (!pInk->CanBecomeA(&MyBecomeA))
04138         {
04139             ERROR3("Ink node cannot become nodepath in OpConvertPathToShapes::ConvertPathToShapes");
04140             return TRUE;
04141         }
04142     }
04143     
04144 
04145     /* find out if we have an applied brush node, if so then do our own thing
04146     Note that this block must always be before the Stroke attribute block because
04147     the stroke attribute, when used in conjunction with the brush attribute, acts
04148     as a pressure provider to the brush
04149     */
04150 //  NodeAttribute* pAttr = NULL;
04151     AttrBrushType* pBrush = NULL;
04152     pInk->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), (NodeAttribute**)&pBrush);
04153     
04154     // note that this only deals with a single ink node case, it cannot deal with groups
04155     if (pBrush != NULL && pBrush->GetBrushHandle() != BrushHandle_NoBrush && !pInk->IsCompound())
04156     {
04157         if (ConvertBrush(pOp, pBrush, pInk))
04158             return TRUE;
04159     }
04160 
04161 
04162     // We have another special case if there is a stroke attribute applied
04163     AttrStrokeType* pStroke = NULL;
04164     pInk->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeType), (NodeAttribute**)&pStroke);
04165     AttrVariableWidth* pVarWidth = NULL;
04166     pInk->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrVariableWidth), (NodeAttribute**)&pVarWidth);
04167 
04168     /* This next block exists as the simplest stroke case, and allows us to avoid making any groups,
04169     however we can only enter the next block if we are a single ink node with an an acitve stroke applied
04170     the entry conditions to this block: 
04171     - Do you have an active PathProcessorStroke?
04172     - Do you have an active VariableWidthFunction?
04173     - Are you not compound?
04174     */
04175     if (pStroke != NULL && pStroke->HasPathProcessor() && pVarWidth != NULL &&  
04176         pVarWidth->HasActiveValueFunction() &&!pInk->IsCompound())
04177     {
04178         BOOL Success = ConvertStroke(pOp, pStroke, pInk);
04179         if (Success)
04180         {
04181             // invalidate the node so we get rid of any fill there might have been
04182             DocRect BRect = pInk->GetBoundingRect();
04183             pInk->ReleaseCached();
04184             Spread* pSpread = Document::GetSelectedSpread();
04185             if (pOp != NULL && pSpread != NULL)
04186                 pOp->DoInvalidateRegion(pSpread, BRect);    
04187 
04188             pInk->SetSelected(FALSE);
04189 
04190             NodeHidden * pHidden = NULL;
04191             
04192             if (pOp)
04193                 return pOp->DoHideNode(pInk, TRUE, &pHidden, FALSE);
04194             else
04195             {
04196                 pInk->CascadeDelete();
04197                 delete pInk;
04198                 return(TRUE);
04199             }
04200         }
04201 
04202     }
04203     
04204     /* If we have reached this point then we are one of the following:
04205     - A group, potentially containing various combinations of brushes or strokes 
04206     - A single normal ink node, with no brush or stroke applied */
04207 
04208     // create the new path node
04209     NodePath * pNewNode = NULL;
04210     ALLOC_WITH_FAIL(pNewNode, new NodePath, pOp);
04211 
04212     pNewNode->InkPath.Initialise(); 
04213     if (pOp)
04214         pOp->DoLocaliseForAttrChange(pInk, (AttrTypeSet *)NULL, (ObjectSet *)NULL);
04215     else
04216     {
04217         Node* pParent = pInk->FindParent(); 
04218         ERROR3IF(!pParent, "UndoableOperation::DoLocaliseForAttrChange called on an object which has no parent"); 
04219         if (pParent->IsCompound())
04220         {
04221             ((NodeRenderableInk*)pParent)->LocaliseCommonAttributes(FALSE, TRUE, NULL);
04222         }
04223     }
04224 
04225 
04226     // we need a group to store any groups of strokes we might have
04227     NodeRenderableInk* pGroup = NULL;
04228 
04229     // Do the conversion
04230     pInk->DoBecomeA(&MyBecomeA);
04231 
04232     // the summed path consists of the outlines of all the normal (i.e. non-brush or stroke) objects
04233     MyBecomeA.GetSummedPath(&(pNewNode->InkPath));
04234 
04235     // the context node is a group under which all strokes and brushes are placed
04236     pGroup = MyBecomeA.GetContextNode();
04237     
04238 
04239     // Right, some changes here to do with the case where we have strokes and brushes in a group
04240     // basically the BecomeA mechanism will have dealt with them separately, and generated a nodegroup
04241     // out of any brushes we may have had, and summed the paths of all other nodes.
04242 
04243     // first deal with any summed paths we may have generated
04244     if (pNewNode->InkPath.GetNumCoords() > 0)
04245     {
04246         AdjustStrokeAndFillAttrs(pOp, pNewNode, pInk);
04247     }
04248     else
04249     {
04250         delete pNewNode;
04251         pNewNode = NULL;
04252     }
04253 
04254     BOOL ok = TRUE;
04255     // ok, if we have a) a group and a nodepath or b) a group with a sibling, 
04256     // then we'll make an extra nodegroup to store them under
04257 
04258     if ((pNewNode && pGroup) || (pGroup && pGroup->FindNext()))
04259     {
04260         NodeGroup* pNewGroup = NULL;
04261         ALLOC_WITH_FAIL(pNewGroup, new NodeGroup, pOp);
04262         if (pNewGroup)
04263         {
04264             pGroup->InsertChainSimple(pNewGroup, LASTCHILD);
04265             if (pNewNode)
04266                 pNewNode->AttachNode(pNewGroup, LASTCHILD);
04267         }
04268         if (pOp)
04269         {
04270             ok = pOp->DoInsertNewNode(pNewGroup, pInk, NEXT, TRUE, FALSE, TRUE, TRUE);
04271             if (ok) ok = pOp->DoFactorOutAfterAttrChange(pNewGroup, (AttrTypeSet *)NULL);
04272         }
04273         else
04274         {
04275             pNewGroup->AttachNode(pInk, NEXT);
04276             Node* pParent;
04277             pParent = pNewGroup->FindParent();
04278             ERROR3IF(!pParent, "Trying to FactorOutCommonChildAttributes on an object which has no parent");
04279             if (pParent->IsCompound())
04280             {
04281                 ((NodeRenderableInk*)pParent)->FactorOutCommonChildAttributes(TRUE, (AttrTypeSet *)NULL);
04282             }
04283         }
04284     }
04285     else if (pNewNode != NULL)
04286     {
04287         // otherwise we've only got one new node, made from non-strokes and brushes
04288         if (pOp)
04289         {
04290             ok = pOp->DoInsertNewNode(pNewNode, pInk, NEXT, TRUE, FALSE, TRUE, TRUE);
04291 //          if (ok) ok = DoFactorOutAfterAttrChange(pNewNode, (AttrTypeSet *)NULL);
04292         }
04293         else
04294         {
04295             pNewNode->AttachNode(pInk, NEXT);
04296         }
04297     }
04298     else if (pGroup != NULL)
04299     {
04300         if (pOp)
04301         {
04302             ok = pOp->DoInsertNewNode(pGroup, pInk, NEXT, TRUE, FALSE, TRUE, TRUE);
04303             if (ok) ok = pOp->DoFactorOutAfterAttrChange(pGroup, (AttrTypeSet *)NULL);
04304         }
04305         else
04306         {
04307             pGroup->AttachNode(pInk, NEXT);
04308             Node* pParent;
04309             pParent = pGroup->FindParent();
04310             ERROR3IF(!pParent, "Trying to FactorOutCommonChildAttributes on an object which has no parent");
04311             if (pParent->IsCompound())
04312             {
04313                 ((NodeRenderableInk*)pParent)->FactorOutCommonChildAttributes(TRUE, (AttrTypeSet *)NULL);
04314             }
04315         }
04316     }
04317 
04318     if (pOp)
04319     {
04320         pOp->DoFactorOutAfterAttrChange(pInk, (AttrTypeSet *)NULL);
04321     }
04322     else
04323     {
04324         Node* pParent;
04325         pParent = pInk->FindParent();
04326         ERROR3IF(!pParent, "Trying to FactorOutCommonChildAttributes on an object which has no parent");
04327         if (pParent->IsCompound())
04328         {
04329             ((NodeRenderableInk*)pParent)->FactorOutCommonChildAttributes(TRUE, (AttrTypeSet *)NULL);
04330         }
04331     }
04332 
04333     pInk->SetSelected(FALSE);
04334 
04335     // Hide the original ink node
04336     if (pOp)
04337     {
04338         NodeHidden * pHidden = NULL;
04339         if (ok)
04340             ok = pOp->DoHideNode(pInk, TRUE, &pHidden, FALSE);
04341     }
04342     else
04343     {
04344         pInk->CascadeDelete();
04345         delete pInk;
04346     }
04347         
04348     return ok;
04349 
04350 }
04351 
04352 
04353 /********************************************************************************************
04354 
04355 >   static BOOL OpConvertPathToShapes::ConvertBrush(OpConvertPathToShapes* pOp, AttrBrushType* pAttrBrush, NodeRenderableInk* pInk)
04356 
04357     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04358     Created:    28/11/2000
04359     Inputs:     pAttrBrush - the brush attribute that is applied to the node we wish to convert
04360                 pInk       - the node we wish to convert
04361             
04362 
04363     Returns:    TRUE for success, FALSE for failure
04364     Purpose:    To convert nodes with a brush attribute applied to them.  Note that this ONLY
04365                 works for single nodes, compound nodes are dealt with in the main Convert function
04366                 as there are many different possible permutations.
04367 
04368 ********************************************************************************************/
04369 
04370 BOOL OpConvertPathToShapes::ConvertBrush(OpConvertPathToShapes* pOp, AttrBrushType* pAttrBrush, NodeRenderableInk* pInk)
04371 {
04372     ERROR2IF(pAttrBrush == NULL || pInk == NULL, FALSE, "Inputs are NULL to OpConvertPathToShapes::ConvertBrush");
04373     
04374     if (pInk->IsCompound())
04375     {
04376         ERROR3("Attempting to convert brush on a compound node when we really shouldn't be");
04377         return FALSE;
04378     }
04379 
04380     PathProcessorBrush* pPPB = pAttrBrush->GetPathProcessor();
04381     if (pPPB == NULL)
04382     {
04383         ERROR3("Brush has no path processor in OpConvertPathToShapes::ConvertBrush");
04384         return FALSE;
04385     }
04386 
04387     // Fairly simple, as we let the attributes becomea function do the work
04388     pInk->ReleaseCached();                      // This call is associated with the DoInvalidateRegion call below
04389                                                 // but must be called before pInk is removed from the tree
04390     pInk->SetSelected(FALSE);
04391     BecomeA BecomeAPath(BECOMEA_REPLACE,CC_RUNTIME_CLASS(NodePath), pOp, FALSE);
04392     BOOL Retval = pAttrBrush->DoBecomeA(&BecomeAPath, pInk);
04393 
04394     // If DoBecomeA worked, pInk is no longer in the tree...
04395 
04396     // invalidate the node so we get rid of any fill there might have been
04397     if (pOp)
04398     {
04399         DocRect BRect = pAttrBrush->GetAttrBoundingRect(pInk);
04400         Spread* pSpread = Document::GetSelectedSpread();
04401         if (pSpread != NULL)
04402             pOp->DoInvalidateRegion(pSpread, BRect);
04403     }
04404 
04405     return Retval;
04406 }
04407 
04408 
04409 /********************************************************************************************
04410 
04411 >   static BOOL OpConvertPathToShapes::ConvertStroke(OpConvertPathToShapes* pOp, AttrStrokeType* pStroke, NodeRenderableInk* pInk)
04412 
04413     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04414     Created:    28/11/2000
04415     Inputs:     pStroke    - the stroke attribute that is applied to the node we wish to convert
04416                 pInk       - the node we wish to convert
04417             
04418 
04419     Returns:    TRUE for success, FALSE for failure
04420     Purpose:    To convert nodes with a stroke attribute applied to them.  Note that this ONLY
04421                 works for single nodes, compound nodes are dealt with in the main Convert function
04422                 as there are many different possible permutations.
04423                 Note that this function assumes that there is also an AttrVariableWidth applied
04424                 to pInk, if there is not then your stroke attr just won't do anything.
04425 
04426 ********************************************************************************************/
04427 
04428 BOOL OpConvertPathToShapes::ConvertStroke(OpConvertPathToShapes* pOp, AttrStrokeType* pStroke, NodeRenderableInk* pInk)
04429 {
04430     ERROR2IF(pStroke == NULL || pInk == NULL, FALSE, "Inputs are NULL to OpConvertPathToShapes::ConvertBrush");
04431     
04432     if (pInk->IsCompound())
04433     {
04434         ERROR3("Attempting to convert brush on a compound node when we really shouldn't be");
04435         return FALSE;
04436     }
04437 
04438     // we need the path processor to do the work
04439     PathProcessorStroke* pPPS = pStroke->GetPathProcessor();
04440     if (pPPS == NULL)
04441     {
04442         ERROR3("Can't get PathProcessorStroke in OpConvertPathToShapes::ConvertStroke");
04443         return FALSE;
04444     }
04445 
04446     // Use a SimpleBecomeA to get the path from the parent object
04447     SimpleBecomeA BecomeA(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), NULL);
04448     
04449     BOOL Retval = FALSE;
04450     
04451     if (pInk->DoBecomeA(&BecomeA))
04452     {
04453         NodePath* pNodePath = BecomeA.GetNodePath();
04454         if (pNodePath)
04455         {
04456             NodePath* pStrokePath = pPPS->GetSmoothProcessedPath(&(pNodePath->InkPath), pInk);
04457             if (pStrokePath)
04458             {
04459                 // Karim 05/12/2000
04460                 // process the returned stroke, to change its working
04461                 // winding rule from non-zero to even-odd.
04462                 Path* pInkStrokePath = &(pStrokePath->InkPath);
04463                 double Flatness = pInkStrokePath->CalculateFlatnessValueFromPath(750.0, 2.0, 375.0);
04464                 pInkStrokePath->ClipPathToPath(*pInkStrokePath, pInkStrokePath, 3 | 0x10, 20, Flatness, Flatness);
04465 
04466                 // We've got the path we wish to use
04467                 if (AdjustStrokeAndFillAttrs(pOp, pStrokePath, pInk))
04468                 {
04469                     if (pOp)
04470                         Retval = pOp->DoInsertNewNode(pStrokePath, pInk, NEXT, TRUE, FALSE, TRUE, TRUE);
04471                     else
04472                     {
04473                         pStrokePath->AttachNode(pInk, NEXT);
04474                         Retval = TRUE;
04475                     }
04476                 }
04477                 else
04478                 {
04479                     delete pStrokePath;
04480                 }
04481             }
04482             delete pNodePath;
04483             pNodePath = NULL;
04484         }
04485         else
04486         {
04487             ERROR3("Failed to get nodepath from ink object in OpConvertPathToShapes::ConvertStroke");
04488         }
04489     }
04490     return Retval;
04491 }
04492 
04493 /********************************************************************************************
04494 
04495 >   static BOOL OpConvertPathToShapes::AdjustStrokeAndFillAttrs(OpConvertPathToShapes* pOp, 
04496                                                     NodePath* pNewNode, 
04497                                                     NodeRenderableInk* pCreatedByNode = NULL,
04498                                                     CCAttrMap* pAttrMap = NULL)
04499 
04500     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04501     Created:    28/11/2000
04502     Inputs:     pNewNode - the newpath node that we have inserted into the tree
04503                 pCreatedByNode - the original node that created pNewNode, can be null
04504                 pAttrMap - if pCreatedByNode is not supplied then an attrmap of the creator node 
04505                             must be supplied
04506 
04507     Returns:    TRUE for success, FALSE for failure
04508     Purpose:    This is only of use for ink nodes that had a variable width stroke attribute
04509                 applied to them.  In this case we wish to take the old stroke colour and make
04510                 it into a new fill colour for pNewNode.  We also wish to apply a transparent
04511                 stroke colour.
04512 
04513 ********************************************************************************************/
04514 
04515 BOOL OpConvertPathToShapes::AdjustStrokeAndFillAttrs(OpConvertPathToShapes* pOp, 
04516                                                         NodePath* pNewNode, 
04517                                                         NodeRenderableInk* pCreatedByNode,
04518                                                         CCAttrMap* pAttrMap)
04519 {
04520     ERROR2IF(pNewNode == NULL, FALSE, "New node is NULL in OpConvertPathToShapes::AdjustStrokeAndFillAttrs");
04521     ERROR2IF(pCreatedByNode == NULL && pAttrMap == NULL, FALSE, "Both parent node and attrmap are NULL in OpConvertPathToShapes::AdjustStrokeAndFillAttrs");
04522 
04523     pNewNode->InkPath.IsFilled = TRUE;
04524     pNewNode->InkPath.IsStroked = TRUE;
04525     pNewNode->InkPath.InitialiseFlags();    
04526 
04527     // we need to get the stroke colour of our original object
04528     AttrStrokeColour * pColour = NULL;
04529 
04530     // look up this attribute
04531     if (pCreatedByNode)
04532     {
04533         pCreatedByNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), 
04534             (NodeAttribute **)(&pColour));
04535     }
04536     else
04537     {
04538         pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrStrokeColour), (void*&)pColour);
04539     }
04540 
04541     // make a new flat fill attribute and apply this to the node
04542     if (pColour)
04543     {
04544         StrokeColourAttribute * pAttrVal = (StrokeColourAttribute *)pColour->GetAttributeValue();
04545 
04546         if (pAttrVal)
04547         {
04548             AttrFlatColourFill *pFill = NULL;
04549             ALLOC_WITH_FAIL(pFill, new AttrFlatColourFill(pNewNode, FIRSTCHILD), pOp);
04550             
04551             if (pFill)
04552                 pFill->SetStartColour(&(pAttrVal->Colour));
04553         }
04554     }
04555     else
04556         ERROR3("Unable to find stroke colour in OpConvertPathToShapes::AdjustStrokeAndFillAttrs");
04557 
04558     // If we've got a current fill transparency then leave it alone
04559     AttrFillGeometry* pTranspFill = NULL;
04560     if (pCreatedByNode)
04561     {
04562         pCreatedByNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTranspFillGeometry), (NodeAttribute**)&pTranspFill);
04563     }
04564     else
04565     {
04566         pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrTranspFillGeometry), (void*&)pTranspFill);
04567     }
04568     if (pTranspFill && !pTranspFill->IsAFlatFill())
04569     {
04570         Node* pNewTranspFill = NULL;
04571         ALLOC_WITH_FAIL(pNewTranspFill, pTranspFill->PublicCopy(), pOp);
04572         if (pNewTranspFill)
04573         {
04574             pNewTranspFill->AttachNode(pNewNode, FIRSTCHILD);
04575         }
04576     }
04577     else
04578     {
04579         // if we've got a current stroke transparency then lets convert this to a fill transparency
04580         AttrStrokeTransp* pTransp = NULL;
04581         if (pCreatedByNode)
04582         {
04583             pCreatedByNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeTransp), (NodeAttribute**)&pTransp);
04584         }
04585         else
04586         {
04587             pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrStrokeTransp), (void*&)pTransp);
04588         }
04589         if (pTransp)
04590         {
04591             // make a flatfill transp and apply it
04592             AttrFlatTranspFill* pTranspFill = NULL;
04593             ALLOC_WITH_FAIL(pTranspFill, new AttrFlatTranspFill(pNewNode, FIRSTCHILD), pOp);
04594 
04595             if (pTranspFill)
04596             {
04597                 pTranspFill->SetStartTransp(&pTransp->Value.Transp);
04598                 pTranspFill->SetTranspType(pTransp->Value.TranspType);
04599             }
04600         }
04601     }
04602     
04603     // apply a transparent line colour
04604     AttrStrokeColour * pTranspAttr = NULL;
04605     ALLOC_WITH_FAIL(pTranspAttr, new AttrStrokeColour(pNewNode, FIRSTCHILD), pOp);
04606     if (pTranspAttr)
04607     {
04608         StrokeColourAttribute * pTranspVal = (StrokeColourAttribute *)pTranspAttr->GetAttributeValue();
04609         pTranspVal->Colour = DocColour(COLOUR_NONE);
04610     }
04611 
04612     // apply a line width
04613     AttrLineWidth* pLineWidth = NULL;
04614     ALLOC_WITH_FAIL(pLineWidth, new AttrLineWidth(pNewNode, FIRSTCHILD), pOp);
04615     if (pLineWidth)
04616         pLineWidth->Value.LineWidth = 500;
04617 
04618     AttrWindingRule * pWindingRule = NULL;
04619     ALLOC_WITH_FAIL(pWindingRule, new AttrWindingRule(pNewNode, LASTCHILD), pOp);
04620 
04621     if (pWindingRule)
04622         pWindingRule->Value.WindingRule = NegativeWinding;
04623 
04624     return TRUE;
04625 }
04626 
04627 
04628 
04630 // The becomeA structure for the above
04631 /********************************************************************************************
04632 
04633 >   ConvertPathToShapesBecomeA::ConvertPathToShapesBecomeA( BecomeAReason Reason,
04634                     CCRuntimeClass* pClass, 
04635                     UndoableOperation* pOp, 
04636                     BOOL Sel) : BecomeA(Reason, pClass, pOp, Sel)
04637 
04638     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04639     Created:    10/2/2000
04640     Inputs:     See base class
04641     Purpose:    Constructor (initialises the path)
04642 
04643 ********************************************************************************************/
04644 ConvertPathToShapesBecomeA::ConvertPathToShapesBecomeA( BecomeAReason Reason,
04645                     CCRuntimeClass* pClass, 
04646                     UndoableOperation* pOp, 
04647                     BOOL Sel) : BecomeA(Reason, pClass, pOp, Sel)
04648 {
04649     m_SummedPath.Initialise();
04650     m_pContextNode = NULL;
04651     
04652 }
04653 
04654 /********************************************************************************************
04655 
04656 >   BOOL ConvertPathToShapesBecomeA::PassBack(NodeRenderableInk* pNewNode,
04657                                           NodeRenderableInk* pCreatedByNode,
04658                                           CCAttrMap* pAttrMap=NULL)
04659     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04660     Inputs:     See base class
04661     Outputs:    TRUE for success, FALSE for failure
04662     Created:    10/2/2000
04663     Purpose:    The passback function for the convert path to shapes operation
04664                 Just stores the path passed in so that the operation can use it
04665 
04666                 DY 28/11/2000 This has been changed to deal with what gets passed back
04667                 by brush and stroke attributes.  So basically there are three cases:
04668 
04669                 1) No brush or stroke attributes applied:  Easy, we just add the paths to
04670                 the summed path that we are storing.
04671                 2) Stroke attribute applied: We ask the stroke for its stroked path and store it 
04672                 as a sibling to our context node.
04673                 3) Brush applied: Somewhat more complex - the BrushBecomeAGroup does pretty much
04674                 what its name suggests, and we store the returned group under the context node.
04675                 Recall that if both a brush and a stroke are applied then the stroke acts as a
04676                 pressure provider to the brush.
04677 
04678 ********************************************************************************************/
04679 BOOL ConvertPathToShapesBecomeA::PassBack(NodeRenderableInk* pNewNode,
04680                                           NodeRenderableInk* pCreatedByNode,
04681                                           CCAttrMap* pAttrMap)
04682 {
04683     // continuity checks
04684     if (!pNewNode || !pCreatedByNode)
04685     {
04686         ERROR3("The new node or the created by node is NULL");
04687         return FALSE;
04688     }
04689 
04690     if (!pNewNode->IsNodePath())
04691     {
04692         ERROR3("New node isn't a node path");
04693         return FALSE;
04694     }
04695 
04696 //  if (!GetUndoOp())
04697 //  {
04698 //      ERROR3("No operation defined");
04699 //      return FALSE;
04700 //  }
04701 
04702     // first, if we've not been given an attribute map, then create one
04703     if (!pAttrMap)
04704     {
04705         CCAttrMap * pXMap = CCAttrMap::MakeAppliedAttrMap(pCreatedByNode);
04706         
04707         pAttrMap = pXMap->Copy();
04708 
04709         delete pXMap;
04710 
04711         // exit if we don't have an attribute map
04712         if (!pAttrMap)
04713         {
04714             pNewNode->DeleteChildren(pNewNode->FindFirstChild());
04715             delete pNewNode;
04716             ERROR3("Couldn't create attribute map");
04717             return FALSE;
04718         }
04719     }
04720     NodePath * pPathNode = NULL;
04721     // Pre release bodge - DY 15/11 Brush attributes should really be catered for in MakeNodePathFromAttributes
04722     // but that has too many potential knock-on effects for me to test now
04723     AttrBrushType* pAttrBrush = NULL;
04724     pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrBrushType), (void*&)pAttrBrush);
04725     if (pAttrBrush && pAttrBrush->GetBrushHandle() != BrushHandle_NoBrush)
04726     {
04727         //Turn the brush into a group with lots of nodepaths
04728         BrushBecomeAGroup BecomeA(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), GetUndoOp());
04729         pAttrBrush->DoBecomeA(&BecomeA, pCreatedByNode);
04730         
04731         // the brush will create a group out of itself and we want to retrieve that
04732         NodeGroup* pBrushGroup = BecomeA.GetNodeGroup();
04733         if (pBrushGroup != NULL)
04734         {
04735             if (m_pContextNode == NULL)
04736             {
04737                 m_pContextNode = pBrushGroup;
04738             }
04739             else
04740             {
04741                 // insert as the last sibling
04742                 Node* pNode = m_pContextNode;
04743                 Node* pNext = NULL;
04744                 while (pNode)
04745                 {
04746                     pNext = pNode->FindNext();
04747                     if (pNext == NULL)
04748                         pBrushGroup->AttachNode(pNode, NEXT);
04749                     pNode = pNext;
04750                 }
04751             }
04752         }
04753         else
04754             ERROR3("Failed to create node group!");
04755 
04756         pAttrMap->DeleteAttributes();
04757         delete pAttrMap;
04758         delete pNewNode;
04759         return TRUE;
04760     }
04761 
04762     // likewise if we have an active stroke attribute
04763     AttrStrokeType* pStroke = NULL;
04764     pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrStrokeType), (void*&)pStroke);
04765     AttrVariableWidth* pVarWidth = NULL;
04766     pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrVariableWidth), (void*&)pVarWidth);
04767     
04768     if (pStroke && pStroke->HasPathProcessor() && pVarWidth && pVarWidth->HasActiveValueFunction())
04769     {
04770         PathProcessorStroke* pPPS = pStroke->GetPathProcessor();
04771         Path* pPath = &((NodePath*)pNewNode)->InkPath;
04772         NodePath* pStrokedPath = pPPS->GetSmoothProcessedPath(pPath, pCreatedByNode);
04773 
04774         if (pStrokedPath)
04775         {
04776             // if we don't have a context node then make one
04777             if (m_pContextNode == NULL)
04778             {
04779                 ALLOC_WITH_FAIL(m_pContextNode, new NodeGroup, GetUndoOp());
04780                 if (m_pContextNode == NULL)
04781                 {
04782                     delete pStrokedPath;
04783                     return FALSE;
04784                 }
04785             }
04786 
04787             // Karim 05/12/2000
04788             // process the returned stroke, to change its working
04789             // winding rule from non-zero to even-odd.
04790             Path* pInkStrokePath = &(pStrokedPath->InkPath);
04791             double Flatness = pInkStrokePath->CalculateFlatnessValueFromPath(750.0, 2.0, 375.0);
04792             pInkStrokePath->ClipPathToPath(*pInkStrokePath, pInkStrokePath, 3 | 0x10, 20, Flatness, Flatness);
04793 
04794             // bit of a hack here, but it avoids some code duplication.  Basically OpConvertPathToShapes
04795             // has a really handy function doing all the things you need to do when converting a stroked shape
04796             // to a path, so we're going to assume that our undo op is definitely an OpConvertPathToShapes.
04797             UndoableOperation* pOp = GetUndoOp();
04798             if (pOp == NULL || pOp->IsKindOf(CC_RUNTIME_CLASS(OpConvertPathToShapes)))
04799             {
04800                 OpConvertPathToShapes* pConvert = (OpConvertPathToShapes*)pOp;
04801         
04802                 OpConvertPathToShapes::AdjustStrokeAndFillAttrs(pConvert, pStrokedPath, NULL, pAttrMap);
04803             }
04804             // insert as the last sibling
04805             Node* pNode = m_pContextNode;
04806             Node* pNext = NULL;
04807             while (pNode)
04808             {
04809                 pNext = pNode->FindNext();
04810                 if (pNext == NULL)
04811                     pStrokedPath->AttachNode(pNode, NEXT);
04812                 pNode = pNext;
04813             }
04814             pAttrMap->DeleteAttributes();
04815             delete pAttrMap;
04816             delete pNewNode;
04817             return TRUE;
04818         }
04819     }
04820 
04821 
04822 
04823     // This deals with the case if we have neither a brush or stroke attribute, 
04824     // simply sum the paths.
04825 
04826     double Flatness = ((NodePath *)pNewNode)->InkPath.CalculateFlatnessValueFromPath(750.0, 1.0, 375.0);
04827     pPathNode = ((NodePath *)pNewNode)->MakeNodePathFromAttributes(Flatness, pAttrMap, TRUE);
04828 
04829         // ensure that the path is correct by clipping it
04830     Path BlankPath;
04831     BlankPath.Initialise();
04832     
04833     Path ClipPath;
04834     ClipPath.Initialise();
04835 
04836     // delete the new node
04837     pNewNode->DeleteChildren(pNewNode->FindFirstChild());
04838     delete pNewNode;
04839 
04840     pAttrMap->DeleteAttributes();
04841     delete pAttrMap;
04842 
04843     if (!pPathNode)
04844     {
04845         return FALSE;
04846     }
04847 /*
04848     // smooth the new node's path
04849     double Error = SMOOTH_MIN + (SMOOTH_MAX - SMOOTH_MIN)*pow((35/100), 3.0);
04850 
04851     FitCurveNoChangeGeometry::SmoothPath(&(pPathNode->InkPath), Error);
04852 */  
04853     DocRect dr1(0,0,0,0);
04854     DocRect dr2(0,0,0,0);
04855 
04856     m_SummedPath.GetTrueBoundingRect(&dr1);
04857     pPathNode->InkPath.GetTrueBoundingRect(&dr2);
04858 
04859     // now, let's add this node to the become A path
04860 //  if (m_SummedPath.GetBoundingRect().IsIntersectedWith(pPathNode->InkPath.GetBoundingRect())) MRH 19/5/00
04861     if (dr1.IsIntersectedWith(dr2))
04862     {
04863         Path OrigPath;
04864         OrigPath.Initialise();
04865         OrigPath.CloneFrom(m_SummedPath);
04866         
04867         m_SummedPath.ClearPath();
04868         
04869         OrigPath.ClipPathToPath(pPathNode->InkPath, &m_SummedPath, 7 | CLIPPING_CLIP_WINDING,
04870             50, 50, 50);
04871     }
04872     else
04873     {
04874         m_SummedPath.MergeTwoPaths(pPathNode->InkPath);
04875     }
04876 
04877     delete pPathNode;
04878 
04879     return TRUE;
04880 }
04881 
04882 
04883 /********************************************************************************************
04884 
04885 >   NodeRenderableInk* ConvertPathToShapesBecomeA::GetContextNode()
04886 
04887     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04888     Inputs:     -
04889     Outputs:    The context node that was generated to hold brushes or strokes converted to 
04890                 shapes, or NULL if there isn't one
04891     Created:    10/2/2000
04892     Purpose:    Having potentially converted brushes or strokes to shapes we need to retrieve 
04893                 them.  This can take a couple of forms, depending on what was converted:
04894                 1 brush will return one group containing nodepaths of the brush objects
04895                 >1 brush will return a group, with group children containing the brushes
04896                 1 or more brushes + 1 or more strokes will return a group
04897                 Strokes ONLY - will return a nodepath, which will contain any other strokes
04898                 as its siblings.
04899                 
04900 
04901 ********************************************************************************************/
04902 
04903 NodeRenderableInk* ConvertPathToShapesBecomeA::GetContextNode()
04904 {
04905     if (m_pContextNode == NULL)
04906         return NULL;
04907 
04908     NodeRenderableInk* pRetNode = m_pContextNode;
04909 
04910     // if the context node has no children then we have no brushes, only strokes, so return the first sibling
04911     if (pRetNode->FindFirstChild() == NULL)
04912     {
04913         // we will have inserted any strokes as siblings to the context node
04914         pRetNode = static_cast<NodeRenderableInk*>(pRetNode->FindNext());
04915         if (pRetNode == NULL)
04916         {
04917             ERROR3("Urk, we don't seem to have anything to return in ConvertPathToShapesBecomeA::GetContextNode");
04918         }
04919         // unhook the context node and delete it
04920         m_pContextNode->CascadeDelete();
04921         delete m_pContextNode;
04922     }
04923     m_pContextNode = NULL;
04924     return pRetNode;
04925 }
04926 
04928 // OpToggleContourInsetPath class
04929 
04930 /********************************************************************************************
04931 
04932 >   BOOL OpToggleContourInsetPath::Declare()
04933 
04934     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04935     Created:    10/2/2000
04936     Returns:    TRUE if all went OK, False otherwise
04937     Purpose:    Adds the operation to the list of all known operations
04938 
04939 ********************************************************************************************/
04940 BOOL OpToggleContourInsetPath::Declare()
04941 {
04942     return (RegisterOpDescriptor(
04943                                 0, 
04944                                 _R(IDS_INSETPATHOP),
04945                                 CC_RUNTIME_CLASS(OpToggleContourInsetPath), 
04946                                 OPTOKEN_TOGGLEINSETPATH,
04947                                 OpToggleContourInsetPath::GetState));
04948 
04949 }
04950 
04951 /********************************************************************************************
04952 
04953 >   OpState OpToggleContourInsetPath::GetState(String_256* Description, OpDescriptor*);
04954 
04955     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04956     Created:    10/2/2000
04957     Returns:    TRUE if all went OK, False otherwise
04958     Purpose:    Gets the state of the operation
04959 
04960 ********************************************************************************************/
04961 OpState OpToggleContourInsetPath::GetState(String_256* Description, OpDescriptor*)
04962 {
04963     OpState Blobby;
04964 
04965     // are there any contours in the selection ?
04966     List ContourList;
04967 
04968     BevelTools::BuildListOfSelectedNodes(&ContourList, CC_RUNTIME_CLASS(NodeContour));
04969 
04970     if (ContourList.IsEmpty())
04971     {
04972         Blobby.Greyed = TRUE;
04973     }
04974     else
04975     {
04976         ContourList.DeleteAll();
04977     }
04978     
04979     return Blobby;
04980 }
04981 
04982 /********************************************************************************************
04983 
04984 >   void OpToggleContourInsetPath::Do(OpDescriptor * pDesc, OpParam * pParam)
04985 
04986     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
04987     Created:    10/2/2000
04988     Returns:    
04989     Purpose:    Does the operation
04990 
04991 ********************************************************************************************/
04992 void OpToggleContourInsetPath::DoWithParam(OpDescriptor * pDesc, OpParam * pParam)
04993 {
04994     DoStartSelOp(TRUE, TRUE);
04995 
04996     if (!GetApplication()->FindSelection())
04997     {
04998         End();
04999         return;
05000     }
05001 
05002     BOOL bFlag = FALSE;
05003 
05004     if (pParam->Param1)
05005         bFlag = TRUE;
05006 
05007 //  BOOL ok = TRUE;
05008 
05009     if (bFlag)
05010         m_OpName = _R(IDS_INSETPATH_OP_UNDO_NAME);
05011     else
05012         m_OpName = _R(IDS_INSETPATH_OP_REDO_NAME);
05013 
05014     List ContourList;
05015     BevelTools::BuildListOfSelectedNodes(&ContourList, CC_RUNTIME_CLASS(NodeContourController));
05016 
05017     NodeListItem * pItem = (NodeListItem *)ContourList.GetHead();
05018 
05019 //  ToggleInsetPathAction * pAction = NULL;
05020 
05021     NodeContour * pContour = NULL;
05022     NodeContourController * pController = NULL;
05023     NodeHidden * pHidden = NULL;
05024     Node * pChild = NULL;
05025 //  Node * pNext = NULL;
05026 //  Node * pNodeGroup = NULL;
05027     CCAttrMap AttrMap;
05028 //  NodeContour * pContourCopy = NULL;
05029     BOOL IsAnOuter = TRUE;
05030 
05031     while (pItem)
05032     {
05033         pController = (NodeContourController *)pItem->pNode;
05034         pContour = (NodeContour *)pController->FindFirstChild(CC_RUNTIME_CLASS(NodeContour));
05035         
05036         if (!pController || !pContour)
05037             goto FailExit;
05038 
05039         IsAnOuter = pController->IsContourAnOuterContour();
05040 
05041         if (bFlag)
05042         {
05043             // only swap attributes when you're going from a contour to an inset path node
05044             // now, try to find the first appropriate node to take an attribute map from to
05045             // copy over to the contour node
05046             pChild = pController->FindFirstDepthFirst();
05047             
05048             while (pChild)
05049             {
05050                 if (pChild->IsAnObject() && !pChild->IS_KIND_OF(NodeContour) && !pChild->IsCompound())
05051                 {
05052                     if (((NodeRenderableInk *)pChild)->FindAppliedAttributes(&AttrMap))
05053                     {
05054 /*                      // create a copy of the contour node, and apply this attribute map to it
05055                         pContourCopy = (NodeContour *)pContour->PublicCopy();
05056                         AttrMap.ApplyAttributesToNode(pContourCopy);
05057                         
05058                         // insert this node into the tree after the contour node
05059                         if (!DoInsertNewNode(pContourCopy, pContour, NEXT, TRUE, FALSE, FALSE, TRUE))
05060                         {
05061                             goto FailExit;
05062                         }
05063 
05064                         if (!DoHideNode(pContour, TRUE, &pHidden, TRUE))
05065                             goto FailExit;
05066 */
05067                         // Create and initialize a new NodePath to hold the inset path!
05068                         NodePath* pNewPath;
05069                         ALLOC_WITH_FAIL(pNewPath, new NodePath, this);
05070                         pNewPath->InkPath.Initialise();
05071 
05072                         DoInvalidateNodeRegion(pController,FALSE);
05073 
05074                         // Create the DoBecomeA Function and call it on the controller
05075                         BecomeA BecomeAReplace(BECOMEA_REPLACE, CC_RUNTIME_CLASS(NodePath), this, FALSE);
05076                         pContour->DoBecomeA(&BecomeAReplace);
05077 
05078                         // Now get the relavent path from the group of path nodes
05079                         NodePath* pPathToCopy = NULL;
05080 
05081                         if(IsAnOuter)
05082                             pPathToCopy = (NodePath*)pController->FindFirstChild(CC_RUNTIME_CLASS(NodePath));
05083                         else
05084                             pPathToCopy = (NodePath*)pController->FindLastChild(CC_RUNTIME_CLASS(NodePath));
05085 
05086                         pNewPath->InkPath.CloneFrom(pPathToCopy->InkPath);
05087 
05088                         // now Initialize the flag array with the new Path and insert it after the group node!
05089                         pNewPath->InkPath.InitialiseFlags(0, pNewPath->InkPath.GetNumCoords());
05090                         DoInsertNewNode(pNewPath, pController, NEXT, TRUE, FALSE, TRUE, TRUE);
05091 
05092                         pNewPath->InkPath.IsFilled = TRUE;
05093 
05094                         // Make sure we have the correct attributes applied to our new path and make it selected!
05095                         AttrMap.ApplyAttributesToNode(pNewPath);
05096                         pNewPath->NormaliseAttributes();
05097                         
05098                         pNewPath->SetSelected(TRUE);
05099                         
05100                         DoHideNode(pController, TRUE, &pHidden, TRUE);
05101 
05102                         // ok we're out
05103                         break;
05104                         
05105                     }
05106                 }
05107                 
05108                 pChild = pChild->FindNextDepthFirst(pController);
05109             }
05110         }
05111 /*
05112         if (ToggleInsetPathAction::Init(this, GetUndoActionList(), pController, bFlag,
05113             &pAction) != AC_OK)
05114         {
05115             goto FailExit;
05116         }
05117 
05118         // make sure that the controller node is deselected and the contour node is
05119         pController->SetSelected(FALSE);
05120 
05121         if (pContourCopy)
05122             pContourCopy->SetSelected(TRUE);
05123 
05124         // do a do become a on the controller
05125         BecomeA BecomeAReplace(BECOMEA_REPLACE, CC_RUNTIME_CLASS(NodePath), this, FALSE);
05126         pController->DoBecomeA(&BecomeAReplace);
05127 */      pItem = (NodeListItem *)ContourList.GetNext(pItem);
05128     }
05129 
05130     ContourList.DeleteAll();
05131 
05132     if (GetApplication()->FindSelection())
05133     {
05134         GetApplication()->FindSelection()->Update(TRUE);
05135     }
05136     
05137     End();
05138     return;
05139 
05140 FailExit:
05141     FailAndExecute();
05142     End();
05143 }
05144 
05145 /********************************************************************************************
05146 
05147 >   void OpToggleContourInsetPath::GetOpName(String_256* OpName)
05148 
05149     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
05150     Created:    10/2/2000
05151     Returns:    
05152     Purpose:    Gets the op's name
05153 
05154 ********************************************************************************************/
05155 void OpToggleContourInsetPath::GetOpName(String_256* OpName)
05156 {
05157     if (OpName)
05158     {
05159         OpName->Load(m_OpName);
05160     }
05161 }
05162 
05164 // The ToggleInsetPathAction class
05165 /********************************************************************************************
05166 
05167 >   ToggleInsetPathAction::ToggleInsetPathAction()
05168 
05169     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
05170     Created:    07/01/97
05171     Inputs:     -
05172     Outputs:    -
05173     Returns:    -
05174     Purpose:    Constructor for the action
05175     Errors:     -
05176     SeeAlso:    -
05177 
05178 ********************************************************************************************/
05179 
05180 ToggleInsetPathAction::ToggleInsetPathAction()
05181 {
05182     m_pNode = NULL;
05183 }
05184 
05185 
05186 /********************************************************************************************
05187 
05188 >   ActionCode ToggleInsetPathAction::Init(     Operation*  pOp,
05189                                                 ActionList* pActionList,
05190                                                 NodeContourController * pNode
05191                                                 ChangePositionShadowXAction**   ppNewAction);
05192 
05193     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
05194     Created:    17/3/99
05195     Inputs:     pOp             = ptr to the operation to which this action belongs
05196                 pActionList     =  ptr to action list to which this action should be added
05197                 pNode           = ptr to the node to address
05198     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
05199                                   a pointer to the created action
05200     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
05201     Purpose:    This is the function which creates an instance of this action. If there is no room 
05202                 in the undo buffer (which is determined by the base class Init function called within)
05203                 the function will either return AC_NO_RECORD which means the operation can continue, 
05204                 but no undo information needs to be stored, or AC_OK which means the operation should
05205                 continue AND record undo information. If the function returns AC_FAIL, there was not 
05206                 enough memory to record the undo information, and the user has decided not to continue
05207                 with the operation.
05208     Errors:     -
05209     SeeAlso:    Action::Init()
05210 
05211 ********************************************************************************************/
05212 
05213 
05214 
05215 ActionCode ToggleInsetPathAction::Init(Operation* pOp,
05216                                         ActionList* pActionList,
05217                                         NodeContourController * pNode,
05218                                         BOOL bFlag, 
05219                                         ToggleInsetPathAction** ppNewAction)
05220 {
05221     UINT32 ActSize = sizeof(ToggleInsetPathAction);
05222     
05223     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(ToggleInsetPathAction),(Action**)ppNewAction);
05224 
05225     if (Ac == AC_OK)
05226     {
05227         (*ppNewAction)->m_pNode = pNode;
05228         (*ppNewAction)->m_OldSetting = pNode->GetInsetPathFlag();
05229 
05230         pNode->SetInsetPathFlag(bFlag);
05231 
05232         pNode->RegenerateNode(NULL, FALSE, TRUE);
05233     }
05234 
05235     return Ac;
05236 }
05237 
05238 /********************************************************************************************
05239 
05240 >   ActionCode ToggleInsetPathAction::Execute();
05241 
05242     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
05243     Created:    17/3/99
05244     Inputs:     -
05245     Outputs:    -
05246     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
05247     Purpose:    Executes the action.  Causes a regen of all bevels nodes in the action's list
05248     Errors:     -
05249     SeeAlso:    Action::Init()
05250 
05251 ********************************************************************************************/
05252 
05253 ActionCode ToggleInsetPathAction::Execute()
05254 {
05255     ActionCode Act;
05256     ToggleInsetPathAction* pAction;
05257 
05258     // re-invalidate the old rect
05259     Document * pDoc = Document::GetCurrent();
05260 
05261     if (pDoc)
05262     {
05263         pDoc->ForceRedraw(m_pNode->FindParentSpread(), m_pNode->GetBoundingRect(), FALSE, m_pNode);
05264     }
05265     
05266     Act = ToggleInsetPathAction::Init(  pOperation, 
05267                                         pOppositeActLst,
05268                                         m_pNode,
05269                                         m_OldSetting,
05270                                         &pAction);
05271 
05272     if (Act != AC_FAIL)
05273     {
05274     }
05275 
05276     return Act;
05277 }
05278 
05279 ToggleInsetPathAction::~ToggleInsetPathAction()
05280 {
05281 
05282 }
05283 
05284 
05285 
05286 
05287 
05288 
05289 
05290 
05291 
05292 
05293 
05294 
05295 
05296 
05297 
05298 
05299 
05300 
05301 
05302 
05303 
05304 
05305 
05306 
05307 
05308 
05309 

Generated on Sat Nov 10 03:47:44 2007 for Camelot by  doxygen 1.4.4