pathops.cpp

Go to the documentation of this file.
00001 // $Id: pathops.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // Home of additional path operations - pathedit.cpp is getting too big
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "pathops.h"
00105                                 
00106 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "nodepath.h"                                       
00110 #include "pathedit.h"
00111 #include "objchge.h"
00112 //#include "peter.h"
00113 #include "progress.h"
00114 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 
00116 
00117 DECLARE_SOURCE("$Revision: 1282 $");
00118 
00119 CC_IMPLEMENT_DYNCREATE( OpBaseConvertPathSegment, SelOperation)
00120 CC_IMPLEMENT_DYNCREATE( OpMakeSegmentsCurves, OpBaseConvertPathSegment)
00121 CC_IMPLEMENT_DYNCREATE( OpMakeSegmentsLines, OpBaseConvertPathSegment)
00122 CC_IMPLEMENT_DYNCREATE( OpReversePath, SelOperation)
00123 CC_IMPLEMENT_DYNCREATE( OpMovePathPoint, TransOperation)
00124 CC_IMPLEMENT_DYNCREATE( OpMenuSelectPathPoints, Operation)
00125 CC_IMPLEMENT_DYNCREATE( OpSelectAllPathPoints, OpMenuSelectPathPoints)
00126 CC_IMPLEMENT_DYNCREATE( OpDeSelectAllPathPoints, OpMenuSelectPathPoints)
00127 
00128 CC_IMPLEMENT_DYNAMIC( NewPathCreatedMsg, Msg)
00129 CC_IMPLEMENT_DYNAMIC( PathEditedMsg, Msg)
00130 CC_IMPLEMENT_MEMDUMP( MovePointsParams, OpParam)
00131 
00132 // Declare smart memory handling in Debug builds
00133 #define new CAM_DEBUG_NEW
00134 
00135 
00136 
00137 /********************************************************************************************
00138 >   NewPathCreatedMsg::NewPathCreatedMsg(NodePath* pPath, Operation* CurOp, ActionList* Undos) 
00139 
00140     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00141     Created:    06/12/94
00142     Inputs:     pPath - pointer to the newly created path
00143                 CurOp - pointer to the currently active operation
00144                 Undos - pointer to the operations undo list
00145     Purpose:    initilise a NewPathCreatedMsg
00146     SeeAlso:    NewPathCreatedMsg
00147 ********************************************************************************************/
00148 NewPathCreatedMsg::NewPathCreatedMsg(NodePath* pPath, Operation* CurOp, ActionList* Undos)                          
00149 {                              
00150     CurrentOp = CurOp;
00151     NewPath = pPath;    
00152     UndoActs = Undos;
00153 }
00154 
00155 
00156 
00157 /********************************************************************************************
00158 >   PathEditedMsg::PathEditedMsg(Path* pPath, Spread* pSpread, INT32 Index)
00159 
00160     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00161     Created:    07/12/94
00162     Inputs:     pPath - pointer to the edited path
00163                 pSpread - pointer to the spread containing the path
00164                 Index - the edited endpoint
00165     Purpose:    initilise a PathEditedMsg
00166     SeeAlso:    PathEditedMsg
00167 ********************************************************************************************/
00168 PathEditedMsg::	PathEditedMsg(Path* pPath, Spread* pSpread, INT32 Index)
00169                             
00170 {                              
00171     EditPath = pPath;
00172     EditSpread = pSpread;
00173     EndPoint = Index;
00174 }
00175 
00176 
00177 
00178 /********************************************************************************************
00179 >   OpBaseConvertPathSegment::OpBaseConvertPathSegment() 
00180 
00181     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00182     Created:    16/8/95
00183     Purpose:    OpBaseConvertPathSegment constructor - does nothing itself
00184 ********************************************************************************************/
00185 OpBaseConvertPathSegment::OpBaseConvertPathSegment(): SelOperation()                                
00186 {                              
00187 }
00188 
00189 
00190 
00191 /********************************************************************************************
00192 >   OpState OpBaseConvertPathSegment::BaseGetState(INT32 PathType)
00193 
00194     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00195     Created:    16/8/95
00196     Inputs:     Type of the path that ends a segment
00197     Returns:    The tick/grey state of OpBaseConvertPathSegment and derived classes
00198     Purpose:    For finding the state of this op
00199     SeeAlso:    OpState
00200 ********************************************************************************************/
00201 OpState OpBaseConvertPathSegment::BaseGetState(INT32 PathType)
00202 {
00203     OpState OpSt;
00204 
00205 #ifndef STANDALONE
00206 
00207     SelRange*   Selected = GetApplication()->FindSelection();
00208 
00209     if ((Document::GetSelected() == NULL) || (Selected == NULL) )
00210     {   // There is no selected document or selrange is invalid
00211         OpSt.Greyed = TRUE;
00212         return OpSt;                                 
00213     }
00214 
00215     Node*   pNode = Selected->FindFirst();
00216     BOOL    FoundSegment = FALSE;
00217     BOOL    AllConverted = TRUE;
00218     BOOL    PrevSelected = FALSE;
00219 
00220     while ((pNode != NULL) && AllConverted)
00221     {
00222         if (pNode->IsNodePath() && ((NodePath*)pNode)->IsPathAllowable())
00223         {
00224             Path* ThisPath = &(((NodePath*)pNode)->InkPath);
00225             PathFlags* Flags = ThisPath->GetFlagArray();
00226             PathVerb* Verbs = ThisPath->GetVerbArray();
00227             INT32 UsedSlots = ThisPath->GetNumCoords();
00228             PrevSelected = FALSE;
00229 
00230             for (INT32 i=0; i<UsedSlots; i++)
00231             {
00232                 if (Flags[i].IsEndPoint)
00233                 {
00234                     if (Flags[i].IsSelected)
00235                     {
00236                         if (PrevSelected && ((Verbs[i] & ~PT_CLOSEFIGURE) != PT_MOVETO) )
00237                         {
00238                             FoundSegment = TRUE;
00239                             if ((Verbs[i] & ~PT_CLOSEFIGURE) != PathType)
00240                                 AllConverted = FALSE;
00241                         }
00242                         PrevSelected = TRUE;
00243                     }
00244                     else                            
00245                     {
00246                         PrevSelected = FALSE;
00247                     }
00248                 }
00249             }
00250         }
00251         pNode = Selected->FindNext(pNode);
00252     }
00253 
00254     OpSt.Greyed = !FoundSegment;
00255     OpSt.Ticked = AllConverted && FoundSegment;
00256 
00257 #endif  // #ifdef STANDALONE
00258 
00259     return OpSt;
00260 }
00261 
00262 
00263 
00264 /********************************************************************************************
00265 >   void OpBaseConvertPathSegment::Do(OpDescriptor*)
00266 
00267     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00268     Created:    16/8/95
00269     Inputs:     OpDescriptor (unused)
00270     Purpose:    Performs the common SelRange scanning part of converting path segments.  Calls
00271                 the ProcessSegment function in derived classes to do the actual processing
00272     Errors:     -
00273     SeeAlso:    -
00274 ********************************************************************************************/
00275 void OpBaseConvertPathSegment::Do(OpDescriptor*)
00276 {   
00277 #ifndef STANDALONE
00278 
00279     // Obtain the current selections and the first node in the selection
00280     SelRange* Selected = GetApplication()->FindSelection();
00281     BOOL ok = (Selected != NULL);
00282 
00283     // Start the op
00284     BeginSlowJob();
00285     if (ok)
00286         ok = DoStartSelOp(TRUE,TRUE);
00287 
00288     // Check with the selrange it is ok to run this op
00289     ObjChangeFlags cFlags;
00290     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
00291     if (ok)
00292     {
00293         if (!Selected->AllowOp(&ObjChange))
00294         {
00295             EndSlowJob();
00296             FailAndExecute();
00297             End();
00298             return;
00299         }
00300     }
00301 
00302     Node* pNode = Selected->FindFirst();
00303     NodePath* ThisPath = NULL;
00304 
00305     while (ok && (pNode != NULL))
00306     {   // we're only interested in NodePaths which have selected points
00307         BOOL DoThisNode = pNode->IsNodePath();
00308         if (DoThisNode)
00309             DoThisNode = (((NodePath*)pNode)->InkPath.IsSubSelection());
00310         if (DoThisNode)
00311             DoThisNode = (((NodePath*)pNode)->IsPathAllowable());
00312 
00313         if  ( DoThisNode )
00314         {
00315             // for convenience, cast the pointer to a pointer to a NodePath
00316             ThisPath = (NodePath*)pNode;
00317 
00318             // First get pointers to the arrays
00319             PathVerb* Verbs = NULL;
00320             PathFlags* Flags = NULL;
00321             DocCoord* Coords = NULL;
00322             ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
00323             INT32 NumCoords = ThisPath->InkPath.GetNumCoords();
00324             BOOL PrevSelected = FALSE;
00325             INT32 PrevPos = 0;
00326 
00327             // Set the NeedToRender flags
00328             INT32       loop;
00329             for (loop = 0; loop < NumCoords; loop++)
00330             {
00331                 if (Flags[loop].IsEndPoint && Flags[loop].IsSelected)
00332                     Flags[loop].NeedToRender = TRUE;
00333                 else
00334                     Flags[loop].NeedToRender = FALSE;
00335             }
00336 
00337             // Force a re-draw of the place where the path used to be
00338             if (ok)
00339                 ok = (RecalcBoundsAction::DoRecalc(this, &UndoActions, ThisPath, TRUE) != AC_FAIL);
00340 
00341             // loop through the points
00342             for (loop = 0; loop<NumCoords; loop++)
00343             {
00344                 if (Flags[loop].IsEndPoint)
00345                 {   // its an endpoint
00346                     if (Flags[loop].IsSelected)
00347                     {   // which is selected
00348                         if (PrevSelected && ((Verbs[loop] & ~PT_CLOSEFIGURE) == GetProcessPathType()) )
00349                         {   //  and the previous was selected and it's a processable segment
00350                             if (ok)
00351                                 ok = ProcessSegment(ThisPath, &loop, PrevPos);
00352                             // Recache array pointers
00353                             ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
00354                             NumCoords = ThisPath->InkPath.GetNumCoords();
00355                             Flags[loop].NeedToRender = TRUE;
00356                         }
00357                         PrevSelected = TRUE;
00358                         PrevPos = loop;
00359                     }
00360                     else
00361                         PrevSelected = FALSE;
00362                 }
00363             }
00364 
00365             // Having finished processing this path go round and smooth it.
00366             DocCoord NewCoord;
00367             for (loop = 0; (ok && (loop < NumCoords)); loop++)
00368             {
00369                 if (Verbs[loop] == PT_BEZIERTO && !(Flags[loop].IsEndPoint) && Flags[loop].IsSmooth)
00370                 {
00371                     NewCoord = ThisPath->InkPath.SmoothControlPoint(loop);
00372                     if (ok && (NewCoord != Coords[loop]))
00373                     {
00374                         ok = DoAlterPathElement(ThisPath, loop, NewCoord, Flags[loop], Verbs[loop], FALSE);
00375                         ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
00376                     }
00377                 }
00378             }
00379 
00380             ThisPath->InvalidateBoundingRect();
00381 
00382             // Force a redraw of the place where the path is now.
00383             if (ok)
00384                 ok = (RecordBoundsAction::DoRecord(this, &UndoActions, ThisPath, TRUE) != AC_FAIL);
00385         }
00386         pNode = Selected->FindNext(pNode);
00387     }
00388 
00389     if (ok)
00390     {
00391         ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
00392         if (!UpdateChangedNodes(&ObjChange))
00393         {
00394             FailAndExecute();
00395             End();
00396             return;
00397         }
00398     }
00399 
00400     EndSlowJob();
00401 
00402     if (!ok)
00403     {   
00404         FailAndExecute();
00405         InformError();
00406     }
00407 
00408 #endif
00409 
00410     End();
00411 }
00412 
00413 
00414 
00415 /********************************************************************************************
00416 
00417 >   OpMakeSegmentsLines::OpMakeSegmentsLines() 
00418 
00419     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00420     Created:    30/9/94
00421     Purpose:    OpMakeSegmentsLines constructor - does nothing itself
00422 
00423 ********************************************************************************************/
00424 OpMakeSegmentsLines::OpMakeSegmentsLines()
00425 {                              
00426 }
00427 
00428 
00429 
00430  /********************************************************************************************
00431 
00432 >   BOOL OpMakeSegmentsLines::Init()
00433 
00434     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00435     Created:    30/9/94
00436     Returns:    TRUE if the operation could be successfully initialised 
00437                 FALSE if no more memory could be allocated 
00438     Purpose:    OpMakeSegmentsLines initialiser method
00439     Errors:     ERROR will be called if there was insufficient memory to allocate the 
00440                 operation.
00441     SeeAlso:    -
00442 
00443 ********************************************************************************************/
00444 BOOL OpMakeSegmentsLines::Init()
00445 {
00446     return (RegisterOpDescriptor(   0, 
00447                                     _R(IDS_MAKELINES),
00448                                     CC_RUNTIME_CLASS(OpMakeSegmentsLines), 
00449                                     OPTOKEN_MAKELINESOP,
00450                                     OpMakeSegmentsLines::GetState,
00451                                     0,  /* help ID */
00452                                     _R(IDBBL_MAKELINES),
00453                                     0   /* bitmap ID */));
00454 }               
00455 
00456 
00457 
00458 OpState OpMakeSegmentsLines::GetState(String_256*, OpDescriptor*)
00459 {
00460     return OpBaseConvertPathSegment::BaseGetState(PT_LINETO);
00461 }
00462 
00463 
00464 
00465 /********************************************************************************************
00466 >   BOOL OpMakeSegmentsLines::ProcessSegment(NodePath* pPath, INT32* Index, INT32 PrevIndex)
00467 
00468     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00469     Created:    16/8/95
00470     Inputs:     pPath - points to the path to process
00471                 Index - index of the PT_BEZIERTO segment to change into lines
00472                 PrevIndex - index of the previois endpoint (other end of the segment to process)
00473     Outputs:    Index is changed to point to the new index of the end of the segment
00474     Returns:    TRUE/FALSE for success/failure
00475     Purpose:    Performs the make selected segments into lines operation. 
00476     Errors:     -
00477     SeeAlso:    OpBaseConvertPathSegment::Do
00478 ********************************************************************************************/
00479 BOOL OpMakeSegmentsLines::ProcessSegment(NodePath* pPath, INT32* Index, INT32 PrevIndex)
00480 {
00481     // Get the path pointers
00482     PathVerb* Verbs;
00483     PathFlags* Flags;
00484     DocCoord* Coords;
00485     pPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
00486 
00487     // Quick check
00488     ERROR2IF(((Verbs[*Index] & ~PT_CLOSEFIGURE) != PT_BEZIERTO), FALSE, "Unknown segment encountered");
00489     ERROR2IF(((PrevIndex+3) != *Index), FALSE, "Not two points between segment start and end");
00490 
00491 //  BOOL ok = TRUE;
00492 
00493     DocCoord EndCoord = Coords[*Index];
00494     PathFlags EndFlags = Flags[*Index];
00495     PathVerb NewEndVerb = Verbs[*Index];
00496     NewEndVerb = (NewEndVerb == PT_BEZIERTO) ? PT_LINETO : PT_LINETO | PT_CLOSEFIGURE;
00497 
00498     BOOL DoneOK = TRUE;
00499 
00500     // Insert a line segment
00501     if (DoneOK)
00502         DoneOK = DoInsertPathElement(pPath, PrevIndex, EndCoord, EndFlags, NewEndVerb, FALSE);
00503 
00504     // Remove the curve segment
00505     if (DoneOK)
00506         DoneOK = DoDeletePathSection(pPath, PrevIndex+2, 3, FALSE);
00507 
00508     *Index = PrevIndex+1;
00509 
00510     return DoneOK;
00511 }
00512 
00513 
00514 
00515 /********************************************************************************************
00516 
00517 >   OpMakeSegmentsCurves::OpMakeSegmentsCurves() 
00518 
00519     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00520     Created:    30/9/94
00521     Purpose:    OpMakeSegmentsCurves constructor - does nothing itself
00522 
00523 ********************************************************************************************/
00524 OpMakeSegmentsCurves::OpMakeSegmentsCurves()
00525 {                              
00526 }
00527 
00528 
00529 
00530 /********************************************************************************************
00531 
00532 >   BOOL OpMakeSegmentsCurves::Init()
00533 
00534     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00535     Created:    30/9/94
00536     Returns:    TRUE if the operation could be successfully initialised 
00537                 FALSE if no more memory could be allocated 
00538     Purpose:    OpMakeSegmentsCurves initialiser method.
00539     Errors:     ERROR will be called if there was insufficient memory to allocate the 
00540                 operation.
00541     SeeAlso:    -
00542 
00543 ********************************************************************************************/
00544 BOOL OpMakeSegmentsCurves::Init()
00545 {
00546     return (RegisterOpDescriptor(   0, 
00547                                     _R(IDS_MAKECURVES),
00548                                     CC_RUNTIME_CLASS(OpMakeSegmentsCurves), 
00549                                     OPTOKEN_MAKECURVESOP,
00550                                     OpMakeSegmentsCurves::GetState,
00551                                     0,  /* help ID */
00552                                     _R(IDBBL_MAKELINES),
00553                                     0   /* bitmap ID */));
00554 }               
00555 
00556 
00557 
00558 OpState OpMakeSegmentsCurves::GetState(String_256*, OpDescriptor*)
00559 {
00560       return OpBaseConvertPathSegment::BaseGetState(PT_BEZIERTO);
00561 }
00562     
00563 
00564 
00565 /********************************************************************************************
00566 >   BOOL OpMakeSegmentsCurves::ProcessSegment(NodePath* pPath, INT32* Index, INT32 PrevIndex)
00567 
00568     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00569     Created:    16/8/95
00570     Inputs:     pPath - points to the path to process
00571                 Index - index of the PT_LINETO segment to change into lines
00572                 PrevIndex - index of the previous endpoint (other end of the segment to process)
00573     Outputs:    Index is changed to point to the new index of the end of the segment
00574     Returns:    TRUE/FALSE for success/failure
00575     Purpose:    Performs the make selected segments into lines operation. 
00576     Errors:     -
00577     SeeAlso:    OpBaseConvertPathSegment::Do
00578 ********************************************************************************************/
00579 BOOL OpMakeSegmentsCurves::ProcessSegment(NodePath* pPath, INT32* Index, INT32 PrevIndex)
00580 {
00581     // Get the path pointers
00582     PathVerb* Verbs;
00583     PathFlags* Flags;
00584     DocCoord* Coords;
00585     pPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
00586 
00587     // Quick check
00588     ERROR2IF(((Verbs[*Index] & ~PT_CLOSEFIGURE) != PT_LINETO), FALSE, "Unknown segment encountered");
00589     ERROR2IF(((PrevIndex+1) != *Index), FALSE, "Points between segment start and end");
00590 
00591     BOOL ok = CarryOut(*Index, PrevIndex, pPath, this, &UndoActions);
00592     *Index = PrevIndex + 3;
00593 
00594     return ok;
00595 }
00596 
00597 
00598 
00599 /********************************************************************************************
00600 
00601 >   static BOOL OpMakeSegmentsCurves::CarryOut(INT32 Count, INT32 PrevPos, NodePath* ThisPath, 
00602                                                 UndoableOperation* pOp, ActionList* pActions)
00603     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00604     Created:    05/10/94
00605     Inputs:     Count - pointer to the index of the PT_LINETO endpoint
00606                 PrevPos - pointer to the index of the previous endpoint
00607                 ThisPath - pointer to the path with the segment to alter
00608                 pOP - pointer to the operation to attach the actions to
00609                 pActions - points to the action list of the operation
00610     Returns:    TRUE if sucessful, FALSE if any of the actions failed
00611     Purpose:    Performs the actions of the make selected segments into lines operation. 
00612     Errors:     Checks the pointers passed for NULL
00613                 Checks the path is valid before altering it
00614     SeeAlso:    OpMakeSegmentsCurves::Do
00615 
00616 ********************************************************************************************/
00617 
00618 BOOL OpMakeSegmentsCurves::CarryOut(INT32 Count, INT32 PrevPos, NodePath* ThisPath, 
00619                                         UndoableOperation* pOp, ActionList* pActions)
00620 {
00621 #ifndef STANDALONE
00622 
00623     ERROR2IF(pOp == NULL,FALSE, "Operation pointer was NULL");
00624     ERROR2IF(ThisPath == NULL,FALSE, "Path pointer was NULL");
00625 
00626     DocCoord* Coords = ThisPath->InkPath.GetCoordArray();
00627 //  PathFlags* Flags = ThisPath->InkPath.GetFlagArray();
00628     PathVerb* Verbs = ThisPath->InkPath.GetVerbArray();
00629 
00630     DocCoord    First;
00631     DocCoord    Second;
00632     PathFlags   NewFlags;
00633     NewFlags.IsEndPoint = FALSE; 
00634     NewFlags.NeedToRender = FALSE; 
00635     NewFlags.IsSelected = TRUE;
00636     NewFlags.IsSmooth = TRUE;
00637     NewFlags.IsRotate = TRUE;
00638 
00639 //  By default position the control points one-third of the way along the line between the
00640 //  first and second endpoints (changing the line into an identical line).  At the end of the 
00641 //  make curves operation we can go round and smooth the entire path.
00642     First.x = Coords[PrevPos].x-(Coords[PrevPos].x-Coords[Count].x)/3;    
00643     First.y = Coords[PrevPos].y-(Coords[PrevPos].y-Coords[Count].y)/3;
00644     Second.x = Coords[PrevPos].x-((Coords[PrevPos].x-Coords[Count].x)/3)*2;   
00645     Second.y = Coords[PrevPos].y-((Coords[PrevPos].y-Coords[Count].y)/3)*2;
00646 
00647     PathVerb EndVerb = Verbs[Count];
00648     DocCoord EndCoord = Coords[Count];
00649 
00650     ERROR2IF((EndVerb & ~PT_CLOSEFIGURE) != PT_LINETO, FALSE, "Attempt to convert a non-line to a curve!");
00651 
00652     EndVerb = ((EndVerb & PT_CLOSEFIGURE) | PT_BEZIERTO) ;
00653 
00654     // After any of these actions the path must be OK.  
00655     BOOL DoneOK  = TRUE;
00656 
00657     // Insert a curve into the path
00658     if (DoneOK)
00659     {
00660         if ((PrevPos+2) >= ThisPath->InkPath.GetNumCoords())
00661         {
00662             DoneOK = ThisPath->InkPath.AddCurveTo(First, Second, EndCoord, &NewFlags);
00663         }
00664         else
00665         {
00666             ThisPath->InkPath.SetPathPosition(PrevPos+2);
00667             DoneOK = ThisPath->InkPath.InsertCurveTo(First, Second, EndCoord, &NewFlags);
00668         }
00669     }
00670 
00671     // Correct the end verb
00672     if (DoneOK)
00673     {
00674         Verbs = ThisPath->InkPath.GetVerbArray();
00675         Verbs[PrevPos+4] = EndVerb;
00676     }
00677 
00678     // Now insert an action to remove the curve
00679     if (DoneOK)
00680     {
00681         Action* UnAction;           
00682         ActionCode Act;             
00683         Act = RemovePathElementAction::Init(pOp, pActions, 3, PrevPos+2, (Action**)(&UnAction));
00684         if (Act == AC_OK)
00685             ((RemovePathElementAction*)UnAction)->RecordPath(ThisPath);
00686         DoneOK = !(Act == AC_FAIL);
00687     }
00688 
00689     // Finally delete the line
00690     if (DoneOK)
00691         DoneOK = pOp->DoDeletePathSection(ThisPath, PrevPos+1, 1, FALSE);
00692 
00693     return DoneOK;
00694 
00695 #else
00696     return TRUE;
00697 #endif
00698 }
00699 
00700 
00701 
00702 /********************************************************************************************
00703 
00704 >   OpMovePathPoint::OpMovePathPoint() 
00705 
00706     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00707     Created:    18/10/94
00708     Purpose:    OpMovePathPoint constructor - does nothing itself
00709 
00710 ********************************************************************************************/
00711 OpMovePathPoint::OpMovePathPoint(): TransOperation()                                
00712 {                              
00713 }
00714 
00715 
00716 
00717  /********************************************************************************************
00718 
00719 >   BOOL OpMovePathPoint::Init()
00720 
00721     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00722     Created:    17/10/94
00723     Returns:    TRUE if the operation could be successfully initialised 
00724                 FALSE if no more memory could be allocated 
00725     Purpose:    OpMovePathPoint initialiser method.
00726     Errors:     ERROR will be called if there was insufficient memory to allocate the 
00727                 operation.
00728     SeeAlso:    -
00729 
00730 ********************************************************************************************/
00731 BOOL OpMovePathPoint::Init()
00732 {
00733     return (RegisterOpDescriptor(   0, 
00734                                     _R(IDS_MOVEPATHPOINT),
00735                                     CC_RUNTIME_CLASS(OpMovePathPoint), 
00736                                     OPTOKEN_MOVEPATHPOINT,
00737                                     OpMovePathPoint::GetState,
00738                                     0,  /* help ID */
00739                                     _R(IDBBL_MOVEPATHPOINT),
00740                                     0   /* bitmap ID */));
00741 }               
00742     
00743 
00744 
00745 /********************************************************************************************
00746 
00747 >   OpState OpMovePathPoint::GetState(String_256*, OpDescriptor*)
00748 
00749     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00750     Created:    17/10/94
00751     Returns:    The state of the OpMovePathPoint - always available
00752     Purpose:    For finding the OpCyclePathSelectionFoward's state.  
00753 
00754 ********************************************************************************************/
00755 OpState OpMovePathPoint::GetState(String_256* UIDescription, OpDescriptor* fred)
00756 {
00757     OpState OpSt;
00758 
00759     return(OpSt);   
00760 }
00761 
00762 
00763 
00764 /********************************************************************************************
00765 
00766 >   void OpMovePathPoint::DoWithParam(OpDescriptor*, OpParam* Params)
00767 
00768     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00769     Created:    1/11/94
00770     Inputs:     OpDescriptor (unused)
00771                 Params - pointer to the OpParam block (should be a MovePointsParams object)
00772     Purpose:    An operation to position elements in a path (in an undoable kind of way).
00773     Errors:     if Params contains a NULL pointer to a path.
00774                 if Params contains a NULL pointer to the changes data.
00775 
00776 ********************************************************************************************/
00777 void OpMovePathPoint::DoWithParam(OpDescriptor* Fred, OpParam* Params)
00778 {
00779     // Cast parameter block to our type
00780     MovePointsParams*   MyParams = (MovePointsParams*)Params;
00781 
00782     ERROR3IF(MyParams == NULL, "Parameter block pointer was NULL");
00783     ERROR3IF(MyParams->ChangesCount == 0, "No elements to alter!");
00784     ERROR3IF(MyParams->PathChanges == NULL, "No changes data supplied (NULL pointer passed)");
00785     ERROR3IF(MyParams->PathToEdit == NULL, "No changes path supplied (NULL pointer passed)");
00786 
00787     // Do the above tests again for the retail build
00788     if ( (MyParams == NULL) || (MyParams->ChangesCount == 0) || (MyParams->PathChanges == NULL)
00789                                                                 || (MyParams->PathToEdit == NULL) )
00790     {
00791         End();
00792         return;
00793     }
00794 
00795     // Get pointers to the path data.
00796     PathFlags*  Flags = MyParams->PathToEdit->InkPath.GetFlagArray();
00797     PathVerb*   Verbs = MyParams->PathToEdit->InkPath.GetVerbArray();
00798     DocCoord*   Coords= MyParams->PathToEdit->InkPath.GetCoordArray();
00799     INT32       NumElements = MyParams->PathToEdit->InkPath.GetNumCoords();
00800     BOOL        NotFailed = TRUE;
00801 
00802     // Tell the operation system to start.
00803     if (!DoStartTransOp(FALSE,MyParams->PathToEdit))
00804     {
00805         FailAndExecute();
00806         End();                              
00807         return;
00808     }
00809 
00810     for (INT32 Loop = 0; (Loop < MyParams->ChangesCount) && NotFailed; Loop++)
00811     {
00812         // Get the index of the point to edit
00813         INT32 Index = MyParams->PathChanges[Loop].Element;
00814         DocCoord NewCoord = MyParams->PathChanges[Loop].Coordinate;
00815 
00816         ERROR3IF(((Index >= NumElements) || (Index < 0)), "Invalid index into path (either -ve or off end of path)");
00817         if ((Index >= NumElements) || (Index < 0))
00818         {
00819             FailAndExecute();
00820             End();                              
00821             return;
00822         }
00823 
00824         // Find the start and end of the subpath containing index
00825         INT32 EndOfSubPathIndex = Index;
00826         MyParams->PathToEdit->InkPath.FindEndElOfSubPath(&EndOfSubPathIndex);
00827         INT32 StartOfSubPathIndex = EndOfSubPathIndex;
00828         while ((Verbs[StartOfSubPathIndex] != PT_MOVETO) && (StartOfSubPathIndex > 0))
00829             StartOfSubPathIndex--;
00830         BOOL IsSubPathClosed = (Verbs[EndOfSubPathIndex] & PT_CLOSEFIGURE);
00831 
00832         // Move the point to the required coordinate
00833         NotFailed = DoAlterPathElement(MyParams->PathToEdit, Index, NewCoord, Flags[Index], Verbs[Index]);
00834     
00835         // If we have just moved one endpoint of a closed path we will have to move the
00836         // other point too!
00837         if ( NotFailed && IsSubPathClosed )
00838         {
00839             if (Index == EndOfSubPathIndex)
00840             {
00841                 NotFailed = DoAlterPathElement(MyParams->PathToEdit, StartOfSubPathIndex, NewCoord,
00842                                                 Flags[StartOfSubPathIndex], Verbs[StartOfSubPathIndex]);
00843             }
00844             if (Index == StartOfSubPathIndex)
00845             {
00846                 NotFailed = DoAlterPathElement(MyParams->PathToEdit, EndOfSubPathIndex, NewCoord,
00847                                                     Flags[EndOfSubPathIndex], Verbs[EndOfSubPathIndex]);
00848             }
00849         }
00850 
00851         // Now if we have just moved a Bezier control point then we need to clear the
00852         // smooth and rotate flags from the associated endpoint.  We are lucky in that a 
00853         // control point's endpoint is at either +1 or -1 elements away from the control point.
00854         if (NotFailed && ( (Verbs[Index] == PT_BEZIERTO) && !Flags[Index].IsEndPoint) )
00855         {
00856             INT32 BezEndpoint = -1;
00857 
00858             if ((Verbs[Index+1] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
00859                 BezEndpoint = Index + 1;
00860             else
00861             {
00862                 ERROR3IF(((Verbs[Index-1] & ~PT_CLOSEFIGURE) != PT_BEZIERTO),"Invalid path detected");
00863                 if ((Verbs[Index-1] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
00864                     BezEndpoint = Index - 1;
00865                 else
00866                     NotFailed = FALSE;
00867             }
00868 
00869             // Having found the endpoint attack its flags.
00870             if (NotFailed)
00871             {
00872                 NotFailed = ClearSmoothAndRotate(MyParams->PathToEdit,BezEndpoint);
00873             }
00874 
00875             // And the other control point if this is a closed path
00876             if (NotFailed && IsSubPathClosed)
00877             {
00878                 if ( (Index == EndOfSubPathIndex-1) || (Index == EndOfSubPathIndex+1) )
00879                     NotFailed = ClearSmoothAndRotate(MyParams->PathToEdit,StartOfSubPathIndex);
00880                 if ( (Index == StartOfSubPathIndex-1) || (Index == StartOfSubPathIndex+1) )
00881                     NotFailed = ClearSmoothAndRotate(MyParams->PathToEdit,EndOfSubPathIndex);
00882             }
00883 
00884             // Clear them from the moved control point
00885             if (NotFailed)
00886             {
00887                 NotFailed = ClearSmoothAndRotate(MyParams->PathToEdit,Index);
00888             }
00889 
00890             // Also clear the flags from the opposite control point
00891             if (NotFailed)
00892             {
00893                 INT32 OtherControlPoint = MyParams->PathToEdit->InkPath.FindOppositeControlPoint(Index);
00894                 if (OtherControlPoint != -1)
00895                 {
00896                     NotFailed = ClearSmoothAndRotate(MyParams->PathToEdit,OtherControlPoint);
00897                 }
00898             }
00899         }
00900     }
00901 
00902     // Now run along the path and smooth it.
00903     if (NotFailed)
00904     {
00905         DocCoord NewCoord;
00906         for (INT32 i = 0; (i < NumElements) && NotFailed; i++)
00907         {
00908             if (Verbs[i] == PT_BEZIERTO && !(Flags[i].IsEndPoint) && Flags[i].IsSmooth)
00909             {
00910                 NewCoord = MyParams->PathToEdit->InkPath.SmoothControlPoint(i);
00911                 if (NewCoord != Coords[i])
00912                     NotFailed = DoAlterPathElement(MyParams->PathToEdit, i, NewCoord, Flags[i], Verbs[i]);
00913             }
00914         }
00915     }
00916 
00917     if (NotFailed)
00918         GetApplication()->FindSelection()->UpdateBounds();
00919 
00920     if (!NotFailed)
00921     {
00922         InformError();
00923         FailAndExecute();
00924     }
00925 
00926     End();
00927 }
00928 
00929 
00930 
00931 /********************************************************************************************
00932 
00933 >   BOOL OpMovePathPoint::ClearSmoothAndRotate(NodePath* pPath, INT32 PathIndex)
00934 
00935     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00936     Created:    06/04/95
00937     Inputs:     pPath - points to the path to edit
00938                 PathIndex - the index of the path element to clear the flags 
00939     Outputs:    -
00940     Returns:    TRUE/FALSE for success/failure
00941     Purpose:    This function calls DoAlterPathElement to clear the Smooth and Rotate flags
00942                 from the specified path endpoint
00943     Errors:     UndoableOperation::DoAlterPathElement
00944 
00945 ********************************************************************************************/
00946 
00947 BOOL OpMovePathPoint::ClearSmoothAndRotate(NodePath* pPath, INT32 PathIndex)
00948 {
00949     PathFlags*  Flags = pPath->InkPath.GetFlagArray();
00950     PathVerb*   Verbs = pPath->InkPath.GetVerbArray();
00951     DocCoord*   Coords= pPath->InkPath.GetCoordArray();
00952 
00953     PathFlags tFlags = Flags[PathIndex];
00954     tFlags.IsSmooth = FALSE;
00955     tFlags.IsRotate = FALSE;
00956     return DoAlterPathElement(pPath, PathIndex, Coords[PathIndex], tFlags, Verbs[PathIndex]);
00957 }
00958 
00959 
00960 /********************************************************************************************
00961 
00962 >   MovePointsParams::MovePointsParams(NodePath* pPath, ElementCoord* ChangeData, INT32 NumChanges)
00963 
00964     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00965     Created:    7/11/94
00966     Inputs:     pPath - Pointer to a path
00967                 ChangeData - pointer to a block describing changes to be made to the path.
00968                 NumChanges - the number of change data items in the change block
00969     Purpose:    Constructor for the parameter class to be passed to OpMovePathPoint::DoWithParam
00970     SeeAlso:    OpMovePathPoint::DoWithParam
00971     Errors:     
00972 
00973 ********************************************************************************************/
00974 MovePointsParams::MovePointsParams(NodePath* pPath, ElementCoord* ChangeData, INT32 NumChanges) : OpParam( INT32(0), INT32(0) ) \
00975 { 
00976     PathToEdit = pPath;
00977     PathChanges = ChangeData;
00978     ChangesCount = NumChanges;
00979 };
00980 
00981 
00982 
00984 // OpSelectPathPoints
00985 
00986 
00987 /********************************************************************************************
00988 >   static BOOL OpMenuSelectPathPoints::Init()
00989 
00990     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00991     Created:    30/04/95
00992     Inputs:     -
00993     Outputs:    -
00994     Returns:    TRUE/FALSE for success/failure
00995     Purpose:    Initialises the two path select points operations
00996     SeeAlso:    OpSelectAllPathPoints, OpDeSelectAllPathPoints
00997 ********************************************************************************************/
00998 BOOL OpMenuSelectPathPoints::Init() 
00999 {
01000     BOOL ok = RegisterOpDescriptor( 0, 
01001                                     _R(IDS_SELECTALLPATHPOINTS),
01002                                     CC_RUNTIME_CLASS(OpSelectAllPathPoints), 
01003                                     OPTOKEN_SELECTALLPATHPOINTS,
01004                                     OpMenuSelectPathPoints::GetState);
01005 
01006     if (ok)
01007         ok = RegisterOpDescriptor(  0, 
01008                                     _R(IDS_DESELECTALLPATHPOINTS),
01009                                     CC_RUNTIME_CLASS(OpDeSelectAllPathPoints), 
01010                                     OPTOKEN_DESELECTALLPATHPOINTS,
01011                                     OpMenuSelectPathPoints::GetState);
01012 
01013     return ok;
01014 }
01015 
01016 
01017 
01018 /********************************************************************************************
01019 >   static OpState OpMenuSelectPathPoints::GetState(String_256*, OpDescriptor*)
01020 
01021     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01022     Created:    30/04/95
01023     Inputs:     (Unused)
01024     Outputs:    -
01025     Returns:    The state of the operation
01026     Purpose:    For getting the start of the operation
01027     SeeAlso:    -
01028 ********************************************************************************************/
01029 OpState OpMenuSelectPathPoints::GetState(String_256*, OpDescriptor*)
01030 {
01031     OpState Banana;
01032 
01033     return Banana;      // Mmmm.... Banana.....
01034 }
01035 
01036 
01037 
01038 /********************************************************************************************
01039 >   BOOL OpMenuSelectPathPoints::DoAction(BOOL SelectPoints)
01040 
01041     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01042     Created:    30/04/95
01043     Inputs:     SelectPoints - TRUE to select all the points in the path
01044                              - FALSE to deslect all the points in the path
01045     Outputs:    -
01046     Returns:    TRUE/FALSE for success/failure          
01047     Purpose:    Common code for selecting or deselecting all the points in all the selected
01048                 paths.
01049     SeeAlso:    -
01050 ********************************************************************************************/
01051 BOOL OpMenuSelectPathPoints::DoAction(BOOL SelectPoints)
01052 {
01053     SelRange* pSelection = GetApplication()->FindSelection();
01054     Node* pNode = pSelection->FindFirst();
01055 
01056     // Cycle through all the selected paths
01057     while (pNode != NULL)
01058     {
01059         if (pNode->IsNodePath())
01060         {
01061             NodePath* pPath = (NodePath*)pNode;
01062             Spread* pSpread = pNode->FindParentSpread();
01063             ERROR2IF(pSpread == NULL, FALSE, "NodePath didn't have a parent spread");
01064 
01065             // Remove the blobs from the path
01066             RenderRegion* pRegion = DocView::RenderOnTop(NULL, pSpread, ClippedEOR);
01067             while (pRegion != NULL)
01068             {
01069                 pPath->RenderObjectBlobs(pRegion);
01070                 pRegion = DocView::GetNextOnTop(NULL);
01071             }
01072             
01073             // Set the selection state
01074             const INT32 NumCoords = pPath->InkPath.GetNumCoords();
01075             for (INT32 loop = 0; loop<NumCoords; loop++)
01076             {
01077                 pPath->InkPath.GetFlagArray()[loop].IsSelected = SelectPoints;
01078             }
01079 
01080             // Put the blobs back on the path
01081             pRegion = DocView::RenderOnTop(NULL, pSpread, ClippedEOR);
01082             while (pRegion != NULL)
01083             {
01084                 pPath->RenderObjectBlobs(pRegion);
01085                 pRegion = DocView::GetNextOnTop(NULL);
01086             }
01087 
01088             GetApplication()->UpdateSelection();
01089         }
01090 
01091         pNode = pSelection->FindNext(pNode);
01092     }
01093 
01094     return TRUE;
01095 }   
01096 
01097 
01098 
01099 /********************************************************************************************
01100 >   void OpSelectAllPathPoints::Do(OpDescriptor*)
01101 
01102     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01103     Created:    30/04/95
01104     Inputs:     Unused
01105     Outputs:    -
01106     Returns:    -       
01107     Purpose:    Selects all the points on the selected paths
01108     SeeAlso:    -
01109 ********************************************************************************************/
01110 void OpSelectAllPathPoints::Do(OpDescriptor*)
01111 {
01112     if (!DoAction(TRUE))
01113         InformError();
01114 
01115     End();
01116 }
01117 
01118 
01119 
01120 /********************************************************************************************
01121 >   void OpDeSelectAllPathPoints::Do(OpDescriptor*)
01122 
01123     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01124     Created:    30/04/95
01125     Inputs:     Unused
01126     Outputs:    -
01127     Returns:    -       
01128     Purpose:    Deselects all the points on the selected paths
01129     SeeAlso:    -
01130 ********************************************************************************************/
01131 void OpDeSelectAllPathPoints::Do(OpDescriptor*)
01132 {
01133     if (!DoAction(FALSE))
01134         InformError();
01135 
01136     End();
01137 }
01138 
01139 
01140 
01141 /********************************************************************************************
01142 
01143 >   OpReversePath::OpReversePath()
01144 
01145     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01146     Created:    10/5/2000
01147     Inputs:     -
01148     Purpose:    Construct an object of this type.
01149 
01150 ********************************************************************************************/
01151 
01152 OpReversePath::OpReversePath()
01153 {
01154 }
01155 
01156 
01157 
01158 /********************************************************************************************
01159 
01160 >   OpReversePath::~OpReversePath()
01161 
01162     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01163     Created:    10/5/2000
01164     Inputs:     -
01165     Purpose:    Destruct an object of this type.
01166 
01167 ********************************************************************************************/
01168 
01169 OpReversePath::~OpReversePath()
01170 {
01171 }
01172 
01173 
01174 
01175 /********************************************************************************************
01176 
01177 >   OpReversePath::Init()
01178 
01179     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01180     Created:    10/5/2000
01181     Returns:    TRUE if the operation could be successfully initialised 
01182                 FALSE if no more memory could be allocated 
01183     Purpose:    OpMakeSegmentsLines initialiser method
01184     Errors:     ERROR will be called if there was insufficient memory to allocate the 
01185                 operation.
01186 
01187 ********************************************************************************************/
01188 
01189 BOOL OpReversePath::Init()
01190 {
01191     return (RegisterOpDescriptor(   0, 
01192                                     _R(IDS_MAKEREVERSE),
01193                                     CC_RUNTIME_CLASS(OpReversePath), 
01194                                     OPTOKEN_REVERSEPATH,
01195                                     OpReversePath::GetState,
01196                                     0,  /* help ID */
01197                                     _R(IDBBL_MAKEREVERSE),
01198                                     0   /* bitmap ID */));
01199 }               
01200 
01201 
01202 
01203 /********************************************************************************************
01204 
01205 >   OpState OpReversePath::GetState (String_256* Description, OpDescriptor*)
01206 
01207     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01208     Created:    7/2/2000
01209     Returns:    Ungreyed, Unticked
01210     Purpose:    Determines the state of the op.
01211 
01212 ********************************************************************************************/
01213 
01214 OpState OpReversePath::GetState (String_256* Description, OpDescriptor*)
01215 {
01216     OpState OpSt;
01217 
01218     SelRange*   Selected = GetApplication ()->FindSelection ();
01219 
01220     if ((Document::GetSelected () == NULL) || (Selected == NULL) )
01221     {   // There is no selected document or selrange is invalid 
01222         OpSt.Greyed = TRUE;
01223         return (OpSt);
01224     }
01225 
01226     if (Selected->Count () == 0)    // if there ain't no selection - return cause we ain't
01227                                     // going to be reversing anything
01228     {
01229         OpSt.Greyed = TRUE;
01230         return (OpSt);
01231     }
01232 
01233     Node* pNode = Selected->FindFirst ();
01234 
01235     // scan the selection and if even a single DoThisNode fails, then return that the op
01236     // is greyed immediately ....
01237 
01238     while (pNode != NULL)
01239     {   // we're only interested in NodePaths which have selected points
01240         BOOL DoThisNode = pNode->IsNodePath ();
01241         //if (DoThisNode)
01242         //  DoThisNode = (((NodePath*)pNode)->InkPath.IsSubSelection());
01243         if (DoThisNode)
01244             DoThisNode = (((NodePath*)pNode)->IsPathAllowable ());
01245 
01246         if (DoThisNode)
01247         {
01248             pNode = Selected->FindNext (pNode);
01249         }
01250         else
01251         {
01252             pNode = NULL;
01253             OpSt.Greyed = TRUE;
01254         }
01255     }
01256 
01257     return (OpSt);
01258 }
01259 
01260 
01261 
01262 /********************************************************************************************
01263 
01264 >   void OpReversePath::Do (OpDescriptor*)
01265 
01266     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01267     Created:    10/5/2000
01268     Inputs:     OpDescriptor (unused)
01269     Purpose:    Does the work of reversing the paths.
01270 
01271 ********************************************************************************************/
01272 
01273 void OpReversePath::Do (OpDescriptor*)
01274 {
01275     // Obtain the current selections and the first node in the selection
01276     SelRange* Selected = GetApplication()->FindSelection();
01277     BOOL ok = (Selected != NULL);
01278 
01279     // Start the op
01280     BeginSlowJob();
01281     if (ok)
01282         ok = DoStartSelOp(TRUE,TRUE);
01283 
01284     // Check with the selrange it is ok to run this op
01285     ObjChangeFlags cFlags;
01286     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
01287     if (ok)
01288     {
01289         if (!Selected->AllowOp(&ObjChange))
01290         {
01291             EndSlowJob();
01292             FailAndExecute();
01293             End();
01294             return;
01295         }
01296     }
01297 
01298     Node* pNode = Selected->FindFirst();
01299     NodePath* ThisPath = NULL;
01300 
01301     //Document* pDocument = GetWorkingDoc();
01302 
01303     while (ok && (pNode != NULL))
01304     {   // we're only interested in NodePaths which have selected points
01305         BOOL DoThisNode = pNode->IsNodePath();
01306         //if (DoThisNode)
01307         //  DoThisNode = (((NodePath*)pNode)->InkPath.IsSubSelection());
01308         if (DoThisNode)
01309             DoThisNode = (((NodePath*)pNode)->IsPathAllowable());
01310 
01311         if  ( DoThisNode )
01312         {
01313             // for convenience, cast the pointer to a pointer to a NodePath
01314             ThisPath = (NodePath*)pNode;
01315 
01316             // First get pointers to the arrays
01317             PathVerb* Verbs = NULL;
01318             PathFlags* Flags = NULL;
01319             DocCoord* Coords = NULL;
01320             ThisPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
01321             INT32 NumCoords = ThisPath->InkPath.GetNumCoords();
01322 //          BOOL PrevSelected = FALSE;
01323 //          INT32 PrevPos = 0;
01324 
01325             ObjChangeFlags cFlags;
01326             cFlags.TransformNode = TRUE;
01327             ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,ThisPath,this);
01328             if (!ThisPath->AllowOp(&ObjChange, TRUE))
01329             {
01330                 return;
01331             }
01332 
01333             // Set the NeedToRender flags
01334             for (INT32 loop = 0; loop < NumCoords; loop++)
01335             {
01336                 if (Flags[loop].IsEndPoint && Flags[loop].IsSelected)
01337                     Flags[loop].NeedToRender = TRUE;
01338                 else
01339                     Flags[loop].NeedToRender = FALSE;
01340             }
01341 
01342             // Force a re-draw of the place where the path used to be
01343             if (ok)
01344                 ok = (RecalcBoundsAction::DoRecalc(this, &UndoActions, ThisPath, TRUE) != AC_FAIL);
01345 
01346             DoReversePath (ThisPath);
01347 
01348             // Force a redraw of the place where the path is now.
01349             if (ok)
01350                 ok = (RecordBoundsAction::DoRecord(this, &UndoActions, ThisPath, TRUE) != AC_FAIL);
01351         }
01352         pNode = Selected->FindNext(pNode);
01353     }
01354 
01355     if (ok)
01356     {
01357         ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
01358         if (!UpdateChangedNodes(&ObjChange))
01359         {
01360             FailAndExecute();
01361             End();
01362             return;
01363         }
01364     }
01365 
01366     EndSlowJob();
01367 
01368     if (!ok)
01369     {   
01370         FailAndExecute();
01371         InformError();
01372     }
01373 
01374     End();
01375 }

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