#include <opfree.h>
Inheritance diagram for OpFreeHand:
Public Member Functions | |
OpFreeHand () | |
Constructor. This simply sets a few of the operation flags. | |
void | DoDrag (DocCoord Anchor, Spread *, INT32, FreeHandJoinInfo *pJoinInfo, Path *ToolPath) |
Starts up the drag operation by storing all start positions and setting up a Path to store the mouse movement in. | |
virtual BOOL | SnappingDrag () |
virtual BOOL | DragKeyPress (KeyPress *pKeyPress, BOOL bSolidDrag) |
Find out if any of the key modifiers are being pressed when the mouse is not moving. | |
virtual void | DragPointerMove (DocCoord PointerPos, ClickModifiers ClickMods, Spread *, BOOL bSolidDrag) |
Handles the event of the mouse moving during a drag. | |
virtual void | DragPointerIdle (DocCoord PointerPos, ClickModifiers ClickMods, Spread *, BOOL bSolidDrag) |
This function checks the Adjust Click modifier while the mouse is not moving to see if it is released during a straight line mode edit. This means that the shift key can be toggled in mid drag to create a straight line shape. | |
virtual void | DragFinished (DocCoord PointerPos, ClickModifiers ClickMods, Spread *, BOOL Success, BOOL bSolidDrag) |
Handles the drag finishing by rubbing out an EOR on the screen and adding the path to the tree and building all the undo that will be needed. | |
void | RenderDragBlobs (DocRect, Spread *, BOOL bSolidDrag) |
EORs the whole path onto the screen a segment at a time. It needs to do it a segment at a time as that is how it is drawn as the path is created. This has to redraw it identically or there will be bits of EORed stuff left all over the place. | |
virtual BOOL | IsBrushOp () |
Static Public Member Functions | |
static BOOL | Declare () |
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 | LoadCursors () |
Tries to Load all the cursors used by the Free Hand Operation. | |
void | RemoveCursors () |
Gets rid of all this operations cursors. It takes the cursor I was using off the top of the stack and deletes all the cursors I had allocated. | |
void | SetCursorOnMove (ClickModifiers ClickMods, Spread *pSpread, DocCoord *PointerPos) |
Decides which cursor to display depending on which modifiers are pressed and where the mouse is. PointerPos can be changed in this function. | |
virtual void | SetCursorAndStatus (CursorType CurType) |
Chanages the cursor to the type requested and sets the status bar message to the appropriate message for the mode we are in. | |
BOOL | PrepareTrackDataPath () |
Tries to initialise the path that we will store the track data in. It also sets up the pressure info stuff it there is pressure info coming in. If the path initialise ok, then it inserts the initial position (including its pressure) into the path. This function will only fail if there is no memory to init the path with. | |
void | RubOutPath (DocCoord Pos, Spread *pSpread) |
Tries to rub out sections of the path that have already been drawn. | |
void | AddPointsToPath (DocCoord Pos, Spread *pSpread) |
Adds a new point to the path of mouse moves. When the drag finishes the mouse moves will be smoothed. | |
BOOL | CheckMouseOverSelectedPath (DocCoord *Pos, Spread *pSpread, BOOL *IsNearEndpoint) |
Checks to see if the mouse is over the endpoint of any of the selected paths in the document and if it is, it makes a note of the path and which end it was attached to. | |
BOOL | AreSlotsInSameSubPath (INT32 Slot1, INT32 Slot2, Path *pPath) |
This function is used when editing lines with the freehand tool. If the drag was started in the middle of a path and the cursor is over that path again, we need to know if we can complete the edit. This is only possible if the start and end points are both on the same sub-path in the path. This function is used to determine if the 2 points are indeed in the same sub-path to allow the tool to display correct cursor etc. | |
BOOL | CompleteOperation () |
Does all the steps required to build a new path, smooth it, try to join it with others and finally insert it into the tree. | |
BOOL | CreateNewPath (NodePath **pNewPath) |
Builds a new Node Path ready to have a Curve fitted into it. If anything goes wrong (not enough memory, the path was not worth fitting etc) then this function fails. | |
BOOL | SmoothNewCurve (NodePath *pNewNodePath) |
Sets up the curve fitter and finally smooths the data in the Track data buffer into the new node path. | |
BOOL | InsertSmoothCurveWithUndo (NodePath *pNewNodePath) |
Starts the Selection operation (recording the selection state etc) and trys to join our new path with any others touching it, before inserting it into the tree. | |
virtual BOOL | TryToReplaceSection (NodePath *pNewNodePath) |
Replaces a section from the path that the drag was started and finished on with the newly drawn curve section. | |
BOOL | SplitAtPoint (const DocCoord &SplitPoint, INT32 *, INT32 *) |
Splits the path, building undo info, at the coord supplied. | |
BOOL | ReplaceMiddleOfPath (NodePath *pNewPath, INT32 FirstChangedIndex, INT32 NumElements) |
This will replace a section of the path with a new path, building undo as it goes. This function will also set up the Retro Curve fitting data so that it is able to retro fit the new section of the path. | |
virtual BOOL | EditBrushLists (NodePath *pNewPath, INT32 FirstChangedIndex, INT32 NumElements) |
When a path is edited that has a timestamping brush applied to it we those points are stored in a list that is generated when the path is drawn. If we subsequently want to edit that path we have to insert or remove points from that list. This function works out what points should be inserted or removed, and performs that action on the applied brush. | |
virtual BOOL | SimpleJoinBrush (NodePath *pNodePath, Path *pPath) |
Currently this only has to do work if we are editing a brush containing pressure data. In this case we must generate a new list of pressure info and insert it into the brush. | |
virtual BOOL | ReverseBrushPressure () |
The base class version does nothing, derived class should reverse its pressure cache. | |
virtual BOOL | RetroSmoothBrush (NodePath *pNodePath) |
As above, the base class version does nothing. | |
BOOL | TryToJoinNewPathWithOthers (NodePath *FreePath) |
Tries to Join the new path with any of the existing paths. | |
BOOL | SimpleJoin (NodePath *FreePath, NodePath *OldPath) |
Joins a Simple path with the new freehand path and builds all the undo that is needed in the process. | |
BOOL | ComplexJoin (NodePath *FreePath, NodePath *OldPath) |
Joins a Complex path with the new freehand path and builds all the undo that is needed in the process. | |
BOOL | ComplexToComplexJoin (NodePath *FreePath, NodePath *OldPath) |
Joins a Complex path with the new freehand path and builds all the undo that is needed in the process. The new freehand path joins two of the complex paths sub-paths together. | |
BOOL | VeryComplexToComplexJoin (NodePath *FreePath, NodePath *TopPath, NodePath *BotPath) |
Joins the new freehand path with two other paths (Which may or may not be complex) and builds all the undo info that is needed. | |
virtual BOOL | ApplyAttributes (NodePath *NewPath, Document *pDocument) |
Applies the current attributes to the Node passed in. It has to find the current document to do this and will ENSURE if it fails to find one. | |
BOOL | AddPressureAttribute (NodePath *NewPath) |
If pressure recording is enabled, this method builds attributes to apply to the path in order to attach the pressure as a variable-width stroking description. | |
NodePath * | MakeCopy (Node *pOriginalNode) |
Copies the node pOriginalNode and all its children an returns a pointer to them. It makes sure that the Node is a NodePath (Which it should be). | |
BOOL | InsertNewNode (NodePath *pNewNode, DocRect &Invalid, Node *pOldNode, Node *pOtherOld=NULL) |
Inserts a new path into the tree and hides the original node that it was Joined to. It will also invalidate the region of the new path that is different. | |
void | SetRetroPath (NodePath *pNodePath, INT32 Start, INT32 Len) |
Calls the freehand tool with details about the new path, so that future changes in the smoothness will re-build the new path. | |
void | AddStraightLine () |
Adds a straight line to the Path, that has been made by the Straight Line Mode. This means it has to set some flags in the path to stop the curve fitter from smoothing this straight line segment out. | |
void | RenderLine (RenderRegion *pRender, Path *pPath, INT32 CoordIndex, BOOL StartCoord=FALSE) |
Renders an EORed line between 2 coordinates in the path. May render pressure information feedback using the pressure stored with the path corrdinates. | |
void | RenderLine (DocRect *Rect, Spread *pSpread, Path *pPath, INT32 Index, BOOL StartCoord=FALSE) |
Renders an EORed line between 2 coordinates in the path. May render pressure information feedback using the pressure stored with the path corrdinates. | |
void | RenderEorStraightLine (DocRect *, Spread *pSpread, DocCoord *Start=NULL, DocCoord *End=NULL) |
Renders the EORed rubber band straight line that is used in Straight Line Mode. It simply draws a single Straight Line segment. | |
void | RenderEorStraightLine (RenderRegion *pRender, DocCoord *pStart, INT32 StartWidth, DocCoord *pEnd, INT32 EndWidth) |
Simply renders a straight-line segment to the given render region. | |
SimpleJoinType | GetSimpleJoinType (Path *pNewPath, Path *ExistingPath) |
This function works out how the new path joins onto the existing path. | |
INT32 | GetCurrentLineWidth (void) |
Determines the current line width (the width of any future lines the user will draw) by asking the attribute manager. | |
NodeGroup * | GetParentOfNodePath () |
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. | |
BOOL | InvalidateBrushRegion (NodePath *pNodePath) |
We may be editing a brushed path with the FHT so this function makes sure the correct region is invalidated. | |
Protected Attributes | |
Path * | TrackData |
DocCoord | StartPoint |
Spread * | StartSpread |
Spread * | PreviousSpread |
INT32 | Smoothness |
DocCoord | PreviousPoint |
INT32 | LineSegmentCount |
BOOL | CanLineJoin |
BOOL | IsStraightLineMode |
DocCoord | StraightLinePos |
BOOL | AddPressureToPath |
UINT32 | FreeHandPressure |
FreeHandJoinInfo * | pJoinInfo |
NodePath * | StartPath |
NodePath * | EndPath |
INT32 | CloseTo |
double | Mu |
BOOL | IsEndNearEndpoint |
Cursor * | pFreeHandCursor |
Cursor * | pJoinCursor |
Cursor * | pRubOutCursor |
Cursor * | pStraightCursor |
Cursor * | pModifyCursor |
Cursor * | MyCurrentCursor |
INT32 | CurrentCursorID |
NodePath * | m_pNewNodePath |
Private Member Functions | |
CC_DECLARE_DYNCREATE (OpFreeHand) |
Definition at line 167 of file opfree.h.
|
Constructor. This simply sets a few of the operation flags.
Definition at line 168 of file opfree.cpp. 00169 { 00170 // Set all our cursors to NULL to start with 00171 pFreeHandCursor = NULL; 00172 pJoinCursor = NULL; 00173 pStraightCursor = NULL; 00174 pRubOutCursor = NULL; 00175 pModifyCursor = NULL; 00176 00177 // Set other default values 00178 TrackData = NULL; 00179 StartSpread = NULL; 00180 PreviousSpread = NULL; 00181 Smoothness = 512; 00182 LineSegmentCount = 0; 00183 CanLineJoin = FALSE; 00184 IsStraightLineMode = FALSE; 00185 AddPressureToPath = FALSE; 00186 FreeHandPressure = 0; 00187 00188 // The paths that we are joined to, or NULL if we are joined to none 00189 pJoinInfo = NULL; 00190 StartPath = NULL; 00191 EndPath = NULL; 00192 CloseTo = 0; 00193 Mu = 0.0; 00194 IsEndNearEndpoint = FALSE; 00195 CurrentCursorID = 0; 00196 00197 m_pNewNodePath = NULL; 00198 00199 }
|
|
Adds a new point to the path of mouse moves. When the drag finishes the mouse moves will be smoothed.
Reimplemented in OpDrawBrush. Definition at line 1079 of file opfree.cpp. 01080 { 01081 // If this coord is the same as the last one, then do not bother adding to the track data 01082 if (PreviousPoint == PointerPos) 01083 return; 01084 01085 // Insert the move 01086 if (TrackData->InsertLineTo(PointerPos)) 01087 { 01088 // and add pressure info if needed 01089 if (AddPressureToPath) 01090 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure); 01091 } 01092 else 01093 { 01094 // Oh no, we ran out of mem in the middle of making a new path 01095 // Tidy up and report back to HQ 01096 EndDrag(); 01097 01098 // Tell the World that it all went horribly wrong 01099 InformError(); 01100 01101 // Remove it from the tree and delete it 01102 TrackData->ClearPath(); 01103 01104 // End this operation and return 01105 FailAndExecute(); 01106 End(); 01107 return; 01108 } 01109 01110 // Now we have to render a new bit of EORed data to the screen 01111 RenderLine(NULL, pSpread, TrackData, TrackData->GetNumCoords()-1); 01112 01113 // Make a note of the coord, inc the line count and mark joining to the start as active. 01114 PreviousPoint = PointerPos; 01115 LineSegmentCount++; 01116 CanLineJoin = TRUE; 01117 }
|
|
If pressure recording is enabled, this method builds attributes to apply to the path in order to attach the pressure as a variable-width stroking description.
Definition at line 1858 of file opfree.cpp. 01859 { 01860 if (IsBrushOp()) 01861 return TRUE; 01862 // Taken out by vector stroking code Neville 2/10/97 01863 #ifdef VECTOR_STROKING 01864 01865 ERROR3IF(GetWorkingDoc() == NULL, "No working doc"); 01866 ERROR3IF(pNewPath == NULL, "Illegal NULL param"); 01867 ERROR3IF(TrackData == NULL, "Trackdata is NULL"); 01868 01869 // If pressure recording is disabled, then we don't need to do anything 01870 if (TrackData == NULL || !AddPressureToPath) 01871 return(TRUE); 01872 01873 // --- Generate a smoothed pressure function from the recorded pressure samples 01874 // If this fails, then we still return TRUE, and the path just loses pressure information 01875 PressureSmoother Bob; 01876 ValueFunction *pValFunc = Bob.Smooth(TrackData, GetCurrentLineWidth()); 01877 if (pValFunc == NULL) 01878 return(TRUE); 01879 01880 // We only want to override the stroke type if it is a simple constant-width line 01881 // - if there is any new-style stroke type applied, we won't try to override it 01882 BOOL ApplyType = FALSE; 01883 01884 // BLOCK 01885 { 01886 Node *pNode = pNewPath->FindFirstChild(); 01887 if (pNode != NULL) 01888 pNode = pNode->FindNext(CC_RUNTIME_CLASS(AttrStrokeType)); 01889 01890 ApplyType = (pNode == NULL); // If there are no StrokeType attrs applied already, we must apply one 01891 if (!ApplyType) 01892 { 01893 // If there is another StrokeType, but it will not stroke using the variable width info, 01894 // (i.e. has a NULL PathProcessor attached to it) we will need to replace it. 01895 StrokeTypeAttrValue *pSAV = (StrokeTypeAttrValue *) ((AttrStrokeType *)pNode)->GetAttributeValue(); 01896 if (pSAV->GetPathProcessor() == NULL) 01897 ApplyType = TRUE; 01898 } 01899 } 01900 01901 // --- Create a simple variable-width path stroke attribute 01902 AttrStrokeType *pStrokeType = NULL; 01903 if (ApplyType) 01904 { 01905 pStrokeType = new AttrStrokeType; 01906 if (pStrokeType == NULL) 01907 return(TRUE); // Return TRUE - we'll only lose the pressure info 01908 01909 PathProcessorStroke *pProcessor = new PathProcessorStroke; 01910 if (pProcessor == NULL) 01911 { 01912 delete pStrokeType; 01913 return(TRUE); // Return TRUE - we'll only lose the pressure info 01914 } 01915 01916 // And attach the stroker to the attribute 01917 ((StrokeTypeAttrValue *)pStrokeType->GetAttributeValue())->SetPathProcessor(pProcessor); 01918 } 01919 01920 // --- Create a pressure table variable-width attribute 01921 AttrVariableWidth *pVarWidth = new AttrVariableWidth; 01922 if (pVarWidth != NULL) 01923 ((VariableWidthAttrValue *)pVarWidth->GetAttributeValue())->SetWidthFunction(pValFunc); 01924 01925 if (pVarWidth == NULL) 01926 { 01927 if (pStrokeType != NULL) 01928 delete pStrokeType; 01929 return(TRUE); // Return TRUE - we'll only lose the pressure info 01930 } 01931 01932 // --- Now apply the attributes to the path, removing any of a similar type which 01933 // are already applied to it. 01934 if (ApplyType) 01935 { 01936 DoRemoveAttrTypeFromSubtree(pNewPath, pStrokeType->GetRuntimeClass()); 01937 pStrokeType->AttachNode(pNewPath, FIRSTCHILD, FALSE, FALSE); 01938 } 01939 01940 // And apply the variable width attribute 01941 DoRemoveAttrTypeFromSubtree(pNewPath, pVarWidth->GetRuntimeClass()); 01942 pVarWidth->AttachNode(pNewPath, FIRSTCHILD, FALSE, FALSE); 01943 01944 #endif // VECTOR_STROKING 01945 01946 return(TRUE); 01947 }
|
|
Adds a straight line to the Path, that has been made by the Straight Line Mode. This means it has to set some flags in the path to stop the curve fitter from smoothing this straight line segment out.
Definition at line 1132 of file opfree.cpp. 01133 { 01134 PathFlags Flags; 01135 Flags.Spare1 = TRUE; 01136 01137 // If this coord is the same as the last one, then do not bother adding to the track data 01138 if (PreviousPoint == StraightLinePos) 01139 return; 01140 01141 // add the line segment into the path 01142 if (TrackData->InsertLineTo(StraightLinePos, &Flags)) 01143 { 01144 // and add pressure info if needed 01145 if (AddPressureToPath) 01146 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure); 01147 } 01148 else 01149 { 01150 // Oh no, we ran out of mem in the middle of making a new path 01151 // Tidy up and report back to HQ 01152 EndDrag(); 01153 01154 // Tell the World that it all went horribly wrong 01155 InformError(); 01156 01157 // Remove it from the tree and delete it 01158 TrackData->ClearPath(); 01159 01160 // End this operation and return 01161 FailAndExecute(); 01162 End(); 01163 return; 01164 } 01165 01166 // Count this bit of line 01167 LineSegmentCount++; 01168 CanLineJoin = TRUE; 01169 }
|
|
Applies the current attributes to the Node passed in. It has to find the current document to do this and will ENSURE if it fails to find one.
Reimplemented in OpDrawBrush. Definition at line 1812 of file opfree.cpp. 01813 { 01814 // Find the current document to get the current attributes from 01815 ENSURE(pDocument!=NULL, "Null Document while setting attributes for new NodePath"); 01816 if (pDocument!=NULL) 01817 { 01818 // Apply the current attributes to the path 01819 if (pDocument->GetAttributeMgr().ApplyCurrentAttribsToNode((NodeRenderableInk*)NewPath)) 01820 { 01821 // ok special case exception here, if we have a brush attribute then delete it 01822 Node* pNode = NewPath->FindFirstChild(CC_RUNTIME_CLASS(AttrBrushType)); 01823 if (pNode) 01824 { 01825 pNode->CascadeDelete(); 01826 delete pNode; 01827 } 01828 01829 return TRUE; 01830 } 01831 } 01832 01833 // We failed to apply the attributes, so fail 01834 return FALSE; 01835 }
|
|
This function is used when editing lines with the freehand tool. If the drag was started in the middle of a path and the cursor is over that path again, we need to know if we can complete the edit. This is only possible if the start and end points are both on the same sub-path in the path. This function is used to determine if the 2 points are indeed in the same sub-path to allow the tool to display correct cursor etc.
Definition at line 1304 of file opfree.cpp. 01305 { 01306 // saftey check 01307 ERROR2IF(pPath==NULL, FALSE, "NULL pointer passed to OpFreeHand::AreSlotsInSameSubPath"); 01308 01309 // We need to look at the verb array in the path. 01310 PathVerb* pVerbs = pPath->GetVerbArray(); 01311 INT32 NumSlots = pPath->GetNumCoords(); 01312 01313 // find the largest and smallest slot numbers 01314 INT32 First = Slot1<Slot2 ? Slot1 : Slot2; 01315 INT32 Last = Slot1<Slot2 ? Slot2 : Slot1; 01316 01317 // Make sure that the slot numbers make sense 01318 ERROR2IF(Last>NumSlots, FALSE, "Bad Slot numbers in OpFreeHand::AreSlotsInSameSubPath"); 01319 01320 // loop from the first to the last slot looking for MoveTos 01321 while (Last>First) 01322 { 01323 // See if the current last slot is a MoveTo 01324 if (pVerbs[Last]==PT_MOVETO) 01325 return FALSE; 01326 01327 // move the last point back 01328 Last--; 01329 } 01330 01331 // We did not find any MoveTos between the points 01332 return TRUE; 01333 }
|
|
|
|
Checks to see if the mouse is over the endpoint of any of the selected paths in the document and if it is, it makes a note of the path and which end it was attached to.
Definition at line 1191 of file opfree.cpp. 01192 { 01193 // Assume we do not find a path 01194 EndPath = NULL; 01195 01196 // Find out about the blob manager so we can find the size of a blob 01197 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 01198 if (pBlobMgr==NULL) 01199 return FALSE; 01200 01201 // Find out about the size of a blob 01202 DocRect BlobRect; 01203 pBlobMgr->GetBlobRect(*PointerPos, &BlobRect); 01204 01205 // Find the selected range of objects 01206 SelRange* Selected = GetApplication()->FindSelection(); 01207 Node* pNode = Selected->FindFirst(); 01208 01209 // see if the selection is on the same spread as the drag 01210 if (pNode!=NULL) 01211 { 01212 // Get the spread and return if it is different from the one with the cursor 01213 Spread* pNodeSpread = pNode->FindParentSpread(); 01214 if (pNodeSpread!=pSpread) 01215 return FALSE; 01216 } 01217 01218 // Walk through the selection 01219 while (pNode!=NULL) 01220 { 01221 if (pNode->IsNodePath()) 01222 { 01223 // Now we know it's a NodePath, get a pointer to the Path object within it, so 01224 // we can find any endpoints 01225 Path* ThisPath = &(((NodePath*)pNode)->InkPath); 01226 01227 // See if it touches any point in this path 01228 INT32 CloseSlot = 0; 01229 if (ThisPath->IsNearOpenEnd(BlobRect, &CloseSlot)) 01230 { 01231 // Yep, better work out where and set the path where is all happens 01232 ThisPath->SetPathPosition(CloseSlot); 01233 *PointerPos = ThisPath->GetCoord(); 01234 *IsNearEndpoint = TRUE; 01235 EndPath = (NodePath*)pNode; 01236 return TRUE; 01237 } 01238 01239 // See if it is near the middle of the path 01240 // This is only relavent if this node is the same as the one we started on 01241 // and we started in the middle of it 01242 if ((StartPath!=NULL) && (StartPath==pNode) && (pJoinInfo->IsNearEndPoint==FALSE)) 01243 { 01244 INT32 Range = BlobRect.Width() / 2; 01245 if (ThisPath->IsPointCloseTo(*PointerPos, Range*Range, &CloseTo, &Mu)) 01246 { 01247 // OK, we are near the path we started on 01248 // see if we are in the same sub-path as we started on 01249 if (AreSlotsInSameSubPath(CloseTo, pJoinInfo->CloseSlot, ThisPath)) 01250 { 01251 // Yep, better work out where and set the path where is all happens 01252 *IsNearEndpoint = FALSE; 01253 EndPath = (NodePath*)pNode; 01254 return TRUE; 01255 } 01256 } 01257 } 01258 } 01259 01260 // Now find the next selected node 01261 pNode = Selected->FindNext(pNode); 01262 } 01263 01264 // we will see if this point is anywhere near the start point 01265 if ((BlobRect.ContainsCoord(StartPoint)) && (StartPath==NULL)) 01266 { 01267 // Note the path that we are starting at and modify the coord 01268 // This will make the start and end points the same, causing the path to be closed 01269 *PointerPos = StartPoint; 01270 01271 // Wait till the cursor has moved out of the original snap range before we start joining 01272 if (CanLineJoin==TRUE) 01273 { 01274 *IsNearEndpoint = TRUE; 01275 return TRUE; 01276 } 01277 } 01278 01279 // Did not find a join 01280 return FALSE; 01281 }
|
|
Does all the steps required to build a new path, smooth it, try to join it with others and finally insert it into the tree.
Definition at line 783 of file opfree.cpp. 00784 { 00785 // Create a new path to be inserted into the tree 00786 NodePath* pNewNodePath = NULL; 00787 if (!CreateNewPath(&pNewNodePath)) 00788 return FALSE; 00789 00790 if (!SmoothNewCurve(pNewNodePath)) 00791 { 00792 // Get rid of the path we created and fail 00793 delete pNewNodePath; 00794 return FALSE; 00795 } 00796 00797 if (!InsertSmoothCurveWithUndo(pNewNodePath)) 00798 { 00799 // Get rid of the path we created, and fail 00800 pNewNodePath->CascadeDelete(); 00801 delete pNewNodePath; 00802 return FALSE; 00803 } 00804 00805 // Mark the selection as no longer valid (the Bounding Box will have changed) 00806 SelRange* Selection = GetApplication()->Selection; 00807 if (Selection) 00808 Selection->Update(); 00809 00810 00811 // All worked 00812 return TRUE; 00813 }
|
|
Joins a Complex path with the new freehand path and builds all the undo that is needed in the process.
Definition at line 1653 of file opfree.cpp. 01654 { 01655 // First we should make a note of the region that we will need redrawing 01656 DocRect InvalidRect = FreePath->GetBlobBoundingRect(); 01657 01658 // Need to know where in the joined path that the new section will be 01659 INT32 NumSlots = FreePath->InkPath.GetNumCoords(); 01660 INT32 StartSlot; 01661 01662 // Make a copy of the node we are joining with 01663 NodePath* JoinPath = MakeCopy(OldPath); 01664 if (JoinPath == NULL) 01665 return FALSE; 01666 01667 // before Joining them 01668 BOOL NewPathReversed = FALSE; 01669 if (!JoinPath->InkPath.ComplexJoin(&FreePath->InkPath, &StartSlot, &NewPathReversed)) 01670 return FALSE; 01671 01672 // Insert the new object 01673 if (!InsertNewNode(JoinPath, InvalidRect, OldPath)) 01674 return FALSE; 01675 01676 // Reverse the original mouse move data if the fitted path was reversed 01677 if (NewPathReversed) 01678 TrackData->Reverse(); 01679 01680 // Tell the freehand tool all about it 01681 SetRetroPath(JoinPath, StartSlot, NumSlots); 01682 01683 m_pNewNodePath = JoinPath; 01684 // It Worked! 01685 return TRUE; 01686 }
|
|
Joins a Complex path with the new freehand path and builds all the undo that is needed in the process. The new freehand path joins two of the complex paths sub-paths together.
Definition at line 1705 of file opfree.cpp. 01706 { 01707 // First we should make a note of the region that we will need redrawing 01708 DocRect InvalidRect = FreePath->GetBlobBoundingRect(); 01709 01710 // Need to know where in the joined path that the new section will be 01711 INT32 NumSlots = FreePath->InkPath.GetNumCoords(); 01712 INT32 StartSlot; 01713 01714 // Make a copy of the of the path we are Joining to 01715 NodePath* JoinPath = MakeCopy(OldPath); 01716 if (JoinPath==NULL) 01717 return FALSE; 01718 01719 // Join the new path with the one already there 01720 BOOL NewPathReversed = FALSE; 01721 if (!JoinPath->InkPath.ComplexToSameComplexJoin(&FreePath->InkPath, &StartSlot, &NewPathReversed)) 01722 return FALSE; 01723 01724 // Insert the new object 01725 if (!InsertNewNode(JoinPath, InvalidRect, OldPath)) 01726 return FALSE; 01727 01728 // Reverse the original mouse move data if the fitted path was reversed 01729 if (NewPathReversed) 01730 TrackData->Reverse(); 01731 01732 // Tell the freehand tool all about it 01733 SetRetroPath(JoinPath, StartSlot, NumSlots); 01734 01735 // It Worked! 01736 return TRUE; 01737 }
|
|
Builds a new Node Path ready to have a Curve fitted into it. If anything goes wrong (not enough memory, the path was not worth fitting etc) then this function fails.
Definition at line 831 of file opfree.cpp. 00832 { 00833 // Get a pointer to the path and set it to NULL 00834 NodePath*& pFreeHandPath = *pNewPath; 00835 pFreeHandPath = NULL; 00836 00837 // Only bother if they had actually drawn something 00838 if (LineSegmentCount==0) 00839 return FALSE; 00840 00841 // See if the path ever got away from the initial snap coord 00842 DocCoord* Coords = TrackData->GetCoordArray(); 00843 INT32 NumCoords = TrackData->GetNumCoords(); 00844 BOOL IsAllSame = TRUE; 00845 00846 // loop through all the coords comparing them with the first one 00847 for (INT32 i=0; (i<NumCoords) && (IsAllSame); i++) 00848 { 00849 // if this coord is different from the first one, then we are ok 00850 if (Coords[0] != Coords[i]) 00851 IsAllSame = FALSE; 00852 } 00853 00854 // If it did not (ie all the coordinates were the same, then chuck it away) 00855 if (IsAllSame) 00856 return FALSE; 00857 00858 // Init the path with the default memory block sizes 00859 pFreeHandPath = new NodePath; 00860 if (pFreeHandPath==NULL) 00861 return FALSE; 00862 00863 // Ok, we got a new NodePath, try and init the Path inside it 00864 if (!pFreeHandPath->SetUpPath(24, 12)) 00865 { 00866 // The path failed to init, so get rid of it and fail 00867 delete pFreeHandPath; 00868 pFreeHandPath = NULL; 00869 return FALSE; 00870 } 00871 00872 // Must have worked 00873 return TRUE; 00874 }
|
|
Adds the operation to the list of all known operations.
Reimplemented in OpDrawBrush. Definition at line 3278 of file opfree.cpp. 03279 { 03280 return (RegisterOpDescriptor( 03281 0, 03282 _R(IDS_FREE_HAND_TOOL), 03283 CC_RUNTIME_CLASS(OpFreeHand), 03284 OPTOKEN_FREEHAND, 03285 OpFreeHand::GetState, 03286 0, /* help ID */ 03287 _R(IDBBL_FREEHANDTOOLOP), 03288 0 /* bitmap ID */)); 03289 }
|
|
Starts up the drag operation by storing all start positions and setting up a Path to store the mouse movement in.
Definition at line 221 of file opfree.cpp. 00223 { 00224 TRACEUSER( "Diccon", _T("Do Drag Free, StartPos = %d, %d\n"), Anchor.x, Anchor.y); 00225 // WEBSTER - markn 25/4/97 00226 // No pen stuff required in Webster 00227 // Taken out by vector stroking code Neville 2/10/97 00228 #ifdef VECTOR_STROKING 00229 // Tell the pressure pen that we're starting a new stroke 00230 CCPen *pPen = GetApplication()->GetPressurePen(); 00231 if (pPen != NULL) 00232 pPen->StartStroke(); 00233 #endif // VECTOR_STROKING 00234 00235 // Snap the starting coord if we are not joining to something else 00236 if ((pFreeHandInfo==NULL) || (pFreeHandInfo->pJoinPath==NULL)) 00237 DocView::SnapCurrent(pSpread, &Anchor, FALSE, TRUE); 00238 00239 // Make a note of various starting conditions 00240 TrackData = ToolPath; 00241 Smoothness = Smooth; 00242 pJoinInfo = pFreeHandInfo; 00243 StartPath = pJoinInfo->pJoinPath; 00244 EndPath = NULL; 00245 00246 // Make a mental note of the start point 00247 StartPoint = Anchor; 00248 StartSpread = pSpread; 00249 PreviousSpread= pSpread; 00250 PreviousPoint = Anchor; 00251 LineSegmentCount = 0; 00252 IsStraightLineMode = FALSE; 00253 CanLineJoin = FALSE; 00254 00255 // Prepare the Track data path and add in the initial click point to the path 00256 if (!PrepareTrackDataPath()) 00257 { 00258 // We failed to get the memory to initialise the track data 00259 InformError(_R(IDS_OUT_OF_MEMORY), _R(IDS_OK)); 00260 FailAndExecute(); 00261 End(); 00262 return; 00263 } 00264 00265 // Create some cursors that I might need 00266 if (!LoadCursors()) 00267 { 00268 // The cursors did not load, so fail? 00269 FailAndExecute(); 00270 End(); 00271 return; 00272 } 00273 00274 // Push my new cursor onto the stack 00275 CurrentCursorID = CursorStack::GPush(pFreeHandCursor, TRUE); 00276 MyCurrentCursor = pFreeHandCursor; 00277 00278 // And tell the Dragging system that we need drags to happen 00279 StartDrag( DRAGTYPE_NOSCROLL ); 00280 }
|
|
Handles the drag finishing by rubbing out an EOR on the screen and adding the path to the tree and building all the undo that will be needed.
Reimplemented from Operation. Reimplemented in OpDrawBrush. Definition at line 647 of file opfree.cpp. 00649 { 00650 // Erase the whole EORed line 00651 DocRect ClipRect(0,0,0,0); 00652 RenderDragBlobs(ClipRect, StartSpread, bSolidDrag); 00653 00654 // Get rid of all the cursors 00655 RemoveCursors(); 00656 00657 // Put the hour glass up as we have to and end the drag 00658 BeginSlowJob(); 00659 EndDrag(); 00660 00661 // Add the new path to the tree if it was valid 00662 BOOL Worked = FALSE; 00663 if (Success) 00664 { 00665 // were we in the middle of drawing a straight line 00666 if (IsStraightLineMode) 00667 { 00668 // we were so add it in to the track data 00669 AddStraightLine(); 00670 PreviousPoint = StraightLinePos; 00671 IsStraightLineMode = FALSE; 00672 } 00673 00674 // try and smooth the path and insert it into the tree 00675 Worked = CompleteOperation(); 00676 00677 // DY 9/99 Check to see if we are editing a blend on a curve, if so we may wish to 00678 // change the number of steps in the blend (making use of the path distance). 00679 NodeGroup* pParent = GetParentOfNodePath(); 00680 if (pParent!= NULL) 00681 { 00682 if (pParent->IS_KIND_OF(NodeBlend)) 00683 { 00684 InsertChangeBlendStepsAction((NodeBlend*)pParent); 00685 00686 ObjChangeFlags cFlags(FALSE,TRUE); 00687 ObjChangeParam ObjChange(OBJCHANGE_FINISHED,cFlags,NULL,this); 00688 Worked = UpdateChangedNodes(&ObjChange); 00689 } 00690 00691 } 00692 } 00693 // WEBSTER - markn 25/4/97 00694 // No pen stuff required in Webster 00695 // Taken out by vector stroking code Neville 2/10/97 00696 #ifdef VECTOR_STROKING 00697 // Inform the pressure pen that we've finished the stroke 00698 CCPen *pPen = GetApplication()->GetPressurePen(); 00699 if (pPen != NULL) 00700 pPen->EndStroke(); 00701 #endif // VECTOR_STROKING 00702 00703 00704 00705 // If the operation failed, then tidy up 00706 if (Worked==FALSE) 00707 FailAndExecute(); 00708 else 00709 { 00710 // Update all the parents of the effected paths. 00711 ObjChangeFlags cFlags; 00712 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); 00713 ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this); 00714 UpdateChangedNodes(&ObjChange); 00715 } 00716 // End the operation properly 00717 End(); 00718 }
|
|
Find out if any of the key modifiers are being pressed when the mouse is not moving.
Reimplemented from Operation. Definition at line 735 of file opfree.cpp. 00736 { 00737 // Need something to see if there was a usful keypress 00738 // BOOL IsKeyPress = FALSE; 00739 00740 // and something to keep them in 00741 ClickModifiers ClickMods; 00742 ClickMods.Adjust = FALSE; 00743 ClickMods.Menu = FALSE; 00744 ClickMods.Constrain = FALSE; 00745 ClickMods.Alternative1 = FALSE; 00746 ClickMods.Alternative2 = FALSE; 00747 ClickMods.Pressure = 0; 00748 00749 // See if was one of the key we are interested in 00750 if (pKeyPress->IsConstrain() || pKeyPress->IsAdjust() || pKeyPress->IsAlternative() || pKeyPress->IsRelease()) 00751 { 00752 // Set up the click modifier 00753 ClickMods.Constrain = pKeyPress->IsConstrainPressed(); 00754 ClickMods.Adjust = pKeyPress->IsAdjustPressed(); 00755 ClickMods.Alternative1 = pKeyPress->IsAlternativePressed(); 00756 00757 // fake a mouse move message 00758 DragPointerMove(PreviousPoint, ClickMods, PreviousSpread, FALSE); 00759 00760 // Tell the keypress people that we used the keypress 00761 return TRUE; 00762 } 00763 00764 // Did not use the click 00765 return FALSE; 00766 }
|
|
This function checks the Adjust Click modifier while the mouse is not moving to see if it is released during a straight line mode edit. This means that the shift key can be toggled in mid drag to create a straight line shape.
Reimplemented from Operation. Reimplemented in OpDrawBrush. Definition at line 610 of file opfree.cpp. 00611 { 00612 // If we are in straight line mode, but the alt button has just come up, then 00613 // end the straight line we are drawing 00614 if (IsStraightLineMode && !ClickMods.Alternative1) 00615 { 00616 // Add the straight line into the path and set the flags as needed 00617 AddStraightLine(); 00618 PreviousPoint = StraightLinePos; 00619 00620 // No longer in Straight Line mode, so set the flag 00621 IsStraightLineMode = FALSE; 00622 } 00623 }
|
|
Handles the event of the mouse moving during a drag.
Reimplemented from Operation. Reimplemented in OpDrawBrush. Definition at line 514 of file opfree.cpp. 00516 { 00517 // Find out the view 00518 DocView* pView = DocView::GetSelected(); 00519 00520 // Lets whip out the current pressure value 00521 if (AddPressureToPath) 00522 FreeHandPressure = ClickMods.Pressure; 00523 00524 // If drag has moved onto a different spread, convert the coord to be relative to the 00525 // original spread. 00526 if (pSpread != StartSpread) 00527 PointerPos = MakeRelativeToSpread(StartSpread, pSpread, PointerPos); 00528 00529 // Change the Cursor to display the appropriate thing. 00530 SetCursorOnMove(ClickMods, StartSpread, &PointerPos); 00531 00532 // Are we in Straight Line Mode? We won't allow straight line mode when recording pressure 00533 if (ClickMods.Alternative1) 00534 { 00535 // Snap and Constrain if needed 00536 DocView::SnapCurrent(pSpread, &PointerPos); 00537 if (ClickMods.Constrain) 00538 DocView::ConstrainToAngle(PreviousPoint, &PointerPos); 00539 00540 // If we are in the Straight Line mode rub out the line 00541 if (IsStraightLineMode) 00542 RenderEorStraightLine(NULL, pSpread); 00543 else 00544 { 00545 // We are just entering straight line mode, so switch the dragging mode 00546 // so that the document auto scrolls at the edges of the screen 00547 if (pView!=NULL) 00548 pView->ChangeDragType(DRAGTYPE_AUTOSCROLL); 00549 } 00550 00551 // Update the mouse position and render the EORed straight line 00552 StraightLinePos = PointerPos; 00553 RenderEorStraightLine(NULL, pSpread); 00554 00555 // Finally note that we are in this mode 00556 IsStraightLineMode = TRUE; 00557 } 00558 else 00559 { 00560 // See if we were in Straight Line mode before 00561 if (IsStraightLineMode) 00562 { 00563 // We do not want to rub the straight line off, so do no drawing 00564 // Add the straight line into the path and set the flags as needed 00565 AddStraightLine(); 00566 PreviousPoint = StraightLinePos; 00567 00568 // We are just leaving straight line mode, so go back to not scrolling 00569 if (pView!=NULL) 00570 pView->ChangeDragType(DRAGTYPE_NOSCROLL); 00571 00572 // No longer in Straight Line mode, so set the flag 00573 IsStraightLineMode = FALSE; 00574 } 00575 else 00576 { 00577 // Either rub out sections of the path, or add new points to it 00578 if (ClickMods.Adjust) 00579 RubOutPath(PointerPos, StartSpread); 00580 else 00581 AddPointsToPath(PointerPos, StartSpread); 00582 } 00583 } 00584 00585 // Set the last spread to something appropriate 00586 PreviousSpread = pSpread; 00587 }
|
|
When a path is edited that has a timestamping brush applied to it we those points are stored in a list that is generated when the path is drawn. If we subsequently want to edit that path we have to insert or remove points from that list. This function works out what points should be inserted or removed, and performs that action on the applied brush.
Reimplemented in OpDrawBrush. Definition at line 2869 of file opfree.cpp. 02870 { 02871 // what we are going to do here is find out whether or not the path we are editing is brushed 02872 // and if so whether or not it uses pressure data. If so then we will generate a list of pressure 02873 // data and insert it. 02874 ERROR2IF(pNewPath == NULL, FALSE, "pNewPath is NULL in OpFreeHand::EditPressureList"); 02875 02876 /* First up, find the nearest applied brush attribute. If there isn't one or 02877 it has no pressure list then we don't have to bother with all this */ 02878 AttrBrushType* pAttrBrush = NULL; 02879 02880 pAttrBrush = EndPath->GetAppliedBrushAttribute(); 02881 if (pAttrBrush == NULL) 02882 return TRUE; 02883 02884 // if we are attempting to edit an existing brush that does not have an existing pressure 02885 // cache then leave now 02886 if (!pAttrBrush->ContainsPressureCache()) 02887 return TRUE; 02888 02889 // most of the action takes place in the attribute value so get that also 02890 BrushAttrValue* pVal = (BrushAttrValue*)pAttrBrush->GetAttributeValue(); 02891 if (pVal == NULL) 02892 return TRUE; 02893 02894 /* next, record the following distances: 02895 - original path length; 02896 - distance to first changed point; 02897 - distance to last changed point; 02898 */ 02899 02900 // double OriginalLength = EndPath->InkPath.GetPathLength(); 02901 MILLIPOINT DistToFirstPoint = -1; 02902 MILLIPOINT DistToLastPoint = -1; 02903 DocCoord* pCoords = EndPath->InkPath.GetCoordArray(); 02904 02905 DocCoord FirstChangedPoint; 02906 DocCoord LastChangedPoint; 02907 02908 if (pCoords == NULL) 02909 return FALSE; 02910 if (FirstChangedIndex + NumElements > EndPath->InkPath.GetNumCoords()) 02911 { 02912 ERROR3("Illegal number of coordinates"); 02913 return FALSE; 02914 } 02915 02916 // get the coordinates from the array 02917 FirstChangedPoint = pCoords[FirstChangedIndex]; 02918 LastChangedPoint = pCoords[FirstChangedIndex + NumElements]; 02919 02920 EndPath->InkPath.GetDistanceToPoint(FirstChangedPoint, &DistToFirstPoint); 02921 EndPath->InkPath.GetDistanceToPoint(LastChangedPoint, &DistToLastPoint); 02922 02923 // Now find the indices into the pressure list that correspond to those distances 02924 INT32 StartPressureIndex = pVal->GetPressureListIndexAtDistance(DistToFirstPoint); 02925 if (StartPressureIndex == -1) 02926 { 02927 ERROR3("StartPressureIndex is -1 in OpDrawBrush::EditPressureList"); 02928 return FALSE; 02929 } 02930 02931 INT32 EndPressureIndex = pVal->GetPressureListIndexAtDistance(DistToLastPoint); 02932 if (EndPressureIndex == -1 || EndPressureIndex <= StartPressureIndex) 02933 { 02934 ERROR3("EndPressureIndex is invalid in OpDrawBrush::EditPressureList"); 02935 return FALSE; 02936 } 02937 UINT32 NumObjects = EndPressureIndex - StartPressureIndex; 02938 02939 CDistanceSampler* pSampler = OpDrawBrush::GeneratePressureData(pAttrBrush, DistToFirstPoint, DistToLastPoint, 02940 (MILLIPOINT)pNewPath->InkPath.GetPathLength()); 02941 02942 if (pSampler == NULL) // did it fail, of so we must quit 02943 return FALSE; 02944 /* now get the pressure points list and ask the attribute to clear all the points 02945 between the edited distances*/ 02946 02947 // Invalidate it as it was 02948 pAttrBrush->ClearCachedRect(); 02949 DocRect Rect = pAttrBrush->GetAttrBoundingRect(EndPath); 02950 EndPath->ReleaseCached(); 02951 Spread* pSpread = Document::GetSelectedSpread(); 02952 if (!DoInvalidateRegion(pSpread, Rect)) 02953 return FALSE; 02954 // now make a removepoints action 02955 RemovePressurePointsAction* pAction; 02956 02957 if (RemovePressurePointsAction::Init(this, &UndoActions, pAttrBrush, (UINT32)StartPressureIndex, NumObjects, NULL, &pAction) == AC_FAIL) 02958 return FALSE; 02959 02960 // now insert our new points into the attribute 02961 AddPressurePointsAction* pAddAction; 02962 02963 // find out how many points we're inserting 02964 UINT32 NumAddPoints = pSampler->GetNumItems(); 02965 02966 if (AddPressurePointsAction::Init(this, &UndoActions, pAttrBrush, pSampler, (UINT32)StartPressureIndex, NumAddPoints, &pAddAction) == AC_FAIL) 02967 return FALSE; 02968 02969 // invalidate the whole thing3 02970 pAttrBrush->ClearCachedRect(); 02971 Rect = pAttrBrush->GetAttrBoundingRect(EndPath); 02972 EndPath->ReleaseCached(); 02973 if (!DoInvalidateRegion(pSpread, Rect)) 02974 return FALSE; 02975 return TRUE; 02976 02977 }
|
|
Determines the current line width (the width of any future lines the user will draw) by asking the attribute manager.
Definition at line 2302 of file opfree.cpp. 02303 { 02304 ERROR3IF(GetWorkingDoc() == NULL, "No working doc!"); 02305 AttrLineWidth *pWidthAttr = (AttrLineWidth *) GetWorkingDoc()->GetAttributeMgr(). 02306 GetCurrentAttribute(CC_RUNTIME_CLASS(NodeRenderableInk), CC_RUNTIME_CLASS(AttrLineWidth)); 02307 INT32 LineWidth = 1000; 02308 if (pWidthAttr != NULL) 02309 LineWidth = pWidthAttr->Value.LineWidth / 2; 02310 02311 return(LineWidth); 02312 }
|
|
To determine if the current selection is a blend on a curve.
Definition at line 3328 of file opfree.cpp. 03329 { 03330 NodeGroup* pParent = NULL; 03331 if (m_pNewNodePath == NULL) // if no blendpath node then there won't be a group parent 03332 return NULL; 03333 if (!m_pNewNodePath->IsANodeBlendPath()) 03334 return NULL; 03335 03336 pParent = (NodeGroup*)m_pNewNodePath->FindParent(); 03337 03338 ERROR2IF(!(pParent->IS_KIND_OF(NodeGroup)), NULL, "Node is not NodeGroup"); 03339 return pParent; 03340 03341 }
|
|
This function works out how the new path joins onto the existing path.
Definition at line 3183 of file opfree.cpp. 03184 { 03185 if (pNewPath == NULL || pExistingPath == NULL) 03186 return JOINTYPE_NONE; 03187 03188 // we must join to one of these paths 03189 if (StartPath == NULL && EndPath == NULL) 03190 return JOINTYPE_NONE; 03191 // get the new coordinate array 03192 DocCoord* pNewCoords = pNewPath->GetCoordArray(); 03193 if (pNewCoords == NULL) 03194 return JOINTYPE_NONE; 03195 03196 INT32 NumCoords = pNewPath->GetNumCoords(); 03197 // get the start and end coordinates of the new path 03198 DocCoord NewStart = pNewCoords[0]; 03199 DocCoord NewEnd = pNewCoords[NumCoords-1]; 03200 03201 SimpleJoinType ReturnVal = JOINTYPE_NONE; 03202 /* 03203 DocCoord* pOldCoords = pExistingPath->GetCoordArray(); 03204 if (pOldCoords != NULL) 03205 { 03206 INT32 NumOldCoords = pExistingPath->GetNumCoords(); 03207 DocCoord OldStart = pOldCoords[0]; 03208 DocCoord OldEnd = pOldCoords[NumOldCoords -1]; 03209 03210 // ok we don't have to be dead on here 03211 MILLIPOINT NewStartToOldStart = NewStart.Distance(OldStart); 03212 MILLIPOINT NewStartToOldEnd = NewStart.Distance(OldEnd); 03213 03214 // for some reason these must be reversed 03215 if (NewStartToOldStart < NewStartToOldEnd) 03216 ReturnVal = JOINTYPE_NEWSTART_TO_OLDSTART; 03217 else 03218 ReturnVal = JOINTYPE_NEWSTART_TO_OLDEND; 03219 } 03220 return Retural; 03221 */ 03222 if (StartPath != NULL) 03223 { 03224 DocCoord* pOldCoords = StartPath->InkPath.GetCoordArray(); 03225 if (pOldCoords != NULL) 03226 { 03227 INT32 NumOldCoords = StartPath->InkPath.GetNumCoords(); 03228 DocCoord OldStart = pOldCoords[0]; 03229 DocCoord OldEnd = pOldCoords[NumOldCoords -1]; 03230 03231 // ok we don't have to be dead on here 03232 MILLIPOINT NewStartToOldStart = (MILLIPOINT)NewStart.Distance(OldStart); 03233 MILLIPOINT NewStartToOldEnd = (MILLIPOINT)NewStart.Distance(OldEnd); 03234 03235 03236 if (NewStartToOldStart < NewStartToOldEnd) 03237 ReturnVal = JOINTYPE_NEWSTART_TO_OLDSTART; 03238 else 03239 ReturnVal = JOINTYPE_NEWSTART_TO_OLDEND; 03240 } 03241 } 03242 03243 // if endpath is not null then we are joining the end of the new path to one of the 03244 // ends of the old path 03245 if (EndPath != NULL) 03246 { 03247 DocCoord* pOldCoords = EndPath->InkPath.GetCoordArray(); 03248 if (pOldCoords != NULL) 03249 { 03250 INT32 NumOldCoords = EndPath->InkPath.GetNumCoords(); 03251 DocCoord OldStart = pOldCoords[0]; 03252 DocCoord OldEnd = pOldCoords[NumOldCoords-1]; 03253 03254 // ok we don't have to be dead on here 03255 const MILLIPOINT NewEndToOldStart = (MILLIPOINT)NewEnd.Distance(OldStart); 03256 const MILLIPOINT NewEndToOldEnd = (MILLIPOINT)NewEnd.Distance(OldEnd); 03257 03258 if (NewEndToOldStart < NewEndToOldEnd) 03259 ReturnVal = JOINTYPE_NEWEND_TO_OLDSTART; 03260 else 03261 ReturnVal = JOINTYPE_NEWEND_TO_OLDEND; 03262 } 03263 } 03264 03265 return ReturnVal; 03266 }
|
|
Find out the state of the operation at the specific time.
Reimplemented in OpDrawBrush. Definition at line 3306 of file opfree.cpp. 03307 { 03308 OpState Blobby; 03309 03310 return Blobby; 03311 }
|
|
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.
Definition at line 3362 of file opfree.cpp. 03363 { 03364 03365 ERROR2IF(pNodeBlend==NULL, FALSE, "NodeBlend pointer is NULL"); 03366 // do we wish to keep the distance between steps constant? If so then determine 03367 // how many steps we need with the new length and make an action. 03368 if (pNodeBlend->GetEditState() == EDIT_DISTANCE) 03369 { 03370 UINT32 NewNumSteps = 0; 03371 UINT32 OldNumSteps = pNodeBlend->GetNumBlendSteps(); 03372 double DistanceEntered = pNodeBlend->GetDistanceEntered(); 03373 NodeBlendPath* pNodeBlendPath = pNodeBlend->GetNodeBlendPath(0); 03374 double NewPathLength = pNodeBlendPath->GetPathLength(); 03375 03376 NewNumSteps = (UINT32)(NewPathLength/DistanceEntered); 03377 03378 03379 BOOL ok = TRUE; 03380 03381 if (OldNumSteps != NewNumSteps) 03382 { 03383 ChangeBlendStepsAction* pAction; 03384 ok = (InvalidateBoundsAction::Init(this,&UndoActions,pNodeBlend,TRUE) != AC_FAIL); 03385 if (ok) ok = ChangeBlendStepsAction::Init(this,&UndoActions,pNodeBlend,OldNumSteps,DistanceEntered, &pAction) != AC_FAIL; 03386 if (ok) ok = DoInvalidateNodeRegion(pNodeBlend,TRUE,FALSE); 03387 if (ok) ok = (InvalidateBoundsAction::Init(this,&UndoActions,pNodeBlend,TRUE) != AC_FAIL); 03388 pNodeBlend->SetNumBlendSteps(NewNumSteps); 03389 03390 // added 9/9/99 now we are shifting the last object along the curve to ensure precise 03391 // step distances. To do this we must set the proportion of the curve used in the 03392 // NodeBlender objects. 03393 if (ok) 03394 { 03395 double PathDistanceUsed = NewNumSteps * DistanceEntered; 03396 double PathProportion = PathDistanceUsed / NewPathLength; 03397 // double PathDistanceUnused = NewPathLength - PathDistanceUsed; 03398 03399 if (PathProportion != 1.0) 03400 { 03401 //ChangeBlenderAction* pBlenderAction; 03402 ChangeBlenderOpParam BlenderParam; 03403 BlenderParam.m_ChangeType = CHANGEBLENDER_PATHEND; 03404 03405 03406 NodeBlender* pNodeBlender = pNodeBlend->FindFirstBlender(); 03407 INT32 NumBlenders = pNodeBlend->GetNumBlenders(); 03408 03409 while (pNodeBlender != NULL) 03410 { 03411 NumBlenders--; 03412 if (NumBlenders ==0) 03413 { 03414 BlenderParam.m_NewPathEnd = PathProportion; 03415 ok = ChangeBlenderAction::Init(this, &UndoActions, pNodeBlender, BlenderParam); 03416 if (ok) 03417 { 03418 DocCoord NewPoint; 03419 double ExtraParam = 0.0; //passed to the function but not used afterwards 03420 ok = pNodeBlender->GetPointOnNodeBlendPath(1.0,&NewPoint,&ExtraParam); 03421 03422 if (ok) 03423 { 03424 NodeRenderableInk* pEnd = pNodeBlender->GetNodeEnd(); 03425 NodeBlend* pNodeBlend = pNodeBlender->GetNodeBlend(); 03426 03427 ok = ((pEnd != NULL) && (pNodeBlend != NULL)); 03428 03429 if (ok) 03430 ok = pNodeBlend->TransformNodeToPoint(pEnd,&NewPoint,this,ExtraParam); 03431 } 03432 } 03433 } 03434 pNodeBlender = pNodeBlend->FindNextBlender(pNodeBlender); 03435 } 03436 } // end if (pathproportion.. 03437 } // end if(ok) 03438 03439 } 03440 } 03441 03442 return TRUE; 03443 }
|
|
Inserts a new path into the tree and hides the original node that it was Joined to. It will also invalidate the region of the new path that is different.
Definition at line 1999 of file opfree.cpp. 02000 { 02001 // Insert the new object 02002 if (!DoInsertNewNode(pNewNode, pOldNode, NEXT, FALSE)) 02003 return FALSE; 02004 02005 // Invalidate the appropriate region. 02006 // if the filled state of the path has changed, then we need to invalidate the whole thing 02007 ENSURE(pOldNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)), "Joining to something that was not a path"); 02008 02009 // if (pNewNode->InkPath.IsFilled == ((NodePath*)pOldNode)->InkPath.IsFilled) 02010 // { 02011 // Invalidate only the new bit 02012 // Spread* pSpread = pOldNode->FindParentSpread(); 02013 // if (!DoInvalidateRegion(pSpread, Invalid)) 02014 // return FALSE; 02015 // } 02016 // else 02017 02018 // invalidate the whole thing 02019 if (!DoInvalidateNodeRegion(pNewNode, TRUE)) 02020 return FALSE; 02021 02022 // Hide the original 02023 if (!DoHideNode(pOldNode, TRUE)) 02024 return FALSE; 02025 02026 // and hide the other original node if it existed 02027 if (pOtherOld != NULL) 02028 if (!DoHideNode(pOtherOld, TRUE)) 02029 return FALSE; 02030 02031 // Make sure that the Selection Cache is refreshed 02032 SelRange* Selection = GetApplication()->Selection; 02033 if (Selection) 02034 Selection->Update(); 02035 02036 // It worked 02037 return TRUE; 02038 }
|
|
Starts the Selection operation (recording the selection state etc) and trys to join our new path with any others touching it, before inserting it into the tree.
Definition at line 954 of file opfree.cpp. 00955 { 00956 // Start the selection operation. 00957 // We don't want to save the end selection status because it will be 00958 // restored automatically when the operation is redone 00959 if (!DoStartSelOp(FALSE)) 00960 return FALSE; 00961 00962 // Now we have to go round testing if we are joined to any other paths 00963 // and building the appropriate undo info 00964 if ((StartPath!=NULL) && (StartPath==EndPath) && 00965 (pJoinInfo->IsNearEndPoint==FALSE) && (IsEndNearEndpoint==FALSE)) 00966 { 00967 // This is a case for replacing a section of an existing path 00968 // with the new smoothed path 00969 if (!TryToReplaceSection(pNewNodePath)) 00970 return FALSE; 00971 } 00972 else 00973 { 00974 // If the new curve did not start and end on the same path we made need to make a few adjustments 00975 if (pJoinInfo->IsNearEndPoint==FALSE) 00976 StartPath = NULL; 00977 00978 // this is a case for inserting the path in the normal way 00979 // Joining it to other paths that it touches etc 00980 if (!TryToJoinNewPathWithOthers(pNewNodePath)) 00981 return FALSE; 00982 } 00983 00984 // Clear the Node path that we made, as it will have been copied into the tree by now 00985 pNewNodePath->CascadeDelete(); 00986 delete pNewNodePath; 00987 00988 // It all worked ok 00989 return TRUE; 00990 }
|
|
We may be editing a brushed path with the FHT so this function makes sure the correct region is invalidated.
Definition at line 3463 of file opfree.cpp. 03464 { 03465 ERROR2IF(pNodePath == NULL, FALSE, "Nodepath is NULL in OpFreeHand::InvalidateBrushRegion"); 03466 03467 AttrBrushType* pAttrBrush; 03468 NodeAttribute* pAttr = NULL; 03469 BrushHandle Handle = BrushHandle_NoBrush; 03470 pNodePath->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), &pAttr); 03471 if (pAttr != NULL) 03472 { 03473 pAttrBrush = (AttrBrushType*)pAttr; 03474 Handle = pAttrBrush->GetBrushHandle(); 03475 } 03476 if (Handle == BrushHandle_NoBrush) 03477 return TRUE; 03478 03479 pAttrBrush->ClearCachedRect(); 03480 pAttrBrush->FlushCache(); 03481 DocRect BRect = pNodePath->GetBoundingRect(); //pAttrBrush->GetAttrBoundingRect(pNodePath); 03482 pNodePath->ReleaseCached(); 03483 pAttrBrush->ClearCachedRect(); 03484 Spread* pSpread = Document::GetSelectedSpread(); 03485 if (pSpread != NULL) 03486 return DoInvalidateRegion(pSpread, BRect); 03487 else 03488 return FALSE; 03489 }
|
|
Reimplemented in OpDrawBrush. Definition at line 200 of file opfree.h. 00200 { return FALSE;}
|
|
Tries to Load all the cursors used by the Free Hand Operation.
Definition at line 352 of file opfree.cpp. 00353 { 00354 // Try to load all the cursors 00355 if (FreeHandTool::FreehandPtrCrosshair) 00356 { 00357 pFreeHandCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDTOOLCURSOR_X)); 00358 pJoinCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDJOINCURSOR_X)); 00359 pRubOutCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDRUBOUTCUR_X)); 00360 pStraightCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDLINECURSOR_X)); 00361 pModifyCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDMODIFY_X)); 00362 } 00363 else 00364 { 00365 pFreeHandCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDTOOLCURSOR)); 00366 pJoinCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDJOINCURSOR)); 00367 pRubOutCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDRUBOUTCUR)); 00368 pStraightCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDLINECURSOR)); 00369 pModifyCursor = new Cursor(TOOLID_FREEHAND, _R(IDC_FREEHANDMODIFY)); 00370 } 00371 00372 // See if any of them failed 00373 if ((pRubOutCursor==NULL) || (!pRubOutCursor->IsValid()) || 00374 (pJoinCursor==NULL) || (!pJoinCursor->IsValid()) || 00375 (pFreeHandCursor==NULL) || (!pFreeHandCursor->IsValid()) || 00376 (pStraightCursor==NULL) || (!pStraightCursor->IsValid()) || 00377 (pModifyCursor==NULL) || (!pModifyCursor->IsValid())) 00378 { 00379 // They did, so Tidy up and exit 00380 delete pFreeHandCursor; 00381 delete pJoinCursor; 00382 delete pStraightCursor; 00383 delete pRubOutCursor; 00384 delete pModifyCursor; 00385 00386 // Set them all to NULL 00387 pFreeHandCursor = NULL; 00388 pJoinCursor = NULL; 00389 pStraightCursor = NULL; 00390 pRubOutCursor = NULL; 00391 pModifyCursor = NULL; 00392 00393 // fail 00394 return FALSE; 00395 } 00396 00397 // It worked 00398 return TRUE; 00399 }
|
|
Copies the node pOriginalNode and all its children an returns a pointer to them. It makes sure that the Node is a NodePath (Which it should be).
Definition at line 1964 of file opfree.cpp. 01965 { 01966 // Make a copy of the node we are joining with 01967 Node* pNode; 01968 if (!pOriginalNode->NodeCopy(&pNode)) 01969 return NULL; 01970 01971 // Check that the new node is OK 01972 ENSURE(pNode!=NULL, "Copied node seems to be NULL in TryToJoinNewPathWithOthers()"); 01973 ENSURE(pNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)), "Copied node was not a Path"); 01974 01975 // return it 01976 return (NodePath*) pNode; 01977 }
|
|
Tries to initialise the path that we will store the track data in. It also sets up the pressure info stuff it there is pressure info coming in. If the path initialise ok, then it inserts the initial position (including its pressure) into the path. This function will only fail if there is no memory to init the path with.
Definition at line 299 of file opfree.cpp. 00300 { 00301 TrackData->ClearPath(); 00302 TrackData->FindStartOfPath(); 00303 00304 // Check to see if we want to store pressure, and if so initialise the path. 00305 AddPressureToPath = FALSE; 00306 00307 // WEBSTER - markn 25/4/97 00308 // No pen stuff required in Webster 00309 // Taken out by vector stroking code Neville 2/10/97 00310 #ifdef VECTOR_STROKING 00311 00312 CCPen *pPen = GetApplication()->GetPressurePen(); 00313 if (IsBrushOp() && pPen != NULL && pPen->GetPressureMode() != PressureMode_None) 00314 { 00315 // Yep, we want the pressure info 00316 AddPressureToPath = TRUE; 00317 00318 // Lets gets the pressure for the first point in the path. 00319 FreeHandPressure = pPen->GetPenPressure(); 00320 00321 // try and initialise the extra info in the path and fail if not 00322 if (!TrackData->InitExtraInfo(CI_PRESSURE)) 00323 return FALSE; 00324 } 00325 00326 #endif // VECTOR_STROKING 00327 00328 // insert the initial coord into the path and fail if it fails 00329 if (!TrackData->InsertMoveTo(StartPoint)) 00330 return FALSE; 00331 00332 // and add pressure info if needed 00333 if (AddPressureToPath) 00334 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure); 00335 00336 // and tell someone that we did it 00337 return TRUE; 00338 }
|
|
Gets rid of all this operations cursors. It takes the cursor I was using off the top of the stack and deletes all the cursors I had allocated.
Definition at line 414 of file opfree.cpp. 00415 { 00416 // Get rid out my cursor from the top of the cursor stack 00417 CursorStack::GPop(CurrentCursorID); 00418 MyCurrentCursor = NULL; 00419 CurrentCursorID = 0; 00420 00421 // destroy all the cursors that I had allocated 00422 delete pFreeHandCursor; 00423 delete pJoinCursor; 00424 delete pRubOutCursor; 00425 delete pStraightCursor; 00426 delete pModifyCursor; 00427 00428 // and make sure that they all point to something sensible 00429 pFreeHandCursor = NULL; 00430 pJoinCursor = NULL; 00431 pStraightCursor = NULL; 00432 pRubOutCursor = NULL; 00433 pModifyCursor = NULL; 00434 }
|
|
EORs the whole path onto the screen a segment at a time. It needs to do it a segment at a time as that is how it is drawn as the path is created. This has to redraw it identically or there will be bits of EORed stuff left all over the place.
Reimplemented from Operation. Reimplemented in OpDrawBrush. Definition at line 2332 of file opfree.cpp. 02333 { 02334 // Work out which bits we need to draw 02335 DocRect* pRect; 02336 if (Rect.IsEmpty()) 02337 pRect = NULL; 02338 else 02339 pRect = &Rect; 02340 02341 // Get information on the path we've got to render 02342 INT32 NumCoords = TrackData->GetNumCoords(); 02343 // DocCoord* Coords = TrackData->GetCoordArray(); 02344 02345 // Find out the current line width 02346 // INT32 LineWidth = GetCurrentLineWidth(); 02347 02348 // Render into all the available rectangles 02349 RenderRegion* pRegion = DocView::RenderOnTop(pRect, pSpread, UnclippedEOR ); 02350 while ( pRegion ) 02351 { 02352 // Rather than just calling DrawPath, we render each line ourselves - this allows the variable 02353 // width indicator lines to be rendered as well, and ensures all the EORing remains consistent. 02354 for (INT32 n = 1; n < NumCoords; n++) 02355 RenderLine(pRegion, TrackData, n); 02356 02357 // get the next region to draw in 02358 pRegion = DocView::GetNextOnTop(pRect); 02359 } 02360 02361 if (IsStraightLineMode) 02362 RenderEorStraightLine(pRect, pSpread); 02363 }
|
|
Simply renders a straight-line segment to the given render region. However, it may also elect to show width information by rendering parallel straight line segments on either side of the line Definition at line 2212 of file opfree.cpp. 02215 { 02216 ERROR3IF(pRender == NULL || pStart == NULL || pEnd == NULL, "illegal NUL params"); 02217 02218 // Always draw the blue centreline 02219 pRender->SetLineColour(COLOUR_XORNEW); 02220 pRender->DrawLine(*pStart, *pEnd); 02221 02222 // Taken out by vector stroking code Neville 2/10/97 02223 #ifdef VECTOR_STROKING 02224 02225 // If we're showing pressure info, and the points are not coincident, and 02226 // the average line width is large enough to avoid hideous EOR mess, render parallel width lines 02227 if (AddPressureToPath && *pStart != *pEnd && (StartWidth + EndWidth) > pRender->GetPixelWidth() * 8) 02228 { 02229 pRender->SetLineColour(COLOUR_MIDGREY); 02230 02231 // Get the normal to the centreline and normalise it to unit length 02232 NormCoord Normal( pStart->y - pEnd->y, -(pStart->x - pEnd->x)); 02233 Normal.Normalise(); 02234 02235 // Now plot the two parallel edges 02236 DocCoord P1(pStart->x + (INT32)(Normal.x * StartWidth), pStart->y + (INT32)(Normal.y * StartWidth)); 02237 DocCoord P2(pEnd->x + (INT32)(Normal.x * EndWidth), pEnd->y + (INT32)(Normal.y * EndWidth)); 02238 pRender->DrawLine(P1, P2); 02239 02240 DocCoord P3(pStart->x - (INT32)(Normal.x * StartWidth), pStart->y - (INT32)(Normal.y * StartWidth)); 02241 DocCoord P4(pEnd->x - (INT32)(Normal.x * EndWidth), pEnd->y - (INT32)(Normal.y * EndWidth)); 02242 pRender->DrawLine(P3, P4); 02243 } 02244 02245 #endif // VECTOR_STROKING 02246 }
|
|
Renders the EORed rubber band straight line that is used in Straight Line Mode. It simply draws a single Straight Line segment.
Definition at line 2266 of file opfree.cpp. 02267 { 02268 if (pStart == NULL) 02269 pStart = &PreviousPoint; 02270 if (pEnd == NULL) 02271 pEnd = &StraightLinePos; 02272 02273 INT32 LineWidth = GetCurrentLineWidth(); 02274 02275 RenderRegion* pRegion = DocView::RenderOnTop(Rect, pSpread, UnclippedEOR ); 02276 while ( pRegion ) 02277 { 02278 RenderEorStraightLine(pRegion, pStart, LineWidth, pEnd, LineWidth); 02279 02280 // get the next region to draw in 02281 pRegion = DocView::GetNextOnTop(Rect); 02282 } 02283 }
|
|
Renders an EORed line between 2 coordinates in the path. May render pressure information feedback using the pressure stored with the path corrdinates.
Definition at line 2177 of file opfree.cpp. 02178 { 02179 RenderRegion* pRegion = DocView::RenderOnTop(Rect, pSpread, UnclippedEOR ); 02180 while ( pRegion ) 02181 { 02182 RenderLine(pRegion, pPath, Index, StartIndex); 02183 02184 // get the next region to draw in 02185 pRegion = DocView::GetNextOnTop(Rect); 02186 } 02187 }
|
|
Renders an EORed line between 2 coordinates in the path. May render pressure information feedback using the pressure stored with the path corrdinates.
Definition at line 2092 of file opfree.cpp. 02093 { 02094 ERROR3IF(pRender == NULL || pPath == NULL, "illegal NUL params"); 02095 ERROR3IF(Index < 1 || Index >= pPath->GetNumCoords(), "Out of range coordinate"); 02096 02097 INT32 EndIndex = Index; 02098 if (!StartIndex) 02099 { 02100 EndIndex = Index; 02101 02102 } 02103 else 02104 EndIndex = pPath->GetNumCoords() - 1; 02105 02106 Index--; 02107 DocCoord *Coord = pPath->GetCoordArray(); 02108 02109 // Always draw the blue centreline 02110 pRender->SetLineColour(COLOUR_XORNEW); 02111 pRender->DrawLine(Coord[Index], Coord[EndIndex]); 02112 02113 // Taken out by vector stroking code Neville 2/10/97 02114 #ifdef VECTOR_STROKING 02115 02116 // If we're showing pressure info, and the points are not coincident, and the average 02117 // line width is large enough to avoid hideous EOR mess, render parallel width lines 02118 if (!AddPressureToPath) 02119 return; 02120 02121 PathWidth *Width = pPath->GetWidthArray(); 02122 if (Width == NULL) 02123 return; 02124 02125 const INT32 CurrentLineWidth = GetCurrentLineWidth(); 02126 const double WidthMul = (double)CurrentLineWidth / (double)EXTRAVALUEMAX; 02127 INT32 StartWidth = (INT32) ((double)Width[Index-1] * WidthMul); 02128 INT32 EndWidth = (INT32) ((double)Width[Index] * WidthMul); 02129 02130 if (StartWidth > CurrentLineWidth) // Damage control in case of rampant pens giving 02131 StartWidth = CurrentLineWidth; // out of range values. You may laugh, but that's 02132 if (EndWidth > CurrentLineWidth) // exactly what the pen code was doing until I 02133 EndWidth = CurrentLineWidth; // just fixed it. This just stops wild rampancy 02134 02135 if (Coord[Index-1] != Coord[Index] && (StartWidth + EndWidth) > pRender->GetPixelWidth() * 8) 02136 { 02137 pRender->SetLineColour(COLOUR_MIDGREY); 02138 02139 // Get the normal to the centreline and normalise it to unit length 02140 NormCoord Normal( Coord[Index-1].y - Coord[Index].y, -(Coord[Index-1].x - Coord[Index].x)); 02141 Normal.Normalise(); 02142 02143 // Now plot the two parallel edges 02144 DocCoord P1(Coord[Index-1].x + (INT32)(Normal.x * StartWidth), Coord[Index-1].y + (INT32)(Normal.y * StartWidth)); 02145 DocCoord P2(Coord[Index].x + (INT32)(Normal.x * EndWidth), Coord[Index].y + (INT32)(Normal.y * EndWidth)); 02146 pRender->DrawLine(P1, P2); 02147 02148 DocCoord P3(Coord[Index-1].x - (INT32)(Normal.x * StartWidth), Coord[Index-1].y - (INT32)(Normal.y * StartWidth)); 02149 DocCoord P4(Coord[Index].x - (INT32)(Normal.x * EndWidth), Coord[Index].y - (INT32)(Normal.y * EndWidth)); 02150 pRender->DrawLine(P3, P4); 02151 } 02152 #endif // VECTOR_STROKING 02153 }
|
|
This will replace a section of the path with a new path, building undo as it goes. This function will also set up the Retro Curve fitting data so that it is able to retro fit the new section of the path.
Definition at line 2741 of file opfree.cpp. 02742 { 02743 // if we are a brush then do our special smoothing 02744 //etroSmoothBrush(pNewPath); 02745 02746 // if we are editing a brush with timestamp or pressure lists 02747 EditBrushLists(pNewPath, FirstChangedIndex, NumElements); 02748 02749 // If there is something to remove from this path, the do it 02750 if (NumElements>0) 02751 { 02752 // Make ourselves an insert action as we are about to delete the 02753 // old bits of the path we no longer want 02754 ActionCode Act; 02755 InsertPathElementAction* ModAction; 02756 Act = InsertPathElementAction::Init(this, &UndoActions, NumElements, FirstChangedIndex, 02757 (Action**)(&ModAction)); 02758 02759 // Did we init the action ok 02760 if (Act == AC_FAIL) 02761 return FALSE; 02762 02763 // If the action will let us, record the details of what we want to delete 02764 if (Act!=AC_NORECORD) 02765 { 02766 // We need to store info about all the elements we are going to delete 02767 PathVerb* ChangedVerbs; 02768 DocCoord* ChangedCoords; 02769 PathFlags* ChangedFlags; 02770 02771 // Get some memory to put them in 02772 ALLOC_WITH_FAIL(ChangedVerbs, (PathVerb*)CCMalloc(NumElements*sizeof(PathVerb)), this); 02773 ALLOC_WITH_FAIL(ChangedCoords, (DocCoord*)CCMalloc(NumElements*sizeof(DocCoord)), this); 02774 ALLOC_WITH_FAIL(ChangedFlags, (PathFlags*)CCMalloc(NumElements*sizeof(PathFlags)), this); 02775 02776 // Make sure that we got the memory 02777 if (!ChangedVerbs || !ChangedCoords || !ChangedFlags) 02778 { 02779 if (ChangedVerbs) CCFree(ChangedVerbs); 02780 if (ChangedCoords) CCFree(ChangedCoords); 02781 if (ChangedFlags) CCFree(ChangedFlags); 02782 return FALSE; 02783 } 02784 02785 // Get pointers to all the arrays of the path 02786 PathVerb* Verbs = EndPath->InkPath.GetVerbArray(); 02787 DocCoord* Coords = EndPath->InkPath.GetCoordArray(); 02788 PathFlags* Flags = EndPath->InkPath.GetFlagArray(); 02789 02790 // Now copy the data from the path into the arrays 02791 for (INT32 i=0; i<NumElements; i++) 02792 { 02793 ChangedVerbs[i] = Verbs[FirstChangedIndex+i]; 02794 ChangedCoords[i] = Coords[FirstChangedIndex+i]; 02795 ChangedFlags[i] = Flags[FirstChangedIndex+i]; 02796 } 02797 02798 // And ask the action to make a note of them 02799 ModAction->RecordPath(ChangedVerbs, ChangedFlags, ChangedCoords, EndPath); 02800 } 02801 02802 // Delete the elements from the path that we no longer want 02803 EndPath->InkPath.DeleteSection(FirstChangedIndex, NumElements); 02804 } 02805 02806 02807 // Next we have to add the new points, so build undo to remove them 02808 Action* UnAction; 02809 INT32 NumCoords = pNewPath->InkPath.GetNumCoords() - 1; 02810 ActionCode Act = RemovePathElementAction::Init(this, &UndoActions, NumCoords, 02811 FirstChangedIndex, (Action**)(&UnAction)); 02812 02813 // if we failed to init the action, then fail this operation 02814 if (Act==AC_FAIL) 02815 return FALSE; 02816 02817 // record details about the path in the action before we start inserting stuff 02818 ((RemovePathElementAction*)UnAction)->RecordPath(EndPath); 02819 02820 // Insert stuff here 02821 EndPath->InkPath.InsertSection(FirstChangedIndex, NumCoords); 02822 02823 // Get pointers to all the arrays of the original path 02824 PathVerb* Verbs = EndPath->InkPath.GetVerbArray(); 02825 DocCoord* Coords = EndPath->InkPath.GetCoordArray(); 02826 PathFlags* Flags = EndPath->InkPath.GetFlagArray(); 02827 02828 // Get the pointer to all the arrays of the new path data 02829 PathVerb* NewVerbs = pNewPath->InkPath.GetVerbArray(); 02830 DocCoord* NewCoords = pNewPath->InkPath.GetCoordArray(); 02831 PathFlags* NewFlags = pNewPath->InkPath.GetFlagArray(); 02832 02833 // Copy the new path data into the hole we have made 02834 FirstChangedIndex--; 02835 for (INT32 i=1; i<=NumCoords; i++) 02836 { 02837 Verbs[FirstChangedIndex+i] = NewVerbs[i]; 02838 Coords[FirstChangedIndex+i] = NewCoords[i]; 02839 Flags[FirstChangedIndex+i] = NewFlags[i]; 02840 } 02841 02842 // set up retro stuff here 02843 SetRetroPath(EndPath, FirstChangedIndex, pNewPath->InkPath.GetNumCoords()); 02844 02845 return TRUE; 02846 }
|
|
As above, the base class version does nothing.
Reimplemented in OpDrawBrush. Definition at line 3145 of file opfree.cpp. 03146 { 03147 return TRUE; 03148 }
|
|
The base class version does nothing, derived class should reverse its pressure cache.
Reimplemented in OpDrawBrush. Definition at line 3165 of file opfree.cpp. 03166 { 03167 return TRUE; 03168 }
|
|
Tries to rub out sections of the path that have already been drawn.
Definition at line 1006 of file opfree.cpp. 01007 { 01008 // If the mouse has not moved then do not do anything 01009 if (Pos==PreviousPoint) 01010 return; 01011 01012 // Get hold of the blob manager for finding out the size of a blob 01013 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 01014 if (pBlobMgr==NULL) 01015 return; 01016 01017 // Find out about all the coords in the path already 01018 INT32 NumCoords = TrackData->GetNumCoords(); 01019 DocCoord* Coords = TrackData->GetCoordArray(); 01020 01021 // Get line width information 01022 // INT32 LineWidth = GetCurrentLineWidth(); 01023 01024 // Find out about the area round the mouse position to consider for rubbing out 01025 DocRect BlobRect; 01026 pBlobMgr->GetBlobRect(Pos, &BlobRect); 01027 01028 // We want to look at the last few coords in the path. So work out how far back to look 01029 INT32 StopLookingAt = 1; 01030 01031 // Loop through the last few coords to see if the mouse is near them 01032 for (INT32 i=NumCoords-2; i>StopLookingAt; i--) 01033 { 01034 if (BlobRect.ContainsCoord(Coords[i])) 01035 { 01036 // Rub out the line from this coord to the end of the line 01037 RenderRegion* pRegion = DocView::RenderOnTop( NULL, pSpread, UnclippedEOR ); 01038 while (pRegion) 01039 { 01040 for (INT32 n = i+1; n < NumCoords; n++) 01041 RenderLine(pRegion, TrackData, n); 01042 01043 // Get the Next render region 01044 pRegion = DocView::GetNextOnTop( NULL ); 01045 } 01046 01047 // Rub out the actual path Data 01048 if (!TrackData->DeleteFromElement(i+1)) 01049 { 01050 InformError(_R(IDS_PATH_DELETE_ERROR)); 01051 return; 01052 } 01053 01054 // Change the operations parameters 01055 PreviousPoint = Coords[i]; 01056 LineSegmentCount = i; 01057 01058 // this mouse message is finished with 01059 return; 01060 } 01061 } 01062 }
|
|
Chanages the cursor to the type requested and sets the status bar message to the appropriate message for the mode we are in.
Reimplemented in OpDrawBrush. Definition at line 1349 of file opfree.cpp. 01350 { 01351 // Now, if FlipCursor = TRUE, we flip it! 01352 Cursor* WhichCursor = NULL; 01353 String_256 StatusMsg(""); 01354 01355 switch (CurType) 01356 { 01357 case NORMAL_CURSOR: 01358 WhichCursor = pFreeHandCursor; 01359 StatusMsg.Load(_R(IDS_FREEHANDDRAG)); 01360 break; 01361 01362 case JOIN_CURSOR: 01363 WhichCursor = pJoinCursor; 01364 StatusMsg.Load(_R(IDS_FREEHANDDRAGJOIN)); 01365 break; 01366 01367 case STRAIGHTLINE_CURSOR: 01368 WhichCursor = pStraightCursor; 01369 StatusMsg.Load(_R(IDS_FREEHANDSTRAIGHT)); 01370 break; 01371 01372 case RUBOUT_CURSOR: 01373 WhichCursor = pRubOutCursor; 01374 StatusMsg.Load(_R(IDS_FREEHANDRUBOUT)); 01375 break; 01376 01377 case MODIFY_CURSOR: 01378 WhichCursor = pModifyCursor; 01379 StatusMsg.Load(_R(IDS_FREEHANDMODIFY)); 01380 break; 01381 01382 default: 01383 return; 01384 } 01385 01386 // Change Status bar message and the cursor 01387 GetApplication()->UpdateStatusBarText(&StatusMsg); 01388 if (WhichCursor != MyCurrentCursor) 01389 { 01390 // set this cursor as the current cursor and immediately display it 01391 CursorStack::GSetTop(WhichCursor, CurrentCursorID); 01392 01393 // remember this is our current cursor 01394 MyCurrentCursor = WhichCursor; 01395 } 01396 }
|
|
Decides which cursor to display depending on which modifiers are pressed and where the mouse is. PointerPos can be changed in this function.
Definition at line 454 of file opfree.cpp. 00455 { 00456 // If the mouse is over an EndPoint, use the Join Cursor 00457 if (CheckMouseOverSelectedPath(PointerPos, pSpread, &IsEndNearEndpoint)) 00458 { 00459 // Ok the cursor is near the path 00460 if (IsEndNearEndpoint) 00461 { 00462 // it was near one of the paths open ends 00463 SetCursorAndStatus(JOIN_CURSOR); 00464 return; 00465 } 00466 00467 // Must be near the middle of the path 00468 // We can only do a modify join if we started the path on the same path 00469 if ((StartPath==EndPath) && (pJoinInfo->IsNearEndPoint==FALSE)) 00470 { 00471 SetCursorAndStatus(MODIFY_CURSOR); 00472 return; 00473 } 00474 } 00475 00476 // See Which of the modifiers are down... 00477 if (ClickMods.Alternative1) 00478 { 00479 // if Alt is down we are in Straight Line mode 00480 SetCursorAndStatus(STRAIGHTLINE_CURSOR); 00481 } 00482 else 00483 { 00484 if (ClickMods.Adjust) 00485 { 00486 // If Shift is down we are in RubOut mode 00487 SetCursorAndStatus(RUBOUT_CURSOR); 00488 } 00489 else 00490 { 00491 // No Modifiers so use the normal cursor 00492 SetCursorAndStatus(NORMAL_CURSOR); 00493 } 00494 } 00495 }
|
|
Calls the freehand tool with details about the new path, so that future changes in the smoothness will re-build the new path.
Definition at line 2058 of file opfree.cpp. 02059 { 02060 // Go find the current tool 02061 Tool* pTool = Tool::GetCurrent(); 02062 if (pTool) 02063 { 02064 // Make sure that it is the freehand tool, and if so set the previous path 02065 if (pTool->GetID()==TOOLID_FREEHAND) 02066 ((FreeHandTool*)pTool)->SetPreviousPath(pNodePath, Start, Len); 02067 } 02068 }
|
|
Joins a Simple path with the new freehand path and builds all the undo that is needed in the process.
Definition at line 1563 of file opfree.cpp. 01564 { 01565 // First we should make a note of the region that we will need redrawing 01566 DocRect InvalidRect = FreePath->GetBlobBoundingRect(); 01567 01568 DocRect OriginalRect = OldPath->GetBoundingRect(); 01569 // Spread* pSpread = Document::GetSelectedSpread(); 01570 01571 InvalidateBrushRegion(OldPath); 01572 01573 01574 // Need to know where in the joined path that the new section will be 01575 INT32 NumSlots = FreePath->InkPath.GetNumCoords(); 01576 INT32 StartSlot = 0; 01577 // INT32 OldNumSlots = OldPath->InkPath.GetNumCoords(); 01578 01579 // DocCoord* pCoords = FreePath->InkPath.GetCoordArray(); 01580 // DocCoord* pOldCoords = OldPath->InkPath.GetCoordArray(); 01581 01582 // Make a copy of the node we are joining with 01583 NodePath* JoinPath = MakeCopy(OldPath); 01584 if (JoinPath == NULL) 01585 return FALSE; 01586 01587 // first find out if we are editing a brush (ugh, yes I know) 01588 AttrBrushType* pAttrBrush; 01589 NodeAttribute* pAttr = NULL; 01590 BrushHandle Handle = BrushHandle_NoBrush; 01591 JoinPath->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), &pAttr); 01592 if (pAttr != NULL) 01593 { 01594 pAttrBrush = (AttrBrushType*)pAttr; 01595 Handle = pAttrBrush->GetBrushHandle(); 01596 } 01597 01598 // find out if the two paths join at the start 01599 BOOL PathReversed = FALSE; 01600 01601 // before Joining them 01602 BOOL NewPathReversed = FALSE; 01603 01604 if (Handle != BrushHandle_NoBrush) 01605 SimpleJoinBrush(JoinPath, &(FreePath->InkPath)); 01606 01607 if (!JoinPath->InkPath.SimpleJoin(&FreePath->InkPath, &StartSlot, &NewPathReversed, &PathReversed)) 01608 return FALSE; 01609 01610 // Insert the new object 01611 if (!InsertNewNode(JoinPath, InvalidRect, OldPath)) 01612 return FALSE; 01613 01614 // Reverse the original mouse move data if the fitted path was reversed 01615 if (NewPathReversed) 01616 TrackData->Reverse(); 01617 01618 // if we are a brush then we don't ever want the path reversed, 01619 if (Handle != BrushHandle_NoBrush && PathReversed) 01620 { 01621 TrackData->Reverse(); 01622 JoinPath->InkPath.Reverse(); 01623 StartSlot = 0; 01624 } 01625 01626 // Tell the freehand tool all about it 01627 SetRetroPath(JoinPath, StartSlot, NumSlots); 01628 01629 m_pNewNodePath = JoinPath; 01630 01631 InvalidateBrushRegion(JoinPath); 01632 01633 // It Worked! 01634 return TRUE; 01635 }
|
|
Currently this only has to do work if we are editing a brush containing pressure data. In this case we must generate a new list of pressure info and insert it into the brush.
Reimplemented in OpDrawBrush. Definition at line 2996 of file opfree.cpp. 02997 { 02998 if (pInsertedNode == NULL || pNewPath == NULL) 02999 { 03000 ERROR3("Null inputs to OpDrawBrush::SimpleJoinBrush"); 03001 return FALSE; 03002 } 03003 03004 // first check to see if the edited path has a brush applied to it, 03005 // if it doesn't then we'll leave 03006 NodeAttribute* pAttr; 03007 AttrBrushType* pAttrBrush; 03008 pInsertedNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), &pAttr); 03009 if (pAttr == NULL) 03010 return TRUE; 03011 03012 pAttrBrush = (AttrBrushType*)pAttr; 03013 // if our brush has a 'no brush' handle then likewise 03014 if (pAttrBrush->GetBrushHandle() == BrushHandle_NoBrush) 03015 return TRUE; 03016 03017 // if our brush is not either timestamping or has a pressure list then we will leave aswell 03018 if (!pAttrBrush->ContainsPressureCache() && !pAttrBrush->IsTimeStamping()) 03019 return TRUE; 03020 03021 // Invalidate the brush rect 03022 NodePath* EditPath = StartPath; 03023 if (EditPath == NULL) 03024 EditPath = EndPath; 03025 03026 if (EditPath != NULL) 03027 { 03028 pAttrBrush->ClearCachedRect(); 03029 DocRect BRect = pAttrBrush->GetAttrBoundingRect(EditPath); 03030 EditPath->ReleaseCached(); 03031 Spread* pSpread = Document::GetSelectedSpread(); 03032 if (pSpread != NULL) 03033 DoInvalidateRegion(pSpread, BRect); 03034 } 03035 else 03036 return FALSE; 03037 03038 // find out what type of join we have 03039 SimpleJoinType JoinType = GetSimpleJoinType(pNewPath, &(pInsertedNode->InkPath)); 03040 if (JoinType == JOINTYPE_NONE) 03041 { 03042 ERROR3("No join type in OpDrawBrush::SimpleJoinBrush"); 03043 return TRUE; 03044 } 03045 03046 // we need to know the distance along the original path where we want to insert the 03047 // new points. As this is a simple join it will either be at the beginning or the end. 03048 // we also need to know the distance to the end of the new points, as this is required 03049 // for the undo. 03050 MILLIPOINT NewPathLength = (MILLIPOINT)pNewPath->GetPathLength(); 03051 MILLIPOINT OldPathLength = -1; 03052 if (StartPath != NULL) 03053 OldPathLength = (MILLIPOINT)StartPath->InkPath.GetPathLength(); 03054 else 03055 { 03056 if (EndPath != NULL) 03057 OldPathLength = (MILLIPOINT)EndPath->InkPath.GetPathLength(); 03058 } 03059 03060 MILLIPOINT InsertDistance = -1; 03061 MILLIPOINT EndInsertDistance = -1; 03062 INT32 StartIndex = 0; //for the pressure insert 03063 03064 // ask the attribute for its pressure cache 03065 CDistanceSampler* pAttrData = pAttrBrush->GetPressureCache(); 03066 if (pAttrData == NULL) 03067 return FALSE; 03068 // according to the type of join we will want to insert our new data at the beginning or the 03069 // end, we may also want to reverse it. We need the distance values to give to the pressure 03070 // generator function 03071 switch (JoinType) 03072 { 03073 case JOINTYPE_NEWSTART_TO_OLDSTART: 03074 InsertDistance = -1; 03075 EndInsertDistance = 0; // indicates that we are inserting at the start 03076 StartIndex = 0; 03077 break; 03078 case JOINTYPE_NEWSTART_TO_OLDEND: 03079 InsertDistance = OldPathLength; // indicates that we are inserting at the end 03080 EndInsertDistance = -1; 03081 StartIndex = pAttrData->GetInternalIndexFromDistance(OldPathLength); 03082 if (StartIndex==-1) StartIndex = pAttrData->GetNumItems(); 03083 break; 03084 case JOINTYPE_NEWEND_TO_OLDSTART: 03085 InsertDistance = -1; 03086 EndInsertDistance = 0; 03087 StartIndex = 0; 03088 break; 03089 case JOINTYPE_NEWEND_TO_OLDEND: 03090 InsertDistance = OldPathLength; 03091 EndInsertDistance = -1; 03092 StartIndex = pAttrData->GetInternalIndexFromDistance(OldPathLength); 03093 if (StartIndex==-1) StartIndex = pAttrData->GetNumItems(); 03094 03095 break; 03096 default: 03097 ERROR3("Unknown join type in OpDrawBrush::SimpleJoinBrush"); 03098 return FALSE; 03099 } 03100 03101 03102 // get ourselves a data cache to insert courtesy of our static function 03103 CDistanceSampler* pSampler = OpDrawBrush::GeneratePressureData(pAttrBrush, InsertDistance, EndInsertDistance, NewPathLength); 03104 if (pSampler == NULL) 03105 return FALSE; 03106 03107 03108 // make the action to insert the pressure list 03109 03110 AddPressurePointsAction* pAction; 03111 UINT32 NumPoints = pSampler->GetNumItems(); 03112 03113 if (AddPressurePointsAction::Init(this, &UndoActions, pAttrBrush, pSampler, 03114 StartIndex, NumPoints, &pAction) == AC_FAIL) 03115 return FALSE; 03116 03117 // Invalidate the brush rect again 03118 if (EditPath != NULL) 03119 { 03120 pAttrBrush->ClearCachedRect(); 03121 DocRect BRect = pAttrBrush->GetAttrBoundingRect(EditPath); 03122 EditPath->ReleaseCached(); 03123 Spread* pSpread = Document::GetSelectedSpread(); 03124 if (pSpread != NULL) 03125 DoInvalidateRegion(pSpread, BRect); 03126 } 03127 03128 return TRUE; 03129 }
|
|
Sets up the curve fitter and finally smooths the data in the Track data buffer into the new node path.
Definition at line 891 of file opfree.cpp. 00892 { 00893 // To work out how much we need to smooth the curve by, we must know what 00894 // zoom factor we are currently at 00895 DocView* pDocView = DocView::GetSelected(); 00896 if (pDocView==NULL) 00897 return FALSE; 00898 00899 // When this path is built it will actually replace a section from the middle of the 00900 // original path, so we must make sure that is starts and ends on the original 00901 // The start was done before the drag started, the end can be done now. 00902 if ((StartPath!=NULL) && (StartPath==EndPath) && (pJoinInfo->IsNearEndPoint==FALSE)) 00903 { 00904 // Find out the coord on the original path where the endpoint got closest to 00905 PreviousPoint = EndPath->InkPath.ClosestPointTo(Mu, CloseTo); 00906 00907 // Add it to the path data 00908 if (TrackData->InsertLineTo(PreviousPoint)) 00909 { 00910 // and add pressure info if needed 00911 if (AddPressureToPath) 00912 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure); 00913 } 00914 } 00915 00916 // Find out how flat they need the curve. This number represents 00917 // how far off the original track data the curve can get before it 00918 // is split and turned into more curves. The smaller the number 00919 // the tighter the fit. 00920 double ScaleFactor = (pDocView->GetViewScale()).MakeDouble(); 00921 double ErrorLevel = (64 + (160*Smoothness)) / ScaleFactor; 00922 ErrorLevel = ErrorLevel * ErrorLevel; 00923 00924 // FitCurve needs the number of points in the path, which is the 00925 // number of Line Segments + 1 00926 CurveFitObject CurveFitter(&(pNewNodePath->InkPath), ErrorLevel); 00927 00928 // Try to initialise the curve fitter 00929 if (!CurveFitter.Initialise(TrackData, LineSegmentCount+1)) 00930 return FALSE; 00931 00932 // All went ok, so fit the curve to the track data and return success 00933 CurveFitter.FitCurve(); 00934 return TRUE; 00935 }
|
|
Reimplemented from Operation. Definition at line 178 of file opfree.h. 00178 { return FALSE; }
|
|
Splits the path, building undo info, at the coord supplied.
Definition at line 2508 of file opfree.cpp. 02509 { 02510 // First we need to get some space to put any new coords etc that will be generated 02511 INT32 SplitElement; 02512 UINT32 NumElements; 02513 PathVerb NewVerbs[6]; 02514 DocCoord NewCoords[6]; 02515 PathFlags NewFlags[6]; 02516 02517 // First we had better go and see if this point is close to any of the existing coords 02518 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 02519 if (pBlobMgr!=NULL) 02520 { 02521 // There was a blob manager, so we could test the coords 02522 // Find out about the area round the mouse position to consider for rubbing out 02523 DocRect BlobRect; 02524 DocCoord BlobPoint = SplitPoint; 02525 pBlobMgr->GetBlobRect(BlobPoint, &BlobRect); 02526 02527 // Find out about all the coords in the path already 02528 PathFlags* Flags = EndPath->InkPath.GetFlagArray(); 02529 DocCoord* Coords = EndPath->InkPath.GetCoordArray(); 02530 INT32 NumCoords = EndPath->InkPath.GetNumCoords(); 02531 02532 // Loop through all the coords in the path 02533 for (INT32 i=0; i<NumCoords; i++) 02534 { 02535 // Is this coord close to the point specified 02536 if ((Flags[i].IsEndPoint==TRUE) && (BlobRect.ContainsCoord(Coords[i]))) 02537 { 02538 // Yep, set the outputs to the correct values and return Success 02539 *SplitAt = i+1; 02540 *NewElements = 0; 02541 02542 // Make sure that the rotate flags are unset around the coord 02543 Flags[i].IsRotate = FALSE; 02544 if (i>0) 02545 Flags[i-1].IsRotate = FALSE; 02546 02547 if (i<NumCoords-1) 02548 Flags[i+1].IsRotate = FALSE; 02549 02550 // And tell caller that it worked 02551 return TRUE; 02552 } 02553 } 02554 } 02555 02556 // Try and split the path. This returns FALSE if the path did not need splitting 02557 if (EndPath->InkPath.SplitAtPoint(SplitPoint, &SplitElement, &NumElements, NewVerbs, NewCoords)) 02558 { 02559 // Make a note of where the new endpoint will be 02560 *SplitAt = SplitElement+(NumElements/2); 02561 *NewElements = NumElements; 02562 02563 // The path was split, so we know where, and how, so let's party on the path 02564 PathVerb* Verbs = EndPath->InkPath.GetVerbArray(); 02565 PathFlags* Flags = EndPath->InkPath.GetFlagArray(); 02566 DocCoord* Coords = EndPath->InkPath.GetCoordArray(); 02567 // UINT32 NumCoords = EndPath->InkPath.GetNumCoords(); 02568 INT32 NumToChange; 02569 02570 // We're adding something, either a line or curve - check which 02571 if ((Verbs[SplitElement] & ~PT_CLOSEFIGURE) == PT_BEZIERTO) 02572 { 02573 // Adding a curve - number to change = 6 02574 NumToChange = 6; 02575 02576 // Initialise the flags appropriately 02577 for (INT32 i=0; i<6; i++) 02578 { 02579 // copy the flags from the old curve (repeat the flag in the first 3 elements) 02580 NewFlags[i] = Flags[SplitElement+(i%3)]; 02581 NewFlags[i].IsSelected = FALSE; 02582 02583 // Want it to be a cusp in the middle 02584 if ((i>0) && (i<4)) 02585 { 02586 NewFlags[i].IsSmooth = FALSE; 02587 NewFlags[i].IsRotate = FALSE; 02588 } 02589 } 02590 02591 // If this was happening at the end of a path, 02592 // then make sure the close figure flag is set correctly 02593 if (Verbs[SplitElement+2] & PT_CLOSEFIGURE) 02594 NewVerbs[5] |= PT_CLOSEFIGURE; 02595 } 02596 else 02597 { 02598 // The slit happened in a straight line section 02599 NumToChange = 2; 02600 NewFlags[0] = NewFlags[1] = Flags[SplitElement]; 02601 NewFlags[0].IsSmooth = NewFlags[0].IsRotate = FALSE; 02602 NewFlags[0].IsSelected = FALSE; 02603 02604 // Make sure that the close figure flag is maintained 02605 if (Verbs[SplitElement] & PT_CLOSEFIGURE) 02606 NewVerbs[1] |= PT_CLOSEFIGURE; 02607 } 02608 02609 // Start performing actions to insert the split point with full undo 02610 Action* UnAction; 02611 ActionCode Act = RemovePathElementAction::Init(this, &UndoActions, NumToChange/2, 02612 SplitElement, (Action**)(&UnAction)); 02613 02614 // if we failed to init the action, then fail this operation 02615 if (Act==AC_FAIL) 02616 return FALSE; 02617 02618 // record details about the path in the action before we start inserting stuff 02619 ((RemovePathElementAction*)UnAction)->RecordPath(EndPath); 02620 02621 // Move to the place in the path where the split took place 02622 EndPath->InkPath.SetPathPosition(SplitElement); 02623 PathFlags InsertFlags; 02624 BOOL InsertWorked; 02625 02626 // insert a curve or a line, depending on where the split happened 02627 if (NumToChange==6) 02628 InsertWorked = EndPath->InkPath.InsertCurveTo(NewCoords[0], NewCoords[1], NewCoords[2], &InsertFlags); 02629 else 02630 InsertWorked = EndPath->InkPath.InsertLineTo(NewCoords[0], &InsertFlags); 02631 02632 // see if the insertion worked 02633 if (!InsertWorked) 02634 return FALSE; 02635 02636 // Build an action to record the changes we're about to make to the path 02637 ModifyPathAction* ModAction; 02638 Act = ModifyPathAction::Init(this, &UndoActions, NumToChange, (Action**)(&ModAction)); 02639 if (Act==AC_FAIL) 02640 return FALSE; 02641 02642 // If the action is happy... 02643 if (Act!=AC_NORECORD) 02644 { 02645 // Some pointers to what has changed 02646 PathVerb* ChangedVerbs; 02647 PathFlags* ChangedFlags; 02648 DocCoord* ChangedCoords; 02649 INT32* ChangedIndices; 02650 02651 // memory for the details about what has changed 02652 ALLOC_WITH_FAIL(ChangedVerbs, (PathVerb*) CCMalloc(NumToChange * sizeof(PathVerb)), this); 02653 ALLOC_WITH_FAIL(ChangedFlags, (PathFlags*) CCMalloc(NumToChange* sizeof(PathFlags)), this); 02654 ALLOC_WITH_FAIL(ChangedCoords, (DocCoord*) CCMalloc(NumToChange* sizeof(DocCoord)), this); 02655 ALLOC_WITH_FAIL(ChangedIndices, (INT32*) CCMalloc(NumToChange* sizeof(INT32)), this); 02656 02657 // See of all the allocations worked 02658 if (!ChangedVerbs || !ChangedFlags || !ChangedCoords || !ChangedIndices) 02659 { 02660 // They did not, so free them up and fail 02661 if (ChangedVerbs) CCFree(ChangedVerbs); 02662 if (ChangedFlags) CCFree(ChangedFlags); 02663 if (ChangedCoords) CCFree(ChangedCoords); 02664 if (ChangedIndices) CCFree(ChangedIndices); 02665 02666 return FALSE; 02667 } 02668 02669 // Reread the pointers, in case they've changed 02670 Verbs = EndPath->InkPath.GetVerbArray(); 02671 Flags = EndPath->InkPath.GetFlagArray(); 02672 Coords = EndPath->InkPath.GetCoordArray(); 02673 02674 // Now record the arrays... 02675 for (INT32 i=0; i<NumToChange; i++) 02676 { 02677 // record which elements changed and what they used to be 02678 ChangedIndices[i] = SplitElement+i; 02679 ChangedVerbs[i] = Verbs[SplitElement+i]; 02680 ChangedFlags[i] = Flags[SplitElement+i]; 02681 ChangedCoords[i] = Coords[SplitElement+i]; 02682 } 02683 02684 // and store the info in the action 02685 ModAction->StoreArrays(ChangedVerbs, ChangedFlags, ChangedCoords, ChangedIndices, EndPath); 02686 } 02687 02688 // Reread the pointers, in case they've changed 02689 Verbs = EndPath->InkPath.GetVerbArray(); 02690 Flags = EndPath->InkPath.GetFlagArray(); 02691 Coords = EndPath->InkPath.GetCoordArray(); 02692 02693 // Now that the undo rigmarole has been done, let's change the path 02694 for (INT32 i=0; i<NumToChange; i++) 02695 { 02696 Verbs[SplitElement+i] = NewVerbs[i]; 02697 Flags[SplitElement+i] = NewFlags[i]; 02698 Coords[SplitElement+i] = NewCoords[i]; 02699 } 02700 } 02701 else 02702 { 02703 // else we tried to split at an existing control point (endpoint) 02704 // That means that there were no new endpoints 02705 *NewElements = 0; 02706 *SplitAt = SplitElement; 02707 02708 // See if we can find the control point in question 02709 DocCoord* Coords = EndPath->InkPath.GetCoordArray(); 02710 INT32 NumCoords = EndPath->InkPath.GetNumCoords(); 02711 02712 // see if the split point is over the last point on the curve 02713 if (Coords[NumCoords-1]==SplitPoint) 02714 *SplitAt = NumCoords; 02715 } 02716 02717 // all worked 02718 return TRUE; 02719 }
|
|
Tries to Join the new path with any of the existing paths.
Definition at line 1411 of file opfree.cpp. 01412 { 01413 ObjChangeFlags cFlagsDelete(TRUE); 01414 ObjChangeFlags cFlagsReplace(FALSE,TRUE); 01415 ObjChangeFlags cFlagsChanging; 01416 ObjChangeParam ObjChange; 01417 01418 if (StartPath != NULL && EndPath != NULL && StartPath != EndPath) 01419 { 01420 // Cope with the case when the two separate paths are being joined together with this freehand line. 01421 // In this case, the EndPath is hidden (effectively deleted), and the StartPath is replaced in the tree 01422 // by hiding it and inserting the resultant NodePath in its place 01423 01424 // Is it ok to delete the end path? 01425 ObjChange.Define(OBJCHANGE_STARTING,cFlagsDelete,EndPath,this); 01426 if (!EndPath->AllowOp(&ObjChange)) 01427 return TRUE; // Pretend that we've done it. 01428 01429 // Is it ok to replace the start path? 01430 ObjChange.Define(OBJCHANGE_STARTING,cFlagsReplace,StartPath,this); 01431 if (!StartPath->AllowOp(&ObjChange)) 01432 return TRUE; // Pretend that we've done it. 01433 } 01434 else if (StartPath != NULL || EndPath != NULL) 01435 { 01436 // Some joining will take place with either in StartPath or EndPath 01437 01438 // Either the StartPath or the EndPath will be hidden and replaced by another NodePath 01439 ObjChange.Define(OBJCHANGE_STARTING,cFlagsChanging,StartPath,this); 01440 01441 // If we have a start path, the op will happen to the start path 01442 if (StartPath != NULL && !StartPath->AllowOp(&ObjChange)) 01443 return TRUE; // Pretend that we've done it. 01444 01445 // If we DONT have a start path, the op will happen to the end path 01446 if (StartPath == NULL && !EndPath->AllowOp(&ObjChange)) 01447 return TRUE; // Pretend that we've done it. 01448 } 01449 01450 if (StartPath == NULL) 01451 { 01452 if (EndPath == NULL) 01453 { 01454 // Trivial Case - No Joining needed 01455 NodePath* JoinPath = MakeCopy(FreePath); 01456 if (JoinPath == NULL) 01457 return FALSE; 01458 01459 // Try to close it 01460 JoinPath->InkPath.TryToClose(); 01461 01462 // Apply some attributes 01463 if (!ApplyAttributes(JoinPath, GetWorkingDoc())) 01464 return FALSE; 01465 01466 01467 if (!AddPressureAttribute(JoinPath)) 01468 return(FALSE); 01469 01470 // Insert the node and invalidate the region 01471 if (!DoInsertNewNode(JoinPath, StartSpread, FALSE)) 01472 return FALSE; 01473 01474 if (!DoInvalidateNodeRegion(JoinPath, TRUE)) 01475 return FALSE; 01476 01477 m_pNewNodePath = JoinPath; 01478 // Tell the freehand tool that it has a previous path 01479 SetRetroPath(JoinPath, 0, JoinPath->InkPath.GetNumCoords()); 01480 } 01481 else 01482 { 01483 if (EndPath->InkPath.IsComplexPath()) 01484 { 01485 // Complex Join (End of new path Joined) 01486 if (!ComplexJoin(FreePath, EndPath)) 01487 return FALSE; 01488 } 01489 else 01490 { 01491 // Simple Join (End of new path Joined) 01492 if (!SimpleJoin(FreePath, EndPath)) 01493 return FALSE; 01494 } 01495 } 01496 } 01497 else 01498 { 01499 if (EndPath == NULL) 01500 { 01501 if (StartPath->InkPath.IsComplexPath()) 01502 { 01503 // Complex Join (Start of new path Joined) 01504 if (!ComplexJoin(FreePath, StartPath)) 01505 return FALSE; 01506 } 01507 else 01508 { 01509 // Simple Join (Start of New Path Joined) 01510 if (!SimpleJoin(FreePath, StartPath)) 01511 return FALSE; 01512 } 01513 } 01514 else 01515 { 01516 if (StartPath == EndPath) 01517 { 01518 if (StartPath->InkPath.IsComplexPath()) 01519 { 01520 // Complex to Same Complex Join 01521 if (!ComplexToComplexJoin(FreePath, StartPath)) 01522 return FALSE; 01523 } 01524 else 01525 { 01526 // Simple to Same Simple Join (Start = End) 01527 if (!SimpleJoin(FreePath, StartPath)) 01528 return FALSE; 01529 } 01530 } 01531 else 01532 { 01533 // Compex To Complex Join (Start and End different and complex) 01534 // Complex To Simple Join (Start and End different and start complex) 01535 // Complex To Simple Join (Start and End different and end complex) 01536 // Simple To Simple Join (Start and End Different) 01537 if (!VeryComplexToComplexJoin(FreePath, StartPath, EndPath)) 01538 return FALSE; 01539 } 01540 } 01541 } 01542 01543 // Worked 01544 return TRUE; 01545 }
|
|
Replaces a section from the path that the drag was started and finished on with the newly drawn curve section.
Definition at line 2381 of file opfree.cpp. 02382 { 02383 // The elements that the split occured on 02384 INT32 FirstElement, SecondElement, NewElements; 02385 02386 ObjChangeFlags cFlags; 02387 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,EndPath,this); 02388 if (!EndPath->AllowOp(&ObjChange, TRUE)) 02389 return TRUE; // Pretend that we've done it. 02390 02391 // Invalidate it as it was 02392 if (!DoInvalidateNodeRegion(EndPath, TRUE)) 02393 return FALSE; 02394 02395 // Split old path at start and end points 02396 if (!SplitAtPoint(StartPoint, &FirstElement, &NewElements)) 02397 return FALSE; 02398 02399 if (!SplitAtPoint(PreviousPoint, &SecondElement, &NewElements)) 02400 return FALSE; 02401 02402 // We may need to adjust the first element if the second element was 02403 // before it in the path 02404 if (SecondElement<=FirstElement) 02405 { 02406 // Swap the elements around and move the first one back a bit 02407 INT32 Temp = FirstElement + (NewElements/2); 02408 FirstElement = SecondElement; 02409 SecondElement = Temp; 02410 02411 // We will also need to reverse the original curve here 02412 // (as well as the original track data) 02413 pNewNodePath->InkPath.Reverse(); 02414 TrackData->Reverse(); 02415 ReverseBrushPressure(); // if we are a brush we will want to reverse our pressure data 02416 } 02417 02418 // Go and see if which part of the path we should be replacing 02419 if (!EndPath->InkPath.IsComplexPath() && EndPath->InkPath.IsFilled) 02420 { 02421 // Here we need to see if we will replace the wrong bit of the path and try and do something 02422 // about it if we are. The wrong bit is defined as follows. If you were to draw a filled shape 02423 // such as an ellipse and modified it by drawing a small loop around one of the control points 02424 // you should get an ellipse with a small notch cut out of it. However, if you do this around 02425 // the Start/End control point you end up with no ellipse and just a small notch. 02426 // To get round this, we always try to replace the smallest number of control points possible. 02427 INT32 HalfElements = EndPath->InkPath.GetNumCoords() / 2; 02428 INT32 ReplaceElements = SecondElement - FirstElement; 02429 if (HalfElements < ReplaceElements) 02430 { 02431 // We were trying to replace more than half of the elements in the path, so actually 02432 // replace the other, large half of the path 02433 02434 // Here we have to change the the start element of the path, so we have 02435 // to hide the original and make a copy of it 02436 BOOL IsOk = FALSE; 02437 Node* pCopyNode = NULL; 02438 CALL_WITH_FAIL(EndPath->NodeCopy(&pCopyNode), this, IsOk); 02439 02440 // See if we managed to make a copy of the node 02441 if (!IsOk) 02442 return FALSE; 02443 02444 // Insert the copy 02445 if (!DoInsertNewNode((NodeRenderableBounded*)pCopyNode, EndPath, NEXT, FALSE)) 02446 return FALSE; 02447 02448 // Hide the original 02449 if (!DoHideNode(EndPath, TRUE)) 02450 return FALSE; 02451 02452 // Copy the pointer back to where it used to be 02453 EndPath = (NodePath*) pCopyNode; 02454 ERROR3IF(!EndPath->IS_KIND_OF(NodePath), "Copy of a Node path was not a node path"); 02455 02456 // Make the Last replace element the start/end of the path 02457 if (EndPath->InkPath.ChangeStartElement(SecondElement-1)) 02458 { 02459 // It worked, so modify the Start and End Elements to match 02460 FirstElement = 1; 02461 SecondElement = EndPath->InkPath.GetNumCoords() - ReplaceElements; 02462 02463 // We will also need to reverse the original curve here 02464 // (as well as the original track data) 02465 pNewNodePath->InkPath.Reverse(); 02466 TrackData->Reverse(); 02467 } 02468 } 02469 02470 } 02471 02472 // replace section with new path 02473 INT32 NumElements = SecondElement - FirstElement; 02474 if (!ReplaceMiddleOfPath(pNewNodePath, FirstElement, NumElements)) 02475 return FALSE; 02476 02477 // Mark the nodes bounding rect as invalid 02478 EndPath->InvalidateBoundingRect(); 02479 02480 TRACEUSER( "Diccon", _T("Replacing middle of Path\n")); 02481 InvalidateBrushRegion(EndPath); 02482 // and invalidate how it is now 02483 if (!DoInvalidateNodeRegion(EndPath, TRUE)) 02484 return FALSE; 02485 02486 // Failed to do it 02487 return TRUE; 02488 }
|
|
Joins the new freehand path with two other paths (Which may or may not be complex) and builds all the undo info that is needed.
Definition at line 1758 of file opfree.cpp. 01759 { 01760 // First we should make a note of the region that we will need redrawing 01761 DocRect InvalidRect = FreePath->GetBlobBoundingRect(); 01762 01763 // Need to know where in the joined path that the new section will be 01764 INT32 NumSlots = FreePath->InkPath.GetNumCoords(); 01765 INT32 StartSlot; 01766 01767 // Make a copy of the of the path we are Joining to 01768 NodePath* JoinPath = MakeCopy(TopPath); 01769 if (JoinPath==NULL) 01770 return FALSE; 01771 01772 // Merge in the other complex path 01773 if (!JoinPath->InkPath.MergeTwoPaths(BotPath->InkPath)) 01774 return FALSE; 01775 01776 // Join the new path with the one already there 01777 BOOL NewPathReversed = FALSE; 01778 if (!JoinPath->InkPath.ComplexToSameComplexJoin(&FreePath->InkPath, &StartSlot, &NewPathReversed)) 01779 return FALSE; 01780 01781 // Insert the new object 01782 if (!InsertNewNode(JoinPath, InvalidRect, TopPath, BotPath)) 01783 return FALSE; 01784 01785 // Reverse the original mouse move data if the fitted path was reversed 01786 if (NewPathReversed) 01787 TrackData->Reverse(); 01788 01789 // Tell the freehand tool all about it 01790 SetRetroPath(JoinPath, StartSlot, NumSlots); 01791 01792 // It Worked 01793 return TRUE; 01794 }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|