penedit.cpp

Go to the documentation of this file.
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();