#include <pathedit.h>
Inheritance diagram for OpToggleSmooth:
Public Member Functions | |
OpToggleSmooth () | |
Constructor for toggle smooth/cusp operation. | |
void | DoTogglePoint (NodePath *, INT32 Index, Spread *, BOOL AllSmooth, BOOL DontMoveOnCusp) |
This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go. | |
Static Public Member Functions | |
static BOOL | Init () |
Adds the operation to the list of all known operations. | |
static OpState | GetState (String_256 *Description, OpDescriptor *) |
Find out the state of the operation at the specific time. | |
Protected Member Functions | |
BOOL | TogglePathPoints (NodePath *CurrentNode, INT32 Index, BOOL AllSmooth, BOOL DontMoveOnCusp) |
This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go. | |
BOOL | MakePointCusp (NodePath *CurrentNode, INT32 Index, BOOL DontMoveOnCusp) |
Makes the specified endpoint in the path a cusp join. | |
BOOL | MakePointSmooth (NodePath *CurrentNode, INT32 Index) |
Makes the specified endpoint in the path a smooth join. Has to move the control points around the endpoint. |
Definition at line 504 of file pathedit.h.
|
Constructor for toggle smooth/cusp operation.
Definition at line 5156 of file pathedit.cpp.
|
|
This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go.
Definition at line 5230 of file pathedit.cpp. 05231 { 05232 if (!DoStartSelOp(TRUE,TRUE)) 05233 { 05234 FailAndExecute(); 05235 End(); 05236 return; 05237 } 05238 05239 // We need to make sure the node or nodes that will be effected will allow this op to happen 05240 ObjChangeFlags cFlags; 05241 cFlags.TransformNode = TRUE; 05242 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); 05243 BOOL Failed = FALSE; 05244 05245 if (ThisNode==NULL) 05246 { 05247 // If there's no node pointer then scan the selection! 05248 SelRange* Selected = GetApplication()->FindSelection(); 05249 Node* pNode = Selected->FindFirst(); 05250 while (pNode!=NULL && !Failed) 05251 { 05252 NodePath* pSelected = pNode->IsAnEditablePath(); 05253 if ( (pSelected != NULL) && (pSelected->AllowOp(&ObjChange)) ) 05254 { 05255 if (!TogglePathPoints(pSelected, Index, AllSmooth, DontMoveOnCusp)) 05256 { 05257 InformError(); 05258 Failed = TRUE; 05259 } 05260 } 05261 pNode = Selected->FindNext(pNode); 05262 } 05263 } 05264 else 05265 { 05266 if (ThisNode->AllowOp(&ObjChange)) 05267 { 05268 if (!TogglePathPoints(ThisNode, Index, AllSmooth, DontMoveOnCusp)) 05269 { 05270 InformError(); 05271 Failed = TRUE; 05272 } 05273 } 05274 } 05275 05276 // Update all the parents of the effected paths. 05277 if (!Failed) 05278 { 05279 ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this); 05280 Failed = !UpdateChangedNodes(&ObjChange); 05281 } 05282 05283 if (Failed) 05284 FailAndExecute(); 05285 05286 End(); 05287 }
|
|
Find out the state of the operation at the specific time.
Definition at line 5195 of file pathedit.cpp. 05196 { 05197 OpState Blobby; // Ungreyed, unticked 05198 return Blobby; 05199 }
|
|
Adds the operation to the list of all known operations.
Reimplemented from SimpleCCObject. Definition at line 5171 of file pathedit.cpp. 05172 { 05173 return (RegisterOpDescriptor( 0, 05174 _R(IDS_NODEPATH_EDIT), 05175 CC_RUNTIME_CLASS(OpToggleSmooth), 05176 OPTOKEN_NODEPATH, 05177 OpToggleSmooth::GetState, 05178 0, // help ID 05179 _R(IDBBL_NODEPATHOP), 05180 0 ) ); // bitmap ID 05181 }
|
|
Makes the specified endpoint in the path a cusp join.
Definition at line 5417 of file pathedit.cpp. 05418 { 05419 // Parameter checks 05420 ERROR2IF(pPath == NULL, FALSE, "Path pointer was NULL"); 05421 ERROR2IF(Index < 0, FALSE, "Path index was negative"); 05422 ERROR2IF(Index >= pPath->InkPath.GetNumCoords(), FALSE, "Path index off end of path"); 05423 05424 // Store the current state of the endpoint for undo then make it cusp 05425 ModifyElementAction* UnAction = NULL; 05426 PathFlags* Flags = NULL; 05427 PathVerb* Verbs = NULL; 05428 DocCoord* Coords = NULL; 05429 pPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 05430 ERROR2IF((Verbs==NULL) || (Coords==NULL) || (Flags==NULL), FALSE, "Path array pointer was NULL (panic!)"); 05431 ActionCode Act = ModifyElementAction::Init(this, &UndoActions, Verbs[Index], Flags[Index], 05432 Coords[Index], Index, pPath, (Action**)&UnAction); 05433 if (Act == AC_FAIL) 05434 return FALSE; 05435 Flags[Index].IsSmooth = FALSE; 05436 Flags[Index].IsRotate = FALSE; 05437 05438 // Modify the previous control point (if there is one) 05439 INT32 PrevControl = pPath->InkPath.FindPrevControlPoint(Index); 05440 if (PrevControl != -1) 05441 { 05442 Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl], Flags[PrevControl], 05443 Coords[PrevControl], PrevControl, pPath, (Action**)&UnAction); 05444 if (Act == AC_FAIL) 05445 return FALSE; 05446 05447 // Move the control point if required and it is possible 05448 if (!DontMoveOnCusp && (!((Verbs[Index] == PT_MOVETO) && (Verbs[Index+1] == PT_BEZIERTO) && 05449 (Verbs[Index+3] & PT_CLOSEFIGURE) && (Coords[Index] == Coords[Index+3])))) 05450 { 05451 Coords[PrevControl] = DocCoord::OneThird(Coords[PrevControl+1],Coords[PrevControl-2]); 05452 } 05453 Flags[PrevControl].IsSmooth = FALSE; 05454 Flags[PrevControl].IsRotate = FALSE; 05455 05456 // Cope with the possibility that we have made the start/end of a closed 05457 // path a cusp - we can tell this if the endpoint associated with the 05458 // previous control point is not the same as Index 05459 if (Index != PrevControl+1) 05460 { 05461 Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl+1], Flags[PrevControl+1], 05462 Coords[PrevControl+1], PrevControl+1, pPath, (Action**)&UnAction); 05463 if (Act == AC_FAIL) 05464 return FALSE; 05465 Flags[PrevControl+1].IsSmooth = FALSE; 05466 Flags[PrevControl+1].IsRotate = FALSE; 05467 } 05468 } 05469 05470 // Modify the next control point (if there is one) 05471 INT32 NextControl = pPath->InkPath.FindNextControlPoint(Index); 05472 if (NextControl != -1) 05473 { 05474 Act = ModifyElementAction::Init(this, &UndoActions, Verbs[NextControl], Flags[NextControl], 05475 Coords[NextControl], NextControl, pPath, (Action**)&UnAction); 05476 if (Act == AC_FAIL) 05477 return FALSE; 05478 05479 // Move the control point if required and it is possible 05480 // If this is a single-segment closed curve, in which case we'll never 05481 // be able to calculate sensible points. Just clear the rotate bits 05482 if (!DontMoveOnCusp && !((Verbs[Index] == PT_MOVETO) && (Verbs[Index+1] == PT_BEZIERTO) && 05483 (Verbs[Index+3] & PT_CLOSEFIGURE) && (Coords[Index] == Coords[Index+3]))) 05484 { 05485 Coords[NextControl] = DocCoord::OneThird(Coords[NextControl-1], Coords[NextControl+2]); 05486 } 05487 Flags[NextControl].IsSmooth = FALSE; 05488 Flags[NextControl].IsRotate = FALSE; 05489 } 05490 05491 return TRUE; 05492 }
|
|
Makes the specified endpoint in the path a smooth join. Has to move the control points around the endpoint.
Definition at line 5510 of file pathedit.cpp. 05511 { 05512 // Parameter checks 05513 ERROR2IF(pPath == NULL, FALSE, "Path pointer was NULL"); 05514 ERROR2IF(Index < 0, FALSE, "Path index was negative"); 05515 ERROR2IF(Index >= pPath->InkPath.GetNumCoords(), FALSE, "Path index off end of path"); 05516 05517 // Store the current state of the endpoint for undo then make it smooth 05518 ModifyElementAction* UnAction = NULL; 05519 PathFlags* Flags = NULL; 05520 PathVerb* Verbs = NULL; 05521 DocCoord* Coords = NULL; 05522 pPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 05523 ERROR2IF((Verbs==NULL) || (Coords==NULL) || (Flags==NULL), FALSE, "Path array pointer was NULL (panic!)"); 05524 ActionCode Act = ModifyElementAction::Init(this, &UndoActions, Verbs[Index], Flags[Index], 05525 Coords[Index], Index, pPath, (Action**)&UnAction); 05526 if (Act == AC_FAIL) 05527 return FALSE; 05528 Flags[Index].IsSmooth = TRUE; 05529 Flags[Index].IsRotate = TRUE; 05530 05531 // Modify the previous control point (if there is one) 05532 INT32 PrevControl = pPath->InkPath.FindPrevControlPoint(Index); 05533 if (PrevControl != -1) 05534 { 05535 Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl], Flags[PrevControl], 05536 Coords[PrevControl], PrevControl, pPath, (Action**)&UnAction); 05537 if (Act == AC_FAIL) 05538 return FALSE; 05539 Flags[PrevControl].IsSmooth = TRUE; 05540 Flags[PrevControl].IsRotate = TRUE; 05541 Coords[PrevControl] = pPath->InkPath.SmoothControlPoint(PrevControl); 05542 05543 // if PrevControl+1 != Index we must be smoothing the joined ends 05544 // of a closed subpath, so we'll have to set the smoothing bits on this point too 05545 if (Index != PrevControl+1) 05546 { 05547 Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl+1], Flags[PrevControl+1], 05548 Coords[PrevControl+1], PrevControl+1, pPath, (Action**)&UnAction); 05549 if (Act == AC_FAIL) 05550 return FALSE; 05551 Flags[PrevControl+1].IsSmooth = TRUE; 05552 Flags[PrevControl+1].IsRotate = TRUE; 05553 } 05554 } 05555 05556 // Modify the next control point (if there is one) 05557 INT32 NextControl = pPath->InkPath.FindNextControlPoint(Index); 05558 if (NextControl != -1) 05559 { 05560 Act = ModifyElementAction::Init(this, &UndoActions, Verbs[NextControl], Flags[NextControl], 05561 Coords[NextControl], NextControl, pPath, (Action**)&UnAction); 05562 if (Act == AC_FAIL) 05563 return FALSE; 05564 Flags[NextControl].IsSmooth = TRUE; 05565 Flags[NextControl].IsRotate = TRUE; 05566 Coords[NextControl] = pPath->InkPath.SmoothControlPoint(NextControl); 05567 } 05568 05569 return TRUE; 05570 }
|
|
This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go.
Definition at line 5316 of file pathedit.cpp. 05317 { 05318 ERROR2IF(CurrentNode==NULL, FALSE, "Path pointer was NULL"); 05319 05320 PathFlags* Flags = NULL; 05321 PathVerb* Verbs = NULL; 05322 DocCoord* Coords = NULL; 05323 CurrentNode->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 05324 ERROR2IF((Verbs==NULL) || (Coords==NULL) || (Flags==NULL), FALSE, "Path array pointer was NULL (panic!)"); 05325 05326 INT32 NumCoords = CurrentNode->InkPath.GetNumCoords(); 05327 INT32 LowIndex = (Index == -1) ? 0 : Index; 05328 INT32 HighIndex = (Index == -1) ? NumCoords-1 : Index; 05329 05330 // Check to see if this is a single-segment closed curve, in which case we'll never 05331 // be able to smooth it. We can only be on the moveto... 05332 if ( (Verbs[0] == PT_MOVETO) && (Verbs[1] == PT_BEZIERTO) && (Verbs[3] & PT_CLOSEFIGURE) && 05333 (Coords[0] == Coords[3]) && (!Flags[0].IsRotate) ) 05334 return TRUE; 05335 05336 BOOL Success = TRUE; 05337 BOOL ChangedThisPath = FALSE; 05338 for (INT32 CurrentIndex = LowIndex; (CurrentIndex <= HighIndex) && Success; CurrentIndex++) 05339 { 05340 BOOL Test = FALSE; // TRUE if this endpoint should be toggled 05341 CurrentNode->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 05342 05343 if (HighIndex != LowIndex) 05344 { 05345 if (Flags[CurrentIndex].IsEndPoint && Flags[CurrentIndex].IsSelected) 05346 { // Force selected point to be either cusp or smooth 05347 if (AllSmooth) 05348 Test = !(Flags[CurrentIndex].IsRotate); 05349 else 05350 Test = Flags[CurrentIndex].IsRotate; 05351 } 05352 else 05353 Test = FALSE; 05354 } 05355 else 05356 { // Toggle single point 05357 Test = Flags[CurrentIndex].IsEndPoint; 05358 } 05359 05360 // Toggle the smooth state of this endpoint 05361 if (Test) 05362 { 05363 ERROR3IF(!Flags[CurrentIndex].IsEndPoint, "Attempting to toggle a control point"); 05364 05365 // Force a re-draw of the place where the path used to be 05366 if (Success && !ChangedThisPath) 05367 { 05368 Success = (RecalcBoundsAction::DoRecalc(this, &UndoActions, CurrentNode) != AC_FAIL); 05369 // // Store the paths sub-selection state 05370 // if (Success) 05371 // Success = (StorePathSubSelStateAction::DoRecord(this, &UndoActions, &CurrentNode->InkPath) != AC_FAIL); 05372 05373 ChangedThisPath = TRUE; 05374 } 05375 05376 // Now let's adjust the smoothness of this point. 05377 if (Success) 05378 { 05379 CurrentNode->InkPath.GetPathArrays(&Verbs, &Coords, &Flags); 05380 if (Flags[CurrentIndex].IsRotate) 05381 Success = MakePointCusp(CurrentNode, CurrentIndex, DontMoveOnCusp); 05382 else 05383 Success = MakePointSmooth(CurrentNode, CurrentIndex); 05384 } 05385 } 05386 } 05387 05388 // Now create a RecordBoundsAction so that the action list has bounds recalculation 05389 // at both ends which ensures undo and redo both work properly 05390 if (Success && ChangedThisPath) 05391 { 05392 CurrentNode->InvalidateBoundingRect(); 05393 GetApplication()->FindSelection()->UpdateBounds(); 05394 Success = (RecordBoundsAction::DoRecord(this, &UndoActions, CurrentNode) != AC_FAIL); 05395 } 05396 05397 return Success; 05398 }
|