snap.cpp

Go to the documentation of this file.
00001 // $Id: snap.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 // Implementation of the Snap class of Camelot - does all snap-type activity
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "snap.h"
00105 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "grid.h"
00109 #include "statline.h"
00110 #include "layer.h"
00111 #include "guides.h"
00112 //#include "scrcamvw.h"
00113 #include "camelot.h"
00114 #include "page.h"
00115 //#include "node.h"
00116 
00117 DECLARE_SOURCE("$Revision: 1282 $");
00118 
00119 CC_IMPLEMENT_MEMDUMP(CSnap, CC_CLASS_MEMDUMP)
00120 
00121 // Declare smart memory handling in Debug builds
00122 #define new CAM_DEBUG_NEW
00123 
00124 #define DIFF(a, b)  (a > b ? (a - b) : (b - a))
00125 
00126 MILLIPOINT  CSnap::SnapDist = 1;
00127 MILLIPOINT  CSnap::SnapToCoordDist = 1;
00128 BOOL        CSnap::TrySnapToPages = TRUE;
00129 
00130 //----------------------------------------------------------------------------------------
00131 //----------------------------------------------------------------------------------------
00132 
00133 /********************************************************************************************
00134 
00135 >   CSnap::CSnap(DocView* pThisDocView,Spread* pSpread)
00136  
00137     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00138     Created:    20/9/94
00139     Inputs:     pThisDocView - the view in which this snapping is occuring
00140                 pThisSpread  - the spread that constains the objects (grids, guides, etc) to snap to
00141     Purpose:    The constructor.
00142                 At the moment, snapping is controlled on a per-view basis, so a DocView has to 
00143                 be supplied.
00144                 Also, snapping to objects happens on a per-spread basis, hence the need to
00145                 supply a spread.
00146     SeeAlso:    
00147 
00148 ********************************************************************************************/
00149 
00150 CSnap::CSnap(DocView* pThisDocView,Spread* pThisSpread)
00151 {
00152     pDocView = pThisDocView;
00153     pSpread  = pThisSpread;
00154     pLastSnappingObject = NULL;
00155 
00156     CalcSnapDist();
00157 }
00158 
00159 //----------------------------------------------------------------------------------------
00160 //----------------------------------------------------------------------------------------
00161 
00162 /********************************************************************************************
00163 
00164 >   BOOL CSnap::Snap(DocCoord* pDocCoord,
00165                                 BOOL TryMagSnap = TRUE,
00166                                 BOOL TryGridSnap = TRUE)
00167  
00168     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00169     Created:    20/9/94
00170     Inputs:     pDocCoord   = a coord relative to the given spread
00171     Returns:    TRUE    - The coord has been snapped to something
00172                 FALSE   - The coord is untouched by man and beast
00173     Purpose:    Allows you to easily snap a coord to something relevant in the given spread
00174                 (e.g. to a grid, magnetic object, etc).
00175     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00176 
00177 ********************************************************************************************/
00178 
00179 BOOL CSnap::Snap(DocCoord* pDocCoord,
00180                                 BOOL TryMagSnap,
00181                                 BOOL TryGridSnap)
00182 {
00183     ERROR2IF(pDocView==NULL,FALSE,"CSnap::Snap() - pDocView==NULL");
00184     ERROR2IF( pSpread==NULL,FALSE,"CSnap::Snap() - pSpread==NULL");
00185     // This has to be called here so that the static SnapDist member var is
00186     // correct for this CSnap's DocView
00187     CalcSnapDist();
00188 
00189     BOOL Snapped=FALSE;
00190 
00191     // Try snapping to the guidelines on the guide layers
00192     if (!Snapped && pDocView->GetSnapToGuidesState())
00193         Snapped = SnapToGuidelines(pDocCoord);
00194 
00195     // Try snapping to the objects on the guide layers
00196     if (!Snapped && pDocView->GetSnapToGuidesState())
00197         Snapped = SnapToGuideObjects(pDocCoord);
00198 
00199     // Find the state of the snapping flags
00200     BOOL SnapToAllObjs = TryMagSnap && pDocView->GetSnapToObjectsState();       // "Snap to all objects" state
00201     BOOL SnapToMagObjs = TryMagSnap && pDocView->GetSnapToMagObjectsState();    // "Snap to magnetic objects" state
00202 
00203     // Only try and snap to objects if either the flags are set
00204     if (!Snapped && (SnapToAllObjs || SnapToMagObjs))
00205     {
00206         // try and snap to the last object we snapped to
00207         if ((pLastSnappingObject!=NULL)                         &&  // Do we have a last snapped object?
00208             (pLastSnappingObject->FindParent() != NULL)         &&  // Does it have a parent (i.e. not been hidden)?
00209             (TryToSnapToObject(pLastSnappingObject, pDocCoord))
00210            )    
00211         {
00212             Snapped=TRUE;
00213         }
00214         else
00215         {
00216             // We failed to snap to the last object we snapped to, so set the pointer to NULL
00217             pLastSnappingObject = NULL;
00218 
00219             // Only check magnetic objects if the "snap to magnetic objects" flag is TRUE and the 
00220             // "Snap to all objects" flag is FALSE
00221             BOOL Magnetic = (SnapToMagObjs && !SnapToAllObjs);
00222             if (SnapToObjects(pSpread->FindLastChild(), pDocCoord, Magnetic, FALSE))
00223                 Snapped=TRUE;
00224         }
00225     }
00226 
00227     // Try snapping to the page boundaries
00228     if (!Snapped && TrySnapToPages && SnapToAllObjs)
00229         Snapped = SnapToPages(pDocCoord);
00230 
00231     // set a flag to indicate if snapped to an object but not the grid
00232     // for update of magnetic snap indicator
00233     BOOL NonGridSnapped=Snapped;
00234     
00235     // if not already snapped to an object, try to snap to grid
00236     if (!Snapped)
00237         if (TryGridSnap && (pDocView->GetSnapToGridState()) && (SnapToGrids(pDocCoord)))
00238             Snapped=TRUE;
00239 
00240 #if !defined(EXCLUDE_FROM_RALPH)
00241     // update mouse position in StatusLine (with snapped mouse position)
00242     StatusLine* pStatusLine=GetApplication()->GetpStatusLine();
00243     if (pStatusLine)
00244         pStatusLine->UpdateMousePosAndSnap(pDocCoord,pSpread,pDocView,NonGridSnapped);
00245 #endif
00246 
00247     return Snapped;
00248 }
00249  
00250 
00251 /********************************************************************************************
00252 
00253 >   BOOL CSnap::Snap(DocRect* pDocRect, const DocCoord& PrevCoord, const DocCoord& CurCoord);
00254  
00255     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00256     Created:    20/9/94
00257     Inputs:     pDocRect    = a rectangle is spread coords
00258                 PrevCoord   = Used to determine how rect is snapped 
00259                 CurCoord    = As above
00260     Returns:    TRUE    - The rect has been snapped to something
00261                 FALSE   - The rect is untouched by man and beast
00262     Purpose:    Allows you to easily snap a rectangle to objects
00263     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00264 
00265 ********************************************************************************************/
00266 
00267 BOOL CSnap::Snap(DocRect* pDocRect, const DocCoord& PrevCoord, const DocCoord& CurCoord)
00268 {
00269     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00270     if (pDocView == NULL || pSpread == NULL) return FALSE;
00271 
00272     // This has to be called here so that the static SnapDist member var is
00273     // correct for this CSnap's DocView
00274     CalcSnapDist();
00275 
00276     BOOL Snapped = FALSE;
00277 
00278     if (!Snapped && pDocView->GetSnapToGuidesState())
00279         Snapped = SnapToGuidelines(pDocRect,PrevCoord,CurCoord);
00280 
00281     if (!Snapped && pDocView->GetSnapToGuidesState())
00282         Snapped = SnapToGuideObjects(pDocRect,PrevCoord,CurCoord);
00283 
00284     BOOL SnapToAllObjs = pDocView->GetSnapToObjectsState();     // "Snap to all objects" state
00285     BOOL SnapToMagObjs = pDocView->GetSnapToMagObjectsState();  // "Snap to magnetic objects" state
00286 
00287     if (!Snapped)
00288     {
00289         // Only try and snap to objects if either the "snap to all objects" OR "snap to magnetic objects"
00290         // flags are set
00291 
00292         if (SnapToAllObjs || SnapToMagObjs)
00293         {
00294             // Only check magnetic objects if the "snap to magnetic objects" flag is TRUE and the 
00295             // "Snap to all objects" flag is FALSE
00296 
00297             BOOL Magnetic = (SnapToMagObjs && !SnapToAllObjs);
00298 
00299             Snapped = SnapToObjects(pDocRect,PrevCoord,CurCoord,Magnetic,FALSE);
00300         }
00301     }
00302 
00303     // Try snapping to the page boundaries
00304     if (!Snapped && TrySnapToPages && SnapToAllObjs)
00305         Snapped = SnapToPages(pDocRect,PrevCoord,CurCoord);
00306 
00307     // Try and snap to the grids
00308     if (!Snapped && pDocView->GetSnapToGridState())
00309         Snapped = SnapToGrids(pDocRect,PrevCoord,CurCoord);
00310 
00311     return (Snapped);
00312 }
00313  
00314 //----------------------------------------------------------------------------------------
00315 //----------------------------------------------------------------------------------------
00316 
00317 /********************************************************************************************
00318 
00319 >   BOOL CSnap::SnapToPages(DocCoord* pDocCoord)
00320  
00321     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00322     Created:    12/12/95
00323     Inputs:     pDocCoord = a spread coord 
00324     Returns:    TRUE    - The coord has been snapped to a page
00325                 FALSE   - The coord is untouched by man and beast
00326     Purpose:    Allows you to easily snap a coord to a page in a spread
00327 
00328     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00329 
00330 ********************************************************************************************/
00331 
00332 BOOL CSnap::SnapToPages(DocCoord* pDocCoord)
00333 {
00334     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00335     if (pDocView == NULL || pSpread == NULL) return FALSE;
00336 
00337     BOOL Snapped = FALSE;
00338 
00339     Page* pPage = pSpread->FindFirstPageInSpread();
00340     while (pPage != NULL && !Snapped)
00341     {
00342         Snapped = pPage->Snap(pDocCoord);
00343         pPage = pPage->FindNextPage();
00344     }
00345 
00346     return Snapped;
00347 }
00348 
00349 /********************************************************************************************
00350 
00351 >   BOOL CSnap::SnapToPages(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00352  
00353     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00354     Created:    12/12/95
00355     Inputs:     pDocRect  = a spread rect
00356                 PrevCoord = Prev coord of mouse pointer
00357                 CurCoord  = Current coord of mouse pointer
00358     Returns:    TRUE    - The rect has been snapped to a page
00359                 FALSE   - The coord is untouched by man and beast
00360     Purpose:    Allows you to easily snap a coord to a page in a spread
00361 
00362     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00363 
00364 ********************************************************************************************/
00365 
00366 BOOL CSnap::SnapToPages(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00367 {
00368     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00369     if (pDocView == NULL || pSpread == NULL) return FALSE;
00370 
00371     BOOL Snapped = FALSE;
00372 
00373     Page* pPage = pSpread->FindFirstPageInSpread();
00374     while (pPage != NULL && !Snapped)
00375     {
00376         Snapped = pPage->Snap(pDocRect,PrevCoord,CurCoord);
00377         pPage = pPage->FindNextPage();
00378     }
00379 
00380     return Snapped;
00381 }
00382 
00383 //----------------------------------------------------------------------------------------
00384 //----------------------------------------------------------------------------------------
00385 
00386 /********************************************************************************************
00387 
00388 >   BOOL CSnap::SnapToGuidelines(DocCoord* pDocCoord,GuidelineType Type = GUIDELINE_NOTYPE)
00389  
00390     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00391     Created:    5/9/95
00392     Inputs:     pDocCoord = a spread coord 
00393                 Type      = type of guideline to snap to (GUIDELINE_NOTYPE means snap to all types)
00394     Returns:    TRUE    - The coord has been snapped to a guideline
00395                 FALSE   - The coord is untouched by man and beast
00396     Purpose:    Allows you to easily snap a coord to a guideline in a spread
00397 
00398                 When Type == GUIDELINE_NOTYPE:
00399                     It snaps the X ordinate to the vertical rulers, and the Y ordinate to horizontal rulers.
00400                     This also creates the desired effect of making H & V guideline intersection points hot.
00401 
00402                 When Type != GUIDELINE_NOTYPE:
00403                     It snaps the given coord to this type of guideline only.
00404                     (Used by the DocRect snapping version of this func)
00405 
00406     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00407 
00408 ********************************************************************************************/
00409 
00410 BOOL CSnap::SnapToGuidelines(DocCoord* pDocCoord,GuidelineType Type)
00411 {
00412     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00413     if (pDocView == NULL || pSpread == NULL) return FALSE;
00414 
00415     // We haven't snapped yet
00416     BOOL Snapped = FALSE;
00417 
00418     // Scan all layers in the spread
00419     Layer* pLayer = pSpread->FindFirstLayer();
00420     while (pLayer != NULL && !Snapped)
00421     {
00422         if (pLayer->IsGuide() && pLayer->IsVisible())
00423         {
00424             // Only guide layers can contain guidelines
00425 
00426             if (Type == GUIDELINE_NOTYPE)
00427             {
00428                 // OK, try to snap to both H & V guidelines
00429                 Snapped  = SnapToGuidesInLayer(pLayer,pDocCoord,GUIDELINE_HORZ);
00430                 Snapped |= SnapToGuidesInLayer(pLayer,pDocCoord,GUIDELINE_VERT);
00431             }
00432             else
00433                 // Only Snap to guidelines of the given type.
00434                 Snapped  = SnapToGuidesInLayer(pLayer,pDocCoord,Type);
00435         }
00436 
00437         pLayer = pLayer->FindNextLayer();
00438     }
00439 
00440     return Snapped;
00441 }
00442 
00443 /********************************************************************************************
00444 
00445 >   BOOL CSnap::SnapToGuidesInLayer(Layer* pLayer,DocCoord* pDocCoord,GuidelineType Type)
00446  
00447     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00448     Created:    5/9/95
00449     Inputs:     pLayer = ptr to layer
00450                 pDocCoord = ptr to DocCoord to snap
00451                 Type      = the type of guide to snap to (HORZ or VERT)
00452     Returns:    TRUE    - The coord has been snapped to a guideline
00453                 FALSE   - The coord is untouched by man and beast
00454     Purpose:    Helper function that will snap one component of the DocCoord to one type of
00455                 guideline.
00456 
00457                 Only guidelines that are top-level children of pLayer are used
00458 
00459                 The following statements describe how the snapping is performed (though the code
00460                 implements a more general method)
00461 
00462                     if Type == HORZ then the Y coord is snapped to the closest HORZ guideline
00463                     if Type == VERT then the X coord is snapped to the closest VERT guideline
00464 
00465     SeeAlso:    CSnap::SnapToGuidelines(DocCoord* pDocCoord)
00466 
00467 ********************************************************************************************/
00468 
00469 BOOL CSnap::SnapToGuidesInLayer(Layer* pLayer,DocCoord* pDocCoord,GuidelineType Type)
00470 {
00471     ERROR2IF(pLayer    == NULL,FALSE,"pLayer is NULL");
00472     ERROR2IF(pDocCoord == NULL,FALSE,"pDocCoord is NULL");
00473 
00474     BOOL Snapped      = FALSE;
00475     BOOL FirstSnapped = TRUE;
00476 
00477     DocCoord SnappedCoord;          // Holds the snapped version of pDocCoord
00478     DocCoord ClosestSnappedCoord;   // The closest snapped coord to the original coord
00479 
00480     // Scan all top-level objects in the layer for guidelines
00481     Node* pNode = pLayer->FindFirstChild(CC_RUNTIME_CLASS(NodeGuideline));
00482     while (pNode != NULL && !Snapped)
00483     {
00484         NodeGuideline* pGuide = ((NodeGuideline*)pNode);
00485 
00486         if (pGuide->GetType() == Type)
00487         {
00488             // We've found a guideline of the correct type
00489 
00490             // Snap the coord
00491             SnappedCoord = *pDocCoord;
00492             Snapped = pGuide->Snap(&SnappedCoord);
00493 
00494             if (Snapped)
00495             {
00496                 // If it has snapped, make sure our idea of the closest snapped coord is correct
00497                 if (FirstSnapped)
00498                 {
00499                     // If it's the first time we have received a snapped coord, it must be the closest
00500                     ClosestSnappedCoord = SnappedCoord;
00501                     FirstSnapped = FALSE;
00502                 }
00503                 else
00504                 {
00505                     // Is this snapped coord closer to the original coord than the previous closest snapped coord?
00506                     if (pDocCoord->Distance(SnappedCoord) < pDocCoord->Distance(ClosestSnappedCoord))
00507                         ClosestSnappedCoord = SnappedCoord;
00508                 }
00509             }
00510         }
00511 
00512         pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeGuideline));
00513     }
00514 
00515     // Update the supplied coord if we have a snapped version.
00516     if (Snapped)
00517         *pDocCoord = ClosestSnappedCoord;
00518 
00519     return Snapped;
00520 }
00521 
00522 
00523 /********************************************************************************************
00524 
00525 >   BOOL CSnap::SnapToGuidelines(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00526  
00527     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00528     Created:    14/9/95
00529     Inputs:     pDocRect  = a spread rect
00530                 PrevCoord = Prev coord of mouse pointer
00531                 CurCoord  = Current coord of mouse pointer
00532     Returns:    TRUE    - The rect has been snapped to something
00533                 FALSE   - The rect is untouched by man and beast
00534     Purpose:    Allows you to easily snap a rect to a guideline in a spread
00535 
00536                 This will snap the sides of the rect closest to the guidelines on the page.
00537 
00538                 It snaps the H & V sides of the rect independantly, so that the corner of the rect
00539                 will snap into H & V guideline intersection points correctly/
00540 
00541     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00542 
00543 ********************************************************************************************/
00544 
00545 BOOL CSnap::SnapToGuidelines(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00546 {
00547     ERROR2IF(pDocRect == NULL,FALSE,"pDocRect is NULL");
00548 
00549     // This is the amount we will be translating pDocRect by in order to get it to snap
00550     INT32 DeltaX = 0, DeltaY = 0;
00551 
00552     // Copy of the original pDocRect to preserve the original coords
00553     DocRect SnappedRect = *pDocRect;
00554 
00555     //----
00556     // Snap the left or right hand side of the rect
00557     //----
00558 
00559     BOOL SnappedLoX = SnapToGuidelines(&SnappedRect.lo,GUIDELINE_VERT);     // Snap the left hand side
00560     BOOL SnappedHiX = SnapToGuidelines(&SnappedRect.hi,GUIDELINE_VERT);     // Snap the right hand side
00561     
00562     if (SnappedLoX && SnappedHiX)
00563     {
00564         // Did both sides snap? I.e. are both sides very close to a vertical guideline?
00565         // If so, choose to snap the side that's closest to a guideline
00566 
00567         BOOL DeltaLoX = SnappedRect.lo.x - pDocRect->lo.x;
00568         BOOL DeltaHiX = SnappedRect.hi.x - pDocRect->hi.x;
00569 
00570         if (abs(DeltaLoX) < abs(DeltaHiX))
00571             DeltaX = DeltaLoX;
00572         else
00573             DeltaX = DeltaHiX;
00574     }
00575     else if (SnappedLoX)
00576         DeltaX = SnappedRect.lo.x - pDocRect->lo.x;     // Only the left hand side snapped
00577     else if (SnappedHiX)
00578         DeltaX = SnappedRect.hi.x - pDocRect->hi.x;     // Only the right hand side snapped
00579 
00580     //----
00581     // Snap the top or bottom of the rect
00582     //----
00583 
00584     BOOL SnappedLoY = SnapToGuidelines(&SnappedRect.lo,GUIDELINE_HORZ);     // Snap the bottom
00585     BOOL SnappedHiY = SnapToGuidelines(&SnappedRect.hi,GUIDELINE_HORZ);     // Snap the top
00586     
00587     if (SnappedLoY && SnappedHiY)
00588     {
00589         // Did both sides snap? I.e. are both sides very close to a horizontal guideline?
00590         // If so, choose to snap the side that's closest to a guideline
00591 
00592         BOOL DeltaLoY = SnappedRect.lo.y - pDocRect->lo.y;
00593         BOOL DeltaHiY = SnappedRect.hi.y - pDocRect->hi.y;
00594 
00595         if (abs(DeltaLoY) < abs(DeltaHiY))
00596             DeltaY = DeltaLoY;
00597         else
00598             DeltaY = DeltaHiY;
00599     }
00600     else if (SnappedLoY)
00601         DeltaY = SnappedRect.lo.y - pDocRect->lo.y;     // Only the bottom snapped
00602     else if (SnappedHiY)
00603         DeltaY = SnappedRect.hi.y - pDocRect->hi.y;     // Only the top snapped
00604 
00605 
00606     // Did any snapping occur?
00607     BOOL Snapped = (SnappedLoX || SnappedHiX || SnappedLoY || SnappedHiY);
00608 
00609     // If it did, translate pDocRect by the required amount
00610     if (Snapped)
00611         pDocRect->Translate(DeltaX,DeltaY);
00612 
00613     return (Snapped);
00614 }
00615 
00616 //------------------------------------------------------------
00617 //------------------------------------------------------------
00618 
00619 /********************************************************************************************
00620 
00621 >   BOOL CSnap::SnapToGuideObjects(DocCoord* pDocCoord)
00622  
00623     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00624     Created:    19/9/95
00625     Inputs:     pDocCoord = a spread coord 
00626     Returns:    TRUE    - The coord has been snapped to a guideline
00627                 FALSE   - The coord is untouched by man and beast
00628     Purpose:    Allows you to easily snap a coord to objects in guide layers
00629 
00630     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00631 
00632 ********************************************************************************************/
00633 
00634 BOOL CSnap::SnapToGuideObjects(DocCoord* pDocCoord)
00635 {
00636     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00637     if (pDocView == NULL || pSpread == NULL) return FALSE;
00638 
00639     // We haven't snapped yet
00640     BOOL Snapped = FALSE;
00641 
00642     // Scan all layers in the spread
00643     Layer* pLayer = pSpread->FindFirstLayer();
00644     while (pLayer != NULL && !Snapped)
00645     {
00646         // Only snap to objects in visible guide layers
00647         if (pLayer->IsGuide() && pLayer->IsVisible())
00648             Snapped = SnapToObjects(pLayer,pDocCoord,FALSE,TRUE);
00649 
00650         pLayer = pLayer->FindNextLayer();
00651     }
00652 
00653     return Snapped;
00654 }
00655 
00656 /********************************************************************************************
00657 
00658 >   BOOL CSnap::SnapToGuideObjects(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00659  
00660     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00661     Created:    19/9/95
00662     Inputs:     pDocRect  = a spread rect
00663                 PrevCoord = Prev coord of mouse pointer
00664                 CurCoord  = Current coord of mouse pointer
00665     Returns:    TRUE    - The rect has been snapped to a guideline
00666                 FALSE   - The rect  is untouched by man and beast
00667     Purpose:    Allows you to easily snap a rect to objects in guide layers
00668 
00669     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00670 
00671 ********************************************************************************************/
00672 
00673 BOOL CSnap::SnapToGuideObjects(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00674 {
00675     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00676     if (pDocView == NULL || pSpread == NULL) return FALSE;
00677 
00678     // We haven't snapped yet
00679     BOOL Snapped = FALSE;
00680 
00681     // Scan all layers in the spread
00682     Layer* pLayer = pSpread->FindFirstLayer();
00683     while (pLayer != NULL && !Snapped)
00684     {
00685         // Only snap to objects in visible guide layers
00686         if (pLayer->IsGuide() && pLayer->IsVisible())
00687             Snapped = SnapToObjects(pDocRect,PrevCoord,CurCoord,FALSE,TRUE);
00688 
00689         pLayer = pLayer->FindNextLayer();
00690     }
00691 
00692     return Snapped;
00693 }
00694 
00695 //------------------------------------------------------------
00696 //------------------------------------------------------------
00697 
00698 /********************************************************************************************
00699 
00700 >   BOOL CSnap::SnapToGrids(DocCoord* pDocCoord)
00701  
00702     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00703     Created:    20/9/94
00704     Inputs:     pDocCoord = a spread coord 
00705     Returns:    TRUE    - The coord has been snapped to a grid
00706                 FALSE   - The coord is untouched by man and beast
00707     Purpose:    Allows you to easily snap a coord to a grid in a spread
00708     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00709 
00710 ********************************************************************************************/
00711 
00712 BOOL CSnap::SnapToGrids(DocCoord* pDocCoord)
00713 {
00714     // Make sure that we can and should be snapping to grids
00715     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00716     if (pDocView == NULL || pSpread == NULL) return FALSE;
00717 // >>>> Phil says: This isn't needed because the caller always checks this
00718 // >>>> if necessary.
00719 //  if (!pDocView->GetSnapToGridState()) return (FALSE);
00720 
00721     // We haven't snapped yet
00722     BOOL Snapped = FALSE;
00723 
00724     // find the first grid in this layer
00725     Node* pNode = pSpread->FindFirstChild();
00726     if (!pNode->IS_KIND_OF(NodeGrid))
00727         pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeGrid));
00728 
00729     // Get some DocCoords ready
00730     DocCoord SnappedCoord,ClosestSnappedCoord;
00731 
00732     while (pNode != NULL)
00733     {
00734         // We've got a kind of grid
00735         NodeGrid* pNodeGrid = (NodeGrid *)pNode;
00736 
00737         SnappedCoord = *pDocCoord;
00738         if (pNodeGrid->Snap(&SnappedCoord))
00739         {
00740             // We've now got a snapped version of the coord
00741             // Keep the snapped coord that is closest to the original point
00742 
00743             if (Snapped)
00744             {
00745                 if (pDocCoord->Distance(SnappedCoord) < pDocCoord->Distance(ClosestSnappedCoord))
00746                     ClosestSnappedCoord = SnappedCoord;
00747             }
00748             else
00749             {
00750                 ClosestSnappedCoord = SnappedCoord;
00751                 Snapped = TRUE;
00752             }
00753         }
00754         // Get the next node, it could be a grid!
00755         pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeGrid));
00756     }
00757 
00758     if (Snapped)
00759         *pDocCoord = ClosestSnappedCoord;
00760 
00761     return (Snapped);
00762 }
00763 
00764 
00765 
00766 /********************************************************************************************
00767 
00768 >   BOOL CSnap::SnapToGrids(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00769  
00770     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00771     Created:    20/9/94
00772     Inputs:     pDocRect    = a rectangle is spread coords
00773                 PrevCoord   = Used to determine how rect is snapped 
00774                 CurCoord    = As above
00775     Returns:    TRUE    - The rect has been snapped to something
00776                 FALSE   - The rect is untouched by man and beast
00777     Purpose:    Allows you to easily snap a coord to a grid in a spread
00778     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00779 
00780 ********************************************************************************************/
00781 
00782 BOOL CSnap::SnapToGrids(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
00783 {
00784     // Make sure that we can and should be snapping to grids
00785     ERROR3IF(pDocView == NULL || pSpread == NULL,"Invalid DocView and/or spread");
00786     if (pDocView == NULL || pSpread == NULL) return FALSE;
00787     if (!pDocView->GetSnapToGridState()) return (FALSE);
00788 
00789     BOOL Snapped = FALSE;
00790 
00791     // find the first grid in this layer
00792     Node* pNode = pSpread->FindFirstChild();
00793     if (!pNode->IS_KIND_OF(NodeGrid))
00794         pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeGrid));
00795 
00796     DocRect SnappedRect,ClosestSnappedRect;
00797 
00798     while (pNode != NULL)
00799     {
00800         NodeGrid* pNodeGrid = (NodeGrid *)pNode;
00801 
00802         SnappedRect = *pDocRect;
00803         if (pNodeGrid->Snap(&SnappedRect,PrevCoord,CurCoord))
00804         {
00805             if (Snapped)
00806             {
00807                 if (pDocRect->lo.Distance(SnappedRect.lo) < pDocRect->lo.Distance(ClosestSnappedRect.lo))
00808                     ClosestSnappedRect = SnappedRect;
00809             }
00810             else
00811             {
00812                 ClosestSnappedRect = SnappedRect;
00813                 Snapped = TRUE;
00814             }
00815         }
00816         pNode = pNode->FindNext(CC_RUNTIME_CLASS(NodeGrid));
00817     }
00818 
00819     if (Snapped)
00820         *pDocRect = ClosestSnappedRect;
00821 
00822     return (Snapped);
00823 }
00824 
00825 //----------------------------------------------------------------------------------------
00826 //----------------------------------------------------------------------------------------
00827 
00828 /********************************************************************************************
00829 
00830 >   BOOL CSnap::SnapToObjects(Node* pRootNode,DocCoord* pDocCoord,BOOL Magnetic,BOOL GuideLayersOnly)
00831  
00832     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00833     Created:    20/9/94
00834     Inputs:     pRootNode = ptr to root node of sub tree of objects to snap to
00835                 pDocCoord = a spread coord 
00836                 Magnetic  = TRUE  means only snap to magnetic objects
00837                             FALSE means snap to all objects
00838                 GuideLayersOnly = TRUE  means objects on visible guide layers only
00839                                   FALSE means objects on visible layers EXCEPT visible guide layers
00840     Returns:    TRUE    - The coord has been snapped to an object
00841                 FALSE   - The coord is untouched by man and beast
00842     Purpose:    Allows you to snap a coord to an object in a spread.
00843                 This will try and snap the coord to NodeRenderableBounded nodes in the sub-tree
00844                 in the reverse order in which they are rendered.
00845                 Each eligable node is firstly checked to see if the bounds contain the coord.
00846                 If the Magnetic param is TRUE, only NodeRend nodes with their Man
00847     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
00848 
00849 ********************************************************************************************/
00850 
00851 BOOL CSnap::SnapToObjects(Node* pRootNode, DocCoord* pDocCoord, BOOL Magnetic, BOOL GuideLayersOnly)
00852 {
00853     // were we passed rubbish
00854     if (pRootNode==NULL)
00855         return FALSE;
00856 
00857     // Got a real node here. It should be the last child node of the spread
00858     Node* pNode = pRootNode;
00859     BOOL  IsRising = FALSE;
00860 //  BOOL  Snapped = FALSE;
00861 
00862     // Find a DocView
00863     DocView* pDocView = DocView::GetCurrent();
00864     if (pDocView==NULL)
00865         return FALSE;
00866 
00867     // set up an interval timer so we can regularly check if we need to abort
00868     const UINT32 AbortDelay = 100;  // milliseconds
00869     MonotonicTime AbortTimer;
00870     AbortTimer.Sample();
00871 
00872     while (!pNode->IsSpread())
00873     {
00874         // at regular intervals, check to see if we should abort the snap test
00875         if (AbortTimer.Elapsed(AbortDelay))
00876         {
00877             // if mouse moved, abort
00878             if (pDocView->IsMouseMoved())
00879                 return FALSE;
00880 
00881             // also abort if the mouse is no longer of the docview
00882 PORTNOTE("Snap", "Removed use of GetMousePosAndWindowID to abort snap processing")
00883 #if !defined(EXCLUDE_FROM_XARALX)
00884             CWindowID WinID;
00885             WinCoord  WndPos;
00886             BOOL      MouseOK = CCamApp::GetMousePosAndWindowID( &WinID, &WndPos );
00887             if( MouseOK && WinID != NULL && 
00888                 pDocView != CCamView::GetDocViewFromWindowID( WinID ) )
00889                 return FALSE;
00890 #endif
00891 
00892             // resample timer
00893             AbortTimer.Sample();
00894         }
00895 
00896 
00897 //          while (pNode->IsLayer() &&
00898 //                 (!(((Layer *)pNode)->IsVisible()) || (GuideLayersOnly && ((Layer*)pNode)->IsGuide()))
00899 //                )
00900 
00901         // We need to skip ALL unsuitable layers, so repeat until we find a layer we can snap to
00902         // A suitable layer has to be visible.
00903         // If 'GuideLayersOnly' flag is set, it also has to be a guide layer
00904 
00905         // Assume the layer is not suitable
00906         BOOL SuitableLayer = FALSE;
00907 
00908         // If we have found a layer, and it's not suitable, keep searching until we find one we like
00909         while (pNode->IsLayer() && !SuitableLayer)
00910         {
00911             Layer* pLayer = (Layer*)pNode;
00912 
00913             BOOL Visible = pLayer->IsVisible();                 // Is layer visible?
00914 
00915             if (GuideLayersOnly)                                // Guide layers only?
00916                 SuitableLayer = Visible && pLayer->IsGuide();   // Suitable if visible & guide layer
00917             else
00918                 SuitableLayer = Visible && !pLayer->IsGuide();  // Else, suitable if visible & NOT guide layer
00919 
00920             if (!SuitableLayer)
00921             {
00922                 // This layer is not suitable, so skip it
00923                 if (pNode->FindPrevious() != NULL)
00924                     pNode = pNode->FindPrevious();
00925                 else
00926                 {
00927                     pNode = pNode->FindParent();
00928                     IsRising = TRUE;    // If we haven't hit a spread, then we'd better make sure
00929                                         // that the next if statement does the right thing
00930                 }
00931 
00932                 // See if we have come back to the spread
00933                 if (pNode == NULL || pNode->IsSpread())
00934                     return FALSE;
00935             }
00936         }
00937 
00938         if (!IsRising)
00939         {
00940             // Get the last most child from this node
00941             if (pNode->ShouldBeRendered())
00942             {
00943                 while (pNode->FindFirstChild()!=NULL)
00944                 {
00945                     // Get the last node in the sibling list
00946                     pNode = pNode->FindLastChild();
00947 
00948                     // If it was NULL then something odd has happened, so fail
00949                     if (pNode==NULL)
00950                         return FALSE;
00951                 }
00952             }
00953         }
00954 
00955         // Test this node for magnetic snapping
00956         if (pNode->ShouldBeRendered())
00957         {       
00958             if (TryToSnapToObject(pNode, pDocCoord))
00959             {
00960                 // This node snapped. Note the node so we can try again next time
00961                 pLastSnappingObject = pNode;
00962                 return TRUE;
00963             }
00964         }
00965 
00966         // It did not snap to that node, so find the previous one
00967         if (pNode->FindPrevious()!=NULL)
00968         {
00969             // find the node before this one
00970             pNode = pNode->FindPrevious();
00971             IsRising = FALSE;
00972         }
00973         else
00974         {
00975             // run out of nodes, so find the parent and flag that
00976             // we are going up in the tree
00977             pNode = pNode->FindParent();
00978             IsRising = TRUE;
00979         }
00980     } 
00981 
00982     // No nodes snapped to the coord
00983     return FALSE;
00984 }
00985 
00986 
00987 /********************************************************************************************
00988 
00989 >   BOOL CSnap::TryToSnapToObject(Node* pNode, DocCoord* pDocCoord)
00990 
00991     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00992     Created:    31/1/95
00993     Inputs:     pNode - The node to try and snap to
00994                 pDocCoord - The coord to snap
00995     Returns:    TRUE if it snapped the object to the coord, FALSE if it failed to snap
00996     Purpose:    Allows a test to see if a particular node snaps to a particaular coord.
00997 
00998 ********************************************************************************************/
00999 
01000 BOOL CSnap::TryToSnapToObject(Node* pNode, DocCoord* pDocCoord)
01001 {
01002     // Test this node for magnetic snapping
01003     if (pNode->IsBounded())
01004     {
01005         // Convert it to a RenderableBounded
01006         NodeRenderableBounded* pNodeRndBnd = (NodeRenderableBounded*) pNode;
01007 
01008         // Don't allow snapping to dragged nodes...
01009         if (pNodeRndBnd->IsDragged())
01010             return FALSE;
01011 
01012         // Firstly, inflate the bounds by the size of the snapping distance
01013         DocRect Bounds = pNodeRndBnd->GetBoundingRect();
01014         if (CSnap::SnapDist > CSnap::SnapToCoordDist)
01015             Bounds.Inflate(CSnap::SnapDist);
01016         else
01017             Bounds.Inflate(CSnap::SnapToCoordDist);
01018 
01019         // If the coord lies inside the inflated bounds of the node, try and snap to the object
01020         if (Bounds.ContainsCoord(*pDocCoord))
01021         {
01022             // Try to snap to the more significant points on the node
01023             if (pNodeRndBnd->SnapToCoords(pDocCoord))
01024                 return TRUE;
01025 
01026             // It failed, so try and snap to the outline of the shape
01027             if (pNodeRndBnd->Snap(pDocCoord))
01028                 return TRUE;
01029         }
01030     }
01031 
01032     // It did not snap to anything
01033     return FALSE;
01034 }
01035 
01036 /********************************************************************************************
01037 
01038 >   BOOL CSnap::SnapToObjects(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord,BOOL Magnetic,BOOL GuideLayersOnly)
01039  
01040     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01041     Created:    20/9/94
01042     Inputs:     pDocRect    = a rectangle is spread coords
01043                 PrevCoord   = Used to determine how rect is snapped 
01044                 CurCoord    = As above
01045                 Magnetic    = TRUE  means only snap to magnetic objects
01046                               FALSE means snap to all objects
01047                 GuideLayersOnly = TRUE  means ignore objects on guide layers
01048                                   FALSE means treat guide layers as standard layers
01049     Returns:    TRUE    - The rect has been snapped to an object
01050                 FALSE   - The rect is untouched by man and beast
01051     Purpose:    Allows you to easily snap a coord to an object in a spread
01052     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
01053 
01054 ********************************************************************************************/
01055 
01056 BOOL CSnap::SnapToObjects(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord,BOOL Magnetic,BOOL GuideLayersOnly)
01057 {
01058     return FALSE;
01059 }
01060 
01061 //----------------------------------------------------------------------------------------
01062 //----------------------------------------------------------------------------------------
01063 
01064 /********************************************************************************************
01065 
01066 >   void CSnap::CalcSnapDist()
01067  
01068     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01069     Created:    22/9/94
01070     Purpose:    Calculates the snapping distance to objects for this CSnap object's DocView.
01071                 Uses the DocView's scale factor as a parameter, so this should be called
01072                 every time the DocView's scale factor changes
01073 
01074 ********************************************************************************************/
01075 
01076 void CSnap::CalcSnapDist()
01077 {
01078     // Find out the Magnetic Line Radius preference from its owner
01079     INT32 MagneticRad = NodeRenderableBounded::MagneticLineRadius;
01080     INT32 PointRad = NodeRenderableBounded::MagneticPointRadius;
01081 
01082     // Scale it according to the ScaleFactor.
01083     if (pDocView!=NULL)
01084     {
01085         // Get the Scale factor and modify the magnetic radius
01086         double Scale = pDocView->GetViewScale().MakeDouble();
01087 
01088         MagneticRad = (INT32) ((double)MagneticRad / Scale);
01089         PointRad = (INT32) ((double)PointRad / Scale);
01090     }
01091 
01092     // Set the snapping distance to the (hopefully) modified magnetic radius
01093     SnapDist = MagneticRad;
01094     SnapToCoordDist = PointRad;
01095 }
01096 
01097 
01098 
01099 /********************************************************************************************
01100 >   static BOOL CSnap::SnapCoordToPath(DocCoord* pDocCoord, Path* pPath)
01101 
01102     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01103     Created:    19/10/95
01104     Inputs:     pDocCoord   = a coord in Spread coords
01105                 pPath - the path it should be snapped to
01106     Outputs:    pDocCoord will hiold the snapped coodinate, if snapped
01107     Returns:    TRUE    - the DocCoord has been snapped to the path.
01108                 FALSE   - the DocCoord has not been snapped
01109     Purpose:    Common code called by a number of Nodes Snap(DocCoord*) functions.  Attempts
01110                 to snap a coord onto a path
01111 ********************************************************************************************/
01112 BOOL CSnap::SnapCoordToPath(DocCoord* pDocCoord, Path* pPath)
01113 {
01114     BOOL Snapped = FALSE;
01115 
01116     MILLIPOINT SnapDist    = CSnap::GetSnapDist();
01117     MILLIPOINT SqrSnapDist = SnapDist*SnapDist;
01118 
01119     INT32 NearEl = 0;
01120     double mu = 0;
01121     double SqrDist = pPath->SqrDistanceToPoint(*pDocCoord, &NearEl, &mu);
01122 
01123     if (SqrDist <= SqrSnapDist)
01124     {
01125         *pDocCoord = pPath->ClosestPointTo(mu, NearEl);
01126         Snapped = TRUE;
01127     }
01128 
01129     return (Snapped);
01130 }
01131 
01132 
01133 
01134 /********************************************************************************************
01135 
01136 >   static BOOL CSnap::SnapRectToRect(DocRect* pSnappedRect, const DocRect& RefRect)
01137 
01138     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01139     Created:    26/10/1999
01140     Inputs:     pSnappedRect    pointer to the rectangle which will be snapped.
01141                 RefRect         the reference rectangle, to snap to.
01142     Outputs:    pSnappedRect may be snapped to RefRect.
01143     Returns:    TRUE if pSnappedRect was snapped,
01144                 FALSE otherwise.
01145     Purpose:    Snap a rectangle so that it lines up with one or more sides of another
01146                 rectangle. This will only happen if the first rectangle is close to the
01147                 second rectangle.
01148     Errors:     ERROR2 if pSnappedRect is NULL.
01149     See also:   
01150 
01151 ********************************************************************************************/
01152 BOOL CSnap::SnapRectToRect(DocRect* pSnappedRect, const DocRect& RefRect)
01153 {
01154     // validate input.
01155     ERROR2IF(pSnappedRect == NULL, FALSE, "CSnap::SnapRectToRect- NULL pSnappedRect.");
01156 
01157     // before we start doing loads of snap-testing, we need to check that the two rectangles
01158     // are close enough together.
01159     DocRect TestIntersect = *pSnappedRect;
01160     TestIntersect.Inflate(SnapDist);
01161     if (!TestIntersect.IsIntersectedWith(RefRect))
01162         return FALSE;
01163 
01164     // try to snap the y-coordinates of pSnappedRect to those of RefRect.
01165     // order of snap-attempts goes:
01166     //
01167     //      top-to-top, bottom-to-bottom, bottom-to-top, top-to-bottom
01168     //
01169     // ,where we are snapping y-values in pSnappedRect-to-RefRect.
01170     BOOL bSnappedY = FALSE;
01171     if (!bSnappedY) bSnappedY = SnapToValue(RefRect.hi.y, &(pSnappedRect->hi.y), &(pSnappedRect->lo.y));
01172     if (!bSnappedY) bSnappedY = SnapToValue(RefRect.lo.y, &(pSnappedRect->lo.y), &(pSnappedRect->hi.y));
01173     if (!bSnappedY) bSnappedY = SnapToValue(RefRect.hi.y, &(pSnappedRect->lo.y), &(pSnappedRect->hi.y));
01174     if (!bSnappedY) bSnappedY = SnapToValue(RefRect.lo.y, &(pSnappedRect->hi.y), &(pSnappedRect->lo.y));
01175 
01176     // try to snap the x-coordinates of pSnappedRect to those of RefRect.
01177     // order of snap-attempts goes:
01178     //
01179     //      left-to-left, right-to-right, left-to-right, right-to-left
01180     //
01181     // ,where we are snapping x-values in pSnappedRect-to-RefRect.
01182     BOOL bSnappedX = FALSE;
01183     if (!bSnappedX) bSnappedX = SnapToValue(RefRect.lo.x, &(pSnappedRect->lo.x), &(pSnappedRect->hi.x));
01184     if (!bSnappedX) bSnappedX = SnapToValue(RefRect.hi.x, &(pSnappedRect->hi.x), &(pSnappedRect->lo.x));
01185     if (!bSnappedX) bSnappedX = SnapToValue(RefRect.hi.x, &(pSnappedRect->lo.x), &(pSnappedRect->hi.x));
01186     if (!bSnappedX) bSnappedX = SnapToValue(RefRect.lo.x, &(pSnappedRect->hi.x), &(pSnappedRect->lo.x));
01187 
01188     // return the result.
01189     return bSnappedY || bSnappedX;
01190 }
01191 
01192 
01193 
01194 /********************************************************************************************
01195 
01196 >   static BOOL CSnap::SnapValues(const INT32 RefValue, INT32* pTestValue, INT32* pLockedValue)
01197 
01198     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01199     Created:    26/10/1999
01200     Inputs:     RefValue        a reference INT32 to snap to.
01201                 pTestValue      pointer to a INT32 to snap to RefValue.
01202                 pLockedValue    pointer to a INT32 whose behaviour is locked with pTestValue's
01203     Outputs:    The values referred to by pTestValue, pLockedValue may be changed, in which
01204                 case this function will return TRUE.
01205     Returns:    TRUE if the given variable values were sucessfully snapped to the reference,
01206                 FALSE otherwise.
01207     Purpose:    Given a reference and pointers to two variable values, this function attempts
01208                 to snap the first variable value to the reference, and if successful adjusts
01209                 the second variable value by the same amount as the first.
01210     Errors:     ERROR3 if either of the variable-value pointers is NULL.
01211                 In release builds, just returns FALSE if this is the case.
01212     See also:   
01213 
01214 ********************************************************************************************/
01215 BOOL CSnap::SnapToValue(const INT32 RefValue, INT32* pTestValue, INT32* pLockedValue)
01216 {
01217     if (pTestValue == NULL || pLockedValue == NULL)
01218     {
01219         ERROR3("CSnap::SnapValues- NULL parameters");
01220         return FALSE;
01221     }
01222 
01223     if ((*pTestValue) > RefValue && ((*pTestValue) - RefValue) <= SnapDist)
01224     {
01225         (*pLockedValue) -= ((*pTestValue) - RefValue);
01226         (*pTestValue) = RefValue;
01227         return TRUE;
01228     }
01229     else if ((*pTestValue) < RefValue && (RefValue - (*pTestValue)) <= SnapDist)
01230     {
01231         (*pLockedValue) += (RefValue - (*pTestValue));
01232         (*pTestValue) = RefValue;
01233         return TRUE;
01234     }
01235 
01236     return FALSE;
01237 }

Generated on Sat Nov 10 03:47:03 2007 for Camelot by  doxygen 1.4.4