OpNodePathEditBlob Class Reference

This operation is started by the NodePath when it receives a drag message from one of the tools. It uses it to drag one (or many) of the paths control points around the screen to edit the path. As the control points are dragged about the new version of the path, corosponding to the new blob positions, will be EOR rendered to the window. More...

#include <pathedit.h>

Inheritance diagram for OpNodePathEditBlob:

SelOperation UndoableOperation Operation MessageHandler ListItem CCObject SimpleCCObject OpNewPath OpNodePathAddEndpoint OpNodePathEditControlBlob OpReshapeOrAddPoint OpCloseNodePaths List of all members.

Public Member Functions

 OpNodePathEditBlob ()
void DoStartDragEdit (NodePath *, DocCoord Anchor, Spread *)
 This is called to start a drag operation on an endpoint on a path.
virtual void DragPointerMove (DocCoord Pos, ClickModifiers Mods, Spread *pSpread, BOOL bSolidDrag)
 This is called every time the mouse moves, during a drag.
virtual void DragFinished (DocCoord Pos, ClickModifiers Mods, Spread *pSpread, BOOL Success, BOOL bSolidDrag)
 This is called when a drag operation finishes.
virtual void RenderDragBlobs (DocRect, Spread *, BOOL bSolidDrag)
 Renders the new version of the path to the window. It makes use of flags in the path to determine which segments of the path need to be rendered.

Static Public Member Functions

static BOOL Init ()
 Adds the operation to the list of all known operations.
static OpState GetState (String_256 *Description, OpDescriptor *)
 Find out the state of the operation at the specific time.

Protected Member Functions

BOOL BuildEditPath ()
 Builds a copy of the path that we can edit, without destroying the original data. Also sets the NeedToRender flags for EOR display.
BOOL BuildEditPaths ()
 Builds a copy of each path in the selection that we can edit, without destroying the original data. Also sets the NeedToRender flags for EOR display.
BOOL CopyEditedPathBack ()
 Copies the contents of the edited path back into the original path.
BOOL CopyEditedPathBack (NodePath *pOrigPath, Path *pEditPath)
 Copies the contents of the edited path back into the original path.
BOOL CopyNeedToRenderFlags ()
 This function is used to copy the NeedToRender flags from EditPath to OriginalPath. This are then used in optimised region invalidation.
BOOL CopyNeedToRenderFlags (NodePath *pOrigPath, Path *pEditPath)
 This function is used to copy the NeedToRender flags from EditPath to OriginalPath. This are then used in optimised region invalidation.
void RecalculatePath (DocCoord Offset, BOOL SnapEnds=FALSE, INT32 SnapIndex=0)
 This goes through the path, moves all the selected coords by the offset and then performs some magic to smooth the rest of the path round the changes if it needs it.
void RecalculatePaths (Path *pEditPath, DocCoord Offset, BOOL SnapEnds=FALSE, INT32 SnapIndex=0)
 This goes through the path, moves all the selected coords by the offset and then performs some magic to smooth the rest of the path round the changes if it needs it.
void SnapEndsTogether ()
 Sets the closefigure flag in the last element in the subpath. Also turns off the rotate bit in the points we're snapping together if their smoothing bits are also turned off. This prevents us creating a cusp that has rotate flags set.
void SnapEndsTogether (Path *pEditPath)
 Sets the closefigure flag in the last element in the subpath. Also turns off the rotate bit in the points we're snapping together if their smoothing bits are also turned off. This prevents us creating a cusp that has rotate flags set.
BOOL JoinWithOtherPath ()
 Looks at the member variables dealing with snapping to another path and joins the paths together. It will always join the other path to the original path, keeping the original path's attributes intact. NOTE: This routine will alter the OriginalPath member variable if it joins paths, because it has to make a copy of the path for undo purposes.
BOOL JoinWithOtherPath (NodePath **pOrigPath)
 Looks at the member variables dealing with snapping to another path and joins the paths together. It will always join the other path to the original path, keeping the original path's attributes intact. NOTE: This routine will alter the OriginalPath member variable if it joins paths, because it has to make a copy of the path for undo purposes.
BOOL FillPathIfEndsSnapped ()
 Will look at the EndSnapped flag and set the IsFilled bit in the OriginalPath Builds undo information. Returns FALSE if it couldn't build the Undo info.
BOOL FillPathIfEndsSnapped (NodePath *pOrigPath)
 Will look at the EndSnapped flag and set the IsFilled bit in the OriginalPath Builds undo information. Returns FALSE if it couldn't build the Undo info.
virtual void RenderDraggingBlobs (DocRect, Spread *)
 Call this function to render all the blobs on screen from this operation.
virtual void RenderDraggingBlobs (Path *pEditPath, Spread *)
 Call this function to render all the blobs on screen from this operation.
void RenderPathEditBlobs (DocRect Rect, Spread *pSpread)
void RenderPathEditBlobs (Path *pEditPath, Spread *pSpread)
 Call this function to render all the blobs on screen from this operation.
virtual void SetStatusLineHelp ()
 Updates the status line message to reflect the current situation.
NodeGroupGetGroupParentOfCurve ()
 To determine if the current selection is a blend on a curve.
NodeGroupGetGroupParentOfCurve (NodePath *pOrigPath)
 To determine if the current selection is a blend on a curve.
BOOL InsertChangeBlendStepsAction (NodeBlend *pNodeBlend)
 To adjust the number of steps in a blend on a path as a result of the path being edited (which is why its here rather than in the blend code). First the number of steps is calculated from the new path distance and if different a new action is inserted.
AttrBrushTypeGetAppliedBrush ()
 To get the brush attribute that is applied to the nodepath we are editing.
virtual BOOL EditBrushAttribute (INT32 FirstIndex, INT32 LastIndex, AttrBrushType *pAttrBrush)
 If we use the shape editor to edit a nodepath with an applied brush attribute and this brush attribute makes use of sampled pressure or time information then the brush needs to resample its data. So here we will insert a few actions to make that happen.
MILLIPOINT GetLengthOfPathSection (Path *pPath, INT32 FirstIndex, INT32 LastIndex)
 As above, if you want to know the distance between two points on the edit path then this function is for you.
MILLIPOINT GetDistanceToPathIndex (Path *pPath, INT32 Index)
 As above,.
void ChangeCursor (Cursor *cursor)
 Changes the mouse pointer to a new shape.
BOOL CreateCursors ()
 Creates the cursor objects for the path operations.
void DestroyCursors ()
 Deletes the path operation cursors.

Protected Attributes

SpreadStartSpread
DocCoord StartMousePos
DocCoord LastMousePos
DocCoord ConstrainPoint
DocCoord ConstrainPrevPoint
DocCoord ConstrainNextPoint
NodePathOriginalPath
Path EditPath
List OriginalPaths
List EditPaths
List PathsDragStarted
BOOL MultiplePaths
BOOL EndSnapped
BOOL SnapToAnother
NodePathSnapToPath
INT32 SnapToIndex
BOOL SnapToLineOrCurve
DocCoord SnapToCoords [4]
CursorpMoveCursor
CursorpCloseCursor
CursorpCrossHairCursor
CursorMyCurrentCursor
INT32 CurrentCursorID
ObjChangePathEdit EditObjChange
List ObjChanges
INT32 DragPoint
INT32 UpdatePoint
BOOL DragStarted

Detailed Description

This operation is started by the NodePath when it receives a drag message from one of the tools. It uses it to drag one (or many) of the paths control points around the screen to edit the path. As the control points are dragged about the new version of the path, corosponding to the new blob positions, will be EOR rendered to the window.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
1/7/93

Definition at line 143 of file pathedit.h.


Constructor & Destructor Documentation

OpNodePathEditBlob::OpNodePathEditBlob  ) 
 


Member Function Documentation

BOOL OpNodePathEditBlob::BuildEditPath  )  [protected]
 

Builds a copy of the path that we can edit, without destroying the original data. Also sets the NeedToRender flags for EOR display.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> - later attacked by Peter
Date:
17/02/94
Returns:
TRUE if it managed to build the path, FALSE if it failed

Errors: If it runs out of memory then it will return FALSE

Reimplemented in OpNodePathEditControlBlob, and OpReshapeOrAddPoint.

Definition at line 2197 of file pathedit.cpp.

02198 {
02199     // Make a copy of the original path
02200     UINT32 NumCoords = OriginalPath->InkPath.GetNumCoords();
02201     if (!EditPath.Initialise(NumCoords, 24))
02202         return FALSE;
02203     if (!EditPath.CopyPathDataFrom(&(OriginalPath->InkPath)))
02204         return FALSE;
02205 
02206     // Go though all the coords, with scary amounts of looking back and forwards
02207     UINT32 LastEndPoint = 0;                // The EndPoint before this one
02208     BOOL SetNextEndPoint = FALSE;       // TRUE if we want to set the next EndPoint to render
02209     BOOL SetNextNextEndPoint = FALSE;   // TRUE if we want the one after the next one to render
02210     PathFlags* Flags = EditPath.GetFlagArray();
02211     for (UINT32 i=0; i<NumCoords; i++)
02212     {
02213         // Make all the flags FALSE by default
02214         Flags[i].NeedToRender = FALSE;
02215 
02216         if (Flags[i].IsEndPoint)
02217         {
02218             // if the endpoint 2 elements back was selected and the last element was smooth
02219             // then we need to mark this point for rendering
02220             if (SetNextNextEndPoint)
02221             {
02222                 Flags[i].NeedToRender = TRUE;
02223                 SetNextNextEndPoint = FALSE;
02224             }
02225 
02226             // We have found an Endpoint, do we want to mark this one as renderable
02227             if (SetNextEndPoint)
02228             {
02229                 // As the last element was selected, this element needs to render
02230                 Flags[i].NeedToRender = TRUE;
02231                 SetNextEndPoint = FALSE;
02232 
02233                 // If the smooth flag is set then the next item needs to render as well
02234                 if (Flags[i].IsRotate || Flags[i].IsSmooth)
02235                     SetNextNextEndPoint = TRUE;
02236             }
02237 
02238             // If its selected, then its renderable
02239             if (Flags[i].IsSelected)
02240             {
02241                 Flags[i].NeedToRender = TRUE;
02242                 if (Flags[LastEndPoint].IsRotate || Flags[LastEndPoint].IsSmooth)
02243                     Flags[LastEndPoint].NeedToRender = TRUE;
02244 
02245                 // Set the flag for the next endpoint
02246                 SetNextEndPoint = TRUE;
02247             }
02248 
02249             LastEndPoint = i;
02250         }
02251     }
02252 
02253     return TRUE;
02254 }

BOOL OpNodePathEditBlob::BuildEditPaths  )  [protected]
 

Builds a copy of each path in the selection that we can edit, without destroying the original data. Also sets the NeedToRender flags for EOR display.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (based upon Rik/Peter)
Date:
17/02/94
Returns:
TRUE if it managed to build the paths, FALSE if it failed

Errors: If it runs out of memory then it will return FALSE

Definition at line 2107 of file pathedit.cpp.

02108 {
02109     NodeListItem* pCurrent = (NodeListItem*) OriginalPaths.GetHead ();
02110 
02111     while (pCurrent)
02112     {
02113         NodePath* pCurrentPath = (NodePath*) (pCurrent->pNode);
02114         Path* NewEditPath = new Path ();
02115 
02116         UINT32 NumCoords = pCurrentPath->InkPath.GetNumCoords();
02117 
02118         if (!NewEditPath->Initialise(NumCoords, 24))
02119             return FALSE;
02120         if (!NewEditPath->CopyPathDataFrom(&(pCurrentPath->InkPath)))
02121             return FALSE;
02122 
02123         // Go though all the coords, with scary amounts of looking back and forwards
02124         UINT32 LastEndPoint = 0;                // The EndPoint before this one
02125         BOOL SetNextEndPoint = FALSE;       // TRUE if we want to set the next EndPoint to render
02126         BOOL SetNextNextEndPoint = FALSE;   // TRUE if we want the one after the next one to render
02127         PathFlags* Flags = NewEditPath->GetFlagArray();
02128         
02129         for (UINT32 i=0; i<NumCoords; i++)
02130         {
02131             // Make all the flags FALSE by default
02132             Flags[i].NeedToRender = FALSE;
02133 
02134             if (Flags[i].IsEndPoint)
02135             {
02136                 // if the endpoint 2 elements back was selected and the last element was smooth
02137                 // then we need to mark this point for rendering
02138                 if (SetNextNextEndPoint)
02139                 {
02140                     Flags[i].NeedToRender = TRUE;
02141                     SetNextNextEndPoint = FALSE;
02142                 }
02143 
02144                 // We have found an Endpoint, do we want to mark this one as renderable
02145                 if (SetNextEndPoint)
02146                 {
02147                     // As the last element was selected, this element needs to render
02148                     Flags[i].NeedToRender = TRUE;
02149                     SetNextEndPoint = FALSE;
02150 
02151                     // If the smooth flag is set then the next item needs to render as well
02152                     if (Flags[i].IsRotate || Flags[i].IsSmooth)
02153                         SetNextNextEndPoint = TRUE;
02154                 }
02155 
02156                 // If its selected, then its renderable
02157                 if (Flags[i].IsSelected)
02158                 {
02159                     Flags[i].NeedToRender = TRUE;
02160                     if (Flags[LastEndPoint].IsRotate || Flags[LastEndPoint].IsSmooth)
02161                         Flags[LastEndPoint].NeedToRender = TRUE;
02162 
02163                     // Set the flag for the next endpoint
02164                     SetNextEndPoint = TRUE;
02165                 }
02166 
02167                 LastEndPoint = i;
02168             }
02169         }
02170 
02171         NodeListItem* pInsert = new NodeListItem;
02172         pInsert->pNode = (Node*) NewEditPath;
02173         
02174         EditPaths.AddTail (pInsert);//NewEditPath);
02175         
02176         pCurrent = (NodeListItem*) OriginalPaths.GetNext (pCurrent);
02177 
02178         //delete (pInsert);
02179 
02180 //      delete (NewEditPath);               // cleanup that is necessary
02181     }
02182     
02183     return (TRUE);
02184 }

void OpNodePathEditBlob::ChangeCursor Cursor cursor  )  [protected]
 

Changes the mouse pointer to a new shape.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/9/94
Parameters:
Pointer to the cursor to use now. [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: -

See also:
OpNodePathEditBlob::CreateCursors(), OpNodePathEditBlob::DestroyCursors()

Definition at line 4787 of file pathedit.cpp.

04788 {
04789     if (cursor != MyCurrentCursor)
04790     {   // only change if this cursor is different from the current cursor
04791         if (MyCurrentCursor != NULL)
04792         {   // If one of our cursors is on the stack then get it off
04793             CursorStack::GPop(CurrentCursorID); 
04794         }
04795         MyCurrentCursor = cursor;
04796         CurrentCursorID = CursorStack::GPush(cursor);
04797     }
04798 }   

BOOL OpNodePathEditBlob::CopyEditedPathBack NodePath pOrigPath,
Path pEditPath
[protected]
 

Copies the contents of the edited path back into the original path.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (based upon Will/Peter)
Date:
20/4/2000
Returns:
TRUE if it worked, FALSE if it failed

Definition at line 2441 of file pathedit.cpp.

02442 {
02443     // Now to do some undo information. To do this, I have to look at each element in the path
02444     // and each element in the copy, and see which ones differ. I then have to work out how many
02445     // elements that was, and create a path to contain those elements, along with an array of indices 
02446     // telling me where those elements came from
02447     INT32 NumElements = pOrigPath->InkPath.GetNumCoords();
02448     PathVerb* SourceVerbs = pOrigPath->InkPath.GetVerbArray();
02449     DocCoord* SourceCoords = pOrigPath->InkPath.GetCoordArray();
02450     PathFlags* SourceFlags = pOrigPath->InkPath.GetFlagArray();
02451     PathVerb* DestVerbs = pEditPath->GetVerbArray();
02452     DocCoord* DestCoords = pEditPath->GetCoordArray();
02453     PathFlags* DestFlags = pEditPath->GetFlagArray();
02454 
02455     INT32 ChangedElements = 0;
02456     INT32 i;    
02457 
02458     for (i=0;i<NumElements;i++)
02459     {
02460         if (SourceVerbs[i] != DestVerbs[i] || 
02461             SourceCoords[i] != DestCoords[i] || 
02462             SourceFlags[i] != DestFlags[i]
02463             )
02464             ChangedElements++;
02465     }
02466 
02467     // ChangedElements is the number of elements in this path that will change.
02468     // We have to create three arrays to contain the changed elements, plus one array
02469     // to tell me where the elements should go (the indices)
02470 
02471     // I also have to create an action object to contain these arrays. I have to create the action
02472     // object first because that does all the work of deciding if there's enough memory in the 
02473     // undo buffer to store the action, and prompting the user accordingly of there isn't
02474 
02475     if (ChangedElements > 0)
02476     {
02477         ModifyPathAction* ModAction;
02478     
02479         ActionCode Act;
02480         Act = ModifyPathAction::Init(this, &UndoActions, ChangedElements, (Action**)(&ModAction));
02481         if (Act == AC_FAIL)
02482         {
02483             FailAndExecute();
02484             End();
02485             return FALSE;
02486         }
02487 
02488         PathVerb* ChangedVerbs=NULL;
02489         DocCoord* ChangedCoords=NULL;
02490         PathFlags* ChangedFlags=NULL;
02491         INT32* ChangedIndices=NULL;
02492 
02493         // If the function returned AC_NO_RECORD we shouldn't record any undo information in the action
02494         // NOTE - during unwind all actions return AC_OK with a NULL ModAction pointer!!
02495         if ((Act!=AC_NORECORD) && (ModAction!=NULL))
02496         {
02497             // This next bit is a bit hellish. Any one of these four allocations can fail, in which case 
02498             // we have to tidy up afterwards. Cue a lot of nested ifs and elses.
02499 
02500             ALLOC_WITH_FAIL(ChangedVerbs,(PathVerb*) CCMalloc(ChangedElements * sizeof(PathVerb)),this);
02501             if (ChangedVerbs)
02502             {
02503                 ALLOC_WITH_FAIL(ChangedCoords,(DocCoord*) CCMalloc(ChangedElements * sizeof(DocCoord)),this);
02504                 if (ChangedCoords)
02505                 {
02506                     ALLOC_WITH_FAIL(ChangedFlags,(PathFlags*) CCMalloc(ChangedElements * sizeof(PathFlags)),this);
02507                     if (ChangedFlags)
02508                     {
02509                         ALLOC_WITH_FAIL(ChangedIndices,(INT32*) CCMalloc(ChangedElements * sizeof(INT32)),this);
02510                         if (!ChangedIndices)
02511                         {
02512                             CCFree( ChangedFlags );
02513                             CCFree( ChangedCoords );
02514                             CCFree( ChangedVerbs);
02515                             FailAndExecute();
02516                             End();
02517                             return FALSE;
02518                         }
02519                     }
02520                     else
02521                     {
02522                         CCFree( ChangedCoords );
02523                         CCFree( ChangedVerbs );
02524                         FailAndExecute();
02525                         End();
02526                         return FALSE;
02527 
02528                     }
02529                 }
02530                 else
02531                 {
02532                     CCFree( ChangedVerbs);
02533                     FailAndExecute();
02534                     End();
02535                     return FALSE;
02536 
02537                 }
02538             }
02539 
02540             // Now to put the undo data into the undo action
02541             INT32 index = 0;
02542             for (i=0;i<NumElements;i++)
02543             {
02544                 if (SourceVerbs[i] != DestVerbs[i] || 
02545                     SourceCoords[i] != DestCoords[i] || 
02546                     SourceFlags[i] != DestFlags[i]
02547                     )
02548                 {
02549                     ChangedVerbs[index] = SourceVerbs[i];
02550                     ChangedFlags[index] = SourceFlags[i];
02551                     ChangedCoords[index] = SourceCoords[i];
02552                     ChangedIndices[index] = i;
02553                     index++;
02554                 }
02555             }
02556 
02557             // Now we've allocated the arrays, let's tell the action about 'em
02558             ModAction->StoreArrays(ChangedVerbs, ChangedFlags, ChangedCoords, ChangedIndices, pOrigPath);
02559         }
02560     }
02561         
02562     if (!pOrigPath->InkPath.CopyPathDataFrom(pEditPath))
02563         return FALSE;
02564     else
02565         return TRUE;
02566 }

BOOL OpNodePathEditBlob::CopyEditedPathBack  )  [protected]
 

Copies the contents of the edited path back into the original path.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
17/02/94
Returns:
TRUE if it worked, FALSE if it failed

Definition at line 2269 of file pathedit.cpp.

02270 {
02271     // Now to do some undo information. To do this, I have to look at each element in the path
02272     // and each element in the copy, and see which ones differ. I then have to work out how many
02273     // elements that was, and create a path to contain those elements, along with an array of indices 
02274     // telling me where those elements came from
02275     INT32 NumElements = OriginalPath->InkPath.GetNumCoords();
02276     PathVerb* SourceVerbs = OriginalPath->InkPath.GetVerbArray();
02277     DocCoord* SourceCoords = OriginalPath->InkPath.GetCoordArray();
02278     PathFlags* SourceFlags = OriginalPath->InkPath.GetFlagArray();
02279     PathVerb* DestVerbs = EditPath.GetVerbArray();
02280     DocCoord* DestCoords = EditPath.GetCoordArray();
02281     PathFlags* DestFlags = EditPath.GetFlagArray();
02282 
02283     // DY now we want to keep track of the indexes of the changed section
02284     INT32 ChangedElements = 0;
02285     INT32 FirstChanged = -1;
02286     INT32 LastChanged  = -1;
02287 
02288     INT32 i;
02289     for (i=0;i<NumElements;i++)
02290     {
02291         if (SourceVerbs[i] != DestVerbs[i] || SourceCoords[i] != DestCoords[i] || 
02292             SourceFlags[i] != DestFlags[i] )
02293         {
02294             ChangedElements++;
02295 
02296         //  if (SourceCoords[i] != DestCoords[i])
02297             {
02298                 // if we have not yet set the first changed index then set it
02299                 if (FirstChanged == -1)
02300                     FirstChanged = i;
02301 
02302                 // always set the last changed index
02303                 LastChanged = i;
02304             }
02305         }
02306 
02307     }
02308     
02309 
02310     // ChangedElements is the number of elements in this path that will change.
02311     // We have to create three arrays to contain the changed elements, plus one array
02312     // to tell me where the elements should go (the indices)
02313 
02314     // I also have to create an action object to contain these arrays. I have to create the action
02315     // object first because that does all the work of deciding if there's enough memory in the 
02316     // undo buffer to store the action, and prompting the user accordingly of there isn't
02317 
02318     if (ChangedElements > 0)
02319     {
02320         // do the brush editing here
02321         // the following block deals with editing path blobs.  For some reason I could not get a
02322         // sensible value for the distance of the edited path from the changed indexes, however
02323         // it works quite nicely by finding the contraining points.
02324         if (DragPoint != -1)
02325         {
02326             // this section only applies for editing blobs (as reshaping has no drag point)
02327             FirstChanged = DragPoint;
02328             LastChanged = DragPoint;
02329             OriginalPath->InkPath.FindPrevEndPoint(&FirstChanged);
02330             OriginalPath->InkPath.FindNextEndPoint(&LastChanged);
02331         }
02332         
02333         AttrBrushType* pAttrBrush = GetAppliedBrush();
02334         if (pAttrBrush != NULL)
02335             EditBrushAttribute(FirstChanged, LastChanged, pAttrBrush);
02336 
02337         ModifyPathAction* ModAction;
02338     
02339         ActionCode Act;
02340         Act = ModifyPathAction::Init(this, &UndoActions, ChangedElements, (Action**)(&ModAction));
02341         if (Act == AC_FAIL)
02342         {
02343             FailAndExecute();
02344             End();
02345             return FALSE;
02346         }
02347 
02348         PathVerb* ChangedVerbs=NULL;
02349         DocCoord* ChangedCoords=NULL;
02350         PathFlags* ChangedFlags=NULL;
02351         INT32* ChangedIndices=NULL;
02352 
02353         // If the function returned AC_NO_RECORD we shouldn't record any undo information in the action
02354         // NOTE - during unwind all actions return AC_OK with a NULL ModAction pointer!!
02355         if ((Act!=AC_NORECORD) && (ModAction!=NULL))
02356         {
02357             // This next bit is a bit hellish. Any one of these four allocations can fail, in which case 
02358             // we have to tidy up afterwards. Cue a lot of nested ifs and elses.
02359 
02360             ALLOC_WITH_FAIL(ChangedVerbs,(PathVerb*) CCMalloc(ChangedElements * sizeof(PathVerb)),this);
02361             if (ChangedVerbs)
02362             {
02363                 ALLOC_WITH_FAIL(ChangedCoords,(DocCoord*) CCMalloc(ChangedElements * sizeof(DocCoord)),this);
02364                 if (ChangedCoords)
02365                 {
02366                     ALLOC_WITH_FAIL(ChangedFlags,(PathFlags*) CCMalloc(ChangedElements * sizeof(PathFlags)),this);
02367                     if (ChangedFlags)
02368                     {
02369                         ALLOC_WITH_FAIL(ChangedIndices,(INT32*) CCMalloc(ChangedElements * sizeof(INT32)),this);
02370                         if (!ChangedIndices)
02371                         {
02372                             CCFree( ChangedFlags );
02373                             CCFree( ChangedCoords );
02374                             CCFree( ChangedVerbs);
02375                             FailAndExecute();
02376                             End();
02377                             return FALSE;
02378                         }
02379                     }
02380                     else
02381                     {
02382                         CCFree( ChangedCoords );
02383                         CCFree( ChangedVerbs );
02384                         FailAndExecute();
02385                         End();
02386                         return FALSE;
02387 
02388                     }
02389                 }
02390                 else
02391                 {
02392                     CCFree( ChangedVerbs);
02393                     FailAndExecute();
02394                     End();
02395                     return FALSE;
02396 
02397                 }
02398             }
02399 
02400             // Now to put the undo data into the undo action
02401             INT32 index = 0;
02402             for (i=0;i<NumElements;i++)
02403             {
02404                 if (SourceVerbs[i] != DestVerbs[i] || 
02405                     SourceCoords[i] != DestCoords[i] || 
02406                     SourceFlags[i] != DestFlags[i]
02407                     )
02408                 {
02409                     ChangedVerbs[index] = SourceVerbs[i];
02410                     ChangedFlags[index] = SourceFlags[i];
02411                     ChangedCoords[index] = SourceCoords[i];
02412                     ChangedIndices[index] = i;
02413                     index++;
02414                 }
02415             }
02416 
02417             // Now we've allocated the arrays, let's tell the action about 'em
02418             ModAction->StoreArrays(ChangedVerbs, ChangedFlags, ChangedCoords, ChangedIndices, OriginalPath);
02419         }
02420     }
02421         
02422     if (!OriginalPath->InkPath.CopyPathDataFrom(&EditPath))
02423         return FALSE;
02424     else
02425         return TRUE;
02426 }

BOOL OpNodePathEditBlob::CopyNeedToRenderFlags NodePath pOrigPath,
Path pEditPath
[protected]
 

This function is used to copy the NeedToRender flags from EditPath to OriginalPath. This are then used in optimised region invalidation.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (based upon Peter)
Date:
20/04/95
Parameters:
- [INPUTS]
(see below) [OUTPUTS]
Returns:
TRUE if the flags have been copied; FALSE if the paths were different lengths

Definition at line 2618 of file pathedit.cpp.

02619 {
02620     const INT32 OrigLength = pOrigPath->InkPath.GetNumCoords();
02621     const INT32 EditLength = pEditPath->GetNumCoords();
02622 
02623     if (EditLength != OrigLength)
02624         return FALSE;
02625 
02626     PathFlags* EditFlags = pEditPath->GetFlagArray();
02627     PathFlags* OrigFlags = pOrigPath->InkPath.GetFlagArray();
02628         
02629     for (INT32 loop = 0; loop < EditLength; loop ++)
02630     {
02631         OrigFlags[loop].NeedToRender = EditFlags[loop].NeedToRender;
02632     }
02633 
02634     return TRUE;
02635 }

BOOL OpNodePathEditBlob::CopyNeedToRenderFlags  )  [protected]
 

This function is used to copy the NeedToRender flags from EditPath to OriginalPath. This are then used in optimised region invalidation.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
10/03/95
Parameters:
- [INPUTS]
(see below) [OUTPUTS]
Returns:
TRUE if the flags have been copied; FALSE if the paths were different lengths

Definition at line 2583 of file pathedit.cpp.

02584 {
02585     const INT32 OrigLength = OriginalPath->InkPath.GetNumCoords();
02586     const INT32 EditLength = EditPath.GetNumCoords();
02587 
02588     if (EditLength != OrigLength)
02589         return FALSE;
02590 
02591     PathFlags* EditFlags = EditPath.GetFlagArray();
02592     PathFlags* OrigFlags = OriginalPath->InkPath.GetFlagArray();
02593         
02594     for (INT32 loop = 0; loop < EditLength; loop ++)
02595     {
02596         OrigFlags[loop].NeedToRender = EditFlags[loop].NeedToRender;
02597     }
02598 
02599     return TRUE;
02600 }

BOOL OpNodePathEditBlob::CreateCursors  )  [protected]
 

Creates the cursor objects for the path operations.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/9/94
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
FALSE if the cursors wern't created, TRUE if they were.

Errors: -

See also:
OpNodePathEditBlob::DestroyCursors()

Definition at line 4816 of file pathedit.cpp.

04817 {
04818     if (pMoveCursor == NULL)
04819     {   // If already created then don't create a new set.
04820         MyCurrentCursor = NULL;
04821         pMoveCursor = new Cursor(TOOLID_BEZTOOL, _R(IDC_MOVEBEZIERCURSOR));
04822         pCloseCursor = new Cursor(TOOLID_BEZTOOL, _R(IDC_CLOSEPATHCURSOR));
04823         pCrossHairCursor = new Cursor(TOOLID_BEZTOOL, _R(IDC_CROSSHAIRCURSOR));
04824         // See if any of them failed
04825         if ((!pMoveCursor || !pMoveCursor->IsValid())
04826                 || (!pCloseCursor || !pCloseCursor->IsValid())
04827                 || (!pCrossHairCursor || !pCrossHairCursor->IsValid()))
04828         {   
04829             // They did fail, so clean up
04830             TRACE( _T("Cursors not created in OpNodePathEditBlob::CreateCursors\n"));
04831             delete pMoveCursor;
04832             delete pCloseCursor;
04833             delete pCrossHairCursor;
04834             pMoveCursor = NULL;
04835             return FALSE;           
04836         }
04837     }
04838     return TRUE;
04839 }

void OpNodePathEditBlob::DestroyCursors  )  [protected]
 

Deletes the path operation cursors.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/9/94
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: -

See also:
OpNodePathEditBlob::CreateCursors()

Definition at line 4858 of file pathedit.cpp.

04859 {
04860     if (pMoveCursor != NULL)
04861     {   // If one is NULL then the rest don't exist
04862         if (MyCurrentCursor != NULL)
04863         {
04864             CursorStack::GPop(CurrentCursorID);         
04865         }
04866         delete pMoveCursor;
04867         delete pCloseCursor;
04868         delete pCrossHairCursor;
04869         pMoveCursor = NULL;
04870         MyCurrentCursor = NULL;
04871         CurrentCursorID = 0;
04872     }
04873 }

void OpNodePathEditBlob::DoStartDragEdit NodePath OrigPath,
DocCoord  Anchor,
Spread pSpread
 

This is called to start a drag operation on an endpoint on a path.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> - latterly Peter
Date:
5/7/93
Parameters:
OrigPath - Pointer to the path we are about to edit [INPUTS] Anchor - The position of the mouse at the start of the Drag pSpread - The spread that the path is on

Definition at line 227 of file pathedit.cpp.

00228 {
00229     BOOL Success = TRUE;
00230     
00231     // We had better take a note of the starting point of the drag
00232     LastMousePos = Anchor;
00233     StartMousePos = Anchor;
00234     StartSpread  = pSpread;
00235 
00236     SelRange* theSelection = GetApplication ()->FindSelection ();
00237 
00238     BOOL selectionContainsMoulds = FALSE;
00239 
00240     if (theSelection)
00241     {
00242         // we need to do some special processing to handle moulds ....
00243 
00244         Node* pCurrentNode = (Node*) theSelection->FindFirst ();
00245 
00246         while (pCurrentNode)
00247         {
00248             if (IS_A (pCurrentNode, NodeMould))
00249             {
00250                 selectionContainsMoulds = TRUE;
00251                 pCurrentNode = NULL;
00252             }
00253             else
00254             {
00255                 pCurrentNode = (Node*) theSelection->FindNext (pCurrentNode);
00256             }
00257         }
00258     }
00259 
00260     if (!selectionContainsMoulds)
00261     {
00262         BevelTools::BuildListOfSelectedNodes(&OriginalPaths, CC_RUNTIME_CLASS(NodePath));
00263     }
00264     else
00265     {
00266         // now go and get those moulds baby !
00267         BevelTools::BuildListOfSelectedNodes(&OriginalPaths, CC_RUNTIME_CLASS(NodeMouldPath));
00268 
00269         // now, we also have to rescan the selection (again!) BUT this time without
00270         // the moulds
00271 
00272         Node* pCurrentNode = (Node*) theSelection->FindFirst ();
00273 
00274         while (pCurrentNode)
00275         {
00276             if (IS_A (pCurrentNode, NodeMould))
00277             {
00278                 pCurrentNode = (Node*) theSelection->FindNext (pCurrentNode);
00279             }
00280             else
00281             {
00282                 if (IS_A (pCurrentNode, NodePath))
00283                 {
00284                     NodeListItem* pInsert = new NodeListItem ();
00285                     
00286                     if (pInsert)    // and insert into the paths list ....
00287                     {
00288                         pInsert->pNode = pCurrentNode;
00289                         OriginalPaths.AddHead (pInsert);
00290                     }
00291                 }
00292                 
00293                 pCurrentNode = (Node*) theSelection->FindNext (pCurrentNode);
00294             }
00295         }
00296     }
00297 
00298     if (OriginalPaths.GetCount () == 1)
00299     //if (TRUE)
00300     {
00301         MultiplePaths = FALSE;
00302         
00303         OriginalPath = OrigPath;
00304 
00305         // Now calculate DragPoint and UpdatePoint
00306         if (Success)
00307         {
00308             PathFlags* Flags = OriginalPath->InkPath.GetFlagArray();
00309             PathVerb* Verbs = OriginalPath->InkPath.GetVerbArray();
00310             INT32 NumCoords = OriginalPath->InkPath.GetNumCoords();
00311 
00312             for (INT32 i=0;i<NumCoords;i++)
00313             {
00314                 if (Flags[i].IsEndPoint && Flags[i].IsSelected 
00315                                 && !(OriginalPath->InkPath.IsSubPathClosed(i) && (Verbs[i] == PT_MOVETO)) )
00316                 {
00317                     // If you are dragging a closepoint then you are actually dragging two points
00318                     // but we need to update the line tool as the user thinks they are dragging one.
00319                     // If we are on the opening moveto then just skip the tests.
00320                     if (DragPoint != -1)
00321                     {
00322                         UpdatePoint = -1;
00323                         DragPoint = -1;
00324                         break;
00325                     }
00326                     else
00327                     {
00328                         UpdatePoint = i;
00329                         DragPoint = i;
00330                     }
00331                 }
00332             }
00333             // On exit from that loop, DragPoint = -1 if there are multiple selected endpoints,
00334             // otherwise DragPoint is the index to the selected endpoint.  UpdatePoint is the
00335             // index of the point displaied in the Line tool
00336         }
00337 
00338         // Set the constrain point
00339         if (DragPoint != -1)
00340         {
00341             ConstrainPoint = OriginalPath->InkPath.GetCoordArray()[DragPoint];
00342 
00343             // Get the previous endpoint
00344             INT32 OtherEndpoint = DragPoint;
00345             if (OriginalPath->InkPath.FindPrevEndPoint(&OtherEndpoint))
00346                 ConstrainPrevPoint = OriginalPath->InkPath.GetCoordArray()[OtherEndpoint];
00347             else
00348                 ConstrainPrevPoint = ConstrainPoint;
00349 
00350             // Get the next endpoint
00351             OtherEndpoint = DragPoint;
00352             if (OriginalPath->InkPath.FindNextEndPoint(&OtherEndpoint))
00353                 ConstrainNextPoint = OriginalPath->InkPath.GetCoordArray()[OtherEndpoint];
00354             else
00355                 ConstrainNextPoint = ConstrainPoint;
00356         }
00357         else
00358         {
00359             ConstrainPoint = Anchor;
00360             ConstrainPrevPoint = Anchor;
00361             ConstrainNextPoint = Anchor;
00362         }
00363 
00364         // We also need to make a version of the path that we can change
00365         Success = BuildEditPath();
00366 
00367         // Create and send a change message about this path edit
00368         // This one is handled by moulds in their OnChildChange() function
00369         if (Success)
00370             Success = (EditObjChange.ObjChangeStarting(OrigPath,this,&EditPath,StartSpread,TRUE) == CC_OK);
00371 
00372         // Create and display the cursors for this operation
00373         if (Success)
00374             Success = CreateCursors();
00375         if (Success)
00376             ChangeCursor(pCrossHairCursor);
00377         
00378     //  // Render the bits of the path that are different
00379         DocRect EditPathBBox = EditPath.GetBoundingRect();
00380     //  if (Success)
00381     //      RenderPathEditBlobs(EditPathBBox, pSpread);
00382 
00383         // Tell the Dragging system that we need drags to happen
00384         if (Success)
00385             Success = StartDrag(DRAGTYPE_AUTOSCROLL, &EditPathBBox, &LastMousePos);
00386 
00387         if (!Success)
00388         {
00389             InformError();
00390             FailAndExecute();
00391             End();
00392         }
00393     }
00394     else
00395     {
00396         // lets try and keep things the same for the blobs parent as in the one selection case
00397         // BUT lets also try and do our extra stuff ....  I expect time MUCK UPS to occur !!!!
00398 
00399         MultiplePaths = TRUE;
00400         
00401         OriginalPath = OrigPath;
00402 
00403         // we need to make OrigPath the first one in our linked list ....
00404 
00405         NodeListItem* pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
00406 
00407         while (pCurrentOrig)
00408         {
00409             NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
00410 
00411             if (pOrigPath == OrigPath)
00412             {
00413                 NodeListItem* newHead = (NodeListItem*) OriginalPaths.RemoveItem (pCurrentOrig);
00414                 
00415                 OriginalPaths.AddHead (newHead);
00416 
00417                 pCurrentOrig = NULL;
00418             }
00419             else
00420             {
00421                 pCurrentOrig = (NodeListItem*) OriginalPaths.GetNext (pCurrentOrig);
00422             }
00423         }
00424 
00425         // Now calculate DragPoint and UpdatePoint
00426         if (Success)
00427         {
00428             NodeListItem* pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
00429 
00430             // CGS:  while loop taken out since we can only be 'drag sensitive' to the point
00431             // that is actually being dragged
00432 
00433             //while (pCurrentOrig)
00434             {
00435                 NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
00436                 
00437                 PathFlags* Flags = pOrigPath->InkPath.GetFlagArray();
00438                 PathVerb* Verbs = pOrigPath->InkPath.GetVerbArray();
00439                 INT32 NumCoords = pOrigPath->InkPath.GetNumCoords();
00440 
00441                 for (INT32 i=0;i<NumCoords;i++)
00442                 {
00443                     if (Flags[i].IsEndPoint && Flags[i].IsSelected 
00444                                     && !(pOrigPath->InkPath.IsSubPathClosed(i) && (Verbs[i] == PT_MOVETO)) )
00445                     {
00446                         // If you are dragging a closepoint then you are actually dragging two points
00447                         // but we need to update the line tool as the user thinks they are dragging one.
00448                         // If we are on the opening moveto then just skip the tests.
00449                         if (DragPoint != -1)
00450                         {
00451                             UpdatePoint = -1;
00452                             DragPoint = -1;
00453                             break;
00454                         }
00455                         else
00456                         {
00457                             UpdatePoint = i;
00458                             DragPoint = i;
00459                         }
00460                     }
00461                 }
00462 
00463             //  pCurrentOrig = (NodeListItem*) OriginalPaths.GetNext (pCurrentOrig);
00464             }
00465             // On exit from that loop, DragPoint = -1 if there are multiple selected endpoints,
00466             // otherwise DragPoint is the index to the selected endpoint.  UpdatePoint is the
00467             // index of the point displaied in the Line tool
00468         }
00469 
00470         // Set the constrain point - do this only for the path that was clicked on
00471         // Any guesses as to why?
00472 
00473         // Answer:  cause its the one that is being dragged!
00474         if (DragPoint != -1)
00475         {
00476             NodeListItem* pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
00477             NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
00478             
00479             ConstrainPoint = pOrigPath->InkPath.GetCoordArray()[DragPoint];
00480 
00481             // Get the previous endpoint
00482             INT32 OtherEndpoint = DragPoint;
00483             if (pOrigPath->InkPath.FindPrevEndPoint(&OtherEndpoint))
00484                 ConstrainPrevPoint = pOrigPath->InkPath.GetCoordArray()[OtherEndpoint];
00485             else
00486                 ConstrainPrevPoint = ConstrainPoint;
00487 
00488             // Get the next endpoint
00489             OtherEndpoint = DragPoint;
00490             if (pOrigPath->InkPath.FindNextEndPoint(&OtherEndpoint))
00491                 ConstrainNextPoint = pOrigPath->InkPath.GetCoordArray()[OtherEndpoint];
00492             else
00493                 ConstrainNextPoint = ConstrainPoint;
00494         }
00495         else
00496         {
00497             ConstrainPoint = Anchor;
00498             ConstrainPrevPoint = Anchor;
00499             ConstrainNextPoint = Anchor;
00500         }
00501 
00502         // We also need to make versions of the paths that we can change
00503         Success = BuildEditPaths();
00504 
00505         // Create and send a change message about this path edit
00506         // This one is handled by moulds in their OnChildChange() function
00507         if (Success)
00508         {
00509             NodeListItem* pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
00510             NodeListItem* pCurrentEdit = (NodeListItem*) EditPaths.GetHead ();
00511 
00512             while ((pCurrentOrig) && (pCurrentEdit))
00513             {
00514                 NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
00515                 Path* pEditPath = (Path*) (pCurrentEdit->pNode);
00516                 
00518                 
00519                 ObjChangePathEdit* NewEditObjChange = new ObjChangePathEdit;
00520                 
00521                 Success = (NewEditObjChange->ObjChangeStarting(pOrigPath,this,pEditPath,StartSpread,TRUE) == CC_OK);
00522 
00523                 NodeListItem* pInsert = new NodeListItem;
00524                 pInsert->pNode = (Node*) NewEditObjChange;
00525         
00526                 ObjChanges.AddTail (pInsert);
00527 
00529 
00530                 BOOL* NewDragStartVal = new BOOL;
00531                 *NewDragStartVal = FALSE;
00532                 
00533                 NodeListItem* pInsert2 = new NodeListItem;
00534                 pInsert2->pNode = (Node*) NewDragStartVal;
00535 
00536                 PathsDragStarted.AddTail (pInsert2);
00537 
00539 
00540                 if (Success)
00541                 {
00542                     pCurrentOrig = (NodeListItem*) OriginalPaths.GetNext (pCurrentOrig);
00543                     pCurrentEdit = (NodeListItem*) EditPaths.GetNext (pCurrentEdit);
00544                 }
00545                 else
00546                 {
00547                     pCurrentOrig = NULL;
00548                     pCurrentEdit = NULL;
00549                 }
00550 
00552                 
00553                 //delete (NewEditObjChange);
00554         //      delete (NewDragStartVal);
00555             }
00556         }
00557 
00558         // Create and display the cursors for this operation (only once - obviously)
00559         if (Success)
00560             Success = CreateCursors();
00561         if (Success)
00562             ChangeCursor(pCrossHairCursor);
00563         
00564     //  // Render the bits of the path that are different
00565         DocRect EditPathBBox;// = EditPath.GetBoundingRect();
00566 
00567         SelRange* Selected = GetApplication()->FindSelection();
00568 
00569         EditPathBBox = Selected->GetBlobBoundingRect ();
00570 
00571     //  if (Success)
00572     //      RenderPathEditBlobs(EditPathBBox, pSpread);
00573 
00574         // Tell the Dragging system that we need drags to happen
00575         if (Success)
00576             Success = StartDrag(DRAGTYPE_AUTOSCROLL, &EditPathBBox, &LastMousePos);
00577 
00578         if (!Success)
00579         {
00580             InformError();
00581             FailAndExecute();
00582             End();
00583         }
00584     }
00585 }

void OpNodePathEditBlob::DragFinished DocCoord  PointerPos,
ClickModifiers  ClickMods,
Spread pSpread,
BOOL  Success,
BOOL  bSolidDrag
[virtual]
 

This is called when a drag operation finishes.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/7/93
Parameters:
PointerPos - The position of the mouse at the end of the drag [INPUTS] ClickMods - the key modifiers being pressed Success - TRUE if the drag was terminated properly, FALSE if it was ended with the escape key being pressed
See also:
ClickModifiers

Reimplemented from Operation.

Reimplemented in OpNodePathAddEndpoint, OpReshapeOrAddPoint, and OpNewPath.

Definition at line 1169 of file pathedit.cpp.

01171 {
01172     if (!MultiplePaths)
01173     {
01174         if (DragStarted)
01175             RenderDraggingBlobs( EditPath.GetBoundingRect(), StartSpread );
01176         DestroyCursors();
01177         EndDrag();
01178         BeginSlowJob();
01179         ChangeCode Chge;                                       
01180 
01181         BOOL NotFailed = Success;
01182         
01183         // DY, if we are editing a brushed nodepath then we need a couple of extra actions
01184         AttrBrushType* pAttrBrush = GetAppliedBrush();
01185 
01186         if (NotFailed)
01187         {
01188             if (!DragStarted)
01189             {
01190                 INT32 i;
01191                 if (OriginalPath->InkPath.FindNearestPoint( PointerPos, 
01192                                                         POINTFLAG_ENDPOINTS | 
01193                                                         POINTFLAG_CONTROLPOINTS | 
01194                                                         POINTFLAG_ENDSFIRST,
01195                                                         &i)
01196                 )
01197                 {
01198                     // Deselect all but the clicked endpoint
01199                     OriginalPath->InkPath.RenderPathSelectedControlBlobs(StartSpread);
01200                     OriginalPath->InkPath.ClearSubSelection();
01201                     PathFlags* pFlags = OriginalPath->InkPath.GetFlagArray();
01202                     pFlags[i].IsSelected = TRUE;
01203                     OriginalPath->InkPath.EnsureSelection(TRUE);
01204                     OriginalPath->InkPath.RenderPathSelectedControlBlobs(StartSpread);
01205 
01206                     // Send a sel-changed message so tools update (hello jason  8-)
01207                     GetApplication()->FindSelection()->Update();
01208 
01209                     // Kill the op so we dont appear in the undo history
01210                     FailAndExecute();
01211                     End();
01212                     return;
01213                 }
01214             }
01215             else
01216             {
01217                 NotFailed = DoStartSelOp(TRUE,TRUE);
01218 
01219                 // Create and send a change message about this path edit
01220                 if (NotFailed)
01221                 {
01222                     ObjChangeFlags cFlags;
01223                     cFlags.TransformNode = TRUE;
01224                     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,OriginalPath,this);
01225                     NotFailed = OriginalPath->AllowOp(&ObjChange, TRUE);
01226                 }
01227 
01228     //          // Store the paths sub-selection state
01229     //          if (NotFailed)
01230     //              NotFailed = (StorePathSubSelStateAction::DoRecord(this, &UndoActions, &OriginalPath->InkPath) != AC_FAIL);
01231 
01232                 // Check we are dealing with a node path. If not, we shouldn't optimise the redraw.
01233                 // Really we should ask the node whether it can cope with optimised redraw. This means
01234                 // whether its correct simply to redraw the changed rectangular section around the moved
01235                 // coordinate. For envelope and perspective moulds whose shapes are govened by derived
01236                 // path objects its not correct to redraw optimally as this can result in sections of the
01237                 // object being left undrawn when the whole surface / contents have changed.
01238                 BOOL OptimiseRedraw = CopyNeedToRenderFlags() && !(EndSnapped || SnapToAnother);
01239                 if (!IS_A(OriginalPath,NodePath))
01240                     OptimiseRedraw = FALSE;
01241                 
01242                 // if we are editing a brush we don't want to optimise either, as it redraws incorrectly
01243                 if (pAttrBrush != NULL)
01244                     OptimiseRedraw = FALSE;
01245                 // We had better copy the path back over the original and re-calc the bounding box
01246                 // Force a re-draw of the place where the path used to be
01247                 if (NotFailed)
01248                     NotFailed = RecalcBoundsAction::DoRecalc(this, &UndoActions, OriginalPath, OptimiseRedraw) != AC_FAIL;
01249 
01250 
01251                 //if we are editing a brushed nodepath we need to have this here for the undo to work
01252                 if (pAttrBrush != NULL && pAttrBrush->IsTimeStamping() && NotFailed)
01253                 {
01254                     UpdateBrushAction* pAction;
01255                     NotFailed = (UpdateBrushAction::Init(this, &UndoActions,  OriginalPath, &pAction) != AC_FAIL);
01256                 }
01257                 // If the EndSnapped flag is set, we have to set the PT_CLOSEFIGURE flag in the last
01258                 // element of the copied path
01259                 if (NotFailed && EndSnapped)
01260                     SnapEndsTogether();
01261         
01262                 // Go and copy the edited path back over the original path
01263                 if (NotFailed)
01264                     NotFailed = CopyEditedPathBack();
01265 
01266                 // If the ends snapped, set the filled bit on the path
01267                 if (NotFailed)
01268                     NotFailed = FillPathIfEndsSnapped();
01269                 if (NotFailed)
01270                     NotFailed = JoinWithOtherPath();
01271 
01272                 if (NotFailed)
01273                 {
01274                     // Recalculate the path's bounding box
01275                     OriginalPath->InvalidateBoundingRect();
01276                     SelRange *Sel = GetApplication()->FindSelection();
01277                     Sel->UpdateBounds();
01278 
01279                     // Expand the pasteboard as necessary to include the new object bounds
01280                     DocRect NewBounds = Sel->GetBoundingRect(TRUE);
01281                     ERROR3IF(pSpread == NULL, "Unexpectedly NULL spread pointer");
01282                     pSpread->ExpandPasteboardToInclude(NewBounds);
01283 
01284                     // Force a redraw of the place where the path is now.
01285                     NotFailed = RecordBoundsAction::DoRecord(this, &UndoActions, OriginalPath, OptimiseRedraw) != AC_FAIL;
01286                 }
01287             }
01288         }
01289 
01290         // DY 9/99 Check to see if we are editing a blend on a curve, if so we may wish to 
01291         // change the number of steps in the blend (making use of the path distance).
01292         NodeGroup* pParent = GetGroupParentOfCurve();
01293         
01294         if (pParent != NULL)
01295         {
01296             if (pParent->IS_KIND_OF(NodeBlend))
01297             {
01298                 if (NotFailed)
01299                     InsertChangeBlendStepsAction((NodeBlend*)pParent);               
01300             }
01301         
01302         }
01303 
01304     
01305 
01306         // Inform all the parents of this node that it has been changed.
01307         if (NotFailed)
01308         {
01309             ObjChangeFlags ChgeFlags;
01310             EditObjChange.Define(OBJCHANGE_FINISHED,ChgeFlags,OriginalPath,this,&EditPath,StartSpread);
01311             NotFailed = UpdateChangedNodes(&EditObjChange);
01312         }
01313         else
01314         {
01315             if (EditObjChange.ChangeMask.Finished)
01316                 Chge=EditObjChange.ObjChangeFailed(OriginalPath,this,&EditPath,StartSpread,TRUE);
01317         }
01318 
01319         
01320         if (!NotFailed) 
01321             FailAndExecute();
01322 
01323         OriginalPaths.DeleteAll ();
01324 
01325         GetApplication()->UpdateSelection();
01326         End();
01327     }
01328     else
01329     {
01330         NodeListItem* pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
01331         NodeListItem* pCurrentEdit = (NodeListItem*) EditPaths.GetHead ();
01332         NodeListItem* pCurrentChange = (NodeListItem*) ObjChanges.GetHead ();
01333         NodeListItem* pCurrentDragS = (NodeListItem*) PathsDragStarted.GetHead ();
01334 
01335         DocCoord Offset;
01336 
01337         DestroyCursors();
01338         EndDrag();
01339         BeginSlowJob();
01340         ChangeCode Chge;           
01341 
01342         BOOL NotFailed = Success;
01343         
01344         // DY, if we are editing a brushed nodepath then we need a couple of extra actions
01345         AttrBrushType* pAttrBrush = GetAppliedBrush();
01346 
01347         if (NotFailed)
01348             NotFailed = DoStartSelOp(TRUE,TRUE);
01349 
01350         while ((pCurrentOrig) && (pCurrentEdit) && (pCurrentChange) && (pCurrentDragS))
01351         {
01352             NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
01353             Path* pEditPath = (Path*) (pCurrentEdit->pNode);
01354 //          ObjChangePathEdit* pObjChange = (ObjChangePathEdit*) (pCurrentChange->pNode);
01355             BOOL* pDragStarted = (BOOL*) (pCurrentDragS->pNode);
01356 
01357             if (*pDragStarted == TRUE)
01358             {
01359                 RenderDraggingBlobs( pEditPath/*EditPath.GetBoundingRect()*/, StartSpread );
01360             }
01361 
01362             if (NotFailed)
01363             {
01364                 if (*pDragStarted == FALSE)
01365                 {
01366                     INT32 i;
01367                     if (pOrigPath->InkPath.FindNearestPoint(PointerPos, 
01368                                                             POINTFLAG_ENDPOINTS | 
01369                                                             POINTFLAG_CONTROLPOINTS | 
01370                                                             POINTFLAG_ENDSFIRST,
01371                                                             &i)
01372                     )
01373                     {
01374                         // Deselect all but the clicked endpoint
01375                         pOrigPath->InkPath.RenderPathSelectedControlBlobs(StartSpread);
01376                         pOrigPath->InkPath.ClearSubSelection();
01377                         PathFlags* pFlags = pOrigPath->InkPath.GetFlagArray();
01378                         pFlags[i].IsSelected = TRUE;
01379                         pOrigPath->InkPath.EnsureSelection(TRUE);
01380                         pOrigPath->InkPath.RenderPathSelectedControlBlobs(StartSpread);
01381 
01382                         // Send a sel-changed message so tools update (hello jason  8-)
01383                         GetApplication()->FindSelection()->Update();
01384 
01385                         // Kill the op so we dont appear in the undo history
01386                         FailAndExecute();
01387                         End();
01388                         return;
01389                     }
01390                 }
01391                 else
01392                 {
01393                     //NotFailed = DoStartSelOp(TRUE,TRUE);
01394 
01395                     // Create and send a change message about this path edit
01396                     if (NotFailed)
01397                     {
01398                         ObjChangeFlags cFlags;
01399                         cFlags.TransformNode = TRUE;
01400                         ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,pOrigPath,this);
01401                         NotFailed = pOrigPath->AllowOp(&ObjChange, TRUE);
01402                     }
01403 
01404         //          // Store the paths sub-selection state
01405         //          if (NotFailed)
01406         //              NotFailed = (StorePathSubSelStateAction::DoRecord(this, &UndoActions, &OriginalPath->InkPath) != AC_FAIL);
01407 
01408                     // Check we are dealing with a node path. If not, we shouldn't optimise the redraw.
01409                     // Really we should ask the node whether it can cope with optimised redraw. This means
01410                     // whether its correct simply to redraw the changed rectangular section around the moved
01411                     // coordinate. For envelope and perspective moulds whose shapes are govened by derived
01412                     // path objects its not correct to redraw optimally as this can result in sections of the
01413                     // object being left undrawn when the whole surface / contents have changed.
01414                     BOOL OptimiseRedraw = CopyNeedToRenderFlags(pOrigPath, pEditPath) && !(EndSnapped || SnapToAnother);
01415                     if (!IS_A(pOrigPath,NodePath))
01416                         OptimiseRedraw = FALSE;
01417                     
01418                     // if we are editing a brush we don't want to optimise either, as it redraws incorrectly
01419                     if (pAttrBrush != NULL)
01420                         OptimiseRedraw = FALSE;
01421 
01422                     // We had better copy the path back over the original and re-calc the bounding box
01423                     // Force a re-draw of the place where the path used to be
01424                     if (NotFailed)
01425                         NotFailed = RecalcBoundsAction::DoRecalc(this, &UndoActions, pOrigPath, OptimiseRedraw) != AC_FAIL;
01426 
01427 
01428                     //if we are editing a brushed nodepath we need to have this here for the undo to work
01429                     if (pAttrBrush != NULL && pAttrBrush->IsTimeStamping() && NotFailed)
01430                     {
01431                         UpdateBrushAction* pAction;
01432                         NotFailed = (UpdateBrushAction::Init(this, &UndoActions,  pOrigPath, &pAction) != AC_FAIL);
01433                     }
01434                     
01435                     if (pCurrentOrig == (NodeListItem*) OriginalPaths.GetHead ())
01436                     {
01437                         // If the EndSnapped flag is set, we have to set the PT_CLOSEFIGURE flag in the last
01438                         // element of the copied path
01439                         if (NotFailed && EndSnapped)
01440                         {   
01441                             SnapEndsTogether (pEditPath);
01442                         }
01443                     }
01444                 
01445                     // Go and copy the edited path back over the original path
01446                     if (NotFailed)
01447                         NotFailed = CopyEditedPathBack(pOrigPath, pEditPath);
01448 
01449                     if (pCurrentOrig == (NodeListItem*) OriginalPaths.GetHead ())
01450                     {
01451                         // If the ends snapped, set the filled bit on the path
01452                         if (NotFailed)
01453                             NotFailed = FillPathIfEndsSnapped(pOrigPath);
01454                     }
01455 
01456                     // CGS:  BUT, we need to delay the snapping of a control point to another
01457                     // paths until here.  These is because the path that we are snapping to
01458                     // could have also of been dragged; and it is NOT guaranteed to have been
01459                     // updated until now ....
01460 
01461                     BOOL useHeadPath = FALSE;
01462                     NodePath*   pHeadPath = NULL;
01463                     NodePath**  hHeadPath = NULL;
01464 
01465                     if (pOrigPath == SnapToPath)
01466                     {
01467                         if (NotFailed)
01468                         {
01469                             NodeListItem* pHeadOrig = (NodeListItem*) OriginalPaths.GetHead ();
01470                             /*NodePath**/ pHeadPath = (NodePath*) (pHeadOrig->pNode);
01471                             hHeadPath = &pHeadPath;
01472 
01473                             NotFailed = JoinWithOtherPath(hHeadPath);
01474                             
01475                             if (NotFailed)
01476                             {
01477                                 useHeadPath = TRUE;
01478                             }
01479                         }
01480                     }
01481 
01482                     if (NotFailed)
01483                     {
01484                         // Recalculate the path's bounding box
01485                         pOrigPath->InvalidateBoundingRect();
01486                         SelRange *Sel = GetApplication()->FindSelection();
01487                         Sel->UpdateBounds();
01488 
01489                         // Expand the pasteboard as necessary to include the new object bounds
01490                         DocRect NewBounds = Sel->GetBoundingRect();
01491                         ERROR3IF(pSpread == NULL, "Unexpectedly NULL spread pointer");
01492                         pSpread->ExpandPasteboardToInclude(NewBounds);
01493 
01494                         if (!useHeadPath)
01495                         {
01496                             // Force a redraw of the place where the path is now.
01497                             NotFailed = RecordBoundsAction::DoRecord(this, &UndoActions, pOrigPath, OptimiseRedraw) != AC_FAIL;
01498                         }
01499                         else
01500                         {
01501                             //NodeListItem* pHeadOrig = (NodeListItem*) OriginalPaths.GetHead ();
01502                             //NodePath* pHeadPath = (NodePath*) (pHeadOrig->pNode);
01503                             
01504                             // Force a redraw of the place where the path is now.
01505                             NotFailed = RecordBoundsAction::DoRecord(this, &UndoActions, (*hHeadPath), OptimiseRedraw) != AC_FAIL;
01506                         }
01507                     }
01508                 }
01509             }
01510 
01511             // DY 9/99 Check to see if we are editing a blend on a curve, if so we may wish to 
01512             // change the number of steps in the blend (making use of the path distance).
01513             NodeGroup* pParent = GetGroupParentOfCurve(pOrigPath);
01514             
01515             if (pParent != NULL)
01516             {
01517                 if (pParent->IS_KIND_OF(NodeBlend))
01518                 {
01519                     if (NotFailed)
01520                         InsertChangeBlendStepsAction((NodeBlend*)pParent);               
01521                 }
01522             }
01523 
01524             // Inform all the parents of this node that it has been changed.
01525             if (NotFailed)
01526             {
01527                 ObjChangeFlags ChgeFlags;
01528                 EditObjChange.Define(OBJCHANGE_FINISHED,ChgeFlags,pOrigPath,this,pEditPath,StartSpread);
01529                 NotFailed = UpdateChangedNodes(&EditObjChange);
01530             }
01531             else
01532             {
01533                 if (EditObjChange.ChangeMask.Finished)
01534                     Chge=EditObjChange.ObjChangeFailed(pOrigPath,this,pEditPath,StartSpread,TRUE);
01535             }
01536 
01537             pCurrentOrig = (NodeListItem*) OriginalPaths.GetNext (pCurrentOrig);
01538             pCurrentEdit = (NodeListItem*) EditPaths.GetNext (pCurrentEdit);
01539             pCurrentChange = (NodeListItem*) ObjChanges.GetNext (pCurrentChange);
01540             pCurrentDragS = (NodeListItem*) PathsDragStarted.GetNext (pCurrentDragS);
01541         }
01542         
01543         if (!NotFailed) 
01544             FailAndExecute();
01545 
01546         GetApplication()->UpdateSelection();
01547 
01548         // now we need to handle destruction ourselves ....
01549 
01550 //      pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
01551         pCurrentEdit = (NodeListItem*) EditPaths.GetHead ();
01552         pCurrentChange = (NodeListItem*) ObjChanges.GetHead ();
01553         pCurrentDragS = (NodeListItem*) PathsDragStarted.GetHead ();
01554 
01555         while (/*(pCurrentOrig) &&*/ (pCurrentEdit) && (pCurrentChange) && (pCurrentDragS))
01556         {
01557 //          NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
01558             Path* pEditPath = (Path*) (pCurrentEdit->pNode);
01559             ObjChangePathEdit* pObjChange = (ObjChangePathEdit*) (pCurrentChange->pNode);
01560             BOOL* pDragStarted = (BOOL*) (pCurrentDragS->pNode);
01561 
01562     //      delete (pCurrentOrig->pNode);
01563             delete (pEditPath);
01564             delete (pObjChange);
01565             delete (pDragStarted);
01566             
01567 //          pCurrentOrig = (NodeListItem*) OriginalPaths.GetNext (pCurrentOrig);
01568             pCurrentEdit = (NodeListItem*) EditPaths.GetNext (pCurrentEdit);
01569             pCurrentChange = (NodeListItem*) ObjChanges.GetNext (pCurrentChange);
01570             pCurrentDragS = (NodeListItem*) PathsDragStarted.GetNext (pCurrentDragS);
01571         }
01572 
01573         OriginalPaths.DeleteAll ();
01574         EditPaths.DeleteAll ();
01575         ObjChanges.DeleteAll ();
01576         PathsDragStarted.DeleteAll ();
01577 
01578         End();
01579     }
01580 }

void OpNodePathEditBlob::DragPointerMove DocCoord  PointerPos,
ClickModifiers  ClickMods,
Spread pSpread,
BOOL  bSolidDrag
[virtual]
 

This is called every time the mouse moves, during a drag.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/7/93
Parameters:
PointerPos - The current position of the mouse in Doc Coords [INPUTS] ClickMods - Which key modifiers are being pressed
See also:
ClickModifiers

Reimplemented from Operation.

Reimplemented in OpNodePathEditControlBlob, and OpReshapeOrAddPoint.

Definition at line 602 of file pathedit.cpp.

00603 {
00604     if (!MultiplePaths)
00605     {
00606         // If drag has moved onto a different spread, convert the coord to be relative to the
00607         // original spread.
00608         if (pSpread != StartSpread)
00609             PointerPos = MakeRelativeToSpread(StartSpread, pSpread, PointerPos);
00610 
00611         Path TempPath;
00612 
00613         // inform the parent a change is happening
00614         if (EditObjChange.ChangeMask.EorBlobs)
00615         {
00616             ChangeCode Chge = EditObjChange.RenderCurrentBlobs(OriginalPath,this,&EditPath,StartSpread,TRUE);
00617             if (Chge!=CC_OK)
00618                 return;
00619             // Create a local copy of the edit path
00620             if (!TempPath.Initialise(EditPath.GetNumCoords(), 12))
00621                 return;
00622             TempPath.CopyPathDataFrom(&EditPath);
00623         }
00624 
00625         // Rub out the old EORed version of the path
00626         if (DragStarted)
00627             RenderPathEditBlobs( EditPath.GetBoundingRect(), StartSpread );
00628         else
00629             DragStarted = TRUE;
00630 
00631         // Here is where we do all the snapping to grids and endpoints
00632         // and constrain. First we check for snapping to line ends, then
00633         // we check constrain, then we check grid snapping
00634 
00635         EndSnapped = FALSE;         // TRUE if this point snaps to the other end
00636         SnapToAnother = FALSE;      // TRUE if this point snaps to another line end
00637         SnapToLineOrCurve = FALSE;  // No snapped other line
00638 
00639         // We might be snapping to an endpoint if the point we're dragging around is either
00640         // a moveto, or is the last point in the subpath. We will also only snap if there is
00641         // only one point selected on the path
00642 
00643         DocRect PointerBlobRect;
00644         GetApplication()->GetBlobManager()->GetBlobRect(PointerPos,&PointerBlobRect);
00645 
00646         DocCoord* Coords = EditPath.GetCoordArray();
00647 //      PathFlags* Flags = EditPath.GetFlagArray();
00648         PathVerb* Verbs = EditPath.GetVerbArray();
00649         INT32 NumCoords = EditPath.GetNumCoords();
00650 
00651         INT32 i;
00652         if (DragPoint != -1)
00653         {
00654             // Look to see if the selected point is a real endpoint
00655             if (Verbs[DragPoint] == PT_MOVETO)
00656             {
00657                 // This is the start element of the path
00658                 i = DragPoint;
00659                 if (!EditPath.IsSubPathClosed(i))
00660                 {
00661                     INT32 NextEndpoint = i;
00662                     if (EditPath.FindNextEndPoint(&NextEndpoint))
00663                     {
00664                         EditPath.FindEndElOfSubPath(&i);        // i indexes to the end element
00665 
00666                         // If this sub-path is one element long then closing it is not allowed
00667                         if ((i != NextEndpoint) && PointerBlobRect.ContainsCoord(Coords[i]))
00668                         {
00669                             PointerPos.x = Coords[i].x + LastMousePos.x - Coords[DragPoint].x;
00670                             PointerPos.y = Coords[i].y + LastMousePos.y - Coords[DragPoint].y;
00671                             EndSnapped = TRUE;
00672                         }
00673                     }
00674                 }
00675             }
00676             else if (DragPoint+1 == NumCoords || Verbs[DragPoint+1] == PT_MOVETO)
00677             {
00678                 // This is the last element in the sub-path
00679                 i = DragPoint;
00680                 if (!EditPath.IsSubPathClosed(i))
00681                 {
00682                     INT32 PrevEndpoint = i;
00683                     if (EditPath.FindPrevEndPoint(&PrevEndpoint))
00684                     {
00685                         EditPath.FindStartOfSubPath(&i);            // i is the index of the start of the sub-path
00686             
00687                         // If this sub-path is one element long then closing it is not allowed
00688                         if ((i != PrevEndpoint) && PointerBlobRect.ContainsCoord(Coords[i]))
00689                         {
00690                             PointerPos.x = Coords[i].x + LastMousePos.x - Coords[DragPoint].x;
00691                             PointerPos.y = Coords[i].y + LastMousePos.y - Coords[DragPoint].y;
00692                             EndSnapped = TRUE;
00693                         }
00694                     }
00695                 }
00696             }
00697         }
00698         
00699         // That detects snapping to the opposite endpoint, but what about snapping to another
00700         // endpoint altogether? Time to check for that eventuality
00701         if (!EndSnapped && DragPoint != -1 && (Verbs[DragPoint] == PT_MOVETO || DragPoint+1 == NumCoords || Verbs[DragPoint+1] == PT_MOVETO) )
00702         {
00703             // Get a snapshot of the selection
00704             SelRange* Selected = GetApplication()->FindSelection();
00705             Node* pNode = Selected->FindFirst();
00706             INT32 SubIndex,SubEnd;
00707             while (pNode)
00708             {
00709                 if ((pNode->FindParentSpread() == StartSpread) && 
00710                     (pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodePath)) /*&&
00711                     (pNode != OriginalPath)*/ )
00712                 {
00713                     Path* ThisPath = &(((NodePath*)pNode)->InkPath);
00714                     INT32 ThisNum = ThisPath->GetNumCoords();
00715                     SubIndex = 0;
00716                     SubEnd = 0;
00717                     while (SubIndex<ThisNum)        
00718                     {
00719                         DocCoord tempStart,tempEnd;
00720                         ThisPath->SetPathPosition(SubIndex);    // Set the path's internal pos index
00721                         if (ThisPath->GetSubPathEnds(&tempStart, &tempEnd))
00722                         {
00723                             SubEnd = ThisPath->GetPathPosition();
00724                             // Now SubIndex is the index of the first, and SubEnd is the index
00725                             // of the last element (N.B. might be a curveto, in which case add 2)
00726                             if (ThisPath->GetVerb() == PT_BEZIERTO)
00727                                 SubEnd+=2;
00728 
00729                             BOOL ClosedPath = (ThisPath->GetVerbArray()[SubEnd] & PT_CLOSEFIGURE) ;
00730 
00731                             // Now compare start and end with pointer position, but not if this
00732                             // subpath is the currently dragging subpath
00733                             if ( !ClosedPath &&
00734                                  ( (pNode != OriginalPath) ||
00735                                    ((pNode == OriginalPath) && (DragPoint != SubIndex) && (DragPoint != SubEnd)) ) )
00736                             {
00737                                 if (PointerBlobRect.ContainsCoord(tempStart))
00738                                 {
00739                                     break;
00740                                 }
00741                                 if (PointerBlobRect.ContainsCoord(tempEnd))
00742                                 {
00743                                     SubIndex = SubEnd;
00744                                     break;
00745                                 }
00746                             }
00747                         }
00748                         else
00749                         {
00750                             SubEnd = ThisPath->GetPathPosition();
00751                         }
00752                         SubIndex = SubEnd+1;        // Points at start of next subpath
00753                                                     // or top of whole path
00754                     }
00755                     // if SubIndex < ThisNum we must have found a matching coord
00756                     // so that's what we'll snap to
00757                     if (SubIndex < ThisNum)
00758                         break;              // Exit the outer while condition
00759                 }
00760                 pNode = Selected->FindNext(pNode);
00761             }
00762             // At this point, if pNode == NULL we haven't snapped to anything
00763             // otherwise pNode is the path we've snapped to, and SubIndex is the index
00764             // of the point we've snapped to
00765             if (pNode)
00766             {
00767                 // if the snap to path is the path being edited check that it has the same number of points!
00768                 if (((NodePath*)pNode == OriginalPath) && (OriginalPath->InkPath.GetNumCoords() != EditPath.GetNumCoords()))
00769                 {
00770 //                  PATRACE( _T("Attempted to join an edited path!\n"));
00771                     // The problem is that if the OriginalPath has been edited by adding an endpoint then
00772                     // SnapToIndex will be wrong as it counted along the original path, not the edited one....
00773                 }
00774                 else
00775                 {
00776                     SnapToAnother = TRUE;
00777                     SnapToPath = (NodePath*)pNode;
00778                     SnapToIndex = SubIndex;
00779                     SnapToPath->InkPath.SetPathPosition(SnapToIndex);
00780                     PointerPos.x = SnapToPath->InkPath.GetCoord().x + LastMousePos.x - Coords[DragPoint].x;
00781                     PointerPos.y = SnapToPath->InkPath.GetCoord().y + LastMousePos.y - Coords[DragPoint].y;
00782                 }
00783             }
00784         }
00785 
00786         // We don't allow closed paths consiting of two straight segments
00787         if (EndSnapped && NumCoords < 4)
00788             EndSnapped = FALSE;
00789             
00790         if ((EndSnapped || SnapToAnother) && (pMoveCursor != NULL))
00791             ChangeCursor(pCloseCursor);
00792         else
00793             ChangeCursor(pCrossHairCursor);
00794         
00795         // Now constrain the mouse point
00796         ERROR3IF(ConstrainPoint == DocCoord(-1,-1),"ConstrainPoint wasn't set");
00797         ERROR3IF(ConstrainPrevPoint == DocCoord(-1,-1),"ConstrainPrevPoint wasn't set");
00798         ERROR3IF(ConstrainNextPoint == DocCoord(-1,-1),"ConstrainNextPoint wasn't set");
00799         if (!EndSnapped && ClickMods.Constrain)
00800         {
00801             if (ClickMods.Adjust)
00802             {
00803                 if (ClickMods.Alternative1 || ClickMods.Alternative2)
00804                     DocView::ConstrainToAngle(ConstrainNextPoint, &PointerPos);
00805                 else
00806                     DocView::ConstrainToAngle(ConstrainPrevPoint, &PointerPos);
00807             }
00808             else
00809                 DocView::ConstrainToAngle(ConstrainPoint, &PointerPos);
00810         }
00811 
00812         // Only snap to grid if we didn't snap to the end of a path
00813         if (!EndSnapped)
00814             DocView::SnapCurrent(StartSpread,&PointerPos);
00815 
00816         // This is the bit where we go off and re-calculate the paths position,
00817         // based on how much the mouse has moved
00818         DocCoord Offset;
00819         Offset.x = PointerPos.x - LastMousePos.x;
00820         Offset.y = PointerPos.y - LastMousePos.y;
00821 
00822         RecalculatePath(Offset, EndSnapped, DragPoint);
00823 
00824         if (EditObjChange.ChangeMask.EorBlobs)
00825         {
00826             ChangeCode Chge = EditObjChange.RenderChangedBlobs(OriginalPath,this,&EditPath,StartSpread,TRUE);
00827             if (Chge!=CC_OK)
00828             {
00829                 // replace the old edit path
00830                 EditPath.CopyPathDataFrom(&TempPath);
00831                 RenderPathEditBlobs( EditPath.GetBoundingRect(), StartSpread );
00832                 return;
00833             }
00834         }
00835 
00836         // Update the Last Mouse Position
00837         LastMousePos = PointerPos;
00838 
00839         // Draw in the new version of the path
00840         RenderPathEditBlobs( EditPath.GetBoundingRect(), StartSpread );
00841 
00842         // If there is just one selected point being dragged then we should show
00843         // its new position in the line tool infobar.
00844         if (UpdatePoint != -1)
00845             BROADCAST_TO_ALL(PathEditedMsg(&EditPath, pSpread, UpdatePoint));
00846 
00847         SetStatusLineHelp();
00848     }
00849     else
00850     {   
00851         NodeListItem* pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
00852         NodeListItem* pCurrentEdit = (NodeListItem*) EditPaths.GetHead ();
00853         NodeListItem* pCurrentChange = (NodeListItem*) ObjChanges.GetHead ();
00854         NodeListItem* pCurrentDragS = (NodeListItem*) PathsDragStarted.GetHead ();
00855 
00856         DocCoord Offset(0,0);
00857 
00858         while ((pCurrentOrig) && (pCurrentEdit) && (pCurrentChange) && (pCurrentDragS))
00859         {
00860             NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
00861             Path* pEditPath = (Path*) (pCurrentEdit->pNode);
00862             ObjChangePathEdit* pObjChange = (ObjChangePathEdit*) (pCurrentChange->pNode);
00863             BOOL* pDragStarted = (BOOL*) (pCurrentDragS->pNode);
00864 
00866 
00867             // If drag has moved onto a different spread, convert the coord to be relative to the
00868             // original spread.
00869             if (pSpread != StartSpread)
00870                 PointerPos = MakeRelativeToSpread(StartSpread, pSpread, PointerPos);
00871 
00872             Path TempPath;
00873 
00874             // inform the parent a change is happening
00875             if (pObjChange->ChangeMask.EorBlobs)
00876             {
00877                 ChangeCode Chge = pObjChange->RenderCurrentBlobs(pOrigPath,this,pEditPath,StartSpread,TRUE);
00878                 if (Chge!=CC_OK)
00879                     return;
00880                 // Create a local copy of the edit path
00881                 if (!TempPath.Initialise(pEditPath->GetNumCoords(), 12))
00882                     return;
00883                 TempPath.CopyPathDataFrom(pEditPath);
00884             }
00885 
00886             // Rub out the old EORed version of the path
00887             if (*pDragStarted == TRUE)
00888             {
00889                 RenderPathEditBlobs(pEditPath, /*pEditPath->GetBoundingRect(),*/ StartSpread );
00890             }
00891             else
00892             {
00893                 *pDragStarted = TRUE;
00894 //              pCurrentDragS->pNode = (Node*) pDragStarted;
00895             }
00896 
00897             DocRect PointerBlobRect;
00898             GetApplication()->GetBlobManager()->GetBlobRect(PointerPos,&PointerBlobRect);
00899 
00900             DocCoord* Coords = pEditPath->GetCoordArray();
00901 //          PathFlags* Flags = pEditPath->GetFlagArray();
00902             PathVerb* Verbs = pEditPath->GetVerbArray();
00903             INT32 NumCoords = pEditPath->GetNumCoords();
00904 
00905             if (pCurrentOrig == (NodeListItem*) OriginalPaths.GetHead ())
00906             {
00907                 // CGS:  all of the operations to do with snapping to grid, snapping to opposite
00908                 // end point and snapping to another lines endpoint are relevant only for
00909                 // that control point that the drag was initiated from ....
00910 
00911                 // Here is where we do all the snapping to grids and endpoints
00912                 // and constrain. First we check for snapping to line ends, then
00913                 // we check constrain, then we check grid snapping
00914 
00915                 EndSnapped = FALSE;         // TRUE if this point snaps to the other end
00916                 SnapToAnother = FALSE;      // TRUE if this point snaps to another line end
00917                 SnapToLineOrCurve = FALSE;  // No snapped other line
00918 
00919                 // We might be snapping to an endpoint if the point we're dragging around is either
00920                 // a moveto, or is the last point in the subpath. We will also only snap if there is
00921                 // only one point selected on the path
00922 
00923                 INT32 i;
00924                 if (DragPoint != -1)
00925                 {
00926                     // Look to see if the selected point is a real endpoint
00927                     if (Verbs[DragPoint] == PT_MOVETO)
00928                     {
00929                         // This is the start element of the path
00930                         i = DragPoint;
00931                         if (!pEditPath->IsSubPathClosed(i))
00932                         {
00933                             INT32 NextEndpoint = i;
00934                             if (pEditPath->FindNextEndPoint(&NextEndpoint))
00935                             {
00936                                 pEditPath->FindEndElOfSubPath(&i);      // i indexes to the end element
00937 
00938                                 // If this sub-path is one element long then closing it is not allowed
00939                                 if ((i != NextEndpoint) && PointerBlobRect.ContainsCoord(Coords[i]))
00940                                 {
00941                                     PointerPos.x = Coords[i].x + LastMousePos.x - Coords[DragPoint].x;
00942                                     PointerPos.y = Coords[i].y + LastMousePos.y - Coords[DragPoint].y;
00943                                     EndSnapped = TRUE;
00944                                 }
00945                             }
00946                         }
00947                     }
00948                     else if (DragPoint+1 == NumCoords || Verbs[DragPoint+1] == PT_MOVETO)
00949                     {
00950                         // This is the last element in the sub-path
00951                         i = DragPoint;
00952                         if (!pEditPath->IsSubPathClosed(i))
00953                         {
00954                             INT32 PrevEndpoint = i;
00955                             if (pEditPath->FindPrevEndPoint(&PrevEndpoint))
00956                             {
00957                                 pEditPath->FindStartOfSubPath(&i);          // i is the index of the start of the sub-path
00958                     
00959                                 // If this sub-path is one element long then closing it is not allowed
00960                                 if ((i != PrevEndpoint) && PointerBlobRect.ContainsCoord(Coords[i]))
00961                                 {
00962                                     PointerPos.x = Coords[i].x + LastMousePos.x - Coords[DragPoint].x;
00963                                     PointerPos.y = Coords[i].y + LastMousePos.y - Coords[DragPoint].y;
00964                                     EndSnapped = TRUE;
00965                                 }
00966                             }
00967                         }
00968                     }
00969                 }
00970             
00971                 // That detects snapping to the opposite endpoint, but what about snapping to another
00972                 // endpoint altogether? Time to check for that eventuality
00973                 if (!EndSnapped && DragPoint != -1 && (Verbs[DragPoint] == PT_MOVETO || DragPoint+1 == NumCoords || Verbs[DragPoint+1] == PT_MOVETO) )
00974                 {
00975                     // Get a snapshot of the selection
00976                     SelRange* Selected = GetApplication()->FindSelection();
00977 
00978                     // do something extra in here ....
00979 
00980                     Node* pNode = Selected->FindFirst();
00981                     INT32 SubIndex,SubEnd;
00982                     while (pNode)
00983                     {
00985                         if ((pNode->FindParentSpread() == StartSpread) && 
00986                             (pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodePath)) /*&&
00987                     (pNode != OriginalPath)*/ )
00988                         {
00990                             Path* ThisPath = &(((NodePath*)pNode)->InkPath);
00991                             INT32 ThisNum = ThisPath->GetNumCoords();
00992                             SubIndex = 0;
00993                             SubEnd = 0;
00994                             while (SubIndex<ThisNum)        
00995                             {
00996                                 DocCoord tempStart,tempEnd;
00997                                 ThisPath->SetPathPosition(SubIndex);    // Set the path's internal pos index
00998                                 if (ThisPath->GetSubPathEnds(&tempStart, &tempEnd))
00999                                 {
01000                                     SubEnd = ThisPath->GetPathPosition();
01001                                     // Now SubIndex is the index of the first, and SubEnd is the index
01002                                     // of the last element (N.B. might be a curveto, in which case add 2)
01003                                     if (ThisPath->GetVerb() == PT_BEZIERTO)
01004                                         SubEnd+=2;
01005 
01006                                     BOOL ClosedPath = (ThisPath->GetVerbArray()[SubEnd] & PT_CLOSEFIGURE) ;
01007 
01008                                     // Now compare start and end with pointer position, but not if this
01009                                     // subpath is the currently dragging subpath
01010                                     if ( !ClosedPath &&
01011                                          ( (pNode != OriginalPath) ||
01012                                            ((pNode == OriginalPath) && (DragPoint != SubIndex) && (DragPoint != SubEnd)) ) )
01013                                     {
01014                                         if (PointerBlobRect.ContainsCoord(tempStart))
01015                                         {
01016                                             break;
01017                                         }
01018                                         if (PointerBlobRect.ContainsCoord(tempEnd))
01019                                         {
01020                                             SubIndex = SubEnd;
01021                                             break;
01022                                         }
01023                                     }
01024                                 }
01025                                 else
01026                                 {
01027                                     SubEnd = ThisPath->GetPathPosition();
01028                                 }
01029                                 SubIndex = SubEnd+1;        // Points at start of next subpath
01030                                                             // or top of whole path
01031                             }
01032                             // if SubIndex < ThisNum we must have found a matching coord
01033                             // so that's what we'll snap to
01034                             if (SubIndex < ThisNum)
01035                                 break;              // Exit the outer while condition
01036                         }
01037                         pNode = Selected->FindNext(pNode);
01038                     }
01039                     // At this point, if pNode == NULL we haven't snapped to anything
01040                     // otherwise pNode is the path we've snapped to, and SubIndex is the index
01041                     // of the point we've snapped to
01042                     if (pNode)
01043                     {
01044                         // if the snap to path is the path being edited check that it has the same number of points!
01045                         if (((NodePath*)pNode == pOrigPath) && (pOrigPath->InkPath.GetNumCoords() != pEditPath->GetNumCoords()))
01046                         {
01047 //                          PATRACE( _T("Attempted to join an edited path!\n"));
01048                             // The problem is that if the OriginalPath has been edited by adding an endpoint then
01049                             // SnapToIndex will be wrong as it counted along the original path, not the edited one....
01050                         }
01051                         else
01052                         {
01053                             SnapToAnother = TRUE;
01054                             SnapToPath = (NodePath*)pNode;
01055                             SnapToIndex = SubIndex;
01056                             SnapToPath->InkPath.SetPathPosition(SnapToIndex);
01057                             PointerPos.x = SnapToPath->InkPath.GetCoord().x + LastMousePos.x - Coords[DragPoint].x;
01058                             PointerPos.y = SnapToPath->InkPath.GetCoord().y + LastMousePos.y - Coords[DragPoint].y;
01059                         }
01060                     }
01061                 }
01062 
01064 
01065                 // only do the following for the node that the drag was started from ....
01066 
01067                 //if (pCurrentOrig == (NodeListItem*) OriginalPaths.GetHead ())
01068                 //{
01069                     // We don't allow closed paths consiting of two straight segments
01070                     if (EndSnapped && NumCoords < 4)
01071                         EndSnapped = FALSE;
01072                         
01073                     if ((EndSnapped || SnapToAnother) && (pMoveCursor != NULL))
01074                         ChangeCursor(pCloseCursor);
01075                     else
01076                         ChangeCursor(pCrossHairCursor);
01077                 //}
01078                 
01079                 // Now constrain the mouse point
01080                 ERROR3IF(ConstrainPoint == DocCoord(-1,-1),"ConstrainPoint wasn't set");
01081                 ERROR3IF(ConstrainPrevPoint == DocCoord(-1,-1),"ConstrainPrevPoint wasn't set");
01082                 ERROR3IF(ConstrainNextPoint == DocCoord(-1,-1),"ConstrainNextPoint wasn't set");
01083                 if (!EndSnapped && ClickMods.Constrain)
01084                 {
01085                     if (ClickMods.Adjust)
01086                     {
01087                         if (ClickMods.Alternative1 || ClickMods.Alternative2)
01088                             DocView::ConstrainToAngle(ConstrainNextPoint, &PointerPos);
01089                         else
01090                             DocView::ConstrainToAngle(ConstrainPrevPoint, &PointerPos);
01091                     }
01092                     else
01093                         DocView::ConstrainToAngle(ConstrainPoint, &PointerPos);
01094                 }
01095 
01096                 // Only snap to grid if we didn't snap to the end of a path
01097                 if (!EndSnapped)
01098                     DocView::SnapCurrent(StartSpread,&PointerPos);
01099             }
01100 
01101             // This is the bit where we go off and re-calculate the paths position,
01102             // based on how much the mouse has moved
01103 
01104             if (pCurrentOrig == (NodeListItem*) OriginalPaths.GetHead ())
01105             {
01106                 Offset.x = PointerPos.x - LastMousePos.x;
01107                 Offset.y = PointerPos.y - LastMousePos.y;
01108             }
01109 
01110             // need to consider the validness of EndSnapped and DragPoint as well ....
01111             // CSG says:  we MUST pass EndSnapped and DragPoint as passed in below,
01112             // since these two values are reserved for the path that the drag was iniated
01113             // on (i.e.  the head of our linked list).  If we don't do this, then we get
01114             // loads of nasty asserts and errors going off.
01115             RecalculatePaths (pEditPath, Offset, FALSE /*EndSnapped*/, -1 /*DragPoint*/);
01116 
01117             if (pObjChange->ChangeMask.EorBlobs)
01118             {
01119                 ChangeCode Chge = pObjChange->RenderChangedBlobs(pOrigPath,this,pEditPath,StartSpread,TRUE);
01120                 if (Chge!=CC_OK)
01121                 {
01122                     // replace the old edit path
01123                     pEditPath->CopyPathDataFrom(&TempPath);
01124                     RenderPathEditBlobs( pEditPath/*->GetBoundingRect()*/, StartSpread );
01125                     return;
01126                 }
01127             }
01128 
01129             // Update the Last Mouse Position
01130             LastMousePos = PointerPos;
01131 
01132             // Draw in the new version of the path
01133             RenderPathEditBlobs( pEditPath/*->GetBoundingRect()*/, StartSpread );
01134 
01135             // If there is just one selected point being dragged then we should show
01136             // its new position in the line tool infobar.
01137 //          if (UpdatePoint != -1)
01138 //              BROADCAST_TO_ALL(PathEditedMsg(pEditPath, pSpread, UpdatePoint));
01139 
01141 
01142             pCurrentOrig = (NodeListItem*) OriginalPaths.GetNext (pCurrentOrig);
01143             pCurrentEdit = (NodeListItem*) EditPaths.GetNext (pCurrentEdit);
01144             pCurrentChange = (NodeListItem*) ObjChanges.GetNext (pCurrentChange);
01145             pCurrentDragS = (NodeListItem*) PathsDragStarted.GetNext (pCurrentDragS);
01146         }
01147         
01148         SetStatusLineHelp();
01149     }
01150 }

BOOL OpNodePathEditBlob::EditBrushAttribute INT32  FirstIndex,
INT32  LastIndex,
AttrBrushType pAttrBrush
[protected, virtual]
 

If we use the shape editor to edit a nodepath with an applied brush attribute and this brush attribute makes use of sampled pressure or time information then the brush needs to resample its data. So here we will insert a few actions to make that happen.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/6/2000 inputs : FirstIndex - first changed index of the path LastIndex - last changed index pAttrBrush - the attribute to change outputs: - returns: TRUE if all went well

Reimplemented in OpNodePathAddEndpoint.

Definition at line 3927 of file pathedit.cpp.

03928 {
03929     if (FirstIndex < 0 || LastIndex < 0 || LastIndex <= FirstIndex || pAttrBrush == NULL)
03930     {
03931         //ERROR3("Invalid inputs to OpNodePathEditBlob::EditBrushAttribute");
03932         return FALSE;
03933     }
03934     
03935     // currently we only have pressure implemented, and if this attribute does not use
03936     // pressure then theres nothing for us to do
03937     CDistanceSampler* pDistSamp = pAttrBrush->GetPressureCache();
03938     if (pDistSamp == NULL)
03939         return TRUE;  // not an error 
03940     
03941     /* Basically what we want to do here is resample the data that applies to the changed 
03942      section of the path, so that we have the same data applying over a different distance.
03943      The way to implement this in an undoable way is this:
03944      1) Find out the new length of the changed section of the path;
03945      2) Ask the sampler to copy out the current data between the changed points;
03946      4) Resample that data over the new length(the sampler can do this for us);
03947      4) Create an action to undoably remove the original section of data from the attribute
03948      5) Create an action to undoably insert the new resampled section;
03949     */
03950     MILLIPOINT ChangedLength = GetLengthOfPathSection(&EditPath, FirstIndex, LastIndex);
03951 //  MILLIPOINT OrigLength    = GetLengthOfPathSection(&(OriginalPath->InkPath), FirstIndex, LastIndex);
03952 
03953     // Get the distances to the changed indexes in the original path
03954     MILLIPOINT OrigStartDist = GetDistanceToPathIndex(&(OriginalPath->InkPath), FirstIndex);
03955     MILLIPOINT OrigEndDist   = GetDistanceToPathIndex(&(OriginalPath->InkPath), LastIndex);
03956 
03957     if (OrigStartDist == -1 || OrigEndDist == -1)
03958     {
03959         ERROR3("Error getting distance to index in OpNodePathEditBlob::EditBrushAttribute");
03960         return FALSE;
03961     }
03962     // we need another sampler to store the section data, needs to be allocated as we're putting
03963     // it into an action later
03964     CDistanceSampler* pSection = new CDistanceSampler;
03965     if (pSection == NULL)
03966         return FALSE;
03967 
03968     // Ask the sampler for its data section
03969     BOOL ok = pDistSamp->GetDataSection(OrigStartDist, OrigEndDist, pSection);
03970     if (!ok)
03971         return FALSE;
03972     
03973     // ask the section to resample itself
03974     if (!pSection->ReSample(ChangedLength))
03975     {
03976         delete pSection;
03977         return FALSE;
03978     }
03979     pSection->SetNumItemsFromArraySize();
03980 
03981     INT32 StartPressIndex = pDistSamp->GetInternalIndexFromDistance(OrigStartDist);
03982     INT32 EndPressIndex   = pDistSamp->GetInternalIndexFromDistance(OrigEndDist);
03983     INT32 NumIndexes = EndPressIndex - StartPressIndex;
03984     if (StartPressIndex == -1 || EndPressIndex == -1 || NumIndexes <= 0)
03985     {
03986         delete pSection;
03987         return FALSE;
03988     }
03989 
03990     // now make a removepoints action 
03991     RemovePressurePointsAction* pAction; 
03992     
03993     if (RemovePressurePointsAction::Init(this, &UndoActions, pAttrBrush, StartPressIndex, NumIndexes, NULL, &pAction) == AC_FAIL)
03994         return FALSE;
03995 
03996     // now insert our new points into the attribute
03997     AddPressurePointsAction* pAddAction;
03998 
03999     // find out how many points we're inserting
04000     size_t NumAddPoints = pSection->GetNumItems();
04001     
04002     if (AddPressurePointsAction::Init(this, &UndoActions, pAttrBrush, pSection, StartPressIndex, NumAddPoints,  &pAddAction) == AC_FAIL)
04003     {
04004         delete pSection;
04005         return FALSE;
04006     }
04007  
04008     return TRUE;
04009 }

BOOL OpNodePathEditBlob::FillPathIfEndsSnapped NodePath pOrigPath  )  [protected]
 

Will look at the EndSnapped flag and set the IsFilled bit in the OriginalPath Builds undo information. Returns FALSE if it couldn't build the Undo info.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (based upon Jim)
Date:
17/5/00
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
TRUE if successful, FALSE otherwise

Errors: -

See also:
-

Definition at line 4922 of file pathedit.cpp.

04923 {
04924     // If the ends snapped, set the filled bit on the path
04925     if (EndSnapped && !(pOrigPath->InkPath.IsFilled))
04926     {
04927         ModifyFilledAction* pAction;
04928         if (ModifyFilledAction::Init(this, &UndoActions, TRUE, FALSE, pOrigPath, (Action**)(&pAction))== AC_FAIL)
04929             return FALSE;
04930         pOrigPath->InkPath.IsFilled = TRUE;
04931     }
04932     return TRUE;
04933 }

BOOL OpNodePathEditBlob::FillPathIfEndsSnapped  )  [protected]
 

Will look at the EndSnapped flag and set the IsFilled bit in the OriginalPath Builds undo information. Returns FALSE if it couldn't build the Undo info.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
21/7/94
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
TRUE if successful, FALSE otherwise

Errors: -

See also:
-

Definition at line 4893 of file pathedit.cpp.

04894 {
04895     // If the ends snapped, set the filled bit on the path
04896     if (EndSnapped && !(OriginalPath->InkPath.IsFilled))
04897     {
04898         ModifyFilledAction* pAction;
04899         if (ModifyFilledAction::Init(this, &UndoActions, TRUE, FALSE, OriginalPath, (Action**)(&pAction))== AC_FAIL)
04900             return FALSE;
04901         OriginalPath->InkPath.IsFilled = TRUE;
04902     }
04903     return TRUE;
04904 }

AttrBrushType * OpNodePathEditBlob::GetAppliedBrush  )  [protected]
 

To get the brush attribute that is applied to the nodepath we are editing.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
26/9/99 inputs : - outputs: - returns: pointer to the attrbrushtype that is applied to this nodepath, or NULL if there isn't one. Note that if the applied brush is the default 'no brush' then we also return NULL

Definition at line 3889 of file pathedit.cpp.

03890 {
03891     if (OriginalPath == NULL)
03892         return NULL;
03893 
03894     NodeAttribute* pAttr = NULL;
03895     AttrBrushType* pAttrBrush = NULL;
03896     OriginalPath->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), &pAttr);
03897     
03898     if (pAttr != NULL)
03899     {
03900         // just check that our applied brush isn't the default
03901         if (((AttrBrushType*)pAttr)->GetBrushHandle() != BrushHandle_NoBrush)
03902             pAttrBrush = (AttrBrushType*)pAttr;
03903     }
03904     return pAttrBrush;
03905 }

INT32 OpNodePathEditBlob::GetDistanceToPathIndex Path pPath,
INT32  Index
[protected]
 

As above,.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/6/2000
Parameters:
pPath - the path containing the index [INPUTS] Index - the index to which we wish to find the distance
Returns:
The distance along pPath to Index, or -1 if theres a problem
Notes: Should really move this into Path at some point

Definition at line 4088 of file pathedit.cpp.

04089 {
04090     // some checks
04091     ERROR2IF(pPath == NULL, -1, "Path is NULL in OpNodePathEditBlob::GetDistanceToPathIndex");
04092     
04093     if (Index >= pPath->GetNumCoords())
04094     {
04095         ERROR3("Invalid index in OpNodePathEditBlob::GetDistanceToPathIndex");
04096         return -1;
04097     }
04098 
04099     // get the coordinates
04100     DocCoord* pCoords = pPath->GetCoordArray();
04101     ERROR2IF(pCoords == NULL, -1, "Failed to get coord array in OpNodePathEditBlob::GetLengthOfEditSection");
04102 
04103     DocCoord Coord = pCoords[Index];
04104 
04105     MILLIPOINT Distance = -1;
04106     if (!pPath->GetDistanceToPoint(Coord, &Distance))
04107         return -1;
04108 
04109     return Distance;
04110 }

NodeGroup * OpNodePathEditBlob::GetGroupParentOfCurve NodePath pOrigPath  )  [protected]
 

To determine if the current selection is a blend on a curve.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (based upon Diccon Yamanaka's)
Date:
20/4/2000 inputs : - outputs: returns: pointer to the first nodeblend in the selection if successful, NULL otherwise

Definition at line 3852 of file pathedit.cpp.

03853 {
03854     if (pOrigPath == NULL)
03855         return NULL;
03856     Node* pParent = pOrigPath->FindParent();
03857 
03858     if (pParent != NULL)
03859     {
03860         if (pParent->IS_KIND_OF(NodeBlend))
03861         {
03862             return (NodeGroup*)pParent;
03863         }
03864         else
03865             return NULL;
03866     }
03867 
03868     return NULL;
03869 
03870 }

NodeGroup * OpNodePathEditBlob::GetGroupParentOfCurve  )  [protected]
 

To determine if the current selection is a blend on a curve.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
26/9/99 inputs : - outputs: returns: pointer to the first nodeblend in the selection if successful, NULL otherwise

Definition at line 3815 of file pathedit.cpp.

03816 {   
03817     if (OriginalPath == NULL)
03818         return NULL;
03819     Node* pParent = OriginalPath->FindParent();
03820 
03821     if (pParent != NULL)
03822     {
03823         if (pParent->IS_KIND_OF(NodeBlend))
03824         {
03825             return (NodeGroup*)pParent;
03826         }
03827         else
03828             return NULL;
03829     }
03830 
03831     return NULL;
03832 
03833 }

MILLIPOINT OpNodePathEditBlob::GetLengthOfPathSection Path pPath,
INT32  FirstIndex,
INT32  LastIndex
[protected]
 

As above, if you want to know the distance between two points on the edit path then this function is for you.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/6/2000
Parameters:
FirstIndex,LastIndex - the indexes marking the start and end of the section [INPUTS] of path we are interested in pPath - the path we are interested in
Returns:
The distance along the pPath between the two indexes, or -1 if something went wrong
Notes: I can't believe no-one has written a Path function to do this. There must be a better way to do this but currently I must get the two coordinates corresponding to the indexes, and call GetDistanceToPoint for both of them and do a subtraction. I will shift this into Path at some point but I don't want to hang around for the rebuild right now.

Definition at line 4035 of file pathedit.cpp.

04036 {
04037     ERROR2IF(pPath == NULL, -1, "Path is NULL in OpNodePathEditBlob::GetLengthOfPathSection");
04038 
04039     // find out how many elements there are in EditPath
04040     INT32 NumElements = pPath->GetNumCoords();
04041 
04042     // check that our indexes are ok
04043     if (FirstIndex < 0 || LastIndex < 0 || LastIndex <= FirstIndex || FirstIndex >= NumElements
04044         || LastIndex > NumElements)
04045     {
04046         ERROR3("Invalid inputs to OpNodePathEditBlob::GetLengthOfEditSection");
04047         return -1;
04048     }
04049     
04050     // get the coordinates
04051     DocCoord* pCoords = pPath->GetCoordArray();
04052     ERROR2IF(pCoords == NULL, -1, "Failed to get coord array in OpNodePathEditBlob::GetLengthOfEditSection");
04053 
04054     DocCoord FirstCoord = pCoords[FirstIndex];
04055     DocCoord LastCoord  = pCoords[LastIndex];
04056 
04057     // Now get the distances along the path to these points
04058     MILLIPOINT FirstDistance = -1;
04059     MILLIPOINT LastDistance  = -1;
04060     
04061     BOOL ok = pPath->GetDistanceToPoint(FirstCoord, &FirstDistance);
04062     if (ok)
04063         ok = pPath->GetDistanceToPoint(LastCoord, &LastDistance);
04064 
04065     MILLIPOINT SectionLength = -1;
04066     if (ok)
04067         SectionLength = LastDistance - FirstDistance;
04068 
04069     return SectionLength;
04070 }

OpState OpNodePathEditBlob::GetState String_256 Description,
OpDescriptor
[static]
 

Find out the state of the operation at the specific time.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/7/93
Parameters:
Description - GetState fills this string with an approriate description [OUTPUTS] of the current state of the selector tool
Returns:
The state of the operation, so that menu items (ticks and greying can be done properly

Reimplemented in OpNodePathEditControlBlob, OpNodePathAddEndpoint, OpCloseNodePaths, OpReshapeOrAddPoint, and OpNewPath.

Definition at line 3351 of file pathedit.cpp.

03352 {
03353     OpState Blobby;
03354     
03355     return Blobby;
03356 }

BOOL OpNodePathEditBlob::Init void   )  [static]
 

Adds the operation to the list of all known operations.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/7/93
Returns:
TRUE if all went OK, False otherwise

Reimplemented from SimpleCCObject.

Reimplemented in OpNodePathEditControlBlob, OpNodePathAddEndpoint, OpCloseNodePaths, OpReshapeOrAddPoint, and OpNewPath.

Definition at line 3325 of file pathedit.cpp.

03326 {
03327     return (RegisterOpDescriptor(   0, 
03328                                     _R(IDS_NODEPATH_EDIT),
03329                                     CC_RUNTIME_CLASS(OpNodePathEditBlob), 
03330                                     OPTOKEN_NODEPATH,
03331                                     OpNodePathEditBlob::GetState,
03332                                     0,                                      // help ID
03333                                     _R(IDBBL_NODEPATHOP),
03334                                     0 ) );                                  // bitmap ID */
03335 }

BOOL OpNodePathEditBlob::InsertChangeBlendStepsAction NodeBlend pNodeBlend  )  [protected]
 

To adjust the number of steps in a blend on a path as a result of the path being edited (which is why its here rather than in the blend code). First the number of steps is calculated from the new path distance and if different a new action is inserted.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
1/9/99
Parameters:
the node blend to change [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: Error2 if pNodeBlend is null

See also:
called from OpNodePathEditBlob::DragFinished or OpNodePathAddEndpoint::CompleteThisPath

Definition at line 1601 of file pathedit.cpp.

01602 {
01603     ERROR2IF(pNodeBlend==NULL, FALSE, "NodeBlend pointer is NULL");
01604     // do we wish to keep the distance between steps constant?  If so then determine
01605     // how many steps we need with the new length and make an action.
01606     if (pNodeBlend->GetEditState() == EDIT_DISTANCE)
01607     {
01608         UINT32 NewNumSteps = 0;
01609         UINT32 OldNumSteps = pNodeBlend->GetNumBlendSteps();
01610         double StepDistance = pNodeBlend->GetDistanceEntered();
01611         double NewPathLength = EditPath.GetPathLength();
01612         NewNumSteps = (UINT32)(NewPathLength/StepDistance);
01613         BOOL ok = TRUE;
01614         
01615     
01616         if (OldNumSteps != NewNumSteps)
01617         {
01618             ChangeBlendStepsAction* pAction;
01619             if (ok) ok = (InvalidateBoundsAction::Init(this,&UndoActions,pNodeBlend,TRUE) != AC_FAIL);
01620             if (ok) ok = ChangeBlendStepsAction::Init(this,&UndoActions,pNodeBlend,OldNumSteps,StepDistance,&pAction) != AC_FAIL;
01621             if (ok) ok = DoInvalidateNodeRegion(pNodeBlend,TRUE,FALSE);
01622             if (ok) ok = (InvalidateBoundsAction::Init(this,&UndoActions,pNodeBlend,TRUE) != AC_FAIL);
01623             pNodeBlend->SetNumBlendSteps(NewNumSteps);
01624         }
01625 
01626         // added 9/9/99 now we are shifting the last object along the curve to ensure precise
01627         // step distances.  To do this we must set the proportion of the curve used in the 
01628         // NodeBlender objects.
01629         if (ok)
01630         {
01631             double PathDistanceUsed = NewNumSteps * StepDistance;
01632             double PathProportion = PathDistanceUsed / NewPathLength;
01633 //          double PathDistanceUnused = NewPathLength - PathDistanceUsed;
01634 
01635             if (PathProportion != 1.0)
01636             {
01637                 ChangeBlenderOpParam BlenderParam;
01638                 BlenderParam.m_ChangeType = CHANGEBLENDER_PATHEND;
01639                             
01640                 NodeBlender* pNodeBlender = pNodeBlend->FindFirstBlender();
01641                 INT32 NumBlenders = pNodeBlend->GetNumBlenders();
01642                         
01643                 while (pNodeBlender != NULL)
01644                 {
01645                     NumBlenders--;
01646                     if (NumBlenders ==0)
01647                     {                                   
01648                         BlenderParam.m_NewPathEnd = PathProportion;
01649                         ok = ChangeBlenderAction::Init(this, &UndoActions, pNodeBlender, BlenderParam);
01650                         if (ok)
01651                         {
01652                             DocCoord NewPoint;
01653                             double ExtraParam = 0.0;  //passed to the function but not used afterwards
01654                             ok = pNodeBlender->GetPointOnNodeBlendPath(1.0,&NewPoint,&ExtraParam);
01655                             if (ok)
01656                             {
01657                                 NodeRenderableInk* pEnd = pNodeBlender->GetNodeEnd();
01658                                 NodeBlend* pNodeBlend = pNodeBlender->GetNodeBlend();
01659                                 ok = ((pEnd != NULL) && (pNodeBlend != NULL));
01660                     
01661                                 if (ok) 
01662                                     ok = pNodeBlend->TransformNodeToPoint(pEnd,&NewPoint,this,ExtraParam);
01663                             }
01664                         }
01665                     }   
01666                     pNodeBlender = pNodeBlend->FindNextBlender(pNodeBlender);
01667                 }
01668             } // end if (pathproportion..
01669         } // end if(ok)
01670     }
01671     return TRUE;
01672 }

BOOL OpNodePathEditBlob::JoinWithOtherPath NodePath **  pOrigPath  )  [protected]
 

Looks at the member variables dealing with snapping to another path and joins the paths together. It will always join the other path to the original path, keeping the original path's attributes intact. NOTE: This routine will alter the OriginalPath member variable if it joins paths, because it has to make a copy of the path for undo purposes.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (based upon Jim)
Date:
17/5/00
Returns:
FALSE if it failed (lack of memory maybe) TRUE otherwise

Errors: If it runs out of memory then it will return FALSE

Definition at line 1984 of file pathedit.cpp.

01985 {
01986     // If SnapToAnother is false there's no snapping to be done, so just return successfully
01987     if (!SnapToAnother)
01988         return TRUE;
01989 
01990     // If we're joining with another path, the rules say we can only have one selected point.
01991     PathFlags* Flags = (*pOrigPath)->InkPath.GetFlagArray();
01992     INT32 NumCoords = (*pOrigPath)->InkPath.GetNumCoords();
01993 
01994     NodePath* OldSnapPath = SnapToPath;
01995     
01996     INT32 MainIndex;
01997     for (MainIndex=0; MainIndex<NumCoords; MainIndex++)
01998     {
01999         if (Flags[MainIndex].IsEndPoint && Flags[MainIndex].IsSelected)
02000             break;
02001     }
02002 
02003     // on exit, MainIndex is the selected endpoint, or = NumCoords
02004 
02005     ENSURE(MainIndex<NumCoords,"There isn't a selected endpoint in the original path (JoinWithAnotherPath)");
02006     
02007     // We're joining to another path, so the easiest way to handle undo is to make a deep copy
02008     // of the original path, then join that with the othe path, put it back into the tree
02009     // and delete the old one. Simple.
02010     Node* pnp;
02011     (*pOrigPath)->NodeCopy(&pnp);   // Make a deep copy of the original path, with attributes
02012     NodePath* MainPath = (NodePath*)pnp;
02013 
02014     if (!MainPath)
02015         return FALSE;
02016 
02017     // Now that we have a copy of this path, let's join it with the other path
02018 
02019     if (SnapToAnother)
02020     {
02021         // If we're snapping to a subpath in the same path, change SnapToPath because we're
02022         // no longer joining to OriginalPath.
02023         if (SnapToPath == (*pOrigPath))
02024             SnapToPath = MainPath;
02025         
02026         // If we're snapping to another, the first thing I have to do is change the control
02027         // point of the point in the other path that we're snapping to, because it might
02028         // have been smoothed.
02029 
02030         if (SnapToLineOrCurve)      // TRUE if the path has been smoothed
02031         {
02032             PathVerb* OtherVerbs = SnapToPath->InkPath.GetVerbArray();
02033             PathFlags* OtherFlags = SnapToPath->InkPath.GetFlagArray();
02034             DocCoord* OtherCoords = SnapToPath->InkPath.GetCoordArray();
02035 
02036             if (OtherVerbs[SnapToIndex] == PT_MOVETO)
02037             {
02038                 // Don't need to undo if SnapToPath == MainPath
02039                 if (SnapToPath == MainPath)
02040                     OtherCoords[SnapToIndex+1] = SnapToCoords[1];
02041                 else
02042                     DoAlterPathElement( SnapToPath, 
02043                                         SnapToIndex+1, 
02044                                         SnapToCoords[1], 
02045                                         OtherFlags[SnapToIndex+1],
02046                                         OtherVerbs[SnapToIndex+1]);
02047             }
02048             else
02049             {
02050                 if (SnapToPath == MainPath)
02051                     OtherCoords[SnapToIndex-1] = SnapToCoords[1];
02052                 else
02053                     DoAlterPathElement( SnapToPath, 
02054                                         SnapToIndex-1, 
02055                                         SnapToCoords[1], 
02056                                         OtherFlags[SnapToIndex-1],
02057                                         OtherVerbs[SnapToIndex-1]);
02058             }
02059         }
02060 
02061         if (!MainPath->InkPath.JoinToAnother(&(SnapToPath->InkPath), MainIndex, SnapToIndex))
02062         {
02063             MainPath->CascadeDelete();
02064             delete MainPath;
02065             return FALSE;
02066         }
02067     }
02068 
02069     // We've joined successfully, so let's insert this new node into the tree next to the original
02070     if (!DoInsertNewNode(MainPath, (*pOrigPath), NEXT, TRUE, FALSE))
02071     {
02072         MainPath->CascadeDelete();
02073         delete MainPath;
02074         return FALSE;
02075     }
02076 
02077     // Hide the original path
02078     if (!DoHideNode((*pOrigPath), TRUE))
02079         return FALSE;
02080 
02081     // Hide the node we joined to
02082     if (OldSnapPath != (*pOrigPath))
02083     {
02084         if (!DoHideNode(OldSnapPath, TRUE))
02085             return FALSE;
02086     }
02087 
02088     // Change the pOrigPath variable so that subsequent operations work properly
02089     (*pOrigPath) = MainPath;
02090 
02091     return TRUE;
02092 }

BOOL OpNodePathEditBlob::JoinWithOtherPath  )  [protected]
 

Looks at the member variables dealing with snapping to another path and joins the paths together. It will always join the other path to the original path, keeping the original path's attributes intact. NOTE: This routine will alter the OriginalPath member variable if it joins paths, because it has to make a copy of the path for undo purposes.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/10/94
Returns:
FALSE if it failed (lack of memory maybe) TRUE otherwise

Errors: If it runs out of memory then it will return FALSE

Definition at line 1856 of file pathedit.cpp.

01857 {
01858     // If SnapToAnother is false there's no snapping to be done, so just return successfully
01859     if (!SnapToAnother)
01860         return TRUE;
01861 
01862     // If we're joining with another path, the rules say we can only have one selected point.
01863     PathFlags* Flags = OriginalPath->InkPath.GetFlagArray();
01864     INT32 NumCoords = OriginalPath->InkPath.GetNumCoords();
01865 
01866     NodePath* OldSnapPath = SnapToPath;
01867     
01868     INT32 MainIndex;
01869     for (MainIndex=0; MainIndex<NumCoords; MainIndex++)
01870     {
01871         if (Flags[MainIndex].IsEndPoint && Flags[MainIndex].IsSelected)
01872             break;
01873     }
01874 
01875     // on exit, MainIndex is the selected endpoint, or = NumCoords
01876 
01877     ENSURE(MainIndex<NumCoords,"There isn't a selected endpoint in the original path (JoinWithAnotherPath)");
01878     
01879     // We're joining to another path, so the easiest way to handle undo is to make a deep copy
01880     // of the original path, then join that with the othe path, put it back into the tree
01881     // and delete the old one. Simple.
01882     Node* pnp;
01883     OriginalPath->NodeCopy(&pnp);   // Make a deep copy of the original path, with attributes
01884     NodePath* MainPath = (NodePath*)pnp;
01885 
01886     if (!MainPath)
01887         return FALSE;
01888 
01889     // Now that we have a copy of this path, let's join it with the other path
01890 
01891     if (SnapToAnother)
01892     {
01893         // If we're snapping to a subpath in the same path, change SnapToPath because we're
01894         // no longer joining to OriginalPath.
01895         if (SnapToPath == OriginalPath)
01896             SnapToPath = MainPath;
01897         
01898         // If we're snapping to another, the first thing I have to do is change the control
01899         // point of the point in the other path that we're snapping to, because it might
01900         // have been smoothed.
01901 
01902         if (SnapToLineOrCurve)      // TRUE if the path has been smoothed
01903         {
01904             PathVerb* OtherVerbs = SnapToPath->InkPath.GetVerbArray();
01905             PathFlags* OtherFlags = SnapToPath->InkPath.GetFlagArray();
01906             DocCoord* OtherCoords = SnapToPath->InkPath.GetCoordArray();
01907 
01908             if (OtherVerbs[SnapToIndex] == PT_MOVETO)
01909             {
01910                 // Don't need to undo if SnapToPath == MainPath
01911                 if (SnapToPath == MainPath)
01912                     OtherCoords[SnapToIndex+1] = SnapToCoords[1];
01913                 else
01914                     DoAlterPathElement( SnapToPath, 
01915                                         SnapToIndex+1, 
01916                                         SnapToCoords[1], 
01917                                         OtherFlags[SnapToIndex+1],
01918                                         OtherVerbs[SnapToIndex+1]);
01919             }
01920             else
01921             {
01922                 if (SnapToPath == MainPath)
01923                     OtherCoords[SnapToIndex-1] = SnapToCoords[1];
01924                 else
01925                     DoAlterPathElement( SnapToPath, 
01926                                         SnapToIndex-1, 
01927                                         SnapToCoords[1], 
01928                                         OtherFlags[SnapToIndex-1],
01929                                         OtherVerbs[SnapToIndex-1]);
01930             }
01931         }
01932 
01933         if (!MainPath->InkPath.JoinToAnother(&(SnapToPath->InkPath), MainIndex, SnapToIndex))
01934         {
01935             MainPath->CascadeDelete();
01936             delete MainPath;
01937             return FALSE;
01938         }
01939     }
01940 
01941     // We've joined successfully, so let's insert this new node into the tree next to the original
01942     if (!DoInsertNewNode(MainPath, OriginalPath, NEXT, TRUE, FALSE))
01943     {
01944         MainPath->CascadeDelete();
01945         delete MainPath;
01946         return FALSE;
01947     }
01948 
01949     // Hide the original path
01950     if (!DoHideNode(OriginalPath, TRUE))
01951         return FALSE;
01952 
01953     // Hide the node we joined to
01954     if (OldSnapPath != OriginalPath)
01955     {
01956         if (!DoHideNode(OldSnapPath, TRUE))
01957             return FALSE;
01958     }
01959 
01960     // Change the OriginalPath member variable so that subsequent operations work properly
01961     OriginalPath = MainPath;
01962 
01963     return TRUE;
01964 }

void OpNodePathEditBlob::RecalculatePath DocCoord  Offset,
BOOL  SnapEnds = FALSE,
INT32  SnapIndex = 0
[protected]
 

This goes through the path, moves all the selected coords by the offset and then performs some magic to smooth the rest of the path round the changes if it needs it.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
9/11/93
Parameters:
Offset - The Amount to move the selected blobs by before re-calcing everything [INPUTS] SnapEnds is TRUE if the start and endpoint should snap (affects smoothing) SnapIndex is the index of the point that's being snapped, so we can only snap one subpath out of many Scope: Private

Definition at line 2658 of file pathedit.cpp.

02659 {
02660     // Get the array that I need
02661     PathFlags* Flags  = EditPath.GetFlagArray();
02662     DocCoord*  Coords = EditPath.GetCoordArray();
02663 
02664     INT32 NumCoords = EditPath.GetNumCoords();
02665 
02666     // Go though all the points
02667     for (INT32 i=0; i<NumCoords; i++)
02668     {
02669         // and translate them by the drag offset if they are selected
02670         if (Flags[i].IsSelected)
02671             Coords[i].translate( Offset.x, Offset.y );
02672     }
02673 
02674     // And now smooth out the new path
02675     EditPath.SmoothCurve(TRUE, SnapEnds, SnapIndex);
02676 
02677     // Now to snap (possibly) to another path, if the SnapToAnother flag is set
02678     // This not only entails changing the part of the line we're dragging, but it might
02679     // also mean we have to set the SnapToCoords array to contain a snapped bezier segment  
02680     if (SnapToAnother)
02681     {
02682         // Get the array pointers
02683         PathVerb* Verbs = EditPath.GetVerbArray();
02684         Flags = EditPath.GetFlagArray();
02685         Coords = EditPath.GetCoordArray();
02686         PathVerb* OtherVerbs = SnapToPath->InkPath.GetVerbArray();
02687         PathFlags* OtherFlags = SnapToPath->InkPath.GetFlagArray();
02688         DocCoord* OtherCoords = SnapToPath->InkPath.GetCoordArray();
02689 
02690         // Because we're snapping, we must be on either the start or the end of a subpath
02691         // And the CloseFigure flag will never be set.
02692         // There are sixteen possibilities - for each line, we could be looking at
02693         // a curve or a line, at the start or end of each subpath. This logic enumerates
02694         // all of the possibilities. It may look tortuous, but it gets them all.
02695         if (Verbs[SnapIndex] == PT_MOVETO)
02696         {
02697             // We're dragging the start of a subpath. See if it's a curve
02698             if (Verbs[SnapIndex+1] == PT_BEZIERTO)
02699             {
02700                 // We are dragging a curve at the start of the path. See what we've snapped to
02701                 if (OtherVerbs[SnapToIndex] == PT_MOVETO)
02702                 {
02703                     // Snapping a curve at start to the start of the other one
02704                     if (OtherVerbs[SnapToIndex+1] == PT_BEZIERTO)
02705                     {
02706                         // Snapping curve at beginning with curve at beginning
02707                         // Let's smooth this bezier according to the snapping
02708                         if (Flags[SnapIndex+1].IsSmooth)
02709                             Coords[SnapIndex+1] = EditPath.SmoothControlPoint(  SnapIndex+1,
02710                                                                                 FALSE,  // start end not snapped
02711                                                                                 TRUE,   // Joined to another
02712                                                                                 TRUE,   // Other is a curve
02713                                                                                 OtherCoords[SnapToIndex+3]
02714                                                                                 );
02715                         // Note that the other control point is not affected by the snap
02716                         // Since the other segment is a curve, we have to set up the SnapToCoords array
02717                         // so that the render routine works properly
02718                         // Notice that the assignment in the if below is required
02719                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex+1].IsSmooth))
02720                         {
02721                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02722                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex+1,
02723                                                                                         FALSE,
02724                                                                                         TRUE,
02725                                                                                         TRUE,
02726                                                                                         Coords[SnapIndex+3]
02727                                                                                         );
02728                             SnapToCoords[2] = OtherCoords[SnapToIndex+2];
02729                             SnapToCoords[3] = OtherCoords[SnapToIndex+3];
02730                         }
02731                     }
02732                     else
02733                     {
02734                         // Snapping curve at beginning with line at beginning
02735                         if (Flags[SnapIndex+1].IsSmooth)
02736                             Coords[SnapIndex+1] = EditPath.SmoothControlPoint(  SnapIndex+1,
02737                                                                                 FALSE,  // start end not snapped
02738                                                                                 TRUE,   // Joined to another
02739                                                                                 FALSE,  // Other is a line
02740                                                                                 OtherCoords[SnapToIndex+1]
02741                                                                                 );
02742                         // Since we're snapping to a line, we just need to set SnapToLineOrCurve to FALSE
02743                         SnapToLineOrCurve = FALSE;
02744 
02745                     }
02746                 }
02747                 else
02748                 {
02749                     // Snapping curve at beginning with the end of the other one
02750                     if (OtherVerbs[SnapToIndex] == PT_BEZIERTO)
02751                     {
02752                         // Snapping curve at beginning with curve at end of other one
02753                         // Smooth the editpath bezier if the flag says we can
02754                         if (Flags[SnapIndex+1].IsSmooth)
02755                             Coords[SnapIndex+1] = EditPath.SmoothControlPoint(  SnapIndex+1,
02756                                                                                 FALSE,
02757                                                                                 TRUE,
02758                                                                                 TRUE,
02759                                                                                 OtherCoords[SnapToIndex-3]
02760                                                                                 );
02761                         // Now set up SnapToCoords array
02762                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex-1].IsSmooth))   // yes the other path is a curve
02763                         {
02764                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02765                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex-1,
02766                                                                                         FALSE,
02767                                                                                         TRUE,
02768                                                                                         TRUE,
02769                                                                                         Coords[SnapIndex+3]
02770                                                                                         );
02771                             SnapToCoords[2] = OtherCoords[SnapToIndex-2];
02772                             SnapToCoords[3] = OtherCoords[SnapToIndex-3];
02773                         }
02774                     }
02775                     else
02776                     {
02777                         // snapping curve at beginning with line at end of other one
02778                         if (Flags[SnapIndex+1].IsSmooth)
02779                             Coords[SnapIndex+1] = EditPath.SmoothControlPoint(  SnapIndex+1,
02780                                                                                 FALSE,
02781                                                                                 TRUE,
02782                                                                                 FALSE,
02783                                                                                 OtherCoords[SnapToIndex-1]
02784                                                                                 );
02785                         // Other is a line, so the SnapToCoords array isn't used
02786                         SnapToLineOrCurve = FALSE;
02787                     }
02788                 }
02789 
02790             }
02791             else
02792             {
02793                 // Dragging a line at the beginning. What are we snapping to
02794                 if (OtherVerbs[SnapToIndex] == PT_MOVETO)
02795                 {
02796                     // Snapping a line at start to the start of the other one
02797                     if (OtherVerbs[SnapToIndex+1] == PT_BEZIERTO)
02798                     {
02799                         // Snapping line at beginning with curve at beginning
02800                         // There's nothing to smooth in the edit path, but we have to
02801                         // set up the SnapToCoords array
02802                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex+1].IsSmooth))
02803                         {
02804                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02805                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex+1,
02806                                                                                         FALSE,
02807                                                                                         TRUE,
02808                                                                                         FALSE,
02809                                                                                         Coords[SnapIndex+1]
02810                                                                                         );
02811                             SnapToCoords[2] = OtherCoords[SnapToIndex+2];
02812                             SnapToCoords[3] = OtherCoords[SnapToIndex+3];
02813                         }
02814                     }
02815                     {
02816                         // Snapping line at beginning with line at beginning
02817                         // Nothing whatever to smooth, just clear the flag
02818                         SnapToLineOrCurve = FALSE;
02819                     }
02820                 }
02821                 else
02822                 {
02823                     // Snapping line at beginning with the end of the other one
02824                     if (OtherVerbs[SnapToIndex] == PT_BEZIERTO)
02825                     {
02826                         // Snapping line at beginning with curve at end of other one
02827                         // Nothing to smooth in editpath, let's set up SnapToCoords array
02828                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex-1].IsSmooth))
02829                         {
02830                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02831                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex-1,
02832                                                                                         FALSE,
02833                                                                                         TRUE,
02834                                                                                         FALSE,
02835                                                                                         Coords[SnapIndex+1]
02836                                                                                         );
02837                             SnapToCoords[2] = OtherCoords[SnapToIndex-2];
02838                             SnapToCoords[3] = OtherCoords[SnapToIndex-3];
02839                         }
02840                     }
02841                     else
02842                     {
02843                         // snapping line at beginning with line at end of other one
02844                         // Just clear the flag
02845                         SnapToLineOrCurve = FALSE;
02846                     }
02847                 }
02848 
02849             }
02850         }
02851         else
02852         {
02853             // We're snapping the end of the path, let's see what
02854             if (Verbs[SnapIndex] == PT_BEZIERTO)
02855             {
02856                 // Snapping a curve at the end to... what?
02857                 if (OtherVerbs[SnapToIndex] == PT_MOVETO)
02858                 {
02859                     // Snapping a curve at the end to the start of the other one
02860                     if (OtherVerbs[SnapToIndex+1] == PT_BEZIERTO)
02861                     {
02862                         // Snapping curve at the end with curve at beginning
02863                         if (Flags[SnapIndex-1].IsSmooth)
02864                             Coords[SnapIndex-1] = EditPath.SmoothControlPoint(  SnapIndex-1,
02865                                                                                 FALSE,
02866                                                                                 TRUE,
02867                                                                                 TRUE,
02868                                                                                 OtherCoords[SnapToIndex+3]
02869                                                                                 );
02870                         // Set up the SnapToCoords array
02871                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex+1].IsSmooth))
02872                         {
02873                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02874                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex+1,
02875                                                                                         FALSE,
02876                                                                                         TRUE,
02877                                                                                         TRUE,
02878                                                                                         Coords[SnapIndex-3]
02879                                                                                         );
02880                             SnapToCoords[2] = OtherCoords[SnapToIndex+2];
02881                             SnapToCoords[3] = OtherCoords[SnapToIndex+3];
02882                         }
02883                     }
02884                     else
02885                     {
02886                         // Snapping curve at the end with line at beginning
02887                         if (Flags[SnapIndex-1].IsSmooth)
02888                             Coords[SnapIndex-1] = EditPath.SmoothControlPoint(  SnapIndex-1,
02889                                                                                 FALSE,
02890                                                                                 TRUE,
02891                                                                                 FALSE,
02892                                                                                 OtherCoords[SnapToIndex+1]
02893                                                                                 );
02894 
02895                         // Clear flag for SnapToCoords array
02896                         SnapToLineOrCurve = FALSE;
02897                     }
02898                 }
02899                 else
02900                 {
02901                     // Snapping curve at the end with the end of the other one
02902                     if (OtherVerbs[SnapToIndex] == PT_BEZIERTO)
02903                     {
02904                         // Snapping curve at the end with curve at end of other one
02905                         if (Flags[SnapIndex-1].IsSmooth)
02906                             Coords[SnapIndex-1] = EditPath.SmoothControlPoint(  SnapIndex-1,
02907                                                                                 FALSE,
02908                                                                                 TRUE,
02909                                                                                 TRUE,
02910                                                                                 OtherCoords[SnapToIndex-3]
02911                                                                                 );
02912                         // Init the SnapToCoords array
02913                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex-1].IsSmooth))
02914                         {
02915                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02916                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex-1,
02917                                                                                         FALSE,
02918                                                                                         TRUE,
02919                                                                                         TRUE,
02920                                                                                         Coords[SnapIndex-3]
02921                                                                                         );
02922                             SnapToCoords[2] = OtherCoords[SnapToIndex-2];
02923                             SnapToCoords[3] = OtherCoords[SnapToIndex-3];
02924                         }
02925                     }
02926                     else
02927                     {
02928                         // snapping curve at the end with line at end of other one
02929                         if (Flags[SnapIndex-1].IsSmooth)
02930                             Coords[SnapIndex-1] = EditPath.SmoothControlPoint(  SnapIndex-1,
02931                                                                                 FALSE,
02932                                                                                 TRUE,
02933                                                                                 FALSE,
02934                                                                                 OtherCoords[SnapToIndex-1]
02935                                                                                 );
02936                         // Other is a line so clear the flag
02937                         SnapToLineOrCurve = FALSE;
02938                     }
02939                 }
02940 
02941             }
02942             else
02943             {
02944                 // Snapping a line at the end with something
02945                 if (OtherVerbs[SnapToIndex] == PT_MOVETO)
02946                 {
02947                     // Snapping a line at the end to the start of the other one
02948                     if (OtherVerbs[SnapToIndex+1] == PT_BEZIERTO)
02949                     {
02950                         // Snapping line at the end with curve at beginning
02951                         // Nothing to smooth in the edit path, but we should set up SnapToCoords array
02952                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex+1].IsSmooth))
02953                         {
02954                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02955                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex+1,
02956                                                                                         FALSE,
02957                                                                                         TRUE,
02958                                                                                         FALSE,
02959                                                                                         Coords[SnapIndex-1]
02960                                                                                         );
02961                             SnapToCoords[2] = OtherCoords[SnapToIndex+2];
02962                             SnapToCoords[3] = OtherCoords[SnapToIndex+3];
02963                         }
02964                     }
02965                     {
02966                         // Snapping line at the end with line at beginning
02967                         // Just clear the flag
02968                         SnapToLineOrCurve = FALSE;
02969                     }
02970                 }
02971                 else
02972                 {
02973                     // Snapping line at the end with the end of the other one
02974                     if (OtherVerbs[SnapToIndex] == PT_BEZIERTO)
02975                     {
02976                         // Snapping line at the end with curve at end of other one
02977                         // Nothing to smooth in Editpath, but we have to do the array
02978                         if ((SnapToLineOrCurve = OtherFlags[SnapToIndex-1].IsSmooth))
02979                         {
02980                             SnapToCoords[0] = OtherCoords[SnapToIndex];
02981                             SnapToCoords[1] = SnapToPath->InkPath.SmoothControlPoint(   SnapToIndex-1,
02982                                                                                         FALSE,
02983                                                                                         TRUE,
02984                                                                                         FALSE,
02985                                                                                         Coords[SnapIndex-1]
02986                                                                                         );
02987                             SnapToCoords[2] = OtherCoords[SnapToIndex-2];
02988                             SnapToCoords[3] = OtherCoords[SnapToIndex-3];
02989                         }
02990                     }
02991                     else
02992                     {
02993                         // snapping line at the end with line at end of other one
02994                         // Just clear the flag
02995                         SnapToLineOrCurve = FALSE;
02996                     }
02997                 }
02998 
02999             }
03000         }
03001 
03002     }
03003 
03004 }

void OpNodePathEditBlob::RecalculatePaths Path pEditPath,
DocCoord  Offset,
BOOL  SnapEnds = FALSE,
INT32  SnapIndex = 0
[protected]
 

This goes through the path, moves all the selected coords by the offset and then performs some magic to smooth the rest of the path round the changes if it needs it.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
Date:
20/4/2000
Parameters:
Offset - The Amount to move the selected blobs by before re-calcing everything [INPUTS] SnapEnds is TRUE if the start and endpoint should snap (affects smoothing) SnapIndex is the index of the point that's being snapped, so we can only snap one subpath out of many Scope: Private

Definition at line 3027 of file pathedit.cpp.

03028 {
03029     //NodeListItem* pCurrentOrig = (NodeListItem*) OriginalPaths.GetHead ();
03030     //NodeListItem* pCurrentEdit = (NodeListItem*) EditPaths.GetHead ();
03031 
03032     //while (/*(pCurrentOrig) &&*/ (pCurrentEdit))
03033     //{
03034         //NodePath* pOrigPath = (NodePath*) (pCurrentOrig->pNode);
03035     //  Path* pEditPath = (Path*) (pCurrentEdit->pNode);
03036     
03037         // Get the array that I need
03038         PathFlags* Flags  = pEditPath->GetFlagArray();
03039         DocCoord*  Coords = pEditPath->GetCoordArray();
03040 
03041         INT32 NumCoords = pEditPath->GetNumCoords();
03042 
03043         // Go though all the points
03044         for (INT32 i=0; i<NumCoords; i++)
03045         {
03046             // and translate them by the drag offset if they are selected
03047             if (Flags[i].IsSelected)
03048                 Coords[i].translate( Offset.x, Offset.y );
03049         }
03050 
03051         // And now smooth out the new path
03052         pEditPath->SmoothCurve(TRUE, SnapEnds, SnapIndex);
03053 
03054         //pCurrentOrig = (NodeListItem*) OriginalPaths.GetNext (pCurrentOrig);
03055     //  pCurrentEdit = (NodeListItem*) EditPaths.GetNext (pCurrentEdit);
03056     //}
03057 }

void OpNodePathEditBlob::RenderDragBlobs DocRect  Rect,
Spread pSpread,
BOOL  bSolidDrag
[virtual]
 

Renders the new version of the path to the window. It makes use of flags in the path to determine which segments of the path need to be rendered.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
6/9/93

Reimplemented from Operation.

Reimplemented in OpNodePathEditControlBlob.

Definition at line 3069 of file pathedit.cpp.

void OpNodePathEditBlob::RenderDraggingBlobs Path pEditPath,
Spread pSpread
[protected, virtual]
 

Call this function to render all the blobs on screen from this operation.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
Date:
20/4/2000

Definition at line 3100 of file pathedit.cpp.

03101 {
03102     RenderPathEditBlobs(pEditPath, pSpread);
03103 }

void OpNodePathEditBlob::RenderDraggingBlobs DocRect  Rect,
Spread pSpread
[protected, virtual]
 

Call this function to render all the blobs on screen from this operation.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
1/5/95

Reimplemented in OpNodePathEditControlBlob.

Definition at line 3085 of file pathedit.cpp.

03086 {
03087     RenderPathEditBlobs(Rect, pSpread);
03088 }

void OpNodePathEditBlob::RenderPathEditBlobs Path pEditPath,
Spread pSpread
[protected]
 

Call this function to render all the blobs on screen from this operation.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
Date:
20/4/2000

Definition at line 3213 of file pathedit.cpp.

03214 {
03215     // First we have to build a path to render
03216     Path RenderPath;
03217     if ( RenderPath.Initialise(24, 12) == FALSE )
03218     {
03219         // We did not get the memory, so don't draw anything
03220         return;
03221     }
03222 
03223     DocRect Rect = pEditPath->GetBoundingRect();
03224 
03225     BOOL IsInCurve = FALSE;
03226     INT32 NumCoords = pEditPath->GetNumCoords();
03227     for (INT32 i=0; i<NumCoords; i++)
03228     {
03229         // Dereference the pointers I need
03230         PathFlags* Flags  = pEditPath->GetFlagArray();
03231         DocCoord*  Coords = pEditPath->GetCoordArray();
03232         PathVerb*  Verbs  = pEditPath->GetVerbArray();
03233 
03234         // We only consider the end points
03235         if (Flags[i].IsEndPoint)
03236         {
03237             if (IsInCurve)
03238             {
03239                 // we are already adding to the curve, so see if we should continue adding
03240                 if (Flags[i].NeedToRender)
03241                 {
03242                     switch (Verbs[i] & (~PT_CLOSEFIGURE))
03243                     {
03244                         case PT_MOVETO:
03245                             RenderPath.InsertMoveTo(Coords[i]);
03246                             break;
03247 
03248                         case PT_LINETO:
03249                             RenderPath.InsertLineTo(Coords[i]);
03250                             break;
03251 
03252                         case PT_BEZIERTO:
03253                             RenderPath.InsertCurveTo(Coords[i-2], Coords[i-1], Coords[i]);
03254                             break;
03255 
03256                         default:
03257                             break;
03258                     }
03259                 }
03260                 else
03261                 {
03262                     IsInCurve = FALSE;
03263                 }
03264             }
03265             else
03266             {
03267                 // We are not currently adding to the render path, so start
03268                 if (Flags[i].NeedToRender)
03269                 {
03270                     switch (Verbs[i] & (~PT_CLOSEFIGURE))
03271                     {
03272                     case PT_MOVETO:
03273                         RenderPath.InsertMoveTo(Coords[i]);
03274                         break;
03275                     case PT_BEZIERTO:
03276                         RenderPath.InsertMoveTo(Coords[i-3]);
03277                         RenderPath.InsertCurveTo(Coords[i-2],Coords[i-1],Coords[i]);
03278                         break;
03279                     case PT_LINETO:
03280                         RenderPath.InsertMoveTo(Coords[i-1]);
03281                         RenderPath.InsertLineTo(Coords[i]);
03282                         break;
03283                     }
03284                     IsInCurve = TRUE;
03285                 }
03286             }
03287         }
03288     }
03289 
03290     // And if we've snapped to another curve
03291     if (SnapToLineOrCurve)
03292     {
03293         // We are snapping to another curve, so render the curve
03294         RenderPath.InsertMoveTo(SnapToCoords[0]);
03295         RenderPath.InsertCurveTo(SnapToCoords[1],SnapToCoords[2],SnapToCoords[3]);
03296     }
03297     
03298     // Make sure that there is something to draw
03299     if (RenderPath.GetNumCoords()==0)
03300         return;
03301 
03302     // And this bit actually draws the path we have just made
03303     RenderRegion* pRegion = DocView::RenderOnTop( NULL, StartSpread, ClippedEOR );
03304     while (pRegion != NULL)
03305     {
03306         pRegion->SetLineColour( COLOUR_XORNEW );    // Set the line colour 
03307         pRegion->DrawPath( &RenderPath );           // Draw an EORed version of how the path will turn out
03308         pRegion = DocView::GetNextOnTop( &Rect );   // Get the next render region
03309     }
03310 }

void OpNodePathEditBlob::RenderPathEditBlobs DocRect  Rect,
Spread pSpread
[protected]
 

Definition at line 3106 of file pathedit.cpp.

03107 {
03108     // First we have to build a path to render
03109     Path RenderPath;
03110     if ( RenderPath.Initialise(24, 12) == FALSE )
03111     {
03112         // We did not get the memory, so don't draw anything
03113         return;
03114     }
03115 
03116     BOOL IsInCurve = FALSE;
03117     INT32 NumCoords = EditPath.GetNumCoords();
03118     for (INT32 i=0; i<NumCoords; i++)
03119     {
03120         // Dereference the pointers I need
03121         PathFlags* Flags  = EditPath.GetFlagArray();
03122         DocCoord*  Coords = EditPath.GetCoordArray();
03123         PathVerb*  Verbs  = EditPath.GetVerbArray();
03124 
03125         // We only consider the end points
03126         if (Flags[i].IsEndPoint)
03127         {
03128             if (IsInCurve)
03129             {
03130                 // we are already adding to the curve, so see if we should continue adding
03131                 if (Flags[i].NeedToRender)
03132                 {
03133                     switch (Verbs[i] & (~PT_CLOSEFIGURE))
03134                     {
03135                         case PT_MOVETO:
03136                             RenderPath.InsertMoveTo(Coords[i]);
03137                             break;
03138 
03139                         case PT_LINETO:
03140                             RenderPath.InsertLineTo(Coords[i]);
03141                             break;
03142 
03143                         case PT_BEZIERTO:
03144                             RenderPath.InsertCurveTo(Coords[i-2], Coords[i-1], Coords[i]);
03145                             break;
03146 
03147                         default:
03148                             break;
03149                     }
03150                 }
03151                 else
03152                 {
03153                     IsInCurve = FALSE;
03154                 }
03155             }
03156             else
03157             {
03158                 // We are not currently adding to the render path, so start
03159                 if (Flags[i].NeedToRender)
03160                 {
03161                     switch (Verbs[i] & (~PT_CLOSEFIGURE))
03162                     {
03163                     case PT_MOVETO:
03164                         RenderPath.InsertMoveTo(Coords[i]);
03165                         break;
03166                     case PT_BEZIERTO:
03167                         RenderPath.InsertMoveTo(Coords[i-3]);
03168                         RenderPath.InsertCurveTo(Coords[i-2],Coords[i-1],Coords[i]);
03169                         break;
03170                     case PT_LINETO:
03171                         RenderPath.InsertMoveTo(Coords[i-1]);
03172                         RenderPath.InsertLineTo(Coords[i]);
03173                         break;
03174                     }
03175                     IsInCurve = TRUE;
03176                 }
03177             }
03178         }
03179     }
03180 
03181     // And if we've snapped to another curve
03182     if (SnapToLineOrCurve)
03183     {
03184         // We are snapping to another curve, so render the curve
03185         RenderPath.InsertMoveTo(SnapToCoords[0]);
03186         RenderPath.InsertCurveTo(SnapToCoords[1],SnapToCoords[2],SnapToCoords[3]);
03187     }
03188     
03189     // Make sure that there is something to draw
03190     if (RenderPath.GetNumCoords()==0)
03191         return;
03192 
03193     // And this bit actually draws the path we have just made
03194     RenderRegion* pRegion = DocView::RenderOnTop( NULL, StartSpread, ClippedEOR );
03195     while (pRegion != NULL)
03196     {
03197         pRegion->SetLineColour( COLOUR_XORNEW );    // Set the line colour 
03198         pRegion->DrawPath( &RenderPath );           // Draw an EORed version of how the path will turn out
03199         pRegion = DocView::GetNextOnTop( &Rect );   // Get the next render region
03200     }
03201 }

void OpNodePathEditBlob::SetStatusLineHelp  )  [protected, virtual]
 

Updates the status line message to reflect the current situation.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
4/1/95

Reimplemented in OpNodePathEditControlBlob, OpNodePathAddEndpoint, and OpReshapeOrAddPoint.

Definition at line 3367 of file pathedit.cpp.

03368 {
03369     String_256 HelpString;
03370     if (EndSnapped)
03371         HelpString = String_256(_R(IDS_PATHDRAGCREATESHAPE));
03372     else
03373     {
03374         if (SnapToAnother)
03375             HelpString = String_256(_R(IDS_PATHDRAGJOINPATHS));
03376         else
03377             HelpString = String_256(_R(IDS_PATHDRAGFINISH));
03378     }
03379     GetApplication()->UpdateStatusBarText(&HelpString, FALSE);
03380 }

void OpNodePathEditBlob::SnapEndsTogether Path pEditPath  )  [protected]
 

Sets the closefigure flag in the last element in the subpath. Also turns off the rotate bit in the points we're snapping together if their smoothing bits are also turned off. This prevents us creating a cusp that has rotate flags set.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (based upon Jim)
Date:
17/5/00
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: -

See also:
-

Definition at line 1775 of file pathedit.cpp.

01776 {
01777     // If ends are snapping, there can only be one selected point on the path...
01778     // Get a pointer to the path's verbs
01779     PathVerb* Verbs = pEditPath->GetVerbArray();
01780     PathFlags* Flags = pEditPath->GetFlagArray();
01781     INT32 NumCoords = pEditPath->GetNumCoords();
01782 
01783     // Find the selected point
01784     INT32               pos;
01785     for ( pos = 0;pos<NumCoords && !(Flags[pos].IsEndPoint && Flags[pos].IsSelected);pos++);
01786 
01787     // Now pos is the index of the selected point
01788 
01789     // This next may seem like a lot of faffing around, but we don't know whether the 
01790     // selected point is the start or the end of the path, so this code doesn't care
01791     // (thus it's not very optimal, but it shouldn't matter).
01792     
01793     // Move to the start of the edit path
01794     INT32 startpos = pos;
01795     pEditPath->FindStartOfSubPath(&startpos);
01796     // find the end element (might be a curve or a line)
01797     pos=startpos;
01798     pEditPath->FindEndOfSubPath(&pos);
01799 
01800     // if the last element is a bezier, pos points at the first control point
01801     // so we have to add 2 to move to the endpoint of the curve
01802     if (Verbs[pos] == PT_BEZIERTO)
01803         pos+=2;
01804     
01805     // Now simply set the PT_CLOSEFIGURE flag in this verb
01806     Verbs[pos] |= PT_CLOSEFIGURE;
01807     
01808     // make sure the first and last points are selected, along with adjacent ctrl points
01809     Flags[pos].IsSelected = TRUE;
01810     // if it's a bezier, select previous control point and check state of smooth/rotate bits
01811     if ((Verbs[pos] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
01812     {
01813         Flags[pos-1].IsSelected = TRUE;
01814         
01815         // if the smooth flag is not set, clear the rotate flag as well, otherwise
01816         // We'll have something that looks like a cusp, but as soon as you drag a control
01817         // point, the opposite point will rotate around.
01818         if (!Flags[pos-1].IsSmooth)
01819             Flags[pos-1].IsRotate = FALSE;
01820 
01821         // Do the same for the endpoint...
01822         if (!Flags[pos].IsSmooth)
01823             Flags[pos].IsRotate = FALSE;
01824     }
01825     pos = startpos;
01826     Flags[pos].IsSelected = TRUE;
01827     if (Verbs[pos+1] == PT_BEZIERTO)
01828     {
01829         Flags[pos+1].IsSelected = TRUE;
01830 
01831         // As above, clear the rotate bit if the smooth bit is clear
01832         if (!Flags[pos+1].IsSmooth)
01833             Flags[pos+1].IsRotate = FALSE;
01834         // Do the same for the endpoint...
01835         if (!Flags[pos].IsSmooth)
01836             Flags[pos].IsRotate = FALSE;
01837     }
01838 }

void OpNodePathEditBlob::SnapEndsTogether  )  [protected]
 

Sets the closefigure flag in the last element in the subpath. Also turns off the rotate bit in the points we're snapping together if their smoothing bits are also turned off. This prevents us creating a cusp that has rotate flags set.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/7/94
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: -

See also:
-

Definition at line 1692 of file pathedit.cpp.

01693 {
01694     // If ends are snapping, there can only be one selected point on the path...
01695     // Get a pointer to the path's verbs
01696     PathVerb* Verbs = EditPath.GetVerbArray();
01697     PathFlags* Flags = EditPath.GetFlagArray();
01698     INT32 NumCoords = EditPath.GetNumCoords();
01699 
01700     // Find the selected point
01701     INT32               pos;
01702     for( pos = 0; pos < NumCoords && !( Flags[pos].IsEndPoint && Flags[pos].IsSelected); pos++ );
01703 
01704     // Now pos is the index of the selected point
01705 
01706     // This next may seem like a lot of faffing around, but we don't know whether the 
01707     // selected point is the start or the end of the path, so this code doesn't care
01708     // (thus it's not very optimal, but it shouldn't matter).
01709     
01710     // Move to the start of the edit path
01711     INT32               startpos = pos;
01712     EditPath.FindStartOfSubPath(&startpos);
01713     // find the end element (might be a curve or a line)
01714     pos=startpos;
01715     EditPath.FindEndOfSubPath(&pos);
01716 
01717     // if the last element is a bezier, pos points at the first control point
01718     // so we have to add 2 to move to the endpoint of the curve
01719     if (Verbs[pos] == PT_BEZIERTO)
01720         pos+=2;
01721     
01722     // Now simply set the PT_CLOSEFIGURE flag in this verb
01723     Verbs[pos] |= PT_CLOSEFIGURE;
01724     
01725     // make sure the first and last points are selected, along with adjacent ctrl points
01726     Flags[pos].IsSelected = TRUE;
01727     // if it's a bezier, select previous control point and check state of smooth/rotate bits
01728     if ((Verbs[pos] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
01729     {
01730         Flags[pos-1].IsSelected = TRUE;
01731         
01732         // if the smooth flag is not set, clear the rotate flag as well, otherwise
01733         // We'll have something that looks like a cusp, but as soon as you drag a control
01734         // point, the opposite point will rotate around.
01735         if (!Flags[pos-1].IsSmooth)
01736             Flags[pos-1].IsRotate = FALSE;
01737 
01738         // Do the same for the endpoint...
01739         if (!Flags[pos].IsSmooth)
01740             Flags[pos].IsRotate = FALSE;
01741     }
01742     pos = startpos;
01743     Flags[pos].IsSelected = TRUE;
01744     if (Verbs[pos+1] == PT_BEZIERTO)
01745     {
01746         Flags[pos+1].IsSelected = TRUE;
01747 
01748         // As above, clear the rotate bit if the smooth bit is clear
01749         if (!Flags[pos+1].IsSmooth)
01750             Flags[pos+1].IsRotate = FALSE;
01751         // Do the same for the endpoint...
01752         if (!Flags[pos].IsSmooth)
01753             Flags[pos].IsRotate = FALSE;
01754     }
01755 }


Member Data Documentation

DocCoord OpNodePathEditBlob::ConstrainNextPoint [protected]
 

Definition at line 205 of file pathedit.h.

DocCoord OpNodePathEditBlob::ConstrainPoint [protected]
 

Definition at line 203 of file pathedit.h.

DocCoord OpNodePathEditBlob::ConstrainPrevPoint [protected]
 

Definition at line 204 of file pathedit.h.

INT32 OpNodePathEditBlob::CurrentCursorID [protected]
 

Definition at line 232 of file pathedit.h.

INT32 OpNodePathEditBlob::DragPoint [protected]
 

Definition at line 241 of file pathedit.h.

BOOL OpNodePathEditBlob::DragStarted [protected]
 

Definition at line 244 of file pathedit.h.

ObjChangePathEdit OpNodePathEditBlob::EditObjChange [protected]
 

Definition at line 237 of file pathedit.h.

Path OpNodePathEditBlob::EditPath [protected]
 

Definition at line 209 of file pathedit.h.

List OpNodePathEditBlob::EditPaths [protected]
 

Definition at line 213 of file pathedit.h.

BOOL OpNodePathEditBlob::EndSnapped [protected]
 

Definition at line 221 of file pathedit.h.

DocCoord OpNodePathEditBlob::LastMousePos [protected]
 

Definition at line 202 of file pathedit.h.

BOOL OpNodePathEditBlob::MultiplePaths [protected]
 

Definition at line 216 of file pathedit.h.

Cursor* OpNodePathEditBlob::MyCurrentCursor [protected]
 

Definition at line 231 of file pathedit.h.

List OpNodePathEditBlob::ObjChanges [protected]
 

Definition at line 239 of file pathedit.h.

NodePath* OpNodePathEditBlob::OriginalPath [protected]
 

Definition at line 208 of file pathedit.h.

List OpNodePathEditBlob::OriginalPaths [protected]
 

Definition at line 212 of file pathedit.h.

List OpNodePathEditBlob::PathsDragStarted [protected]
 

Definition at line 214 of file pathedit.h.

Cursor* OpNodePathEditBlob::pCloseCursor [protected]
 

Definition at line 229 of file pathedit.h.

Cursor* OpNodePathEditBlob::pCrossHairCursor [protected]
 

Definition at line 230 of file pathedit.h.

Cursor* OpNodePathEditBlob::pMoveCursor [protected]
 

Definition at line 228 of file pathedit.h.

BOOL OpNodePathEditBlob::SnapToAnother [protected]
 

Definition at line 222 of file pathedit.h.

DocCoord OpNodePathEditBlob::SnapToCoords[4] [protected]
 

Definition at line 226 of file pathedit.h.

INT32 OpNodePathEditBlob::SnapToIndex [protected]
 

Definition at line 224 of file pathedit.h.

BOOL OpNodePathEditBlob::SnapToLineOrCurve [protected]
 

Definition at line 225 of file pathedit.h.

NodePath* OpNodePathEditBlob::SnapToPath [protected]
 

Definition at line 223 of file pathedit.h.

DocCoord OpNodePathEditBlob::StartMousePos [protected]
 

Definition at line 201 of file pathedit.h.

Spread* OpNodePathEditBlob::StartSpread [protected]
 

Definition at line 200 of file pathedit.h.

INT32 OpNodePathEditBlob::UpdatePoint [protected]
 

Definition at line 242 of file pathedit.h.


The documentation for this class was generated from the following files:
Generated on Sat Nov 10 03:58:33 2007 for Camelot by  doxygen 1.4.4