PenTool Class Reference

This class handles the Pen Tool that is used to draw lines and curves via clicking and draging on the workarea. More...

#include <pentool.h>

Inheritance diagram for PenTool:

Tool_v1 List of all members.

Public Member Functions

 PenTool ()
 Dummy Constructor - It does nothing. All the real initialisation is done in PenTool::Init which is called by the Tool Manager.
 ~PenTool ()
 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.
virtual void OnClick (DocCoord, ClickType, ClickModifiers, Spread *)
 To handle a Mouse Click event for the Pen Tool.
virtual void RenderToolBlobs (Spread *, DocRect *)
 The blobs this tool renders are (1) a moveto floating endpoint (2) a dragto floating endpoint These are usually rendered after the first click/drag on a document.
virtual BOOL GetStatusLineText (String_256 *, Spread *, DocCoord, ClickModifiers)
 generate up-to-date text for the status line (called on idles)
virtual void OnMouseMove (DocCoord, Spread *, ClickModifiers)
 This routine is called whenever the mouse moves while we're in the pen tool. it sees what is under the pointer, and flips the cursor if clicking will have a different effect.
virtual BOOL OnKeyPress (KeyPress *pKeyPress)
 To handle keypress events for the Pen 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 GenerateStatusLineText (NodePath *pNodePath, penclick WhatToDo, String_256 *pStatusMsg)
 Loads up an appropriate help string into the text buffer pointed to by pStatusMsg, using the nodepath and 'whattodo' information passed.
void SetInternalState ()
 This function is called from an operation which tells the tool that there should be a virtual moveto coordinate and dragto coordinate set within the tool. If the dragto is equal to the moveto, then an internal move should be created, rather than an internal drag.
void ClearInternalState ()
 Clears the internal condition.
BOOL OverPathEnd (DocCoord, Spread *, NodePath **)
penclick DetermineClickEffect (DocCoord, Spread *, NodePath **)
 Used when single clicking. This routine determines what effect a click will have. In this tool, clicking will add a segment to the end of a line, adjust the last element of a path or start a new path entirely.
void RemoveSelection (DocCoord PointerPos, Spread *pSpread, NodePath *pNodePath=NULL)
 This routine scans the specified spread for all path objects and checks whether the mouse coord is over an open end point. It can be used to work out whether to change the mouse shape or not. This routine should really exist in some other file, available to all tools but I dont know where to put it yet so it shall have to stay here for the mo.
void ClearPath ()
 Throw away the internal data of the pen path.
void ClearOp ()
 Throw away the internal op state we've been holding.
void CreateNewPath ()
 Once a drag has finished we need to build a new path with the data.
void AddElementToPath ()
 Once a drag has finished we need to add the newly edited element to the specified path.
void CloseWithPath ()
 Once a drag has finished we need to add the newly edited element to the specified path.
penopstate GetPenOpState () const
 return the operation state the pen tool thinks its in.

Private Member Functions

 CC_DECLARE_MEMDUMP (PenTool)
void ClickOnEndPoint (ClickType Click, ClickModifiers ClickMods, Spread *pSpread, NodePath *pNodePath)
 An end point click has occured. This function acts on such a click by selecting the point or editing the point dependent on the click type.
BOOL CreatePenCursors ()
 Pen tool cursor creation.
void DeletePenCursors ()
 Pen tool cursor deletion.
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.

Private Attributes

penstate CurrPenState
penopstate CurrPenOpState
Path EditPath
ControlPts EditHandles
NodePathpNodePath
INT32 NodeIndex
CursorpcPenCursor
CursorpcPenAdjustCursor
CursorpcPenReshapeCursor
CursorpcMoveBezCursor
CursorMyCurrentCursor
INT32 CurrentCursorID
PenToolInfoBarOppPenInfoBarOp

Static Private Attributes

static TCHARFamilyName = _T("Drawing Tools")
static TCHARToolName = _T("Pen Tool")
static TCHARPurpose = _T("To draw lines and curves")
static TCHARAuthor = _T("Mike")

Detailed Description

This class handles the Pen Tool that is used to draw lines and curves via clicking and draging on the workarea.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/9/94

Definition at line 158 of file pentool.h.


Constructor & Destructor Documentation

PenTool::PenTool  ) 
 

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

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/9/94
See also:
PenTool::Init

Definition at line 162 of file pentool.cpp.

00163 {
00164     pcPenCursor = NULL;
00165     pcPenAdjustCursor = NULL;
00166     pcPenReshapeCursor = NULL;
00167     pcMoveBezCursor = NULL;
00168     MyCurrentCursor = NULL;
00169 
00170     CurrPenState = IS_Undefined;
00171 }

PenTool::~PenTool  ) 
 

Destructor (Virtual). Does nothing.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/9/94

Definition at line 186 of file pentool.cpp.

00187 {
00188     // Dummy destructor
00189 }


Member Function Documentation

void PenTool::AddElementToPath  ) 
 

Once a drag has finished we need to add the newly edited element to the specified path.

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

Errors: -

See also:
-

Definition at line 1668 of file pentool.cpp.

01669 {
01670     // Right, the last drag has created a new path section for me
01671     // I need to add it in to the specified nodepath object
01672 
01673     OpAddPathToPath* pOpAddPathToPath = new OpAddPathToPath;
01674     pOpAddPathToPath->DoAddPathToPath(pNodePath, &EditPath, NodeIndex);
01675 }

PenTool::CC_DECLARE_MEMDUMP PenTool   )  [private]
 

void PenTool::ChangeCursor Cursor cursor  )  [private]
 

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

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
20/9/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 1492 of file pentool.cpp.

01493 {
01494     // only change if this cursor is different from the current cursor
01495     if (cursor != MyCurrentCursor)
01496     {
01497         // set this cursor as the current cursor and immediately display it
01498         CursorStack::GSetTop(cursor, CurrentCursorID);
01499         // remember this is our current cursor
01500         MyCurrentCursor = cursor;
01501     }
01502 }

void PenTool::ClearInternalState  ) 
 

Clears the internal condition.

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

Errors: -

See also:
-

Definition at line 1556 of file pentool.cpp.

01557 {
01558     if (CurrPenState == IS_MoveTo || CurrPenState == IS_DragTo)
01559     {
01560         BlobManager* BlobMgr = GetApplication()->GetBlobManager();
01561         ENSURE(BlobMgr!=NULL, "Blob Manager was not there");
01562         BlobMgr->RenderToolBlobsOff(this, EditHandles.pHndSpread,NULL);
01563     }
01564     CurrPenState = IS_Undefined;
01565 }

void PenTool::ClearOp  ) 
 

Throw away the internal op state we've been holding.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/9/94
Parameters:
- [INPUTS]

Definition at line 1604 of file pentool.cpp.

01605 {
01606     CurrPenOpState = OS_Undefined;
01607 }

void PenTool::ClearPath  ) 
 

Throw away the internal data of the pen path.

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

Errors: -

See also:
-

Definition at line 1585 of file pentool.cpp.

01586 {
01587     // call the path clearing function!
01588 
01589     ClearInternalState();
01590     EditPath.ClearPath();
01591 }

void PenTool::ClickOnEndPoint ClickType  Click,
ClickModifiers  ClickMods,
Spread pSpread,
NodePath pNodePath
[private]
 

An end point click has occured. This function acts on such a click by selecting the point or editing the point dependent on the click type.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
26/9/94
Parameters:
Click - Describes the type of click that was detected. [INPUTS] ClickMods - Indicates which buttons caused the click and which modifers were pressed at the same time pSpread - the spread in which the click happened pNodePath - The path on which the click happened (current pos set to the point clicked on)
- [OUTPUTS]
Returns:
-

Definition at line 913 of file pentool.cpp.

00914 {
00915     Path* pPath = &(pNodePath->InkPath);
00916 
00917     DocCoord* Coords = pPath->GetCoordArray();
00918     PathFlags* Flags = pPath->GetFlagArray();
00919     PathVerb*  Verbs = pPath->GetVerbArray();
00920     INT32 NumCoords = pPath->GetNumCoords();
00921 
00922     // grab the index of the point actually clicked on!
00923     INT32 Pos = pPath->GetPathPosition();
00924 
00925     // Clicks on control points have no effect
00926     // but clicks on endpoints do have an effect
00927 
00928     switch (Click)
00929     {
00930         case CLICKTYPE_SINGLE:
00931         {
00932             if (Flags[Pos].IsEndPoint)
00933             {
00934                 pPath->RenderPathPenBlobs(pSpread);
00935 
00936                 BOOL CurSelState = Flags[Pos].IsSelected;
00937                 BOOL NewSelState = TRUE;
00938                 BOOL ClearOthers = FALSE;
00939                 
00940                 // if shift held down then toggle the point whatever
00941                 if (ClickMods.Adjust) 
00942                     NewSelState = !CurSelState;
00943 
00944                 // if the end point is not selected and we're not toggling
00945                 if (!CurSelState && !ClickMods.Adjust)
00946                     ClearOthers=TRUE;
00947                     
00948                 if (ClearOthers)
00949                 {
00950                     for (INT32 i=0; i<NumCoords; i++)
00951                     {
00952                         Flags[i].IsSelected = FALSE;
00953                     }
00954                 }
00955 
00956                 // Now change the selection of this point
00957                 Flags[Pos].IsSelected = NewSelState;
00958 
00959                 if ((Pos>0) && (!Flags[Pos-1].IsEndPoint))
00960                     Flags[Pos-1].IsSelected = NewSelState;
00961 
00962                 if ((Pos+1<NumCoords) && (!Flags[Pos+1].IsEndPoint))
00963                     Flags[Pos+1].IsSelected = NewSelState;
00964 
00965                 // Check for this being the first element in a closed subpath
00966                 // If this element is a moveto, and the end of the path has the
00967                 // CLOSEFIGURE flag set, we should select the endpoint as well
00968                 if (Verbs[Pos] == PT_MOVETO)
00969                 {
00970                     // This for loop will find either the end of the path, or the next moveto
00971                     INT32 j;
00972                     for (j=Pos+1;j<NumCoords && Verbs[j] != PT_MOVETO;j++); // ; is intentional!
00973                     j--;
00974                     if (Verbs[j] & PT_CLOSEFIGURE)
00975                     {
00976                         //HandleBlobClick(Coords,Flags,j,NumCoords,TRUE);
00977                         Flags[j].IsSelected = NewSelState;
00978                         // If the previous point is a control point then deal with it
00979                         if ((j>0) && (!Flags[j-1].IsEndPoint))
00980                         {
00981                             // Change the control point's selection state
00982                             Flags[j-1].IsSelected = NewSelState;
00983                         }
00984                     }
00985 
00986                 }
00987 
00988                 pPath->RenderPathPenBlobs(pSpread);
00989             }
00990             break;
00991         }
00992 
00993         case CLICKTYPE_DOUBLE:
00994             break;
00995 
00996         case CLICKTYPE_DRAG:
00997         {
00998             if ((Flags[Pos].IsEndPoint) && (!ClickMods.Menu))
00999             {
01000                 // Need to do a drag on the selected points, so we had better start an operation
01001                 OpNodePathEditBlob* pOpNodePath = new OpNodePathEditBlob;
01002                 if (pOpNodePath == NULL)
01003                     InformError();
01004                 else
01005                     pOpNodePath->DoStartDragEdit(pNodePath, Coords[Pos], pSpread);
01006             }
01007         }
01008         break;
01009 
01010         default:
01011         {
01012         }
01013         break;
01014     }
01015 }

void PenTool::CloseWithPath  ) 
 

Once a drag has finished we need to add the newly edited element to the specified path.

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

Errors: -

See also:
-

Definition at line 1694 of file pentool.cpp.

01695 {
01696     // Right, the last drag has closed a path.
01697     // I need to add it in to the specified nodepath object
01698 
01699     OpClosePathWithPath* pOpClosePathWithPath = new OpClosePathWithPath;
01700     pOpClosePathWithPath->DoClosePathWithPath(pNodePath, &EditPath, NodeIndex);
01701 }

void PenTool::CreateNewPath  ) 
 

Once a drag has finished we need to build a new path with the data.

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

Errors: -

See also:
-

Definition at line 1642 of file pentool.cpp.

01643 {
01644     // Ok, the last drag has altered our internal drag path. We now
01645     // have a path ready to add to the tree, so we need to get on with it!
01646     OpAddNewPath* pOpAddNewPath = new OpAddNewPath;
01647     pOpAddNewPath->DoAddNewPath(&EditPath, EditHandles.pHndSpread);
01648 }

BOOL PenTool::CreatePenCursors  )  [private]
 

Pen tool cursor creation.

BOOL PenTool::CreatePenCursors()

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

Definition at line 406 of file pentool.cpp.

00407 {
00408     pcPenAdjustCursor = new Cursor(this, _R(IDC_PENADJUSTCURSOR));
00409     if (!pcPenAdjustCursor || !pcPenAdjustCursor->IsValid())
00410     {
00411         DeletePenCursors();
00412         InformError( _R(IDS_OUT_OF_MEMORY), _R(IDS_OK) );
00413         return FALSE;                                        
00414     }
00415 
00416     pcPenCursor = new Cursor(this, _R(IDC_NEWPATHCURSOR));
00417     if (!pcPenCursor || !pcPenCursor->IsValid())
00418     {
00419         DeletePenCursors();
00420         InformError( _R(IDS_OUT_OF_MEMORY), _R(IDS_OK) );
00421         return FALSE;
00422     }
00423 
00424     pcPenReshapeCursor = new Cursor(this, _R(IDC_RESHAPECURSOR));
00425     if (!pcPenReshapeCursor || !pcPenReshapeCursor->IsValid())
00426     {
00427         DeletePenCursors();
00428         InformError( _R(IDS_OUT_OF_MEMORY), _R(IDS_OK) );
00429         return FALSE;                                        
00430     }
00431 
00432     pcMoveBezCursor = new Cursor(this, _R(IDC_MOVEBEZIERCURSOR));
00433     if (!pcMoveBezCursor || !pcMoveBezCursor->IsValid())
00434     {
00435         DeletePenCursors();
00436         InformError( _R(IDS_OUT_OF_MEMORY), _R(IDS_OK) );
00437         return FALSE;
00438     }
00439 
00440     return TRUE;
00441 }

void PenTool::DeletePenCursors  )  [private]
 

Pen tool cursor deletion.

BOOL PenTool::DeletePenCursors()

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

Definition at line 457 of file pentool.cpp.

00458 {
00459     if (pcPenCursor!=NULL)
00460     {
00461         delete pcPenCursor;
00462         pcPenCursor=NULL;
00463     }
00464     
00465     if (pcPenAdjustCursor!=NULL)
00466     {
00467         delete pcPenAdjustCursor;
00468         pcPenAdjustCursor=NULL;
00469     }
00470 
00471     if (pcPenReshapeCursor!=NULL)
00472     {
00473         delete pcPenReshapeCursor;
00474         pcPenReshapeCursor=NULL;
00475     }
00476 
00477     if (pcMoveBezCursor!=NULL)
00478     {
00479         delete pcMoveBezCursor;
00480         pcMoveBezCursor=NULL;
00481     }
00482 }

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

Allows the tool manager to extract information about the tool.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
20/9/94
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 277 of file pentool.cpp.

00278 {
00279     // Cast structure into the latest one we understand.
00280     ToolInfo_v1 *Info = (ToolInfo_v1 *) InfoPtr;
00281 
00282     Info -> InfoVersion = 1;
00283     
00284     Info -> InterfaceVersion = GetToolInterfaceVersion();  // You should always have this line.
00285         
00286     // These are all arbitrary at present.
00287     Info -> Version = 1;
00288     Info -> ID      = GetID();
00289     Info -> TextID  = _R(IDS_PEN_TOOL);
00290 
00291     Info -> Family  = FamilyName;
00292     Info -> Name    = ToolName;
00293     Info -> Purpose = Purpose;
00294     Info -> Author  = Author;
00295     
00296     Info -> InfoBarDialog = _R(IDD_FREEHANDTOOL);
00297 
00298     Info -> BubbleID = _R(IDBBL_PEN_TOOL);
00299 
00300 }

penclick PenTool::DetermineClickEffect DocCoord  PointerPos,
Spread pSpread,
NodePath **  ReturnNode
 

Used when single clicking. This routine determines what effect a click will have. In this tool, clicking will add a segment to the end of a line, adjust the last element of a path or start a new path entirely.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
26/9/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 has clicked on [OUTPUTS]
Returns:
The effect of clicking - one of NewPath, AddSegment, OnPoint or EditInternalMove

Definition at line 752 of file pentool.cpp.

00753 {
00754     penclick WhatToDo = PenNewPath; // tells me what effect the click would have
00755     NodePath* WhichNode = NULL;     // Saves me using a pointer to a pointer
00756 
00757     // Now scan through the selected paths, and see if we've clicked on any endpoints
00758     DocView* pDocView = DocView::GetSelected();
00759     ENSURE( pDocView != NULL, "PenTool::DetermineClickEffect: Can't find selected DocView");
00760     if (pDocView==NULL)
00761         return(PenNewPath);
00762 
00763     // Find the Rect round the mouse pos that counts as a hit
00764     DocRect BlobRect;
00765     OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), PointerPos, BT_SELECTEDLARGEST, &BlobRect);
00766 
00767     // if we're in an internal state and someone has clicked on the moveto
00768     // again then go and edit it.
00769     if (CurrPenState == IS_MoveTo || CurrPenState == IS_DragTo)
00770     {
00771         if (BlobRect.ContainsCoord(EditHandles.HndClick))
00772             return (PenEditInternalMove);
00773     }
00774 
00775 
00776     // Find the selected range of objects
00777     SelRange* Selected = GetApplication()->FindSelection();
00778     Node* pNode = Selected->FindFirst();
00779 
00780     INT32 TotSelectedEndpoints = 0;     // Count selected points in paths
00781     BOOL MultiSegments = FALSE;
00782 
00783     if (pNode != NULL)
00784     {
00785         Spread* NodeSpread = pNode->FindParentSpread();
00786         if (NodeSpread == pSpread)
00787         {
00788             // On the same spread, so see if the pointer is over an endpoint
00789             while ((pNode!=NULL) && ((WhatToDo==PenNewPath) || (WhatToDo==PenAddSegment)))
00790             {
00791                 if (pNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodePath))
00792                 {
00793                     // Now we know it's a NodePath, get a pointer to the Path object within it, so
00794                     // we can find any endpoints
00795                     Path* ThisPath = &(((NodePath*)pNode)->InkPath);
00796 
00797                     // count the number of selected points on the path (excluding control points)
00798                     INT32 NumCoords = ThisPath->GetNumCoords();
00799                     PathFlags* Flags = ThisPath->GetFlagArray();
00800 
00801                     // Count selected points in this path
00802                     INT32 NumSelectedEndpoints = 0;     
00803                     INT32 lastsel = 0;
00804                     for (INT32 i=0; i<NumCoords; i++)
00805                     {
00806                         if (Flags[i].IsSelected && Flags[i].IsEndPoint)
00807                         {
00808                             lastsel = i;
00809                             NumSelectedEndpoints++;
00810                         }
00811                     }
00812                     // Sum up
00813                     TotSelectedEndpoints+=NumSelectedEndpoints;
00814 
00815                     INT32 point;
00816                     // First, see if the mouse is over a point.
00817                     if (ThisPath->FindNearestPoint(PointerPos, POINTFLAG_ENDPOINTS | POINTFLAG_ENDSFIRST, &point))
00818                     {
00819                         WhichNode = (NodePath*)pNode;
00820                         WhatToDo = PenOnPoint;
00821                         ThisPath->SetPathPosition(point);
00822 
00823                         // if the mouse was over an open end and the other end of this sub
00824                         // path is selected then we need to close the path
00825                         // find the start and end of the subpath the point was found in
00826                         INT32 start = point;
00827                         INT32 end = point;
00828                         ThisPath->FindStartOfSubPath(&start);
00829                         ThisPath->FindEndElOfSubPath(&end);
00830                         if (point==start || point==end)
00831                         {
00832                             INT32 other;
00833                             (point==start) ? (other=end) : (other=start);
00834                             if ((Flags[other].IsSelected) && (!Flags[point].IsSelected))
00835                                 WhatToDo = PenClosePath;
00836                         }
00837                         continue;
00838                     }
00839 
00840                     // if the mouse is close to an element, then it might be close
00841                     // enough to reshape the line
00842                     if (ThisPath->PointCloseToLine(PointerPos, &point))
00843                     {
00844                         WhichNode=(NodePath*)pNode;
00845                         WhatToDo=PenReshapeLine;
00846                         ThisPath->SetPathPosition(point);
00847                         continue;
00848                     }
00849 
00850                     if (!MultiSegments && NumSelectedEndpoints==1)
00851                     {
00852                         INT32 start = lastsel;
00853                         INT32 end = lastsel;
00854                         ThisPath->FindStartOfSubPath(&start);
00855                         ThisPath->FindEndElOfSubPath(&end);
00856                         if (lastsel==start || lastsel==end)
00857                         {
00858                             if (WhatToDo==PenNewPath)
00859                             {   
00860                                 WhichNode=(NodePath*)pNode;
00861                                 WhatToDo=PenAddSegment;
00862                                 ThisPath->SetPathPosition(lastsel);
00863                             }
00864                             else
00865                             {
00866                                 // We have more than one path with a selected end point.
00867                                 // Adding elements is ambiguous so force a NewPath creation
00868                                 WhichNode=(NodePath*)pNode;
00869                                 WhatToDo=PenNewPath;
00870                                 MultiSegments=TRUE;
00871                             }
00872                         }
00873                     }
00874                 }
00875                 // Now find the next selected node
00876                 pNode = Selected->FindNext(pNode);
00877             }
00878         }
00879     }
00880 
00881     // WhatToDo tells us what the action will be
00882     // WhichNode points to the node we are dealing with
00883     // PathPosition is the index into that path of the element we are using
00884 
00885     *ReturnNode = WhichNode;
00886     return (WhatToDo);
00887 }

void PenTool::GenerateStatusLineText NodePath pNodePath,
penclick  WhatToDo,
String_256 pStatusMsg
 

Loads up an appropriate help string into the text buffer pointed to by pStatusMsg, using the nodepath and 'whattodo' information passed.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
05/01/95
Parameters:
pNodePath = pointer to a node path the mouse is over [INPUTS] (can be NULL) WhatToDo = what action to be taken (return param of DetermineClickEffect) pStatusMsg = pointer to a 256 character text buffer
pStatusMsg - holds a text string [OUTPUTS]
Returns:
-

Errors: -

Definition at line 1200 of file pentool.cpp.

01201 {
01202     switch (WhatToDo)
01203     {
01204         case PenNewPath:
01205             switch(CurrPenState)
01206             {
01207                 case IS_MoveTo:
01208                     pStatusMsg->Load(_R(IDS_PENADDPOINT), Tool::GetModuleID(GetID()));  
01209                     break;
01210                 case IS_DragTo:
01211                     pStatusMsg->Load(_R(IDS_PENADDCURVE), Tool::GetModuleID(GetID()));  
01212                     break;
01213                 default:
01214                     pStatusMsg->Load(_R(IDS_PENNEWPATH), Tool::GetModuleID(GetID()));
01215                     break;
01216             }
01217             break;
01218 
01219         case PenAddSegment:
01220             if (pNodePath != NULL)
01221             {
01222                 PathVerb  Verb  = (pNodePath->InkPath).GetVerb();
01223                 PathFlags Flags = (pNodePath->InkPath).GetFlags();
01224                 switch (Verb)
01225                 {
01226                     case PT_BEZIERTO:
01227                         if (Flags.IsRotate)
01228                             pStatusMsg->Load(_R(IDS_PENADDCURVE), Tool::GetModuleID(GetID()));
01229                         else
01230                             pStatusMsg->Load(_R(IDS_PENADDPOINT), Tool::GetModuleID(GetID()));
01231                         break;
01232                     default:
01233                         pStatusMsg->Load(_R(IDS_PENADDPOINT), Tool::GetModuleID(GetID()));
01234                         break;
01235                 }
01236             }
01237             else
01238                 pStatusMsg->Load(_R(IDS_PENADDPOINT), Tool::GetModuleID(GetID()));
01239             break;
01240 
01241         case PenEditInternalMove: 
01242             pStatusMsg->Load(_R(IDS_PENEDITINT), Tool::GetModuleID(GetID()));
01243             break;
01244             
01245         case PenClosePath:
01246             pStatusMsg->Load(_R(IDS_PENCLOSEPATH), Tool::GetModuleID(GetID()));
01247             break;
01248 
01249         case PenReshapeLine:
01250             pStatusMsg->Load(_R(IDS_RESHAPE_LINE),Tool::GetModuleID(GetID()));
01251             break;
01252 
01253         case PenOnPoint:
01254             if (pNodePath != NULL)
01255             {
01256                 PathFlags Flags = (pNodePath->InkPath).GetFlags();
01257                 if (Flags.IsSelected)
01258                     pStatusMsg->Load(_R(IDS_PENONSELPOINT), Tool::GetModuleID(GetID()));
01259                 else
01260                     pStatusMsg->Load(_R(IDS_PENONPOINT), Tool::GetModuleID(GetID()));
01261             }
01262             break;
01263             
01264         default:
01265             pStatusMsg->Load(_R(IDS_PENADDPOINT), Tool::GetModuleID(GetID()));
01266             break;
01267     }
01268 }

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

Reimplemented from Tool_v1.

Definition at line 169 of file pentool.h.

00169 { return TOOLID_PEN; };

penopstate PenTool::GetPenOpState  )  const
 

return the operation state the pen tool thinks its in.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/9/94
Parameters:
- [INPUTS]

Definition at line 1621 of file pentool.cpp.

01622 {
01623     return (CurrPenOpState);
01624 }

BOOL PenTool::GetStatusLineText String_256 ptext,
Spread pSpread,
DocCoord  coord,
ClickModifiers  mods
[virtual]
 

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

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
05/01/95
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 1161 of file pentool.cpp.

01162 {
01163     ERROR1IF(ptext==NULL,FALSE,"PenTool::GetStatusLineText() passed a NULL text buffer");
01164 
01165     *ptext = "";
01166 
01167     NodePath* pNodePath = NULL;
01168 
01169     // find what type of click we will generate
01170     penclick WhatToDo = DetermineClickEffect(coord, pSpread, &pNodePath);
01171     GenerateStatusLineText(pNodePath, WhatToDo, ptext);
01172 
01173     return TRUE;
01174 }

BOOL PenTool::Init void   )  [virtual]
 

Used to check if the Tool was properly constructed.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/9/94
Returns:
FALSE if it does not want to be created, TRUE otherwise
See also:
PenTool::PenTool

Reimplemented from Tool_v1.

Definition at line 204 of file pentool.cpp.

00205 {
00206 
00207     BOOL                    ok;
00208     CCResTextFile           file;               // Resource File
00209     PenToolInfoBarOpCreate  BarCreate;          // Object that creates PenInfoBarOp objects
00210 
00211     // This should be set to NULL by default. It will be set properly below, if
00212     // everthing is working as it should
00213     pPenInfoBarOp = NULL;
00214 
00215     // initially, no cursor
00216     pcPenCursor = 0;
00217 
00218     pPenInfoBarOp = new PenToolInfoBarOp();
00219     ok = (pPenInfoBarOp != NULL);
00220     if (ok) pPenInfoBarOp->pPenTool = this;             // Set a pointer from the op to this tool
00221 
00222 #if 0
00223         ok = file.open(_R(IDM_PENTOOL_BAR), _R(IDT_INFO_BAR_RES));          // Open resource
00224     if (ok) ok = DialogBarOp::ReadBarsFromFile(file,BarCreate);     // Read and create info bar
00225     if (ok) file.close();                                           // Close resource.
00226 
00227     ENSURE(ok,"Unable to load penbar.ini from resource\n"); 
00228 
00229     if (ok)
00230     {
00231         // Info bar now exists.  Now get a pointer to it
00232         String_32 str = String_32(_R(IDS_PENTOOL_INFOBARNAME));
00233         DialogBarOp* pDialogBarOp = DialogBarOp::FindDialogBarOp(str);
00234 
00235                 ok = (pDialogBarOp != NULL);
00236         if (ok) ok = pDialogBarOp->IsKindOf(CC_RUNTIME_CLASS(PenToolInfoBarOp));
00237         if (ok) pPenInfoBarOp = (PenToolInfoBarOp*)pDialogBarOp;
00238         if (ok) pPenInfoBarOp->pPenTool = this;             // Set a pointer from the op to this tool
00239 
00240         ENSURE(ok,"Failed to create PENTOOL info bar");
00241     }
00242 #endif
00243 
00244     if (ok) ok = EditPath.Initialise(12,24);                // create the edit path buffers please
00245 
00246     // Register our pen operation(s).
00247     if (ok)
00248     {
00249         ok = OpPenCreateInternal::Init();
00250         if (ok) ok = OpPenEditInternal::Init();
00251         if (ok) ok = OpPenCreatePath::Init();
00252         if (ok) ok = OpPenAddElement::Init();
00253         if (ok) ok = OpAddNewPath::Init();
00254         if (ok) ok = OpPenClosePath::Init();
00255     }
00256 
00257     return ok;
00258 
00259 }

void PenTool::OnClick DocCoord  PointerPos,
ClickType  Click,
ClickModifiers  ClickMods,
Spread pSpread
[virtual]
 

To handle a Mouse Click event for the Pen Tool.

Author:
Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> (via Rik)
Date:
20/9/94
Parameters:
PointerPos - The Coords (in spread coords) of the point where the mouse [INPUTS] button was clicked Click - Describes the type of click that was detected. ClickMods - Indicates which buttons caused the click and which modifers were pressed at the same time pSpread - the spread in which the click happened
Returns:
TRUE if it handled the Click, FALSE otherwise
See also:
Tool::MouseClick; ClickType; ClickModifiers

Reimplemented from Tool_v1.

Definition at line 592 of file pentool.cpp.

00594 {
00595     if (ClickMods.Menu) return;                         // Don't do anything if the user clicked the Menu button
00596 
00597     // determine what to do with this click
00598     penclick WhatToDo = DetermineClickEffect(PointerPos, pSpread, &pNodePath);
00599 
00600     // if someones holding the adjust down and we're not on a point then clear the sel
00601     if (Click==CLICKTYPE_SINGLE && ClickMods.Adjust && WhatToDo!=PenOnPoint)
00602     {
00603         RemoveSelection(PointerPos,pSpread);
00604         ClearInternalState();   
00605         return;
00606     }
00607 
00608     switch (Click)
00609     {
00610         case CLICKTYPE_SINGLE:
00611             switch (WhatToDo)
00612             {
00613                 case PenNewPath:
00614                 {
00615                     BOOL MakeInternal = TRUE;
00616                     if ((CurrPenState == IS_MoveTo) || (CurrPenState == IS_DragTo))
00617                     {
00618                         // create a new path using the internal data points.
00619                         // If LastDragTo==LastMoveTo, then the internal is a point,
00620                         // else a curve control end exists.
00621                         if (EditHandles.pHndSpread==pSpread)
00622                         {
00623                             MakeInternal = FALSE;
00624                             OpPenCreatePath* pOpCreatePath = new OpPenCreatePath;
00625                             if (pOpCreatePath!=NULL)
00626                             {
00627                                 pOpCreatePath->DoPenCreatePath(&EditHandles, PointerPos, pSpread, &EditPath);
00628                                 CurrPenOpState = OS_CreatePath;
00629                             }
00630                         }
00631                     }
00632                     
00633                     if (MakeInternal)
00634                     {
00635                         // First remove any selected points in the spread and create an
00636                         // internal move or dragto
00637                         RemoveSelection(PointerPos,pSpread);
00638                         OpPenCreateInternal* pOpCreateInternal = new OpPenCreateInternal;
00639                         if (pOpCreateInternal!=NULL)
00640                         {
00641                             pOpCreateInternal->DoPenCreateInternal(PointerPos, pSpread, &EditHandles);
00642                             CurrPenOpState = OS_EditInternal; 
00643                         }
00644                     }
00645                 }
00646                 break;
00647 
00648                 case PenClosePath:
00649                     {
00650                         NodeIndex = pNodePath->InkPath.GetPathPosition();
00651                         OpPenClosePath* pOpPenClosePath = new OpPenClosePath;
00652                         if (pOpPenClosePath!=NULL)
00653                         {
00654                             pOpPenClosePath->DoPenClosePath(pNodePath, NodeIndex, pSpread, &EditPath);
00655                             CurrPenOpState = OS_ClosePath;
00656                         }
00657                     }
00658                     break;
00659 
00660                 case PenOnPoint:
00661                     {
00662                         // Ordinary click from OnPoint
00663                         // Currently this does not work correctly because of eor'ing. The wrong
00664                         // Eor blobs get put on by the node path click handler 
00665                         RemoveSelection(PointerPos,pSpread,pNodePath);
00666                         ClickOnEndPoint(Click, ClickMods, pSpread, pNodePath);
00667                     }
00668                     break;
00669 
00670                 case PenAddSegment:
00671                     {
00672                         NodeIndex = pNodePath->InkPath.GetPathPosition();
00673                         OpPenAddElement* pOpPenAddElement = new OpPenAddElement;
00674                         if (pOpPenAddElement!=NULL)
00675                         {
00676                             pOpPenAddElement->DoPenAddElement(pNodePath, NodeIndex, PointerPos, pSpread, &EditPath);
00677                             CurrPenOpState = OS_AddElement;
00678                         }
00679                     }
00680                     break;
00681 
00682                 case PenEditInternalMove:
00683                     {
00684                         OpPenEditInternal* pOpEditInternal = new OpPenEditInternal;
00685                         if (pOpEditInternal!=NULL)
00686                         {
00687                             pOpEditInternal->DoPenEditInternal(&EditHandles);
00688                             CurrPenOpState = OS_EditInternal;
00689                         }
00690                     }
00691                     break;
00692                
00693                case PenReshapeLine:
00694                     {
00695                         double pdist;
00696                         INT32 tempel;
00697                         pNodePath->InkPath.SqrDistanceToPoint(PointerPos, &tempel, &pdist);
00698                         INT32 PathPos = pNodePath->InkPath.GetPathPosition();
00699 
00700                         OpReshapeOrAddPoint* pOpReshape = new OpReshapeOrAddPoint;
00701                         if (pOpReshape!=NULL)
00702                             pOpReshape->