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 }