00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 #include "camtypes.h"
00105 #include "opfree.h"
00106
00107
00108
00109
00110
00111
00112 #include "paper.h"
00113
00114
00115
00116 #include "csrstack.h"
00117 #include "nodepath.h"
00118
00119 #include "fitcurve.h"
00120
00121
00122 #include "freehand.h"
00123 #include "pen.h"
00124 #include "progress.h"
00125
00126 #include "blobs.h"
00127 #include "pathedit.h"
00128
00129 #include "keypress.h"
00130
00131 #include "objchge.h"
00132 #include "bubbleid.h"
00133
00134 #include "lineattr.h"
00135 #include "pathtrap.h"
00136 #include "ppstroke.h"
00137 #include "pressure.h"
00138 #include "strkattr.h"
00139 #include "valfunc.h"
00140 #include "nodeblnd.h"
00141 #include "blndtool.h"
00142 #include "ndbldpth.h"
00143 #include "nodebldr.h"
00144 #include "opdrbrsh.h"
00145 #include "ophist.h"
00146 #include "brshattr.h"
00147
00148
00149 DECLARE_SOURCE("$Revision: 1282 $");
00150
00151
00152 CC_IMPLEMENT_DYNCREATE( OpFreeHand, SelOperation )
00153
00154
00155 #define new CAM_DEBUG_NEW
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 OpFreeHand::OpFreeHand()
00169 {
00170
00171 pFreeHandCursor = NULL;
00172 pJoinCursor = NULL;
00173 pStraightCursor = NULL;
00174 pRubOutCursor = NULL;
00175 pModifyCursor = NULL;
00176
00177
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
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 }
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 void OpFreeHand::DoDrag(DocCoord Anchor, Spread *pSpread, INT32 Smooth,
00222 FreeHandJoinInfo* pFreeHandInfo, Path* ToolPath)
00223 {
00224 TRACEUSER( "Diccon", _T("Do Drag Free, StartPos = %d, %d\n"), Anchor.x, Anchor.y);
00225
00226
00227
00228 #ifdef VECTOR_STROKING
00229
00230 CCPen *pPen = GetApplication()->GetPressurePen();
00231 if (pPen != NULL)
00232 pPen->StartStroke();
00233 #endif // VECTOR_STROKING
00234
00235
00236 if ((pFreeHandInfo==NULL) || (pFreeHandInfo->pJoinPath==NULL))
00237 DocView::SnapCurrent(pSpread, &Anchor, FALSE, TRUE);
00238
00239
00240 TrackData = ToolPath;
00241 Smoothness = Smooth;
00242 pJoinInfo = pFreeHandInfo;
00243 StartPath = pJoinInfo->pJoinPath;
00244 EndPath = NULL;
00245
00246
00247 StartPoint = Anchor;
00248 StartSpread = pSpread;
00249 PreviousSpread= pSpread;
00250 PreviousPoint = Anchor;
00251 LineSegmentCount = 0;
00252 IsStraightLineMode = FALSE;
00253 CanLineJoin = FALSE;
00254
00255
00256 if (!PrepareTrackDataPath())
00257 {
00258
00259 InformError(_R(IDS_OUT_OF_MEMORY), _R(IDS_OK));
00260 FailAndExecute();
00261 End();
00262 return;
00263 }
00264
00265
00266 if (!LoadCursors())
00267 {
00268
00269 FailAndExecute();
00270 End();
00271 return;
00272 }
00273
00274
00275 CurrentCursorID = CursorStack::GPush(pFreeHandCursor, TRUE);
00276 MyCurrentCursor = pFreeHandCursor;
00277
00278
00279 StartDrag( DRAGTYPE_NOSCROLL );
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 BOOL OpFreeHand::PrepareTrackDataPath()
00300 {
00301 TrackData->ClearPath();
00302 TrackData->FindStartOfPath();
00303
00304
00305 AddPressureToPath = FALSE;
00306
00307
00308
00309
00310 #ifdef VECTOR_STROKING
00311
00312 CCPen *pPen = GetApplication()->GetPressurePen();
00313 if (IsBrushOp() && pPen != NULL && pPen->GetPressureMode() != PressureMode_None)
00314 {
00315
00316 AddPressureToPath = TRUE;
00317
00318
00319 FreeHandPressure = pPen->GetPenPressure();
00320
00321
00322 if (!TrackData->InitExtraInfo(CI_PRESSURE))
00323 return FALSE;
00324 }
00325
00326 #endif // VECTOR_STROKING
00327
00328
00329 if (!TrackData->InsertMoveTo(StartPoint))
00330 return FALSE;
00331
00332
00333 if (AddPressureToPath)
00334 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure);
00335
00336
00337 return TRUE;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 BOOL OpFreeHand::LoadCursors()
00353 {
00354
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
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
00380 delete pFreeHandCursor;
00381 delete pJoinCursor;
00382 delete pStraightCursor;
00383 delete pRubOutCursor;
00384 delete pModifyCursor;
00385
00386
00387 pFreeHandCursor = NULL;
00388 pJoinCursor = NULL;
00389 pStraightCursor = NULL;
00390 pRubOutCursor = NULL;
00391 pModifyCursor = NULL;
00392
00393
00394 return FALSE;
00395 }
00396
00397
00398 return TRUE;
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 void OpFreeHand::RemoveCursors()
00415 {
00416
00417 CursorStack::GPop(CurrentCursorID);
00418 MyCurrentCursor = NULL;
00419 CurrentCursorID = 0;
00420
00421
00422 delete pFreeHandCursor;
00423 delete pJoinCursor;
00424 delete pRubOutCursor;
00425 delete pStraightCursor;
00426 delete pModifyCursor;
00427
00428
00429 pFreeHandCursor = NULL;
00430 pJoinCursor = NULL;
00431 pStraightCursor = NULL;
00432 pRubOutCursor = NULL;
00433 pModifyCursor = NULL;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 void OpFreeHand::SetCursorOnMove(ClickModifiers ClickMods, Spread* pSpread, DocCoord* PointerPos)
00455 {
00456
00457 if (CheckMouseOverSelectedPath(PointerPos, pSpread, &IsEndNearEndpoint))
00458 {
00459
00460 if (IsEndNearEndpoint)
00461 {
00462
00463 SetCursorAndStatus(JOIN_CURSOR);
00464 return;
00465 }
00466
00467
00468
00469 if ((StartPath==EndPath) && (pJoinInfo->IsNearEndPoint==FALSE))
00470 {
00471 SetCursorAndStatus(MODIFY_CURSOR);
00472 return;
00473 }
00474 }
00475
00476
00477 if (ClickMods.Alternative1)
00478 {
00479
00480 SetCursorAndStatus(STRAIGHTLINE_CURSOR);
00481 }
00482 else
00483 {
00484 if (ClickMods.Adjust)
00485 {
00486
00487 SetCursorAndStatus(RUBOUT_CURSOR);
00488 }
00489 else
00490 {
00491
00492 SetCursorAndStatus(NORMAL_CURSOR);
00493 }
00494 }
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 void OpFreeHand::DragPointerMove( DocCoord PointerPos, ClickModifiers ClickMods,
00515 Spread *pSpread, BOOL bSolidDrag)
00516 {
00517
00518 DocView* pView = DocView::GetSelected();
00519
00520
00521 if (AddPressureToPath)
00522 FreeHandPressure = ClickMods.Pressure;
00523
00524
00525
00526 if (pSpread != StartSpread)
00527 PointerPos = MakeRelativeToSpread(StartSpread, pSpread, PointerPos);
00528
00529
00530 SetCursorOnMove(ClickMods, StartSpread, &PointerPos);
00531
00532
00533 if (ClickMods.Alternative1)
00534 {
00535
00536 DocView::SnapCurrent(pSpread, &PointerPos);
00537 if (ClickMods.Constrain)
00538 DocView::ConstrainToAngle(PreviousPoint, &PointerPos);
00539
00540
00541 if (IsStraightLineMode)
00542 RenderEorStraightLine(NULL, pSpread);
00543 else
00544 {
00545
00546
00547 if (pView!=NULL)
00548 pView->ChangeDragType(DRAGTYPE_AUTOSCROLL);
00549 }
00550
00551
00552 StraightLinePos = PointerPos;
00553 RenderEorStraightLine(NULL, pSpread);
00554
00555
00556 IsStraightLineMode = TRUE;
00557 }
00558 else
00559 {
00560
00561 if (IsStraightLineMode)
00562 {
00563
00564
00565 AddStraightLine();
00566 PreviousPoint = StraightLinePos;
00567
00568
00569 if (pView!=NULL)
00570 pView->ChangeDragType(DRAGTYPE_NOSCROLL);
00571
00572
00573 IsStraightLineMode = FALSE;
00574 }
00575 else
00576 {
00577
00578 if (ClickMods.Adjust)
00579 RubOutPath(PointerPos, StartSpread);
00580 else
00581 AddPointsToPath(PointerPos, StartSpread);
00582 }
00583 }
00584
00585
00586 PreviousSpread = pSpread;
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 void OpFreeHand::DragPointerIdle(DocCoord PointerPos, ClickModifiers ClickMods, Spread* pSpread, BOOL bSolidDrag)
00611 {
00612
00613
00614 if (IsStraightLineMode && !ClickMods.Alternative1)
00615 {
00616
00617 AddStraightLine();
00618 PreviousPoint = StraightLinePos;
00619
00620
00621 IsStraightLineMode = FALSE;
00622 }
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647 void OpFreeHand::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods,
00648 Spread *pSpread, BOOL Success, BOOL bSolidDrag)
00649 {
00650
00651 DocRect ClipRect(0,0,0,0);
00652 RenderDragBlobs(ClipRect, StartSpread, bSolidDrag);
00653
00654
00655 RemoveCursors();
00656
00657
00658 BeginSlowJob();
00659 EndDrag();
00660
00661
00662 BOOL Worked = FALSE;
00663 if (Success)
00664 {
00665
00666 if (IsStraightLineMode)
00667 {
00668
00669 AddStraightLine();
00670 PreviousPoint = StraightLinePos;
00671 IsStraightLineMode = FALSE;
00672 }
00673
00674
00675 Worked = CompleteOperation();
00676
00677
00678
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
00694
00695
00696 #ifdef VECTOR_STROKING
00697
00698 CCPen *pPen = GetApplication()->GetPressurePen();
00699 if (pPen != NULL)
00700 pPen->EndStroke();
00701 #endif // VECTOR_STROKING
00702
00703
00704
00705
00706 if (Worked==FALSE)
00707 FailAndExecute();
00708 else
00709 {
00710
00711 ObjChangeFlags cFlags;
00712 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
00713 ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
00714 UpdateChangedNodes(&ObjChange);
00715 }
00716
00717 End();
00718 }
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 BOOL OpFreeHand::DragKeyPress(KeyPress* pKeyPress, BOOL bSolidDrag)
00736 {
00737
00738
00739
00740
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
00750 if (pKeyPress->IsConstrain() || pKeyPress->IsAdjust() || pKeyPress->IsAlternative() || pKeyPress->IsRelease())
00751 {
00752
00753 ClickMods.Constrain = pKeyPress->IsConstrainPressed();
00754 ClickMods.Adjust = pKeyPress->IsAdjustPressed();
00755 ClickMods.Alternative1 = pKeyPress->IsAlternativePressed();
00756
00757
00758 DragPointerMove(PreviousPoint, ClickMods, PreviousSpread, FALSE);
00759
00760
00761 return TRUE;
00762 }
00763
00764
00765 return FALSE;
00766 }
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783 BOOL OpFreeHand::CompleteOperation()
00784 {
00785
00786 NodePath* pNewNodePath = NULL;
00787 if (!CreateNewPath(&pNewNodePath))
00788 return FALSE;
00789
00790 if (!SmoothNewCurve(pNewNodePath))
00791 {
00792
00793 delete pNewNodePath;
00794 return FALSE;
00795 }
00796
00797 if (!InsertSmoothCurveWithUndo(pNewNodePath))
00798 {
00799
00800 pNewNodePath->CascadeDelete();
00801 delete pNewNodePath;
00802 return FALSE;
00803 }
00804
00805
00806 SelRange* Selection = GetApplication()->Selection;
00807 if (Selection)
00808 Selection->Update();
00809
00810
00811
00812 return TRUE;
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831 BOOL OpFreeHand::CreateNewPath(NodePath** pNewPath)
00832 {
00833
00834 NodePath*& pFreeHandPath = *pNewPath;
00835 pFreeHandPath = NULL;
00836
00837
00838 if (LineSegmentCount==0)
00839 return FALSE;
00840
00841
00842 DocCoord* Coords = TrackData->GetCoordArray();
00843 INT32 NumCoords = TrackData->GetNumCoords();
00844 BOOL IsAllSame = TRUE;
00845
00846
00847 for (INT32 i=0; (i<NumCoords) && (IsAllSame); i++)
00848 {
00849
00850 if (Coords[0] != Coords[i])
00851 IsAllSame = FALSE;
00852 }
00853
00854
00855 if (IsAllSame)
00856 return FALSE;
00857
00858
00859 pFreeHandPath = new NodePath;
00860 if (pFreeHandPath==NULL)
00861 return FALSE;
00862
00863
00864 if (!pFreeHandPath->SetUpPath(24, 12))
00865 {
00866
00867 delete pFreeHandPath;
00868 pFreeHandPath = NULL;
00869 return FALSE;
00870 }
00871
00872
00873 return TRUE;
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891 BOOL OpFreeHand::SmoothNewCurve(NodePath* pNewNodePath)
00892 {
00893
00894
00895 DocView* pDocView = DocView::GetSelected();
00896 if (pDocView==NULL)
00897 return FALSE;
00898
00899
00900
00901
00902 if ((StartPath!=NULL) && (StartPath==EndPath) && (pJoinInfo->IsNearEndPoint==FALSE))
00903 {
00904
00905 PreviousPoint = EndPath->InkPath.ClosestPointTo(Mu, CloseTo);
00906
00907
00908 if (TrackData->InsertLineTo(PreviousPoint))
00909 {
00910
00911 if (AddPressureToPath)
00912 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure);
00913 }
00914 }
00915
00916
00917
00918
00919
00920 double ScaleFactor = (pDocView->GetViewScale()).MakeDouble();
00921 double ErrorLevel = (64 + (160*Smoothness)) / ScaleFactor;
00922 ErrorLevel = ErrorLevel * ErrorLevel;
00923
00924
00925
00926 CurveFitObject CurveFitter(&(pNewNodePath->InkPath), ErrorLevel);
00927
00928
00929 if (!CurveFitter.Initialise(TrackData, LineSegmentCount+1))
00930 return FALSE;
00931
00932
00933 CurveFitter.FitCurve();
00934 return TRUE;
00935 }
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 BOOL OpFreeHand::InsertSmoothCurveWithUndo(NodePath* pNewNodePath)
00955 {
00956
00957
00958
00959 if (!DoStartSelOp(FALSE))
00960 return FALSE;
00961
00962
00963
00964 if ((StartPath!=NULL) && (StartPath==EndPath) &&
00965 (pJoinInfo->IsNearEndPoint==FALSE) && (IsEndNearEndpoint==FALSE))
00966 {
00967
00968
00969 if (!TryToReplaceSection(pNewNodePath))
00970 return FALSE;
00971 }
00972 else
00973 {
00974
00975 if (pJoinInfo->IsNearEndPoint==FALSE)
00976 StartPath = NULL;
00977
00978
00979
00980 if (!TryToJoinNewPathWithOthers(pNewNodePath))
00981 return FALSE;
00982 }
00983
00984
00985 pNewNodePath->CascadeDelete();
00986 delete pNewNodePath;
00987
00988
00989 return TRUE;
00990 }
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006 void OpFreeHand::RubOutPath(DocCoord Pos, Spread* pSpread)
01007 {
01008
01009 if (Pos==PreviousPoint)
01010 return;
01011
01012
01013 BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
01014 if (pBlobMgr==NULL)
01015 return;
01016
01017
01018 INT32 NumCoords = TrackData->GetNumCoords();
01019 DocCoord* Coords = TrackData->GetCoordArray();
01020
01021
01022
01023
01024
01025 DocRect BlobRect;
01026 pBlobMgr->GetBlobRect(Pos, &BlobRect);
01027
01028
01029 INT32 StopLookingAt = 1;
01030
01031
01032 for (INT32 i=NumCoords-2; i>StopLookingAt; i--)
01033 {
01034 if (BlobRect.ContainsCoord(Coords[i]))
01035 {
01036
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
01044 pRegion = DocView::GetNextOnTop( NULL );
01045 }
01046
01047
01048 if (!TrackData->DeleteFromElement(i+1))
01049 {
01050 InformError(_R(IDS_PATH_DELETE_ERROR));
01051 return;
01052 }
01053
01054
01055 PreviousPoint = Coords[i];
01056 LineSegmentCount = i;
01057
01058
01059 return;
01060 }
01061 }
01062 }
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079 void OpFreeHand::AddPointsToPath(DocCoord PointerPos, Spread* pSpread)
01080 {
01081
01082 if (PreviousPoint == PointerPos)
01083 return;
01084
01085
01086 if (TrackData->InsertLineTo(PointerPos))
01087 {
01088
01089 if (AddPressureToPath)
01090 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure);
01091 }
01092 else
01093 {
01094
01095
01096 EndDrag();
01097
01098
01099 InformError();
01100
01101
01102 TrackData->ClearPath();
01103
01104
01105 FailAndExecute();
01106 End();
01107 return;
01108 }
01109
01110
01111 RenderLine(NULL, pSpread, TrackData, TrackData->GetNumCoords()-1);
01112
01113
01114 PreviousPoint = PointerPos;
01115 LineSegmentCount++;
01116 CanLineJoin = TRUE;
01117 }
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132 void OpFreeHand::AddStraightLine()
01133 {
01134 PathFlags Flags;
01135 Flags.Spare1 = TRUE;
01136
01137
01138 if (PreviousPoint == StraightLinePos)
01139 return;
01140
01141
01142 if (TrackData->InsertLineTo(StraightLinePos, &Flags))
01143 {
01144
01145 if (AddPressureToPath)
01146 TrackData->AddExtraInfo(CI_PRESSURE, FreeHandPressure);
01147 }
01148 else
01149 {
01150
01151
01152 EndDrag();
01153
01154
01155 InformError();
01156
01157
01158 TrackData->ClearPath();
01159
01160
01161 FailAndExecute();
01162 End();
01163 return;
01164 }
01165
01166
01167 LineSegmentCount++;
01168 CanLineJoin = TRUE;
01169 }
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191 BOOL OpFreeHand::CheckMouseOverSelectedPath(DocCoord* PointerPos, Spread* pSpread, BOOL* IsNearEndpoint)
01192 {
01193
01194 EndPath = NULL;
01195
01196
01197 BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
01198 if (pBlobMgr==NULL)
01199 return FALSE;
01200
01201
01202 DocRect BlobRect;
01203 pBlobMgr->GetBlobRect(*PointerPos, &BlobRect);
01204
01205
01206 SelRange* Selected = GetApplication()->FindSelection();
01207 Node* pNode = Selected->FindFirst();
01208
01209
01210 if (pNode!=NULL)
01211 {
01212
01213 Spread* pNodeSpread = pNode->FindParentSpread();
01214 if (pNodeSpread!=pSpread)
01215 return FALSE;
01216 }
01217
01218
01219 while (pNode!=NULL)
01220 {
01221 if (pNode->IsNodePath())
01222 {
01223
01224
01225 Path* ThisPath = &(((NodePath*)pNode)->InkPath);
01226
01227
01228 INT32 CloseSlot = 0;
01229 if (ThisPath->IsNearOpenEnd(BlobRect, &CloseSlot))
01230 {
01231
01232 ThisPath->SetPathPosition(CloseSlot);
01233 *PointerPos = ThisPath->GetCoord();
01234 *IsNearEndpoint = TRUE;
01235 EndPath = (NodePath*)pNode;
01236 return TRUE;
01237 }
01238
01239
01240
01241
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
01248
01249 if (AreSlotsInSameSubPath(CloseTo, pJoinInfo->CloseSlot, ThisPath))
01250 {
01251
01252 *IsNearEndpoint = FALSE;
01253 EndPath = (NodePath*)pNode;
01254 return TRUE;
01255 }
01256 }
01257 }
01258 }
01259
01260
01261 pNode = Selected->FindNext(pNode);
01262 }
01263
01264
01265 if ((BlobRect.ContainsCoord(StartPoint)) && (StartPath==NULL))
01266 {
01267
01268
01269 *PointerPos = StartPoint;
01270
01271
01272 if (CanLineJoin==TRUE)
01273 {
01274 *IsNearEndpoint = TRUE;
01275 return TRUE;
01276 }
01277 }
01278
01279
01280 return FALSE;
01281 }
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304 BOOL OpFreeHand::AreSlotsInSameSubPath(INT32 Slot1, INT32 Slot2, Path* pPath)
01305 {
01306
01307 ERROR2IF(pPath==NULL, FALSE, "NULL pointer passed to OpFreeHand::AreSlotsInSameSubPath");
01308
01309
01310 PathVerb* pVerbs = pPath->GetVerbArray();
01311 INT32 NumSlots = pPath->GetNumCoords();
01312
01313
01314 INT32 First = Slot1<Slot2 ? Slot1 : Slot2;
01315 INT32 Last = Slot1<Slot2 ? Slot2 : Slot1;
01316
01317
01318 ERROR2IF(Last>NumSlots, FALSE, "Bad Slot numbers in OpFreeHand::AreSlotsInSameSubPath");
01319
01320
01321 while (Last>First)
01322 {
01323
01324 if (pVerbs[Last]==PT_MOVETO)
01325 return FALSE;
01326
01327
01328 Last--;
01329 }
01330
01331
01332 return TRUE;
01333 }
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349 void OpFreeHand::SetCursorAndStatus(CursorType CurType)
01350 {
01351
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
01387 GetApplication()->UpdateStatusBarText(&StatusMsg);
01388 if (WhichCursor != MyCurrentCursor)
01389 {
01390
01391 CursorStack::GSetTop(WhichCursor, CurrentCursorID);
01392
01393
01394 MyCurrentCursor = WhichCursor;
01395 }
01396 }
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411 BOOL OpFreeHand::TryToJoinNewPathWithOthers(NodePath* FreePath)
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
01421
01422
01423
01424
01425 ObjChange.Define(OBJCHANGE_STARTING,cFlagsDelete,EndPath,this);
01426 if (!EndPath->AllowOp(&ObjChange))
01427 return TRUE;
01428
01429
01430 ObjChange.Define(OBJCHANGE_STARTING,cFlagsReplace,StartPath,this);
01431 if (!StartPath->AllowOp(&ObjChange))
01432 return TRUE;
01433 }
01434 else if (StartPath != NULL || EndPath != NULL)
01435 {
01436
01437
01438
01439 ObjChange.Define(OBJCHANGE_STARTING,cFlagsChanging,StartPath,this);
01440
01441
01442 if (StartPath != NULL && !StartPath->AllowOp(&ObjChange))
01443 return TRUE;
01444
01445
01446 if (StartPath == NULL && !EndPath->AllowOp(&ObjChange))
01447 return TRUE;
01448 }
01449
01450 if (StartPath == NULL)
01451 {
01452 if (EndPath == NULL)
01453 {
01454
01455 NodePath* JoinPath = MakeCopy(FreePath);
01456 if (JoinPath == NULL)
01457 return FALSE;
01458
01459
01460 JoinPath->InkPath.TryToClose();
01461
01462
01463 if (!ApplyAttributes(JoinPath, GetWorkingDoc()))
01464 return FALSE;
01465
01466
01467 if (!AddPressureAttribute(JoinPath))
01468 return(FALSE);
01469
01470
01471 if (!DoInsertNewNode(JoinPath, StartSpread, FALSE))
01472 return FALSE;
01473
01474 if (!DoInvalidateNodeRegion(JoinPath, TRUE))
01475 return FALSE;
01476
01477 m_pNewNodePath = JoinPath;
01478
01479 SetRetroPath(JoinPath, 0, JoinPath->InkPath.GetNumCoords());
01480 }
01481 else
01482 {
01483 if (EndPath->InkPath.IsComplexPath())
01484 {
01485
01486 if (!ComplexJoin(FreePath, EndPath))
01487 return FALSE;
01488 }
01489 else
01490 {
01491
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
01504 if (!ComplexJoin(FreePath, StartPath))
01505 return FALSE;
01506 }
01507 else
01508 {
01509
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
01521 if (!ComplexToComplexJoin(FreePath, StartPath))
01522 return FALSE;
01523 }
01524 else
01525 {
01526
01527 if (!SimpleJoin(FreePath, StartPath))
01528 return FALSE;
01529 }
01530 }
01531 else
01532 {
01533
01534
01535
01536
01537 if (!VeryComplexToComplexJoin(FreePath, StartPath, EndPath))
01538 return FALSE;
01539 }
01540 }
01541 }
01542
01543
01544 return TRUE;
01545 }
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563 BOOL OpFreeHand::SimpleJoin(NodePath* FreePath, NodePath* OldPath)
01564 {
01565
01566 DocRect InvalidRect = FreePath->GetBlobBoundingRect();
01567
01568 DocRect OriginalRect = OldPath->GetBoundingRect();
01569
01570
01571 InvalidateBrushRegion(OldPath);
01572
01573
01574
01575 INT32 NumSlots = FreePath->InkPath.GetNumCoords();
01576 INT32 StartSlot = 0;
01577
01578
01579
01580
01581
01582
01583 NodePath* JoinPath = MakeCopy(OldPath);
01584 if (JoinPath == NULL)
01585 return FALSE;
01586
01587
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
01599 BOOL PathReversed = FALSE;
01600
01601
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
01611 if (!InsertNewNode(JoinPath, InvalidRect, OldPath))
01612 return FALSE;
01613
01614
01615 if (NewPathReversed)
01616 TrackData->Reverse();
01617
01618
01619 if (Handle != BrushHandle_NoBrush && PathReversed)
01620 {
01621 TrackData->Reverse();
01622 JoinPath->InkPath.Reverse();
01623 StartSlot = 0;
01624 }
01625
01626
01627 SetRetroPath(JoinPath, StartSlot, NumSlots);
01628
01629 m_pNewNodePath = JoinPath;
01630
01631 InvalidateBrushRegion(JoinPath);
01632
01633
01634 return TRUE;
01635 }
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653 BOOL OpFreeHand::ComplexJoin(NodePath* FreePath, NodePath* OldPath)
01654 {
01655
01656 DocRect InvalidRect = FreePath->GetBlobBoundingRect();
01657
01658
01659 INT32 NumSlots = FreePath->InkPath.GetNumCoords();
01660 INT32 StartSlot;
01661
01662
01663 NodePath* JoinPath = MakeCopy(OldPath);
01664 if (JoinPath == NULL)
01665 return FALSE;
01666
01667
01668 BOOL NewPathReversed = FALSE;
01669 if (!JoinPath->InkPath.ComplexJoin(&FreePath->InkPath, &StartSlot, &NewPathReversed))
01670 return FALSE;
01671
01672
01673 if (!InsertNewNode(JoinPath, InvalidRect, OldPath))
01674 return FALSE;
01675
01676
01677 if (NewPathReversed)
01678 TrackData->Reverse();
01679
01680
01681 SetRetroPath(JoinPath, StartSlot, NumSlots);
01682
01683 m_pNewNodePath = JoinPath;
01684
01685 return TRUE;
01686 }
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705 BOOL OpFreeHand::ComplexToComplexJoin(NodePath* FreePath, NodePath* OldPath)
01706 {
01707
01708 DocRect InvalidRect = FreePath->GetBlobBoundingRect();
01709
01710
01711 INT32 NumSlots = FreePath->InkPath.GetNumCoords();
01712 INT32 StartSlot;
01713
01714
01715 NodePath* JoinPath = MakeCopy(OldPath);
01716 if (JoinPath==NULL)
01717 return FALSE;
01718
01719
01720 BOOL NewPathReversed = FALSE;
01721 if (!JoinPath->InkPath.ComplexToSameComplexJoin(&FreePath->InkPath, &StartSlot, &NewPathReversed))
01722 return FALSE;
01723
01724
01725 if (!InsertNewNode(JoinPath, InvalidRect, OldPath))
01726 return FALSE;
01727
01728
01729 if (NewPathReversed)
01730 TrackData->Reverse();
01731
01732
01733 SetRetroPath(JoinPath, StartSlot, NumSlots);
01734
01735
01736 return TRUE;
01737 }
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758 BOOL OpFreeHand::VeryComplexToComplexJoin(NodePath* FreePath, NodePath* TopPath, NodePath* BotPath)
01759 {
01760
01761 DocRect InvalidRect = FreePath->GetBlobBoundingRect();
01762
01763
01764 INT32 NumSlots = FreePath->InkPath.GetNumCoords();
01765 INT32 StartSlot;
01766
01767
01768 NodePath* JoinPath = MakeCopy(TopPath);
01769 if (JoinPath==NULL)
01770 return FALSE;
01771
01772
01773 if (!JoinPath->InkPath.MergeTwoPaths(BotPath->InkPath))
01774 return FALSE;
01775
01776
01777 BOOL NewPathReversed = FALSE;
01778 if (!JoinPath->InkPath.ComplexToSameComplexJoin(&FreePath->InkPath, &StartSlot, &NewPathReversed))
01779 return FALSE;
01780
01781
01782 if (!InsertNewNode(JoinPath, InvalidRect, TopPath, BotPath))
01783 return FALSE;
01784
01785
01786 if (NewPathReversed)
01787 TrackData->Reverse();
01788
01789
01790 SetRetroPath(JoinPath, StartSlot, NumSlots);
01791
01792
01793 return TRUE;
01794 }
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812 BOOL OpFreeHand::ApplyAttributes(NodePath* NewPath, Document *pDocument)
01813 {
01814
01815 ENSURE(pDocument!=NULL, "Null Document while setting attributes for new NodePath");
01816 if (pDocument!=NULL)
01817 {
01818
01819 if (pDocument->GetAttributeMgr().ApplyCurrentAttribsToNode((NodeRenderableInk*)NewPath))
01820 {
01821
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
01834 return FALSE;
01835 }
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858 BOOL OpFreeHand::AddPressureAttribute(NodePath *pNewPath)
01859 {
01860 if (IsBrushOp())
01861 return TRUE;
01862
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
01870 if (TrackData == NULL || !AddPressureToPath)
01871 return(TRUE);
01872
01873
01874
01875 PressureSmoother Bob;
01876 ValueFunction *pValFunc = Bob.Smooth(TrackData, GetCurrentLineWidth());
01877 if (pValFunc == NULL)
01878 return(TRUE);
01879
01880
01881
01882 BOOL ApplyType = FALSE;
01883
01884
01885 {
01886 Node *pNode = pNewPath->FindFirstChild();
01887 if (pNode != NULL)
01888 pNode = pNode->FindNext(CC_RUNTIME_CLASS(AttrStrokeType));
01889
01890 ApplyType = (pNode == NULL);
01891 if (!ApplyType)
01892 {
01893
01894
01895 StrokeTypeAttrValue *pSAV = (StrokeTypeAttrValue *) ((AttrStrokeType *)pNode)->GetAttributeValue();
01896 if (pSAV->GetPathProcessor() == NULL)
01897 ApplyType = TRUE;
01898 }
01899 }
01900
01901
01902 AttrStrokeType *pStrokeType = NULL;
01903 if (ApplyType)
01904 {
01905 pStrokeType = new AttrStrokeType;
01906 if (pStrokeType == NULL)
01907 return(TRUE);
01908
01909 PathProcessorStroke *pProcessor = new PathProcessorStroke;
01910 if (pProcessor == NULL)
01911 {
01912 delete pStrokeType;
01913 return(TRUE);
01914 }
01915
01916
01917 ((StrokeTypeAttrValue *)pStrokeType->GetAttributeValue())->SetPathProcessor(pProcessor);
01918 }
01919
01920
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);
01930 }
01931
01932
01933
01934 if (ApplyType)
01935 {
01936 DoRemoveAttrTypeFromSubtree(pNewPath, pStrokeType->GetRuntimeClass());
01937 pStrokeType->AttachNode(pNewPath, FIRSTCHILD, FALSE, FALSE);
01938 }
01939
01940
01941 DoRemoveAttrTypeFromSubtree(pNewPath, pVarWidth->GetRuntimeClass());
01942 pVarWidth->AttachNode(pNewPath, FIRSTCHILD, FALSE, FALSE);
01943
01944 #endif // VECTOR_STROKING
01945
01946 return(TRUE);
01947 }
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964 NodePath* OpFreeHand::MakeCopy(Node* pOriginalNode)
01965 {
01966
01967 Node* pNode;
01968 if (!pOriginalNode->NodeCopy(&pNode))
01969 return NULL;
01970
01971
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
01976 return (NodePath*) pNode;
01977 }
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999 BOOL OpFreeHand::InsertNewNode(NodePath* pNewNode, DocRect& Invalid, Node* pOldNode, Node* pOtherOld)
02000 {
02001
02002 if (!DoInsertNewNode(pNewNode, pOldNode, NEXT, FALSE))
02003 return FALSE;
02004
02005
02006
02007 ENSURE(pOldNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)), "Joining to something that was not a path");
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019 if (!DoInvalidateNodeRegion(pNewNode, TRUE))
02020 return FALSE;
02021
02022
02023 if (!DoHideNode(pOldNode, TRUE))
02024 return FALSE;
02025
02026
02027 if (pOtherOld != NULL)
02028 if (!DoHideNode(pOtherOld, TRUE))
02029 return FALSE;
02030
02031
02032 SelRange* Selection = GetApplication()->Selection;
02033 if (Selection)
02034 Selection->Update();
02035
02036
02037 return TRUE;
02038 }
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058 void OpFreeHand::SetRetroPath(NodePath* pNodePath, INT32 Start, INT32 Len)
02059 {
02060
02061 Tool* pTool = Tool::GetCurrent();
02062 if (pTool)
02063 {
02064
02065 if (pTool->GetID()==TOOLID_FREEHAND)
02066 ((FreeHandTool*)pTool)->SetPreviousPath(pNodePath, Start, Len);
02067 }
02068 }
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092 void OpFreeHand::RenderLine(RenderRegion *pRender, Path *pPath, INT32 Index, BOOL StartIndex)
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
02110 pRender->SetLineColour(COLOUR_XORNEW);
02111 pRender->DrawLine(Coord[Index], Coord[EndIndex]);
02112
02113
02114 #ifdef VECTOR_STROKING
02115
02116
02117
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)
02131 StartWidth = CurrentLineWidth;
02132 if (EndWidth > CurrentLineWidth)
02133 EndWidth = CurrentLineWidth;
02134
02135 if (Coord[Index-1] != Coord[Index] && (StartWidth + EndWidth) > pRender->GetPixelWidth() * 8)
02136 {
02137 pRender->SetLineColour(COLOUR_MIDGREY);
02138
02139
02140 NormCoord Normal( Coord[Index-1].y - Coord[Index].y, -(Coord[Index-1].x - Coord[Index].x));
02141 Normal.Normalise();
02142
02143
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 }
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175
02176
02177 void OpFreeHand::RenderLine(DocRect* Rect, Spread* pSpread, Path *pPath, INT32 Index, BOOL StartIndex)
02178 {
02179 RenderRegion* pRegion = DocView::RenderOnTop(Rect, pSpread, UnclippedEOR );
02180 while ( pRegion )
02181 {
02182 RenderLine(pRegion, pPath, Index, StartIndex);
02183
02184
02185 pRegion = DocView::GetNextOnTop(Rect);
02186 }
02187 }
02188
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198
02199
02200
02201
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211
02212 void OpFreeHand::RenderEorStraightLine(RenderRegion *pRender,
02213 DocCoord *pStart, INT32 StartWidth,
02214 DocCoord *pEnd, INT32 EndWidth)
02215 {
02216 ERROR3IF(pRender == NULL || pStart == NULL || pEnd == NULL, "illegal NUL params");
02217
02218
02219 pRender->SetLineColour(COLOUR_XORNEW);
02220 pRender->DrawLine(*pStart, *pEnd);
02221
02222
02223 #ifdef VECTOR_STROKING
02224
02225
02226
02227 if (AddPressureToPath && *pStart != *pEnd && (StartWidth + EndWidth) > pRender->GetPixelWidth() * 8)
02228 {
02229 pRender->SetLineColour(COLOUR_MIDGREY);
02230
02231
02232 NormCoord Normal( pStart->y - pEnd->y, -(pStart->x - pEnd->x));
02233 Normal.Normalise();
02234
02235
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 }
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266 void OpFreeHand::RenderEorStraightLine(DocRect* Rect, Spread* pSpread, DocCoord *pStart, DocCoord *pEnd)
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
02281 pRegion = DocView::GetNextOnTop(Rect);
02282 }
02283 }
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302 INT32 OpFreeHand::GetCurrentLineWidth(void)
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 }
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332 void OpFreeHand::RenderDragBlobs( DocRect Rect, Spread* pSpread, BOOL bSolidDrag )
02333 {
02334
02335 DocRect* pRect;
02336 if (Rect.IsEmpty())
02337 pRect = NULL;
02338 else
02339 pRect = &Rect;
02340
02341
02342 INT32 NumCoords = TrackData->GetNumCoords();
02343
02344
02345
02346
02347
02348
02349 RenderRegion* pRegion = DocView::RenderOnTop(pRect, pSpread, UnclippedEOR );
02350 while ( pRegion )
02351 {
02352
02353
02354 for (INT32 n = 1; n < NumCoords; n++)
02355 RenderLine(pRegion, TrackData, n);
02356
02357
02358 pRegion = DocView::GetNextOnTop(pRect);
02359 }
02360
02361 if (IsStraightLineMode)
02362 RenderEorStraightLine(pRect, pSpread);
02363 }
02364
02365
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381 BOOL OpFreeHand::TryToReplaceSection(NodePath* pNewNodePath)
02382 {
02383
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;
02390
02391
02392 if (!DoInvalidateNodeRegion(EndPath, TRUE))
02393 return FALSE;
02394
02395
02396 if (!SplitAtPoint(StartPoint, &FirstElement, &NewElements))
02397 return FALSE;
02398
02399 if (!SplitAtPoint(PreviousPoint, &SecondElement, &NewElements))
02400 return FALSE;
02401
02402
02403
02404 if (SecondElement<=FirstElement)
02405 {
02406
02407 INT32 Temp = FirstElement + (NewElements/2);
02408 FirstElement = SecondElement;
02409 SecondElement = Temp;
02410
02411
02412
02413 pNewNodePath->InkPath.Reverse();
02414 TrackData->Reverse();
02415 ReverseBrushPressure();
02416 }
02417
02418
02419 if (!EndPath->InkPath.IsComplexPath() && EndPath->InkPath.IsFilled)
02420 {
02421
02422
02423
02424
02425
02426
02427 INT32 HalfElements = EndPath->InkPath.GetNumCoords() / 2;
02428 INT32 ReplaceElements = SecondElement - FirstElement;
02429 if (HalfElements < ReplaceElements)
02430 {
02431
02432
02433
02434
02435
02436 BOOL IsOk = FALSE;
02437 Node* pCopyNode = NULL;
02438 CALL_WITH_FAIL(EndPath->NodeCopy(&pCopyNode), this, IsOk);
02439
02440
02441 if (!IsOk)
02442 return FALSE;
02443
02444
02445 if (!DoInsertNewNode((NodeRenderableBounded*)pCopyNode, EndPath, NEXT, FALSE))
02446 return FALSE;
02447
02448
02449 if (!DoHideNode(EndPath, TRUE))
02450 return FALSE;
02451
02452
02453 EndPath = (NodePath*) pCopyNode;
02454 ERROR3IF(!EndPath->IS_KIND_OF(NodePath), "Copy of a Node path was not a node path");
02455
02456
02457 if (EndPath->InkPath.ChangeStartElement(SecondElement-1))
02458 {
02459
02460 FirstElement = 1;
02461 SecondElement = EndPath->InkPath.GetNumCoords() - ReplaceElements;
02462
02463
02464
02465 pNewNodePath->InkPath.Reverse();
02466 TrackData->Reverse();
02467 }
02468 }
02469
02470 }
02471
02472
02473 INT32 NumElements = SecondElement - FirstElement;
02474 if (!ReplaceMiddleOfPath(pNewNodePath, FirstElement, NumElements))
02475 return FALSE;
02476
02477
02478 EndPath->InvalidateBoundingRect();
02479
02480 TRACEUSER( "Diccon", _T("Replacing middle of Path\n"));
02481 InvalidateBrushRegion(EndPath);
02482
02483 if (!DoInvalidateNodeRegion(EndPath, TRUE))
02484 return FALSE;
02485
02486
02487 return TRUE;
02488 }
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508 BOOL OpFreeHand::SplitAtPoint(const DocCoord& SplitPoint, INT32* SplitAt, INT32* NewElements)
02509 {
02510
02511 INT32 SplitElement;
02512 UINT32 NumElements;
02513 PathVerb NewVerbs[6];
02514 DocCoord NewCoords[6];
02515 PathFlags NewFlags[6];
02516
02517
02518 BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
02519 if (pBlobMgr!=NULL)
02520 {
02521
02522
02523 DocRect BlobRect;
02524 DocCoord BlobPoint = SplitPoint;
02525 pBlobMgr->GetBlobRect(BlobPoint, &BlobRect);
02526
02527
02528 PathFlags* Flags = EndPath->InkPath.GetFlagArray();
02529 DocCoord* Coords = EndPath->InkPath.GetCoordArray();
02530 INT32 NumCoords = EndPath->InkPath.GetNumCoords();
02531
02532
02533 for (INT32 i=0; i<NumCoords; i++)
02534 {
02535
02536 if ((Flags[i].IsEndPoint==TRUE) && (BlobRect.ContainsCoord(Coords[i])))
02537 {
02538
02539 *SplitAt = i+1;
02540 *NewElements = 0;
02541
02542
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
02551 return TRUE;
02552 }
02553 }
02554 }
02555
02556
02557 if (EndPath->InkPath.SplitAtPoint(SplitPoint, &SplitElement, &NumElements, NewVerbs, NewCoords))
02558 {
02559
02560 *SplitAt = SplitElement+(NumElements/2);
02561 *NewElements = NumElements;
02562
02563
02564 PathVerb* Verbs = EndPath->InkPath.GetVerbArray();
02565 PathFlags* Flags = EndPath->InkPath.GetFlagArray();
02566 DocCoord* Coords = EndPath->InkPath.GetCoordArray();
02567
02568 INT32 NumToChange;
02569
02570
02571 if ((Verbs[SplitElement] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
02572 {
02573
02574 NumToChange = 6;
02575
02576
02577 for (INT32 i=0; i<6; i++)
02578 {
02579
02580 NewFlags[i] = Flags[SplitElement+(i%3)];
02581 NewFlags[i].IsSelected = FALSE;
02582
02583
02584 if ((i>0) && (i<4))
02585 {
02586 NewFlags[i].IsSmooth = FALSE;
02587 NewFlags[i].IsRotate = FALSE;
02588 }
02589 }
02590
02591
02592
02593 if (Verbs[SplitElement+2] & PT_CLOSEFIGURE)
02594 NewVerbs[5] |= PT_CLOSEFIGURE;
02595 }
02596 else
02597 {
02598
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
02605 if (Verbs[SplitElement] & PT_CLOSEFIGURE)
02606 NewVerbs[1] |= PT_CLOSEFIGURE;
02607 }
02608
02609
02610 Action* UnAction;
02611 ActionCode Act = RemovePathElementAction::Init(this, &UndoActions, NumToChange/2,
02612 SplitElement, (Action**)(&UnAction));
02613
02614
02615 if (Act==AC_FAIL)
02616 return FALSE;
02617
02618
02619 ((RemovePathElementAction*)UnAction)->RecordPath(EndPath);
02620
02621
02622 EndPath->InkPath.SetPathPosition(SplitElement);
02623 PathFlags InsertFlags;
02624 BOOL InsertWorked;
02625
02626
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
02633 if (!InsertWorked)
02634 return FALSE;
02635
02636
02637 ModifyPathAction* ModAction;
02638 Act = ModifyPathAction::Init(this, &UndoActions, NumToChange, (Action**)(&ModAction));
02639 if (Act==AC_FAIL)
02640 return FALSE;
02641
02642
02643 if (Act!=AC_NORECORD)
02644 {
02645
02646 PathVerb* ChangedVerbs;
02647 PathFlags* ChangedFlags;
02648 DocCoord* ChangedCoords;
02649 INT32* ChangedIndices;
02650
02651
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
02658 if (!ChangedVerbs || !ChangedFlags || !ChangedCoords || !ChangedIndices)
02659 {
02660
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
02670 Verbs = EndPath->InkPath.GetVerbArray();
02671 Flags = EndPath->InkPath.GetFlagArray();
02672 Coords = EndPath->InkPath.GetCoordArray();
02673
02674
02675 for (INT32 i=0; i<NumToChange; i++)
02676 {
02677
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
02685 ModAction->StoreArrays(ChangedVerbs, ChangedFlags, ChangedCoords, ChangedIndices, EndPath);
02686 }
02687
02688
02689 Verbs = EndPath->InkPath.GetVerbArray();
02690 Flags = EndPath->InkPath.GetFlagArray();
02691 Coords = EndPath->InkPath.GetCoordArray();
02692
02693
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
02704
02705 *NewElements = 0;
02706 *SplitAt = SplitElement;
02707
02708
02709 DocCoord* Coords = EndPath->InkPath.GetCoordArray();
02710 INT32 NumCoords = EndPath->InkPath.GetNumCoords();
02711
02712
02713 if (Coords[NumCoords-1]==SplitPoint)
02714 *SplitAt = NumCoords;
02715 }
02716
02717
02718 return TRUE;
02719 }
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741 BOOL OpFreeHand::ReplaceMiddleOfPath(NodePath* pNewPath, INT32 FirstChangedIndex, INT32 NumElements)
02742 {
02743
02744
02745
02746
02747 EditBrushLists(pNewPath, FirstChangedIndex, NumElements);
02748
02749
02750 if (NumElements>0)
02751 {
02752
02753
02754 ActionCode Act;
02755 InsertPathElementAction* ModAction;
02756 Act = InsertPathElementAction::Init(this, &UndoActions, NumElements, FirstChangedIndex,
02757 (Action**)(&ModAction));
02758
02759
02760 if (Act == AC_FAIL)
02761 return FALSE;
02762
02763
02764 if (Act!=AC_NORECORD)
02765 {
02766
02767 PathVerb* ChangedVerbs;
02768 DocCoord* ChangedCoords;
02769 PathFlags* ChangedFlags;
02770
02771
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
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
02786 PathVerb* Verbs = EndPath->InkPath.GetVerbArray();
02787 DocCoord* Coords = EndPath->InkPath.GetCoordArray();
02788 PathFlags* Flags = EndPath->InkPath.GetFlagArray();
02789
02790
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
02799 ModAction->RecordPath(ChangedVerbs, ChangedFlags, ChangedCoords, EndPath);
02800 }
02801
02802
02803 EndPath->InkPath.DeleteSection(FirstChangedIndex, NumElements);
02804 }
02805
02806
02807
02808 Action* UnAction;
02809 INT32 NumCoords = pNewPath->InkPath.GetNumCoords() - 1;
02810 ActionCode Act = RemovePathElementAction::Init(this, &UndoActions, NumCoords,
02811 FirstChangedIndex, (Action**)(&UnAction));
02812
02813
02814 if (Act==AC_FAIL)
02815 return FALSE;
02816
02817
02818 ((RemovePathElementAction*)UnAction)->RecordPath(EndPath);
02819
02820
02821 EndPath->InkPath.InsertSection(FirstChangedIndex, NumCoords);
02822
02823
02824 PathVerb* Verbs = EndPath->InkPath.GetVerbArray();
02825 DocCoord* Coords = EndPath->InkPath.GetCoordArray();
02826 PathFlags* Flags = EndPath->InkPath.GetFlagArray();
02827
02828
02829 PathVerb* NewVerbs = pNewPath->InkPath.GetVerbArray();
02830 DocCoord* NewCoords = pNewPath->InkPath.GetCoordArray();
02831 PathFlags* NewFlags = pNewPath->InkPath.GetFlagArray();
02832
02833
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
02843 SetRetroPath(EndPath, FirstChangedIndex, pNewPath->InkPath.GetNumCoords());
02844
02845 return TRUE;
02846 }
02847
02848
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860
02861
02862
02863
02864
02865
02866
02867
02868
02869 BOOL OpFreeHand::EditBrushLists(NodePath* pNewPath, INT32 FirstChangedIndex, INT32 NumElements)
02870 {
02871
02872
02873
02874 ERROR2IF(pNewPath == NULL, FALSE, "pNewPath is NULL in OpFreeHand::EditPressureList");
02875
02876
02877
02878 AttrBrushType* pAttrBrush = NULL;
02879
02880 pAttrBrush = EndPath->GetAppliedBrushAttribute();
02881 if (pAttrBrush == NULL)
02882 return TRUE;
02883
02884
02885
02886 if (!pAttrBrush->ContainsPressureCache())
02887 return TRUE;
02888
02889
02890 BrushAttrValue* pVal = (BrushAttrValue*)pAttrBrush->GetAttributeValue();
02891 if (pVal == NULL)
02892 return TRUE;
02893
02894
02895
02896
02897
02898
02899
02900
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
02917 FirstChangedPoint = pCoords[FirstChangedIndex];
02918 LastChangedPoint = pCoords[FirstChangedIndex + NumElements];
02919
02920 EndPath->InkPath.GetDistanceToPoint(FirstChangedPoint, &DistToFirstPoint);
02921 EndPath->InkPath.GetDistanceToPoint(LastChangedPoint, &DistToLastPoint);
02922
02923
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)
02943 return FALSE;
02944
02945
02946
02947
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
02955 RemovePressurePointsAction* pAction;
02956
02957 if (RemovePressurePointsAction::Init(this, &UndoActions, pAttrBrush, (UINT32)StartPressureIndex, NumObjects, NULL, &pAction) == AC_FAIL)
02958 return FALSE;
02959
02960
02961 AddPressurePointsAction* pAddAction;
02962
02963
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
02970 pAttrBrush->ClearCachedRect();
02971 Rect = pAttrBrush->GetAttrBoundingRect(EndPath);
02972 EndPath->ReleaseCached();
02973 if (!DoInvalidateRegion(pSpread, Rect))
02974 return FALSE;
02975 return TRUE;
02976
02977 }
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988
02989
02990
02991
02992
02993
02994
02995
02996 BOOL OpFreeHand::SimpleJoinBrush(NodePath* pInsertedNode, Path* pNewPath)
02997 {
02998 if (pInsertedNode == NULL || pNewPath == NULL)
02999 {
03000 ERROR3("Null inputs to OpDrawBrush::SimpleJoinBrush");
03001 return FALSE;
03002 }
03003
03004
03005
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
03014 if (pAttrBrush->GetBrushHandle() == BrushHandle_NoBrush)
03015 return TRUE;
03016
03017
03018 if (!pAttrBrush->ContainsPressureCache() && !pAttrBrush->IsTimeStamping())
03019 return TRUE;
03020
03021
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
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
03047
03048
03049
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;
03063
03064
03065 CDistanceSampler* pAttrData = pAttrBrush->GetPressureCache();
03066 if (pAttrData == NULL)
03067 return FALSE;
03068
03069
03070
03071 switch (JoinType)
03072 {
03073 case JOINTYPE_NEWSTART_TO_OLDSTART:
03074 InsertDistance = -1;
03075 EndInsertDistance = 0;
03076 StartIndex = 0;
03077 break;
03078 case JOINTYPE_NEWSTART_TO_OLDEND:
03079 InsertDistance = OldPathLength;
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
03103 CDistanceSampler* pSampler = OpDrawBrush::GeneratePressureData(pAttrBrush, InsertDistance, EndInsertDistance, NewPathLength);
03104 if (pSampler == NULL)
03105 return FALSE;
03106
03107
03108
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
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 }
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145 BOOL OpFreeHand::RetroSmoothBrush(NodePath* pNewNodePath)
03146 {
03147 return TRUE;
03148 }
03149
03150
03151
03152
03153
03154
03155
03156
03157
03158
03159
03160
03161
03162
03163
03164
03165 BOOL OpFreeHand::ReverseBrushPressure()
03166 {
03167 return TRUE;
03168 }
03169
03170
03171
03172
03173
03174
03175
03176
03177
03178
03179
03180
03181
03182
03183 SimpleJoinType OpFreeHand::GetSimpleJoinType(Path* pNewPath, Path* pExistingPath)
03184 {
03185 if (pNewPath == NULL || pExistingPath == NULL)
03186 return JOINTYPE_NONE;
03187
03188
03189 if (StartPath == NULL && EndPath == NULL)
03190 return JOINTYPE_NONE;
03191
03192 DocCoord* pNewCoords = pNewPath->GetCoordArray();
03193 if (pNewCoords == NULL)
03194 return JOINTYPE_NONE;
03195
03196 INT32 NumCoords = pNewPath->GetNumCoords();
03197
03198 DocCoord NewStart = pNewCoords[0];
03199 DocCoord NewEnd = pNewCoords[NumCoords-1];
03200
03201 SimpleJoinType ReturnVal = JOINTYPE_NONE;
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213
03214
03215
03216
03217
03218
03219
03220
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
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
03244
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
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 }
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278 BOOL OpFreeHand::Declare()
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,
03287 _R(IDBBL_FREEHANDTOOLOP),
03288 0 ));
03289 }
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306 OpState OpFreeHand::GetState(String_256* Description, OpDescriptor*)
03307 {
03308 OpState Blobby;
03309
03310 return Blobby;
03311 }
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328 NodeGroup* OpFreeHand::GetParentOfNodePath()
03329 {
03330 NodeGroup* pParent = NULL;
03331 if (m_pNewNodePath == NULL)
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 }
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362 BOOL OpFreeHand::InsertChangeBlendStepsAction(NodeBlend* pNodeBlend)
03363 {
03364
03365 ERROR2IF(pNodeBlend==NULL, FALSE, "NodeBlend pointer is NULL");
03366
03367
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
03391
03392
03393 if (ok)
03394 {
03395 double PathDistanceUsed = NewNumSteps * DistanceEntered;
03396 double PathProportion = PathDistanceUsed / NewPathLength;
03397
03398
03399 if (PathProportion != 1.0)
03400 {
03401
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;
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 }
03437 }
03438
03439 }
03440 }
03441
03442 return TRUE;
03443 }
03444
03445
03446
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463 BOOL OpFreeHand::InvalidateBrushRegion(NodePath* pNodePath)
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();
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 }