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 = pBoundingBox->lo.y;
01202     else
01203         Point.y = 0;
01204 
01205     double Scale = GetViewScale().MakeDouble();
01206     Margin.x = (INT32) (ScrollToShowMargin/Scale);
01207     Margin.y = (INT32) (ScrollToShowMargin/Scale);
01208 
01209     // call ScrollToShowAux, which does all the actual work
01210     ScrollToShowAux(&Point, Margin);
01211 }
01212 
01213 /********************************************************************************************
01214 
01215 >   void DocView::ScrollToShowAux(DocCoord *pCoord, DocCoord Margin)
01216 
01217     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
01218     Created:    6/3/1996
01219     Inputs:     pCoord      - coord to show in spread coords
01220                 Margin      - margin to give between point and edge of view
01221     Outputs:    -
01222     Returns:    -
01223     Purpose:    Scrolls the view to ensure that pCoord is in the view, with a margin of Margin
01224                 between it and the edges of the view.
01225 
01226                 If an ordinate of pCoord is zero then we ignore it and do not scroll in that
01227                 direction.
01228 
01229 ********************************************************************************************/
01230 
01231 void DocView::ScrollToShowAux(DocCoord *pCoord, DocCoord Margin)
01232 {
01233     ERROR3IF(pCoord == NULL,"pCoord is NULL");
01234     if (pCoord == NULL) return;
01235 
01236     ERROR3IF(Margin.x < 0,"Negative X margin");
01237     if (Margin.x < 0) return;
01238 
01239     ERROR3IF(Margin.y < 0,"Negative Y margin");
01240     if (Margin.y < 0) return;
01241     
01242     Spread* pSpread = GetFirstSelectedSpread();
01243 
01244     if (pSpread == NULL)
01245     {
01246         // do nothing
01247     }
01248     else
01249     {
01250         DocRect ViewRect;
01251         DocRect PasteRect;
01252         DocCoord Offset;
01253 
01254         // The TRUE argument for GetPasteBoardRect means that the result gets
01255         // pixelised. Otherwise the clipping code below doesn't work properly
01256         ViewRect = (GetDocViewRect(pSpread)).ToSpread(pSpread, this);
01257         PasteRect = (pSpread->GetPasteboardRect(TRUE)).ToSpread(pSpread, this);
01258 
01259         Offset = DocCoord(0,0);
01260 
01261         // suppose the view rectangle is smaller than two margins width, either in height or
01262         // width, we'll need to alter the margin to half the height or width as appropriate
01263         {
01264             INT32 Width = ViewRect.hi.x - ViewRect.lo.x;
01265             INT32 Height = ViewRect.hi.y - ViewRect.lo.y;
01266 
01267             if (Width < 2*Margin.x)
01268                 Margin.x = Width/2;
01269 
01270             if (Height < 2*Margin.y)
01271                 Margin.y = Height/2;
01272         }
01273                 
01274         // only scroll in the X direction if pCoord->x is not zero
01275         if (pCoord->x != 0)
01276         {
01277             if (pCoord->x >= PasteRect.hi.x-Margin.x) pCoord->x = PasteRect.hi.x-Margin.x;
01278             if (pCoord->x <= PasteRect.lo.x+Margin.x) pCoord->x = PasteRect.lo.x+Margin.x;
01279             
01280             if (pCoord->x < (ViewRect.lo.x+Margin.x))
01281             {
01282                 // need to scroll to the left
01283                 Offset.x = pCoord->x - (ViewRect.lo.x + Margin.x);
01284             }
01285             
01286             if (pCoord->x > (ViewRect.hi.x-Margin.x))
01287             {
01288                 // need to scroll to the right
01289                 Offset.x = pCoord->x - (ViewRect.hi.x - Margin.x);
01290             }
01291         }
01292         else
01293         {
01294             Offset.x = 0;
01295         }
01296 
01297         // only scroll in the Y direction if pCoord->y is not zero
01298         if (pCoord->y != 0)
01299         {
01300             if (pCoord->y >= PasteRect.hi.y-Margin.y) pCoord->y = PasteRect.hi.y-Margin.y;
01301             if (pCoord->y <= PasteRect.lo.y+Margin.y) pCoord->y = PasteRect.lo.y+Margin.y;
01302                 
01303             if (pCoord->y < (ViewRect.lo.y+Margin.y))
01304             {
01305                 // need to scroll down
01306                 Offset.y = pCoord->y - (ViewRect.lo.y+Margin.y);
01307             }
01308             
01309             if (pCoord->y > (ViewRect.hi.y-Margin.y))
01310             {
01311                 // need to scroll up
01312                 Offset.y = pCoord->y - (ViewRect.hi.y-Margin.y);
01313             }
01314         }
01315         else
01316         {
01317             Offset.y = 0;
01318         }
01319         
01320         // determine if we need to scroll or not,
01321         if (Offset != DocCoord(0,0))
01322         {
01323             WorkCoord ScrollOffset;
01324             WorkCoord WorkOffset;
01325 
01326             WorkOffset.x = (XLONG) (MakeXLong(Offset.x) * GetViewScale());
01327             WorkOffset.y = (XLONG) (MakeXLong(Offset.y) * GetViewScale());
01328 
01329             ScrollOffset = GetScrollOffsets();
01330             ScrollOffset.x = ScrollOffset.x + WorkOffset.x;
01331             ScrollOffset.y = ScrollOffset.y + WorkOffset.y;
01332 
01333             if (ScrollOffset.x < (XLONG) 0) ScrollOffset.x = (XLONG) 0;
01334             if (ScrollOffset.y > (XLONG) 0) ScrollOffset.y = (XLONG) 0;
01335 
01336             SetScrollOffsets(ScrollOffset, TRUE);
01337         }
01338         // else do nothing
01339     }
01340 }
01341 
01342 /********************************************************************************************
01343 
01344 >   BOOL DocView::ViewStateChanged()
01345 
01346     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01347     Created:    18/5/93
01348     Purpose:    Inform the DocView that the ViewState has been changed in some way.
01349                 When this function detects a new ViewState object (IsNewView = TRUE) it sets
01350                 the scroll offsets to the top left hand corner of the first page in the
01351                 document.
01352 
01353 ********************************************************************************************/
01354 /*
01355 Technical notes:
01356     This function is called soon after construction of every DocView. At this time the CCamView 
01357     has written lots of useful stuff into the ViewState (like the size of pixels) and so we
01358     can now calculate the extents of the document and give them back to CCamView.
01359 
01360 ********************************************************************************************/
01361 
01362 BOOL DocView::ViewStateChanged()
01363 {
01364     // Local variables...
01365     DocCoord    ExtentLo;                       // coord of bottom-left of logical extent
01366     DocCoord    ExtentHi;                       // coord of top-right of logical extent
01367 
01368     DialogBarOp::SetSystemStateChanged();
01369 
01370     // Implementation...
01371     ERROR2IF(this==NULL,FALSE,"DocView member func called on NULL pointer");
01372     ERROR2IF(pDoc==NULL,FALSE,"ViewStateChanged: There MUST be an   owner doc for this view!");
01373     
01374     // Read DocCoords extent of document & set extent in platform-indy ViewState struct.
01375     pDoc->GetExtents(&ExtentLo, &ExtentHi, &PhysExtent, this);
01376     SetExtent(ExtentLo, ExtentHi);              
01377 
01378     // Set extent in platform-indy ViewState struct
01379     ViewFlags.WorkClickCached = FALSE;          
01380     return TRUE;
01381 }
01382 
01383 
01384 /*********************************************************************************************
01385 
01386 >   BOOL DocView::SetViewScale(FIXED16 NewScale)
01387 
01388     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01389     Created:    31/5/93
01390     Inputs:     New view scale factor
01391     Purpose:    Set the viewing scale factor for this view.
01392                 (Also, sets up the scaled pixel size in DocCoord if this View is current.
01393                                                                  
01394 *********************************************************************************************/
01395 
01396 BOOL DocView::SetViewScale(FIXED16 NewScale)
01397 {
01398     if (!View::SetViewScale(NewScale))
01399         // Error
01400         return FALSE;
01401 
01402     // Tell everyone that a DocView scale has changed.
01403     BROADCAST_TO_ALL(DocViewMsg(this,DocViewMsg::SCALECHANGED));
01404 
01405     return TRUE;
01406 }
01407 
01408 
01409 
01410 /********************************************************************************************
01411 >   void DocView::OnNewView()
01412 
01413     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01414     Created:    26/4/94
01415     Inputs:     -
01416     Outputs:    -
01417     Returns:    -
01418     Purpose:    Called by CCamView as part of its "initial update" function provided that
01419                 this view onto a document has not been previously saved and reloaded.
01420                 Sets the defaults, eg. scroll offset, for newly created views.
01421     Errors:     -
01422     SeeAlso:    DocView::OnLoadedView; CCamView::OnInitialUpdate; struct ViewState
01423 ********************************************************************************************/
01424 
01425 void DocView::OnNewView()
01426 {
01427     // Only set the scroll offsets if they have not been set yet.
01428     // eg. When a document is loaded it is possible that it has already set the Scroll Offsets
01429     // to something sensible.
01430     WorkCoord CurrentOffset = GetScrollOffsets();
01431     if ((CurrentOffset.x==0) && (CurrentOffset.y==0))
01432     {
01433         // Find the first page in the document and set the scroll offsets so that the top
01434         // left corner of the page is in the top left corner of the view.
01435         Node* pSearchNode = Node::DocFindFirstDepthFirst(pDoc);
01436         while (pSearchNode != NULL && !pSearchNode->IsSpread())
01437             pSearchNode = pSearchNode->DocFindNextDepthFirst();
01438 
01439         ERROR3IF(pSearchNode == NULL, "ViewStateChanged: Can't find first spread.");
01440 
01441         if (pSearchNode != NULL)
01442         {
01443             Spread *pSpread = (Spread *)pSearchNode;
01444 
01445             // OK, found the spread. Go look for the first page
01446             Page *pPage = pSpread->FindFirstPageInSpread();
01447             ERROR3IF(pPage == NULL, "ViewStateChanged: Can't find first page in spread.");
01448 
01449             if (pPage != NULL)
01450             {
01451                 // OK, found the first page.
01452                 // Read its position in the spread, translate into Doc Coord space
01453                 DocRect PageRect = pPage->GetPageRect();
01454 
01455                 DocCoord TopLeft(PageRect.lo.x, PageRect.hi.y);
01456                 pSpread->SpreadCoordToDocCoord(&TopLeft);
01457 
01458                 // Then translate to work coords
01459                 WorkCoord TopLeftWrk = TopLeft.ToWork(pSpread, this);
01460             
01461                 // Shift the corner of the page 1/8th of an inch into the window.
01462                 TopLeftWrk.x -= (72000/8);
01463                 TopLeftWrk.y += (72000/8);
01464 
01465                 // Only set the new scroll offsets if valid. Otherwise we will get an Error2.
01466                 // We may try to set illegal values now that we allow zero sized pasterboards.
01467                 if (TopLeftWrk.x >= (XLONG)0 && TopLeftWrk.y <= (XLONG)0)
01468                 {
01469                     // And scroll to place that offset at the top left of the view window
01470                     SetScrollOffsets(TopLeftWrk, FALSE);
01471                 }
01472             }
01473         }
01474     }
01475 
01476     DialogBarOp::SetSystemStateChanged();
01477 
01478     // Change the View State so that it is no longer marked as new
01479 PORTNOTE("other","Removed ViewState usage")
01480 #ifndef EXCLUDE_FROM_XARALX
01481     if (pVState!=NULL)
01482         pVState->IsNewView = FALSE;
01483 #endif
01484 }
01485 
01486 
01487 
01488 /********************************************************************************************
01489 >   void DocView::OnLoadedView()
01490 
01491     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01492     Created:    27/4/94
01493     Inputs:     -
01494     Outputs:    -
01495     Returns:    -
01496     Purpose:    Called by CCamView as part of its "initial update" function provided that
01497                 this view onto a document has been previously saved and reloaded.
01498                 Currently does nothing, but one day - who knows.
01499     Errors:     -
01500     SeeAlso:    DocView::OnNewView; CCamView::OnInitialUpdate; struct ViewState
01501 ********************************************************************************************/
01502 
01503 void DocView::OnLoadedView()
01504 {
01505     // empty for now
01506 }
01507 
01508 
01509 
01510 /********************************************************************************************
01511 
01512 >   void DocView::SetExtent(DocCoord lolog, DocCoord hilog)
01513 
01514     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01515     Created:    26/5/93
01516     Inputs:     Two DocCoords describing the low and high corners of a rectangle in logical
01517                 space describing the full extent of the document. I.E. the bottom-left corner
01518                 of the last chapter and the top-right corner of the first.
01519     Purpose:    Informs the DocView that the extent of the document has changed in some way and 
01520                 that the view must be altered to take this into account (namely the 
01521                 scrollbars).
01522 
01523 ********************************************************************************************/
01524 
01525 void DocView::SetExtent(DocCoord lolog, DocCoord hilog)
01526 {
01527     if (ViewFlags.LogicalView)
01528     {
01529         // "Pixelise" the extent DocCoords.
01530         // Effectively, this helps ensure that the spread will be aligned to a whole pixel boundary
01531         // and allows both GDraw and GDI to consistently plot the same pixels when rendering
01532         // the same primitive
01533         lolog.Pixelise(this);
01534         hilog.Pixelise(this);
01535 
01536         // Logical view means that chapters are shown in a contiguous column
01537         // Convert the extent given in DocCoord to WorkCoords...
01538         pVState->WorkAreaExtent.lo = lolog.ToWork(pDoc, this);
01539         pVState->WorkAreaExtent.hi = hilog.ToWork(pDoc, this);
01540 
01541         // If we know where the OIL view is then tell it that the extents have changed...
01542         if (pViewWindow)
01543         {
01544             pViewWindow->SetWorkAreaExtent(pVState->WorkAreaExtent, FALSE);
01545         }
01546     }
01547     else
01548     {
01549         // Physical view means that chapters are shown in their true positions in Document space
01550         ERROR3("DocView::SetExtent - Can't do physical views yet!");
01551     }
01552 }
01553 
01554 
01555 
01556 
01557 
01558 
01559 /********************************************************************************************
01560 
01561 >   WorkRect DocView::GetViewRect()
01562 
01563     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01564     Created:    5/7/93
01565     Returns:    A WorkCoords rectangle describing the viewport onto the document which this
01566                 view is displaying. I.E. The top left corner of this rectangle is the same as
01567                 the value returned by GetScrollOffsets().
01568     Purpose:    To find the rectangle describing the viewport onto the document.
01569 
01570 ********************************************************************************************/
01571 
01572 WorkRect DocView::GetViewRect()
01573 {
01574     ERROR3IF(pViewWindow == NULL, "DocView::GetViewRect called when we have no ViewWindow");
01575 
01576     // Get the width and height of the view in OS units
01577     INT32 ClientWidth = 0;
01578     INT32 ClientHeight = 0;
01579     pViewWindow->GetClientSize(&ClientWidth, &ClientHeight);
01580 
01581     OilRect OilViewRect;
01582     OilViewRect.lo.x = 0;
01583     OilViewRect.lo.y = -ClientHeight;
01584     OilViewRect.hi.x = ClientWidth;
01585     OilViewRect.hi.y = 0;
01586 
01587     // Convert the OSRect into Workarea coords
01588 //  WorkCoord pos;
01589 //  pViewWindow->GetScrollOffset(&pos);
01590 //  pVState->SetScrollPos(pos);
01591 //  return OilViewRect.ToWork(pos);
01592     return OilViewRect.ToWork(pVState->GetScrollPos());
01593 }
01594 
01595 
01596 
01597 
01598 /********************************************************************************************
01599 
01600 >   DocRect DocView::GetDocViewRect(Spread* pSpread)
01601 
01602     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01603     Created:    21/7/93
01604     Inputs:     pSpread - the spread that we are interested in
01605     Returns:    A DocCoords rectangle describing the viewport onto the document which this
01606                 view is displaying. I.E. The top left corner of this rectangle is the same as
01607                 the value returned by GetScrollOffsets() except in DocCoords.
01608     Purpose:    To find the rectangle describing the viewport onto the document.
01609 
01610 ********************************************************************************************/
01611 
01612 DocRect DocView::GetDocViewRect(Spread* pSpread)
01613 {
01614     ERROR3IF(pViewWindow == NULL, "DocView::GetDocViewRect called when we have no view");
01615 
01616     INT32 ClientWidth = 0;
01617     INT32 ClientHeight = 0;
01618 
01619     // Get the width and height of the view in OS units
01620     pViewWindow->GetClientSize(&ClientWidth, &ClientHeight);
01621 
01622     OilRect OilViewRect;
01623     OilViewRect.lo.x = 0;
01624     OilViewRect.lo.y = -ClientHeight;
01625     OilViewRect.hi.x = ClientWidth;
01626     OilViewRect.hi.y = 0;
01627 
01628     // Convert the OSRect into Doc coords
01629     return OilViewRect.ToDoc(pSpread, this);
01630 }
01631 
01632 
01633 
01634 /*********************************************************************************************
01635 
01636 >   void DocView::SetForeBackMode(BOOL NewFlag)
01637 
01638     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01639     Created:    31/5/93
01640     Inputs:     NewFlag - New bg render flag.
01641     Purpose:    Set the background render flag for this view.
01642                 Also sets the new value to be used as the default preference.
01643                                                                  
01644 *********************************************************************************************/
01645 
01646 void DocView::SetForeBackMode(BOOL NewFlag)
01647 {
01648     ViewFlags.BackgroundRender = NewFlag;
01649     
01650     // Update the preference to use this
01651     // Ensure that we either set TRUE or FALSE and not -1 or 0.
01652     // The preference is limited to 0 and 1 values and so -1 is illegal
01653     if (NewFlag == FALSE)
01654         BackgroundRendering = FALSE;
01655     else
01656         BackgroundRendering = TRUE;
01657 }
01658 
01659 
01660 
01661 /*********************************************************************************************
01662 
01663 >   BOOL DocView::GetForeBackMode()
01664 
01665     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01666     Created:    31/5/93
01667     Returns:    TRUE if background rendering is on
01668     Purpose:    To find out if background rendering is on
01669                                                                  
01670 *********************************************************************************************/
01671 
01672 BOOL DocView::GetForeBackMode()
01673 {
01674     // As the flag is a BOOL in a bitfield, it seems to like returning -1 or 0
01675     // Therefore, ensure that we always return TRUE or FALSE
01676 
01677     if (ViewFlags.BackgroundRender == FALSE)
01678         return (FALSE);
01679     else
01680         return (TRUE);
01681 
01682 }
01683 
01684 
01685 
01686 
01687 /********************************************************************************************
01688 
01689 >   void DocView::RenderView(RenderRegion* pRRegion, Matrix& ViewTransform, Spread *pSpread,
01690                                 BOOL bPrintPaper, BOOL fDeleteRegionAfter = TRUE,
01691                                 BOOL bForceImmediate = TRUE)
01692 
01693     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01694     Created:    19/5/93
01695     Inputs:     pRRegion - the region to use for rendering the spread
01696                 ViewTransform - the matrix to use when transforming document coordinates
01697                 into Window coordinates.
01698                 pSpread - the spread we are rendering with this render region.
01699                 bPrintPaper should be TRUE if paper-like items need to be rendered e.g. page
01700                 marks, blobs, etc, or FALSE otherwise. A TRUE value also will enable background
01701                 rendering, so long as Viewflags.BackgroundRender is also set.
01702                 fDeleteRegionAfter  ---  by default TRUE - if so then this function will
01703                 deallocate the RenderRegion passed to it when it has been comletely rendered.
01704     Purpose:    To render a Document through a given RenderRegion.
01705                 The dominating factor in this routine is that it renders the document with as 
01706                 little time overhead as possible. Obviously, this is mainly down to 
01707                 RenderRegions and the tree scanning routines working fast but we can do a bit 
01708                 to help.
01709                 This routine is called directly by other functions in DocView and externally
01710                 from the Background redraw Idle event processor.
01711 
01712 ********************************************************************************************/
01713 /*
01714 Technical notes:
01715                 This routine stores and restores its position in the document tree from the 
01716                 RenderRegion. If it ever picks up a NULL it assumes that the RenderRegion has 
01717                 just been created and renders the background to the document, eg. pages, 
01718                 pasteboard, etc...
01719                 When the routine hits the end of the tree it will pass a NULL in for the 
01720                 RenderRegion to store as its state. This can be used a a signal that rendering 
01721                 in this RenderRegion is complete and that the RenderRegion can be destroyed.
01722 
01723                 The control flow path through this routine is very carefully laid out. When
01724                 the call to GetRenderState returns NULL, we assume that the RenderRegion is 
01725                 newly created and in that case we render all paper nodes and find the first 
01726                 ink node before dropping through to the renderer proper.
01727                 When GetRenderState returns a pointer to a node then this RenderRegion has
01728                 already rendered some ink nodes in the tree and so we must carry on where we
01729                 left off. In this case the control path must be VERY CLEAN - it must not
01730                 alter the tree pointer or change any attributes because the RenderRegion has
01731                 records of all of these things set from the previous session.
01732 
01733 ********************************************************************************************/
01734 
01735 void DocView::RenderView(RenderRegion* pRRegion, Matrix& ViewTransform,
01736                          Spread *pSpread, BOOL bPrintPaper,
01737                          BOOL fDeleteRegionAfter,
01738                          BOOL bForceImmediate)
01739 {
01740     Node* pNode = NULL;
01741     BOOL CleanUp = TRUE;                            // TRUE if cleanup at end, FALSE if dont
01742     BOOL IsMoreBands = FALSE;
01743     DocRect ClipRect;
01744 
01745     BOOL HasRendered = FALSE;
01746     BOOL Continue = TRUE;
01747     BOOL bPaperRenderedThisTime = FALSE;
01748 
01749     // Record time when rendering started
01750     StartTime.Sample();
01751 
01752     // Scroll offsets etc may have changed, so transfer matrix.
01753     pRRegion->SetMatrix(ViewTransform);
01754 
01755     // Prepare to find out whether any bounds in selection are changed during redraw
01756     m_bBoundsChanged = FALSE;
01757 
01758     // Start the first band
01759     if (!pRRegion->SetFirstBand())
01760     {
01761         goto ExitRenderNoStop;
01762     }
01763 
01764     do
01765     {
01766         // See if we are actually waiting for memory
01767         if (pRRegion->IsWaitingForRAM)
01768         {
01769             // See if we can get the memory yet ?
01770             pRRegion->GetNextBand();
01771 
01772             if (pRRegion->IsWaitingForRAM)
01773                 break;  // Nope still not enough
01774         }
01775 
01776         // Tell the RenderRegion that I am going to start rendering.
01777         if (!pRRegion->StartRender())
01778         {
01779             TRACEALL( _T("StartRender failed in RenderView\n") );
01780                                                                 // will be deleted quickly
01781             goto ExitRenderNoStop;                              // skip StopRender call
01782         }
01783 
01784         // If the state is NULL I take this to mean that the RenderRegion has only just been 
01785         // created and I will therefore ensure that the window background is rendered by rendering 
01786         // all the "paper" parts of the document. That is, the pages, chapters, pasteboard, etc...
01787         if (pRRegion->IsPaperRendered == FALSE)
01788         {
01789             if (bPrintPaper)
01790             {
01791                 // Render all paper nodes from there into the real render region
01792                 pRRegion->SaveContext();
01793                 RenderPaper(pRRegion, pSpread);
01794                 pRRegion->RestoreContext();
01795 
01796                 if (pRRegion->NeedsOSPaper)
01797                 {
01798                     // This render region uses the OS to render paper, so if we don't
01799                     // render anything except paper then there is no need for e.g.
01800                     // GRenderRegions to blit anything.  Hence we call this function
01801                     // to clear the changed bbox.
01802                     pRRegion->SetClean(TRUE, FALSE);
01803                 }
01804             }
01805 
01806 #ifdef _DEBUG
01807 // TEMP BODGE! DO NOT RELEASE!
01808 //if (pRRegion->IsKindOf(CC_RUNTIME_CLASS(GRenderRegion)))
01809 //  ((GRenderRegion*)pRRegion)->DebugTrace();
01810 #endif 
01811 
01812             // The Paper is now done
01813             pRRegion->IsPaperRendered = TRUE;
01814             bPaperRenderedThisTime = TRUE;
01815         }
01816 
01817         // ------------------------------------------
01818         // Call the central tree renderer...
01819         Continue = pRRegion->RenderTree(pSpread,
01820                                         ViewFlags.BackgroundRender && !bForceImmediate      // Only timeslice if bgr && ! rendering paper
01821                                         );
01822         // ------------------------------------------
01823 
01824         // Reset state to new posn in tree.
01825         BOOL bRendered = pRRegion->StopRender();
01826         HasRendered = HasRendered || bRendered;
01827 
01828         // Dragging blobs/boxes.
01829         Operation* pDragOp = Operation::GetCurrentDragOp();
01830         if (pDragOp) pDragOp->RenderDragBlobs(pRRegion->GetClipRect(), pSpread, m_bSolidDrag);
01831 
01832         // Assume we ran out of time
01833         IsMoreBands = FALSE;
01834 
01835         // If we did not run out of time, prepare the next band
01836         if (Continue)
01837         {
01838             IsMoreBands = pRRegion->GetNextBand();
01839 
01840             if (pRRegion->IsWaitingForRAM)
01841                 break;      // Leave this region for a while
01842         }
01843     } while (IsMoreBands);
01844 
01845     // Could jump straight to here if the render region was waiting for some ram to show up
01846 
01847 ExitRenderNoStop:
01848     pNode = pRRegion->GetRenderState();
01849 
01850     // Find out whether all bounds have become cached during this render
01851     // If so, update the SelRange and tell all tools the SelRange has changed
01852     // This handles the situation where effects change their bounds during rendering
01853     if (m_bBoundsChanged)
01854     {
01855         // Only broadcast to the rest of the program if we're not trying to be quick
01856         Camelot.FindSelection()->Update(!Operation::GetQuickRender(NULL));
01857     }
01858 
01859     // Find out the rectangle of the whole unbanded region
01860     DocRect BlobClipRect = pRRegion->GetRegionRect();
01861     BOOL IsRegionFinished = CleanUp && !pRRegion->IsWaitingForRAM && pRRegion->IsLastBand && !pNode;
01862 
01863     // If the region has finished rendering, delete it, otherwise update its context node.
01864     if (IsRegionFinished)
01865     {
01866         if (fDeleteRegionAfter)
01867         {
01868             // Unlink the RenderRegion from list
01869             BOOL InList = Camelot.DeleteRenderRegion(pRRegion);
01870             ERROR2IF(!InList, (void)0, "DocView::RenderView tried to delete a RenderRegion not in list");
01871             delete pRRegion;
01872         }
01873     }
01874 
01875     // Draw the blobs if we are the "selected" view.
01876     // And we're not solid dragging...
01877     if (this == Selected && !(pCurrentDragOp!=NULL && m_bSolidDrag))
01878     {
01879         // Tool & selection blobs.
01880         // HasRendered really means "Has blitted and wiped out previous blobs within the changedrect..."
01881         // So we should redraw the blobs inside the changed rect (note that the paper chanegd rect
01882         // needs to be derived differently than the ink changed rect)
01883         // BUT we don't know here what the changed rect is!
01884         // SO, all we can do is wait until the render is over then put the blobs back on
01885 //      if (HasRendered || bPaperRenderedThisTime))
01886         if (IsRegionFinished)
01887         {
01888             Tool* pTool = Tool::GetCurrent();
01889             if (pTool)
01890             {
01891                 pTool->RenderToolBlobs(pSpread, &BlobClipRect);
01892             }
01893 
01894             // Render the Currently selected objects selection blobs
01895             RenderSelectBlobs(BlobClipRect, pSpread);
01896         }
01897     }
01898 }
01899 
01900 
01901 
01902 
01903 /********************************************************************************************
01904 
01905 >   void DocView::ContinueRenderView(RenderRegion* pRRegion, Chapter* pChapter,
01906                                      BOOL fRenderPaper = TRUE,
01907                                      BOOL fDeleteRegionAfter = TRUE,
01908                                      BOOL bForceImmediate = FALSE)
01909 
01910     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01911     Created:    11/7/93
01912     Inputs:     Pointer to RenderRegion which needs rendering to be performed.
01913                 Pointer to chapter which RenderRegion represents.
01914                 fRenderPaper        ---  if TRUE then render paper, blobs etc.
01915                                          By default TRUE.
01916                 fDeleteRegionAfter  ---  if TRUE then this function will deallocate the
01917                                          RenderRegion passed to it when it has been
01918                                          completely rendered.  By default TRUE.
01919     Outputs:    None
01920     Returns:    None
01921     Scope:      Public
01922     Purpose:    To re-start rendering a Document through a given RenderRegion. This call is
01923                 different from RenderView because it may need to re-compute the Doc to OS
01924                 matrix.
01925     Errors:     None
01926 
01927 ********************************************************************************************/
01928 
01929 void DocView::ContinueRenderView(RenderRegion* pRRegion, Spread* pSpread,
01930                                  BOOL fRenderPaper /* = TRUE */,
01931                                  BOOL fDeleteRegionAfter /* = TRUE */,
01932                                  BOOL bForceImmediate /*= FALSE*/)
01933 {
01934     // Diccon 10/5/2000 my awful flag that prevents rendering of the view from occurring
01935     // whilst a brush stroke is in progress
01936     if (m_bPreventRenderView == TRUE)
01937         return;
01938 
01939     // Remove the drag blobs from this region, if there are any.
01940     if (fRenderPaper)
01941     {
01942         Operation* pDragOp = Operation::GetCurrentDragOp();
01943         if (pDragOp)
01944             pDragOp->RenderDragBlobs(pRRegion->GetClipRect(), pSpread, m_bSolidDrag);
01945     }
01946 
01947     // Render the document in one operation.
01948     Matrix mxConv = ConstructRenderingMatrix(pSpread);
01949 
01950     if (OnTopCount == 0 && GetColourPlate() != NULL && !GetColourPlate()->IsDisabled())
01951     {
01952         ColourPlateType PlateType = GetColourPlate()->GetType();
01953         if (PlateType != COLOURPLATE_NONE && PlateType != COLOURPLATE_COMPOSITE)
01954         {
01955             // We have to do this before the render as the RenderSimpleView call
01956             // will delete the render region
01957             DocRect BlobClipRect = pRRegion->GetRegionRect();
01958             DocRect DragClipRect = pRRegion->GetClipRect();
01959             
01960             // Do a printer style simple/complex ScanningRenderRegion type render
01961             RenderSimpleView(pRRegion, mxConv, pSpread, fRenderPaper);
01962 
01963             // Dragging blobs/boxes.
01964             if (fRenderPaper)
01965             {
01966                 Operation* pDragOp = Operation::GetCurrentDragOp();
01967                 if (pDragOp) pDragOp->RenderDragBlobs(DragClipRect, pSpread, m_bSolidDrag);
01968             }
01969 
01970             // Draw the blobs if we are the "selected" view.
01971             // And we're not solid dragging...
01972             if (fRenderPaper && this == Selected && !(pCurrentDragOp!=NULL && m_bSolidDrag))
01973             {
01974                 Tool* pTool = Tool::GetCurrent();
01975                 if (pTool) pTool->RenderToolBlobs(pSpread, &BlobClipRect);
01976 
01977                 // Render the Currently selected objects selection blobs
01978                 RenderSelectBlobs(BlobClipRect, pSpread);
01979             }
01980             return;
01981         }
01982     }
01983     
01984     RenderView(pRRegion, mxConv, pSpread, fRenderPaper, fDeleteRegionAfter, bForceImmediate);
01985 }
01986 
01987 
01988 
01989 
01990 /********************************************************************************************
01991 
01992 >   void DocView::RenderEntireView(RenderRegion* pRender, Spread* pSpread)
01993 
01994     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01995     Created:    17/8/2000
01996     Inputs:     pRRegion - the region to use for rendering the spread
01997             
01998     Purpose:    To render a Document through a given RenderRegion.
01999                 This differs from your regular RenderView service in that it pays no mind as to
02000                 how long things take.  Once you start this function off it will run until it 
02001                 renders the lot.
02002                 The reason for this is that it is designed for use with the brush tool.  Here we
02003                 will need to render the entire view into an offscreen bitmap which is then
02004                 used to with the brush.  It serves as an alternative when we cannot simply blit
02005                 the contents of the screen.
02006                 I don't really recommend using this function in other circumstances as if you
02007                 have a complex document it will probably lock up for a while.
02008 ********************************************************************************************/
02009 
02010 void DocView::RenderEntireView(RenderRegion* pRRegion, Spread* pSpread)
02011 {
02012     DocRect ClipRect;
02013 
02014     Matrix ViewTransform = ConstructRenderingMatrix(pSpread);
02015     // Scroll offsets etc may have changed, so transfer matrix.
02016     pRRegion->SetMatrix(ViewTransform);
02017 
02018     // Get the region to clip all the rendering to
02019     ClipRect = pRRegion->GetClipRect();
02020 
02021     // If the state is NULL I take this to mean that the RenderRegion has only just been 
02022     // created and I will therefore ensure that the window background is rendered by rendering 
02023     // all the "paper" parts of the document. That is, the pages, chapters, pasteboard, etc...
02024     if (pRRegion->IsPaperRendered == FALSE)
02025     {
02026         // Render all paper nodes from there into the real render region
02027         pRRegion->SaveContext();
02028         RenderPaper(pRRegion, pSpread);
02029         pRRegion->RestoreContext();
02030 
02031         // The Paper is now done
02032         pRRegion->IsPaperRendered = TRUE;
02033     }
02034 
02035     // Now render all the ink (non-paper) parts of the document.
02036     pRRegion->RenderTree(pSpread, FALSE);
02037 
02038     // Reset state to new posn in tree.
02039     pRRegion->StopRender();
02040 }
02041 
02042 
02043 /********************************************************************************************
02044 
02045 >   void DocView::GetViewParams(FIXED16* pReturnViewScale,
02046                                 FIXED16* pReturnPixelScaleX,
02047                                 FIXED16* pReturnPixelScaleY,
02048                                 WorkCoord* pReturnScrollOffset) 
02049 
02050     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02051     Created:    24/5/93
02052     Inputs:     None
02053     Outputs:    None
02054     Returns:    None
02055     Purpose:    This function returns the parameters which control the transformation of 
02056                 coordinates between Document space and OS space. These parameters can be used 
02057                 to build transformation matrices to perform the transformation in either 
02058                 direction.
02059     Errors:     None
02060 
02061 ********************************************************************************************/
02062 /*
02063 void DocView::GetViewParams(FIXED16* pReturnViewScale,
02064                             FIXED16* pReturnPixelScaleX,
02065                             FIXED16* pReturnPixelScaleY,
02066                             WorkCoord* pReturnScrollOffset) 
02067 {
02068     ENSURE( pViewWindow != NULL, "DocView::GetViewParams() called when there we no ViewWindow");
02069 
02070     *pReturnViewScale = Scale;
02071     *pReturnPixelScaleX = pVState->PixelXScale;
02072     *pReturnPixelScaleY = pVState->PixelYScale;
02073     *pReturnScrollOffset = pVState->GetScrollPos();
02074 }
02075 */
02076 
02077 /********************************************************************************************
02078 
02079 >   static DocRect DocView::ChapterClip(DocRect& DocClip, Chapter* pChapter)
02080 
02081     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02082     Created:    18/9/93
02083     Inputs:     The DocRect to Clip, and a Chapter to clip it with.
02084     Outputs:    -
02085     Returns:    A Clipped DocRect
02086     Purpose:    Clips the DocRect so that it does not go outside the Chapter Bounds.
02087                 This is used to try and stop the problems with DocCoords that are not within
02088                 any chapters (ie. in OffPaste area).
02089     Errors:     -
02090     SeeAlso:    -
02091 
02092 ********************************************************************************************/
02093 /*
02094 static DocRect DocView::ChapterClip(DocRect& DocClip, Chapter* pChapter)
02095 {
02096     DocRect ChapterRect = pChapter->GetPasteboardRect();
02097 
02098     ChapterRect.lox = MAX(DocClip.lox, ChapterRect.lox);
02099     ChapterRect.loy = MAX(DocClip.loy, ChapterRect.loy);
02100     ChapterRect.hix = MIN(DocClip.hix, ChapterRect.hix);
02101     ChapterRect.hiy = MIN(DocClip.hiy, ChapterRect.hiy);
02102                 
02103     return ChapterRect;
02104 }
02105 */
02106 
02107 
02108 
02109 
02110 /*********************************************************************************************
02111 
02112 >   static DocView *DocView::GetCurrent()
02113 
02114     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02115     Created:    24/5/93
02116     Returns:    Pointer to the current DocView object.
02117     Purpose:    Find the current DocView object which SHOULD have been set as one of the very 
02118                 first actions during event processing.             
02119                                                                  
02120 *********************************************************************************************/
02121 
02122 DocView *DocView::GetCurrent()
02123 {
02124     View *pView = View::GetCurrent();
02125 
02126     // Make sure it really is a DocView;
02127     if ((pView == NULL) || (pView->IS_KIND_OF(DocView)))
02128         // Yes - return it.
02129         return (DocView *) pView;
02130 
02131     // Complain!
02132     //ERROR2(NULL, "DocView::GetCurrent called when current view is not a DocView!");
02133     TRACEALL( _T("DocView::GetCurrent called when current view is not a DocView!\n") );
02134     return NULL;
02135 }
02136 
02137 
02138 /********************************************************************************************
02139 
02140 >   void DocView::SetViewPixelSize()
02141 
02142     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02143     Created:    02/10/95
02144     Purpose:    Sets up the normal and scaled pixel sizes according to this view.
02145     SeeAlso:    OilCoord::SetPixelSize; DocCoord::SetScaledPixelSize
02146 
02147 ********************************************************************************************/
02148 
02149 void DocView::SetViewPixelSize()
02150 {
02151     // Set the scaled pixel size
02152     ScaledPixelWidth = PixelWidth / Scale;
02153     ScaledPixelHeight = PixelHeight / Scale;
02154 }
02155 
02156 /*********************************************************************************************
02157 >   static CNativeWnd* DocView::GetCurrentRenderWindow()
02158 
02159     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> (modified to use DocView::GetRenderWindow() by Ed 1/9/95)
02160     Created:    15 Oct 93
02161     Returns:    Pointer to the current CNativeWnd window object which is being rendered.
02162     Purpose:    Useful function allowing fairly direct access to CCamView's render window,
02163                 which comes in handy on the odd occasion.
02164     Errors:     Returns NULL if there isn't one.
02165 *********************************************************************************************/
02166 
02167 CNativeWnd *DocView::GetCurrentRenderWindow()
02168 {
02169     DocView* pCurrent=GetCurrent();
02170     if (pCurrent==NULL)
02171         return NULL;
02172 
02173     return pCurrent->GetRenderWindow();
02174 }
02175 
02176 
02177 /*********************************************************************************************
02178 >   CNativeWnd* DocView::GetRenderWindow()
02179 
02180     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02181     Created:    1/9/95
02182     Returns:    Pointer to CNativeWnd (else NULL if none)
02183     Purpose:    Get a pointer to a CNativeWnd window object associated with a DocView
02184 *********************************************************************************************/
02185 
02186 CNativeWnd* DocView::GetRenderWindow()
02187 {
02188     if (pViewWindow==NULL)
02189         return NULL;
02190 
02191     return pViewWindow->GetRenderWindow();
02192 }
02193 
02194 
02195 /*********************************************************************************************
02196 
02197 >   static DocView *DocView::GetSelected()
02198 
02199     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02200     Created:    24/5/93
02201     Returns:    Pointer to the selected DocView object.
02202     Purpose:    Find the selected DocView object which SHOULD have been set as one of the very 
02203                 first actions during event processing.
02204                                                                  
02205 *********************************************************************************************/
02206 
02207 DocView *DocView::GetSelected()
02208 {
02209     return Selected;
02210 }
02211 
02212 
02213 
02214     
02215 /*********************************************************************************************
02216 
02217 >   BOOL DocView::SetCurrent()
02218 
02219     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02220     Created:    24/5/93
02221     Inputs:     -
02222     Outputs:    -
02223     Returns:    TRUE if function set current correctly
02224                 FALSE otherwise (then an Error has been set)
02225     Purpose:    Make this object be the 'current' DocView.
02226 
02227 *********************************************************************************************/
02228 
02229 BOOL DocView::SetCurrent()
02230 {
02231     return View::SetCurrent();
02232 }                                                     
02233 
02234 
02235 
02236 /*********************************************************************************************
02237 
02238 >   static void DocView::SetNoCurrent()
02239 
02240     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02241     Created:    24/5/93
02242     Inputs:     -
02243     Outputs:    -
02244     Returns:    -
02245     Purpose:    Set the current DocView pointer to be NULL, i.e., there is no current
02246                 DocView object.
02247                                                                  
02248 *********************************************************************************************/
02249 
02250 void DocView::SetNoCurrent()
02251 {
02252     View::SetNoCurrent();
02253 }
02254 
02255 
02256 
02257 /*********************************************************************************************
02258 
02259 >   static void DocView::SetSelectedInternal(DocView *NewSelected)
02260 
02261     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02262     Created:    14/2/95
02263 
02264     Inputs:     NewSelected - NULL, or the new selected DocView
02265 
02266     Purpose:    This is an INTERNAL function, which MUST NOT BE CALLED by anything
02267                 other than Document::SetSelectedViewAndSpread.
02268 
02269                 It sets the new selected DocView, but DOES NOT broadcast a message.
02270                 The broadcast follows later, via SendSelectedMessage.
02271 
02272                 It can be used to set No Selected DocView (NewSelected = NULL)
02273 
02274                 It also sets this DocView as the Current DocView.
02275 
02276     SeeAlso:    Document::SetSelectedViewAndSpread; DocView::SendSelectedMessage
02277 
02278 *********************************************************************************************/
02279 
02280 void DocView::SetSelectedInternal(DocView *NewSelected)
02281 {
02282     Selected = NewSelected;
02283     
02284     if (NewSelected == NULL)
02285         DocView::SetNoCurrent();
02286     else
02287         NewSelected->SetCurrent();
02288 }
02289 
02290 
02291 
02292 /*********************************************************************************************
02293 
02294 >   static void DocView::SendSelectedMessage(DocView *OldSelected, DocView *NewSelected);
02295 
02296     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02297     Created:    14/2/95
02298 
02299     Inputs:     OldSelected - Points to the previously selected DocView (may be NULL)
02300                 NewSelected - Points to the new selected DocView (may be NULL)
02301 
02302     Purpose:    This is an INTERNAL function, which MUST NOT BE CALLED by anything
02303                 other than Document::SetSelectedViewAndSpread.
02304 
02305                 It is used to broadcast a DocViewMsg (SELCHANGED) to inform of a selection
02306                 change. It follows a SetSelectedInternal call (a bit later, so that the
02307                 message is only broadcast once the document, view, and spread states have
02308                 all been updated correctly)
02309 
02310     SeeAlso:    Document::SetSelectedViewAndSpread; DocView::SetSelectedInternal
02311 
02312 *********************************************************************************************/
02313 
02314 void DocView::SendSelectedMessage(DocView *OldSelected, DocView *NewSelected)
02315 {
02316     BROADCAST_TO_ALL(DocViewMsg(OldSelected, NewSelected, DocViewMsg::SELCHANGED));
02317 }
02318 
02319 
02320 
02321 /********************************************************************************************
02322 >   INT32 DocView::GetZoomTableIndex() const
02323 
02324     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02325     Created:    16/5/94
02326     Inputs:     -
02327     Outputs:    -
02328     Returns:    Returns the value of the zoom table index.
02329     Purpose:    
02330     Errors:     -
02331     SeeAlso:    DocView::SetZoomTableIndex
02332 ********************************************************************************************/
02333 
02334 INT32 DocView::GetZoomTableIndex() const
02335 {
02336     return ZoomTableIndex;
02337 }
02338 
02339 
02340 
02341 /********************************************************************************************
02342 >   void DocView::SetZoomTableIndex(INT32 nIndex)
02343 
02344     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02345     Created:    16/5/94
02346     Inputs:     The new index value.
02347     Outputs:    -
02348     Returns:    -
02349     Purpose:    
02350     Errors:     -
02351     SeeAlso:    DocView::GetZoomTableIndex
02352 ********************************************************************************************/
02353 
02354 void DocView::SetZoomTableIndex(INT32 nIndex)
02355 {
02356     ZoomTableIndex = nIndex;
02357 }
02358 
02359 
02360 
02361 /********************************************************************************************
02362 >   INT32 DocView::GetPrevZoomIndex() const
02363 
02364     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02365     Created:    17/5/94
02366     Inputs:     -
02367     Outputs:    -
02368     Returns:    -
02369     Purpose:    Returns the index into the zoom tool's tabel of a previous zoom on this
02370                 DocView.
02371     Errors:     -
02372     SeeAlso:    DocView::SetPrevZoomIndex
02373 ********************************************************************************************/
02374 
02375 INT32 DocView::GetPrevZoomIndex() const
02376 {
02377     return PrevIndex;
02378 }
02379 
02380 
02381 
02382 /********************************************************************************************
02383 >   void DocView::SetPrevZoomIndex(INT32 nIndex)
02384 
02385     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02386     Created:    17/5/94
02387     Inputs:     The previous zoom index.
02388     Outputs:    -
02389     Returns:    -
02390     Purpose:    Sets the zoom table index of a previous zoom onto this DocView.
02391     Errors:     -
02392     SeeAlso:    DocView::GetPrevZoomIndex
02393 ********************************************************************************************/
02394 
02395 void DocView::SetPrevZoomIndex(INT32 nIndex)
02396 {
02397     PrevIndex = nIndex;
02398 }
02399 
02400 
02401 
02402 
02403 
02404 /********************************************************************************************
02405 >   FIXED16 DocView::GetPrevZoomScale() const
02406 
02407     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02408     Created:    17/5/94
02409     Inputs:     -
02410     Outputs:    -
02411     Returns:    The scale factor of this view as set by a previous zoom.
02412     Purpose:    
02413     Errors:     -
02414     SeeAlso:    DocView::SetPrevZoomScale
02415 ********************************************************************************************/
02416 
02417 FIXED16 DocView::GetPrevZoomScale() const
02418 {
02419     return PrevScale;
02420 }
02421 
02422 
02423 
02424 /********************************************************************************************
02425 >   void DocView::SetPrevZoomScale(FIXED16 fxScale)
02426 
02427     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02428     Created:    17/5/94
02429     Inputs:     The previous zoom scale.
02430     Outputs:    -
02431     Returns:    -
02432     Purpose:    Sets the scale factor this DocView will "remember" as a previous zoom.
02433     Errors:     -
02434     SeeAlso:    DocView::GetPrevZoomScale
02435 ********************************************************************************************/
02436 
02437 void DocView::SetPrevZoomScale(FIXED16 fxScale)
02438 {
02439     PrevScale = fxScale;
02440 }
02441 
02442 
02443 
02444 /********************************************************************************************
02445 >   WorkCoord DocView::GetPrevZoomOffset() const
02446 
02447     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02448     Created:    17/5/94
02449     Inputs:     -
02450     Outputs:    -
02451     Returns:    The scroll offset of this DocView during a previous zoom.
02452     Purpose:    
02453     Errors:     -
02454     SeeAlso:    DocView::SetPrevZoomOffset
02455 ********************************************************************************************/
02456 
02457 WorkCoord DocView::GetPrevZoomOffset() const
02458 {
02459     return PrevOffset;
02460 }
02461 
02462 
02463 
02464 /********************************************************************************************
02465 >   void DocView::SetPrevZoomOffset(const WorkCoord& wcOffset)
02466 
02467     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02468     Created:    17/5/94
02469     Inputs:     The previous zoom's scroll offset.
02470     Outputs:    -
02471     Returns:    -
02472     Purpose:    Sets the scroll offset this DocView will "remember" as a previous zoom.
02473     Errors:     -
02474     SeeAlso:    DocView::GetPrevZoomOffset
02475 ********************************************************************************************/
02476 
02477 void DocView::SetPrevZoomOffset(const WorkCoord& wcOffset)
02478 {
02479     PrevOffset = wcOffset;
02480 }
02481 
02482 
02483 
02484 
02485 /********************************************************************************************
02486 
02487 >   void DocView::ForceRedraw(BOOL ForcePaper = FALSE)
02488 
02489     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02490     Created:    1/7/93
02491     Inputs:     ForcePaper: TRUE => do a normal OS-style invalidation
02492                            FALSE => do a 'clever' internal invalidation which does not 
02493                                     cause paper to be drawn straight away, so we get a
02494                                     smoother feel to the update.
02495     Purpose:    Force the entire view to be redrawn.
02496                 NB. If you are redrawing because you have changed the zoom or scroll 
02497                     offsets, then you must pass in TRUE for ForcePaper!!!
02498                     (Because (a) Otherwise our scroll offsets are invalid and the next
02499                                  time we scroll it gets mucked up, and
02500                              (b) Scrolling or zooming should give instant feedback to
02501                                  the user.)
02502                                                                  
02503 ********************************************************************************************/
02504 
02505 void DocView::ForceRedraw(BOOL ForcePaper)
02506 {
02507     // Make sure we use this DocView
02508     SetCurrent();
02509 
02510     // Get rid of any render regions associated with this DocView
02511     Camelot.DeleteRenderRegions(this);
02512 
02513     // Invalidate the whole view window
02514     if (ForcePaper)
02515     {
02516         // We want an instant update with paper drawn now, so use the OS to do the
02517         // invalidation.
02518         pViewWindow->InvalidateView();
02519         return;
02520     }
02521 
02522     // find type of rendering device
02523     CCamView *pCamView = GetConnectionToOilView();
02524     ERROR2IF(pCamView == NULL, (void)0, "DocView::ForceRedraw: DocView has no CamView");
02525 
02526     pCamView->AllocateDC(); // allocate a DC
02527 
02528     CNativeDC* pDevContext = pCamView->GetRenderDC();
02529     const RenderType rType = CCDC::GetType(pDevContext, TRUE);
02530 
02531     // Get DocView rectangle in 64 bit WorkCoods
02532     WorkRect ClipRect = GetViewRect();
02533 
02534     ERROR3IF(ClipRect.lo.x > ClipRect.hi.x, "DocView::ForceRedraw: clipping rect is invalid");
02535     ERROR3IF(ClipRect.lo.y > ClipRect.hi.y, "DocView::ForceRedraw: clipping rect is invalid");
02536 
02537     // Find all the spreads in the document that intersect the clipping rect, and create
02538     // a render region for each of them.
02539 
02540     // Get the first chapter in the document
02541     for (Chapter* pChapter = Node::FindFirstChapter(pDoc);
02542          pChapter != 0;
02543          pChapter = pChapter->FindNextChapter())
02544     {
02545         // Convert chapter bounding box to logical coords
02546         DocRect PhysChapterRect = pChapter->GetPasteboardRect(TRUE, this);
02547         WorkRect LogChapterRect;
02548         LogChapterRect.lo = PhysChapterRect.lo.ToWork(pDoc, this);
02549         LogChapterRect.hi = PhysChapterRect.hi.ToWork(pDoc, this);
02550 
02551         // Check to see if this chapter intersects the clipping rectangle.
02552         // If the chapter is the last one in the document, then the chapter's pasteboard
02553         // does not include the area of the bottom of the last spread, so we only check
02554         // the chapter's top boundary.
02555 
02556         BOOL fIsLastChapter = (pChapter->FindNextChapter() == 0);
02557 
02558         if (ClipRect.lo.y <= LogChapterRect.hi.y &&
02559             (fIsLastChapter || ClipRect.hi.y >= LogChapterRect.lo.y))
02560         {
02561             for (Spread* pSpread = pChapter->FindFirstSpread();
02562                  pSpread != 0;
02563                  pSpread = pSpread->FindNextSpread())
02564             {
02565                 // Convert spread bounding box to logical coords
02566                 DocRect PhysSpreadRect = pSpread->GetPasteboardRect(TRUE);  // Pixelised
02567                 WorkRect LogSpreadRect;
02568                 LogSpreadRect.lo = PhysSpreadRect.lo.ToWork(pSpread, this);
02569                 LogSpreadRect.hi = PhysSpreadRect.hi.ToWork(pSpread, this);
02570 
02571                 BOOL fIsLastSpread = (pSpread->FindNextSpread() == 0);
02572 
02573                 // Check if spread intersects the clipping rect
02574                 if (ClipRect.lo.y <= LogSpreadRect.hi.y &&
02575                     ((fIsLastChapter && fIsLastSpread) || ClipRect.hi.y >= LogSpreadRect.lo.y))
02576                 {
02577                     // Make render region for intersection between spread and cliprect.
02578                     DocRect SpreadClipRect = pSpread->GetWidePasteboard(this);
02579 
02580                     // Convert clip rectangle to document coords
02581                     DocRect DocClipRect = GetDocViewRect(pSpread);
02582 
02583                     // Clip to spread rectangle
02584                     SpreadClipRect = SpreadClipRect.Intersection(DocClipRect);
02585 
02586                     // Make sure that the clip region is valid after the intersection
02587                     if (SpreadClipRect.IsValid() && !SpreadClipRect.IsEmpty())
02588                     {
02589                         // Convert it to Spread coords and create a render region
02590                         pSpread->DocCoordToSpreadCoord(&SpreadClipRect);
02591                         MakeNewRenderRegion(pSpread, SpreadClipRect, pDevContext, rType, FALSE);
02592                     }
02593                 }
02594             }
02595         }
02596     }
02597 
02598     pCamView->DoneWithDC(); // deallocate a DC
02599 }
02600 
02601 
02602 /********************************************************************************************
02603 
02604 >   void DocView::ForceRedraw(const DocRect& ForceRect)
02605 
02606     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02607     Created:    1/7/93
02608     Inputs:     ForceRect - the rectangle to be invalidated
02609     Purpose:    Force a specific rectangle of the view to be redrawn
02610                                                                  
02611 ********************************************************************************************/
02612 
02613 void DocView::ForceRedraw(WorkRect& ForceRect)
02614 {
02615     PORTNOTETRACE("other","DocView::ForceRedraw - do nothing");
02616 #ifndef EXCLUDE_FROM_XARALX
02617     ERROR3("Should not be called!");
02618 
02619     OilCoord OilRectLo = (ForceRect.lo).ToOil(GetScrollOffsets());
02620     OilCoord OilRectHi = (ForceRect.hi).ToOil(GetScrollOffsets());
02621 
02622     OilRect RedrawOilRect(OilRectLo, OilRectHi);
02623 
02624     pViewWindow->InvalidateView(&RedrawOilRect);
02625 #endif
02626 }
02627 
02628 
02629 
02630 /********************************************************************************************
02631 
02632 >   void DocView::ForceRedraw(Spread *pSpread, DocRect& SpreadRect, BOOL Accumulate = FALSE, Node* pInvalidNode = NULL)
02633 
02634     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> & Rik
02635     Created:    14/12/93
02636     Inputs:     pSpread - the spread which contains the invalid region.
02637                 SpreadRect - the invalid region (in spread coordinates, i.e. (0,0) based)
02638                 Accumulate - TRUE => invalidate *now*
02639                             FALSE => don't invalidate right now, but accumulate this
02640                                      into a list of rectangles for this view, and update
02641                                      intelligently when DocView::FlushRedraw() is called.
02642                 ForceRecache - TRUE => Make sure that any overlapping cached bitmaps that capture bits of
02643                                         objects around/under/over them are thrown away during this redraw
02644                               FALSE => Don't need to worry about cached objects because nothing in the tree
02645                                         has changed
02646 
02647     Purpose:    Force redraw of an area of a spread.
02648     SeeAlso:    DocView::FlushRedraw
02649 
02650 ********************************************************************************************/
02651 
02652 void DocView::ForceRedraw(Spread *pSpread, DocRect SpreadRect, BOOL Accumulate, Node* pInvalidNode)
02653 {
02654     ERROR3IF(pSpread == NULL, "ForceRedraw has been passed a NULL spread pointer");
02655 
02656     // Make sure we use this DocView
02657     SetCurrent();
02658 
02659     // This rectangle has come directly from the program and might not lie on pixel
02660     // boundaries. So pixelise it before passing it directly on to the rendering system.
02661     SpreadRect.lo.Pixelise(this);
02662     SpreadRect.hi.Pixelise(this);
02663 
02664     // Should we do it now?
02665 // IMMEDIATE REDRAW
02666 //  if (FALSE)
02667     if (Accumulate)
02668     {
02669         // No - add it to our list and wait until the Operation finishes...as long as it
02670         // works.
02671         if (PendingRedrawList.AddInvalidRegion(pSpread, SpreadRect, pInvalidNode))
02672         {
02673             // Worked - exit now and wait for FlushRedraw() to be called.
02674             return;
02675         }
02676 
02677         // Otherwise fall through to normal processing (which will probably fail too!)
02678     }
02679 
02680     // Is this a bodge I see before me???
02681     // Not really. This modification expands the invalid region to take anti-aliasing
02682     // pixels into account. It could be made conditional on anti-aliasing being turned on
02683     // but this is simpler and the overhead when anti-aliasing is off is not great.
02684     SpreadRect.Inflate(ScaledPixelWidth.MakeLong(), ScaledPixelHeight.MakeLong());
02685 
02686     // Translate spread coords to document coords
02687     pSpread->SpreadCoordToDocCoord(&SpreadRect);
02688 
02689     // Clip this region to the spread
02690     DocRect WidePasteRect = pSpread->GetWidePasteboard(this);
02691     SpreadRect = SpreadRect.Intersection(WidePasteRect);
02692 
02693     // need to check for valid intersections here as Intersecting with
02694     // an invalid rectangle again will give a valid rectangle would you
02695     // believe! (Mike 20/12/95)
02696     if ( SpreadRect.IsEmpty() || (!SpreadRect.IsValid()) )
02697     {
02698         return;
02699     }
02700 
02701     // Convert clip rectangle to document coords
02702     DocRect DocClipRect = GetDocViewRect(pSpread);
02703 
02704     // Clip to spread rectangle
02705     SpreadRect = SpreadRect.Intersection(DocClipRect);
02706                                                         
02707     // Check to see if the result is an empty rectangle
02708     if ((SpreadRect.IsValid()) && (!SpreadRect.IsEmpty()))
02709     {
02710         // Find type of rendering device
02711         CCamView *pCamView = GetConnectionToOilView();
02712         ERROR2IF(pCamView == NULL, (void)0, "DocView has no CamView!");
02713 
02714 // These next two are commented out because 
02715 // a) rType is never used, and
02716 // b) pDevContext idn't needed in MakeNewRenderRegion if PaintPaper is FALSE (which is is)
02717 
02718 //      CDC *pDevContext = pCamView->GetRenderDC();
02719 //      const RenderType rType = CCDC::GetType(pDevContext, TRUE);
02720 
02721         // Translate document coords back to spread coords
02722         pSpread->DocCoordToSpreadCoord(&SpreadRect);
02723 
02724         // Use this to make a render region.
02725 //      MakeNewRenderRegion(pSpread, SpreadRect, pDevContext, RENDERTYPE_SCREEN, FALSE);    // See changed line below
02726         
02727         // Notice that because the PaintPaper parameter (5th one) is FALSE, we can pass
02728         // NULL as a pointer to a device context, and thus we don't have to call
02729         // GetRenderDC above at all, and hopefully, this will speed up translation
02730         // no end.
02731         MakeNewRenderRegion(pSpread, SpreadRect, NULL, RENDERTYPE_SCREEN, FALSE, pInvalidNode);
02732     }
02733 }
02734 
02735 
02736 /********************************************************************************************
02737 
02738 >   void DocView::FlushRedraw()
02739 
02740     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02741     Created:    22/12/94
02742     Purpose:    Intelligently invalidate all the regions gathered so far for this DocView.
02743                 This performs smart invalidation depending on the number and nature of the 
02744                 regions.
02745     SeeAlso:    DocView::ForceRedraw; PendingRedraws; SpreadRedraws
02746 
02747 ********************************************************************************************/
02748 
02749 void DocView::FlushRedraw()
02750 {
02751     // Ask the update list to do its stuff
02752     PendingRedrawList.FlushRedraw(this);
02753 }
02754 
02755 /********************************************************************************************
02756 
02757 >   void DocView::HandleNodeDeletion(Node* pNode)
02758 
02759     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02760     Created:    22/12/94
02761     Purpose:    Intelligently invalidate all the regions gathered so far for this DocView.
02762                 This performs smart invalidation depending on the number and nature of the 
02763                 regions.
02764     SeeAlso:    DocView::ForceRedraw; PendingRedraws; SpreadRedraws
02765 
02766 ********************************************************************************************/
02767 
02768 void DocView::HandleNodeDeletion(Node* pNode)
02769 {
02770     // Ask the update list to do its stuff
02771     PendingRedrawList.HandleNodeDeletion(pNode);
02772 }
02773 
02774 /********************************************************************************************
02775 
02776 >   ObjectDragTarget DocView::IsPointerOverNode(NodeRenderableInk** ThisNode, INT32 Range,
02777                                                 BOOL Interrupt = TRUE, BOOL bIsColourDrag=FALSE)
02778 
02779     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (and Will)
02780     Created:    23/1/95
02781     Outputs:    ThisNode - ptr to node over if any NULL otherwise
02782     Inputs:     Range - Margin to use in line hittest
02783                 Interrupt  - TRUE if the Hit Test should be interruptable or not.
02784 
02785                 // DMc inserted 6/5/99
02786                 For colour drags, you don't want to addess the shadow
02787                 or bevel controller node, but what's inside
02788                 
02789     Returns:    an ObjectDragTarget - FILL/LINE/STARTFILL/ENDFILL       
02790     Purpose:    to determine whether pointer is over 1 - an objects outline
02791                                                      2 - any visible fill blobs
02792                                                      3 - a simple (non grouped) object            
02793 ********************************************************************************************/
02794 
02795 ObjectDragTarget DocView::IsPointerOverNode(NodeRenderableInk** pThisNode, INT32 Range,
02796                                             BOOL Interrupt, BOOL bIsColourDrag)
02797 {
02798     Spread *pSpread=NULL;
02799     DocCoord pMousePos;
02800         
02801     // get the current spread and mouse pos
02802     if(!GetCurrentMousePos(&pSpread, &pMousePos))
02803         return NO_TARGET;
02804     
02805     // mouse pos to be used at end of drag
02806     DragPos = pMousePos;
02807 
02808     // ouch !
02809     if(!pSpread)
02810         return NO_TARGET;
02811 
02812     // See if we are close to the TextStory caret - We can't hittest on it as it is only a blob
02813     if (TextStory::GetFocusStory() != NULL)
02814     {
02815         CaretNode* pCaret = TextStory::GetFocusStory()->GetCaret();
02816         Matrix matrix;
02817 
02818         if ((pCaret != NULL) && pCaret->IsSelected() && (pCaret->GetStoryAndCharMatrix(&matrix)!=FALSE))
02819         {
02820             // get the bounds of the caret path for the blob bounds
02821             Path* pCaretPath = pCaret->CreatePath(&matrix);
02822             if (pCaretPath != NULL)
02823             {
02824                 INT32 CloseSlot = 0;
02825                 double mu = 0.0;
02826                 if (pCaretPath->IsPointCloseTo(pMousePos, Range*Range, &CloseSlot, &mu))
02827                 {
02828                     *pThisNode = pCaret;
02829                     delete pCaretPath;
02830                     return FILL_TARGET;
02831                 }
02832                 delete pCaretPath;
02833             }
02834         }
02835     }
02836 
02837     // Allow the hit-test to be interrupted if the mouse moves!
02838     Node* pInterruptedNode = NULL;
02839     NodeRenderableInk * pCompoundNode = NULL;
02840     NodeRenderableInk* pSimpleNode = NodeRenderableInk::FindSimpleAtPoint(pSpread,
02841                   pMousePos,
02842                   NULL,
02843                   Interrupt ? &pInterruptedNode : NULL);
02844 
02845     if (pInterruptedNode!=NULL)
02846         // hit-test was interrupted...
02847         pSimpleNode=NULL;
02848 
02849     // Now we have the 'Simple' node that the pointer was over.
02850 
02851     // If we can we should use any Selected nodes, so lets see if
02852     // this node or any of it's parents are selected.
02853     // We will stop if we get to the layer.
02854 
02855     if (pSimpleNode != NULL)    // Did we hit anything ?
02856     {
02857         Node* pSelNode = NULL;
02858 
02859         if ((ClickModifiers::GetClickModifiers().Constrain) || pSimpleNode->IsSelected())
02860         {
02861             // The node we hit was selected, so we will just use that
02862             pSelNode = pSimpleNode;
02863         }
02864         else
02865         {
02866             // Hunt up the tree, looking for a selected parent
02867             Node* pParent = pSimpleNode->FindParent();
02868             while (pParent != NULL && !pParent->IsLayer())
02869             {
02870                 if (pParent->IsSelected())
02871                 {
02872                     // Found a selected parent, so we'll use that
02873 
02874                     // don't do it for shadow controller nodes, or bevel nodes
02875                     if ((!pSimpleNode->IsKindOf(CC_RUNTIME_CLASS(NodeShadow)) &&
02876                         !pSimpleNode->IsKindOf(CC_RUNTIME_CLASS(NodeBevel))) ||
02877                         !bIsColourDrag)
02878                     {
02879                         pSelNode = pParent;
02880                     }
02881                     else
02882                     {
02883                         pSelNode = pSimpleNode;
02884                     }
02885 
02886                     
02887                     break;
02888                 }
02889 
02890                 pParent = pParent->FindParent();
02891             }
02892         }
02893 
02894         if (pSelNode != NULL)
02895         {
02896             // We will use the selected node in preference to anything else
02897             pSimpleNode = (NodeRenderableInk*)pSelNode;
02898         }
02899         else
02900         {
02901             // We didn't find any selected nodes, so we will try and apply
02902             // to a Parent group of the hit node.
02903 
02904             // This function will return the same node, if it has no parent group
02905 
02906             // DMc 6/5/99
02907             // change to hit testing for drags - don't do a compound node
02908             // for bevel controller or shadow controller nodes
02909             pCompoundNode = NodeRenderableInk::FindCompoundFromSimple(pSimpleNode);
02910             pSimpleNode = pCompoundNode;
02911 
02912             if ((!pSimpleNode->IsKindOf(CC_RUNTIME_CLASS(NodeShadow)) &&
02913                         !pSimpleNode->IsKindOf(CC_RUNTIME_CLASS(NodeBevel))) ||
02914                         !bIsColourDrag)
02915             {
02916                 pSimpleNode = pCompoundNode;
02917             }
02918     
02919         }
02920     }
02921     
02922     // we can pass this back to the drag target
02923 
02924     *pThisNode = pSimpleNode;
02925     
02926     
02927     // get the object bounds for this object 
02928     DocRect pSimpleBounds;
02929     if(pSimpleNode)
02930         pSimpleBounds = pSimpleNode->GetBoundingRect();
02931     else
02932         pSimpleBounds.MakeEmpty();
02933     
02934     AttrColourDrop *Attrib = new AttrColourDrop(pMousePos,pSimpleBounds,DocColour(COLOUR_TRANS));
02935 
02936     // this will sort out whether we are over any fill blobs 
02937     // pThisNode will then point to the relevant Node 
02938     // OverFill is the FillControl type we are currently over
02939     FillControl OverFill = AttrFillGeometry::DoColourDropTest(Attrib,pThisNode,NULL);
02940     delete Attrib;
02941 
02942     ObjectDragTarget TargetHit;
02943     
02944     // return the appropriate colour drag target 
02945     switch(OverFill)
02946     {
02947         case FILLCONTROL_STARTPOINT:
02948             TargetHit = STARTCOL_TARGET;
02949             break;
02950         
02951         case FILLCONTROL_ENDPOINT:
02952         case FILLCONTROL_SECONDARYPOINT:
02953             TargetHit = ENDCOL_TARGET;
02954             break;
02955         
02956         case FILLCONTROL_ENDPOINT2:
02957             TargetHit = ENDCOL2_TARGET;
02958             break;
02959         
02960         case FILLCONTROL_ENDPOINT3:
02961             TargetHit = ENDCOL3_TARGET;
02962             break;
02963         
02964         case FILLCONTROL_MANY:      
02965             TargetHit = MANY_TARGET;
02966             break;
02967 
02968         case FILLCONTROL_NULL:
02969             TargetHit = FILL_TARGET;
02970             break;
02971 
02972         default:
02973             TargetHit = FILL_TARGET;
02974             break;
02975     }   
02976     
02977         // BODGE ??? This should all change when we can do hit testing on lines.
02978     if(pSimpleNode)
02979     {
02980         // we're over an object - we'll see how close to its path we are
02981         Path* pPath = NULL; 
02982     
02983         if (IS_A(pSimpleNode, NodePath))
02984         {
02985             // get the node as a NodePath
02986             NodePath* pNPath = (NodePath*) pSimpleNode;
02987             pPath= &(pNPath->InkPath);
02988         }
02989         else if (pSimpleNode->IsKindOf(CC_RUNTIME_CLASS(NodeSimpleShape)))
02990         {
02991             // get the node as a NodeSimpleShape
02992             NodeSimpleShape * pNShape = (NodeSimpleShape*) pSimpleNode;
02993             pPath= &(pNShape->InkPath);
02994         }
02995         else if (pSimpleNode->IsKindOf(CC_RUNTIME_CLASS(NodeRegularShape)))
02996         {
02997             NodeRegularShape * pNShape = (NodeRegularShape*) pSimpleNode;
02998             pNShape->BuildShapePath(&pPath);
02999         }
03000 
03001         // we'll use the snap range to determine whether we are close to the path or not
03002         if(pPath)
03003         {
03004             INT32 CloseSlot = 0;
03005             double mu = 0.0;
03006             if (pPath->IsPointCloseTo(pMousePos,Range*Range, &CloseSlot, &mu))
03007             {
03008                 return LINE_TARGET;         // yes we are
03009             }
03010         }
03011     }
03012 
03013     return TargetHit;
03014 }
03015 
03016 /********************************************************************************************
03017 
03018 >   BOOL DocView::DM_DragFinished(DragInformation* DragInfo, ViewDragTarget* pDragTarget)
03019 
03020     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (and Will)
03021     Created:    23/1/95
03022     Inputs:     DragInformation - about this drag..
03023                 pDragTarget - The drag target created for this DocView
03024     Purpose:    act at the end of a general drag according to the drag type.
03025                                                                  
03026 ********************************************************************************************/
03027 
03028 BOOL DocView::DM_DragFinished(DragInformation* DragInfo, ViewDragTarget* pDragTarget)
03029 {
03030     // The DragInfo must know what to do, or else we wouldn't 
03031     // have accepted the drag
03032     BOOL DropOK = DragInfo->OnPageDrop(pDragTarget);
03033 
03034     return DropOK;
03035 }
03036 
03037 /********************************************************************************************
03038 
03039 >   void DocView::DragPointerMove(Operation* pDragOp, OilCoord PointerPos, ClickModifiers Mods)
03040 
03041     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03042     Created:    2/7/93
03043     Inputs:     pDragOp - Pointer to the current drag operation
03044                 PointerPos - Coordinate of pointer in OS space
03045                 Mods - Click modifiers structure
03046     Purpose:    Tell the current dragging operation that the pointer has moved. This function
03047                 is ony called when a drag has been started in CCamView by calling its
03048                 StartDrag function and should not be called after EndDrag has been called.
03049                                                                  
03050 ********************************************************************************************/
03051 
03052 void DocView::DragPointerMove(Operation* pDragOp, OilCoord PointerPos, ClickModifiers Mods)
03053 {
03054 //  BOOL bDragSolidly = FALSE;
03055 
03056     // Ignore if system is disabled
03057     if (CCamApp::IsDisabled())
03058         return;                             // If the system is disabled, ignore
03059 
03060     // Find the spread that contains DocPos
03061     Spread *pSpread = FindEnclosingSpread(PointerPos);
03062 
03063 // Note GetSelectedSpread is quicker in situations where you know you only have one spread
03064 //      but it prevents drags on multiple spread views working properly...
03065 //  Spread *pSpread = Document::GetSelectedSpread();
03066 
03067     if (pSpread == NULL)
03068     {
03069         ERROR3("Could not find spread in which the click happened");
03070         return; // Exit reasonably nicely
03071     }
03072 
03073     // Convert the OSRect into document coords
03074     DocCoord DocPos = PointerPos.ToDoc(pSpread, this);
03075 
03076     // Convert the coord to spread coords
03077     pSpread->DocCoordToSpreadCoord(&DocPos);
03078 
03079     // Store away the WorkCoord version of this click in the DocView for later extraction by
03080     // GetClickWorkCoord();
03081     LastWorkClick = PointerPos.ToWork( pVState->GetScrollPos() );
03082     ViewFlags.WorkClickCached = TRUE;           // Cached WorkCoord is valid.
03083 
03084     // Now call the current tool with the DocCoord click point
03085     ERROR3IF( pDragOp==NULL, "There was not operation in DragPointerMove()" );
03086     if (pDragOp)
03087         pDragOp->DragPointerMove(DocPos, Mods, pSpread, m_bSolidDrag);
03088 
03089     ViewFlags.WorkClickCached = FALSE;          // Cached WorkCoord is no longer valid!
03090 }
03091 
03092 
03093 
03094 
03095 /********************************************************************************************
03096 
03097 >   void DocView::DragPointerIdle(Operation* pDragOp, OilCoord PointerPos, ClickModifiers Mods)
03098 
03099     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03100     Created:    2/7/93
03101     Inputs:     pDragOp - Pointer to the current drag operation
03102                 PointerPos - Coordinate of pointer in OS space
03103                 Mods - Click modifiers structure
03104     Purpose:    Tell the current dragging operation that the pointer has NOT moved and that
03105                 there is idle CPU time to be used. This function is only called when a drag has
03106                 been started in CCamView by calling its StartDrag function and should not be
03107                 called after EndDrag has been called.
03108                                                                  
03109 ********************************************************************************************/
03110 
03111 void DocView::DragPointerIdle(Operation* pDragOp, OilCoord PointerPos, ClickModifiers Mods)
03112 {
03113     ERROR3IF(pDragOp == NULL, "Illegal NULL parameter!");
03114 
03115     // Ignore if system is disabled
03116     if (CCamApp::IsDisabled())
03117         return;                             // If the system is disabled, ignore
03118 
03119     // Find the spread that contains DocPos
03120     Spread *pSpread = FindEnclosingSpread(PointerPos);
03121 
03122 // Note GetSelectedSpread is quicker in situations where you know you only have one spread
03123 //      but it prevents drags on multiple spread views working properly...
03124 //  Spread *pSpread = Document::GetSelectedSpread();
03125 
03126     if (pSpread == NULL)
03127     {
03128         ERROR3("Could not find spread in which the click happened");
03129         return; // Exit reasonably nicely
03130     }
03131 
03132     // First of all convert the OSRect into document coords
03133     DocCoord DocPos = PointerPos.ToDoc(pSpread, this);
03134 
03135     // Convert the coord to spread coords
03136     pSpread->DocCoordToSpreadCoord(&DocPos);
03137 
03138     // Store away the WorkCoord version of this click in the DocView for later extraction by
03139     // GetClickWorkCoord();
03140     LastWorkClick = PointerPos.ToWork( pVState->GetScrollPos() );
03141     ViewFlags.WorkClickCached = TRUE;           // Cached WorkCoord is valid.
03142 
03143     // Now call the current tool with the DocCoord click point
03144     if (pDragOp != NULL)
03145         pDragOp->DragPointerIdle(DocPos, Mods, pSpread, m_bSolidDrag);
03146 
03147     // Cached WorkCoord is no longer valid!
03148     ViewFlags.WorkClickCached = FALSE;
03149 }
03150 
03151 
03152 
03153 
03154 /********************************************************************************************
03155 
03156 >   void DocView::DragFinished(Operation* pDragOp, OilCoord PointerPos, ClickModifiers Mods,
03157                                 BOOL Success)
03158 
03159     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03160     Created:    2/7/93
03161     Inputs:     pDragOp - Pointer to the current drag operation
03162                 PointerPos - Coordinate of pointer in OS space
03163                 Mods - Click modifiers structure
03164                 Success - Flag saying whether drag ended OK or was aborted for some reason
03165     Purpose:    Tell the current dragging operation that the drag has ended either because
03166                 the pointer buttons have all been released or the drag has been aborted in
03167                 some way (Escape was pressed?).
03168                 This function is ony called when a drag has been started in CCamView by
03169                 calling its StartDrag function and should not be called after EndDrag has been
03170                 called.
03171                                                                  
03172 ********************************************************************************************/
03173 
03174 void DocView::DragFinished(Operation* pDragOp, OilCoord PointerPos, ClickModifiers Mods,
03175                             BOOL Success)
03176 {
03177     // Ignore if system is disabled
03178     if (CCamApp::IsDisabled())
03179         return;                             // If the system is disabled, ignore
03180     // SHOULD END THE DRAG
03181 
03182     // Find the spread that contains DocPos
03183     Spread *pSpread = FindEnclosingSpread(PointerPos);
03184 
03185     if (pSpread == NULL)
03186     {
03187         ERROR3("Could not find spread in which the click happened");
03188         return; // Exit reasonably nicely
03189     }
03190 
03191     // First of all convert the OSRect into document coords
03192     DocCoord DocPos = PointerPos.ToDoc( pSpread, this );
03193 
03194     // Convert the coord to spread coords
03195     pSpread->DocCoordToSpreadCoord(&DocPos);
03196 
03197     // Store away the WorkCoord version of this click in the DocView for later extraction by
03198     // GetClickWorkCoord();
03199     LastWorkClick = PointerPos.ToWork( pVState->GetScrollPos() );
03200 
03201     // Cached WorkCoord is valid.
03202     ViewFlags.WorkClickCached = TRUE;
03203 
03204     // Broadcast a "starting operation" message to begin with (normally broadcast by
03205     // OpDescriptor::Invoke, but thanks to the brain-damaged Camelot architecture, operations
03206     // which drag do not invoke, and this is the best place to catch them.  Go figure.)
03207     BROADCAST_TO_ALL(OpMsg(pDragOp, OpMsg::BEGIN));
03208 
03209     // Now call the current tool with the DocCoord click point
03210     pDragOp->DragFinished(DocPos, Mods, pSpread, Success, m_bSolidDrag);
03211 
03212     // Cached WorkCoord is no longer valid!
03213     ViewFlags.WorkClickCached = FALSE;
03214     m_bSolidDrag = FALSE;
03215 }
03216 
03217 
03218 
03219 
03220 /********************************************************************************************
03221 
03222 >   void DocView::OnClick(OilCoord PointerPos, ClickType Click, ClickModifiers Mods)
03223 
03224     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03225     Created:    2/7/93
03226     Inputs:     PointerPos - Position of click from OS
03227                 Click - Type of click (single, double or drag)
03228                 Mods - Other inputs which modify the meaning of the click
03229     Purpose:    Convert click coordinates into DocCoords and pass them on to the current
03230                 tool.
03231                                                                  
03232 ********************************************************************************************/
03233 /*  Technical notes:
03234                 This routine also converts the click position into WorkCoords and keeps it
03235                 for those routines which need it. They can get it by calling
03236                 GetClickWorkCoord so long as the ViewState hasn't changed in the meantime.
03237 
03238 ********************************************************************************************/
03239 
03240 void DocView::OnClick(OilCoord PointerPos, ClickType Click, ClickModifiers Mods)
03241 {
03242     // Ignore if system is disabled
03243     if (CCamApp::IsDisabled())
03244         return;                             // If the system is disabled, ignore
03245 
03246     // grab the focus if it's stuck in  a control somewhere
03247     DialogManager::DefaultKeyboardFocus();  
03248     
03249     // Find the spread in which the click happened
03250     Spread *pSpread = FindEnclosingSpread(PointerPos);
03251 
03252     if (pSpread == NULL)
03253     {
03254         ERROR3("Could not find spread in which the click happened");
03255         return; // Exit reasonably nicely
03256     }
03257 
03258     // When the user clicks on a spread which is not the selected spread then this spread becomes
03259     // selected and the selection is cleared.
03260     //Document::SetSelectedSpread(pSpread);
03261     Document::SetSelectedViewAndSpread(pDoc, this, pSpread);
03262 
03263     //GetApplication()->FindSelection()->SetSelectedSpread(pSpread);
03264 
03265     // First of all convert the OilRect into device coords
03266     DocCoord DocPos = PointerPos.ToDoc( pSpread, this );
03267     
03268     // Convert the coord to spread coords
03269     pSpread->DocCoordToSpreadCoord(&DocPos);
03270 
03271 
03272     // Store away the WorkCoord version of this click in the DocView for later extraction by
03273     // GetClickWorkCoord();
03274     LastWorkClick = PointerPos.ToWork( pVState->GetScrollPos() );
03275     ViewFlags.WorkClickCached = TRUE;           // Cached WorkCoord is valid.
03276 
03277     // Check the click mods to see if they specify an operation which we can do directly here
03278     if (Mods.IsHandledByTool())
03279     {
03280         // Now call the current tool with the DocCoord click point
03281         // Graham 18/6/96: When one button clicks while another one is dragging
03282         // we call the current drag operation, not the tool
03283         if (Mods.ClickWhileDrag)
03284         {
03285             //First make sure there is a current drag operation
03286             ERROR3IF(Operation::GetCurrentDragOp()==NULL, "DocView::OnClick - no current drag operation");
03287 
03288             //Now call the current drag operation.
03289             //If the current drag operation is not a transform operation, this
03290             //will call the empty virtual function Operator::OnClickWhileDragging.
03291             Operation::GetCurrentDragOp()->OnClickWhileDragging(PointerPos, Click, Mods, m_bSolidDrag);
03292         }
03293         else if (Mods.PushCentreTool)
03294         {
03295             // Matt 16/11/2000 - Use the push tool/auto-screen-centrey-tool when required
03296             OpPush* pOpPush = new OpPush;
03297             ERROR3IF(!pOpPush,"Out of memory in DocView() -> Cannot create PushOp");
03298 
03299             // Matt 12/01/2001
03300             // Change the cursor to show the hand icon
03301             PushToolCursorID = CursorStack::GPush( &m_PushCursor, TRUE );
03302 
03303             // Start the drag operation and pass in the Anchor Point to the push operation
03304             pOpPush -> DoDrag( DocPos );
03305         }
03306         else
03307         {
03308             Tool* pCurrentTool = Tool::GetCurrent();
03309 
03310             if(pCurrentTool)
03311             {
03312                 pCurrentTool->OnClick(DocPos, Click, Mods, pSpread);
03313             }
03314         else
03315             ERROR3("No current tool in DocView::OnClick()!");
03316         }
03317 
03318         // ---------------------------------------------------------------------------
03319         // Do special handling for menu clicks
03320         // Allow the Selector to do it's normal stuff for "Click" events and "Up" events
03321         // So that menu clicks perform selection as required by Windows UI guidelines
03322         // On the up stroke show the context menu
03323         if (Mods.Menu)
03324         {
03325 #ifndef STANDALONE
03326             Tool* pSelector = Tool::FindTool(TOOLID_SELECTOR);
03327             ERROR3IF(pSelector==NULL, "ARGH! No Selector when DocView got a menu click!");
03328             Tool* pCurrentTool = Tool::GetCurrent();
03329             if (pSelector!=pCurrentTool &&
03330                 (Click == CLICKTYPE_SINGLE || Click == CLICKTYPE_UP) && // Don't allow menu drags while selector not current
03331                 !Mods.ClickWhileDrag &&
03332                 Operation::GetCurrentDragOp()==NULL)
03333             {
03334                 pSelector->OnClick(DocPos, Click, Mods, pSpread);
03335             }
03336 
03337             // On the up stroke
03338             if (Click==CLICKTYPE_UP && !Mods.ClickWhileDrag)
03339             {
03340 #ifdef PHOTOSHOPPLUGINS
03341                 // As we are just about to invoke a context menu, check that the plug-in manager has its list
03342                 // of available plug-ins otherwise, go and get it now as we are just about to need it.
03343                 // Must do it now before even the hint of a context menu is started as the context
03344                 // menus stack the automatic menu id and then restore it after they are destroyed.
03345                 // This is bad if our main plug in menu ids are in this range!
03346                 // We have to do it generally as at this point we don't know whether we are over a node
03347                 // such as NodeBitmap which requires it.
03348                 PlugInManager* pManager = GetApplication()->GetPlugInManager();
03349                 if (pManager)
03350                     pManager->CheckHaveDetailsOnPlugIns();
03351 #endif // PHOTOSHOPPLUGINS
03352                 
03353                 // Pop up the context sensitive view menu.
03354                 ViewContextMenu* pViewPopup = new ViewContextMenu;
03355                 pViewPopup->ShowOverView(pSpread, DocPos, Mods);
03356             }
03357 #endif
03358         }
03359         // ---------------------------------------------------------------------------
03360     }
03361     else
03362     {
03363         if (Click==CLICKTYPE_UP)
03364         {
03365             if (Mods.EditObject)
03366             {
03367                 // Find the node under the pointer and ask it what its favourite editing
03368                 // tool is.
03369             }
03370 
03371             else if (Mods.FullScreen)
03372             {
03373                 // Use the full screen toggle.
03374                 OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor( OPTOKEN_VIEWFULLSCREEN );
03375                 if (pOpDesc) pOpDesc->Invoke();
03376             }
03377 
03378             else if (Mods.ZoomIn)
03379             {
03380                 // Try to create an instance of the zoom operation.
03381                 OpZoom* pZoomOp = new OpZoom;
03382                 if (pZoomOp == NULL)
03383                 {
03384                     // We ran out of memory, so sorry.
03385                     InformError(_R(IDE_NOMORE_MEMORY));
03386                     return;
03387                 }           
03388 
03389                 // Zoom in or out around the mouse position.
03390                 if (Mods.Adjust)
03391                 {
03392                     pZoomOp->ZoomOut(LastWorkClick);
03393                 }
03394                 else
03395                 {
03396                     pZoomOp->ZoomIn(LastWorkClick);
03397                 }
03398             }
03399             else if (Mods.PushCentreTool)
03400             {
03401                 // Then the user wants us to centre the view about their mouse position
03402             }
03403 
03404         }
03405     }
03406 
03407     ViewFlags.WorkClickCached = FALSE;          // Cached WorkCoord is no longer valid!
03408 }
03409 
03410 
03411 
03412 /********************************************************************************************
03413 >   void DocView::OnMouseMove(OilCoord Pos, ClickModifiers mods)
03414 
03415     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> (Updated by Tim & Rik)
03416     Created:    14 Oct 93
03417     Inputs:     Pos - The position of the mouse, in OIL layer coordinates.
03418                 mods - which buttons/keys are down.
03419     Purpose:    Converts the mouse position into document coordinates, then calls the
03420                 OnMouseMove() function of the currently selected tool with this
03421                 information.
03422 
03423 ********************************************************************************************/
03424 
03425 void DocView::OnMouseMove(OilCoord Pos, ClickModifiers mods)
03426 {
03427     // Ignore if system is disabled
03428     if (CCamApp::IsDisabled())
03429         return;                             // If the system is disabled, ignore
03430 
03431     Spread *pSpread = FindEnclosingSpread(Pos);
03432     if (pSpread != NULL)
03433     {
03434         // Convert from OIL coordinates to document coordinates
03435         DocCoord DocPos = Pos.ToDoc(pSpread, this );
03436 
03437         // Convert the coord to spread coords
03438         pSpread->DocCoordToSpreadCoord(&DocPos);
03439 
03440         // Call the currently selected tool.
03441         Tool* pTool = Tool::GetCurrent();
03442 
03443         //Is there a currently selected tool?
03444         if (pTool != NULL)
03445         {
03446             // And pass the mouse move event to the tool.
03447             pTool->OnMouseMove(DocPos, pSpread, mods);
03448         }
03449         else
03450             //No, there's no currently selected tool. We're in Camelot so that's worrying.
03451             //Show an error.
03452             ERROR3("No current tool in DocView::OnMouseMove()!");
03453     }
03454 }
03455 
03456 
03457 
03458 /********************************************************************************************
03459 >   virtual BOOL DocView::HandleKeyPress(KeyPress* pKeyPress)
03460 
03461     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03462     Created:    6/10/94
03463     Inputs:     A pointer to the keypress event.
03464     Outputs:    -
03465     Returns:    TRUE if the event was handled by this function, or a function it called.
03466     Purpose:    Passes keystroke events to the current drag op, if dragging, or the
03467                 current tool, if not.
03468     Errors:     -
03469     SeeAlso:    App::OnKeyPress; Tool::OnKeyPress; Operation::DragKeyPress
03470 ********************************************************************************************/
03471 
03472 BOOL DocView::HandleKeyPress(KeyPress* pKeyPress)
03473 {
03474     // Ignore if system is disabled
03475     if (CCamApp::IsDisabled())
03476         return FALSE;                           // If the system is disabled, ignore
03477 
03478     // If we are dragging then pass the event on to the current drag operation.
03479     if (pCurrentDragOp != NULL)
03480     {
03481         // Handle the TAB key out here on behalf of ALL drag ops
03482         if (m_bSolidDragSupported && pKeyPress->IsPress() && !pKeyPress->IsRepeat())    // I.e. is this a non-auto-repeated key-down event?
03483         {
03484             switch (pKeyPress->GetVirtKey())
03485             {
03486                 // TAB key means "change solid dragging mode"
03487                 case CAMKEY(TAB):
03488                 {
03489                     DocView::SolidDragging = !DocView::SolidDragging;
03490                     m_bSolidDrag = (m_bSolidDragSupported && DocView::SolidDragging);
03491                     pCurrentDragOp->DragModeChanged(m_bSolidDrag);
03492 
03493                     // update indicator in StatusLine
03494                     DialogBarOp::SetSystemStateChanged();
03495                     break;
03496                 }
03497             }
03498         }
03499 
03500         return pCurrentDragOp->DragKeyPress(pKeyPress, m_bSolidDrag);
03501     }
03502     
03503     // Otherwise give the current tool, if any, the chance to deal with it.
03504     Tool* pTool = Tool::GetCurrent();
03505     return (pTool != NULL) ? pTool->OnKeyPress(pKeyPress) : FALSE;
03506 }
03507 
03508 
03509 
03510 /********************************************************************************************
03511 
03512 >   WorkCoord DocView::GetClickWorkCoord()
03513 
03514     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03515     Created:    7/7/93
03516     Returns:    The position of the last click in work coords
03517     Purpose:    To let people know where the last click was in Work Coordinates
03518                                                                  
03519 ********************************************************************************************/
03520 
03521 WorkCoord DocView::GetClickWorkCoord()
03522 {
03523     ERROR3IF(!ViewFlags.WorkClickCached,
03524                 "DocView::GetClickWorkCoord called when WorkClickCached is FALSE");
03525     return LastWorkClick;
03526 }
03527 
03528 
03529 
03530 /********************************************************************************************
03531 
03532 >   BOOL DocView::StartDrag(Operation* pDragOp, 
03533                             DragType type, 
03534                             DocRect* pMoveBBox,
03535                             DocCoord* StartPos,
03536                             BOOL KeepAccuracy,
03537                             BOOL bSolidDragSupported)
03538 
03539     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03540     Created:    2/7/93
03541     Inputs:     pDragOp - Pointer to the operation
03542                 type - the type of drag to do
03543                 pMoveBBox - 
03544                 StartPos - 
03545                 KeepAccuracy - TRUE if drag is biased towards accurate following of all mouse
03546                                     movements;
03547                                FALSE if drag is biased towards keeping up to date with user.
03548                 bSolidDragSupported
03549                             - FALSE (default) Do EORed outline dragging
03550                               TRUE  Update the tree during dragging
03551     Returns:    TRUE if all went well
03552     Purpose:    Tells the world that a drag is starting
03553                                                                  
03554 ********************************************************************************************/
03555 
03556 BOOL DocView::StartDrag(Operation* pDragOp, 
03557                         DragType type, 
03558                         DocRect* pMoveBBox, 
03559                         DocCoord* StartPos,
03560                         BOOL KeepAccuracy,
03561                         BOOL bSolidDragSupported)
03562 {
03563     // Ignore if system is disabled
03564     if (CCamApp::IsDisabled())
03565         return TRUE;                            // If the system is disabled, ignore
03566 
03567     if (pMoveBBox != NULL)
03568     {
03569         StartDragPos = *StartPos;
03570         if (pMoveBBox->ContainsCoord(StartDragPos))
03571         {
03572         }
03573     }
03574 
03575     // Remember the drag operation (this also serves as a flag to indicate whether we
03576     // are dragging or not).
03577     ERROR3IF(pCurrentDragOp != NULL, "Nested drag in DocView::StartDrag");
03578     ERROR3IF(pDragOp == NULL, "Null DragOp* in DocView::StartDrag?");
03579     pCurrentDragOp = pDragOp;
03580     m_bSolidDragSupported = bSolidDragSupported;
03581     m_bSolidDrag = (m_bSolidDragSupported && DocView::SolidDragging);
03582 
03583     ERROR3IF(pViewWindow==NULL, "ARGH! DocView is not connected to a window in StartDrag!");
03584     return pViewWindow->StartDrag(pDragOp, type, KeepAccuracy);
03585 }
03586 
03587 
03588 
03589 
03590 /********************************************************************************************
03591 
03592 >   BOOL DocView::EndDrag(Operation* pDragOp)
03593 
03594     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03595     Created:    2/7/93
03596     Inputs:     pDragOp - The current operation
03597     Returns:    TRUE if it workded
03598     Purpose:    Tell the oil layer that the drag has finished
03599                                                                  
03600 ********************************************************************************************/
03601 
03602 BOOL DocView::EndDrag(Operation* pDragOp)
03603 {
03604     ERROR3IF(pViewWindow == NULL, "ARGH! DocView is not connected to a window in EndDrag!");
03605 //  ERROR3IF(pCurrentDragOp == NULL, "Not dragging in DocView::EndDrag?");
03606 //  ERROR3IF(pDragOp != pCurrentDragOp, "DragOp pointer inconsistent in DocView::EndDrag");
03607     pCurrentDragOp = NULL;
03608 
03609     // Matt 12/01/2001 - Restore the cursor if we've changed it earlier to the push tool cursor...
03610     if (PushToolCursorID && (PushToolCursorID != 0))
03611     {
03612             CursorStack::GPop(PushToolCursorID);
03613             PushToolCursorID = 0;
03614     }
03615 
03616     return pViewWindow->EndDrag(pDragOp);
03617 }
03618 
03619 
03620 
03621 /********************************************************************************************
03622 
03623 >   BOOL DocView::ChangeDragType(DragType Type)
03624 
03625     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
03626     Created:    3/4/95
03627     Inputs:     Type - The type of drag to change to
03628     Returns:    TRUE if it worked, FALSE if it failed
03629     Purpose:    Change the type of drag during the middle of a drag. This can only be called
03630                 if there is a drag already happening (ie between calls to StartDrag and
03631                 EndDrag).
03632     Errors:     ERROR3 if there is no render window or there is no drag happening
03633     SeeAlso:    ScreenCamView::ChangeDragType
03634 
03635 ********************************************************************************************/
03636 
03637 BOOL DocView::ChangeDragType(DragType Type)
03638 {
03639     TRACE( _T("Warning - DocView::ChangeDragType called\n") );
03640     // A bit of error checking
03641     ERROR3IF(pViewWindow == NULL, "ARGH! DocView is not connected to a window in ChangeDragType!");
03642     ERROR3IF(pCurrentDragOp == NULL, "Not dragging in ChangeDragType");
03643 
03644     // Ask the Oil side of things to change the drag
03645     BOOL Result = pViewWindow->ChangeDragType(Type);
03646     return Result;
03647 }
03648 
03649 
03650 
03651 /********************************************************************************************
03652 
03653 >   void DocView::RenderSelectBlobs( DocRect Rect )
03654 
03655     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
03656     Created:    16/9/93
03657     Inputs:     Rect - The Clipping Rectangle of the bit to draw
03658     Purpose:    Renders the Selection blobs of all the currently selected objects.
03659     SeeAlso:    DocView::OnDraw
03660 
03661 ********************************************************************************************/
03662 
03663 void DocView::RenderSelectBlobs( DocRect Rect, Spread *pSpread )
03664 {
03665 //  TRACEUSER("Gerry", _T("RenderSelectBlobs (%d, %d) - (%d, %d)\n"), Rect.lo.x, Rect.lo.y, Rect.hi.x, Rect.hi.y);
03666 
03667     // Only render blobs if there is a selection, and this spread owns it.
03668     SelRange* Selected = GetApplication()->FindSelection();
03669 
03670     // Karim 29/06/2000
03671     //  PromoteToParent should never be set TRUE on the selection range, outside
03672     //  of code in which its modifications are required.
03673     //  I have included a TRACE statement here, as a 'quiet' note to programmers,
03674     //  should this occur.
03675     RangeControl rc = Selected->GetRangeControlFlags();
03676     if (rc.PromoteToParent)
03677     {
03678         TRACE( _T("DocView::RenderSelectBlobs; PromoteToParent is TRUE! Read inline comment for details.\n") );
03679         rc.PromoteToParent = FALSE;
03680         Selected->Range::SetRangeControl(rc);
03681     }
03682 
03683 //PostProcessorStack* pStack = Selected->GetPostProcessorStack();
03684 //ListRange* pLevel = pStack->GetNewLevelRange(FALSE);
03685 
03686     Node* pNode = Selected->FindFirst();
03687 //Node* pNode = pLevel->FindFirst();
03688     if ((pNode == NULL) || ( pNode->FindParentSpread() != pSpread))
03689         // This spread does not own selection
03690         return;
03691 
03692     // Go find the blob manager
03693     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
03694     ERROR3IF( BlobMgr == NULL, "BlobManager unexpectedly turned out NULL!");
03695 
03696     // Go and render the blobs
03697     RenderRegion* pRender = DocView::RenderOnTop( &Rect, pSpread, ClippedEOR );
03698     while (pRender)
03699     {
03700         pNode = Selected->FindFirst();
03701 //pNode = pLevel->FindFirst();
03702         while (pNode != NULL)
03703         {
03704             ERROR3IF(!pNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk)),
03705                     "Selected node is not a NodeRenderableInk in DocView::RenderSelectBlobs()");
03706 
03707             // Make sure that the nodes bounding box overlaps the redraw box
03708             //if ( Rect.IsIntersectedWith(((NodeRenderableInk*)pNode)->GetBlobBoundingRect()))
03709                 // tell the node to draw in its selection blobs
03710             //  ((NodeRenderableInk*)pNode)->RenderSelectBlobs();
03711 
03712             // Render those blobs           
03713             BlobMgr->RenderMyBlobs(&Rect, pSpread, (NodeRenderable*)pNode);
03714 
03715             // Find the next selected node to render
03716             pNode = Selected->FindNext(pNode);
03717 //pNode = pLevel->FindNext(pNode);
03718         }
03719 
03720         // Get the next render region
03721         pRender = DocView::GetNextOnTop(&Rect);
03722     }
03723 //delete pLevel;
03724 
03725     // Bodge to stop fill meshes EOR each other out.
03726     AttrFillGeometry::LastRenderedMesh = NULL;
03727 }
03728 
03729 
03730 
03731 /********************************************************************************************
03732 
03733 >   BOOL DocView::IsMouseMoved()
03734 
03735     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
03736     Created:    23/11/94
03737     Returns:    TRUE if the mouse has moved, FALSE if not
03738     Purpose:    This function finds out if the mouse has moved yet. This is only really
03739                 useful if you are doing some processing as a result of a mouse move
03740                 event. If, in the middle of your processing, you discover that the mouse
03741                 has moved again, you may be able to stop processing immediatly and wait
03742                 for the next mouse event to arrive in the not too distant future.
03743     SeeAlso:    CCamView::IsWaitingMouseMove
03744 
03745 ********************************************************************************************/
03746 
03747 BOOL DocView::IsMouseMoved()
03748 {
03749     PORTNOTETRACE("other","DocView::IsMouseMoved - do nothing");
03750 #ifndef EXCLUDE_FROM_XARALX
03751     // If there is a Cam View about, ask it to see if there are more ouse messages
03752     // kicking about
03753     if (pViewWindow!=NULL)
03754         return pViewWindow->IsWaitingMouseMove();
03755 #endif
03756     // there was no CamView, so no mouse messages
03757     return FALSE;
03758 }
03759 
03760 
03761 
03762 /********************************************************************************************
03763 >   static BOOL DocView::GetCurrentMousePos(Spread** ppSpread, DocCoord* pdcMousePos)
03764 
03765     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03766     Created:    12/10/94
03767     Inputs:     -
03768     Outputs:    ppSpread        pointer to a Spread pointer that will hold the spread
03769                                 containing the mouse
03770                 pdcMousePos     pointer to a DocCoord that will hold the coordinates of
03771                                 the mouse
03772     Returns:    TRUE if the mouse is within the "selected" DocView, FALSE otherwise.
03773     Purpose:    Reports the position of the mouse if it is within the "selected" DocView.
03774                 It position is "returned" in Spread coordinates.
03775     Errors:     -
03776     SeeAlso:    CCamView::GetCurrentMousePos
03777 ********************************************************************************************/
03778 
03779 BOOL DocView::GetCurrentMousePos(Spread** ppSpread, DocCoord* pdcMousePos)
03780 {
03781     // Valid output arguments must be provided.
03782     ERROR3IF(ppSpread == NULL, "Null Spread** in DocView::GetCurrentMousePos");
03783     ERROR3IF(pdcMousePos == NULL, "Null DocCoord* in DocView::GetCurrentMousePos");
03784 
03785     // Check if there is a "selected" DocView.
03786     if (Selected == NULL) return FALSE;
03787 
03788     // Ask the CCamView attached to the selected DocView to report the mouse position.
03789     OilCoord pt;
03790     if (!Selected->pViewWindow->GetCurrentMousePos(&pt)) return FALSE;
03791 
03792     // Convert the OIL coordinate to spread / doccoords.
03793     Spread* pSpread = Selected->FindEnclosingSpread(pt);
03794     if (pSpread == NULL)
03795     {
03796         ERROR3("Couldn't find a spread containing mouse position in DocView::GetCurrentMousePos");
03797         return FALSE;
03798     }
03799 
03800     // Convert the OSRect into document coords
03801     DocCoord dc = pt.ToDoc(pSpread, Selected );
03802 
03803     // Convert the coord to spread coords
03804     pSpread->DocCoordToSpreadCoord(&dc);
03805 
03806     // Return result and success code to caller.
03807     *ppSpread = pSpread;
03808     *pdcMousePos = dc;
03809     return TRUE;
03810 }
03811 
03812 
03813 
03814 
03815 /********************************************************************************************
03816 
03817 >   RenderRegion* DocView::GetFirstRenderRegion(const DocRect& ClipRect, Spread* pSpread,
03818                                                 OnTopCode Reason )
03819 
03820     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03821     Created:    23/8/93
03822     Inputs:     ClipRect - The Rectangle to clip to
03823                 pSpread - The Spread that the render region is for
03824                 Reason - the kind of rendering needed
03825     Returns:    A Ptr to a RenderRegion to render into.
03826     Purpose:    RenderRegion's cannt span Spreads, because different Matrices are needed
03827                 for the Coordinate transforms.  This Function (Along with GetNext...) is
03828                 used to Split a DocRect area into a number of RenderRegions depending on
03829                 the number of spreads the DocRect spans.
03830                 First call this function to return the first RenderRegion (there will always
03831                 be at least one for a valid DocRect), and then call GetNextRenderRegion until
03832                 it returns NULL (which may be immediately).  Repeat the Rendering process for
03833                 each RenderRegion returned.
03834                 You do NOT need to call Init/Exit Render as they will be set up for 
03835                 Immediate rendering.
03836     SeeAlso:    DocView::GetNextRenderRegion()
03837 
03838 ********************************************************************************************/
03839 
03840 RenderRegion* DocView::GetFirstRenderRegion(DocRect& ClipRect, Spread *pSpread, OnTopCode Reason)
03841 {
03842     // Construct the transformation matrix for the spread.
03843     Matrix RenderMatrix = ConstructRenderingMatrix(pSpread);
03844 
03845     // Make render region for intersection between spread and cliprect.
03846     // (Cliprect is still d)
03847     DocRect SpreadClipRect = pSpread->GetWidePasteboard(this);
03848 
03849     // Convert the coord to spread coords
03850     pSpread->DocCoordToSpreadCoord(&SpreadClipRect);
03851 
03852     // Clip to spread rectangle, if required
03853     if (Reason == ClippedEOR)
03854         SpreadClipRect = SpreadClipRect.Intersection(ClipRect);
03855     else
03856         SpreadClipRect = ClipRect;
03857 
03858     // Make sure that the clip region is valid after the intersection
03859     if ( (SpreadClipRect.IsValid()) && (!SpreadClipRect.IsEmpty()) )
03860     {
03861         RenderType rType = RENDERTYPE_NONE; // Initialise it! Mark H
03862 
03863         switch (Reason)
03864         {
03865             case CLICKBITMAP:   rType = RENDERTYPE_HITDETECT; break;
03866             case COLOURBITMAP:  rType = RENDERTYPE_COLOURBITMAP; break;
03867             case Normal:        rType = RENDERTYPE_SCREEN;
03868             default:            rType = RENDERTYPE_SCREENXOR; break;
03869         }
03870 
03871         CNativeDC* pDC = pViewWindow->GetRenderDC();
03872         ERROR3IF(!pDC, "No allocated DC");
03873 
03874         RenderRegion *NewRegion =   View::NewRenderRegion(SpreadClipRect, RenderMatrix, 
03875                                     pDC, pSpread, rType);
03876 
03877         if (NewRegion == NULL)
03878             TRACEALL( _T("Not enough memory to create render region\n") );
03879         else
03880             NewRegion->ImmediateRender();
03881 
03882         return NewRegion;
03883     }
03884 
03885     // No render region could be created as the spread clip rect was empty or invalid
03886     return NULL;
03887 }
03888 
03889 
03890 
03891 /********************************************************************************************
03892 
03893 >   RenderRegion* DocView::GetNextRenderRegion(const DocRect& ClipRect, Spread* pSpread,
03894                                                OnTopCode Reason)
03895 
03896     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03897     Created:    23/8/93
03898     Inputs:     ClipRect - The Rectangle to clip to
03899                 pSpread - The Spread that the render region is for
03900                 Reason - the kind of rendering needed
03901     Returns:    A Ptr to a RenderRegion to render into.
03902     Purpose:    Used to split a DocRect to be redrawn into one or more RenderRegions.
03903                 See DocView::GetFirstRenderRegion(DocRect& ClipRect) for more details.
03904     SeeAlso:    DocView::GetFirstRenderRegion()
03905 
03906 ********************************************************************************************/
03907 
03908 RenderRegion* DocView::GetNextRenderRegion(DocRect& ClipRect, Spread *pSpread, OnTopCode Reason)
03909 {
03910     // This needs to be expanded!
03911     // It's ok for Windows, but maybe not for other platforms...
03912     return NULL;
03913 }
03914 
03915 
03916 
03917 /********************************************************************************************
03918 
03919 >   RenderRegion* DocView::RenderOnTop( DocRect* Rect, OnTopCode Reason )
03920 
03921     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
03922     Created:    18/8/93
03923     Inputs:     Rect - The DocRect of the area that needs to be redrawn
03924                 Reason - EOR or Normal or CLICKBITMAP
03925     Returns:    A pointer to a render region, or NULL if a valid RRegion could not
03926                 be generated (or there were none to make in the first place
03927     Purpose:    Marks the start of an 'On Top' rendering loop. On Top simply means that
03928                 the rendering will be done directly over the top of anything else that
03929                 happens to be there, without causeing a redraw from the bottom of the tree.
03930                 This functions main use is drawing on the EOR blobs that show selection, are
03931                 part of a tool or are there to show a drag is in progress. This function could
03932                 also be used to draw objects that we know will be placed on top of all other
03933                 objects (ie a new object, being drawn for the first time).
03934                 You should always use a loop like the one below :-
03935                 MonoOn
03936                     RenderRegion* pRegion = DocView::RenderOnTop( MyRect, EOR );
03937                     while ( pRegion )
03938                     {
03939                         // Do your EOR rendering in here
03940                         pRegion = DocView::GetNextOnTop( MyRect );
03941                     }
03942                 MonoOff
03943                 This bit of code will loop through all the invalid regions that the OS needs
03944                 redrawing as well as all the rectangles that Camelot splits a region into
03945                 itself.
03946                 IMPORTANT : Because this is a loop, you should not change the state of any
03947                 data within it, because it will then be different the second time the code
03948                 in the loop is executed.
03949     SeeAlso:    DocView::GetNextOnTop
03950 
03951 ********************************************************************************************/
03952 
03953 RenderRegion* DocView::RenderOnTop( DocRect* Rect, Spread *pSpread, OnTopCode Reason )
03954 {
03955     RenderRegion* pRender = NULL; //RenderRegion::GetCurrent();
03956 
03957     if ( OnTopCount == 0 )
03958     {
03959         // Find out about the current view
03960         DocView* pCurrentView = GetSelected();
03961 
03962         // If there is no current view, then return NULL
03963         if (pCurrentView==NULL)
03964             return NULL;
03965 
03966         // We should only hand out render regions if the view is not in the process of dying
03967         if (pCurrentView->IsViewDying)
03968             return NULL;
03969 
03970         // if the spread is NULL then this is bad
03971         if (pSpread==NULL)
03972             return NULL;
03973 
03974         // Find the first rectangle or region that needs redrawing and make
03975         // a render region for it.
03976         DocRect ClipRect;
03977         if (Rect == NULL)
03978         {
03979             // Get the DocView's viewport, in Spread Coords
03980             ClipRect = pCurrentView->GetDocViewRect(pSpread);
03981             pSpread->DocCoordToSpreadCoord(&ClipRect);
03982         }
03983         else
03984             ClipRect = *Rect;
03985 
03986         // Make sure that the clip rect is valid
03987         if (!ClipRect.IsValid())
03988         {
03989             // The Clip rect was not a valid rectangle
03990             ERROR3("RenderOnTop was asked to render to an invalid rect.");
03991             return NULL;
03992         }
03993                 
03994         // Go and get a render region based on all this info
03995         pRender = pCurrentView->GetFirstRenderRegion(ClipRect, pSpread, Reason);
03996             
03997         // stop now if we did not get one
03998         if ( !pRender )
03999             return NULL;
04000 
04001         // Set the static Reason code so that all future calls to RenderOnTop and
04002         // GetNextOnTop will do the same thing
04003         OnTopReason = Reason;
04004         OnTopSpread = pSpread;
04005         OnTopRenderRegion = pRender;
04006     
04007         // Turn on EORing for the RenderRegion if needed
04008         if (( OnTopReason == UnclippedEOR ) || (OnTopReason == ClippedEOR))
04009             pRender -> SetDrawingMode( DM_EORPEN );
04010             
04011         // Increment the Static Counter so that we know how many times this
04012         // function has been called
04013         OnTopCount++;
04014         
04015         // return the render region
04016         return pRender;
04017     }
04018     else
04019     {
04020         // Get the current RenderOnTop RenderRegion
04021         pRender = OnTopRenderRegion;
04022         
04023         // If there is no current render region, then we had better stop now
04024         if (!pRender)
04025             return NULL;
04026 
04027         // Increment the Static Counter so that we know how many times this
04028         // function has been nested through
04029         OnTopCount++;
04030         
04031         // if we want to be EORing, then make sure that EORing has been switched on
04032         if (( OnTopReason == UnclippedEOR ) || (OnTopReason == ClippedEOR))
04033             pRender -> SetDrawingMode( DM_EORPEN );
04034         
04035         // return the current render region
04036         return pRender;
04037     }
04038 }
04039 
04040 
04041 
04042 
04043 
04044 /********************************************************************************************
04045 
04046 >   RenderRegion* DocView::GetNextOnTop(DocRect* Rect)
04047 
04048     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
04049     Created:    18/8/93
04050     Inputs:     Rect - A pointer to the DocRect that the Rendering is to be clipped to
04051     Returns:    A RenderRegion if there is another valid one to be rendered into, or
04052                 NULL if there is not
04053     Purpose:    This function continues the RenderOnTop loop, returning the next
04054                 RenderRegion to be considered. If we are not in the outer most
04055                 rendering loop then this function will return NULL, as it will be
04056                 up to the top level to re-call everyone with the next render region.
04057                 It should always be used as part of a rendering loop as described in
04058                 DocView::RenderOnTop.
04059     SeeAlso:    DocView::RenderOnTop
04060 
04061 ********************************************************************************************/
04062 
04063 RenderRegion* DocView::GetNextOnTop( DocRect* Rect )
04064 {
04065     ERROR3IF( OnTopCount <= 0, "GetNextOnTop was called before RenderOnTop was called\n" );
04066 
04067     RenderRegion* pRender = OnTopRenderRegion;
04068     
04069     if (OnTopCount == 1)
04070     {
04071         // Delete the old render region that is no longer needed
04072         if (pRender!=NULL)
04073         {
04074             pRender->StopRender();
04075 
04076             if (( OnTopReason == UnclippedEOR ) || (OnTopReason == ClippedEOR))
04077             {
04078                 // Detach the Static OnTopRegion
04079                 View::DeInitOnTopRegion();
04080             }
04081             else
04082             {
04083                 delete pRender;
04084             }
04085 
04086             pRender = NULL;
04087             OnTopRenderRegion = NULL;
04088         }
04089         
04090         // Find the current view
04091         DocView* pView = GetSelected();
04092         if (pView==NULL)
04093             return NULL;
04094 
04095         // Get the next rectangle or region and make a RenderRegion
04096         DocRect ClipRect;
04097         if (Rect == NULL)
04098         {
04099             // Get the DocView's viewport and convert it from document coords to
04100             // spread coords
04101             ClipRect = pView->GetDocViewRect(OnTopSpread);
04102             OnTopSpread->DocCoordToSpreadCoord(&ClipRect);
04103         }
04104         else
04105             ClipRect = *Rect;
04106 
04107         // Go and build a new render region
04108         pRender = pView->GetNextRenderRegion(ClipRect, OnTopSpread, OnTopReason);
04109         OnTopRenderRegion = pRender;
04110             
04111         // See if we got one
04112         if (!pRender)
04113         {
04114             // There were no more render regions, so decrement the call count and 
04115             // return NULL
04116             OnTopCount--;
04117             return NULL;
04118         }
04119 
04120         // Turn on EORing for the RenderRegion if needed
04121         if ((OnTopReason == UnclippedEOR) || (OnTopReason == ClippedEOR))
04122             pRender->SetDrawingMode(DM_EORPEN);
04123                 
04124         // return the render region
04125         return pRender;
04126     }
04127     else
04128     {
04129         // It is not up to this level to try and find more RenderRegions
04130         // so decrement the counter
04131         OnTopCount--;
04132 
04133         // No more RenderRegions here, so return NULL
04134         return NULL;
04135     }
04136 
04137     return NULL;
04138 }
04139 
04140 
04141 
04142 
04143 /********************************************************************************************
04144 
04145 >   Spread* DocView::OilToSpreadCoord(OilCoord oilpos, DocCoord* pdocpos)
04146 
04147     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04148     Created:    22/11/94
04149     Inputs:     oilpos  - OilCoord to find spread and DocCoord for.
04150     Outputs:    pdocpos - Pointer to DocCoord to receive DocCoord.
04151     Returns:    Spread* - Pointer to spread in which pdocpos is valid.
04152     Purpose:    Combines the functions of FindEnclosingSpread and OilCoord::ToDoc.
04153                 Finds which spread an OilCoord is in and then computes the DocCoord of
04154                 that position within the spread.
04155                                                                      
04156 ********************************************************************************************/
04157 
04158 Spread* DocView::OilToSpreadCoord(OilCoord oilpos, DocCoord* pdocpos)
04159 {
04160     // Preconditions
04161     ERROR2IF(this==NULL,NULL,"DocView::OilToDoc called on NULL pointer");
04162 
04163     // Clear the destination DocCoord in case it all goes horribly wrong...
04164     *pdocpos = DocCoord(0,0);
04165 
04166     // Find the spread that contains DocPos, if none then return NULL immediately...
04167     Spread *pSpread = FindEnclosingSpread(oilpos);
04168     if (pSpread != NULL)
04169     {
04170         // Convert the OilCoord into document coords...
04171         *pdocpos = oilpos.ToDoc(pSpread, this);
04172 
04173         // and then into Spread coords...
04174         pSpread->DocCoordToSpreadCoord(pdocpos);
04175     }
04176 
04177     // Return pointer to enclosing spread to caller.
04178     return pSpread;
04179 }
04180 
04181 
04182 
04183 /********************************************************************************************
04184 
04185 >   Spread *DocView::FindEnclosingSpread(OilCoord Pos)
04186 
04187     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
04188     Created:    15/12/93
04189     Inputs:     Pos - the coord to look for.
04190     Returns:    The spread that contains the coordinate, or NULL if such a spread does not
04191                 exist.
04192     Purpose:    Given a chapter and an OilCoord, finds the spread that contains the
04193                 coordinate.
04194 
04195 ********************************************************************************************/
04196 
04197 Spread *DocView::FindEnclosingSpread(OilCoord Pos)
04198 {
04199     // Find first spread in chapter
04200     Chapter* pChapter = Node::FindFirstChapter(pDoc);
04201     if (pChapter==NULL)
04202     {
04203         ERROR3( "There was no chapter in this document");
04204         return NULL;
04205     }
04206 
04207     Spread* pSpread = (Spread*)pChapter->FindFirstChild();
04208     ERROR3IF((pSpread == NULL) || !pSpread->IsSpread(), "Chapter has no spreads");
04209 
04210     // Optimisation for simple documents:
04211     // If only one chapter containing only one spread then that must be the
04212     // enclosing spread!
04213     if (pSpread && (pSpread->FindNext()==NULL || !pSpread->FindNext()->IsSpread()) && pChapter->FindNext()==NULL)
04214         return pSpread;
04215 
04216     // If the cursor was above the top of the document, then return the first spread
04217     // if there is one
04218     if (Pos.y >= 0)
04219         return pSpread;
04220 
04221     // Find this position in 64-bit work coords
04222     WorkCoord WorkPos = Pos.ToWork( pVState->GetScrollPos() );
04223 
04224     do
04225     {
04226         pSpread = (Spread *) pChapter->FindFirstChild();
04227         ERROR3IF((pSpread == NULL) || !pSpread->IsSpread(), 
04228                 "Chapter has no spreads");
04229 
04230         do
04231         {
04232             // Convert spread bounding box to logical coords
04233             DocRect PhysSpreadRect = pSpread->GetWidePasteboard(this);
04234             WorkRect LogSpreadRect;
04235             LogSpreadRect.lo = PhysSpreadRect.lo.ToWork(pSpread, this);
04236             LogSpreadRect.hi = PhysSpreadRect.hi.ToWork(pSpread, this);
04237 
04238             // Check if spread intersects the clipping rect
04239             if ((WorkPos.y <= LogSpreadRect.hi.y) &&
04240                 (WorkPos.y >= LogSpreadRect.lo.y))
04241             {
04242                 // Found the correct spread so stop looking.
04243                 return pSpread;
04244             }
04245 
04246             // try next spread
04247             pSpread = (Spread *) pSpread->FindNext();
04248             ERROR3IF((pSpread != NULL) && !(pSpread->IsSpread()),
04249                     "Spread is not a Spread!");
04250 
04251         } while (pSpread != NULL);
04252 
04253         // Was not in that chapter, so try the next one
04254         pChapter = (Chapter*) pChapter->FindNext();
04255         ERROR3IF( (pChapter!=NULL) && !(pChapter->IsKindOf(CC_RUNTIME_CLASS(Chapter))),
04256                  "Chapter is not a Chapter!" );
04257 
04258     } while (pChapter != NULL);
04259 
04260 
04261     ERROR3IF( pSpread == NULL, "Could not find spread in which the click happened");
04262 
04263     return pSpread;
04264 }
04265 
04266 //----------------------------------------------------------------------------
04267 //----------------------------------------------------------------------------
04268 //----------------------------------------------------------------------------
04269 //----------------------------------------------------------------------------
04270 
04271 /********************************************************************************************
04272 
04273 >   BOOL DocView::Snap(Spread* pSpread,DocCoord* pDocCoord,
04274                                 BOOL TryMagSnap = TRUE,
04275                                 BOOL TryGridSnap = TRUE)
04276  
04277     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04278     Created:    14/2/94 (modified 20/9/94)
04279     Inputs:     pSpread     = a ptr to a spread node
04280                 pDocCoord   = a coord relative to the given spread
04281     Returns:    TRUE    - The coord has been snapped to something
04282                 FALSE   - The coord is untouched by man and beast
04283     Purpose:    Allows you to easily snap a coord to something relevant in the given spread
04284                 (e.g. to a grid, magnetic object, etc).
04285     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04286 
04287 ********************************************************************************************/
04288 
04289 BOOL DocView::Snap(Spread* pSpread,DocCoord* pDocCoord,
04290                                 BOOL TryMagSnap,
04291                                 BOOL TryGridSnap)
04292 {
04293     BOOL Snapped = FALSE;
04294 
04295     if (pCSnap == NULL)
04296         pCSnap = new CSnap(this,pSpread);
04297 
04298     if (pCSnap != NULL)
04299     {
04300         pCSnap->SetSpread(pSpread);
04301         Snapped = pCSnap->Snap(pDocCoord,TryMagSnap,TryGridSnap);
04302     }
04303 
04304     return (Snapped);
04305 }
04306  
04307 /********************************************************************************************
04308 
04309 >   BOOL DocView::Snap(Spread* pSpread,DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
04310  
04311     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04312     Created:    14/2/94 (modified 20/9/94)
04313     Inputs:     pSpread     = a ptr to a spread node
04314                 pDocRect    = a rectangle relative to the given spread
04315                 PrevCoord   = Used to determine how rect is snapped 
04316                 CurCoord    = As above
04317     Returns:    TRUE    - The rect has been snapped to something
04318                 FALSE   - The rect is untouched by man and beast
04319     Purpose:    Allows you to easily snap a rectangle to something relevant in the given spread
04320                 (e.g. to a grid, magnetic object, etc).
04321     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04322 
04323 ********************************************************************************************/
04324 
04325 BOOL DocView::Snap(Spread* pSpread,DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
04326 {
04327     BOOL Snapped = FALSE;
04328 
04329     if (pCSnap == NULL)
04330         pCSnap = new CSnap(this,pSpread);
04331 
04332     if (pCSnap != NULL)
04333     {
04334         pCSnap->SetSpread(pSpread);
04335         Snapped = pCSnap->Snap(pDocRect,PrevCoord,CurCoord);
04336     }
04337 
04338     return (Snapped);
04339 }
04340 
04341 /********************************************************************************************
04342 
04343 >   static BOOL DocView::ForceSnapToGuides(Spread* pSpread, DocCoord* pDocCoord, GuidelineType Type)
04344  
04345     Author:     Martin Wuerthner <xara@mw-software.com>
04346     Created:    24/08/06
04347     Inputs:     pSpread     Pointer to spread on which node exists
04348                 pDocCoord   A coordinate to test magnetically against the node
04349     Returns:    TRUE    - The coord has been snapped to something
04350                 FALSE   - The coord is untouched by man and beast
04351     Purpose:    Calls guideline snapper ignoring enabling flags.
04352     Errors:     Will error in debug builds if there is no selected DocView
04353     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04354 
04355 ********************************************************************************************/
04356 
04357 BOOL DocView::ForceSnapToGuides(Spread* pSpread, DocCoord* pDocCoord, GuidelineType Type)
04358 {
04359     ERROR3IF(Selected == NULL,"DocView::ForceSnapToGuides called when no selected DocView");
04360 
04361     if (Selected != NULL)
04362     {
04363         BOOL Snapped = FALSE;
04364 
04365         if (Selected->pCSnap == NULL)
04366             Selected->pCSnap = new CSnap(Selected,pSpread);
04367 
04368         if (Selected->pCSnap != NULL)
04369         {
04370             Selected->pCSnap->SetSpread(pSpread);
04371             Snapped = Selected->pCSnap->SnapToGuidelines(pDocCoord, Type);
04372         }
04373 
04374         return (Snapped);
04375     }
04376     else
04377         return (FALSE);
04378 }
04379 
04380 /********************************************************************************************
04381 
04382 >   BOOL DocView::SnapSelected(Spread* pSpread,DocCoord* pDocCoord,
04383                                 BOOL TryMagSnap = TRUE,
04384                                 BOOL TryGridSnap = TRUE)
04385  
04386     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04387     Created:    14/2/94
04388     Inputs:     pSpread     = a ptr to a spread node
04389                 pDocCoord   = a coord relative to the given spread
04390     Returns:    TRUE    - The coord has been snapped to something
04391                 FALSE   - The coord is untouched by man and beast
04392     Purpose:    Calls the Snap(pSpread,pDocCoord) function of the selected DocView.
04393     Errors:     Will error in debug builds if there is no selected DocView
04394     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04395 
04396 ********************************************************************************************/
04397 
04398 BOOL DocView::SnapSelected(Spread* pSpread,DocCoord* pDocCoord,
04399                                 BOOL TryMagSnap,
04400                                 BOOL TryGridSnap)
04401 {
04402     ERROR3IF(Selected == NULL,"DocView::SnapSelected called when no selected DocView");
04403 
04404     if (Selected != NULL)
04405         return (Selected->Snap(pSpread,pDocCoord,TryMagSnap,TryGridSnap));
04406     else
04407         return (FALSE);
04408 }
04409 
04410 /********************************************************************************************
04411 
04412 >   static BOOL DocView::SnapToMagneticNode(Spread* pSpread, Node* pNode, DocCoord* pDocCoord)
04413  
04414     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04415     Created:    25/3/94
04416     Inputs:     pSpread     Pointer to spread on which node exists
04417                 pNode       Pointer to node to test magnetically
04418                 pDocCoord   A coordinate to test magnetically against the node
04419     Returns:    TRUE    - The coord has been snapped to something
04420                 FALSE   - The coord is untouched by man and beast
04421     Purpose:    Calls magnetic snapping functions taking into acount the control flags
04422                 held in this DocView.
04423     Errors:     Will error in debug builds if there is no selected DocView
04424     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04425 
04426 ********************************************************************************************/
04427 
04428 BOOL DocView::SnapToMagneticNode(Spread* pSpread, Node* pNode, DocCoord* pDocCoord)
04429 {
04430     ERROR3IF(Selected == NULL,"DocView::SnapSelected called when no selected DocView");
04431 
04432     if (Selected != NULL)
04433     {
04434         BOOL Snapped = FALSE;
04435 
04436         if (Selected->pCSnap == NULL)
04437             Selected->pCSnap = new CSnap(Selected,pSpread);
04438 
04439         if (Selected->pCSnap != NULL)
04440         {
04441             Selected->pCSnap->SetSpread(pSpread);
04442             Snapped = Selected->pCSnap->TryToSnapToObject(pNode, pDocCoord);
04443         }
04444 
04445         return (Snapped);
04446     }
04447     else
04448         return (FALSE);
04449 }
04450 
04451 /********************************************************************************************
04452 
04453 >   static BOOL DocView::ForceSnapToGrid(Spread* pSpread, DocCoord* pDocCoord)
04454  
04455     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04456     Created:    28/3/94
04457     Inputs:     pSpread     Pointer to spread on which node exists
04458                 pDocCoord   A coordinate to test magnetically against the node
04459     Returns:    TRUE    - The coord has been snapped to something
04460                 FALSE   - The coord is untouched by man and beast
04461     Purpose:    Calls grid snapper ignoring enabling flags.
04462     Errors:     Will error in debug builds if there is no selected DocView
04463     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04464 
04465 ********************************************************************************************/
04466 
04467 BOOL DocView::ForceSnapToGrid(Spread* pSpread, DocCoord* pDocCoord)
04468 {
04469     ERROR3IF(Selected == NULL,"DocView::SnapSelected called when no selected DocView");
04470 
04471     if (Selected != NULL)
04472     {
04473         BOOL Snapped = FALSE;
04474 
04475         if (Selected->pCSnap == NULL)
04476             Selected->pCSnap = new CSnap(Selected,pSpread);
04477 
04478         if (Selected->pCSnap != NULL)
04479         {
04480             Selected->pCSnap->SetSpread(pSpread);
04481             Snapped = Selected->pCSnap->SnapToGrids(pDocCoord);
04482         }
04483 
04484         return (Snapped);
04485     }
04486     else
04487         return (FALSE);
04488 }
04489 
04490 /********************************************************************************************
04491 
04492 >   BOOL DocView::SnapSelected(Spread* pSpread,DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
04493  
04494     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04495     Created:    14/2/94
04496     Inputs:     pSpread     = a ptr to a spread node
04497                 pDocRect    = a rectangle relative to the given spread
04498                 PrevCoord   = Used to determine how rect is snapped 
04499                 CurCoord    = As above
04500     Returns:    TRUE    - The rect has been snapped to something
04501                 FALSE   - The rect is untouched by man and beast
04502     Purpose:    Calls the Snap(pSpread,pDocRect,PrevCoord,CurCoord) function of the selected DocView.
04503     Errors:     Will error in debug builds if there is no selected DocView
04504     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04505 
04506 ********************************************************************************************/
04507 
04508 BOOL DocView::SnapSelected(Spread* pSpread,DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
04509 {
04510     ERROR3IF(Selected == NULL,"DocView::SnapSelected called when no selected DocView");
04511 
04512     if (Selected != NULL)
04513         return (Selected->Snap(pSpread,pDocRect,PrevCoord,CurCoord));
04514     else
04515         return (FALSE);
04516 }
04517 
04518 /********************************************************************************************
04519 
04520 >   BOOL DocView::SnapCurrent(Spread* pSpread,DocCoord* pDocCoord,
04521                                 BOOL TryMagSnap = TRUE,
04522                                 BOOL TryGridSnap = TRUE)
04523  
04524     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04525     Created:    14/2/94
04526     Inputs:     pSpread     = a ptr to a spread node
04527                 pDocCoord   = a coord relative to the given spread
04528     Returns:    TRUE    - The coord has been snapped to something
04529                 FALSE   - The coord is untouched by man and beast
04530     Purpose:    Calls the Snap(pSpread,pDocCoord) function of the Current DocView.
04531     Errors:     Will error in debug builds if there is no Current DocView
04532     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04533 
04534 ********************************************************************************************/
04535 
04536 BOOL DocView::SnapCurrent(Spread* pSpread,DocCoord* pDocCoord,
04537                                 BOOL TryMagSnap,
04538                                 BOOL TryGridSnap)
04539 {
04540     ERROR3IF(Current == NULL,"DocView::SnapCurrent called when no Current DocView");
04541 
04542     DocView *pCurrent = GetCurrent();
04543 
04544     if (pCurrent != NULL)
04545         return (pCurrent->Snap(pSpread,pDocCoord,TryMagSnap,TryGridSnap));
04546     else
04547         return (FALSE);
04548 }
04549 
04550 /********************************************************************************************
04551 
04552 >   BOOL DocView::SnapCurrent(Spread* pSpread,DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
04553  
04554     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04555     Created:    14/2/94
04556     Inputs:     pSpread     = a ptr to a spread node
04557                 pDocRect    = a rectangle relative to the given spread
04558                 PrevCoord   = Used to determine how rect is snapped 
04559                 CurCoord    = As above
04560     Returns:    TRUE    - The rect has been snapped to something
04561                 FALSE   - The rect is untouched by man and beast
04562     Purpose:    Calls the Snap(pSpread,pDocRect,PrevCoord,CurCoord) function of the Current DocView.
04563     Errors:     Will error in debug builds if there is no Current DocView
04564     SeeAlso:    All Snap member functions of all classes derived from NodeRenderableBounded.
04565 
04566 ********************************************************************************************/
04567 
04568 BOOL DocView::SnapCurrent(Spread* pSpread,DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
04569 {
04570     ERROR3IF(Current == NULL,"DocView::SnapCurrent called when no Current DocView");
04571 
04572     DocView *pCurrent = GetCurrent();
04573 
04574     if (pCurrent != NULL)
04575         return (pCurrent->Snap(pSpread,pDocRect,PrevCoord,CurCoord));
04576     else
04577         return (FALSE);
04578 }
04579 
04580 //----------------------------------------------------------------------------
04581 
04582 /********************************************************************************************
04583 
04584 >   void DocView::SetSnapToGridState(BOOL SnapToGrid)
04585  
04586     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04587     Created:    14/2/94
04588     Inputs:     SnapToGrid  - A bool used to set the snap status of grids in the view
04589     Returns:    -
04590     Purpose:    Allow you to change the "snap to grid" state of a DocView.
04591     SeeAlso:
04592 
04593 ********************************************************************************************/
04594 
04595 void DocView::SetSnapToGridState(BOOL SnapToGrid)
04596 {
04597     ViewFlags.GridSnap = SnapToGrid;
04598 }
04599 
04600 /********************************************************************************************
04601 
04602 >   BOOL DocView::GetSnapToGridState()
04603  
04604     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04605     Created:    14/2/94
04606     Inputs:     -
04607     Returns:    TRUE    - snap to grids in the doc view
04608                 FALSE   - don't snap to grids in the doc view
04609     Purpose:    To find the "Snap to grid" state of a DocView
04610     SeeAlso:
04611 
04612 ********************************************************************************************/
04613 
04614 BOOL DocView::GetSnapToGridState()
04615 {
04616     return (ViewFlags.GridSnap);
04617 }
04618 
04619 /********************************************************************************************
04620 
04621 >   void DocView::SetSnapToObjectsState(BOOL SnapToObjects)
04622  
04623     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04624     Created:    20/9/94
04625     Inputs:     SnapToObjects - A bool used to set the snap status of all objects in the view
04626     Returns:    -
04627     Purpose:    Allow you to change the "snap to all objects" state of a DocView.
04628     SeeAlso:
04629 
04630 ********************************************************************************************/
04631 
04632 void DocView::SetSnapToObjectsState(BOOL SnapToObjects)
04633 {
04634     ViewFlags.ObjectsSnap = SnapToObjects;
04635 }
04636 
04637 /********************************************************************************************
04638 
04639 >   BOOL DocView::GetSnapToObjectsState()
04640  
04641     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04642     Created:    20/9/94
04643     Inputs:     -
04644     Returns:    TRUE    - snap to objects in the doc view
04645                 FALSE   - don't snap to objects in the doc view
04646     Purpose:    To find the "Snap to all objects" state of a DocView
04647     SeeAlso:
04648 
04649 ********************************************************************************************/
04650 
04651 BOOL DocView::GetSnapToObjectsState()
04652 {
04653     return (ViewFlags.ObjectsSnap);
04654 }
04655 
04656 /********************************************************************************************
04657 
04658 >   void DocView::SetSnapToMagObjectsState(BOOL SnapToMagObjects)
04659  
04660     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04661     Created:    20/9/94
04662     Inputs:     SnapToMagObjects - A bool used to set the snap status of magnetic objects in the view
04663     Returns:    -
04664     Purpose:    Allow you to change the "snap to magnetic objects" state of a DocView.
04665     SeeAlso:
04666 
04667 ********************************************************************************************/
04668 
04669 void DocView::SetSnapToMagObjectsState(BOOL SnapToMagObjects)
04670 {
04671     ViewFlags.MagObjectsSnap = SnapToMagObjects;
04672 }
04673 
04674 /********************************************************************************************
04675 
04676 >   BOOL DocView::GetSnapToMagObjectsState()
04677  
04678     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04679     Created:    20/9/94
04680     Inputs:     -
04681     Returns:    TRUE    - snap to magnetic objects in the doc view
04682                 FALSE   - don't snap to magnetic objects in the doc view
04683     Purpose:    To find the "Snap to magnetic objects" state of a DocView
04684     SeeAlso:
04685 
04686 ********************************************************************************************/
04687 
04688 BOOL DocView::GetSnapToMagObjectsState()
04689 {
04690     return (ViewFlags.MagObjectsSnap);
04691 }
04692 
04693 /********************************************************************************************
04694 
04695 >   void DocView::SetShowGridState(BOOL ShowGrid)
04696  
04697     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04698     Created:    14/2/94
04699     Inputs:     ShowGrid    - A bool used to set the visible status of grids in the view
04700     Returns:    -
04701     Purpose:    Allow you to change the "show grid" state of a DocView.
04702     SeeAlso:
04703 
04704 ********************************************************************************************/
04705 
04706 void DocView::SetShowGridState(BOOL ShowGrid)
04707 {
04708     ViewFlags.GridShow = ShowGrid;
04709 }
04710 
04711 /********************************************************************************************
04712 
04713 >   BOOL DocView::GetShowGridState()
04714  
04715     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04716     Created:    14/2/94
04717     Inputs:     -
04718     Returns:    TRUE    - grids are visible in the doc view
04719                 FALSE   - grids are not visible in the doc view
04720     Purpose:    To find the "Show grid" state of a DocView
04721     SeeAlso:
04722 
04723 ********************************************************************************************/
04724 
04725 BOOL DocView::GetShowGridState()
04726 {
04727     return (ViewFlags.GridShow);
04728 }
04729 
04730 
04731 //----------------------------------------------------------------------------
04732 //----------------------------------------------------------------------------
04733 //----------------------------------------------------------------------------
04734 //----------------------------------------------------------------------------
04735 //----------------------------------------------------------------------------
04736 
04737 
04738 
04739 
04740 /********************************************************************************************
04741 
04742 >   static void DocView::ConstrainToAngle(DocCoord& Centre, DocCoord* CurCoord,
04743                                           double Constrain = 0.0)
04744 
04745     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
04746     Created:    14/7/94
04747     Inputs:     Centre - The point that all the constrain rays come from
04748                 Constrain - The constrain angle in Radians. You should not pass in this
04749                 param except in very special circumstances. When this param is left out
04750                 the constrain angle from the users preferences is used, which should be
04751                 the way it is done in almost all circumstances.
04752     Outputs:    CurCoord - contains the mouse coord on entry and contains the constrained
04753                 mouse coord afterwards
04754     Purpose:    Constrains the mouse movement to rays coming out from a central point. This
04755                 is ideal for rotation etc. You should use this version of the function as
04756                 the other verison of the function is being phased out right now.
04757 
04758 ********************************************************************************************/
04759 
04760 void DocView::ConstrainToAngle(DocCoord& Centre, DocCoord* CurCoord, double Constrain)
04761 {
04762     if (Constrain==0.0)
04763     {
04764         // Use the angle found in the preferences
04765         Constrain = DefaultConstrainAngle;
04766     }
04767 
04768     // Find out which of the 2 axis are the most significant
04769     double dx = CurCoord->x - Centre.x;
04770     double dy = CurCoord->y - Centre.y;
04771 
04772     // make sure that the cursor is not over the origin
04773     if ((dx==0) && (dy==0))
04774         return;
04775 
04776     // Find the square of the length of the ray
04777     double RayLength = sqrt((dy*dy) + (dx*dx));
04778 
04779     // Find the angle that this coord is around a circle
04780     double Angle = atan2(dy, dx);
04781 
04782     // constrain the angle to the nearest band
04783     double SnapAngle = (Angle + (Constrain/2)) / Constrain;
04784     SnapAngle = floor(SnapAngle);
04785     SnapAngle *= Constrain;
04786 
04787     // recalculate the new coordinate for the cursor
04788     dx = (INT32)(RayLength * cos(SnapAngle));
04789     dy = (INT32)(RayLength * sin(SnapAngle));
04790 
04791     // Calculate the new position for the cursor
04792     CurCoord->x = (INT32)(Centre.x + dx);
04793     CurCoord->y = (INT32)(Centre.y + dy);
04794 }
04795 
04796 
04797 /********************************************************************************************
04798 
04799 >   void DocView::ConstrainToAngle(DocCoord& Centre, double Constrain, DocCoord* CurCoord)
04800 
04801     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
04802     Created:    14/7/94
04803     Inputs:     Centre - The point that all the constrain rays come from
04804                 Constrain - The constrain angle in Radians
04805     Outputs:    CurCoord - contains the mouse coord on entry and contains the constrained
04806                 mouse coord afterwards
04807     Purpose:    Constrains the mouse movement to rays coming out from a central point. This
04808                 is ideal for rotation etc.
04809                 DO NOT USE THIS VERSION OF THE FUNCTION. There is a newer version that
04810                 makes use of the constrain angle in the preferences and should be used
04811                 instead of this version.
04812 
04813 ********************************************************************************************/
04814 
04815 void DocView::ConstrainToAngle(DocCoord& Centre, double Constrain, DocCoord* CurCoord)
04816 {
04817     // Just call the new version of the function
04818     ConstrainToAngle(Centre, CurCoord, Constrain);
04819 }
04820 
04821 
04822 /********************************************************************************************
04823 
04824 >   void DocView::ConstrainToAspect(DocCoord& FixedCoord, FIXED16& AspectLock, DocCoord* CurCoord)
04825 
04826     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
04827     Created:    14/7/94
04828     Inputs:     FixedCoord - a fixed reference point, usually the opposite corner of the
04829                 bounding rectangle to be constrained
04830                 AspectLock - The aspect ratio to maintain (1 is square)
04831     Outputs:    CurCoord - This coordinate will be modified so that it forms a rectangle of
04832                 the correct aspect ratio from the fixed corner.
04833     Purpose:    Forces the supplied coordinate to be constrained to positions that force
04834                 the aspect ratio from the fixed corner to be the one supplied. It should be
04835                 called by the tools to 'snap' the coordinates from a drag to positions
04836                 where the shape is not deformed.
04837                 NOT FINISHED
04838     SeeAlso:    DocView::ConstrainToAngle()
04839 
04840 ********************************************************************************************/
04841 
04842 void DocView::ConstrainToAspect(DocCoord& FixedCoord, FIXED16& AspectLock, DocCoord* CurCoord)
04843 {
04844     // Get something to avoid all the rampant *s in my code
04845     DocCoord& DiffCoord = *CurCoord;
04846 
04847     // Find out which of the 2 axis are the most significant
04848     INT32 dx = DiffCoord.x - FixedCoord.x;
04849     INT32 dy = DiffCoord.y - FixedCoord.y;
04850     double dAspect = AspectLock.MakeDouble();
04851 
04852     if (abs(dx)>abs(dy))
04853     {
04854         // The x coord is the most significant, so change the y coord to match
04855         // First work out the magnitude of the change and correct it for sign
04856         INT32 NewOffset = (INT32)(abs(dx) / dAspect);
04857         if (dy<0)
04858             NewOffset = -NewOffset;
04859 
04860         // add in the difference
04861         DiffCoord.y = FixedCoord.y + NewOffset;
04862     }
04863     else
04864     {
04865         // The y coord is the most significant, so chnage the x coord to match
04866         // First work out the magnitude of the change and correct it for sign
04867         INT32 NewOffset = (INT32)(abs(dy) * dAspect);
04868         if (dx<0)
04869             NewOffset = -NewOffset;
04870 
04871         // add in the difference
04872         DiffCoord.x = FixedCoord.x + NewOffset;
04873     }
04874 }
04875 
04876 
04877 
04878 
04879 /********************************************************************************************
04880 
04881 >   Spread* DocView::GetVisibleSpread()
04882 
04883     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04884     Created:    18/5/94
04885     Returns:    A pointer to a Spread, or NULL.
04886     Purpose:    Compares the bounding rectangles of Spreads in this view's document with
04887                 the section of the document currently visible in the view, looking for
04888                 the largest spread object that is within the view.  If none are visible
04889                 then the function returns NULL.
04890 
04891                 NB. hacked to simply return the first spread for the v1 release.
04892     Errors:     -
04893     SeeAlso:    DocView::GetFirstSelectedSpread
04894 
04895 d********************************************************************************************/
04896 
04897 Spread* DocView::GetVisibleSpread()
04898 {
04899     // Initially we have no visible spread, which has zero area (of course).
04900     Spread* pCandidateSpread = NULL;
04901 //  XLONG xlCandidateArea = 0;
04902 
04903     // Begin by finding the extent of the viewport.
04904     WorkRect wrViewPort = GetViewRect();
04905 
04906     // Check that we have a document.
04907     if (pDoc == NULL) 
04908         return NULL;
04909 
04910     // Find the first node in the document's tree.
04911     Node* pNode = pDoc->GetFirstNode();
04912     if (pNode == NULL) 
04913         return NULL;
04914 
04915     // Find its first sibling, which should be a NodeDocument.
04916     pNode = pNode->FindNext();
04917     if (pNode == NULL) 
04918         return NULL;
04919 
04920     ERROR3IF(!pNode->IsKindOf(CC_RUNTIME_CLASS(NodeDocument)),
04921                 "Can't find a NodeDocument in DocView::GetVisibleSpread");
04922 
04923     // Find the first child node of the NodeDocument.
04924     pNode = pNode->FindFirstChild();
04925     if (pNode == NULL) return NULL;
04926 
04927     // Check if it's a chapter, skip it if it isn't.
04928     if (pNode->GetRuntimeClass() != CC_RUNTIME_CLASS(Chapter))
04929     { 
04930         pNode = pNode->FindNext(CC_RUNTIME_CLASS(Chapter));
04931         if (pNode == NULL) return NULL;
04932     }
04933     
04934     // We've found a chapter.
04935     Chapter* pChapter = (Chapter*) pNode;
04936 //  do {
04937         // Find the first child of the chapter.
04938         pNode = pChapter->FindFirstChild();
04939         if (pNode == NULL) return NULL;
04940 
04941         // If it isn't a spread then skip it.
04942         if (pNode->GetRuntimeClass() != CC_RUNTIME_CLASS(Spread))
04943         {
04944             pNode = pNode->FindNext(CC_RUNTIME_CLASS(Spread));
04945             if (pNode == NULL) return NULL;
04946         } 
04947         
04948         // Now check all sibling spreads.
04949         Spread* pSpread = (Spread*) pNode;
04950 /*      do {
04951             // At last, we found a spread!  Get its bounding rectangle in
04952             // document coordinates.
04953             DocRect drBound = pSpread->GetPageBounds();
04954 
04955             // Convert to work coordinates.
04956             WorkRect wrBound(drBound.lo.ToWork(pSpread, this),
04957                              drBound.hi.ToWork(pSpread, this));
04958 
04959             // If it intersects with the current viewport then we check if it is
04960             // the largest considered so far.
04961             WorkRect wrIntersect = wrBound.Intersection(wrViewPort);
04962             if (wrIntersect.IsValid() && !wrIntersect.IsEmpty())
04963             {
04964                 XLONG xlArea = wrIntersect.Width() * wrIntersect.Height();
04965                 if (xlArea > xlCandidateArea)
04966                 {
04967 */                  // It is the largest so far, so remember it.
04968                     pCandidateSpread = pSpread;
04969 /*                  xlCandidateArea = xlArea;
04970                 }
04971             }
04972 
04973             // Find the next sibling spread, if any.
04974             pSpread = (Spread*) pSpread->FindNext(CC_RUNTIME_CLASS(Spread));
04975         }
04976         while (pSpread != NULL);
04977 
04978         // Find the next sibling chapter, if any.
04979         pChapter = (Chapter*) pChapter->FindNext(CC_RUNTIME_CLASS(Chapter));
04980     } while (pChapter != NULL);
04981 */
04982     // If we get here we couldn't find anything!
04983     return pCandidateSpread;
04984 }
04985 
04986 
04987 
04988 /********************************************************************************************
04989 
04990 >   Spread* DocView::GetFirstSelectedSpread()
04991 
04992     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04993     Created:    18/5/94
04994     Inputs:     -
04995     Outputs:    -
04996     Returns:    A pointer to a Spread node in this view's document, or NULL.
04997     Purpose:    Searches for a selected object in the document, and returns a pointer to
04998                 the spread containing said object.  If there are no selected objects then
04999                 it returns NULL.
05000     Errors:     -
05001     SeeAlso:    DocView::GetVisibleSpread
05002 
05003 ********************************************************************************************/
05004 
05005 Spread* DocView::GetFirstSelectedSpread()
05006 {
05007     // Obtain the current selection, if any.
05008     //GetApplication()->UpdateSelection();
05009     SelRange* pSel = GetApplication()->FindSelection();
05010     if (pSel == NULL) return NULL;
05011     
05012     // Find the first selected object.
05013     Node* pFirstSelectedNode = pSel->FindFirst();
05014 
05015     // If there isn't one, then there is no spread with sel objects.
05016     // Otherwise get the selected object's parent spread.
05017     return (pFirstSelectedNode != NULL)
05018          ? (Spread*) pFirstSelectedNode->FindParent(CC_RUNTIME_CLASS(Spread))
05019          : NULL;
05020 }
05021 
05022 
05023 
05024 /***********************************************************************************************
05025 
05026 >   BOOL DocView::IsSingleClickReallyTriple() const
05027 
05028     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
05029     Created:    22/12/95
05030     Inputs:     -
05031     Outputs:    -
05032     Returns:    TRUE if the last click event was a triple click.  FALSE if not, or the attached
05033                 oil view is not a screen view.
05034     Purpose:    For determining wether the current single click event is really a triple click
05035                 It only makes sense to call this when you are processing a click event!
05036     SeeAlso:    DocView::IsSingleClickReallyQuad()
05037 
05038 *********************************************************************************************/
05039 
05040 BOOL DocView::IsSingleClickReallyTriple() const
05041 {
05042     // Salary check
05043     if (pViewWindow == NULL)
05044     {
05045         ERROR3("No attached oil view");
05046         return FALSE;
05047     }
05048 
05049     return pViewWindow->IsSingleClickReallyTriple();
05050 }
05051 
05052 
05053 
05054 /***********************************************************************************************
05055 
05056 >   BOOL DocView::IsSingleClickReallyQuad() const
05057 
05058     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
05059     Created:    22/12/95
05060     Inputs:     -
05061     Outputs:    -
05062     Returns:    TRUE if the last click event was a quad click.  FALSE if not, or the attached
05063                 oil view is not a screen view.
05064     Purpose:    For determining wether the current single click event is really a quad click
05065                 It only makes sense to call this when you are processing a click event!
05066     SeeAlso:    DocView::IsSingleClickReallyTriple()
05067 
05068 *********************************************************************************************/
05069 
05070 BOOL DocView::IsSingleClickReallyQuad() const
05071 {
05072     // Salary check
05073     if (pViewWindow == NULL)
05074     {
05075         ERROR3("No attached oil view");
05076         return FALSE;
05077     }
05078 
05079     return pViewWindow->IsSingleClickReallyQuad();
05080 }
05081 
05082 
05083 
05084 
05085 /***********************************************************************************************
05086 
05087 >   void DocView::ShowViewScrollers(BOOL fIsVisible)
05088 
05089     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
05090     Created:    2/11/94
05091     Inputs:     -
05092     Outputs:    -
05093     Returns:    -
05094     Purpose:    Pass on Show Hide Scrollers Message to CamView
05095     SeeAlso:    -
05096 
05097 *********************************************************************************************/
05098 
05099 void DocView::ShowViewScrollers(BOOL fIsVisible)
05100 {
05101     PORTNOTETRACE("other","DocView::ShowViewScrollers - do nothing");
05102 #ifndef EXCLUDE_FROM_XARALX
05103     pViewWindow->ShowScrollers(fIsVisible);
05104 #endif
05105 }
05106 
05107 /***********************************************************************************************
05108 
05109 >   void DocView::ShowViewRulers(BOOL fIsVisible)
05110 
05111     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05112     Created:    2/11/94
05113     Inputs:     -
05114     Outputs:    -
05115     Returns:    -
05116     Purpose:    Pass on Show Hide Rulers Message to CamView
05117     SeeAlso:    -
05118 
05119 *********************************************************************************************/
05120 
05121 void DocView::ShowViewRulers(BOOL fIsVisible)
05122 {
05123     pViewWindow->ShowRulers(fIsVisible);
05124 }
05125 
05126 
05127 /***********************************************************************************************
05128 
05129 >   BOOL DocView::AreRulersVisible()
05130 
05131     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05132     Created:    2/11/94
05133     Inputs:     -
05134     Outputs:    -
05135     Returns:    Are Rulers Visible on this view
05136     Purpose:    -
05137     SeeAlso:    -
05138 
05139 *********************************************************************************************/
05140 
05141 BOOL DocView::AreRulersVisible()
05142 {
05143     return pViewWindow->AreRulersVisible( );
05144 }
05145 
05146 
05147 /***********************************************************************************************
05148 
05149 >   BOOL DocView::AreScrollersVisible()
05150 
05151     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05152     Created:    2/11/94
05153     Inputs:     -
05154     Outputs:    -
05155     Returns:    Are Rulers Visible on this view
05156     Purpose:    -
05157     SeeAlso:    -
05158 
05159 *********************************************************************************************/
05160 
05161 BOOL DocView::AreScrollersVisible()
05162 {
05163     return pViewWindow->AreScrollersVisible( );
05164 }
05165 
05166 /********************************************************************************************
05167 
05168 >   CDC *DocView::GetRenderDC()
05169 
05170     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
05171     Created:    02/09/95
05172     Purpose:    Access function for the device context of this kernel view object.
05173     SeeAlso:    PrintView; View
05174 
05175 ********************************************************************************************/
05176 
05177 CNativeDC *DocView::GetRenderDC()
05178 {
05179     // Ask our CCamView to give us its DC and return that.
05180     return pViewWindow->GetRenderDC();
05181 }
05182 
05183 
05184 /********************************************************************************************
05185 
05186 >   virtual void DocView::RenderPageMarks(Spread *pSpread, 
05187                                           DocRect ClipRect,
05188                                           CDC *pDevContext,
05189                                           Matrix& RenderMatrix
05190                                           RenderType rType)
05191 
05192     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
05193     Created:    08/08/96
05194     Inputs:     pSpread     - pointer to the spread concerned
05195                 ClipRect    - Rectangle to create region from
05196                 pDevContect - pointer to the device context for this region (may be NULL
05197                                 if PaintPaper == FALSE)
05198                 RenderMatrix- the render matrix to use.
05199                 rType       - the type of render to give the region
05200 
05201     Outputs:    -
05202     Returns:    -
05203     Purpose:    Performs the rendering of page marks, ie crop marks, registration marks etc
05204                 to the screen and printer. This base class version does nothing. All
05205                 mark rendering technology is held in DocView and PrintView.
05206     SeeAlso:    View, PrintView
05207 
05208 ********************************************************************************************/
05209 
05210 /*
05211 void DocView::RenderPageMarks(Spread *pSpread, DocRect ClipRect, CDC *pDevContext, Matrix& RenderMatrix, RenderType rType)
05212 {
05213 #ifndef STANDALONE
05214     // No paper rendering region - get a new render region
05215     OSRenderRegion* pPageMarksRegion = (OSRenderRegion *) NewRenderRegion(ClipRect, RenderMatrix, pDevContext, pSpread, rType);
05216     if (!pPageMarksRegion)
05217         return;
05218 
05219     // We save the context here, so that PaperRenderRegion::DetachDevice() can
05220     // throw away all the attributes.  We only need to do it here because
05221     // PaperRenderRegion::AttachDevice() (see 2 inches below) calls SaveContext()
05222     // automagically.
05223     pPageMarksRegion->SaveContext();
05224 
05225     // Set up the rendering system.
05226     if (!pPageMarksRegion->StartRender())
05227     {
05228         TRACEALL( _T("StartRender failed during View::RenderPageMarks\n"));
05229         pPageMarksRegion->RestoreContext();
05230         delete pPageMarksRegion;
05231         return;
05232     }
05233 
05234     // Render the page mark objects using the permanent PageMarks render region.
05235     pPageMarksRegion->SaveContext();
05236     RenderPageMarks(pPageMarksRegion, pSpread);
05237     pPageMarksRegion->RestoreContext();
05238     pPageMarksRegion->StopRender();
05239 
05240     delete pPageMarksRegion;
05241 #endif
05242 }
05243 */
05244 
05245 /********************************************************************************************
05246 
05247 >   virtual void DocView::RenderPageMarks(RenderRegion *pRRegion, 
05248                                           Matrix &ViewTrans,
05249                                           ClipRect &ClipRect
05250                                           Spread *pSpread)
05251 
05252     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
05253     Created:    08/08/96
05254     Inputs:     pSpread     - pointer to the spread concerned
05255                 pRRegion    - pointer to the render region to use.
05256     Outputs:    -
05257     Returns:    -
05258     Purpose:    Performs the rendering of page marks, ie crop marks, registration marks etc
05259                 to the screen and printer. This base class version does nothing. All
05260                 mark rendering technology is held in DocView and PrintView.
05261     SeeAlso:    View, PrintView
05262 
05263 ********************************************************************************************/
05264 
05265 BOOL DocView::RenderPageMarks(RenderRegion *pCurrRegion, Matrix &ViewTrans, DocRect &ClipRect, Spread *pSpread)
05266 {
05267     return TRUE;    
05268 }
05269 
05270 /********************************************************************************************
05271 
05272 >   DocCoord DocView::GetCentreCoord() const
05273 
05274     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
05275     Created:    14/7/97
05276     Inputs:     -
05277     Outputs:    -
05278     Returns:    The DocCoord for the centre of the view
05279     Purpose:    Gets a DocCoord for the centre of the view
05280     Errors:     -
05281     SeeAlso:    -
05282 
05283 ********************************************************************************************/
05284 
05285 DocCoord DocView::GetCentreCoord()  
05286 {
05287     //First get the document associated with this view
05288     Document* pDocument=GetDoc();
05289 
05290     //And find the first spread in that document
05291 PORTNOTE("spread", "Multi-spread warning!")
05292     Spread* pSpread=pDocument->FindFirstSpread();
05293 
05294     //Check we got both of those
05295     ERROR2IF(pDocument==NULL || pSpread==NULL, DocCoord(0,0), "DocView::GetCentreImportPosition - no document or spread");
05296 
05297     //So get the view rectangle
05298     DocRect rectView = GetDocViewRect(pSpread);
05299     
05300     //And find the middle of that rectangle
05301     DocCoord dcCentre;
05302     dcCentre.x = rectView.lo.x / 2 + rectView.hi.x / 2;
05303     dcCentre.y = rectView.lo.y / 2 + rectView.hi.y / 2;
05304                 
05305     //Now make that into a spread coordinate
05306     DocRect rectSpread = pSpread->GetPasteboardRect();
05307 
05308     DocCoord dcToReturn;
05309     
05310     dcToReturn.x = dcCentre.x - rectSpread.lo.x; 
05311     dcToReturn.y = dcCentre.y - rectSpread.lo.y;
05312                                                                                         
05313     //And return that DocCoord
05314     return dcToReturn;
05315 }
05316 
05317 /********************************************************************************************
05318 
05319 >   ImportPosition DocView::GetCentreImportPosition() const
05320 
05321     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
05322     Created:    14/7/97
05323     Inputs:     -
05324     Outputs:    -
05325     Returns:    The import position for the centre of the view
05326     Purpose:    Gets an import position for the centre of the view
05327     Errors:     -
05328     SeeAlso:    -
05329 
05330 ********************************************************************************************/
05331 
05332 ImportPosition DocView::GetCentreImportPosition()
05333 {
05334     //First get the document associated with this view
05335     Document* pDocument=GetDoc();
05336 
05337     //And find the first spread in that document
05338 PORTNOTE("spread", "Multi-spread warning!")
05339     Spread* pSpread=pDocument->FindFirstSpread();
05340 
05341     //Now get the DocCoord in the centre of the view
05342     DocCoord dcToReturn=GetCentreCoord();
05343 
05344     //Put all those values into an ImportPosition structure
05345     ImportPosition posToReturn;
05346 
05347     posToReturn.pSpread=pSpread;
05348     posToReturn.Position=dcToReturn;
05349 
05350     //And return that ImportPosition
05351     return posToReturn;
05352 
05353 }
05354 
05355 /********************************************************************************************
05356 
05357 >   DocCoord DocView::GetTopLeftCoord()
05358 
05359     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
05360     Created:    14/7/97
05361     Inputs:     -
05362     Outputs:    -
05363     Returns:    The DocCoord for the top left of the view
05364     Purpose:    Gets a DocCoord for the top left of the view
05365     Errors:     -
05366     SeeAlso:    -
05367 
05368 ********************************************************************************************/
05369 
05370 DocCoord DocView::GetTopLeftCoord() 
05371 {
05372     //First get the document associated with this view
05373     Document* pDocument=GetDoc();
05374 
05375     //And find the first spread in that document
05376 PORTNOTE("spread", "Multi-spread warning!")
05377     Spread* pSpread=pDocument->FindFirstSpread();
05378 
05379     //Check we got both of those
05380     ERROR2IF(pDocument==NULL || pSpread==NULL, DocCoord(0,0), "DocView::GetCentreImportPosition - no document or spread");
05381 
05382     //So get the view rectangle
05383     DocRect rectView = GetDocViewRect(pSpread);
05384     
05385     //And find the top left of that rectangle
05386     DocCoord dcTopLeft(rectView.lo.x, rectView.hi.y);
05387                 
05388     //Now make that into a spread coordinate
05389     DocRect rectSpread = pSpread->GetPasteboardRect();
05390 
05391     DocCoord dcToReturn;
05392     
05393     dcToReturn.x = dcTopLeft.x - rectSpread.lo.x; 
05394     dcToReturn.y = dcTopLeft.y - rectSpread.lo.y;
05395 
05396     TRACEUSER( "luke", _T("rcToReturn (%x, %x), dcTopLeft (%x, %x), rectSpead (%x, %x)"),
05397         dcToReturn.x, dcToReturn.y, dcTopLeft.x, dcTopLeft.y, rectSpread.lo.x, rectSpread.lo.y );
05398                                                                                         
05399     //And return that DocCoord
05400     return dcToReturn;
05401 }
05402 
05403 /********************************************************************************************
05404 
05405 >   ImportPosition DocView::GetTopLeftImportPosition() const
05406 
05407     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
05408     Created:    14/7/97
05409     Inputs:     -
05410     Outputs:    -
05411     Returns:    The import position for the top left of the view
05412     Purpose:    Gets an import position for the top left of the view
05413     Errors:     -
05414     SeeAlso:    -
05415 
05416 ********************************************************************************************/
05417 
05418 ImportPosition DocView::GetTopLeftImportPosition()
05419 {
05420     //First get the document associated with this view
05421     Document* pDocument=GetDoc();
05422 
05423     //And find the first spread in that document
05424 PORTNOTE("spread", "Multi-spread warning!")
05425     Spread* pSpread=pDocument->FindFirstSpread();
05426 
05427     //Now get the DocCoord in the top left of the view
05428     DocCoord dcToReturn=GetTopLeftCoord();
05429 
05430     //Put all those values into an ImportPosition structure
05431     ImportPosition posToReturn;
05432 
05433     posToReturn.pSpread=pSpread;
05434     posToReturn.Position=dcToReturn;
05435 
05436     //And return that ImportPosition
05437     return posToReturn;
05438 
05439 }
05440 
05441 
05442 
05443 /********************************************************************************************
05444 
05445 >   double DocView::GetZoomFactor() const
05446 
05447     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
05448     Created:    17 February 2000
05449     Returns:    The current zoom factor for this document view.
05450     Purpose:    Obtain the current zoom factor for this document view.
05451     Errors:     
05452     See also:   GetScaledPixelWidth(), GetPixelWidth().
05453 
05454 ********************************************************************************************/
05455 double DocView::GetZoomFactor()
05456 {
05457     return GetScaledPixelWidth().MakeDouble() / GetPixelWidth().MakeDouble();
05458 }
05459 
05460 
05461 /********************************************************************************************
05462 
05463 >   void DocView::SetPreventRenderView(BOOL Value)
05464 
05465     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05466     Created:    10/5/2000
05467     Inputs:     Value to set
05468     Returns:    -
05469     Purpose:    To set our member variable that will prevent rendering of the view. As you might
05470                 imagine this is something to be careful about
05471     Errors:     
05472     See also:   
05473 
05474 ********************************************************************************************/
05475 
05476 void DocView::SetPreventRenderView(BOOL Value)
05477 {
05478     m_bPreventRenderView = Value;
05479 }
05480 
05481 
05482 /********************************************************************************************
05483 
05484 >   BOOL DocView::GetPreventRenderView()
05485 
05486     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05487     Created:    10/5/2000
05488     Returns:    The state of our flag which prevents the view from rendering
05489     Purpose:    As above
05490     Errors:     
05491     See also:   
05492 
05493 ********************************************************************************************/
05494 
05495 BOOL DocView::GetPreventRenderView()
05496 {
05497     return m_bPreventRenderView;
05498 }
05499 
05500 
05501 /********************************************************************************************
05502 
05503 >   void DocView::ClearClickState()
05504 
05505     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05506     Created:    26/02/2004
05507     Returns:    -
05508     Purpose:    Allows click handlers to reset the click logic if they are doing things
05509                 that would break it.
05510     Errors:     
05511     See also:   
05512 
05513 ********************************************************************************************/
05514 
05515 void DocView::ClearClickState()
05516 {
05517     PORTNOTETRACE("other","DocView::ClearClickState - do nothing");
05518 #ifndef EXCLUDE_FROM_XARALX
05519     if (pViewWindow)
05520     {
05521         pViewWindow->ClearClickState();
05522     }
05523 #endif
05524 }
05525 
05526 
05527 /********************************************************************************************
05528                         TOGGLE FORE/BACKGROUND RENDERING OPERATION
05529 */
05530 /********************************************************************************************
05531 
05532 >   OpToggleFore::OpToggleFore() : Operation()
05533 
05534     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05535     Created:    9/7/93
05536     Inputs:     -
05537     Outputs:    -
05538     Returns:    -
05539     Purpose:    Constructs an OpToggleFore object.
05540     Errors:     -
05541     SeeAlso:    -
05542 
05543 ********************************************************************************************/
05544 
05545 OpToggleFore::OpToggleFore() : Operation()
05546 {
05547 
05548 }
05549 
05550 
05551 
05552 /********************************************************************************************
05553 
05554 >   OpToggleFore::~OpToggleFore()
05555 
05556     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05557     Created:    9/7/93
05558     Inputs:     -
05559     Outputs:    -
05560     Returns:    -
05561     Purpose:    Destructs an OpToggleFore object.
05562     Errors:     -
05563     SeeAlso:    -
05564 
05565 ********************************************************************************************/
05566 
05567 OpToggleFore::~OpToggleFore()
05568 {
05569     // Empty
05570 }
05571 
05572 
05573 
05574 /********************************************************************************************
05575 
05576 >   void OpToggleFore::Do(OpDescriptor*)
05577 
05578     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05579     Created:    9/7/93
05580     Inputs:     Pointer to Operation Descriptor
05581     Outputs:    -
05582     Returns:    -
05583     Purpose:    Actually "DO" a ToggleFore operation.
05584     Errors:     -
05585     SeeAlso:    -
05586 
05587 ********************************************************************************************/
05588 
05589 void OpToggleFore::Do(OpDescriptor*)
05590 {
05591     if (DocView::GetSelected() != NULL)
05592         DocView::GetSelected()->SetForeBackMode(!DocView::GetSelected()->GetForeBackMode());
05593     End();
05594 }
05595 
05596 
05597 
05598 /********************************************************************************************
05599 
05600 >   OpState OpToggleFore::GetState(String_256* UIDescription, OpDescriptor*)
05601 
05602     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05603     Created:    9/7/93
05604     Inputs:     Pointer to Operation Descriptor
05605                 Text Description
05606     Outputs:    -
05607     Returns:    -
05608     Purpose:    Find the state of the OpToggleFore operation.
05609     Errors:     -
05610     SeeAlso:    -
05611 
05612 ********************************************************************************************/
05613 
05614 OpState OpToggleFore::GetState(String_256* UIDescription, OpDescriptor*)
05615 {
05616     // Default to !ticked and greyed
05617     OpState blobby(FALSE, TRUE);
05618     if (DocView::GetSelected() != NULL)
05619     {
05620         // If we have a selected view then get the state and ungrey
05621         blobby.Ticked = DocView::GetSelected()->GetForeBackMode();
05622         blobby.Greyed = FALSE;
05623     }
05624     return(blobby);
05625 }
05626 
05627 
05628 
05629 /********************************************************************************************
05630 
05631 >   BOOL OpToggleFore::Init()
05632 
05633     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05634     Created:    9/7/93
05635     Inputs:     -
05636     Outputs:    -
05637     Returns:    -
05638     Purpose:    Create an OpDescriptor for the ToggleFore operation
05639     Errors:     -
05640     SeeAlso:    -
05641 
05642 ********************************************************************************************/
05643 
05644 BOOL OpToggleFore::Init()   
05645 {
05646     return Operation::RegisterOpDescriptor( 
05647                                             0, 
05648                                             _R(IDS_TOGGLE_FORE_BACK),
05649                                             CC_RUNTIME_CLASS(OpToggleFore), 
05650                                             OPTOKEN_TOGGLEFORE,
05651                                             OpToggleFore::GetState,
05652                                             0,                      // help ID
05653                                             0,// _R(IDBBL_FOREBACKGRNDOP),
05654                                             0,                      // bitmap ID
05655                                             0,                      // control ID
05656                                             SYSTEMBAR_ILLEGAL,      // group bar ID
05657                                             TRUE,
05658                                             FALSE,
05659                                             TRUE,
05660                                             NULL,
05661                                             0,
05662                                             0,
05663                                             TRUE
05664                                            );
05665 }
05666 
05667 
05668 /********************************************************************************************
05669                         TOGGLE PROPORTIONAL SCROLL BARS OPERATION
05670 */
05671 /********************************************************************************************
05672 
05673 >   OpToggleScroll::OpToggleScroll() : Operation()
05674 
05675     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05676     Created:    9/7/93
05677     Inputs:     -
05678     Outputs:    -
05679     Returns:    -
05680     Purpose:    Constructs an OpToggleScroll object.
05681     Errors:     -
05682     SeeAlso:    -
05683 
05684 ********************************************************************************************/
05685 
05686 OpToggleScroll::OpToggleScroll()
05687   : Operation()
05688 {
05689     // Empty
05690 }
05691 
05692 
05693 
05694 
05695 /********************************************************************************************
05696 
05697 >   OpToggleScroll::~OpToggleScroll()
05698 
05699     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05700     Created:    9/7/93
05701     Inputs:     -
05702     Outputs:    -
05703     Returns:    -
05704     Purpose:    Destructs an OpToggleScroll object.
05705     Errors:     -
05706     SeeAlso:    -
05707 
05708 ********************************************************************************************/
05709 
05710 OpToggleScroll::~OpToggleScroll()
05711 {
05712 }
05713 
05714 
05715 
05716 
05717 /********************************************************************************************
05718 
05719 >   void OpToggleScroll::Do(OpDescriptor*)
05720 
05721     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05722     Created:    9/7/93
05723     Inputs:     Pointer to an operation descriptor
05724     Outputs:    -
05725     Returns:    -
05726     Purpose:    Actually "DO" a ToggleScroll operation.
05727     Errors:     -
05728     SeeAlso:    -
05729 
05730 ********************************************************************************************/
05731 
05732 void OpToggleScroll::Do(OpDescriptor*)
05733 {
05734     PORTNOTE("other","OpToggleScroll::Do - do nothing")
05735 #ifndef EXCLUDE_FROM_XARALX
05736     CCamView *pView = DocView::GetSelected()->GetConnectionToOilView();
05737     BOOL Prop = pView->GetScrollerStyle();
05738     pView->SetScrollerStyle(!Prop);
05739     End();
05740 #endif
05741 }
05742 
05743 
05744 
05745 /********************************************************************************************
05746 
05747 >   OpState OpToggleScroll::GetState(String_256* UIDescription, OpDescriptor*)
05748 
05749     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05750     Created:    9/7/93
05751     Inputs:     A Pointer to an operation description
05752                 Text Description
05753     Outputs:    -
05754     Returns:    -
05755     Purpose:    Find the state of the OpToggleScroll operation.
05756     Errors:     -
05757     SeeAlso:    -
05758 
05759 ********************************************************************************************/
05760 
05761 OpState OpToggleScroll::GetState(String_256* UIDescription, OpDescriptor*)
05762 {
05763     PORTNOTETRACE("other","OpToggleScroll::Do - do nothing");
05764 #ifndef EXCLUDE_FROM_XARALX
05765     CCamView *pView = DocView::GetSelected()->GetConnectionToOilView();
05766     OpState blobby;
05767     blobby.Ticked = pView->GetScrollerStyle();
05768     blobby.Greyed = FALSE;
05769     return blobby;
05770 #else
05771     return OpState();
05772 #endif
05773 }
05774 
05775 
05776 
05777 
05778 /********************************************************************************************
05779 
05780 >   BOOL OpToggleScroll::Init()
05781 
05782     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05783     Created:    9/7/93
05784     Inputs:     -
05785     Outputs:    -
05786     Returns:    -
05787     Purpose:    Create an OpDescriptor for the ToggleScroll operation
05788     Errors:     -
05789     SeeAlso:    -
05790 
05791 ********************************************************************************************/
05792 
05793 BOOL OpToggleScroll::Init()
05794 {
05795     PORTNOTETRACE("other","OpToggleScroll::Init - do nothing");
05796 #ifndef EXCLUDE_FROM_XARALX
05797     return Operation::RegisterOpDescriptor(0, 
05798                                            _R(IDS_TOGGLE_SCROLLBARS),
05799                                            CC_RUNTIME_CLASS(OpToggleScroll), 
05800                                            OPTOKEN_TOGGLESCROLL,
05801                                            OpToggleScroll::GetState,
05802                                             0,                          // help ID
05803                                            _R(IDBBL_PROPSCROLLERSOP),   // bubble ID 
05804                                             0,                          // bitmap ID
05805                                             0,                          // control ID
05806                                             SYSTEMBAR_ILLEGAL,          // group bar ID
05807                                             TRUE,
05808                                             FALSE,
05809                                             TRUE,
05810                                             NULL,
05811                                             0,
05812                                             0,
05813                                             TRUE
05814                                            );
05815 #else
05816     return FALSE;
05817 #endif
05818 }
05819 
05820 /********************************************************************************************
05821 
05822 >   OpToggleSolidDrag::OpToggleSolidDrag() : Operation()
05823 
05824     Author:     Alex Bligh <alex@alex.org.uk>
05825     Created:    14 Mar 2006
05826     Inputs:     -
05827     Outputs:    -
05828     Returns:    -
05829     Purpose:    Constructs an OpToggleSolidDrag object.
05830     Errors:     -
05831     SeeAlso:    -
05832 
05833 ********************************************************************************************/
05834 
05835 OpToggleSolidDrag::OpToggleSolidDrag() : Operation()
05836 {
05837 
05838 }
05839 
05840 
05841 
05842 /********************************************************************************************
05843 
05844 >   OpToggleSolidDrag::~OpToggleSolidDrag()
05845 
05846     Author:     Alex Bligh <alex@alex.org.uk>
05847     Created:    14 Mar 2006
05848     Inputs:     -
05849     Outputs:    -
05850     Returns:    -
05851     Purpose:    Destructs an OpToggleSolidDrag object.
05852     Errors:     -
05853     SeeAlso:    -
05854 
05855 ********************************************************************************************/
05856 
05857 OpToggleSolidDrag::~OpToggleSolidDrag()
05858 {
05859     // Empty
05860 }
05861 
05862 
05863 
05864 /********************************************************************************************
05865 
05866 >   void OpToggleSolidDrag::Do(OpDescriptor*)
05867 
05868     Author:     Alex Bligh <alex@alex.org.uk>
05869     Created:    14 Mar 2006
05870     Inputs:     Pointer to Operation Descriptor
05871     Outputs:    -
05872     Returns:    -
05873     Purpose:    Actually "DO" a ToggleFore operation.
05874     Errors:     -
05875     SeeAlso:    -
05876 
05877 ********************************************************************************************/
05878 
05879 void OpToggleSolidDrag::Do(OpDescriptor*)
05880 {
05881     DocView::SolidDragging=!DocView::SolidDragging;
05882     End();
05883 }
05884 
05885 
05886 
05887 /********************************************************************************************
05888 
05889 >   OpState OpToggleSolidDrag::GetState(String_256* UIDescription, OpDescriptor*)
05890 
05891     Author:     Alex Bligh <alex@alex.org.uk>
05892     Created:    14 Mar 2006
05893     Inputs:     Pointer to Operation Descriptor
05894                 Text Description
05895     Outputs:    -
05896     Returns:    -
05897     Purpose:    Find the state of the OpToggleSolidDrag operation.
05898     Errors:     -
05899     SeeAlso:    -
05900 
05901 ********************************************************************************************/
05902 
05903 OpState OpToggleSolidDrag::GetState(String_256* UIDescription, OpDescriptor*)
05904 {
05905     // Default to !ticked and greyed
05906     OpState blobby(FALSE, TRUE);
05907     blobby.Ticked = DocView::SolidDragging;
05908     blobby.Greyed = FALSE;
05909     return(blobby);
05910 }
05911 
05912 
05913 /********************************************************************************************
05914 
05915 >   BOOL OpToggleSolidDrag::Init()
05916 
05917     Author:     Alex Bligh <alex@alex.org.uk>
05918     Created:    14 Mar 2006
05919     Inputs:     -
05920     Outputs:    -
05921     Returns:    -
05922     Purpose:    Create an OpDescriptor for the OpToggleSolidDrag operation
05923     Errors:     -
05924     SeeAlso:    -
05925 
05926 ********************************************************************************************/
05927 
05928 BOOL OpToggleSolidDrag::Init()  
05929 {
05930     return Operation::RegisterOpDescriptor( 
05931                                             0, 
05932                                             _R(IDS_TOGGLE_SOLIDDRAG),
05933                                             CC_RUNTIME_CLASS(OpToggleSolidDrag), 
05934                                             OPTOKEN_TOGGLESOLIDDRAG,
05935                                             OpToggleSolidDrag::GetState,
05936                                             0,                      // help ID
05937                                             0,// _R(IDBBL_FOREBACKGRNDOP),
05938                                             0,                      // bitmap ID
05939                                             0,                      // control ID
05940                                             SYSTEMBAR_ILLEGAL,      // group bar ID
05941                                             TRUE,
05942                                             FALSE,
05943                                             TRUE,
05944                                             NULL,
05945                                             0,
05946                                             0,
05947                                             TRUE
05948                                            );
05949 }

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