BezierTool Class Reference

This class handles the Free Hand Tool that is used to draw lines that follow the path of the Mouse Pointer. More...

#include <beztool.h>

Inheritance diagram for BezierTool:

Tool_v1 List of all members.

Public Types

enum  CurrentMode { New, Add, Change }

Public Member Functions

 BezierTool ()
 Dump Constructor - It does nothing. All the real initialisation is done in BezierTool::Init which is called by the Tool Manager.
 ~BezierTool ()
 Destructor (Virtual). Does nothing.
BOOL Init ()
 Used to check if the Tool was properly constructed.
void Describe (void *InfoPtr)
 Allows the tool manager to extract information about the tool.
UINT32 GetID ()
void SelectChange (BOOL)
 Called when the tool is selected or deselected. Creates and pushes the tool's cursor; pops and destroys it.
void OnClick (DocCoord, ClickType, ClickModifiers, Spread *)
 To handle a Mouse Click event for the Bezier Tool. It starts up a Bezier Operation.
virtual void RenderToolBlobs (Spread *, DocRect *)
 Renders the Tools Blobs. The only blob this tool renders is the floating endpoint which only appears the the flag is set.
void HandleInfoBarMessage (CDlgMessage DlgMsg, CGadgetID Gadget)
void OnMouseMove (DocCoord, Spread *, ClickModifiers)
 This routine is called whenever the mouse moves while we're in the freehand tool. it sees what is under the pointer, and flips the cursor if clicking will have a different effect. The rules are:.
BOOL OnKeyPress (KeyPress *)
 To handle keypress events for the Bezier Tool. If it is a keypress that it know about it starts up an appropiate operation. THIS IS BADLY WRONG AT THE MOMENT - WHEN THERE IS THE TECHNOLOGY FOR USER DEFINABLE KEY-SHORTCUTS THIS FUNCTION WILL NEED FIXING.
void SetMoveTo (DocCoord MovePos, Spread *pSpread, Document *pDoc)
 This function is called from an operation which tells the tool that there should be a virtual moveTo coordinate at the given point. This virtual coordinate looks much like the old single moveto used to in ArtWorks, with the added advantage that it doesn't really exist, so it can't cock up the tree like they used to do in ArtWorks.
void ClearMoveTo ()
 Clears the floating endpoint condition.
BOOL GetMoveTo (Spread **ppSpread, DocCoord *pCoord, Document **ppDoc)
 Read the state of the floating endpoint.
void SetModeFlag ()
 Sets the current tool mode (new/add/change) and gets the infobar to redraw the text item that shows it. We are in New mode if there are no selected lines. We are in Add mode if there is just one endpoint on the end od a path selected. Otherwise we are in Change mode.
BOOL GetStatusLineText (String_256 *ptext, Spread *pSpread, DocCoord DocPos, ClickModifiers ClickMods)
 generate up-to-date text for the status line (called on idles)
void GenerateStatusLineText (String_256 *ptext, Spread *pSpread, DocCoord DocPos, ClickModifiers ClickMods)
 To find the string to display on the status line given the current mouse position.

Protected Member Functions

BOOL CyclePathPoints (BOOL Fowards)
 Performs the cycle the selected points task. The selection status of each endpoint on selected paths is applied to the next endpoint.
BOOL HomePathPoints ()
 Moves the selected endpoints back along the selected path(s) so that the first point is selected. The pattern of selection remains the same.
BOOL EndPathPoints ()
 Moves the selected endpoints foward along the selected path(s) so that the last point is selected. The pattern of selection remains the same.
BOOL AutoClosePaths ()
 Runs through all selected lines. If the path is open and either of the ends are selected then the path is closed.
void RemoveFloater (DocCoord *FloatPos, Spread *FloatSpread, Document *pDoc)
 Invokes the operation to remove the floating endpoint.
void RetroSmoothChanging (double Smooth)
 Scan the selection for a path to smooth. If we find only one path object selected then we should tell the retro smooth code to begin smoothing. Arh!, actually we need to be able to keep track of the selected object? possibly.... Surely its fast enough already to find the selected objects, there must be some caching going on somewhere. Ok, best thing to do is to make sure theres only one selected object and ignore the slider change if there isn't.
void RetroSmoothFinished ()
 Calls the retro smooth finalisation code to perform the completed smoothing action.
void RetroSmoothSet (INT32 percent, BOOL Enabled)
 Set the position of the retro smooth slider, given a percentage value. The function will also update the percent text field.
void RetroSmoothInvalidate ()
 Invalidate the retro smooth cached information.
void UpdateRetroSlider (Path *pPath)
 Sets the retro smooth slider position for a given path.
void ResetRetroSlider ()
 There has been a change in the selection so we need to update the retro slider state.
NodeOneNodePathSelected ()
 Checks the selection and determins whether exactly one nodepath object is selected.
void ChangeCursor (Cursor *cursor)
 Changes to the specified cursor. Will only change the cursor if it isn't already this cursor, so it doesn't flicker.
clickeffect DetermineClickEffect (DocCoord PointerPos, Spread *pSpread, NodeRenderableInk **ReturnNode, INT32 *ReturnPosition, INT32 *NumSelectedPaths, INT32 *NumSelectedPoints)
 Used when the cursor moves and when single clicking. This routine determines what effect a click will have. In this tool, clicking will either select a point on an already selected line, reshape a line segment (a la Corel), add a segment to the end of a line, or start a new path entirely.
NodePathFindEditablePath (Node *pSelected)
 Finds the node to edit (if it exists). This node could actually be the selected node passed as a parameter or one of its children which the node wants to be editable.

Protected Attributes

DocCoord StartPos
SpreadStartSpread
CursorpcMoveBezCursor
CursorpcReshapeLineCursor
CursorpcNewPathCursor
CursorpcAddPathCursor
CursorpcClosePathCursor
CursorMyCurrentCursor
INT32 CurrentCursorID
BOOL FloatingEndpoint
DocumentMoveToDoc
DocCoord MoveToPoint
SpreadMoveToSpread
RetroSmoothpSmooth
BOOL RetroFlag
NodepRetroNode
SpreadpRetroSpread
BOOL DontDrawOnClearMoveTo
CurrentMode CurrentToolMode

Static Protected Attributes

static TCHARFamilyName = _T("Drawing Tools")
static TCHARToolName = _T("Bezier Tool")
static TCHARPurpose = _T("To Draw arbitrary lines")
static TCHARAuthor = _T("Jim (latterly Peter)")
static BezToolInfoBarOppBezToolInfoBarOp = NULL
static BOOL CreateCurve = TRUE
static BOOL CreateCusp = FALSE

Private Member Functions

 CC_DECLARE_MEMDUMP (BezierTool)

Friends

class BezToolInfoBarOp

Detailed Description

This class handles the Free Hand Tool that is used to draw lines that follow the path of the Mouse Pointer.

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

Definition at line 242 of file beztool.h.


Member Enumeration Documentation

enum BezierTool::CurrentMode
 

Enumerator:
New 
Add 
Change 

Definition at line 250 of file beztool.h.

00250 {New, Add, Change};


Constructor & Destructor Documentation

BezierTool::BezierTool  ) 
 

Dump Constructor - It does nothing. All the real initialisation is done in BezierTool::Init which is called by the Tool Manager.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
21/6/93
See also:
BezierTool::Init

Definition at line 197 of file beztool.cpp.

00198 {
00199     StartSpread = NULL;
00200     FloatingEndpoint = FALSE;
00201     MoveToDoc = NULL;
00202     MoveToSpread = NULL;
00203     pSmooth = NULL;
00204     RetroFlag = FALSE;
00205     DontDrawOnClearMoveTo = FALSE;
00206     CurrentToolMode = New;
00207 }

BezierTool::~BezierTool  ) 
 

Destructor (Virtual). Does nothing.

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

Definition at line 221 of file beztool.cpp.

00222 {
00223     // Destroy any resident retro smooth object
00224     if (pSmooth != NULL)
00225     {
00226         delete pSmooth;
00227         pSmooth = NULL;
00228     }
00229 
00230     pBezToolInfoBarOp->pBezTool = NULL;
00231 }


Member Function Documentation

BOOL BezierTool::AutoClosePaths  )  [protected]
 

Runs through all selected lines. If the path is open and either of the ends are selected then the path is closed.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/12/95
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
TRUE if all went well, FALSE if an error occured.
See also:
-

Definition at line 4363 of file beztool.cpp.

04364 {
04365     OpState Calcium = OpCloseNodePaths::GetState(NULL, NULL);
04366 
04367     if (!Calcium.Greyed)
04368     {
04369         OpParam Param(CreateCurve, !CreateCusp);
04370         OpDescriptor* Apple = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpCloseNodePaths));
04371         if (Apple != NULL)
04372             Apple->Invoke(&Param);
04373     }
04374 
04375     return TRUE;
04376 }

BezierTool::CC_DECLARE_MEMDUMP BezierTool   )  [private]
 

void BezierTool::ChangeCursor Cursor cursor  )  [protected]
 

Changes to the specified cursor. Will only change the cursor if it isn't already this cursor, so it doesn't flicker.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
16/3/94
Parameters:
ID of the cursor you want to flip to [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: can fail if the cursor cannot be created - the cursor code will fail.

See also:
-

Definition at line 1472 of file beztool.cpp.

01473 {
01474     // only change if this cursor is different from the current cursor
01475     if (cursor != MyCurrentCursor)
01476     {
01477         // set this cursor as the current cursor and immediately display it
01478         CursorStack::GSetTop(cursor, CurrentCursorID);
01479         // remember this is our current cursor
01480         MyCurrentCursor = cursor;
01481     }
01482 
01483 }

void BezierTool::ClearMoveTo  ) 
 

Clears the floating endpoint condition.

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

Errors: -

See also:
BezierTool::SetMoveTo

Definition at line 1539 of file beztool.cpp.

01540 {
01541     if (FloatingEndpoint && IsCurrent() && !DontDrawOnClearMoveTo)
01542     {
01543         BlobManager* pBlobManager = GetApplication()->GetBlobManager();
01544         ENSURE(pBlobManager, "Can't get BlobManager");
01545         pBlobManager->RenderToolBlobsOff(this, MoveToSpread,NULL);
01546     }
01547     FloatingEndpoint = FALSE;
01548 }

BOOL BezierTool::CyclePathPoints BOOL  Fowards  )  [protected]
 

Performs the cycle the selected points task. The selection status of each endpoint on selected paths is applied to the next endpoint.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/10/94
Parameters:
Fowards - TRUE if the point selection status are to move fowards, otherwise [INPUTS] they move backwards.
Returns:
TRUE if all went well, FALSE if an error occured

Errors: -

See also:
-

Definition at line 2968 of file beztool.cpp.

02969 {   
02970     // Obtain the current selections and the first node in the selection
02971     SelRange*   Selected = GetApplication()->FindSelection();
02972     Node*       pNode = Selected->FindFirst();
02973     NodePath*   ThisPath;
02974 
02975     // Holds the coords of the last selected point we find on our travels,
02976     // we then call DocView::ScrolToShowWithMargin to ensure that this point is visible
02977     DocCoord LastSelectedPoint;
02978     BOOL LastSelectedPointValid = FALSE;    // does LastSelectedPoint hold a valid value?
02979 
02980     while (pNode != NULL)
02981     {   // we're only interested in NodePaths which have selected points
02982         NodePath* pSelected = FindEditablePath(pNode);
02983         if (pSelected)
02984         {
02985                 // for convenience, cast the pointer to a pointer to a NodePath
02986                 ThisPath = pSelected;
02987 
02988                 // First get pointers to the arrays
02989                 PathFlags*  Flags = ThisPath->InkPath.GetFlagArray();
02990                 PathVerb*   Verbs = ThisPath->InkPath.GetVerbArray();
02991                 DocCoord*   Coords = ThisPath->InkPath.GetCoordArray();
02992                 const INT32 NumCoords = ThisPath->InkPath.GetNumCoords();
02993             
02994             if (pSelected->InkPath.IsSubSelection())
02995             {   
02996                 // Render off the current selection blobs
02997                 ThisPath->InkPath.RenderPathSelectedControlBlobs(pNode->FindParentSpread());
02998 
02999                 if (Fowards)
03000                 {   
03001                     INT32 Current = 0;
03002                     INT32 Next = 0;
03003                     BOOL MoreEndpoints = TRUE;
03004                     BOOL PrevSelected = Flags[0].IsSelected;
03005 
03006                     while (MoreEndpoints)
03007                     {
03008                         // Find the next endpoint
03009                         MoreEndpoints = ThisPath->InkPath.FindNextEndPoint(&Next);  
03010                         if (MoreEndpoints && (Verbs[Next] & PT_CLOSEFIGURE))
03011                             MoreEndpoints = ThisPath->InkPath.FindNextEndPoint(&Next);
03012                         if (MoreEndpoints)
03013                         {
03014                             BOOL temp = Flags[Next].IsSelected;
03015                             Flags[Next].IsSelected = PrevSelected;
03016                             if (Flags[Next].IsSelected)
03017                             {
03018                             LastSelectedPoint = Coords[Next];
03019                             LastSelectedPointValid = TRUE;
03020                             }
03021                             PrevSelected= temp;
03022                             Current = Next;
03023                         }
03024                         else
03025                         {
03026                             Flags[0].IsSelected = PrevSelected;
03027                             if (Flags[0].IsSelected)
03028                             {
03029                                 LastSelectedPoint = Coords[0];
03030                                 LastSelectedPointValid = TRUE;
03031                             }
03032                         }
03033                     }
03034 
03035                     // Tidy up the selection state
03036                     ThisPath->InkPath.EnsureSelection(TRUE);
03037                 }
03038                 else                                                        
03039                 {
03040                     INT32 Current = NumCoords-1;
03041                     INT32 Next = Current;
03042                     BOOL MoreEndpoints = TRUE;
03043                     BOOL PrevSelected = Flags[Current].IsSelected;
03044                     BOOL ClosedPath = (Verbs[Next] & PT_CLOSEFIGURE);
03045 
03046                     while (MoreEndpoints)
03047                     {
03048                         // Find the previous endpoint
03049                         MoreEndpoints = ThisPath->InkPath.FindPrevEndPoint(&Next);  
03050                         if (MoreEndpoints && ClosedPath && (Verbs[Next] == PT_MOVETO))
03051                             MoreEndpoints = ThisPath->InkPath.FindPrevEndPoint(&Next);
03052                         if (MoreEndpoints)
03053                         {
03054                             BOOL temp = Flags[Next].IsSelected;
03055                             Flags[Next].IsSelected = PrevSelected;
03056                             if (Flags[Next].IsSelected)
03057                             {
03058                                 LastSelectedPoint = Coords[Next];
03059                                 LastSelectedPointValid = TRUE;
03060                             }
03061                             PrevSelected = temp;
03062                             Current = Next;
03063                         }
03064                         else
03065                         {
03066                             Flags[NumCoords-1].IsSelected = PrevSelected;
03067                             if (Flags[NumCoords-1].IsSelected)
03068                             {
03069                                 LastSelectedPoint = Coords[NumCoords-1];
03070                                 LastSelectedPointValid = TRUE;
03071                             }
03072                         }
03073                     }
03074 
03075                     // Tidy up the selection state
03076                     ThisPath->InkPath.EnsureSelection(FALSE);
03077                 }
03078 
03079             }
03080             // If no SubSelection
03081             else
03082             {
03083                 if (Fowards) 
03084                 {
03085                     Flags[0].IsSelected = TRUE;
03086                     ThisPath->InkPath.EnsureSelection(TRUE);
03087                 }
03088                 else
03089                     Flags[NumCoords-1].IsSelected = TRUE; 
03090                     ThisPath->InkPath.EnsureSelection(FALSE);
03091             }
03092     
03093             // Render on the new selection blobs
03094             ThisPath->InkPath.RenderPathSelectedControlBlobs(pNode->FindParentSpread());
03095         }
03096         pNode = Selected->FindNext(pNode);
03097     }
03098     DialogBarOp::SetSystemStateChanged();       
03099     if (LastSelectedPointValid)
03100     {
03101         DocView* pDocView = DocView::GetSelected();
03102         if (pDocView != NULL)
03103         {
03104             pDocView->ScrollToShowWithMargin(&LastSelectedPoint);
03105         }
03106     }
03107     return TRUE;
03108 }

void BezierTool::Describe void *  InfoPtr  )  [virtual]
 

Allows the tool manager to extract information about the tool.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
21/6/93
Parameters:
InfoPtr - A pointer to a tool info block. It is passed cast to void* as [INPUTS] the version of the tool is unknown at this point. Later versions of the Tool class may have more items in this block, that this tool will not use
InfoPtr - The structure pointed to by InfoPtr will have had all the info [OUTPUTS] that this version of the Tool knows about

Reimplemented from Tool_v1.

Definition at line 334 of file beztool.cpp.

00335 {
00336     // Cast structure into the latest one we understand.
00337     ToolInfo_v1 *Info = (ToolInfo_v1 *) InfoPtr;
00338 
00339     Info -> InfoVersion = 1;
00340     
00341     Info -> InterfaceVersion = GetToolInterfaceVersion();  // You should always have this line.
00342         
00343     // These are all arbitrary at present.
00344     Info -> Version = 1;
00345     Info -> ID      = GetID();
00346     Info -> TextID  = _R(IDS_BEZIER_TOOL);
00347 
00348     Info -> Family  = FamilyName;
00349     Info -> Name    = ToolName;
00350     Info -> Purpose = Purpose;
00351     Info -> Author  = Author;
00352 
00353     Info -> InfoBarDialog = _R(IDD_BEZTOOLBAR);
00354 
00355     Info -> BubbleID = _R(IDBBL_LINETOOL);
00356     Info -> StatusID = _R(IDS_LINETOOL);
00357 }

clickeffect BezierTool::DetermineClickEffect DocCoord  PointerPos,
Spread pSpread,
NodeRenderableInk **  ReturnNode,
INT32 *  ReturnPosition,
INT32 *  NumSelectedPaths,
INT32 *  NumSelectedPoints
[protected]
 

Used when the cursor moves and when single clicking. This routine determines what effect a click will have. In this tool, clicking will either select a point on an already selected line, reshape a line segment (a la Corel), add a segment to the end of a line, or start a new path entirely.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
29/4/94
Parameters:
PointerPos is the mouse position [INPUTS] pSpread is a pointer to the spread containing the mouse position
ReturnNode returns a pointer to the node the mouse would click on [OUTPUTS] ReturnPosition returns the index into the nodepath of the affected point NumSelectedPaths is the number of paths in the selection NumSelectedPoints is the total number of selected points (on all paths)
Returns:
The effect of clicking - one of NewPath, AddSegment, OnPoint or ReshapeLine

Definition at line 1199 of file beztool.cpp.

01202 {
01203     clickeffect WhatToDo = NewPath; // tells me what effect the click would have
01204     INT32 PathPosition = 0;         // temp var for return value
01205     INT32 TempIndex = 0;                // Temporary index into a path
01206     INT32 NumSelPaths = 0;          // Number of selected paths
01207     double Distance = 0;            // gets the returned distance from the nearest point
01208     double Nearest = 0;             // distance of current nearest point
01209     NodeRenderableInk* WhichNode = NULL;    // Saves me using a pointer to a pointer
01210 
01211     // Scan through the selected paths, and see if any of them want the click
01212 
01213     DocRect BlobRect;
01214     DocView* pDocView = DocView::GetCurrent();
01215     ERROR2IF( pDocView==NULL, NewPath, "BezierTool::DetermineClickEffect: Can't find current DocView");
01216 
01217     // Find the selected range of objects
01218     SelRange* Selected = GetApplication()->FindSelection();
01219     Node* pNode = Selected->FindFirst();
01220 
01221     INT32 NumSelectedEndpoints = 0;     // Count selected points in paths
01222 
01223     if (pNode != NULL)
01224     {
01225         Spread* NodeSpread = pNode->FindParentSpread();
01226         if (NodeSpread == pSpread)
01227         {
01228             // On the same spread, so see if the pointer is over an endpoint
01229             while ((pNode != NULL) && WhatToDo!=OnPoint)
01230             {
01231                 NodePath* pActNode = FindEditablePath(pNode);
01232                 if (pActNode)
01233                 {
01234 
01235                     // Now we know it's a NodePath, get a pointer to the Path object within it, so
01236                     // we can find any endpoints
01237                 
01238                     Path* ThisPath = &((pActNode)->InkPath);
01239 
01240                     // Increment the number of selected paths
01241                     NumSelPaths++;
01242                     
01243                     // count the number of selected points on the path (excluding control points)
01244                     INT32 NumCoords = ThisPath->GetNumCoords();
01245                     PathFlags* Flags = ThisPath->GetFlagArray();
01246 
01247                     for (INT32 i=0; i<NumCoords; i++)
01248                     {
01249                         if (Flags[i].IsSelected && Flags[i].IsEndPoint)
01250                             NumSelectedEndpoints++;
01251                     }
01252 
01253                     if (ThisPath->FindStartOfPath())
01254                     {
01255                         // First, check to see if this click occurs on a selected point
01256                         INT32 tempPos;
01257                         if (ThisPath->FindNearestPoint(PointerPos,
01258                                                        POINTFLAG_ENDPOINTS |
01259                                                        POINTFLAG_CONTROLPOINTS |
01260                                                        POINTFLAG_ENDSFIRST,
01261                                                        &tempPos)
01262                            )
01263                         {
01264                             // The click occurred on one of the points on the line
01265                             // so remember this path, the position, and the fact that
01266                             // the user clicked on a point
01267 
01268                             WhatToDo = OnPoint;
01269                             WhichNode = (NodeRenderableInk*)pActNode;
01270                             PathPosition = tempPos;
01271                         }
01272                         else if (WhatToDo != OnPoint && ThisPath->PointCloseToLine(PointerPos, &tempPos))
01273                         {
01274                             WhatToDo = ReshapeLine;
01275                             WhichNode = (NodeRenderableInk*)pActNode;
01276                             PathPosition = tempPos;
01277                         }
01278                         else if ((WhatToDo == AddSegment || WhatToDo == NewPath) && ThisPath->ClosestSelectedEndpoint(PointerPos,&TempIndex,&Distance))
01279                         {
01280                             // TempIndex is the index into the path for the closest selected endpoint
01281                             // Distance is the distance
01282                             if (WhatToDo == NewPath)
01283                             {
01284                                 WhatToDo = AddSegment;
01285                                 WhichNode = (NodeRenderableInk*)pActNode;
01286                                 Nearest = Distance;
01287                                 PathPosition = TempIndex;
01288                             }
01289                             else if (Nearest > Distance)
01290                             {
01291                                 Nearest = Distance;
01292                                 WhichNode = (NodeRenderableInk*)pActNode;
01293                                 PathPosition = TempIndex;
01294                             }
01295                         }
01296                     }
01297                 }
01298                 // Now find the next selected node
01299                 pNode = Selected->FindNext(pNode);
01300             }
01301         }
01302     }
01303 
01304     // WhatToDo tells us what the action will be
01305     // WhichNode points to the node we are dealing with
01306     // PathPosition is the index into that path of the element we are using
01307 
01308     // If WhatToDo == OnPoint and it's the end of a subpath, and the opposite
01309     // end is selected, and the path isn't closed we should change WhatToDo 
01310     // to be ClosePath
01311 
01312     if (WhatToDo == OnPoint && NumSelectedEndpoints == 1)
01313     {
01314         Path* ThisPath = &(((NodePath*)WhichNode)->InkPath);
01315         PathFlags* Flags = ThisPath->GetFlagArray();
01316         PathVerb* Verbs = ThisPath->GetVerbArray();
01317 //      DocCoord* Coords = ThisPath->GetCoordArray();
01318         INT32 NumCoords = ThisPath->GetNumCoords();
01319         if (Verbs[PathPosition] == PT_MOVETO)           // Start of subpath
01320         {
01321             INT32 i = PathPosition;
01322             ThisPath->FindEndElOfSubPath(&i);               // i = index to end element
01323             
01324             if ((Flags[i].IsSelected) && !(Verbs[i] & PT_CLOSEFIGURE))
01325                 WhatToDo = ClosePath;
01326         }
01327         else if (PathPosition+1 == NumCoords || Verbs[PathPosition+1] == PT_MOVETO)
01328         {
01329             if (!(Verbs[PathPosition] & PT_CLOSEFIGURE))
01330             {
01331                 INT32 i = PathPosition;
01332                 ThisPath->FindStartOfSubPath(&i);
01333                 if (Flags[i].IsSelected)
01334                     WhatToDo = ClosePath;
01335             }
01336         }
01337         // Now we must detect the case of an attempted closepath on a path consisting
01338         // of a moveto and one segment
01339         if ((WhatToDo == ClosePath) && ( (((NodePath*)WhichNode)->InkPath.GetNumCoords() == 2) ||
01340             ((((NodePath*)WhichNode)->InkPath.GetNumCoords() == 4) && (Verbs[3] == PT_BEZIERTO)) ) )
01341         {
01342             WhatToDo = OnPoint;
01343         }
01344     }
01345 
01346 
01347     if ((WhatToDo == AddSegment || WhatToDo == ClosePath) && NumSelectedEndpoints > 1)
01348         WhatToDo = NewPath;
01349 
01350     if (WhatToDo == AddSegment || WhatToDo == ReshapeLine)
01351     {
01352         // If we're pointing at a curve, make sure we're pointing to the first element
01353         Path* ThisPath = &(((NodePath*)WhichNode)->InkPath);
01354         PathFlags* flags = ThisPath->GetFlagArray();
01355         while(!(flags[PathPosition].IsEndPoint ))
01356             PathPosition++;
01357         ThisPath->SetPathPosition(PathPosition);
01358         if (ThisPath->GetVerb() == PT_BEZIERTO)
01359             PathPosition-=2;
01360     }
01361 
01362     *ReturnPosition = PathPosition;
01363     *ReturnNode = WhichNode;
01364     *NumSelectedPoints = NumSelectedEndpoints;
01365     *NumSelectedPaths = NumSelPaths;
01366     return (WhatToDo);
01367 }

BOOL BezierTool::EndPathPoints  )  [protected]
 

Moves the selected endpoints foward along the selected path(s) so that the last point is selected. The pattern of selection remains the same.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/1/94
Parameters:
- [INPUTS]
Returns:
TRUE if all went well, FALSE if an error occured

Errors: -

See also:
BezierTool::HomePathPoints

Definition at line 3247 of file beztool.cpp.

03248 {   
03249     // Obtain the current selections and the first node in the selection
03250     SelRange*   Selected = GetApplication()->FindSelection();
03251     Node*       pNode = Selected->FindFirst();
03252     NodePath*   ThisPath;
03253 
03254     // Variable to hold the position of the last 'end point'. This is updated as we
03255     // loop through the selection until it holds the end point of the last line
03256     // in the selection with subselection.
03257     DocCoord LastEndPoint;
03258     BOOL LastEndPointValid = FALSE;
03259 
03260     while (pNode != NULL)
03261     {   // we're only interested in NodePaths which have selected points
03262             NodePath* pSelected = FindEditablePath(pNode);
03263             if (pSelected)
03264             {
03265                 // for convenience, cast the pointer to a pointer to a NodePath
03266                 ThisPath = pSelected;
03267 
03268                 // First get pointers to the arrays
03269                 PathFlags*  Flags = ThisPath->InkPath.GetFlagArray();
03270                 PathVerb*   Verbs = ThisPath->InkPath.GetVerbArray();
03271                 DocCoord*   Coords = ThisPath->InkPath.GetCoordArray();
03272                 INT32   NumCoords = ThisPath->InkPath.GetNumCoords()-1;
03273                 if (pSelected->InkPath.IsSubSelection() ) 
03274                 {
03275                     // We only need to bother if the last endpoint is not selected!
03276                     if (!Flags[NumCoords].IsSelected)
03277                     {
03278                         // Render off the current selection blobs
03279                         ThisPath->InkPath.RenderPathSelectedControlBlobs(pNode->FindParentSpread());
03280 
03281                         // Find the last selected point
03282                         INT32 Offset = NumCoords;
03283                         while ((Offset > -1) && !(Flags[Offset].IsSelected && Flags[Offset].IsEndPoint))
03284                     
03285                         {
03286                             Offset--;
03287                         }
03288 
03289                         ERROR3IF(Offset == -1,"No selected endpoint found when there was one");
03290 
03291                         // Now we can move the selection on to the end
03292                         INT32 Current = NumCoords;
03293                         BOOL MoreEndpoints = TRUE;
03294 
03295                         while (MoreEndpoints)
03296                         {
03297                             Flags[Current].IsSelected = Flags[Offset].IsSelected;
03298                             MoreEndpoints = ThisPath->InkPath.FindPrevEndPoint(&Offset);    
03299                             if (MoreEndpoints && (Verbs[Offset] & PT_CLOSEFIGURE))
03300                                 MoreEndpoints = ThisPath->InkPath.FindPrevEndPoint(&Offset);
03301                             if (MoreEndpoints)
03302                             {
03303                                 ThisPath->InkPath.FindPrevEndPoint(&Current);   
03304                                 if (Verbs[Current] & PT_CLOSEFIGURE)
03305                                     ThisPath->InkPath.FindPrevEndPoint(&Current);   
03306                             }   
03307                             else
03308                                 Current --;
03309                         }
03310 
03311                         // Unselect the remaining endpoints
03312                         while (Current > -1)
03313                         {
03314                             Flags[Current--].IsSelected = FALSE;
03315                         }
03316 
03317                         // Now fix up the selections so if the starts of subpaths are selected then so are the ends
03318                         ThisPath->InkPath.EnsureSelection(FALSE);
03319     
03320                         // Render on the new selection blobs
03321                         ThisPath->InkPath.RenderPathSelectedControlBlobs(pNode->FindParentSpread());
03322                     }
03323                 
03324                     // this path is in the selection, and has a subselection, so remember its end point
03325                     // position, as it may be the last end point
03326                     LastEndPoint = Coords[NumCoords];
03327                     LastEndPointValid = TRUE;
03328             }
03329 
03330             else
03331             {
03332                     Flags[NumCoords].IsSelected = TRUE;
03333                     // Now fix up the selections so if the starts of subpaths are selected then so are the ends
03334                     ThisPath->InkPath.EnsureSelection(FALSE);
03335                     // Render on the new selection blobs
03336                     ThisPath->InkPath.RenderPathSelectedControlBlobs(pNode->FindParentSpread());        
03337             }                               
03338         }
03339         pNode = Selected->FindNext(pNode);
03340     }
03341     DialogBarOp::SetSystemStateChanged();       
03342 
03343     // scroll to show the last end point (if it exists) at the coordinates we remembered earlier
03344     if (LastEndPointValid)
03345     {
03346         DocView* pDocView = DocView::GetSelected();
03347         if (pDocView != NULL)
03348         {
03349             pDocView->ScrollToShowWithMargin(&LastEndPoint);
03350         }
03351     }
03352 
03353     return TRUE;
03354 }

NodePath * BezierTool::FindEditablePath Node pSelected  )  [protected]
 

Finds the node to edit (if it exists). This node could actually be the selected node passed as a parameter or one of its children which the node wants to be editable.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/3/95
Parameters:
pSelected = A pointer to the selected node to check [INPUTS]
- [OUTPUTS]
Returns:
A pointer to an editable node path (or derived) object NULL if there isn't one.

Definition at line 1387 of file beztool.cpp.

01388 {
01389     if (pSelected->IsNodePath())
01390         return ((NodePath*)pSelected);
01391 
01392     return ((NodePath*)pSelected->HasEditableChild(CC_RUNTIME_CLASS(NodePath), NULL));
01393 }

void BezierTool::GenerateStatusLineText String_256 ptext,
Spread pSpread,
DocCoord  coord,
ClickModifiers  mods
 

To find the string to display on the status line given the current mouse position.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
08/12/94
Parameters:
pSpread - pointer to spread under mouse (else NULL) [INPUTS] DocPos - position of mouse in doc (in spread coords) ClickMods - mouse click modifiers
ptext - text for status line [OUTPUTS]
Returns:
-

Errors: -

Definition at line 3623 of file beztool.cpp.

03624 {
03625     // Call DetermineClickEffect to see what a click will do at this position
03626 
03627     INT32 PathPosition;         // Needed to receive a return, not used otherwise
03628     NodeRenderableInk* node;    // again, only temporary
03629     INT32 NumPts;               // Number of selected points
03630     INT32 NumPaths;             // Number of selected paths
03631     clickeffect WhatToDo = DetermineClickEffect(coord, pSpread, &node, &PathPosition, &NumPaths, &NumPts);
03632 
03633     switch (WhatToDo)
03634     {
03635     case AddSegment:
03636         if (CreateCurve)
03637             ptext->Load(_R(IDS_ADD_SEGMENT),Tool::GetModuleID(GetID()));
03638         else
03639             ptext->Load(_R(IDS_ADDLINESEGMENT),Tool::GetModuleID(GetID()));
03640         break;
03641     case NewPath:
03642         if (FloatingEndpoint)
03643         {
03644             if (CreateCurve)
03645             {
03646                 if (NumPts == 0)
03647                     ptext->Load(_R(IDS_CLICK_TO_MAKE_NEW),Tool::GetModuleID(GetID()));
03648                 else
03649                     ptext->Load(_R(IDS_CLICK_TO_MAKE_NEW),Tool::GetModuleID(GetID()));
03650             }
03651             else
03652             {
03653                 ptext->Load(_R(IDS_CLICKMAKENEWLINE),Tool::GetModuleID(GetID()));
03654             }
03655         }
03656         else
03657         {
03658             if (CreateCurve)
03659             {
03660                 if (NumPts == 0)
03661                     ptext->Load(_R(IDS_STARTNEWCURVENOSEL),Tool::GetModuleID(GetID()));
03662                 else
03663                     ptext->Load(_R(IDS_CREATE_NEW_PATH),Tool::GetModuleID(GetID()));
03664             }
03665             else
03666             {
03667                 if (NumPts == 0)
03668                     ptext->Load(_R(IDS_STARTNEWLINENOSEL),Tool::GetModuleID(GetID()));
03669                 else
03670                     ptext->Load(_R(IDS_STARTNEWLINE),Tool::GetModuleID(GetID()));
03671             }
03672         }
03673         break;
03674     case OnPoint:
03675         // There are various different combinations of selected/unselected, which require
03676         // different status line messages
03677         {
03678             NodePath* ThisPath = (NodePath*)node;
03679 //          PathVerb* Verbs = ThisPath->InkPath.GetVerbArray();
03680             PathFlags* Flags = ThisPath->InkPath.GetFlagArray();
03681             INT32 ptype = 0;
03682             if (Flags[PathPosition].IsSelected)
03683                 ptype |= 1;
03684             if (Flags[PathPosition].IsEndPoint)
03685                 ptype |= 2;
03686             if (Flags[PathPosition].IsRotate)
03687                 ptype |= 4;
03688 
03689             // Now ptype holds a number from 0 to 7 which completely describes what type of
03690             // point this is, so we can use that to select the correct string
03691             switch(ptype)
03692             {
03693                 case 0:     //Unselected, unsmoothed control point
03694                 case 4:     // UnSelected, smoothed control point 
03695                 case 1:     // Selected, unsmoothed control point
03696                 case 5:     // Selected, smoothed control point
03697                     ptext->Load(_R(IDS_SELCONTROL),Tool::GetModuleID(GetID()));
03698                     break;
03699                 case 2:     // UnSelected, unsmoothed end point
03700                     ptext->Load(_R(IDS_UNSELCUSP),Tool::GetModuleID(GetID()));
03701                     break;
03702                 case 3:     // Selected, unsmoothed end point
03703                     ptext->Load(_R(IDS_SELCUSP),Tool::GetModuleID(GetID()));
03704                     break;
03705                 case 6:     // UnSelected, smoothed end point
03706                     ptext->Load(_R(IDS_UNSELSMOOTH),Tool::GetModuleID(GetID()));
03707                     break;
03708                 case 7:     // Selected, smoothed end point
03709                     ptext->Load(_R(IDS_SELSMOOTH),Tool::GetModuleID(GetID()));
03710                     break;
03711             }
03712         }
03713         break;
03714     case ReshapeLine:
03715         ptext->Load(_R(IDS_RESHAPE_LINE),Tool::GetModuleID(GetID()));
03716         break;
03717     case ClosePath:
03718         ptext->Load(_R(IDS_CLOSEPATH),Tool::GetModuleID(GetID()));
03719         break;
03720     }
03721 }

UINT32 BezierTool::GetID void   )  [inline, virtual]
 

Reimplemented from Tool_v1.

Definition at line 256 of file beztool.h.

00256 { return TOOLID_BEZTOOL; };

BOOL BezierTool::GetMoveTo Spread **  ppSpread,
DocCoord pCoord,
Document **  ppDoc
 

Read the state of the floating endpoint.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
05/12/94
Parameters:
ppSpread - pointer to a pointer to a spread [INPUTS] pCoord - pointer to a DocCoord
*ppSpread is set to point to the spread the floating endpoint is on [OUTPUTS] pCoord is set to the location of the floating endpoint
Returns:
TRUE if there was a floating endpoint, FALSE if not (in this case there is no outputs)

Errors: -

See also:
BezierTool::SetMoveTo, BezierTool::ClearMoveTo

Definition at line 1570 of file beztool.cpp.

01571 {
01572     if (FloatingEndpoint)
01573     {
01574         *ppSpread = MoveToSpread;
01575         *pCoord = MoveToPoint;
01576         *ppDoc = MoveToDoc;
01577         return TRUE;
01578     }
01579     else
01580         return FALSE;
01581 }

BOOL BezierTool::GetStatusLineText String_256 ptext,
Spread pSpread,
DocCoord  DocPos,
ClickModifiers  ClickMods
[virtual]
 

generate up-to-date text for the status line (called on idles)

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
08/12/94
Parameters:
pSpread - pointer to spread under mouse (else NULL) [INPUTS] DocPos - position of mouse in doc (in spread coords) ClickMods - mouse click modifiers
ptext - text for status line [OUTPUTS]
Returns:
TRUE if outputting valid text

Errors: ERROR3 if ptext is NULL

Reimplemented from Tool_v1.

Definition at line 3592 of file beztool.cpp.

03593 {
03594     ERROR2IF(ptext==NULL,FALSE,"ptext was NULL");
03595 
03596     *ptext = "";
03597 
03598     GenerateStatusLineText(ptext, pSpread, DocPos, ClickMods);
03599 
03600     return TRUE;
03601 }

void BezierTool::HandleInfoBarMessage CDlgMessage  DlgMsg,
CGadgetID  Gadget
 

BOOL BezierTool::HomePathPoints  )  [protected]
 

Moves the selected endpoints back along the selected path(s) so that the first point is selected. The pattern of selection remains the same.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/1/94
Parameters:
- [INPUTS]
Returns:
TRUE if all went well, FALSE if an error occured

Errors: -

See also:
BezierTool::EndPathPoints

Definition at line 3125 of file beztool.cpp.

03126 {   
03127     // Obtain the current selections and the first node in the selection
03128     SelRange*   Selected = GetApplication()->FindSelection();
03129     Node*