00001 // $Id: penedit.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // The pen tools edit code. Contains all operations provided for the 00099 // pen tool 00100 // Created by Mike on 25/9/94 00101 00102 #include "camtypes.h" 00103 //#include "resource.h" 00104 #include "penedit.h" 00105 //#include "mike.h" 00106 #include "osrndrgn.h" 00107 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 #include "nodepath.h" 00109 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 //#include "selop.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00112 #include "progress.h" 00113 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00114 #include "pathedit.h" 00115 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00116 //#include "stockcol.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00117 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00118 00119 CC_IMPLEMENT_DYNCREATE( OpPenHandles, Operation ) 00120 CC_IMPLEMENT_DYNCREATE( OpPenDragBlobs, OpPenHandles ) 00121 CC_IMPLEMENT_DYNCREATE( OpPenCreateInternal, OpPenDragBlobs ) 00122 CC_IMPLEMENT_DYNCREATE( OpPenEditInternal, OpPenDragBlobs ) 00123 CC_IMPLEMENT_DYNCREATE( OpPenEditPath, OpPenHandles ) 00124 CC_IMPLEMENT_DYNCREATE( OpPenCreatePath, OpPenEditPath ) 00125 CC_IMPLEMENT_DYNCREATE( OpPenAddElement, OpPenEditPath ) 00126 CC_IMPLEMENT_DYNCREATE( OpPenClosePath, OpPenEditPath ) 00127 00128 CC_IMPLEMENT_DYNCREATE( OpAddPath, SelOperation ) 00129 CC_IMPLEMENT_DYNCREATE( OpAddNewPath, OpAddPath ) 00130 CC_IMPLEMENT_DYNCREATE( OpAddPathToPath, OpAddPath ) 00131 CC_IMPLEMENT_DYNCREATE( OpClosePathWithPath, OpAddPath ) 00132 00133 00134 #define new CAM_DEBUG_NEW 00135 00136 /* 00137 */ 00138 00139 00140 /******************************************************************************************** 00141 00142 > HandleFlags::HandleFlags(BOOL rTrackEnd = TRUE, 00143 BOOL rGhostEnd = TRUE, 00144 BOOL TrackPtMoves = TRUE, 00145 BOOL TrackPtSpins = FALSE, 00146 BOOL GhostPtMoves = TRUE 00147 BOOL GhostPtSpins = FALSE); 00148 00149 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00150 Created: 25/9/94 00151 Purpose: constructor for handle flags class 00152 SeeAlso: - 00153 00154 ********************************************************************************************/ 00155 00156 HandleFlags::HandleFlags( BOOL rTrackEnd, 00157 BOOL rGhostEnd, 00158 BOOL TrackPtMoves, 00159 BOOL GhostPtMoves, 00160 BOOL TrackPtSpins, 00161 BOOL GhostPtSpins) 00162 { 00163 // Set up some flags for rendering handles correctly 00164 RenderTrackEnd = rTrackEnd; 00165 RenderGhostEnd = rGhostEnd; 00166 TrackPointMoves = TrackPtMoves; 00167 GhostPointMoves = GhostPtMoves; 00168 TrackPointSpins = TrackPtSpins; 00169 GhostPointSpins = GhostPtSpins; 00170 } 00171 00172 00173 /******************************************************************************************** 00174 00175 > WobbleFlags::WobbleFlags(BOOL pSister = FALSE, 00176 BOOL pBrother = TRUE, 00177 BOOL nBrother = FALSE, 00178 BOOL nSister = FALSE) 00179 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00180 Created: 25/9/94 00181 Purpose: constructor for wobble flags class 00182 SeeAlso: - 00183 00184 ********************************************************************************************/ 00185 00186 WobbleFlags::WobbleFlags( BOOL pSister, 00187 BOOL pBrother, 00188 BOOL nBrother, 00189 BOOL nSister) 00190 { 00191 // Set up some flags for wobbling a curves control points correctly 00192 PrevSister = pSister; 00193 PrevBrother = pBrother; 00194 NextBrother = nBrother; 00195 NextSister = nSister; 00196 }; 00197 00198 /******************************************************************************************** 00199 00200 ControlPts::ControlPts() / ~ControlPts() 00201 00202 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00203 Created: 25/9/94 00204 Purpose: Control points class constructor and destructor 00205 SeeAlso: - 00206 00207 ********************************************************************************************/ 00208 00209 ControlPts::ControlPts() 00210 { 00211 pHndSpread = NULL; 00212 } 00213 00214 ControlPts::~ControlPts() 00215 { 00216 } 00217 00218 00219 /******************************************************************************************** 00220 00221 > OpPenHandles::OpPenHandles() 00222 00223 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00224 Created: 25/9/94 00225 Purpose: OpPenEorHandles constructor 00226 SeeAlso: - 00227 00228 ********************************************************************************************/ 00229 00230 OpPenHandles::OpPenHandles() 00231 { 00232 // default constructor (do nothing) 00233 } 00234 00235 00236 /******************************************************************************************** 00237 00238 > DocCoord OpPenHandles::GetTrackHandle() const; 00239 00240 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00241 Created: 25/9/94 00242 Inputs: - 00243 Outputs: The current track handle coordinate 00244 Purpose: Return the private track handle coordinate for reference by none 00245 inclass code. 00246 00247 ********************************************************************************************/ 00248 00249 DocCoord OpPenHandles::GetTrackHandle() const 00250 { 00251 return TrackEnd; 00252 } 00253 00254 DocCoord OpPenHandles::GetGhostHandle() const 00255 { 00256 return GhostEnd; 00257 } 00258 00259 DocCoord OpPenHandles::GetMidHandle() const 00260 { 00261 return MidPoint; 00262 } 00263 00264 00265 /******************************************************************************************** 00266 00267 > DocCoord OpPenHandles::CalcGhostEnd(DocCoord start, DocCoord end) const; 00268 00269 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00270 Created: 25/9/94 00271 Inputs: start = point 1 00272 end = point 2 00273 Returns: ghost doc coordinate 00274 Purpose: Calculate a ghost end coordinate given two input coordinates. 00275 ghost = point1 - (point2 - point1) 00276 00277 ********************************************************************************************/ 00278 00279 DocCoord OpPenHandles::CalcGhostEnd(DocCoord start, DocCoord end) const 00280 { 00281 DocCoord ghost; 00282 ghost.x = start.x - (end.x - start.x); 00283 ghost.y = start.y - (end.y - start.y); 00284 00285 return ghost; 00286 } 00287 00288 00289 00290 /******************************************************************************************** 00291 00292 > DocRect OpPenHandles::GetHandlesRect() 00293 00294 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00295 Created: 26/9/94 00296 Returns: DocRect, 00297 Purpose: Calculate the bounding rect of the drag blobs. 00298 00299 ********************************************************************************************/ 00300 00301 DocRect OpPenHandles::GetHandlesRect() 00302 { 00303 // just set it to be an empty rectangle 00304 DocRect BoundRect (0,0,0,0); 00305 DocView* pDocView = DocView::GetSelected(); 00306 ERROR2IF(pDocView == NULL, BoundRect, 00307 "No selected DocView in OpPenHandles::GetHandlesRect()"); 00308 00309 // Find the Rect around the drag blobs if there is any, otherwise return that bbox 00310 // of the start pos. 00311 00312 OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), TrackEnd, BT_SELECTEDLARGEST, &BoundRect); 00313 DocRect BlobRect; 00314 OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), GhostEnd, BT_SELECTEDLARGEST, &BlobRect); 00315 BoundRect = BoundRect.Union(BlobRect); 00316 return BoundRect; 00317 } 00318 00319 00320 00321 /******************************************************************************************** 00322 00323 > void OpPenHandles::RecalcHandles(DocCoord DragPos, BOOL constrain) 00324 00325 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00326 Created: 26/9/94 00327 Inputs: DragPos = New position to take as the drag position 00328 constrain = TRUE the constrain the handle positions 00329 Purpose: Recalc handles, given a new drag position which is generally following the 00330 mouse pointer, will work out the relative positions of the drag handles. 00331 The drag handles can be made to follow the drag position absolutely, or 00332 reletively dependent on their start positions. 00333 00334 ********************************************************************************************/ 00335 00336 void OpPenHandles::RecalcHandles(DocCoord DragPos, BOOL constrain) 00337 { 00338 00339 // Recalculate the position of the handle which is following the 00340 // mouse. 00341 00342 DocCoord Constrain = DragPos; 00343 if (constrain) 00344 DocView::ConstrainToAngle(MidPoint, &Constrain); 00345 00346 if (Hflags.TrackPointMoves) 00347 TrackEnd=Constrain; 00348 else if (Hflags.TrackPointSpins) 00349 { 00350 double Glen = TrackEnd.Distance(MidPoint); 00351 double Dlen = Constrain.Distance(MidPoint); 00352 DocCoord direction; 00353 direction.x = Constrain.x - MidPoint.x; 00354 direction.y = Constrain.y - MidPoint.y; 00355 if (Dlen!=0) 00356 { 00357 double ndx = direction.x / Dlen; 00358 double ndy = direction.y / Dlen; 00359 TrackEnd.x = MidPoint.x + (INT32)(Glen*ndx); 00360 TrackEnd.y = MidPoint.y + (INT32)(Glen*ndy); 00361 } 00362 } 00363 00364 // Recalc the position of the handle opposite, the track handle accross 00365 // the midpoint. 00366 00367 if (Hflags.GhostPointMoves) 00368 { 00369 GhostEnd.x = MidPoint.x - (Constrain.x - MidPoint.x); 00370 GhostEnd.y = MidPoint.y - (Constrain.y - MidPoint.y); 00371 } 00372 else if (Hflags.GhostPointSpins) 00373 { 00374 // if we're spinning, the ghost point will remain a set distance 00375 // from the midpoint, but just spin around coincident with 00376 // the drag pos. 00377 double Glen = GhostEnd.Distance(MidPoint); 00378 double Dlen = Constrain.Distance(MidPoint); 00379 DocCoord direction; 00380 direction.x = Constrain.x - MidPoint.x; 00381 direction.y = Constrain.y - MidPoint.y; 00382 if (Dlen!=0) 00383 { 00384 double ndx = direction.x / Dlen; 00385 double ndy = direction.y / Dlen; 00386 GhostEnd.x = MidPoint.x - (INT32)(Glen*ndx); 00387 GhostEnd.y = MidPoint.y - (INT32)(Glen*ndy); 00388 } 00389 } 00390 00391 } 00392 00393 00394 00395 /******************************************************************************************** 00396 00397 > void OpPenHandles::RenderHandles() 00398 00399 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00400 Created: 26/9/94 00401 Purpose: Render some drag control handles as the mouse moves around. These will 00402 spin around an anchor point. 00403 00404 ********************************************************************************************/ 00405 00406 void OpPenHandles::RenderHandles() 00407 { 00408 DocRect Rect = GetHandlesRect(); 00409 RenderRegion* pRegion = DocView::RenderOnTop( &Rect, StartSpread, ClippedEOR ); 00410 while ( pRegion ) 00411 { 00412 UpdateHandles(pRegion); 00413 pRegion = DocView::GetNextOnTop(NULL); 00414 } 00415 } 00416 00417 00418 /******************************************************************************************** 00419 00420 > void OpPenHandles::UpdateHandles( RenderRegion* pRegion ) 00421 00422 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00423 Created: 30/9/94 00424 Inputs: pRegion = Pointer to a region to draw into 00425 Purpose: Render some drag control handles as the mouse moves around. These will 00426 spin around an anchor point. Their appearence and positioning is set 00427 by the flags variable hflags. 00428 SeeAlso: Hflags 00429 00430 00431 ********************************************************************************************/ 00432 00433 void OpPenHandles::UpdateHandles( RenderRegion* pRegion ) 00434 { 00435 pRegion->SetLineColour(COLOUR_BEZIERBLOB); 00436 pRegion->SetFillColour(COLOUR_TRANS); 00437 pRegion->DrawBlob(MidPoint, BT_SELECTED); 00438 00439 if (TrackEnd != MidPoint) 00440 { 00441 pRegion->SetLineColour(COLOUR_BEZIERLINE); 00442 pRegion->SetFillColour(COLOUR_TRANS); 00443 00444 if (Hflags.RenderTrackEnd && Hflags.RenderGhostEnd) 00445 pRegion->DrawLine(TrackEnd, GhostEnd); 00446 else 00447 { 00448 if (Hflags.RenderTrackEnd) 00449 pRegion->DrawLine(TrackEnd,MidPoint); 00450 if (Hflags.RenderGhostEnd) 00451 pRegion->DrawLine(GhostEnd,MidPoint); 00452 } 00453 00454 pRegion -> SetLineColour(COLOUR_TRANS); 00455 pRegion -> SetFillColour(COLOUR_UNSELECTEDBLOB); 00456 00457 if (Hflags.RenderTrackEnd) 00458 pRegion -> DrawBlob(TrackEnd, BT_UNSELECTED); 00459 if (Hflags.RenderGhostEnd) 00460 pRegion -> DrawBlob(GhostEnd, BT_UNSELECTED); 00461 00462 } 00463 } 00464 00465 00466 /******************************************************************************************** 00467 00468 > void OpPenHandles::SetHandleEnds(DocCoord ClickPos, DocCoord DragPos) 00469 00470 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00471 Created: 26/9/94 00472 Purpose: 00473 00474 ********************************************************************************************/ 00475 00476 void OpPenHandles::SetHandleEnds(DocCoord ClickPos, DocCoord DragPos, DocCoord GhostPos) 00477 { 00478 MidPoint = ClickPos; 00479 TrackEnd = DragPos; 00480 GhostEnd = GhostPos; 00481 } 00482 00483 00484 00485 /******************************************************************************************** 00486 00487 > OpPenHandles::SetDragHandles( HandleFlags HandFlags, 00488 DocCoord Click, 00489 DocCoord Drag, 00490 DocCoord Ghost, 00491 Spread* pSpread) 00492 00493 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00494 Created: 25/9/94 00495 Purpose: Set up the initial positions of the drag handles. Note, the handles 00496 contain their own coordinates of where they think they are. These are 00497 separate from the drag mouse position. This allows the handles to represent 00498 a relation to the drag point and not an absolute position. 00499 SeeAlso: - 00500 00501 ********************************************************************************************/ 00502 00503 void OpPenHandles::SetDragHandles( HandleFlags HandFlags, 00504 DocCoord Click, 00505 DocCoord Drag, 00506 DocCoord Ghost, 00507 Spread* pSpread) 00508 { 00509 StartMousePos = Click; 00510 CurrentMousePos = Click; 00511 StartSpread = pSpread; 00512 Hflags = HandFlags; 00513 SetHandleEnds(Click, Drag, Ghost); 00514 } 00515 00516 00517 /******************************************************************************************** 00518 00519 > void OpPenHandles::ChangeTrackHandle(DocCoord newpos, BOOL constrain) 00520 00521 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00522 Created: 26/9/94 00523 Purpose: 00524 00525 ********************************************************************************************/ 00526 00527 void OpPenHandles::ChangeTrackHandle(DocCoord newpos, BOOL constrain) 00528 { 00529 CurrentMousePos = newpos; 00530 RecalcHandles(newpos, constrain); 00531 } 00532 00533 00534 00535 /******************************************************************************************** 00536 00537 > void OpPenHandles::HasMouseMoved(DocCoord& OriginalPoint, DocCoord& PointerPos, double threshold=2) 00538 00539 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00540 Created: 26/9/94 00541 Inputs OriginalPoint = usually the last mouse position recorded 00542 PointerPos = usually the current mouse position to check 00543 threshold = a value to multiply the scaled pixel size for the view by. 00544 Purpose: Checks to see whether two coordinates are the same. The current test also 00545 checks for movement of less than two pixels in the scaled view. If the mouse 00546 has moved less than threshold*ScaledPixelSize then the points are considered 00547 equivalent. 00548 00549 ********************************************************************************************/ 00550 00551 BOOL OpPenHandles::HasMouseMoved(DocCoord& OriginalPoint, DocCoord& PointerPos, double threshold) 00552 { 00553 if (OriginalPoint==PointerPos) 00554 return FALSE; 00555 00556 INT32 dist = (INT32)(OriginalPoint.Distance(PointerPos)+0.5); 00557 00558 FIXED16 ScaledPixelWidth, 00559 ScaledPixelHeight; 00560 GetWorkingView()->GetScaledPixelSize(&ScaledPixelWidth, &ScaledPixelHeight); 00561 00562 INT32 PixWidth = ScaledPixelWidth.MakeLong(); 00563 INT32 PixHeight = ScaledPixelHeight.MakeLong(); 00564 00565 PixWidth = (INT32)(PixWidth*threshold+0.5); 00566 PixHeight = (INT32)(PixHeight*threshold+0.5); 00567 00568 INT32 range; 00569 (PixWidth<PixHeight) ? (range=PixHeight) : (range=PixWidth); 00570 00571 return (dist>range); 00572 } 00573 00574 00575 00576 /******************************************************************************************** 00577 00578 > void OpPenHandles::RenderTestRect( DocRect Rect, Spread* pSpread, StockColour colour ) 00579 00580 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00581 Created: 29/9/94 00582 Purpose: Render a black rectangle. Useful for checking render regions and clipping 00583 00584 ********************************************************************************************/ 00585 00586 void OpPenHandles::RenderTestRect( DocRect Rect, Spread* pSpread, StockColour colour ) 00587 { 00588 if (Error::IsUserName("Mike")) 00589 { 00590 TRACE( _T("RectLox=%d\n"),Rect.lo.x); 00591 TRACE( _T("RectLoy=%d\n"),Rect.lo.y); 00592 TRACE( _T("RectHix=%d\n"),Rect.hi.x); 00593 TRACE( _T("RectHiy=%d\n\n"),Rect.hi.y); 00594 } 00595 00596 RenderRegion* pRegion = DocView::RenderOnTop( &Rect, pSpread, ClippedEOR ); 00597 while ( pRegion ) 00598 { 00599 pRegion -> SetFillColour(colour); 00600 pRegion -> DrawRect(&Rect); 00601 pRegion = DocView::GetNextOnTop(NULL); 00602 } 00603 } 00604 00605 /******************************************************************************************** 00606 00607 > OpPenDragBlobs::OpPenDragBolbs() 00608 00609 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00610 Created: 25/9/94 00611 Purpose: OpPenDragBlobs constructor 00612 SeeAlso: - 00613 00614 ********************************************************************************************/ 00615 00616 OpPenDragBlobs::OpPenDragBlobs() 00617 { 00618 } 00619 00620 00621 /******************************************************************************************** 00622 00623 > BOOL OpPenDragBlobs::DoPenDragBlobs() 00624 00625 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00626 Created: 26/9/94 00627 Inputs: tptr = pointer to calling tool. 00628 Outputs: - 00629 Returns: TRUE if able to start the drag, FALSE if not 00630 Purpose: 00631 Errors: failandexecute will be called if the operation fails in some way, most 00632 likely when no memory is available. 00633 00634 ********************************************************************************************/ 00635 00636 BOOL OpPenDragBlobs::DoPenDragBlobs() 00637 { 00638 // And tell the Dragging system that we need drags to happen 00639 DocRect HandlesRect = GetHandlesRect(); 00640 return StartDrag(DRAGTYPE_AUTOSCROLL, &HandlesRect, &CurrentMousePos); 00641 } 00642 00643 00644 00645 /******************************************************************************************** 00646 00647 > void OpPenDragBlobs::DragPointerMove( DocCoord PointerPos, 00648 ClickModifiers ClickMods, 00649 Spread* pSpread, 00650 BOOL bSolidDrag) 00651 00652 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00653 Created: 26/9/94 00654 Inputs: PointerPos - The current position of the mouse in Doc Coords 00655 ClickMods - Which key modifiers are being pressed 00656 Purpose: This is called every time the mouse moves, during a drag. 00657 SeeAlso: ClickModifiers 00658 00659 ********************************************************************************************/ 00660 00661 void OpPenDragBlobs::DragPointerMove(DocCoord PointerPos, 00662 ClickModifiers ClickMods, 00663 Spread* pSpread, 00664 BOOL bSolidDrag) 00665 { 00666 // If drag has moved onto a different spread, convert the coord to be relative to the 00667 // original spread. 00668 if (pSpread != StartSpread) 00669 PointerPos = MakeRelativeToSpread(StartSpread, pSpread, PointerPos); 00670 00671 // Make sure we get the grid snapping involved 00672 DocCoord SnapPos = PointerPos; 00673 DocView::SnapCurrent(pSpread,&SnapPos); 00674 00675 // Rub out the old EORed version of the handles, and stick some new ones on. 00676 RenderHandles(); 00677 ChangeTrackHandle(SnapPos, ClickMods.Constrain); 00678 RenderHandles(); 00679 } 00680 00681 00682 00683 /******************************************************************************************** 00684 00685 > void OpPenDragBlobs::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 00686 Spread* pSpread, BOOL Success, BOOL bSolidDrag) 00687 00688 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00689 Created: 26/9/94 00690 Inputs: PointerPos - The position of the mouse at the end of the drag 00691 ClickMods - the key modifiers being pressed 00692 Success - TRUE if the drag was terminated properly, FALSE if it 00693 was ended with the escape key being pressed 00694 Purpose: This is called when a drag operation finishes. 00695 SeeAlso: ClickModifiers 00696 00697 ********************************************************************************************/ 00698 00699 void OpPenDragBlobs::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 00700 Spread* pSpread, BOOL Success, BOOL bSolidDrag) 00701 { 00702 // terminate the drag and operation 00703 EndDrag(); 00704 } 00705 00706 00707 00708 /******************************************************************************************** 00709 00710 > virtual void OpPenDragBlobs::RenderDragBlobs( DocRect Rect, Spread* pSpread, BOOL bSolidDrag ) 00711 00712 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00713 Created: 29/9/94 00714 Purpose: This function is called to render our drag blobs during scrolling. 00715 00716 ********************************************************************************************/ 00717 00718 void OpPenDragBlobs::RenderDragBlobs( DocRect Rect, Spread* pSpread, BOOL bSolidDrag ) 00719 { 00720 if (StartSpread!=pSpread) return; 00721 RenderRegion* pRegion = DocView::RenderOnTop( &Rect, pSpread, ClippedEOR ); 00722 while ( pRegion ) 00723 { 00724 UpdateHandles(pRegion); 00725 pRegion = DocView::GetNextOnTop(NULL); 00726 } 00727 } 00728 00729 00730 00731 00732 /******************************************************************************************** 00733 00734 > OpPenCreateInternal::OpPenCreateInternal() 00735 00736 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00737 Created: 25/9/94 00738 Purpose: OpPenCreateInternal constructor 00739 SeeAlso: - 00740 00741 ********************************************************************************************/ 00742 00743 OpPenCreateInternal::OpPenCreateInternal() 00744 { 00745 } 00746 00747 00748 00749 /******************************************************************************************** 00750 00751 > BOOL OpPenCreateInternal::Init() 00752 00753 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00754 Created: 25/9/94 00755 Inputs: - 00756 Outputs: - 00757 Returns: TRUE if the operation could be successfully initialised 00758 FALSE if no more memory could be allocated 00759 00760 Purpose: OpDeletePoints initialiser method 00761 Errors: ERROR will be called if there was insufficient memory to allocate the 00762 operation. 00763 SeeAlso: - 00764 00765 ********************************************************************************************/ 00766 00767 BOOL OpPenCreateInternal::Init() 00768 { 00769 return (RegisterOpDescriptor(0, // tool ID 00770 _R(IDS_PENCREATEINTERNALOP), // string resource ID 00771 CC_RUNTIME_CLASS(OpPenCreateInternal), // runtime class for Op 00772 OPTOKEN_PENCREATEINTERNAL, // Ptr to token string 00773 OpPenCreateInternal::GetState, // GetState function 00774 0, // help ID = 0 00775 _R(IDBBL_PENCREATEINTERNALOP), // bubble help ID = 0 00776 0 // resource ID = 0 00777 )); 00778 00779 } 00780 00781 00782 /******************************************************************************************** 00783 00784 > OpState OpPenCreateInternal::GetState(String_256*, OpDescriptor*) 00785 00786 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00787 Created: 26/9/94 00788 Inputs: - 00789 Outputs: - 00790 Returns: The state of the OpPenCreateInternal 00791 Purpose: For finding the OpPenCreateInternal's state. 00792 Errors: - 00793 SeeAlso: - 00794 00795 ********************************************************************************************/ 00796 00797 OpState OpPenCreateInternal::GetState(String_256* UIDescription, OpDescriptor*) 00798 { 00799 OpState OpSt; 00800 return OpSt; 00801 } 00802 00803 00804 00805 00806 00807 00808 00809 /******************************************************************************************** 00810 00811 > void OpPenCreateInternal::DoPenCreateInternal( DocCoord Anchor, 00812 Spread *pSpread, 00813 ControlPts* pHandles) 00814 00815 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00816 Created: 26/9/94 00817 Inputs: Anchor = position of first click 00818 pSpread = pointer to spread where first click occured 00819 pHandles= pointer to handles block 00820 Outputs: - 00821 Returns: - 00822 Purpose: 00823 Errors: failandexecute will be called if the operation fails in some way, most 00824 likely when no memory is available. 00825 00826 ********************************************************************************************/ 00827 00828 void OpPenCreateInternal::DoPenCreateInternal(DocCoord Anchor, Spread* pSpread, ControlPts* pHandles) 00829 { 00830 // initialise the drag handles into the default mode. 00831 00832 pUserHandles = pHandles; 00833 HandleFlags Flags; 00834 00835 // Make sure we get the grid snapping involved 00836 DocCoord SnapPos = Anchor; 00837 DocView::SnapCurrent(pSpread,&SnapPos); 00838 00839 SetDragHandles(Flags, SnapPos, SnapPos, SnapPos, pSpread); 00840 00841 // call the base classes drag init function 00842 if (!DoPenDragBlobs()) 00843 { 00844 FailAndExecute(); 00845 End(); 00846 return; 00847 } 00848 00849 // Render the current drag blobs where necessary 00850 RenderHandles(); 00851 } 00852 00853 00854 00855 00856 /******************************************************************************************** 00857 00858 > void OpPenCreateInternal::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 00859 Spread* pSpread, BOOL Success, BOOL bSolidDrag) 00860 00861 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00862 Created: 26/9/94 00863 Inputs: PointerPos - The position of the mouse at the end of the drag 00864 ClickMods - the key modifiers being pressed 00865 Success - TRUE if the drag was terminated properly, FALSE if it 00866 was ended with the escape key being pressed 00867 Purpose: This is called when a drag operation finishes. 00868 SeeAlso: ClickModifiers 00869 00870 ********************************************************************************************/ 00871 00872 void OpPenCreateInternal::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 00873 Spread* pSpread, BOOL Success, BOOL bSolidDrag) 00874 { 00875 // Rub out the old EORed version of the handles 00876 RenderHandles(); 00877 00878 // inform the base class to stop dragging 00879 OpPenDragBlobs::DragFinished( PointerPos, ClickMods, pSpread, Success, bSolidDrag); 00880 00881 // inform the pen tool that a drag has come to an end 00882 if (Success) 00883 { 00884 pUserHandles->HndClick = GetMidHandle(); 00885 pUserHandles->HndDrag = GetTrackHandle(); 00886 pUserHandles->pHndSpread = StartSpread; 00887 } 00888 else 00889 FailAndExecute(); 00890 // End the operation 00891 End(); 00892 } 00893 00894 00895 00896 00897 /******************************************************************************************** 00898 00899 > OpPenEditInternal::OpPenEditInternal() 00900 00901 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00902 Created: 25/9/94 00903 Purpose: OpPenEditInternal constructor 00904 SeeAlso: - 00905 00906 ********************************************************************************************/ 00907 00908 OpPenEditInternal::OpPenEditInternal() 00909 { 00910 } 00911 00912 00913 /******************************************************************************************** 00914 00915 > BOOL OpPenEditInternal::Init() 00916 00917 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00918 Created: 25/9/94 00919 Inputs: - 00920 Outputs: - 00921 Returns: TRUE if the operation could be successfully initialised 00922 FALSE if no more memory could be allocated 00923 00924 Purpose: OpPenEditInternal initialiser method 00925 Errors: ERROR will be called if there was insufficient memory to allocate the 00926 operation. 00927 SeeAlso: - 00928 00929 ********************************************************************************************/ 00930 00931 BOOL OpPenEditInternal::Init() 00932 { 00933 return (RegisterOpDescriptor(0, // tool ID 00934 _R(IDS_PENEDITINTERNALOP), // string resource ID 00935 CC_RUNTIME_CLASS(OpPenEditInternal), // runtime class for Op 00936 OPTOKEN_PENEDITINTERNAL, // Ptr to token string 00937 OpPenEditInternal::GetState, // GetState function 00938 0, // help ID = 0 00939 _R(IDBBL_PENEDITINTERNALOP), // bubble help ID = 0 00940 0 // resource ID = 0 00941 )); 00942 00943 } 00944 00945 00946 /******************************************************************************************** 00947 00948 > OpState OpPenEditInternal::GetState(String_256*, OpDescriptor*) 00949 00950 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00951 Created: 26/9/94 00952 Inputs: - 00953 Outputs: - 00954 Returns: The state of the OpPenEditInternal 00955 Purpose: For finding the OpPenEditInternal's state. 00956 Errors: - 00957 SeeAlso: - 00958 00959 ********************************************************************************************/ 00960 00961 OpState OpPenEditInternal::GetState(String_256* UIDescription, OpDescriptor*) 00962 { 00963 OpState OpSt; 00964 return OpSt; 00965 } 00966 00967 00968 00969 /******************************************************************************************** 00970 00971 > void OpPenEditInternal::DoPenEditInternal(ControlPts* pHandles) 00972 00973 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00974 Created: 26/9/94 00975 Inputs: pHandles = Pointer to a handles block containing click pos, drag pos 00976 and spread ptr 00977 Outputs: - 00978 Returns: - 00979 Purpose: 00980 Errors: failandexecute will be called if the operation fails in some way, most 00981 likely when no memory is available. 00982 00983 ********************************************************************************************/ 00984 00985 void OpPenEditInternal::DoPenEditInternal(ControlPts* pHandles) 00986 { 00987 00988 // Set the internal state 00989 pUserHandles = pHandles; 00990 00991 HandleFlags Flags; 00992 DocCoord ghst = CalcGhostEnd(pHandles->HndClick, pHandles->HndDrag); 00993 SetDragHandles(Flags, pHandles->HndClick, pHandles->HndDrag, ghst, pHandles->pHndSpread); 00994 00995 // call the base classes drag init function 00996 if (!DoPenDragBlobs()) 00997 { 00998 FailAndExecute(); 00999 End(); 01000 return; 01001 } 01002 } 01003 01004 01005 /******************************************************************************************** 01006 01007 > void OpPenEditInternal::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 01008 Spread* pSpread, BOOL Success, BOOL bSolidDrag) 01009 01010 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01011 Created: 26/9/94 01012 Inputs: PointerPos - The position of the mouse at the end of the drag 01013 ClickMods - the key modifiers being pressed 01014 Success - TRUE if the drag was terminated properly, FALSE if it 01015 was ended with the escape key being pressed 01016 Purpose: This is called when a drag operation finishes. 01017 SeeAlso: ClickModifiers 01018 01019 ********************************************************************************************/ 01020 01021 void OpPenEditInternal::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 01022 Spread* pSpread, BOOL Success, BOOL bSolidDrag) 01023 { 01024 // Rub out the old EORed version of the handles 01025 RenderHandles(); 01026 01027 // inform the base class to stop dragging 01028 OpPenDragBlobs::DragFinished( PointerPos, ClickMods, pSpread, Success, bSolidDrag); 01029 01030 // inform the pen tool that a drag has come to an end 01031 if (Success) 01032 { 01033 pUserHandles->HndClick = GetMidHandle(); 01034 pUserHandles->HndDrag = GetTrackHandle(); 01035 pUserHandles->pHndSpread = StartSpread; 01036 } 01037 else 01038 FailAndExecute(); 01039 01040 // terminate the op 01041 End(); 01042 } 01043 01044 01045 01046 01047 /******************************************************************************************** 01048 01049 > OpPenEditPath::OpPenEditPath() 01050 01051 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01052 Created: 29/9/94 01053 Purpose: OpPenEditPath constructor 01054 SeeAlso: - 01055 01056 ********************************************************************************************/ 01057 01058 OpPenEditPath::OpPenEditPath() 01059 { 01060 } 01061 01062 /******************************************************************************************** 01063 01064 > OpPenEditPath::SetWobbleIndex(WobbleFlags wibble, const INT32 index) 01065 01066 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01067 Created: 29/9/94 01068 Inputs: wibble = wobble flags indicating which control handles will follow those 01069 of the drag handles. 01070 index = the index into our edit curve of the endpoint handle whose brother 01071 and sister handles are being dragged around. 01072 Outputs: - 01073 Purpose: Set the control handle index of our edit curve which will follow the 01074 dragging control handles. 01075 SeeAlso: - 01076 01077 ********************************************************************************************/ 01078 01079 void OpPenEditPath::SetWobbleIndex(WobbleFlags wibble, const INT32 index) 01080 { 01081 Wobble = wibble; 01082 WobbleIndex = index; 01083 } 01084 01085 01086 01087 /******************************************************************************************** 01088 01089 > BOOL OpPenEditPath::DoPenDragPath(Path* pEditPath) 01090 01091 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01092 Created: 29/9/94 01093 Inputs: pEditPath = pointer a path to begin editing. 01094 Returns: TRUE if able to start the drag, FALSE otherwise 01095 Returns: - 01096 Purpose: 01097 01098 ********************************************************************************************/ 01099 01100 BOOL OpPenEditPath::DoPenDragPath() 01101 { 01102 // Tell the Dragging system that we need drags to happen 01103 DocRect HandlesRect = GetBoundingRect(); 01104 return StartDrag(DRAGTYPE_AUTOSCROLL, &HandlesRect, &CurrentMousePos); 01105 } 01106 01107 01108 01109 /******************************************************************************************** 01110 01111 > void OpPenEditPath::WobbleCoords 01112 01113 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01114 Created: 11/10/94 01115 Inputs: 01116 Purpose: Moves the control handles around dependent on the classes wobble flags 01117 01118 ********************************************************************************************/ 01119 01120 void OpPenEditPath::WobbleCoords() 01121 { 01122 DocCoord* Coords = pEditPath->GetCoordArray(); 01123 01124 if (Wobble.PrevBrother) 01125 Coords[WobbleIndex-1] = GetGhostHandle(); 01126 01127 if (Wobble.PrevSister) 01128 { 01129 Coords[WobbleIndex-2].x = (2*Coords[WobbleIndex-3].x + Coords[WobbleIndex-1].x)/3; 01130 Coords[WobbleIndex-2].y = (2*Coords[WobbleIndex-3].y + Coords[WobbleIndex-1].y)/3; 01131 } 01132 01133 if (Wobble.NextBrother) 01134 Coords[WobbleIndex+1] = GetTrackHandle(); 01135 01136 if (Wobble.NextSister) 01137 { 01138 Coords[WobbleIndex+2].x = (Coords[WobbleIndex+1].x + 2*Coords[WobbleIndex+3].x)/3; 01139 Coords[WobbleIndex+2].y = (Coords[WobbleIndex+1].y + 2*Coords[WobbleIndex+3].y)/3; 01140 } 01141 } 01142 01143 01144 /******************************************************************************************** 01145 01146 > void OpPenEditPath::DragPointerMove(DocCoord PointerPos, 01147 ClickModifiers ClickMods, 01148 Spread* pSpread, BOOL bSolidDrag) 01149 01150 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01151 Created: 26/9/94 01152 Inputs: PointerPos - The current position of the mouse in Doc Coords 01153 ClickMods - Which key modifiers are being pressed 01154 Purpose: This is called every time the mouse moves, during a drag. 01155 SeeAlso: ClickModifiers 01156 01157 ********************************************************************************************/ 01158 01159 void OpPenEditPath::DragPointerMove(DocCoord PointerPos, 01160 ClickModifiers ClickMods, 01161 Spread* pSpread, BOOL bSolidDrag) 01162 { 01163 // If drag has moved onto a different spread, convert the coord to be relative to the 01164 // original spread. 01165 if (pSpread != StartSpread) 01166 PointerPos = MakeRelativeToSpread(StartSpread, pSpread, PointerPos); 01167 01168 // Make sure we get the grid snapping involved 01169 DocCoord SnapPos = PointerPos; 01170 DocView::SnapCurrent(pSpread,&SnapPos); 01171 01172 if (CurrentMousePos != SnapPos) 01173 { 01174 01175 // Rub out the old EORed version of the path and stick a new one on 01176 DocRect Rect = OpPenEditPath::GetBoundingRect(); 01177 RenderDragBlobs(Rect, StartSpread, bSolidDrag); 01178 01179 Rect.IncludePoint(SnapPos); 01180 01181 // Alter the curve drag handles 01182 ChangeTrackHandle(SnapPos, ClickMods.Constrain); 01183 01184 // make sure we wobble all the coordinates around this control point 01185 // correctly. 01186 WobbleCoords(); 01187 01188 // Now render the blobs back on again 01189 Rect = Rect.Union(OpPenEditPath::GetBoundingRect()); 01190 RenderDragBlobs(Rect, StartSpread, bSolidDrag); 01191 } 01192 01193 } 01194 01195 01196 01197 /******************************************************************************************** 01198 01199 > DocRect OpPenEditPath::GetBoundingRect() 01200 01201 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01202 Created: 30/9/94 01203 Inputs: - 01204 Purpose: Find the bounding box of the edit path and the drag handles. 01205 01206 ********************************************************************************************/ 01207 01208 DocRect OpPenEditPath::GetBoundingRect() 01209 { 01210 01211 DocRect Rect; 01212 DocView* pDocView = DocView::GetSelected(); 01213 ENSURE( pDocView != NULL, "There was no selected docview when getting the bounding box" ); 01214 01215 if ( pDocView != NULL ) 01216 { 01217 DocRect BlobRect; 01218 DocCoord Coord; 01219 Rect = pEditPath->GetBoundingRect(); 01220 Rect = Rect.Union(OpPenHandles::GetHandlesRect()); 01221 // inflate by 1/4 of an inch to avoid eor problems 01222 Rect.Inflate(72000>>2); 01223 } 01224 01225 return Rect; 01226 } 01227 01228 01229 /******************************************************************************************** 01230 01231 > DocRect OpPenEditPath::ConvertToLine(const INT32 index) 01232 01233 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01234 Created: 30/9/94 01235 Inputs: index = index of element to remove from. 01236 Purpose: Convert the currently edited curve element into a line 01237 01238 ********************************************************************************************/ 01239 01240 void OpPenEditPath::ConvertToLine(const INT32 index) 01241 { 01242 // remove the curve element, then stick a none smooth line 01243 // segment in there. 01244 01245 pEditPath->DeleteFromElement(index); 01246 PathFlags tempflags; 01247 tempflags.IsSelected = TRUE; 01248 pEditPath->InsertLineTo(GetMidHandle(), &tempflags); 01249 } 01250 01251 01252 01253 /******************************************************************************************** 01254 01255 > void OpPenEditPath::RemoveRotateEnd(const INT32 index) 01256 01257 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01258 Created: 30/9/94 01259 Inputs: index = index of bezierto element 01260 Purpose: Remove any rotate bits from a bezier element, starting at index 01261 01262 ********************************************************************************************/ 01263 01264 void OpPenEditPath::RemoveRotateEnd(const INT32 index) 01265 { 01266 // Remove all rotate values from the end curve element 01267 PathFlags* Flags = pEditPath->GetFlagArray();