00001 // $Id: docview.cpp 1729 2006-08-30 12:48:48Z luke $ 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 00099 /******************************************************************************************** 00100 DocView.CPP - DocView class definition file. 00101 00102 This is the Camelot document viewer object. 00103 00104 ********************************************************************************************/ 00105 00106 #include "camtypes.h" 00107 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 #include "camview.h" 00109 #include "vstate.h" 00110 #include "wrkrect.h" 00111 //#include "tool.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00112 #include "toollist.h" 00113 //#include "monotime.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00114 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 #include "osrndrgn.h" 00116 #include "grndrgn.h" 00117 #include "paper.h" 00118 //#include "oilcoord.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00119 //#include "doccoord.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00120 //#include "winrect.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00121 //#include "oilrect.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00122 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00123 //#include "mario.h" 00124 //#include "will.h" 00125 #include "camelot.h" // For DisableSys flag 00126 #include "ccdc.h" 00127 #include "csrstack.h" 00128 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00129 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00130 #include "nodedoc.h" 00131 #include "chapter.h" 00132 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00133 #include "page.h" 00134 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00135 #include "blobs.h" 00136 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00137 #include "snap.h" 00138 //#include "progress.h" 00139 #include "lineattr.h" 00140 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00141 #include "nodepath.h" 00142 #include "nodeshap.h" 00143 #include "nodershp.h" 00144 //#include "dragcol.h" 00145 //#include "mainfrm.h" 00146 #include "zoomops.h" 00147 #include "viewmenu.h" 00148 #include "menuops.h" 00149 //#include "clikmods.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00150 #include "nodetext.h" 00151 #include "nodetxts.h" 00152 #include "rulers.h" 00153 #include "dlgmgr.h" 00154 //#include "bubbleid.h" 00155 //#include "filters.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00156 #include "keypress.h" 00157 #include "nodebev.h" 00158 00159 // for shadow node hit-testing 00160 #include "nodecont.h" 00161 #include "nodeshad.h" 00162 #include "nbevcont.h" 00163 00164 #include "pushtool.h" // For OpPush 00165 //#include "bars.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00166 00167 #ifdef PHOTOSHOPPLUGINS 00168 #include "plugmngr.h" // CheckHaveDetailsOnPlugIns 00169 #endif //PHOTOSHOPPLUGINS 00170 00171 //#include "resource.h" // Matt 12/01/2001 - For _R(IDC_PUSHTOOLCURSOR) 00172 00173 #include "colplate.h" // For on-screen separated rendering 00174 00175 #include "rendwnd.h" // Shouldn't need this 00176 #include "draginfo.h" 00177 00178 DECLARE_SOURCE("$Revision: 1729 $"); 00179 00180 00181 // Used by SpreadRedraws class. 00182 #define MAX_REDRAW_REGIONS (20) 00183 00184 /******************************************************************************************** 00185 00186 > class SpreadRedraws : public ListItem 00187 00188 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00189 Created: 22/12/94 00190 Purpose: Encapsulates a set of regions on a spread, which must be accumulated in order 00191 for them to be redrawn at some point, possibly all in one go. This class 00192 chooses the most efficient invalidation method, according to the number 00193 and nature of regions added. 00194 SeeAlso: PendingRedraws 00195 00196 ********************************************************************************************/ 00197 00198 class SpreadRedraws : public ListItem 00199 { 00200 CC_DECLARE_MEMDUMP(SpreadRedraws); 00201 00202 public: 00203 SpreadRedraws(Spread*); 00204 00205 Spread *GetSpread() { return pInvalidSpread; } 00206 void AddInvalidRegion(DocRect, Node* pInvalidNode); 00207 void FlushRedraw(DocView*); 00208 void ClearBackmostChangedNode(Node* pNode); 00209 00210 private: 00211 Spread *pInvalidSpread; 00212 UINT32 RectCount; 00213 BOOL TooManyRegions; 00214 DocRect InvalidRegions[MAX_REDRAW_REGIONS]; 00215 Node* m_pBackmostChangedNode; 00216 }; 00217 00218 00219 00220 CC_IMPLEMENT_MEMDUMP(PendingRedraws, List) 00221 CC_IMPLEMENT_MEMDUMP(SpreadRedraws, ListItem) 00222 CC_IMPLEMENT_DYNAMIC(DocView, View) 00223 CC_IMPLEMENT_DYNAMIC(DocViewMsg, Msg) 00224 CC_IMPLEMENT_DYNCREATE(OpToggleFore, Operation) 00225 CC_IMPLEMENT_DYNCREATE(OpToggleScroll, Operation) 00226 CC_IMPLEMENT_DYNCREATE(OpToggleSolidDrag, Operation) 00227 00228 00229 #define new CAM_DEBUG_NEW 00230 00231 00232 00233 //-----------------------------------------------------------------------------------------// 00234 // Swap macro 00235 // this is too beautiful to work! (This is too obscure to be worth it!) 00236 00237 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b)) 00238 00239 00240 00241 // ******************************************************* 00242 // MIN and MAX Macros - These should not be here, I'm sure 00243 00244 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 00245 #define MAX(a, b) ((a) < (b) ? (b) : (a)) 00246 00247 // ******************************************************* 00248 00249 00250 00251 //-----------------------------------------------------------------------------------------// 00252 // Initialise class static variables... 00253 // 00254 DocView* DocView::Selected = NULL; 00255 00256 INT32 DocView::OnTopCount = 0; 00257 OnTopCode DocView::OnTopReason = Normal; 00258 Spread* DocView::OnTopSpread = NULL; 00259 RenderRegion* DocView::OnTopRenderRegion = NULL; 00260 00261 00262 /******************************************************************************************** 00263 00264 Preference: ConstrainAngle 00265 Section: Constraints 00266 Range: >0 ---> <2PI 00267 Purpose: This is the default angle to which angles are constrained to (eg when 00268 rotating with constrain on, it will only rotate in multiples of this 00269 constrain angle. It must be greater than zero degrees and less than 00270 360 degrees (note that it is recorded in radians). 00271 00272 ********************************************************************************************/ 00273 00274 double DocView::DefaultConstrainAngle = PI / 4.0; 00275 00276 00277 /******************************************************************************************** 00278 00279 Preference: BackgroundRendering 00280 Section: Rendering 00281 Range: 0 or 1 00282 Purpose: Defines whether or not to use background rendering on new views. 00283 0 => No background rendering 00284 1 => Use background rendering 00285 00286 ********************************************************************************************/ 00287 00288 BOOL DocView::BackgroundRendering = TRUE; 00289 00290 00291 //-----------------------------------------------------------------------------------------// 00292 00293 00294 00295 /******************************************************************************************** 00296 00297 Preference: SolidDragging 00298 Section: Dragging 00299 Range: 0 or 1 00300 Purpose: Defines whether or not solid dragging is enabled. 00301 0 => Solid dragging disabled 00302 1 => Solid dragging enabled 00303 00304 ********************************************************************************************/ 00305 00306 BOOL DocView::SolidDragging = TRUE; 00307 00308 00309 //-----------------------------------------------------------------------------------------// 00310 00311 00312 00313 /******************************************************************************************** 00314 00315 Preference: IdleDragDelay 00316 Section: Dragging 00317 Range: 0 to 10000 00318 Purpose: Defines delay time in milliseconds between detecting idle state and showing 00319 extra dragging info. 00320 00321 ********************************************************************************************/ 00322 00323 UINT32 DocView::IdleDragDelay = 200; 00324 00325 00326 //-----------------------------------------------------------------------------------------// 00327 00328 00329 00330 /******************************************************************************************** 00331 00332 Preference: IdleDragDelay2 00333 Section: Dragging 00334 Range: 0 to 10000 00335 Purpose: Defines delay time in milliseconds between detecting idle state and showing 00336 extra dragging info. 00337 00338 ********************************************************************************************/ 00339 00340 UINT32 DocView::IdleDragDelay2 = 1000; 00341 00342 00343 //-----------------------------------------------------------------------------------------// 00344 00345 00346 00347 /******************************************************************************************** 00348 00349 Preference: SolidDragTimeLimit 00350 Section: Dragging 00351 Range: 0 to 10000 00352 Purpose: Defines time limit in milliseconds for solid drag redraw. When redraw takes 00353 longer than this value, dragging falls back to outline mode 00354 00355 ********************************************************************************************/ 00356 00357 UINT32 DocView::SolidDragTimeLimit = 333; 00358 00359 00360 //-----------------------------------------------------------------------------------------// 00361 00362 00363 00364 /******************************************************************************************** 00365 00366 Preference: OriginOutlineShowNonOverlap 00367 Section: Dragging 00368 Range: 0 or 1 00369 Purpose: Original outlines will be shown as soon as dragged items don't overlap 00370 originals. 00371 00372 ********************************************************************************************/ 00373 00374 BOOL DocView::OriginOutlineShowNonOverlap = FALSE; 00375 00376 00377 //-----------------------------------------------------------------------------------------// 00378 00379 00380 00381 /******************************************************************************************** 00382 00383 Preference: OriginOutlineShowAlways 00384 Section: Dragging 00385 Range: 0 or 1 00386 Purpose: Original outlines will be shown as soon as dragged items don't overlap 00387 originals. 00388 00389 ********************************************************************************************/ 00390 00391 BOOL DocView::OriginOutlineShowAlways = FALSE; 00392 00393 00394 //-----------------------------------------------------------------------------------------// 00395 00396 00397 00398 /******************************************************************************************** 00399 00400 Preference: OutlineShowBounds 00401 Section: Dragging 00402 Range: 0 or 1 00403 Purpose: Dragged outlines will show a bounding rectangle. 00404 00405 ********************************************************************************************/ 00406 00407 BOOL DocView::OutlineShowBounds = TRUE; 00408 00409 00410 //-----------------------------------------------------------------------------------------// 00411 00412 00413 00414 /******************************************************************************************** 00415 00416 > SpreadRedraws::SpreadRedraws(Spread *pSpread) 00417 00418 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00419 Created: 22/12/94 00420 Inputs: pSpread - the spread on which invalid regions will occur. 00421 Purpose: Construct a spread redraw regions object for a given spread. The invalid 00422 region is initially NULL. 00423 SeeAlso: SpreadRedraws; PendingRedraws 00424 00425 ********************************************************************************************/ 00426 00427 SpreadRedraws::SpreadRedraws(Spread *pSpread) 00428 { 00429 pInvalidSpread = pSpread; 00430 RectCount = 0; 00431 TooManyRegions = FALSE; 00432 m_pBackmostChangedNode = NULL; 00433 } 00434 00435 /******************************************************************************************** 00436 00437 > void SpreadRedraws::AddInvalidRegion(DocRect Rect, Node* pInvalidNode) 00438 00439 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00440 Created: 22/12/94 00441 Inputs: Rect - the region to add (in document co-ordinates) 00442 Purpose: Add another invalid region to the collection of regions for a spread. 00443 SeeAlso: SpreadRedraws; PendingRedraws 00444 00445 ********************************************************************************************/ 00446 00447 void SpreadRedraws::AddInvalidRegion(DocRect Rect, Node* pInvalidNode) 00448 { 00449 if (pInvalidNode!=NULL) 00450 if (m_pBackmostChangedNode==NULL || pInvalidNode->IsUnder(m_pBackmostChangedNode)) m_pBackmostChangedNode = pInvalidNode; 00451 00452 if (TooManyRegions) 00453 { 00454 // We have exceeded the maximum number of inidividual regions, so we just 00455 // union them all together. 00456 InvalidRegions[0] = InvalidRegions[0].Union(Rect); 00457 } 00458 else 00459 { 00460 // Have we just exceeded the maximum number of regions? 00461 if (RectCount == MAX_REDRAW_REGIONS) 00462 { 00463 // Yes - gather all the existing regions together into one. 00464 for (INT32 i = 1; i < MAX_REDRAW_REGIONS; i++) 00465 { 00466 InvalidRegions[0] = InvalidRegions[0].Union(InvalidRegions[i]); 00467 } 00468 00469 // Now merge the new region in 00470 InvalidRegions[0] = InvalidRegions[0].Union(Rect); 00471 00472 // Indicate that we have too many regions 00473 RectCount = 1; 00474 TooManyRegions = TRUE; 00475 } 00476 else 00477 { 00478 // Otherwise, just add region to the array 00479 InvalidRegions[RectCount] = Rect; 00480 RectCount++; 00481 } 00482 } 00483 } 00484 00485 /******************************************************************************************** 00486 00487 > void SpreadRedraws::ClearBackMostChangedNode(Node* pNode) 00488 00489 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00490 Created: 22/12/94 00491 Inputs: Rect - the region to add (in document co-ordinates) 00492 Purpose: Add another invalid region to the collection of regions for a spread. 00493 SeeAlso: SpreadRedraws; PendingRedraws 00494 00495 ********************************************************************************************/ 00496 00497 void SpreadRedraws::ClearBackmostChangedNode(Node* pNode) 00498 { 00499 if (pNode && (m_pBackmostChangedNode==pNode || pNode->IsNodeInSubtree(m_pBackmostChangedNode))) 00500 m_pBackmostChangedNode = pNode->FindParentSpread(); 00501 } 00502 00503 /******************************************************************************************** 00504 00505 > void SpreadRedraws::FlushRedraw(DocView *pDocView) 00506 00507 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00508 Created: 22/12/94 00509 Inputs: pDocView - the DocView to invalidate 00510 Purpose: Force the specified DocView to immediately update all the regions 00511 encapsulated by this object. 00512 SeeAlso: SpreadRedraws; PendingRedraws 00513 00514 ********************************************************************************************/ 00515 00516 void SpreadRedraws::FlushRedraw(DocView *pDocView) 00517 { 00518 // Cause an immediate update of the DocView 00519 for (UINT32 i = 0; i < RectCount; i++) 00520 { 00521 // For the moment, assume that pending redraws must have been due to editing... 00522 pDocView->ForceRedraw(pInvalidSpread, InvalidRegions[i], FALSE, m_pBackmostChangedNode); 00523 } 00524 } 00525 00526 00527 /******************************************************************************************** 00528 00529 > PendingRedraws::PendingRedraws() 00530 00531 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00532 Created: 22/12/94 00533 Purpose: Initialise a PendingRedraws object. 00534 SeeAlso: SpreadRedraws; PendingRedraws 00535 00536 ********************************************************************************************/ 00537 00538 PendingRedraws::PendingRedraws() 00539 { 00540 } 00541 00542 00543 /******************************************************************************************** 00544 00545 > PendingRedraws::~PendingRedraws() 00546 00547 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00548 Created: 22/12/94 00549 Purpose: Destroys a PendingRedraws object. 00550 SeeAlso: SpreadRedraws; PendingRedraws 00551 00552 ********************************************************************************************/ 00553 00554 PendingRedraws::~PendingRedraws() 00555 { 00556 DeleteAll(); 00557 } 00558 00559 00560 /******************************************************************************************** 00561 00562 > BOOL PendingRedraws::AddInvalidRegion(Spread *pSpread, DocRect Rect, Node* pInvalidNode) 00563 00564 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00565 Created: 22/12/94 00566 Inputs: pSpread - the spread on which the invalid region is located. 00567 Rect - the invalid region (in document co-ordinates) 00568 Returns: TRUE if added ok; 00569 FALSE if not 00570 Purpose: Add another invalid region to the specified Spread's collection. 00571 Errors: Out of memory => ERROR1 00572 SeeAlso: SpreadRedraws; PendingRedraws 00573 00574 ********************************************************************************************/ 00575 00576 BOOL PendingRedraws::AddInvalidRegion(Spread *pSpread, DocRect Rect, Node* pInvalidNode) 00577 { 00578 // Look for this spread in our list 00579 SpreadRedraws *pItem = (SpreadRedraws *) GetHead(); 00580 00581 while ((pItem != NULL) && (pItem->GetSpread() != pSpread)) 00582 { 00583 // Nope - try next item 00584 pItem = (SpreadRedraws *) GetNext(pItem); 00585 } 00586 00587 if (pItem == NULL) 00588 { 00589 // No entry for the spread - we'd better make one 00590 pItem = new SpreadRedraws(pSpread); 00591 00592 // Did it work? 00593 if (pItem == NULL) 00594 return FALSE; 00595 00596 // Yes - add to the list 00597 AddTail(pItem); 00598 } 00599 00600 // Got an an entry for this spread - add the region 00601 pItem->AddInvalidRegion(Rect, pInvalidNode); 00602 00603 // All ok 00604 return TRUE; 00605 } 00606 00607 /******************************************************************************************** 00608 00609 > void PendingRedraws::FlushRedraw(DocView *pDocView) 00610 00611 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00612 Created: 22/12/94 00613 Inputs: pDocView - the DocView to invalidate. 00614 Purpose: Cause all pending update regions on all spreads for this DocView to be 00615 updated immediately. 00616 SeeAlso: SpreadRedraws; PendingRedraws 00617 00618 ********************************************************************************************/ 00619 00620 void PendingRedraws::FlushRedraw(DocView *pDocView) 00621 { 00622 // Invalidate the regions on each spread... 00623 SpreadRedraws *pItem = (SpreadRedraws *) GetHead(); 00624 00625 while (pItem != NULL) 00626 { 00627 // Invalid the regions on this spread, and delete this item 00628 pItem->FlushRedraw(pDocView); 00629 delete RemoveItem(pItem); 00630 00631 // Now try the next item... 00632 pItem = (SpreadRedraws *) GetHead(); 00633 } 00634 } 00635 00636 00637 /******************************************************************************************** 00638 00639 > void PendingRedraws::HanldeNodeDeletion(Node* pNode) 00640 00641 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00642 Created: 22/12/94 00643 Inputs: pDocView - the DocView to invalidate. 00644 Purpose: Cause all pending update regions on all spreads for this DocView to be 00645 updated immediately. 00646 SeeAlso: SpreadRedraws; PendingRedraws 00647 00648 ********************************************************************************************/ 00649 00650 void PendingRedraws::HandleNodeDeletion(Node* pNode) 00651 { 00652 // Invalidate the regions on each spread... 00653 SpreadRedraws *pItem = (SpreadRedraws *) GetHead(); 00654 00655 while (pItem != NULL) 00656 { 00657 pItem->ClearBackmostChangedNode(pNode); 00658 00659 // Now try the next item... 00660 pItem = (SpreadRedraws *) this->GetNext(pItem); 00661 } 00662 } 00663 00664 00665 /******************************************************************************************** 00666 00667 > static BOOL DocView::DeclarePreferences() 00668 00669 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00670 Created: 19/10/94 00671 Returns: TRUE if it worked, FALSE if it failed 00672 Purpose: Declares any preferences that the DocView class needs to decalre 00673 00674 ********************************************************************************************/ 00675 00676 BOOL DocView::DeclarePreferences() 00677 { 00678 // NB. Constrain angle must be between 1 and 359 degrees. 00679 return GetApplication()->DeclareSection(TEXT("Constraints"), 1) 00680 && GetApplication()->DeclarePref(TEXT("Constraints"), TEXT("Constrain Angle"), 00681 &DefaultConstrainAngle, 00682 (2 * PI) / 360, ((2 * PI) * 359) / 360) 00683 00684 && GetApplication()->DeclareSection(TEXT("Rendering"), 2) 00685 && GetApplication()->DeclarePref(TEXT("Rendering"), TEXT("BackgroundRendering"), 00686 &BackgroundRendering, FALSE, TRUE) 00687 00688 && GetApplication()->DeclareSection(TEXT("AutoScrolling"), 1) 00689 && GetApplication()->DeclarePref(TEXT("AutoScrolling"), TEXT("ScrollToShowMargin"), 00690 &ScrollToShowMargin) 00691 00692 && GetApplication()->DeclareSection(TEXT("Dragging"), 6) 00693 && GetApplication()->DeclarePref(TEXT("Dragging"), TEXT("SolidDragging"), 00694 &SolidDragging, FALSE, TRUE) 00695 && GetApplication()->DeclarePref(TEXT("Dragging"), TEXT("IdleDragDelay"), 00696 (UINT32*)&IdleDragDelay, 0, 10000) 00697 && GetApplication()->DeclarePref(TEXT("Dragging"), TEXT("IdleDragDelay2"), 00698 (UINT32*)&IdleDragDelay2, 0, 10000) 00699 && GetApplication()->DeclarePref(TEXT("Dragging"), TEXT("SolidDragTimeLimit"), 00700 (UINT32*)&SolidDragTimeLimit, 0, 10000) 00701 && GetApplication()->DeclarePref(TEXT("Dragging"), TEXT("OriginOutlineShowAlways"), 00702 &OriginOutlineShowAlways, FALSE, TRUE) 00703 && GetApplication()->DeclarePref(TEXT("Dragging"), TEXT("OriginOutlineShowNonOverlap"), 00704 &OriginOutlineShowNonOverlap, FALSE, TRUE) 00705 && GetApplication()->DeclarePref(TEXT("Dragging"), TEXT("OutlineShowBounds"), 00706 &OutlineShowBounds, FALSE, TRUE); 00707 } 00708 00709 /******************************************************************************************** 00710 00711 > DocView::DocView() 00712 00713 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00714 Created: 12/5/93 00715 Inputs: Pointer to Document to which it belongs 00716 Outputs: None 00717 Returns: None 00718 Purpose: DocView class constructor 00719 A DocView object is usually created by the Document and is linked into a list 00720 of DocViews owned by the Document. So the DocView constructor takes and stores 00721 a pointer to the Document object so that it can get to it quickly. 00722 Errors: None 00723 00724 00725 ********************************************************************************************/ 00726 /* 00727 Technical notes: 00728 In debugging mode, constructor will assert that the Owner document pointer is not null. 00729 00730 ********************************************************************************************/ 00731 00732 DocView::DocView(Document* pOwnerDoc) : 00733 m_PushCursor( (Tool_v1*)NULL, _R(IDC_PUSHTOOLCURSOR) ) 00734 { 00735 // Set the flag that indicates if the view is dying or not. Make sure it is not dying 00736 IsViewDying = FALSE; 00737 00738 // Implementation... 00739 ERROR3IF( pOwnerDoc == NULL, "DocView has no Owner Document !!" ); 00740 00741 pDoc = pOwnerDoc; // Maintain link to Document which owns us 00742 pViewWindow = NULL; // Clear pointer to window 00743 pVState = NULL; 00744 PushToolCursorID = 0; // Matt 12/01/2001 - Ensure it is set to a sensible value at creation 00745 pCurrentDragOp = NULL; // we aren't dragging just yet 00746 Scale = 1.0; // Viewing scale = 1.00 00747 00748 ViewFlags.BackgroundRender = BackgroundRendering; // Use preference 00749 00750 ViewFlags.GridShow = FALSE; // Grid not shown 00751 ViewFlags.GridSnap = FALSE; // Grid not snapping 00752 ViewFlags.ObjectsSnap = FALSE; // All objects not snapping 00753 ViewFlags.MagObjectsSnap = FALSE; // Magnetic objects not snapping 00754 ViewFlags.PrintBorderShow = FALSE; // Print borders not shown 00755 ViewFlags.LogicalView = TRUE; // Chapters are shown one above the other 00756 ViewFlags.WorkClickCached = FALSE; // Haven't got a click cached 00757 ViewFlags.Dragging = FALSE; // We're not dragging anything 00758 ViewFlags.GuidesSnap = TRUE; // Not snapping to guides 00759 ViewFlags.GuidesShow = TRUE; // Show guides by default 00760 00761 // Get the default quality level 00762 RenderQuality = Quality::DefaultQuality; 00763 00764 // Initialise the snap object to NULL. This is set up in the Snap functions 00765 pCSnap = NULL; 00766 00767 // init pointer to rulers 00768 pRulerPair = NULL; 00769 00770 // make sure we don't prevent ourselves from rendering 00771 m_bPreventRenderView = FALSE; 00772 00773 // Setup solid dragging flags 00774 m_bSolidDragSupported = FALSE; 00775 m_bSolidDrag = FALSE; 00776 00777 // Make ourselves current. 00778 SetCurrent(); 00779 00780 // Broadcast a message to all that there's a new view on the block . . . 00781 BROADCAST_TO_ALL(DocViewMsg(this, DocViewMsg::BORN)); 00782 00783 } 00784 00785 00786 00787 /******************************************************************************************** 00788 > virtual DocView::~DocView() 00789 00790 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00791 Created: 12/5/93 00792 Inputs: None 00793 Outputs: None 00794 Returns: None 00795 Purpose: DocView class destructor 00796 Errors: None 00797 ********************************************************************************************/ 00798 00799 DocView::~DocView() 00800 { 00801 // delete the rulers (must be done first to prevent them receiving doc view dying messages) 00802 if(pRulerPair) 00803 { 00804 delete pRulerPair; 00805 } 00806 pRulerPair=NULL; 00807 00808 // Set the flag that indicates if the view is dying. 00809 IsViewDying = TRUE; 00810 00811 // Make sure that Current and Selected do not refer to the dying DocView 00812 if (this == Current) SetNoCurrent(); 00813 if (this == Selected) Document::SetNoSelectedViewAndSpread(); 00814 00815 Camelot.DeleteRenderRegions(this); 00816 00817 // Inform parent doc that we are about to die 00818 pDoc->OnDocViewDying(this); 00819 00820 // Bye bye to the ViewState object (DON'T deallocate - done by CCamView). 00821 pVState = NULL; 00822 00823 // If we have an attached CSnap object, junk it 00824 if (pCSnap != NULL) delete pCSnap; 00825 00826 // Broadcast to everyone that this view is a dead duck. 00827 BROADCAST_TO_ALL(DocViewMsg(this, DocViewMsg::KILLED)); 00828 } 00829 00830 00831 /******************************************************************************************** 00832 > BOOL DocView::Init() 00833 00834 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00835 Created: 1/9/95 00836 Returns: FALSE if fails 00837 Purpose: Init a doc view 00838 ********************************************************************************************/ 00839 00840 BOOL DocView::Init() 00841 { 00842 pRulerPair = NULL; 00843 00844 pRulerPair = new RulerPair(); 00845 ERROR2IF(pRulerPair==NULL,FALSE,"DocView::Init() - failed to create RulerPair"); 00846 00847 // update indicator in StatusLine 00848 DialogBarOp::SetSystemStateChanged(); 00849 00850 return TRUE; 00851 } 00852 00853 /******************************************************************************************** 00854 00855 > DocView::ScrollToShowMargin 00856 00857 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 00858 Created: 3/6/1996 00859 Purpose: Margins to use (in millipoints) when autoscrolling with a margin 00860 00861 See Also: ScrollToShowWithMargin 00862 00863 ********************************************************************************************/ 00864 00865 UINT32 DocView::ScrollToShowMargin = 18000; // defaults to 1/4 inch 00866 00867 /******************************************************************************************** 00868 > BOOL DocView::SetScrollOffsets(WorkCoord NewTopLeft, BOOL RedrawNeeded = TRUE) 00869 00870 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00871 Created: 6/7/93 00872 Inputs: New scroll offsets 00873 Flag to control whether redraw is needed or not 00874 Purpose: To scroll this view to a new position over the document. The coordinate 00875 supplied is the coordinate of the top left corner of the viewport onto the 00876 document. The RedrawNeeded flag is TRUE when any invalid areas created should 00877 be redrawn immediately and FALSE if they should be ignored. 00878 ********************************************************************************************/ 00879 00880 BOOL DocView::SetScrollOffsets(WorkCoord NewTopLeft, BOOL RedrawNeeded) 00881 { 00882 if (!View::SetScrollOffsets(NewTopLeft, RedrawNeeded)) 00883 // Something went wrong - report failure to caller. 00884 return FALSE; 00885 00886 WorkCoord RoundedTopLeft = GetScrollOffsets(); 00887 00888 // Tell Oil they've changed 00889 pViewWindow->SetScrollOffset(RoundedTopLeft, RedrawNeeded); 00890 00891 return TRUE; 00892 } 00893 00894 00895 00896 /******************************************************************************************** 00897 00898 > void DocView::ScrollToShow(DocCoord* pCoord) 00899 00900 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 00901 Created: 6/3/1996 00902 Inputs: pCoord - coord to show in spread coords 00903 Outputs: - 00904 Returns: - 00905 Purpose: Scrolls the currently selected document view to bring this coord into view. 00906 If this coord is already visible then we do nothing. 00907 00908 If an ordinate of pCoord is zero then it is ignored and the view willnot 00909 be scrolled in that direction. 00910 00911 ********************************************************************************************/ 00912 00913 void DocView::ScrollToShow(DocCoord* pCoord) 00914 { 00915 ERROR3IF(pCoord == NULL,"pCoord is NULL"); 00916 if (pCoord == NULL) return; 00917 00918 // call ScrollToShowAux, which does the actual work 00919 ScrollToShowAux(pCoord, DocCoord(0,0)); 00920 } 00921 00922 00923 00924 /******************************************************************************************** 00925 00926 > void DocView::ScrollToShow(DocRect *RectToShow) 00927 00928 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00929 Created: 22/3/96 00930 Inputs: RectToShow - Rectangle to show, in spread coords 00931 00932 Purpose: Scrolls the currently selected view to ensure that as much as possible of 00933 RectToShow is visible. If the entire rect cannot be seen, then it will scroll 00934 the minimum distance in order to make a part of it visible. 00935 00936 i.e. Unlike the other ScrollToShow functions, this actually scrolls to show 00937 the given rectangle, as opposed to single points. 00938 00939 ********************************************************************************************/ 00940 00941 void DocView::ScrollToShow(DocRect *RectToShow) 00942 { 00943 ERROR3IF(RectToShow == NULL, "Illegal NULL params"); 00944 00945 Spread* pSpread = GetFirstSelectedSpread(); 00946 00947 if (pSpread == NULL) 00948 return; 00949 00950 // The TRUE argument for GetPasteBoardRect means that the result gets 00951 // pixelised. Otherwise the clipping code below doesn't work properly 00952 DocRect ViewRect = (GetDocViewRect(pSpread)).ToSpread(pSpread, this); 00953 00954 // If the rect is entirely visible, or as much as possible of it is visible, then don't scroll! 00955 if (ViewRect.ContainsRect(*RectToShow) || RectToShow->ContainsRect(ViewRect)) 00956 return; 00957 00958 // Find the distance of the rectangle from each edge of the view rect, and work out 00959 // the distance we should scroll the view by 00960 DocCoord Offset(0,0); 00961 00962 // If we need to scroll in x axis, work out by how much 00963 // "Need to scroll" means: The target rect lies outside the view rect on *only* one side 00964 if ( 00965 (RectToShow->lo.x < ViewRect.lo.x || RectToShow->hi.x > ViewRect.hi.x) && // Outside 00966 !(RectToShow->lo.x < ViewRect.lo.x && RectToShow->hi.x > ViewRect.hi.x) // On one side only 00967 ) 00968 { 00969 // Find the distance needed to scroll the left edge of target to the left edge of the view 00970 // and the right edge to the right edge. 00971 INT32 Diff1 = RectToShow->lo.x - ViewRect.lo.x; 00972 INT32 Diff2 = RectToShow->hi.x - ViewRect.hi.x; 00973 00974 // We need to scroll by the smaller of these 2 distances 00975 INT32 AbsDiff1 = ABS(Diff1); 00976 INT32 AbsDiff2 = ABS(Diff2); 00977 00978 Offset.x = (AbsDiff1 < AbsDiff2) ? Diff1 : Diff2; 00979 } 00980 00981 // Repeat the above for the Y axis 00982 if ( 00983 (RectToShow->lo.y < ViewRect.lo.y || RectToShow->hi.y > ViewRect.hi.y) && // Outside 00984 !(RectToShow->lo.y < ViewRect.lo.y && RectToShow->hi.y > ViewRect.hi.y) // On one side only 00985 ) 00986 { 00987 // Find the distance to scroll to the left and right edges 00988 INT32 Diff1 = RectToShow->lo.y - ViewRect.lo.y; 00989 INT32 Diff2 = RectToShow->hi.y - ViewRect.hi.y; 00990 00991 // We need to scroll by the smaller of these 2 distances 00992 INT32 AbsDiff1 = ABS(Diff1); 00993 INT32 AbsDiff2 = ABS(Diff2); 00994 00995 Offset.y = (AbsDiff1 < AbsDiff2) ? Diff1 : Diff2; 00996 } 00997 00998 // Ensure we don't scroll off the pasteboard area. This should really be done by 00999 // SetScrollOffsets, but it appears that function is complete pants, and I've already 01000 // had to change over 60 files because of poorly designed fundamental code, so 01001 // I really don't have time to fix yet more problems. 01002 DocRect PasteRect = (pSpread->GetPasteboardRect(TRUE)).ToSpread(pSpread, this); 01003 if (Offset.x < 0) 01004 { 01005 if (ViewRect.lo.x + Offset.x < PasteRect.lo.x) 01006 Offset.x = ViewRect.lo.x - PasteRect.lo.x; 01007 } 01008 else 01009 { 01010 if (ViewRect.hi.x + Offset.x > PasteRect.hi.x) 01011 Offset.x = PasteRect.hi.x - ViewRect.hi.x; 01012 } 01013 01014 if (Offset.y < 0) 01015 { 01016 if (ViewRect.lo.y + Offset.y < PasteRect.lo.y) 01017 Offset.y = ViewRect.lo.y - PasteRect.lo.y; 01018 } 01019 else 01020 { 01021 if (ViewRect.hi.y + Offset.y > PasteRect.hi.y) 01022 Offset.y = PasteRect.hi.y - ViewRect.hi.y; 01023 } 01024 01025 // determine if we need to scroll or not, 01026 if (Offset != DocCoord(0,0)) 01027 { 01028 WorkCoord ScrollOffset; 01029 WorkCoord WorkOffset; 01030 01031 WorkOffset.x = (XLONG) (MakeXLong(Offset.x) * GetViewScale()); 01032 WorkOffset.y = (XLONG) (MakeXLong(Offset.y) * GetViewScale()); 01033 01034 ScrollOffset = GetScrollOffsets(); 01035 ScrollOffset.x = ScrollOffset.x + WorkOffset.x; 01036 ScrollOffset.y = ScrollOffset.y + WorkOffset.y; 01037 01038 if (ScrollOffset.x < (XLONG) 0) ScrollOffset.x = (XLONG) 0; 01039 if (ScrollOffset.y > (XLONG) 0) ScrollOffset.y = (XLONG) 0; 01040 01041 SetScrollOffsets(ScrollOffset, TRUE); 01042 } 01043 } 01044 01045 01046 01047 /******************************************************************************************** 01048 01049 > DocView::ScrollToShow(DocRect* pBoundingBox, DocCoord Direction) 01050 01051 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 01052 Created: 6/3/1996 01053 Inputs: pBoundingBox - DocRect to show in spread coords 01054 Direction - Direction of movement 01055 Outputs: - 01056 Returns: - 01057 Purpose: Scrolls the currently selected view to ensure that edge(s) of pBoundingBox 01058 are visible. The Direction argument tells us which edges. If the movement 01059 was towards the top of the screen then we need to make the top edge of the 01060 DocRect visible. 01061 01062 If an ordinate of Direction is zero then we ignore it and no scrolling is done 01063 in that direction. 01064 01065 ********************************************************************************************/ 01066 01067 void DocView::ScrollToShow(DocRect* pBoundingBox, DocCoord Direction) 01068 { 01069 ERROR3IF(pBoundingBox == NULL,"pBoundingBox is NULL"); 01070 if (pBoundingBox == NULL) return; 01071 01072 DocCoord Point; 01073 01074 if (Direction.x > 0) 01075 Point.x = pBoundingBox->hi.x; 01076 else if (Direction.x < 0) 01077 Point.x = pBoundingBox->lo.x; 01078 else 01079 Point.x = 0; 01080 01081 if (Direction.y > 0) 01082 Point.y = pBoundingBox->hi.y; 01083 else if (Direction.y < 0) 01084 Point.y = pBoundingBox->lo.y; 01085 else 01086 Point.y = 0; 01087 01088 // call ScrollToShowAux which does the actual work 01089 ScrollToShowAux(&Point, DocCoord(0,0)); 01090 } 01091 01092 01093 01094 /******************************************************************************************** 01095 01096 > void DocView::ScrollToShowWithMargin(DocCoord* pCoord) 01097 01098 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 01099 Created: 6/3/1996 01100 Inputs: pCoord - coord to show in spread coords 01101 Outputs: - 01102 Returns: - 01103 Purpose: Scrolls the currently selected view to show the coord; if the coord in already 01104 in view then we do nothing. 01105 01106 If an ordinate of pCoord is zero then we ignore it and do not scroll in that 01107 direction. 01108 01109 ********************************************************************************************/ 01110 01111 void DocView::ScrollToShowWithMargin(DocCoord* pCoord) 01112 { 01113 ERROR3IF(pCoord == NULL,"pCoord is NULL"); 01114 if (pCoord == NULL) return; 01115 01116 DocCoord Margin; 01117 01118 double Scale = GetViewScale().MakeDouble(); 01119 01120 Margin.x = (INT32) (ScrollToShowMargin/Scale); 01121 Margin.y = (INT32) (ScrollToShowMargin/Scale); 01122 01123 // call ScrollToShowAux, which does all the actual work 01124 ScrollToShowAux(pCoord, Margin); 01125 } 01126 01127 01128 01129 /******************************************************************************************** 01130 01131 > void DocView::ScrollToShowWithMargin(DocRect *RectToShow) 01132 01133 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01134 Created: 22/3/96 01135 Inputs: RectToShow - Rectangle to show, in spread coords 01136 01137 Purpose: Scrolls the currently selected view to ensure that as much as possible of 01138 RectToShow is visible. If the entire rect cannot be seen, then it will scroll 01139 the minimum distance in order to make a part of it visible. 01140 01141 i.e. Unlike the other ScrollToShow functions, this actually scrolls to show 01142 the given rectangle, as opposed to single points. 01143 01144 ********************************************************************************************/ 01145 01146 void DocView::ScrollToShowWithMargin(DocRect *RectToShow) 01147 { 01148 ERROR3IF(RectToShow == NULL, "Illegal NULL params"); 01149 01150 DocRect Temp(*RectToShow); 01151 01152 double Scale = GetViewScale().MakeDouble(); 01153 01154 INT32 Margin = (INT32) (ScrollToShowMargin / Scale); 01155 01156 Temp.Inflate(Margin, Margin); 01157 01158 ScrollToShow(&Temp); 01159 } 01160 01161 01162 01163 /******************************************************************************************** 01164 01165 > void DocView::ScrollToShowWithMargin(DocRect* pBoundingBox, DocCoord Direction) 01166 01167 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 01168 Created: 6/3/1996 01169 Inputs: pBoundingBox - DocRect to show, in spread coords 01170 Direction - direction of movement 01171 Outputs: - 01172 Returns: - 01173 Purpose: Scrolls the current view to show parts of pBoundingBox. The edge(s) of 01174 pBoundingBox are determined by Direction, if we have moved objects towards 01175 the top of the screen then we need to ensure that the top edge of the DocRect 01176 is visible. 01177 01178 If an ordinate of Direction is zero then we ignore it and do not scroll in 01179 that direction. 01180 01181 ********************************************************************************************/ 01182 01183 void DocView::ScrollToShowWithMargin(DocRect* pBoundingBox, DocCoord Direction) 01184 { 01185 ERROR3IF(pBoundingBox == NULL,"pBoundingBox is NULL"); 01186 if (pBoundingBox == NULL) return; 01187 01188 DocCoord Point; 01189 DocCoord Margin; 01190 01191 if (Direction.x > 0) 01192 Point.x = pBoundingBox->hi.x; 01193 else if (Direction.x < 0) 01194 Point.x = pBoundingBox->lo.x; 01195 else 01196 Point.x = 0; 01197 01198 if (Direction.y > 0) 01199 Point.y = pBoundingBox->hi.y; 01200 else if (Direction.y < 0) 01201 Point.y = pBounding