docview.cpp

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