camview.cpp

Go to the documentation of this file.
00001 // $Id: camview.cpp 1743 2006-09-06 09:32:51Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 #include "camtypes.h"
00099 
00100 #include "camview.h"
00101 
00102 #include "camelot.h"
00103 #include "camframe.h"
00104 #include "camdoc.h"
00105 #include "vstate.h"
00106 #include "ccdc.h"
00107 #include "csrstack.h"
00108 
00109 #include "rendwnd.h"
00110 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 #include "prntview.h"
00112 #include "osrndrgn.h"
00113 #include "scroller.h"
00114 #include "rulers.h"
00115 //#include "bars.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "localenv.h"
00117 #include "zoomops.h"
00118 #include "vkextra.h"
00119 #include "brushmsg.h"
00120 #include "statline.h"
00121 #include "draginfo.h"
00122 #include "prdlgctl.h"
00123 #include "prncamvw.h"
00124 #include "opbevel.h"
00125 #include "psrndrgn.h"
00126 #include "prnmks.h"
00127 #include "princomp.h"
00128 #include "oilruler.h"
00129 #include "strlist.h"
00130 #include "impexpop.h"
00131 
00132 /***************************************************************************************************************************/
00133 
00134 IMPLEMENT_DYNAMIC_CLASS( CCamView, wxView )
00135 CC_IMPLEMENT_DYNAMIC( ViewDragTarget, OilDragTarget )
00136 CC_IMPLEMENT_DYNCREATE( PageDropInfo, CCObject )
00137 
00138 // Declare smart memory handling in Debug builds
00139 #define new CAM_DEBUG_NEW
00140 
00141 // This user preference controls how many pixels the mouse must move before a
00142 // drag is initiated.
00143 INT32 CCamView::DragLatency = 3;
00144 
00145 INT32 CCamView::s_MouseMoveEliminationPeriod = 0;
00146 
00147 // Used to start drags after user has clicked but not moved mouse for n milliseconds.
00148 INT32 CCamView::DragDelay = 500;
00149 MonotonicTime CCamView::DragTimer;
00150 
00151 INT32 CCamView::PopCount = 0;
00152 ViewState* CCamView::pReadyMadeViewState = NULL;
00153 BOOL CCamView::DefaultScrollersState = TRUE;
00154 BOOL CCamView::DefaultRulersState = FALSE;
00155 BOOL CCamView::UseVisibleDefaults = TRUE;
00156 
00157 // Default to a nonsense size.  Will be fixed up in OnSize
00158 INT32 CCamView::ScrollBarSize = 1;
00159 
00160 BEGIN_EVENT_TABLE( CCamView, wxView )
00161     EVT_SIZE(CCamView::OnSize)
00162     EVT_SCROLL(CCamView::OnScroll)
00163     EVT_TIMER(DragIdleID, CCamView::OnDragIdle)
00164 END_EVENT_TABLE()
00165 
00166 /*********************************************************************************************
00167 
00168 >   CCamView::CCamView()
00169 
00170     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00171     Created:    ages ago
00172     Inputs:     -
00173     Outputs:    -
00174     Returns:    -
00175     Purpose:    Default constructor for a CCamView window.  Sets the pointers to the
00176                 child windows to null, so that an incomplete construction of the view
00177                 that is later destroyed won't try to delete invalid pointers.  The
00178                 Windows side of construction is done later, in the OnCreate() message
00179                 handler.
00180 
00181                 Updates the CCamView population counter. Called from somewhere deep
00182                 inside MFC.             
00183     Errors:     -
00184     Scope:      Protected.
00185     SeeAlso:    CCamView::OnCreate(); CCamView::~CCamView()
00186 
00187 **********************************************************************************************/ 
00188 
00189 CCamView::CCamView()
00190 {
00191     TRACEUSER("Gerry", _T("Creating CCamView at 0x%08x\n"), this);
00192 
00193     // No child windows or connections yet.
00194     pDocView = NULL;
00195     pPrintView = NULL;
00196 
00197     // Create a ViewState object to maintain device-independent information.
00198     Status = new ViewState;
00199 
00200     RenderWindow = NULL;
00201     HScrollBar = NULL;
00202     VScrollBar = NULL;
00203     Corner = NULL;
00204     HRuler = NULL;
00205     VRuler = NULL;
00206     OGadget= NULL;
00207 
00208     // Set/clear these internal flags.
00209     fSetupDone = FALSE;
00210     fInitialUpdate = FALSE;
00211 
00212     // Not dragging or scrolling either.
00213     pCurrentDragOp = NULL;
00214 
00215     OLERecaptureMouse = FALSE;
00216 
00217     // Set up click event variables
00218     LastClickType = CLICKTYPE_NONE;
00219     LastClickButton = 0;
00220     LastClickPoint.x = 0;
00221     LastClickPoint.y = 0;
00222     CurrentMousePos.x = 0;
00223     CurrentMousePos.y = 0;
00224     FirstClickButton = 0;
00225     DragKeepAccuracy = TRUE;
00226     AutoScrollExcludeRulers = FALSE;
00227     
00228     // Bump the population.
00229     PopCount++;
00230 
00231     // Vars used by InvokeDragOp() mechanism
00232     DragOpToken = "";
00233     pDragOpParam = NULL;
00234     DragOpInvoke = FALSE;
00235 
00236     // Set up the drag idle timer
00237     m_DragIdleTimer.SetOwner(this, DragIdleID);
00238 
00239     // Triple and quad click support
00240     LastDoubleClickPos = wxPoint( 0, 0 );
00241     ThisSingleIsTriple = FALSE;
00242     ThisDoubleIsQuad = FALSE;
00243 
00244     // Set this flag until we have been through OnActivateView once, after which we can
00245     // include this view in the eat-activating-click system.
00246     fJustCreated = TRUE;
00247 
00248     // Mouse move handling
00249     m_LastMouseState=0;
00250     m_LastMousePosition=wxDefaultPosition;
00251     m_LastMouseUsedTimestamp=0;
00252     m_CouldSkipNextMouse=FALSE;
00253 
00254     OldOffset = WorkCoord(0, 0); // need to initialize it to something
00255 }
00256 
00257 /*********************************************************************************************
00258 >   virtual CCamView::~CCamView()
00259 
00260     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00261     Created:    ages ago
00262     Inputs:     -
00263     Outputs:    -
00264     Returns:    -
00265     Purpose:    Destroys a CCamView window.  Deletes child windows first.
00266                 Updates the CCamView population counter.
00267     Errors:     -
00268     Scope:      Public
00269     SeeAlso:    CCamView::CCamView()
00270 
00271 **********************************************************************************************/ 
00272 
00273 CCamView::~CCamView()
00274 {
00275     TRACEUSER("Gerry", _T("Deleting CCamView at 0x%08x\n"), this);
00276 
00277     PopCount--;         // one less ScreenView in the world, sigh
00278 
00279     if(pDocView != NULL)
00280         delete pDocView;
00281     
00282     if(Status != NULL)
00283         delete Status;
00284 
00285     pDocView = NULL;
00286     Status = NULL;
00287 
00288     // We shouldn't have a print view here!
00289     if (pPrintView != NULL)
00290     {
00291         ERROR3("CCamView is dying when it still has a PrintView attached!");
00292         delete pPrintView;
00293     }
00294 }
00295 
00296 /*********************************************************************************************/
00297 
00298 // What to do when a view is created. Creates actual
00299 // windows for displaying the view.
00300 bool CCamView::OnCreate( wxDocument *pDoc, /* TYPENOTE: Correct */ long flags )
00301 {
00302     TRACEUSER("Gerry", _T("CCamView::OnCreate at 0x%08x\n"), this);
00303 
00304     // Construct the (C++) child windows.
00305     RenderWindow = new CRenderWnd(this);
00306     HScrollBar = new CWinScroller(TRUE);
00307     VScrollBar = new CWinScroller(FALSE);
00308 PORTNOTE("other","ScreenCamView::OnCreate - Removed scroller corner usage")
00309 #ifndef EXCLUDE_FROM_XARALX
00310     Corner = new CScrollerCorner;
00311 #endif // EX_LX
00312     HRuler = new OILHorizontalRuler;
00313     VRuler = new OILVerticalRuler;
00314     OGadget = new OriginGadget;
00315     if (!RenderWindow
00316         || !HScrollBar 
00317         || !VScrollBar 
00318 #ifndef EXCLUDE_FROM_XARALX
00319         || !Corner 
00320 #endif // EX_LX
00321         || !HRuler ||!VRuler    ||!OGadget
00322         )
00323     {
00324         Error::SetError(_R(IDE_CREATE_VIEW_FAILED), 0);
00325         InformError();
00326         return false;
00327     } 
00328 
00329     m_pFrame = wxGetApp().CreateChildFrame( pDoc, this );
00330     m_pFrame->SetTitle(_T("DrawingView"));
00331 
00332     INT32 width, height;
00333     m_pFrame->GetClientSize( &width, &height );
00334 
00335     // Now do the other half of the construction.  The stated sizes and
00336     // positions of the windows here will be changed very soon.
00337     const WinRect rcARect(-100,-100,-90,-90);
00338     if (!RenderWindow->Create(rcARect, m_pFrame, WID_RENDERWINDOW)
00339         || !HScrollBar->Create(m_pFrame, WID_HSCROLLBAR, wxPoint(-100, -100))
00340         || !VScrollBar->Create(m_pFrame, WID_VSCROLLBAR, wxPoint(-100, -100))
00341 //      || !Corner->Create("", "", 0, rcARect, this, WID_SIZECORNER)
00342         || !HRuler->Create(this, WID_HRULER)
00343         || !VRuler->Create(this, WID_VRULER)
00344         || !OGadget->Create(this, WID_RULERORIGIN)
00345         )
00346     {
00347         Error::SetError(_R(IDE_CREATE_VIEW_FAILED), 0);
00348         InformError();
00349         return false;
00350     }
00351 
00352     CreateNewDocView();
00353 
00354     CViewFileDropTarget* pTarget = new CViewFileDropTarget(this);
00355     if (pTarget)
00356         RenderWindow->SetDropTarget(pTarget);
00357 
00358     // init the kernel rulers and establish pointer links to them
00359     RulerPair* pRulers=pDocView->GetpRulerPair();
00360     pRulers->Init(pDocView,HRuler,VRuler,OGadget);
00361     HRuler->LinkToKernel(pRulers->GetpHorizontalRuler());
00362     VRuler->LinkToKernel(pRulers->GetpVerticalRuler());
00363     ENSURE(pDocView != 0, "CCamView::ScreenView can't get a new DocView!");
00364     pDocView->ConnectToOilView(this);
00365     
00366     // find the last view so we can use some of it's settings to create the new
00367 //  DocView * LastView = DocView::GetSelected();
00368 
00369     // Link this and the DocView to the ViewState object.
00370     pDocView->SetViewState(Status);
00371 
00373     
00374     wxScreenDC dc;
00375     wxSize pixsize=OSRenderRegion::GetFixedDCPPI(dc);
00376 
00377     // Tell DocView how big the pixel size is.
00378     FIXED16 PixelWidth  = FIXED16(72000.0/pixsize.x);
00379     FIXED16 PixelHeight = FIXED16(72000.0/pixsize.y);
00380     ERROR3IF(PixelWidth != PixelHeight, "Luke says non-square pixels are not supported");
00381     pDocView->SetPixelSize(PixelWidth, PixelHeight);
00382 
00383     // Make our DocView the current DocView
00384     pDocView->SetCurrent();
00385 
00386     if (GetFrame())
00387         GetFrame()->GetClientSize(&CurrentSize.width,&CurrentSize.height);
00388     // Now the scrollers have all their information, we can set their appearance.
00389     // Make sure that they are invisible until the rest of the frame is ready
00390 /*  XLONG x1 = CurrentSize.GetWidth () * PixelWidth;
00391     XLONG x2 = CurrentSize.GetHeight() * PixelHeight;
00392     GetFrame()->SetScrollbar(wxHORIZONTAL,0,x1,Status->WorkAreaExtent.hi.x-Status->WorkAreaExtent.lo.x,false);
00393     GetFrame()->SetScrollbar(  wxVERTICAL,0,x2,Status->WorkAreaExtent.hi.y-Status->WorkAreaExtent.lo.y,false);
00394 */
00395     
00396     ShowScrollers(DefaultScrollersState);
00397     ShowRulers(DefaultRulersState);
00398 
00400     
00401     // Register for WM_DROPFILES messages
00402 //  DragAcceptFiles(TRUE);
00403 
00405 
00406     // now that the ScreenView (and hence DocView) is stable, broadcast a message to let everyone know
00407     BROADCAST_TO_ALL(DocViewMsg(pDocView,DocViewMsg::NEWANDSTABLE));
00408 
00409 #ifdef __X__
00410     // X seems to require a forced resize
00411     m_pFrame->SetSize(wxDefaultCoord, wxDefaultCoord, width, height);
00412 #endif
00413     m_pFrame->Show(true);
00414 
00415     // This has been removed as it causes the problem where loaded documents
00416     // don't render correctly if a wxYield happens before the document has 
00417     // finished loading.  It may be possible to rewrite the handling in this 
00418     // class so that the order of activation and OnInitialUpdate is not important 
00419     // but efforts so far have been in vain.
00420     // The view seems to be activated correctly in any case so hopefully it 
00421     // should not be necessary
00422 //  Activate(true);
00423 
00424     TRACEUSER("Gerry", _T("Leaving CCamView::OnCreate at 0x%08x\n"), this);
00425 
00426     return true;
00427 }
00428 
00429 /*********************************************************************************************/
00430 
00431 // Clean up windows used for displaying the view.
00432 bool CCamView::OnClose( bool fDeleteWindow /*= TRUE*/ )
00433 {
00434     TRACEUSER("Gerry", _T("CCamView::OnClose at 0x%08x\n"), this);
00435 
00436     if( !GetDocument()->Close() )
00437         return false;
00438     
00439     SetFrame( (wxFrame *)NULL );
00440     
00441     Activate( false );
00442 
00443     if( fDeleteWindow )
00444     {
00445         TRACEUSER("Gerry", _T("CCamView::OnClose deleting frame at 0x%08x\n"), m_pFrame);
00446         m_pFrame->Show( false );
00447         
00448         delete m_pFrame;
00449         m_pFrame = NULL;
00450 
00451         // This will also have deleted the child windows of the frame making our
00452         // pointers invalid so vape them here
00453         RenderWindow = NULL;
00454         HScrollBar = NULL;
00455         VScrollBar = NULL;
00456 
00457 #ifndef EXCLUDE_FROM_XARALX
00458         Corner = NULL;
00459 #endif // EX_LX
00460         HRuler = NULL;
00461         VRuler = NULL;
00462         OGadget = NULL;
00463 
00464     }
00465 
00466     return true;
00467 }
00468 
00469 /********************************************************************************************
00470 >   static BOOL CCamView::ReadViewPrefs()
00471 
00472     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00473     Created:    26/11/93
00474     Inputs:     -
00475     Outputs:    -
00476     Returns:    TRUE if the .INI file settings were loaded (or created) successfully.
00477     Purpose:    Tries to load preferences for CCamView, creating them with default values
00478                 if they don't exist.
00479     Errors:     -
00480     SeeAlso:    Application::DeclareSection; Application::DeclarePref
00481 ********************************************************************************************/
00482 
00483 BOOL CCamView::ReadViewPrefs()
00484 {
00485     // Declare and load the .INI file settings.
00486     BOOL ok =   Camelot.DeclareSection(TEXT("Mouse"), 10) &&
00487                 Camelot.DeclarePref(TEXT("Mouse"), TEXT("DragLatency"),
00488                                     &CCamView::DragLatency, 1, 10) &&
00489                 Camelot.DeclarePref(TEXT("Mouse"), TEXT("DragDelay"),
00490                                     &CCamView::DragDelay, 100, 2000) &&
00491                 Camelot.DeclarePref(TEXT("Mouse"), TEXT("MoveEliminationPeriod"),
00492                                     &CCamView::s_MouseMoveEliminationPeriod, 0, 1000) &&
00493 
00494                 Camelot.DeclareSection(TEXT("WindowFurniture"), 10) &&
00495 #ifndef EXCLUDE_FROM_XARALX
00496                 Camelot.DeclarePref(TEXT("WindowFurniture"), TEXT("PropScrollers"),
00497                                    &CCamView::PropScrollersOn, FALSE, TRUE) &&
00498 #endif
00499                 Camelot.DeclarePref(TEXT("WindowFurniture"), TEXT("ScrollersVisibiltyState"),
00500                                    &CCamView::DefaultScrollersState, FALSE, TRUE)&&
00501                 Camelot.DeclarePref(TEXT("WindowFurniture"), TEXT("RulersVisibiltyState"),
00502                                    &CCamView::DefaultRulersState, FALSE, TRUE) &&
00503 
00504 #ifndef EXCLUDE_FROM_XARALX
00505                 Camelot.DeclareSection(TEXT("Windows"), 10) &&
00506                 Camelot.DeclarePref(TEXT("Windows"), TEXT("UnzoomOnNewView"),
00507                                    &CCamView::UnzoomOnNewView, FALSE, TRUE) &&
00508                 Camelot.DeclarePref(TEXT("Windows"), TEXT("ZoomSingleView"),
00509                                    &CCamView::ZoomSingleView, FALSE, TRUE) &&
00510 #endif
00511                 TRUE ;
00512 
00513     return ok;
00514 }
00515 
00517 // Interface to the kernel's DocView and Document.
00518 
00519 /*********************************************************************************************
00520 >   CCamDoc* CCamView::GetDocument() const
00521 
00522     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00523     Created:    ages ago
00524     Inputs:     -
00525     Outputs:    -
00526     Returns:    A pointer to the CCamDoc object associated with this CCamView.
00527     Purpose:    Mainly used by MFC.
00528     Errors:     ASSERTion failure if CCamView::m_pDocument does not point to
00529                 a CCamDoc.
00530     Scope:      Public
00531     SeeAlso:    class CCamDoc; DocView::GetDocument
00532 **********************************************************************************************/ 
00533 
00534 CCamDoc* CCamView::GetDocument() const
00535 {
00536     ENSURE( m_viewDocument->IsKindOf( CLASSINFO(CCamDoc) ), 
00537             "CCamView::GetDocument: Document is not a Camelot document");
00538     return (CCamDoc *)m_viewDocument;
00539 }
00540 
00541 
00542 
00543 /*********************************************************************************************
00544 >   BOOL CCamView::CreateNewDocView()
00545 
00546     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00547     Created:    16/6/96
00548     Inputs:     -
00549     Outputs:    -
00550     Returns:    Success/Fail
00551     Purpose:    Creates a new attached DocView - overridden in RalphView 
00552                 to avoid the no Document problem.
00553     
00554 **********************************************************************************************/ 
00555 
00556 BOOL CCamView::CreateNewDocView()
00557 {
00558     
00559     Document* KernelDoc = GetDocument()->GetKernelDoc();
00560     pDocView = KernelDoc->GetNewDocView();
00561     return TRUE;
00562 
00563 }
00564 
00565 /********************************************************************************************
00566 >   ViewState* CCamView::GetViewState() const
00567 
00568     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00569     Created:    29/3/94
00570     Inputs:     -
00571     Outputs:    -
00572     Returns:    A pointer to the ViewState shared between this CCamView with a DocView.
00573     Purpose:    Allows access to the platform-independent description of a view.
00574     Errors:     -
00575     SeeAlso:    DocView::SetViewState
00576 ********************************************************************************************/
00577 
00578 ViewState* CCamView::GetViewState() const
00579 {
00580     ENSURE(Status != NULL, "Null ViewState* in CCamView::GetViewState");
00581     return Status;
00582 }
00583 
00584 
00585 
00586 /********************************************************************************************
00587 >   void CCamView::SetViewState(ViewState* pvs)
00588 
00589     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00590     Created:    25/9/95
00591     Inputs:     pvs         the new view-state
00592     Returns:    pointer to the old view-state
00593     Purpose:    Sets this CCamView's shared ViewState object.
00594     SeeAlso:    CCamView::GetViewState
00595 ********************************************************************************************/
00596 
00597 ViewState* CCamView::SetViewState(ViewState* pvs)
00598 {
00599     ViewState* pvsOld = Status;
00600     Status = pvs;
00601     if (pvsOld->pView != NULL) pvsOld->pView->SetViewState(Status);
00602     return pvsOld;
00603 }
00604 
00605 
00606 
00607 /********************************************************************************************
00608 >   void CCamView::SetCurrentStates()
00609 
00610     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00611     Created:    15/6/96
00612     Inputs:     -
00613     Purpose:    Set the  View and Document current
00614     SeeAlso:    
00615 ********************************************************************************************/
00616 
00617 void CCamView::SetCurrentStates()
00618 {
00619     if(pDocView)
00620     {
00621         pDocView->SetCurrent();
00622         Document* KernelDoc = pDocView->GetDoc();
00623         if(KernelDoc)
00624             KernelDoc->SetCurrent();
00625     }
00626 }
00627 
00629 // Painting.
00630 
00631 /********************************************************************************************
00632 
00633 >   CNativeDC* CCamView::GetRenderDC()
00634 
00635     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00636     Created:    02/09/95
00637     Returns:    pointer to a CNativeDC for rendering into this view
00638     Purpose:    Access function for this CCamView's device context.
00639     Errors:     -
00640     SeeAlso:    -
00641 
00642 ********************************************************************************************/
00643 
00644 CNativeDC* CCamView::GetRenderDC() const
00645 {
00646     return RenderWindow?RenderWindow->GetClientDC():NULL;
00647 }
00648 
00649 /********************************************************************************************
00650 
00651 >   void CCamView::DoneWithDC()
00652 
00653     Author:     Alex Bligh <alex@alex.org.uk>
00654     Created:    12/06/2006
00655     Purpose:    Hints that we've done with our DC
00656     SeeAlso:    View; PaperRenderRegion.
00657 
00658 Note this is merely a hint. This routine is not guaranteed to eb called
00659 
00660 ********************************************************************************************/
00661 
00662 void CCamView::DoneWithDC() const
00663 {
00664     if (RenderWindow)
00665         RenderWindow->DoneWithDC();
00666 }
00667 
00668 /********************************************************************************************
00669 
00670 >   void CCamView::AllocateDC()
00671 
00672     Author:     Alex Bligh <alex@alex.org.uk>
00673     Created:    12/06/2006
00674     Purpose:    Hints that we've done with our DC
00675     SeeAlso:    View; PaperRenderRegion.
00676 
00677 Note this is merely a hint. This routine is not guaranteed to eb called
00678 
00679 ********************************************************************************************/
00680 
00681 void CCamView::AllocateDC() const
00682 {
00683     if (RenderWindow)
00684         RenderWindow->AllocateDC();
00685 }
00686 
00687 
00688 /*********************************************************************************************
00689 >   void CCamView::GetClientSize(int * pWidth, int * pHeight) const    TYPENOTE: Correct
00690 
00691     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00692     Created:    ages ago
00693     Inputs:     -
00694     Outputs:    The width and height of the client area which the kernel can render into.
00695     Returns:    -
00696     Purpose:    Calculates the size of the CCamView's RendWnd.
00697     Errors:     -
00698     Scope:      Public
00699     SeeAlso:    class CRendWnd
00700 
00701 **********************************************************************************************/ 
00702 
00703 void CCamView::GetClientSize(int * pWidth, int * pHeight) const /* TYPENOTE: Correct */
00704 {
00705     if (GetRenderWindow())
00706     {
00707         WinRect wrect(0,0,0,0);
00708         GetRenderWindow()->GetClientSize(&wrect.width, &wrect.height);
00709         if (wrect.width<0) wrect.width = 0;
00710         if (wrect.height<0) wrect.height = 0;
00711         OilRect orect = wrect.ToOil(pDocView);
00712         *pWidth  = orect.Width();
00713         *pHeight = orect.Height();
00714     }
00715     else
00716     {
00717         *pWidth = 0;
00718         *pHeight = 0;
00719     }
00720 }
00721 
00722 
00723 // set this to 1 to show update rectangles using cross-hatching, 0 to not
00724 #define SHOW_RECT 0
00725 
00726 #if SHOW_RECT
00727 void DumpRect( wxDC *pDC, WinRect *lpRect, TCHAR *type )
00728 {
00729     static INT32 BrushNum = wxFIRST_HATCH;
00730     wxBrush Brush;
00731 
00732     Brush.SetStyle(BrushNum);
00733     Brush.SetColour(0, 0, 0);
00734 
00735     if (++BrushNum > wxLAST_HATCH)
00736         BrushNum = wxFIRST_HATCH;
00737 
00738     pDC->SetBrush(Brush);
00739     pDC->DrawRectangle(*lpRect);
00740 
00741     if (type)
00742     {
00743         TRACE( _T("%s (%ld, %ld) [%ld, %ld]"), type, lpRect->GetLeft(), lpRect->GetTop(), 
00744             lpRect->GetWidth(), lpRect->GetHeight() );
00745     }
00746 }
00747 
00748 #else
00749 #define DumpRect(pdc, rect, name)
00750 #endif
00751 
00752 /*********************************************************************************************
00753 
00754 >   virtual void CCamView::OnDraw(CDC* pDC)
00755 
00756     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00757     Created:    ages ago
00758     Inputs:     A pointer to the CDC object to render into.
00759     Outputs:    -
00760     Returns:    -
00761     Purpose:    Makes sure that the kernel knows which view to render into.  Retrieves the
00762                 clipping rectangle from the CDC.  Passes the CDC and the rectangle to
00763                 DocView::OnDraw(), which does the actual rendering.
00764     Errors:     -
00765     Scope:      Public
00766     SeeAlso:    CView::OnPrepareDC(); CCamView::OnRenderView(); DocView::OnDraw()
00767 
00768 **********************************************************************************************/ 
00769 
00770 void CCamView::OnDraw( wxDC* pDC )
00771 {
00772 //  TRACEUSER("Gerry",  _T("CCamView::OnDraw\n"));
00773 
00774     if (pDocView==NULL)
00775         return;
00776         
00777     // Set the current DocView, ie. the DocView being worked upon. (and the Doc!)
00778     pDocView->SetCurrent();
00779     (pDocView->GetDoc())->SetCurrent();
00780 
00781     // Are we printing?
00782     if (CCDC::ConvertFromNativeDC(pDC)->IsPrinting())
00783     {
00784         //TRACE( _T("BAD ! CCamView::OnDraw reckons we're printing\n"));
00785 #ifndef STANDALONE
00786 
00787         // Yes - do the printing!
00788 
00789         // Find out from the display context the rectangle bounding the invalid
00790         // region.
00791         WinRect clip;
00792         pDC->GetClippingBox(clip);
00793 
00794         if (clip.IsEmpty())
00795             return;
00796 
00797         // Pass the drawing parameters on to the associated PrintView object.
00798         pPrintView->AttachToDC(pDC);
00799         pPrintView->OnDraw(pDC, clip.ToOil(pPrintView));
00800         pPrintView->AttachToDC(NULL);
00801 
00802 #endif
00803     }
00804     else
00805     {
00806         WinRect clip;
00807 
00808         // wxWidget only provides a unified accessor, so that's
00809         // what we'll use
00810         wxRegionIterator upd( GetRenderWindow()->GetUpdateRegion() ); // get the update rect list
00811         while( upd )
00812         {
00813             clip.x      = upd.GetX();
00814             clip.y      = upd.GetY();
00815             clip.width  = upd.GetW();
00816             clip.height = upd.GetH();
00817 
00818 //          DumpRect( pDC, &clip, wxT("OnDraw UpdateRect : ") );
00819 
00820             OilRect oRect = clip.ToOil( pDocView );
00821 //          TRACEUSER("Gerry", _T("OilRect = (%d, %d) - (%d, %d)\n"), oRect.lo.x, oRect.lo.y, oRect.hi.x, oRect.hi.y);
00822             
00823             pDocView->OnDraw( pDC, oRect );
00824 
00825             upd ++ ;
00826         }
00827     }
00828 
00829 //  TRACEUSER("Gerry", _T("Leaving CCamView::OnDraw\n"));
00830 }
00831 
00832 /*********************************************************************************************
00833 
00834 >   afx_msg LRESULT CCamView::OnRenderView(WPARAM, LPARAM lp)
00835 
00836     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00837     Created:    ages ago
00838     Inputs:     A pointer to a CPaintDC, cast into an LPARAM.  The WPARAM is not used.
00839     Outputs:    -
00840     Returns:    Returns 0, indicating to Windows that the message was successfully
00841                 processed.
00842     Purpose:    Responds to a WM_PAINT message sent to the RendWnd window object.
00843                 Effectively tricks MFC into painting the RendWnd as if it was a
00844                 CView window, not a child of a CView - calls CView::OnPrepareDC()
00845                 and ScreenCamView::OnDraw().
00846     Errors:     -
00847     Scope:      Protected
00848     SeeAlso:    class CRendWnd; CRenderWnd::OnPaint(); ScreenCamView::OnDraw();
00849 
00850 **********************************************************************************************/ 
00851 
00852 LRESULT CCamView::OnRenderView( WPARAM, LPARAM lp )
00853 {
00854     PORTNOTETRACE("other","CCamView::OnRenderView - do nothing");
00855 #ifndef EXCLUDE_FROM_XARALX
00856     wxPaintDC         *pDC = (wxPaintDC *)lp;
00857     OnPrepareDC(pDC);
00858     OnDraw(pDC);
00859 #endif
00860     return 0;
00861 }
00862 
00863 #define USERNAME "Mike"
00864 
00865 //static RECT DriverBand;
00866 //static RECT TestBand;
00867 
00868 /********************************************************************************************
00869 
00870 >   void CCamView::OnFilePrint()
00871 
00872     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00873     Created:    02/09/95
00874     Purpose:    The main printing control function.  This is a modified version of the MFC
00875                 one because MFC does not allow the concept of having a mapping between
00876                 pages and physical pieces of paper other than 1 to 1.  i.e. MFC can't handle
00877                 two-up printing, fit lots, pamphlet printing etc.
00878     Errors:     -
00879     SeeAlso:    CView::OnFilePrint(); CCamView::OnFilePrintPreview()
00880 
00881 ********************************************************************************************/
00882 //  WEBSTER-ranbirr-12/11/96
00883 #ifndef WEBSTER
00884 void CCamView::OnFilePrint()
00885 {
00886 #if 0
00887 #ifndef _DEBUG
00888     ::wxMessageBox(_T("Printing currently disabled in retail builds"));
00889     return;
00890 #endif
00891 #endif
00892 
00893     SetCurrentStates();
00894 
00895     // Set Current states...
00896     Document* KernelDoc = GetDocument()->GetKernelDoc();
00897     ENSURE(KernelDoc != NULL, "Oh no!!");
00898     KernelDoc->SetCurrent();
00899     pDocView->SetCurrent();
00900 
00901     TRACEUSER( USERNAME, _T("OnFilePrint()\n"));
00902 
00903     // get default print info
00904     CCPrintInfo *pPrintInfo;
00905     pPrintInfo = new CCPrintInfo(KernelDoc,this);
00906     if (!pPrintInfo)
00907     {
00908         // Out of memory - report error and exit.
00909         Error::SetError(_R(IDS_OUT_OF_MEMORY));
00910         InformError();
00911         return;
00912     }
00913 
00914     // Make sure the user can't get 2 print dialog boxes up
00915     PrintMonitor::SetPrintingActive(TRUE);
00916 
00917     // Now bring up the print dialog
00918     if (!pPrintInfo->OnPreparePrinting())
00919     {
00920         TRACEUSER( USERNAME, _T("OnPreparePrinting() returned FALSE\n"));
00921         delete pPrintInfo;
00922         PrintMonitor::SetPrintingActive(FALSE);
00923         return;
00924     }
00925 
00926     // Get some paints out of the way
00927     ::wxSafeYield(FALSE);
00928 
00929     // Ensure the current documents remain the same
00930     KernelDoc->SetCurrent();
00931     pDocView->SetCurrent();
00932 
00933     List CompoundNodeList;
00934     NodeCompound * pCompound = NULL;
00935     NodeListItem * pItem = NULL;
00936     // Get ourselves a print view and attach it to this CCamView.
00937     // NB. Must be after the user has clicked OK on print dialog, as we set up
00938     //     anti-aliasing etc. in PrintView constructor.
00939     // Delete any old print view
00940     if (pPrintView != NULL)
00941     {
00942         delete pPrintView;
00943         pPrintView = NULL;
00944         delete pPrintInfo;
00945         PrintMonitor::SetPrintingActive(FALSE);
00946         ERROR2((void)0, "OnPreparePrinting(): we already have a PrintView!");
00947     }
00948     // make a new one
00949     pPrintView = new PrintView(pDocView->GetDoc());
00950     if (pPrintView == NULL)
00951     {
00952         delete pPrintInfo;
00953         PrintMonitor::SetPrintingActive(FALSE);
00954         ERROR2((void)0, "Not enough memory to create PrintView object");
00955     }
00956     // and connect it to the OilView
00957     if (!pPrintView->ConnectToOilView(this))
00958     {
00959         delete pPrintView;
00960         pPrintView = NULL;
00961         delete pPrintInfo;
00962         PrintMonitor::SetPrintingActive(FALSE);
00963         ERROR2((void)0, "Unable to attach PrintView to CCamView.");
00964     }
00965 
00966     double dpi = 96.0;
00967 
00968     PrintControl* pPrCtrl = NULL;
00969     PrintComponent* pComp = (PrintComponent*)KernelDoc->GetDocComponent(CC_RUNTIME_CLASS(PrintComponent));
00970     if (pComp != NULL)
00971         pPrCtrl = pComp->GetPrintControl();
00972 
00973     if (pPrCtrl != NULL)
00974         pPrCtrl->SetUp(KernelDoc->GetSelectedSpread());
00975 
00976     wxString strTemp;
00977 
00978     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
00979     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
00980     TRACEUSER( "ChrisS", _T("Entering print loop\n"));
00981     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
00982     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
00983 
00984 //  ERROR3IF(pPrintInfo->m_pPD->m_pd.hDC == NULL, "NULL DC when trying to print.");
00985     // must be set (did you remember to call DoPreparePrinting?)
00986 
00987     // Let's see if we can start printing...
00988     if ((!pPrintInfo->GetDC()) || 
00989         !PrintMonitor::StartPrintJob(pPrintInfo->GetDC()))
00990     {
00991         TRACEUSER( USERNAME, _T("StartPrintJob() screwed up\n"));
00992 
00993         // No - something went wrong.
00994         if (!pPrintInfo->GetDC())
00995         {
00996             // No DC - set a generic "we can't print" error.
00997             Error::SetError(_R(IDE_PRINT_ERROR_SYSTEM));
00998         }
00999 
01000         // Tell user and exit.
01001         InformError();
01002         delete pPrintInfo;
01003         PrintMonitor::SetPrintingActive(FALSE);
01004         return;
01005     }
01006 
01007     // OnBeginPrinting(pPrintInfo->GetDC(), pPrintInfo);
01008 
01009     // Get access to our print control object
01010     PrintControl *pPrintControl = pPrintView->GetPrintControl();
01011 
01012     Spread * pSpread = Document::GetSelectedSpread();
01013 
01014     // disable main window while printing & init printing status dialog
01015 //  AfxGetMainWnd()->EnableWindow(FALSE);
01016 
01017 PORTNOTE("printing", "Disable pDocInfo stuff");
01018 #ifndef EXCLUDE_FROM_XARALX
01019     // set up document info and start the document printing process
01020     DOCINFO* pDocInfo = NULL;
01021 
01022     // start document printing process
01023     if  ((pPrintInfo->SetAbortProc(&dcPrint) < 0) ||
01024          !pPrintInfo->SetUpDocInfo(&pDocInfo)     ||        // SetUpDocInfo() allocs a DOCINFO for pDocInfo
01025          pDocInfo == NULL                         ||
01026 #else
01027     if (
01028 #endif
01029          (!pPrintInfo->GetDC()->StartDoc(wxString((TCHAR *)(Document::GetSelected()->GetTitle()))))
01030         )
01031     {
01032         TRACEUSER( USERNAME, _T("Unable to start document\n"));
01033 
01034         // enable main window before proceeding
01035 //      AfxGetMainWnd()->EnableWindow(TRUE);
01036 
01037         // cleanup and show error message
01038 //      OnEndPrinting(&dcPrint, pPrintInfo);
01039 
01040         BOOL PrintToFileUserAborted = pPrintInfo->GetPrintControl ()->GetPrintToFile ();
01041 
01042         delete pPrintInfo;
01043         pPrintInfo = NULL;
01044         PrintMonitor::EndPrintJob();
01045 
01046         // Lose our PrintView
01047         delete pPrintView;
01048         pPrintView = NULL;
01049 
01050 PORTNOTE("printing", "Disabled pDocInfo")
01051 #ifndef EXCLUDE_FROM_XARALX
01052         // Delete a the docinfo object
01053         if (pDocInfo != NULL)
01054         {
01055             delete pDocInfo;
01056             pDocInfo = NULL;
01057         }
01058 #endif
01059 
01060 //      dcPrint.Detach();   // will be cleaned up by CPrintInfo destructor
01061         if (!PrintToFileUserAborted)
01062         {
01063             InformError(_R(AFX_IDP_FAILED_TO_START_PRINT));
01064         }
01065         PrintMonitor::SetPrintingActive(FALSE);
01066         return;
01067     }
01068 
01069     BOOL StartedPrinting = FALSE;
01070 
01071     // CGS:  any blended compound nodes MUST be tagged as having been generated for printing
01072     NodeGroup::SetIsForPrinting (TRUE);
01073 
01074     // begin page printing loop
01075     BOOL bError = TRUE;
01076 
01077     // Set up the print layout system.
01078     // This allows GetNextPaper() and ReprintPaper() functions
01079     // to be called.
01080     if (!pPrintInfo->StartPrinting())
01081     {
01082         TRACEUSER( USERNAME, _T("StartPrinting() failed\n"));
01083         // Error in starting printing.
01084         Error::SetError(_R(IDE_PRINT_ERROR_SYSTEM));
01085         goto ExitPrint;
01086     }
01087 
01088     // Must remember to tell print info object when we are done.
01089     StartedPrinting = TRUE;
01090 
01091     // Work out if we should do our own PostScript
01092     BOOL DoPostScript;
01093     if ((pPrintControl->GetPrintMethod() == PRINTMETHOD_NORMAL) &&
01094         (pPrintInfo->GetCCDC()->GetRenderType() == RENDERTYPE_PRINTER_PS))
01095     {
01096         // Not printing as a bitmap and it is a PostScript printer so mark it as such.
01097         DoPostScript = TRUE;
01098     }
01099     else
01100     {
01101         // Either it's not a PostScript printer or we are printing as a bitmap,
01102         // so don't do weird PostScript stuff
01103         DoPostScript = FALSE;
01104     }
01105 
01106     // If we are printing as bitmap, then set the "Printing blah.art" message in the dialog.
01107     // (This is done by RenderSimpleView() when we are printing normally).
01108     if ((pPrintControl->GetPrintMethod() != PRINTMETHOD_NORMAL) && (pPrintInfo != NULL))
01109         // We going to print the document now
01110         pPrintInfo->SetPrinting();
01111 
01112 PORTNOTE("printing", "Disable banding call");
01113 #ifndef EXCLUDE_FROM_XARALX
01114     // Ask the printer if it supports banding. We don't actually need the result of this call,
01115     // but asking the printer about banding has the side effect that the printer driver then
01116     // knows that we support banding! If we don't do this, then some printing (e.g. to an HP DeskJet
01117     // on Win3.1) simply chucks out blank pages, because the driver thinks we can't band, and there
01118     // isn't enough memory/disc space (or something) to do the page in one go.
01119     //
01120     // BLOCK
01121     {
01122         BOOL BandInfoSupported = FALSE;
01123         WORD wEscape = BANDINFO;
01124         if (!DoPostScript && 
01125             PrintMonitor::PrintWithDriverBands &&
01126             dcPrint.Escape(QUERYESCSUPPORT, sizeof(WORD), (LPCSTR) &wEscape, NULL) > 0)
01127         {
01128             // The BANDINFO Escape is supported  -  but we don't actually care!
01129             BandInfoSupported = TRUE;
01130         }
01131     }
01132 #endif
01133 
01134     // DMc 22-7-99
01135     // MRH 11/9/00 - Major rewrite of the below david code. Fixed major logic problem and
01136     // cut out the regeneratenodes function as this is not required!
01137     BevelTools::GetAllNodesUnderNode(pSpread, &CompoundNodeList, CC_RUNTIME_CLASS(NodeCompound));
01138     
01139     dpi = OSRenderRegion::GetFixedDCPPI(*pPrintInfo->GetDC()).GetWidth();
01140 
01141     if (pPrintControl)
01142         dpi = (double)pPrintControl->GetDotsPerInch();
01143     
01144     pItem = (NodeListItem *)CompoundNodeList.GetHead();
01145     
01146     while (pItem)
01147     {
01148         pCompound = (NodeCompound *)pItem->pNode;
01149         
01150         if (pCompound)
01151         {
01152             if (pCompound->RegenerateForPrinting())
01153             {
01154                 pCompound->SetDPI(dpi);
01155                 pCompound->SetPrinting(TRUE);
01156             }
01157         }
01158         
01159         pItem = (NodeListItem *)CompoundNodeList.GetNext(pItem);
01160     }
01161     
01162     TRACEUSER( "DavidM", _T("Beginning print dpi %d\n"), dpi);
01163 
01164     // Loop around for each physical page ("paper") we have to print. Note that now we may print out
01165     // multiple physical pieces of paper for each "paper" (page) as we may do C, M, Y, K plates etc.
01166 
01167     while (pPrintInfo->MorePaper())
01168     {
01169         // Start off the print marks system bits for this paper
01170         // We lock progress window updates during this call so that the progress window will
01171         // ignore all attempts to update the display.
01172         pPrintInfo->LockProgressUpdate(TRUE);
01173             EnumeratePagePatches(pPrintInfo);
01174         pPrintInfo->LockProgressUpdate(FALSE);
01175 
01176         // Initialise the plate printing system for any plates of this page
01177         // It also sets up GetNextPlate() and ReprintPlate functions
01178         UINT32 plateerr;
01179         if (!pPrintInfo->StartPlatePrinting(pPrintView, &plateerr))
01180         {
01181             TRACEUSER( USERNAME, _T("StartPlatePrinting() failed\n"));
01182             // Error in startplateprinting! the error id may have been returned
01183             // We ignore the id if zero, ie StartPlatePrinting reported it.
01184             if (plateerr>0)
01185             {
01186                 String_64 reason;
01187                 String_256 ErrorMsg;
01188                 BOOL ok = ( reason.Load(plateerr) );
01189                 ok = ok && ( ErrorMsg.MakeMsg( _R(IDE_PRINT_ERROR), (LPCTSTR) reason) > 0);
01190                 if (ok)
01191                     Error::SetError(_R(IDE_PRINT_ERROR), (TCHAR *) ErrorMsg, 0);
01192                 else
01193                     Error::SetError(_R(IDE_PRINT_USERABORT));
01194             }
01195             goto ExitPrint;
01196         }
01197         
01198         // Loop around for each logical plate we have to print - this generates a piece of physical
01199         // paper out of the printer on each pass.
01200         while (pPrintInfo->MorePlates())
01201         {
01202             // Get the first "paper" (plate or page) to print
01203             pPrintInfo->GetNextPaper();
01204 
01205             // and set up the plate printing system ready to print the next plate on the next pass
01206             if (!pPrintInfo->SetNextPlate(pPrintView))
01207             {
01208                 TRACEUSER( USERNAME, _T("SetNextPlate() failed!\n"));
01209                 // Error in starting printing.
01210                 Error::SetError(_R(IDE_PRINT_ERROR_SYSTEM));
01211                 pPrintInfo->EndPlatePrinting(pPrintView);
01212                 goto ExitPrint;
01213             }
01214 
01215             // Now, prepare this paper (plate/page) for printing
01216             TRACEUSER( USERNAME, _T("Starting physical page\n"));           
01217 //          OnPrepareDC(pPrintInfo->GetDC(), pPrintInfo);
01218 
01219             // check for end of print
01220             if (!pPrintInfo->m_bContinuePrinting || pPrintInfo->Abort())
01221             {
01222                 TRACEUSER( USERNAME, _T("Print abort 1\n"));
01223                 pPrintInfo->EndPlatePrinting(pPrintView);
01224                 goto ExitPrint;
01225             }
01226 
01227             // attempt to start the current paper
01228             pPrintInfo->GetDC()->StartPage();
01229             if (0) // error handling non-existant
01230             {
01231                 TRACEUSER( USERNAME, _T("Unable to StartPage()\n"));
01232                 Error::SetError(_R(IDE_PRINT_ERROR_SYSTEM));
01233                 pPrintInfo->EndPlatePrinting(pPrintView);
01234                 goto ExitPrint;
01235             }                 
01236 
01237             // Is it a PostScript printer?
01238             if (DoPostScript)
01239             {
01240                 // Yes, so before we start the page, we send our PostScript procset to the device.
01241                 if (!PrintPSRenderRegion::InitPSDevice(pPrintInfo->GetDC(), pPrintView))
01242                 {
01243                     TRACEUSER( USERNAME, _T("Unable to Init PS device\n"));
01244                     Error::SetError(_R(IDE_PRINT_ERROR_SYSTEM));
01245                     pPrintInfo->EndPlatePrinting(pPrintView);
01246                     goto ExitPrint;
01247                 }
01248             }
01249 
01250 PORTNOTE("printing", "Disable banding call");
01251 #ifndef EXCLUDE_FROM_XARALX
01252             // If banding, find the first band to print
01253             // Only use driver banding if the preference says so, and never band
01254             // to PS devices (yes, the Win95 PS driver supports banding, except
01255             // not really and it just screws up).
01256             if (PrintMonitor::PrintWithDriverBands && !DoPostScript)
01257             {
01258                 // Do the driver banding
01259                 dcPrint.Escape(NEXTBAND, 0, NULL, (LPSTR) &DriverBand);
01260 
01261                 TRACEUSER( USERNAME, _T("INITIALBAND: (%d,%d), (%d, %d)\n"),
01262                          DriverBand.left, DriverBand.top, DriverBand.right, DriverBand.bottom);
01263             }
01264 #endif
01265 
01266             TRACEUSER( USERNAME, _T("Starting PrintPaper() loop...\n"));
01267 
01268             // Now render the paper into each band.
01269             BOOL MoreBands = TRUE;
01270             while (MoreBands)
01271             {
01272                 TRACEUSER( USERNAME, _T("Calling PrintPaper()...\n"));
01273                 // Print this piece of paper (to the current band)
01274                 if (!PrintPaper(pPrintInfo->GetDC(), pPrintInfo, pPrintControl))
01275                 {
01276                     // Something went wrong - quit and abort print job.
01277                     TRACEUSER( USERNAME, _T("PrintPaper() failed\n"));
01278                     Error::SetError(_R(IDE_PRINT_ERROR_SYSTEM));
01279                     pPrintInfo->EndPlatePrinting(pPrintView);
01280                     goto ExitPrint;
01281                 }
01282 
01283                 // Only use driver banding if the preference says so, and never band to PS devices.
01284                 MoreBands = FALSE;      // Assume no more bands until told otherwise
01285 PORTNOTE("printing", "Disable banding call");
01286 #ifndef EXCLUDE_FROM_XARALX
01287                 if (PrintMonitor::PrintWithDriverBands && !DoPostScript)
01288                 {
01289                     // We've printed this band - see if printer driver has any bands left,
01290                     // NB we kludge this as some drivers keep returning the same band...fabby eh?
01291                     dcPrint.Escape(NEXTBAND, 0, NULL, (LPSTR) &DriverBand);
01292                     TRACEUSER( USERNAME, _T("Driver returned valid band: (%d,%d), (%d, %d)\n"),
01293                               DriverBand.left, DriverBand.top, DriverBand.right, DriverBand.bottom);
01294 
01295                     // If it does, then we need to loop around to print this physical piece of paper
01296                     // into the next band...
01297                     if (!IsRectEmpty(&DriverBand))
01298                     {
01299                         TRACEUSER( USERNAME, _T("Forcing a reprint of paper [for band: (%d,%d), (%d, %d)]\n"),
01300                                   DriverBand.left, DriverBand.top, DriverBand.right, DriverBand.bottom);
01301                         MoreBands = TRUE;
01302                     }
01303                     else
01304                     {
01305                         TRACEUSER( USERNAME, _T("End of bands for this page\n"));
01306                     }
01307                 }
01308 #endif
01309 
01310                 // If we're going to print more bands, then set up the "paper" for the next band
01311                 if (MoreBands)
01312                 {
01313                     // Tell the print control that we want the same "paper" again, rather than moving
01314                     // on to the next one.
01315                     pPrintControl->ReprintPaper();
01316 
01317                     // And reset all the PrintInfo data for this "paper" ready for the next band
01318                     pPrintInfo->GetNextPaper();
01319                 }
01320             }
01321 
01322             TRACEUSER( USERNAME, _T("Ending physical page\n"));
01323             
01324             // End of page clean up.
01325             // Note that we don't check for an error from EndPage() because due to
01326             // a bug (in Windows/GDI) it returns -1 when using banding.
01327             // The MS workaround is to not check the return value!
01328             pPrintInfo->GetDC()->EndPage();
01329 
01330             if (!pPrintInfo->m_bContinuePrinting || pPrintInfo->Abort())
01331             {
01332                 TRACEUSER( USERNAME, _T("Print abort 2\n"));
01333                 pPrintInfo->EndPlatePrinting(pPrintView);
01334                 goto ExitPrint;
01335             }
01336         
01337             // Any more plates to print?, if so we need to print the plate as a complete new page.
01338             // We set ReprintPaper so that the next pass tries to print the same "paper" (document page)
01339             // again, but we've moved it on to the next plate (in SetNextPlate, above), so we'll actually
01340             // be rendering a different plate the next time around.
01341             if (pPrintInfo->MorePlates())
01342                 pPrintControl->ReprintPaper();
01343         }   
01344 
01345         // End the plate printing function
01346         pPrintInfo->EndPlatePrinting(pPrintView);
01347     }
01348 
01349     // Set the flag to indicate that we're exiting happily
01350     bError = FALSE;
01351 
01352 
01353 ExitPrint:
01354     if (!bError)
01355         pPrintInfo->GetDC()->EndDoc();
01356     else
01357     {
01358         TRACEUSER( USERNAME, _T("ExitPrint: an error occured()\n"));
01359         // An error occured - abort the job.
01360 //      pPrintInfo->GetDC()->AbortDoc();
01361 
01362         // If the user did not cancel the job, report what went wrong.
01363         if (!pPrintInfo->Abort())
01364             InformError();
01365     }
01366 
01367     // cleanup document printing process
01368     PrintMonitor::EndPrintJob();
01369 
01370 //  AfxGetMainWnd()->EnableWindow();    // enable main window
01371 
01372 //  OnEndPrinting(pPrintInfo->GetDC(), pPrintInfo);    // clean up after printing
01373 
01374     // Clean up kernel printing code
01375     if (StartedPrinting)
01376         pPrintInfo->EndPrinting();
01377 
01378 PORTNOTE("printing", "Remove DOCINFO stuff");
01379 #ifndef EXCLUDE_FROM_XARALX
01380     // Delete a the docinfo object
01381     if (pDocInfo != NULL)
01382     {
01383         delete pDocInfo;
01384         pDocInfo = NULL;
01385     }
01386 #endif
01387 
01388     PrintMonitor::SetPrintingActive(FALSE);
01389 
01390     // Lose our PrintView (if it exists) - not needed anymore.
01391     if (pPrintView)
01392     {
01393         delete pPrintView;
01394         pPrintView = NULL;
01395     }
01396 
01397     // Deleting the print view appears to unset the current document, so fix it
01398     KernelDoc->SetCurrent();
01399     pDocView->SetCurrent();
01400 
01401     if (pPrintInfo)
01402     {
01403         delete pPrintInfo;
01404         pPrintInfo = NULL;
01405     }
01406 
01407     // If we need to redraw everything then do it.
01408     if (PrintMonitor::FullRedrawNeeded)
01409     {
01410         // iterate through all the documents and get them to redraw themselves
01411         Document* pDoc = (Document*) Camelot.Documents.GetHead();
01412 
01413         while (pDoc!=NULL)
01414         {
01415             // Get it to redraw itself
01416             pDoc->ForceRedraw();
01417 
01418             // get the next document in the list
01419             pDoc = (Document*) Camelot.Documents.GetNext(pDoc);
01420         }
01421     }
01422 
01423     // mark the PrintMonitor as not needing a redraw
01424     PrintMonitor::WantFullRedraw(FALSE);
01425 
01426     // DMc restore the compound nodes dpi's
01427     pItem = (NodeListItem *)CompoundNodeList.GetHead();
01428     
01429     while (pItem)
01430     {
01431         pCompound = (NodeCompound *)pItem->pNode;
01432         
01433         if (pCompound)
01434         {
01435             if (pCompound->RegenerateForPrinting())
01436             {
01437                 pCompound->SetDPI(96.0);
01438                 pCompound->SetPrinting(FALSE);
01439             
01440                 pCompound->RegenerateNode(NULL, FALSE);
01441             }
01442         }
01443         
01444         pItem = (NodeListItem *)CompoundNodeList.GetNext(pItem);
01445     }   
01446 
01447     CompoundNodeList.DeleteAll();
01448 
01449     NodeGroup::KillAllBlendBecomeAConsLists (FALSE, TRUE);
01450     NodeGroup::SetIsForPrinting (FALSE);
01451 
01452     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
01453     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
01454     TRACEUSER( "ChrisS", _T("Exiting print loop\n"));
01455     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
01456     TRACEUSER( "ChrisS", _T("------------------------------------------------------------------------\n"));
01457 }
01458 
01459 #endif //webster
01460 
01461 
01462 
01463 // Size of bands to use when printing as bitmap.
01464 #define BAND_HEIGHT (128)
01465 
01466 /********************************************************************************************
01467 
01468 >   BOOL ScreenCamView::PrintPaper(CDC *pPrintDC, 
01469                                    CCPrintInfo *pPrintInfo,
01470                                    PrintControl *pPrintControl)
01471 
01472     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01473     Created:    05/11/95
01474     Inputs:     pPrintDC - the (printer) device context to print to.
01475                 pPrintInfo - the object to use for layout control.
01476     Returns:    TRUE if the paper was printed ok;
01477                 FALSE if not.
01478     Purpose:    Prints all the ink onto a physical piece of paper.  This includes coping
01479                 with patches (multiple copies on one piece of paper, and banding bitmap
01480                 printing to improve performance.
01481     Errors:     pPrintDC has a bad DC handle => ERROR3
01482                 Problem with setting up clipping region => ERROR2
01483     SeeAlso:    ScreenCamView::OnFilePrint; ScreenCamView::GetPrintClipRect
01484 
01485 ********************************************************************************************/
01486 //  WEBSTER-ranbirr-12/11/96
01487 #ifndef WEBSTER
01488 BOOL CCamView::PrintPaper(CNativeDC *pPrintDC, 
01489                             CCPrintInfo *pPrintInfo, 
01490                             PrintControl *pPrintControl)
01491 {
01492 //  TRACEUSER( "Tim", _T("PrintPaper() started\n"));
01493 
01494 //  TRACEUSER( "Tim", _T("PrintPaper() printing band=(%d,%d),(%d,%d)\n"),
01495 //            DriverBand.left, DriverBand.top, DriverBand.right, DriverBand.bottom);
01496 
01497 
01498     // Page successfully started, so now render the page by doing each 'patch'
01499     // in turn.  Note that we store the patch information in the print view,
01500     // which the view will use when setting up to render
01501     // (see PrintView::ConstructRenderingMatrix())
01502     while (pPrintInfo->GetNextPatch(&pPrintView->PatchInfo))
01503     {
01504         // Tell the view what scale this is.
01505         pPrintView->SetViewScale(pPrintView->PatchInfo.Scale / FIXED16(100));
01506 
01507         // Set up drawing rect to entire page (in logical coordinates)
01508         wxRect r(wxPoint(0, 0), pPrintDC->GetSize());
01509         wxCoord x1=pPrintDC->DeviceToLogicalX(r.GetLeft());
01510         wxCoord x2=pPrintDC->DeviceToLogicalX(r.GetRight()+1);
01511         wxCoord y1=pPrintDC->DeviceToLogicalY(r.GetTop());
01512         wxCoord y2=pPrintDC->DeviceToLogicalY(r.GetBottom()+1);
01513         wxCoord lowx=wxMin(x1,x2);
01514         wxCoord highx=wxMax(x1,x2);
01515         wxCoord lowy=wxMin(y1,y2);
01516         wxCoord highy=wxMax(y1,y2);
01517         pPrintInfo->m_rectDraw=wxRect(wxPoint(lowx,lowy),wxSize(highx-lowx,highy-lowy));
01518 
01519         // Let's band this to make performance acceptable.
01520 
01521         // Bodge banding - many printer drivers don't do banding so performance
01522         // is a dog (i.e. not enough memory to print on my 32Mb machine!)
01523         const INT32 BandHeight = BAND_HEIGHT;
01524         INT32 BottomOfPage = pPrintInfo->m_rectDraw.GetBottom()+1; //+1 is wxRect stupidity
01525 //      const INT32 PageHeight = pPrintInfo->m_rectDraw.GetBottom() - pPrintInfo->m_rectDraw.GetTop();
01526 
01527         // Find print control object for this document, to see if we are
01528         // printing via bitmap, and so if we need to band the output.
01529         PrintMethodType PrintType;
01530         PrintType = pPrintControl->GetPrintMethod();
01531 
01532         // Work out whether or not to use banding for printing.
01533         // (i.e. are we printing with a bitmap?)
01534         if ((PrintType == PRINTMETHOD_AABITMAP) ||
01535             (PrintType == PRINTMETHOD_BITMAP))
01536         {
01537             // Banding is required - set up first band.
01538             pPrintInfo->SetSliderSubRangeMax(pPrintInfo->m_rectDraw.GetHeight() / BAND_HEIGHT);
01539             pPrintInfo->m_rectDraw.height = BandHeight;
01540         }
01541 
01542         INT32 CurrentBand = 0;
01543 
01544         TRACEUSER( "Tim", _T("Rectangle: (%d,%d), (%d,%d) BottomOfPage=%d\n"),
01545                  pPrintInfo->m_rectDraw.GetLeft(), pPrintInfo->m_rectDraw.GetTop(),
01546                  pPrintInfo->m_rectDraw.GetRight()+1,pPrintInfo->m_rectDraw.GetBottom()+1,
01547                  BottomOfPage);
01548 
01549         while (pPrintInfo->m_rectDraw.GetBottom()+1 <= BottomOfPage)
01550         {
01551             // Update slider
01552             if ((PrintType == PRINTMETHOD_AABITMAP) ||
01553                 (PrintType == PRINTMETHOD_BITMAP))
01554             {
01555                 // Doing our own banding, so update progress slider.
01556                 pPrintInfo->SetSliderSubRangePos(CurrentBand);
01557             }
01558 
01559             //
01560             // Strange stuff to work out what area to print in this band.
01561             //
01562             WinRect OILClip = GetPrintClipRect(pPrintDC, pPrintInfo);
01563 
01564             // Check for no intersection.
01565             if (!OILClip.IsEmpty())
01566             {
01567                 // Put this clip region into print info structure.
01568                 pPrintInfo->m_rectDraw = OILClip;
01569 
01570                 wxRect oldclip(wxPoint(0,0), wxSize(0,0));
01571                 pPrintDC->GetClippingBox(oldclip);
01572                 pPrintDC->SetClippingRegion(pPrintInfo->m_rectDraw);
01573 
01574                 // Print the band.
01575                 pPrintView->SetCurrent();
01576                 OnPrint(pPrintDC, pPrintInfo);
01577 
01578                 pPrintDC->SetClippingRegion(oldclip);
01579 
01580                 if (!pPrintInfo->m_bContinuePrinting || pPrintInfo->Abort())
01581                     // Printing has finished.
01582                     return FALSE;
01583             }
01584 
01585             // Is this the last band?
01586             if (pPrintInfo->m_rectDraw.GetBottom()+1 < BottomOfPage)
01587             {
01588                 // No - get the next band.
01589                 pPrintInfo->m_rectDraw.y = pPrintInfo->m_rectDraw.GetBottom()+1;
01590                 pPrintInfo->m_rectDraw.height = BandHeight;
01591 
01592                 // Limit to bottom of page if necessary.
01593                 if (pPrintInfo->m_rectDraw.GetBottom()+1 > BottomOfPage)
01594                     pPrintInfo->m_rectDraw.height -= pPrintInfo->m_rectDraw.GetBottom()+1 - BottomOfPage;
01595             }
01596             else
01597             {
01598                 // No bands left - so we're done here.
01599                 TRACEUSER( "Tim", _T("No bespoke banding\n"));
01600                 break;
01601             }
01602 
01603             CurrentBand++;
01604         }
01605     }
01606 
01607     TRACEUSER( "Tim", _T("PrintPaper() finished\n"));
01608 
01609     // All worked ok
01610     return TRUE;
01611 }
01612 #endif //webster
01613 
01614 
01615 /********************************************************************************************
01616 
01617 >   WinRect CCamView::GetPrintClipRect(CDC *pPrintDC, CCPrintInfo *pPrintInfo)
01618 
01619     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01620     Created:    05/11/95
01621     Inputs:     pPrintDC - the device context we are printing to - we need this because
01622                            otherwise the PrintView object can't compute the rendering
01623                            matrix, which we need in order to find out the position of the
01624                            patch on the DC.
01625                 pPrintInfo - the print info object, which specifies the window onto the
01626                              page/DC that we can print into.
01627     Returns:    The intersection of the area of the current patch (as held in 
01628                 ScreenCamView::pPrintView->PatchInfo) and the printable area of the DC,
01629                 in WinCoords.
01630     Purpose:    Works out which area of the paper to print on, given the current patch
01631                 (as held in the PrintView object), and the printing area specified by
01632                 the CCPrintInfo object.
01633     SeeAlso:    ScreenCamView::PrintPaper; PrintView::ConstructRenderingMatrix
01634 
01635 ********************************************************************************************/
01636 //  WEBSTER-ranbirr-12/11/96
01637 #ifndef WEBSTER
01638 WinRect CCamView::GetPrintClipRect(CNativeDC *pPrintDC, CCPrintInfo *pPrintInfo)
01639 {
01640     // We need to attach the PrintView while we are doing this so it knows how big
01641     // the pixels are and so on.
01642     pPrintView->AttachToDC(pPrintDC);
01643 
01644     // Get the rendering matrix for this patch
01645     Spread *pSpread = Document::GetSelectedSpread(); // Should be PatchInfo.pSpread
01646     Matrix TheMatrix = pPrintView->ConstructRenderingMatrix(pSpread);
01647 
01648     // Use matrix to transform clip rect of patch to Oil coords.
01649     DocRect ClipRect = pPrintView->PatchInfo.GetClipRect(FALSE,FALSE);
01650 
01651     // turn this clip rect into an OilRect
01652     OilRect PatchClipRect(OilCoord(ClipRect.lo.x, ClipRect.lo.y),
01653                           OilCoord(ClipRect.hi.x, ClipRect.hi.y));
01654 
01655     TheMatrix.transform(&PatchClipRect.lo);
01656     TheMatrix.transform(&PatchClipRect.hi);
01657 
01658     // Rendering transform may involve a rotation so correct if necesary.
01659     pPrintView->CorrectRotatedRectangle((Rect *) &PatchClipRect);
01660 
01661     // We need to inflate the clipping rectangle as this is used to determin the
01662     // bitmap size when rendering to AABITMAP output (and BITMAP).
01663     // Ok, There is a problem here.... We need to set the clip rectangle to cover
01664     // the crop area too. Otherwise, when rendering text as text, GDI will bin the
01665     // crop mark text we render. We do this after the transform to avoid the transform
01666     // scaling this unscalable value.
01667     pPrintView->PatchInfo.InflateRectBy(&PatchClipRect, TRUE, TRUE);
01668 
01669     // Convert the OIL cliprect to logical GDI units
01670     WinRect WinClipRect;
01671     WinClipRect = PatchClipRect.ToWin(pPrintView);
01672 
01673     // Find intersection with clip rect.
01674     WinRect OILClip=WinClipRect;
01675     OILClip.Intersect(pPrintInfo->m_rectDraw);
01676 
01677     // Finished messing with the PrintView for the mo so we can detach the DC.
01678     // It is eventually re-attached (in ScreenCamView::OnDraw()) when we call OnPrint().
01679     pPrintView->AttachToDC(NULL);
01680 
01681     return OILClip;
01682 }
01683 #endif //webster
01684 
01685 /********************************************************************************************
01686 
01687 >   void CCamView::EnumeratePagePatches(CCPrintInfo *pPrintInfo)
01688 
01689     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01690     Created:    14/09/96
01691     Inputs:     pPrintInfo - the print info object, which specifies the window onto the
01692                              page/DC that we can print into.
01693     Returns:    
01694     Purpose:    In order to locate crop marks / registration marks etc correctly, we need
01695                 to work out the bounds of all patches printed on a single sheet of paper.
01696                 This routine does just that.
01697                 
01698 ********************************************************************************************/
01699 //  WEBSTER-ranbirr-12/11/96
01700 #ifndef WEBSTER
01701 void CCamView::EnumeratePagePatches(CCPrintInfo *pPrintInfo)
01702 {
01703 #ifndef EXCLUDE_FROM_RALPH
01704 #ifndef STANDALONE
01705 
01706     DocRect Bounds;
01707     DocRect cliprect;
01708     INT32 bleed=0;
01709     BOOL emuldwn=FALSE;
01710 
01711     // get a pointer to the print marks manager
01712     PrintMarksMan *pMarksMan = GetApplication()->GetMarksManager();
01713     if (pMarksMan==NULL)
01714         return;
01715 
01716     // Destroy what we may already have from a previous piece of paper
01717     pMarksMan->ResetPageRects();
01718 
01719     PrintPatchInfo* pPatchInfo = &pPrintView->PatchInfo;
01720     if (pPrintInfo->GetNextPaper())
01721     {
01722         // scan through each patch on the first paper region
01723         while (pPrintInfo->GetNextPatch(pPatchInfo))
01724         {
01725             // Get raw patch clip rectangle
01726             cliprect = pPatchInfo->GetClipRect(FALSE,FALSE);
01727             bleed = pPatchInfo->GetBleed();
01728             emuldwn = pPatchInfo->EmulsionDown;
01729             // dont inflate by the bleed, this is passed in and used by the print marks manager
01730             //cliprect.Inflate(pPatchInfo->Bleed);
01731             // Build a Spread=>OS conversion matrix for this patch
01732             Matrix TheMatrix = pPrintView->ConstructRenderingMatrix(pPatchInfo->pSpread);
01733             // transform the patch
01734             TheMatrix.transform(&cliprect.lo);
01735             TheMatrix.transform(&cliprect.hi);
01736             // Rendering matrix may involve a rotation when printing so correct the rectangle
01737             // for this if necessary.
01738             pPrintView->CorrectRotatedRectangle((Rect *)&cliprect);
01739             // tell the marks manager about these bounds.
01740             pMarksMan->AddPageRect(cliprect);
01741         }
01742     }
01743     
01744     // Get the marks manager to update its imagesetting rect
01745     pMarksMan->SetImagesettingRect();
01746     pMarksMan->SetBleed(bleed);
01747     pMarksMan->SetEmulsionDown(emuldwn);
01748     
01749     // reprint this piece of paper so we dont upset the print system
01750     pPrintInfo->ReprintPaper();
01751 
01752 #endif
01753 #endif
01754 }
01755 
01756 #endif //webster
01757 
01758 PORTNOTE("printing", "Disabled lots of printing code")
01759 #ifndef EXCLUDE_FROM_XARALX
01760 
01761 /*********************************************************************************************
01762 >   BOOL CCamView::OnPreparePrinting(CPrintInfo* pInfo)
01763 
01764     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01765     Created:    by the wonderful AppWizard
01766     Inputs:     -
01767     Outputs:    Fills the passed CPrintInfo with some stuff.
01768     Returns:    TRUE if successful preparation for printing.
01769     Purpose:    Current just returns that value of CView::DoPreparePrinting()
01770     Errors:     -
01771     Scope:      Public
01772     SeeAlso:    CView::DoPreparePrinting()
01773 
01774 **********************************************************************************************/ 
01775 
01776 BOOL CCamView::OnPreparePrinting(CPrintInfo* pInfo)
01777 {
01778 #ifndef STANDALONE
01779 
01780 //  if (!CCPrintDialog::OnPreparePrinting(pInfo,pDocView->GetDoc()))
01781 //      ERROR2(FALSE,"Unable to initialise the customized print dialog");
01782 
01783     // default preparation
01784     BOOL Result = CCamView::DoPreparePrinting(pInfo);
01785     if (!Result)
01786         return FALSE;
01787 
01788     // Check because brainless CView only checks for valid DC in debug builds - handy eh? NOT!
01789     if (pInfo->m_pPD->m_pd.hDC == NULL)
01790     {
01791         ERROR1(FALSE,_R(IDE_NULL_PRINTDC));
01792         //ERROR2(FALSE, "No valid DC returned by print dialog!");
01793     }
01794 
01795     // Get ourselves a print view and attach it to this CCamView.
01796     // NB. Must be after the user has clicked OK on print dialog, as we set up
01797     //     anti-aliasing etc. in PrintView constructor.
01798     if (pPrintView != NULL)
01799     {
01800         delete pPrintView;
01801         pPrintView = NULL;
01802         ERROR2(FALSE, "OnPreparePrinting(): we already have a PrintView!");
01803     }
01804 
01805     pPrintView = new PrintView(pDocView->GetDoc());
01806     if (pPrintView == NULL)
01807         ERROR2(FALSE, "Not enough memory to create PrintView object");
01808 
01809     if (!pPrintView->ConnectToOilView(this))
01810     {
01811         delete pPrintView;
01812         pPrintView = NULL;
01813         ERROR2(FALSE, "Unable to attach PrintView to CCamView.");
01814     }
01815 
01816 #endif
01817 
01818     // OK if we got this far.
01819     return TRUE;
01820 }
01821 
01822 #endif //EXCLUDE_FROM_XARALX
01823 
01825 // Menu functions
01826 
01827 
01828 
01829 /*********************************************************************************************
01830 >   void CCamView::OnFilePrintPreview()
01831 
01832     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01833     Created:    ages ago
01834     Inputs:     -
01835     Outputs:    -
01836     Returns:    -
01837     Purpose:    Simply makes CView::OnFilePrintPreview() have public scope.
01838                 Used by the menu system.
01839     Errors:     -
01840     Scope:      Public
01841     SeeAlso:    CView::OnFilePrintPreview(); CCamView::OnFilePrint()
01842 
01843 **********************************************************************************************/ 
01844 
01845 void CCamView::OnFilePrintPreview()
01846 {
01847     SetCurrentStates();
01848 
01849 //  CView::OnFilePrintPreview();
01850 }
01851 
01852 
01853 /*********************************************************************************************
01854 >   void CCamView::InvalidateView(const OilRect* pRect = NULL, BOOL updatenow = FALSE)
01855 
01856     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01857     Created:    ages ago
01858     Inputs:     A pointer to the client area rectangle, an OilRect, which is to be
01859                 invalidated (marked as needing to be redrawn).  This parameter may be
01860                 omitted.  If the first parameter is present, an optional second parameter
01861                 may be specified, which if TRUE tells Windows to immediately send a
01862                 WM_PAINT message to the view, which will force an instant redraw of any
01863                 invalid areas (normally Windows waits until all other messages have been
01864                 processed before sending the WM_PAINT message).
01865     Outputs:    -
01866     Returns:    -
01867     Purpose:    Invalidates the appropriate section of the RendWnd client area - if the
01868                 passed parameter is NULL then the whole client area is invalidated.  The
01869                 rectangle will be redrawn at some time in the (near) future.
01870     Errors:     -
01871     Scope:      Public
01872     SeeAlso:    class CRendWnd; CCamView::OnDraw()
01873 
01874 **********************************************************************************************/ 
01875 
01876 void CCamView::InvalidateView(const OilRect* pRect, BOOL updatenow)
01877 {
01878     if (pRect != NULL)
01879     {
01880         // Convert passed rectangle to an MFC-derived type and invalidate it.  Add an extra
01881         // pixel to the right and bottom edges of the rectangle to ensure that the whole
01882         // rectangle, after scaling and rounding, is invalidated.
01883         WinRect r = pRect->ToWin( pDocView );
01884 //      r.width++;
01885 //      r.height++;     
01886         GetRenderWindow()->Refresh( true, &r );
01887     }
01888     else
01889     {
01890         // We are completely redrawing the client area, so it is possible that the
01891         // "cached" previous scroll offsets, contained in OldOffset, will become
01892         // incorrect.
01893         GetRenderWindow()->Refresh( true );
01894         GetScrollOffset(&OldOffset);
01895     }
01896     
01897     if (updatenow) GetRenderWindow()->Update();
01898 }
01899 
01900 
01901 /*********************************************************************************************
01902 >   BOOL CCamView::StartDrag(Operation* pOp, DragType type, BOOL KeepAccuracy)
01903 
01904     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01905     Created:    ages ago
01906     Inputs:     A pointer to the current (drag) Operation; the type of the drag.
01907     Outputs:    -
01908     Returns:    Returns TRUE if successful.  Returns FALSE if a timer couldn't be allocated.
01909     Purpose:    Begins a drag operation, from the point of view of the OIL layer.  Unbounds
01910                 the mouse cursor, so it can go off-screen (display driver permitting).
01911                 Captures all mouse input, to guarantee that the drag being started will
01912                 terminate properly at some time in the future.  Sets some internal variables
01913                 indicating that ScreenView is in "drag mode".  Finally, asks the system for a
01914                 timer which is used to generate "idle" mouse events.
01915     Errors:     ASSERTion failure if the ScreenView is already dragging.
01916     Scope:      Public
01917     SeeAlso:    CCamView::EndDrag(); CCamView::HandleDragEvent();
01918                           
01919 **********************************************************************************************/ 
01920 
01921 BOOL CCamView::StartDrag(Operation* pOp, DragType type, BOOL KeepAccuracy)
01922 {
01923     ENSURE( pCurrentDragOp == 0, "CCamView::StartDrag: pCurrentDragOp is not zero");
01924     
01925     // This has been commented out as some screen drivers can not handle the mouse drifting
01926     // off the top of the screen.
01927     // Unbound mouse from the screen and set the current drag operation.  Note that under
01928     // Win32 raw mouse coordinates change from being 16-bit INTs to 16-bit SHORTs.
01929     //WinRect unbound(SHRT_MIN / 4, SHRT_MIN / 4, SHRT_MAX / 4, SHRT_MAX / 4);
01930     //::GetClipCursor(&MouseClipRect);
01931     //::ClipCursor(&unbound);
01932     GetRenderWindow()->CaptureMouse();
01933 
01934     // Remember what kind of drag we are performing.
01935     pCurrentDragOp = pOp;
01936     CurrentDragType = type;
01937     OLERecaptureMouse = FALSE;
01938     DragKeepAccuracy = KeepAccuracy;
01939     AutoScrollExcludeRulers = FALSE;
01940     m_OLELastOutTime.Sample();
01941     return TRUE;
01942 }
01943 
01944 
01945 
01946 /*********************************************************************************************
01947 >   BOOL CCamView::EndDrag(Operation* pOp)
01948 
01949     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01950     Created:    ages ago
01951     Inputs:     A pointer to the current drag operation (currently not used).
01952     Outputs:    -
01953     Returns:    TRUE if the drag is successfully terminated.
01954     Purpose:    Finishes a drag operation in the OIL layer.  Releases mouse capture and
01955                 restores the previous mouse cursor clipping rectangle (generally the screen).
01956                 Sets internal variables to indicate that ScreenView is not in "drag mode".
01957                 Kills the timer set in StartDrag().
01958     Errors:     ASSERTion failure if ScreenView was not already in "drag mode". 
01959     Scope:      Public
01960     SeeAlso:    CCamView::StartDrag(); CCamView::HandleDragEvent()
01961 
01962 **********************************************************************************************/ 
01963 
01964 BOOL CCamView::EndDrag(Operation*)
01965 {
01966 /*
01967 #ifdef  _DEBUG
01968     // Prevent a very nasty recursive ENSURE!
01969     if (!CCamApp::IsDisabled())
01970     {
01971         ENSURE(pCurrentDragOp != 0, "CCamView::EndDrag: pCurrentDragOp is zero");
01972     }
01973 #endif  // _DEBUG
01974 */
01975     // Restore the previous mouse clipping rectangle.  Windows will move the
01976     // mouse, if necessary, so that the mouse is within the new clipping
01977     // rectangle (or so the documentation says!)
01978     //::ClipCursor(&MouseClipRect);
01979     pCurrentDragOp = 0;
01980     FirstClickButton = 0;
01981     DragKeepAccuracy = TRUE;
01982     if (GetRenderWindow()->GetCapture() == RenderWindow)
01983         GetRenderWindow()->ReleaseMouse();
01984 
01985     // Check status of temporary tool selection - this is because we don't change tool
01986     // mid-drag! (e.g. user holds down Alt to get selector, starts drag, releases Alt,
01987     // then ends drag - we want to restore the original tool).
01988     Tool::EndDrag();
01989 
01990     // Kill the timer started in HandleDragEvent().
01991     m_DragIdleTimer.Stop();
01992     
01993     return TRUE;
01994 }
01995 
01996 /********************************************************************************************
01997 >   BOOL CCamView::GetCurrentMousePos(OilCoord* pMousePos) const
01998 
01999     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02000     Created:    12/10/94
02001     Inputs:     -
02002     Outputs:    pMousePos       the mouse position within this view, in OIL coordinates
02003     Returns:    TRUE if the mouse is within this view, and hence that *pMousePos holds
02004                 its position; FALSE if the mouse is outside the view (in which case
02005                 *pMousePos is unchanged).
02006     Purpose:    Finds out the current mouse position within this view window.
02007     Errors:     -
02008     SeeAlso:    -
02009 ********************************************************************************************/
02010 
02011 BOOL CCamView::GetCurrentMousePos(OilCoord* pMousePos) const
02012 {
02013     // Get the Windows screen coordinates of the mouse cursor.
02014     // Convert from screen to window coordinates.
02015     WinCoord pt;
02016     *(wxPoint *)&pt = GetRenderWindow()->ScreenToClient( ::wxGetMousePosition() );
02017 
02018     // If the mouse is outside the view then we can do nothing more.
02019     if (!CurrentSize.Inside(pt)) return FALSE;
02020 
02021     // Convert to OIL coordinates.
02022     if (pMousePos!=NULL)
02023         *pMousePos = pt.ToOil(pDocView, TRUE);
02024 
02025     // We stored something useful.
02026     return TRUE;
02027 }
02028 
02029 
02030 /*********************************************************************************************
02031 >   void CCamView::SetWorkAreaExtent(const WorkRect& area, BOOL redraw)
02032 
02033     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02034     Created:    ages ago
02035     Inputs:     A WorkRect describing the new WorkAreaExtent, a boolean which if TRUE
02036                 means immediately repaint the view window to reflect the change.
02037     Outputs:    -
02038     Returns:    -
02039     Purpose:    Calculates the size of the RendWnd, setting the "page size" of the
02040                 scroll bars accordingly.  Sets the scroll range of the scroll bars
02041                 to the size of the WorkAreaExtent (note that the Y range is negated
02042                 and inverted - the mother of all bodges).
02043     Errors:     -
02044     Scope:      Public
02045     SeeAlso:    CCamView::GetWorkAreaExtent(); CScroller::SetPageSize();
02046                 CScroller::SetScrollRange(); class CRendWnd
02047 
02048 **********************************************************************************************/ 
02049 
02050 void CCamView::SetWorkAreaExtent(const WorkRect& area, BOOL redraw)
02051 {
02052     WorkArea = area;
02053     FIXED16 PixelWidth, PixelHeight;
02054     pDocView->GetPixelSize(&PixelWidth,&PixelHeight);
02055     INT32 HScrRange = (INT32)(WorkArea.Width()/PixelWidth.MakeDouble());
02056     INT32 VScrRange = (INT32)(WorkArea.Height()/PixelHeight.MakeDouble());
02057     if (HScrollBar)
02058         HScrollBar->SetScrollbar(HScrollBar->GetThumbPosition(), CurrentSize.GetWidth(), HScrRange, CurrentSize.GetWidth(), true);
02059     if (VScrollBar)
02060         VScrollBar->SetScrollbar(VScrollBar->GetThumbPosition(), CurrentSize.GetHeight(), VScrRange, CurrentSize.GetHeight(), true);
02061 
02062     // Should really do something about the redraw param here
02063     // E.g. call the function that causes an immediate repaint of invalid areas
02064     // However, until I see some obvious sign that this is ever necessary I'll 
02065     // leave it commented out
02066 //  if (redraw)
02067 //  {
02068 //      if (RenderWindow)
02069 //          RenderWindow->Update();
02070 //  }
02071 }
02072 
02073 /*********************************************************************************************
02074 >   void CCamView::GetScrollOffset(WorkCoord* pOffset) const
02075 
02076     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02077     Created:    ages ago
02078     Inputs:     -
02079     Outputs:    The current scroll offset is written to the passed WorkCoord.
02080     Returns:    -
02081     Purpose:    Reads the offset from the horizontal and vertical scroll bars,
02082                 combining then into a WorkCoord.
02083     Errors:     -
02084     Scope:      Public
02085     SeeAlso:    CCamView::SetScrollOffset(); CScroller::GetScrollPos()
02086 
02087 **********************************************************************************************/ 
02088 
02089 void CCamView::GetScrollOffset(WorkCoord* pOffset) const
02090 {   
02091 //  TRACEUSER("Gerry", _T("CV::GetScrollOffset\n"));
02092 
02093     FIXED16 PixelWidth,PixelHeight;
02094     pDocView->GetPixelSize(&PixelWidth,&PixelHeight);
02095 
02096     INT32 HPos = HScrollBar->GetThumbPosition();
02097     INT32 VPos = VScrollBar->GetThumbPosition();
02098 
02099 //  TRACEUSER("Gerry", _T("CanvasPos = (%d, %d)\n"), HPos, VPos);
02100 
02101     pOffset->x = XLONG(WorkArea.lo.x + HPos*PixelWidth.MakeDouble());
02102     pOffset->y = XLONG(WorkArea.hi.y - VPos*PixelHeight.MakeDouble());
02103 
02104 //  TRACEUSER("Gerry", _T("ScrollOffset = (%d, %d)\n"), (INT32)(pOffset->x), (INT32)(pOffset->y));
02105 }
02106 
02107 
02108 
02109 /*********************************************************************************************
02110 >   void CCamView::SetScrollOffset(const WorkCoord& pos, BOOL redraw)
02111 
02112     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02113     Created:    ages ago
02114     Inputs:     The desired scroll offset, in WorkCoords, and a boolean indicating if
02115                 TRUE that the view window should be repainted immediately to reflect
02116                 the change in scroll position.
02117     Outputs:    -
02118     Returns:    -
02119     Purpose:    Changes the scroll offset in the horizontal and vertical scroll bar.  Note
02120                 that it DOES NOT immediately scroll the client area, which is only done
02121                 when the scroll bars send back a WM_SCROLLEREVENT message to the ScreenView.
02122     Errors:     -
02123     Scope:      Public
02124     SeeAlso:    CCamView::GetScrollOffset; CCamView::OnScrollerEvent()
02125 
02126 **********************************************************************************************/ 
02127 
02128 void CCamView::SetScrollOffset(const WorkCoord& pos, BOOL redraw)
02129 {
02130 //  TRACEUSER("Gerry", _T("CV::SetScrollOffset(%d, %d)\n"), (INT32)(pos.x), (INT32)(pos.y));
02131     FIXED16 PixelWidth,PixelHeight;
02132     pDocView->GetPixelSize(&PixelWidth,&PixelHeight);
02133 
02134     // Validate suggested ScrollOffset...
02135     WorkCoord tpos = pos;
02136     WorkRect wrScrollRect = GetMaxScrollRect();
02137     if (tpos.x < wrScrollRect.lo.x) tpos.x = wrScrollRect.lo.x;
02138     if (tpos.y < wrScrollRect.lo.y) tpos.y = wrScrollRect.lo.y;
02139     if (tpos.x > wrScrollRect.hi.x) tpos.x = wrScrollRect.hi.x;
02140     if (tpos.y > wrScrollRect.hi.y) tpos.y = wrScrollRect.hi.y;
02141 
02142     INT32 sx = INT32((tpos.x-WorkArea.lo.x)/PixelWidth .MakeDouble());
02143     INT32 sy = INT32((WorkArea.hi.y-tpos.y)/PixelHeight.MakeDouble());
02144 //  TRACEUSER("Gerry", _T("Scrolling to (%d, %d)\n"), sx, sy);
02145 
02146     HScrollBar->SetThumbPosition(sx);
02147     VScrollBar->SetThumbPosition(sy);
02148 
02149     SetCurrentStates();
02150     if (Status && fSetupDone)
02151     {
02152         WorkCoord temp;
02153         GetScrollOffset(&temp);
02154         Status->SetScrollPos(temp);
02155         if (redraw)
02156             ScrollTo(temp);
02157     }
02158 
02159     // Neville 22/8/97
02160     // Somebody is setting the scroll position so make sure that this is set
02161     // Other calls to OnScrollerEvent can be filtered out completely so that a document
02162     // can load in completely but not had one single call to ScrollTo code allowed. Everything
02163     // looks ok but if you scroll slightly then becuase the OldOffset is wrong, usually 0,0,
02164     // a large redraw problem can occur OR the whole drawing will be redrawn needlessly.
02165     // This is called by the document loading code and so when it says it wants this scroll position
02166     // it is generally late enough in the loading process that the 'Fixes bug #1448.' comment
02167     // should have been sorted.
02168     fSetupDone = TRUE;
02169 }
02170 
02171 
02172 /*********************************************************************************************
02173 >   virtual void CCamView::OnInitialUpdate()
02174 
02175     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02176     Created:    19 Jan 1994
02177     Inputs:     -
02178     Outputs:    -
02179     Returns:    -
02180     Purpose:    Called when the view must first display the document.  Moves this
02181                 view/frame to the position given in the ViewState object.
02182     Errors:     -
02183     Scope:      Protected
02184     SeeAlso:    CCamView::SetThisFromViewState; CCamView::SetViewStateFromThis;
02185                 DocView::ViewStateChanged
02186 **********************************************************************************************/ 
02187 
02188 void CCamView::OnUpdate(wxView* sender, wxObject* hint)
02189 {
02190     TRACEUSER("Gerry", _T("CCamView::OnUpdate\n"));
02191     if ( sender==NULL && !fInitialUpdate )
02192     {
02193         OnInitialUpdate();
02194         fInitialUpdate = TRUE;
02195     }
02196     wxView::OnUpdate(sender, hint);
02197 }
02198 
02199 
02200 //
02201 // OnIntialUpdate is no longer called automatically, so we call it instead
02202 // just once from OnUpdate.
02203 //
02204 void CCamView::OnInitialUpdate()
02205 {
02206     TRACEUSER("Gerry", _T("CCamView::OnInitialUpdate\n"));
02207     // Set up current etc.
02208     SetCurrentStates();
02209 
02210     // Check if this view is being created by LoadAppWindowState at the start.  If it is
02211     // then pick up the ViewState object ready-made by LoadAppWindowState and set
02212     // this view according to that.
02213     if (pReadyMadeViewState != NULL)
02214     {
02215         TRACEUSER("Gerry", _T("Got pReadyMadeViewState\n"));
02216 
02217         // Set the flags saved in temp. storage in the ViewState in the corresponding
02218         // DocView.
02219         DocView* pdv = GetDocViewPtr();
02220         ERROR3IF(pdv == NULL, "Null DocView* in CCamView::OnInitialUpdate");
02221 
02222         // Deallocate the old ViewState and set the new.
02223         delete SetViewState(pReadyMadeViewState);
02224 
02225         // Set these flags as well in the DocView.
02226         pdv->ViewFlags.GridShow        = pReadyMadeViewState->_GridShow;
02227         pdv->ViewFlags.GridSnap        = pReadyMadeViewState->_GridSnap;
02228         pdv->ViewFlags.ObjectsSnap     = pReadyMadeViewState->_ObjectsSnap;
02229         pdv->ViewFlags.MagObjectsSnap  = pReadyMadeViewState->_MagObjectsSnap;
02230         pdv->ViewFlags.PrintBorderShow = pReadyMadeViewState->_PrintBorderShow;
02231         pdv->ViewFlags.LogicalView     = pReadyMadeViewState->_LogicalView;
02232         pdv->ViewFlags.GuidesSnap      = pReadyMadeViewState->_GuidesSnap;
02233         pdv->ViewFlags.GuidesShow      = pReadyMadeViewState->_GuidesShow;
02234         
02235         // Make sure we set this view from the view-state, not the other way around.
02236         pReadyMadeViewState = NULL;
02237         Status->IsNewView = FALSE;
02238     }
02239 
02240     // Force the DocView to set the work area extent.
02241     pDocView->ViewStateChanged();
02242 
02243     if (HScrollBar)
02244     {
02245         // Calculate the scroller page & line sizes, and its range, and make sure the
02246         // work area extent is updated.
02247         INT32 Width = CurrentSize.GetWidth();
02248         HScrollBar->SetScrollbar(HScrollBar->GetThumbPosition(), Width, HScrollBar->GetRange(), Width);
02249     }
02250 
02251     if (VScrollBar)
02252     {
02253         INT32 Height = CurrentSize.GetHeight();
02254         VScrollBar->SetScrollbar(VScrollBar->GetThumbPosition(), Height, VScrollBar->GetRange(), Height);
02255     }
02256 
02257     // Either make this view conform to the ViewState, or update the ViewState with
02258     // information about this view, depending on whether the view is new or (re)loaded.
02259     if (Status->IsNewView)
02260     {
02261         SetViewStateFromThis();
02262         pDocView->OnNewView();          // give the DocView a shot
02263     }
02264     else
02265     {
02266         SetThisFromViewState();
02267         pDocView->OnLoadedView();       // let kernel have its say
02268     }
02269 
02270 PORTNOTE("other","CCamView::OnInitialUpdate - code removed")
02271 #ifndef EXCLUDE_FROM_XARALX
02272     // RALPH
02273     if (GetParentFrame())
02274     {
02275     #if (_OLE_VER >= 0x200)
02276         // In OLE builds only do this for non-embedded docs, as OnShowDocument will handle it
02277         // for embedded docs.
02278         if (!GetDocument()->IsServer())
02279     #endif
02280         {
02281             // Apply preferences.  To begin, maximise this view if it is the only one around.
02282             BOOL fAppIsIcon = GetMainFrame()->IsIconic();
02283             if (HowMany() == 1)
02284             {
02285                 // This flag is TRUE during workspace restoration of more than one doc.  We don't
02286                 // want to maximise any views if its TRUE.
02287                 extern BOOL fDontMaximiseViews;
02288                 if (ZoomSingleView && !fAppIsIcon && !fDontMaximiseViews)
02289                     ((CMDIChildWnd*) GetParentFrame())->MDIMaximize();
02290             }
02291             else
02292             {
02293                 // Otherwise, if a view is already maximised, un-maximise it so that this
02294                 // view is visible.
02295                 if (UnzoomOnNewView || fAppIsIcon)
02296                 {
02297                     // Find out the active view, which must be the one maximised, if any are.
02298                     BOOL fIsMaxed;
02299                     CMDIFrameWnd* pMainWnd = ((CMDIChildWnd*) GetParentFrame())->GetMDIFrame();
02300                     ENSURE(pMainWnd, "No MDI frame window in CCamView::OnShowWindow!");
02301                     CMDIChildWnd* pMaxiWnd = pMainWnd->MDIGetActive(&fIsMaxed);
02302 
02303                     // If it is maximised then restore it.
02304                     if (fIsMaxed && pMaxiWnd != NULL)
02305                     {
02306                         wxView* pv = pMaxiWnd->GetActiveView();
02307                         if (pv && pv->GetDocument() &&
02308                             ((CCamDoc*) pv->GetDocument())->IsUntouched())
02309                         {
02310                             TRACEUSER( "JustinF", _T("MDI Restore in CCamView::OnInitialUpdate\n"));
02311                             pMaxiWnd->MDIRestore();
02312                         }
02313                     }
02314                 }
02315             }
02316         }
02317     }
02318 #ifdef _DEBUG
02319     else
02320     {
02321         TRACEUSER( "JustinF", _T("\t- no parent frame in CCamView::OnInitialUpdate\n"));
02322     }
02323 #endif
02324 #endif
02325 
02326     // Make sure the render window gets repainted and inform the kernel that something
02327     // has happened.
02328     GetRenderWindow()->Refresh(false);
02329     pDocView->ViewStateChanged();
02330 
02331     // Indicate that we have set the position, size, focus etc so OnActivateView is safe
02332     // to update the HasFocus fields of ViewStates.
02333     fSetupDone = TRUE;
02334 
02335 #if (_OLE_VER >= 0x200)
02336 
02337     // Check if the document wants to zoom to the page.  This is the best place to
02338     // do this as everything should now be stable.
02339     LPCTSTR lpcszZoomOp = GetDocument()->GetInitialZoom();
02340     if (lpcszZoomOp)
02341     {
02342         // Remember the old prev. zoom setting.
02343         INT32 nPrev;
02344         FIXED16 fxPrev;
02345         WorkCoord wcPrev;
02346         nPrev  = pDocView->GetPrevZoomIndex();
02347         fxPrev = pDocView->GetPrevZoomScale();
02348         wcPrev = pDocView->GetPrevZoomOffset();
02349 
02350         // There is, so zoom it to show the new page bounds.  Set-up the kernel.
02351         DocView* pOldCurrent = DocView::GetCurrent();
02352         pDocView->SetCurrent();
02353 
02354         // Perform the Zoom-to-Page Operation (it's non-undo-able).
02355         OpDescriptor* pOp = OpDescriptor::FindOpDescriptor((LPTSTR) lpcszZoomOp);
02356         ERROR3IF(!pOp, "Can't find the Zoom Operation in CCamView::OnInitialUpdate");
02357         pOp->Invoke(0);
02358 
02359         // Restore the old prev. zoom setting.
02360         pDocView->SetPrevZoomIndex(nPrev);
02361         pDocView->SetPrevZoomScale(fxPrev);
02362         pDocView->SetPrevZoomOffset(wcPrev);
02363     }
02364 
02365 #endif 
02366 }
02367 
02368 
02369 
02370 /*********************************************************************************************
02371 >   void CCamView::OnActivateView(BOOL bActivate, wxView* pActiveView, wxView* pDeactiveView)
02372 
02373     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02374     Created:    ages ago
02375     Inputs:     A boolean which if TRUE means that this view is being activated, if FALSE
02376                 that this view is being deactivated; two pointers to the CView objects which
02377                 are being activated/deactivated. 
02378     Outputs:    Possibly changes the pointed-to views.
02379     Returns:    -
02380     Purpose:    Called by MFC when a view gains or loses the input focus, either due to the
02381                 the user clicking about, or another application popping up a window etc etc.
02382                 I would just like to point out that this MFC function is the most brain-damaged
02383                 Microsoft have come up so far.  It's documentation bears no resemblance to
02384                 the way the function is called/used - for example, as far as I can see, the
02385                 two CView* parameters are NEVER different!
02386     Errors:     -
02387     Scope:      Protected
02388     SeeAlso:    Pretty unique, this one, so I can't think of anything to put here.
02389 
02390 **********************************************************************************************/ 
02391 
02392 void CCamView::OnActivateView( bool bActivate, wxView* pActiveView, wxView* pDeactiveView )
02393 {
02394     TRACEUSER("Gerry", _T("CCamView::OnActivateView(%s) - 0x%08x\n"), bActivate ? _T("true") : _T("false"), this);
02395 
02396     if ( !pDocView )
02397     {
02398         TRACE( _T("CCamView::OnActivateView - Warning: pDocView is NULL\n") );
02399         return;
02400     }
02401 
02402     if (bActivate) SetCurrentStates();
02403 
02404     Document* KernelDoc = NULL; 
02405     if (pDocView) KernelDoc = pDocView->GetDoc();
02406 
02407     // MFC does some hidden stuff here . . .
02408     wxView::OnActivateView( bActivate, pActiveView, pDeactiveView );
02409 
02410     // Trigger off some messages into the kernel.
02411     if (bActivate)
02412     {
02413         // make sure the global preference reflects the current state
02414         SetDefaultRulersState(Status->RulersVisible);
02415         SetDefaultScrollersState(Status->ScrollersVisible);
02416         
02417         // Update our records of who is top-most and set the keyboard input focus to
02418         // the rendering child window.
02419         GetRenderWindow()->SetFocus();
02420 
02421         // Inform the kernel that the view's Z-order has changed. This sets the selected
02422         // View, Document, and spread, to legal values.
02423         Document::SetSelectedViewAndSpread(KernelDoc, pDocView, NULL);
02424     }
02425     else
02426     {
02427         TRACEUSER("Gerry", _T("Deactivating the view\n"));
02428 
02429         // Lets just try setting no selected for the time being but only if this view is the selected one
02430         if (DocView::GetSelected() == pDocView)
02431         {
02432             PORTNOTE("other", "CCamView::OnActivateView(false) now setting no selected doc and view")
02433             Document::SetNoSelectedViewAndSpread();
02434         }
02435         else
02436         {
02437             TRACEUSER("Gerry", _T("Not the selected view\n"));
02438         }
02439     }
02440 }
02441 
02442 
02443 /*********************************************************************************************
02444 >   void CCamView::SetViewStateFromThis() const
02445 
02446     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02447     Created:    ages ago
02448     Inputs:     -
02449     Outputs:    -
02450     Returns:    -
02451     Purpose:    Called by a virgin ScreenView, ie. a view onto a new, unedited
02452                 document.  The function reads the attributes of the view window
02453                 from the operating system, converts them into a device-
02454                 independent form, and stores them in the ViewState.
02455     Errors:     -
02456     Scope:      Private
02457     SeeAlso:    CCamView::OnInitialUpdate; CCamView::SetThisFromViewState();
02458                 DocView::ViewStateChanged(); class ViewState
02459 
02460 **********************************************************************************************/ 
02461 
02462 void CCamView::SetViewStateFromThis() const
02463 {
02464     TRACEUSER("Gerry", _T("SetViewStateFromThis\n"));
02465 
02466     // Set the current docview.
02467     pDocView->SetCurrent();
02468 
02469     // Set most of the ViewState according to the current state (the default) of this
02470     // ScreenView.
02471     UpdateViewPosition();
02472 
02473     // Make sure the scale factor is accurate.
02474     FIXED16 scale = pDocView->GetViewScale();
02475     if (scale != Status->ViewScale) Status->ViewScale = scale;
02476     
02477     // Record the current scroller position.
02478     WorkCoord temp;
02479     GetScrollOffset(&temp);
02480     Status->SetScrollPos(temp);
02481 
02482     if( NULL != GetParentFrame() )
02483     {
02484         // Record the top-most attribute of the frame window.
02485 PORTNOTE("other","Removed WM_TOPMOSTENQUIRY usage - is this really needed?")
02486 #ifndef EXCLUDE_FROM_XARALX
02487         Status->AlwaysOnTop = m_pFrame->SendMessage( WM_TOPMOSTENQUIRY );
02488 #endif
02489     }
02490 }
02491 
02492 
02493 
02494 
02495 /*********************************************************************************************
02496 >   void CCamView::SetThisFromViewState()
02497 
02498     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02499     Created:    ages ago
02500     Inputs:     -
02501     Outputs:    -
02502     Returns:    -
02503     Purpose:    Move and resize the ScreenView according to the (device-independent)
02504                 settings of a ViewState object.  This typically happens when a new
02505                 view is opened on a saved document.
02506     Errors:     -
02507     Scope:      Private
02508     SeeAlso:    CCamView::SetViewStateFromThis(); CCamView::OnInitialUpdate()
02509 
02510 **********************************************************************************************/ 
02511 
02512 void CCamView::SetThisFromViewState()
02513 {
02514     TRACEUSER("Gerry", _T("SetThisFromViewState\n"));
02515 
02516     PORTNOTE("other","CCamView::SetThisFromViewState - do nothing");
02517 #ifndef EXCLUDE_FROM_XARALX
02518     // Get a pointer to this view's frame window.
02519     wxMDIChildFrame    *pframewnd = (wxMDIChildFrame *)GetParentFrame();
02520     //ENSURE(pframewnd != NULL, "Found a ScreenView without a frame window?!?");
02521 
02522     // Fill in a Windows placement structure with some converted positions from the
02523     // ViewState object, and set the placement of the parent frame window accordingly.
02524     WINDOWPLACEMENT wp;
02525     wp.length = sizeof(wp);
02526     wp.flags = WPF_SETMINPOSITION;
02527     wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
02528 
02529     // Work out how to display the window, either as an icon, maximised, or just normal.
02530     // Note that it is possible for a maximised window to be iconised without being
02531     // restore first.
02532     if (Status->IsMinimised)
02533     {
02534         wp.showCmd = SW_SHOWMINIMIZED;              // display as an icon
02535         if (Status->IsMaximised)
02536         {
02537             wp.flags |= WPF_RESTORETOMAXIMIZED;     // go from icon to maximised
02538         }
02539     }
02540     else if (Status->IsMaximised)
02541     {
02542         wp.showCmd = SW_SHOWMAXIMIZED;              // display maximised
02543     }
02544     else
02545     {
02546         wp.showCmd = SW_SHOWNORMAL;                 // display normally
02547     }
02548 
02549     Coord2POINT(Status->IconPoint, &wp.ptMinPosition);
02550     Rect2RECT(Status->ViewRect, &wp.rcNormalPosition);
02551 
02552     //RALPH
02553     if(pframewnd)
02554         pframewnd->SetWindowPlacement(&wp);
02555 #endif
02556 
02557     // Needs to set the window position and size
02558 
02559     // Set the scroll offset.
02560     OldOffset = Status->GetScrollPos();
02561     SetScrollOffset(OldOffset);
02562 
02563     // Set the scale factor.
02564     pDocView->SetViewScale(Status->ViewScale);
02565 
02566     PORTNOTE("other","CCamView::SetThisFromViewState - do nothing");
02567 #ifndef EXCLUDE_FROM_XARALX
02568     // If the view was "always on top" then fake a user selection of the appropriate
02569     // menu option.
02570     // RALPH
02571     if (Status->AlwaysOnTop && GetParentFrame())
02572     {
02573         GetParentFrame()->PostMessage(WM_SYSCOMMAND, _R(IDM_ALWAYSONTOP));
02574     }
02575 #endif
02576 }
02577 
02578 
02579 /********************************************************************************************
02580 >   void CCamView::UpdateViewPosition() const
02581 
02582     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02583     Created:    12/4/94
02584     Inputs:     -
02585     Outputs:    -
02586     Returns:    -
02587     Purpose:    Updates the ViewState object shared between this ScreenView and its
02588                 associated DocView with the new size of the view etc.
02589     Errors:     -
02590     SeeAlso:    -
02591 ********************************************************************************************/
02592 
02593 void CCamView::UpdateViewPosition() const
02594 {
02595     TRACEUSER("Gerry", _T("CCamView::UpdateViewPosition\n"));
02596 
02597     ENSURE(Status != NULL, "No ViewState object in CCamView::UpdateViewPosition!");
02598 
02599     wxRect rc;
02600     wxFrame* pFrame = GetParentFrame();
02601     if(pFrame)
02602     {
02603         // Get the rectangle of the parent's MDICLIENT window.  All child window sizes and
02604         // positions are calculated as relative to this.  This is more accurate than just
02605         // taking the size of the main frame window as a whole, including menus, title bar etc.
02606         GetMainFrame()->GetClientSize( &rc.width, &rc.height );
02607         wxRect2Rect(rc, &Status->ParentRect);
02608     }
02609 
02610     if(pFrame)
02611         rc = pFrame->GetRect();
02612 
02613     // Fill in the ViewState with the position of the normal and iconised
02614     // window.  The maximised position of the window does not need to be
02615     // stored as it always fills the whole MDI client area of its parent.
02616     wxRect2Rect(rc, &Status->ViewRect);
02617 
02618     Status->IsMinimised = Status->IsMaximised = FALSE;
02619 
02620     PORTNOTE("other","CCamView::UpdateViewPosition - removed GetWindowPlacement");
02621 #ifndef EXCLUDE_FROM_XARALX
02622     ENSURE(Status != NULL, "No ViewState object in CCamView::UpdateViewPosition!");
02623 
02624     // Get the size of the screen.  We don't use this for anything, but I'm afraid to
02625     // take it out in case something breaks!
02626     // LH 31/08/2005 - Removed, if something breaks I'll revisit!
02627     wxRect              rc;
02628 //  GetDesktopWindow()->GetWindowRect( &rc );
02629 //  RECT2Rect(rc, &Status->ScreenRect);
02630 
02631     wxFrame            *pframewnd = GetParentFrame();
02632 
02633     if(pframewnd)
02634     {
02635         // Get the rectangle of the parent's MDICLIENT window.  All child window sizes and
02636         // positions are calculated as relative to this.  This is more accurate than just
02637         // taking the size of the main frame window as a whole, including menus, title bar etc.
02638         GetMainFrame()->GetClientSize( &rc.width, &rc.height );
02639         RECT2Rect(rc, &Status->ParentRect);
02640     }
02641 
02642     // Get the placement information for this view (MDI child) window.  Note
02643     // that because it is a child window, the position is taken relative to the
02644     // client area of its parent.
02645     WINDOWPLACEMENT wp;
02646     wp.length = sizeof(wp);
02647     
02648     
02649     //ENSURE(pframewnd != NULL, "Found a ScreenView without a frame window?!?");
02650     if(pframewnd)
02651         pframewnd->GetWindowPlacement(&wp);
02652 
02653     // Fill in the ViewState with the position of the normal and iconised
02654     // window.  The maximised position of the window does not need to be
02655     // stored as it always fills the whole MDI client area of its parent.
02656     RECT2Rect(wp.rcNormalPosition, &Status->ViewRect);
02657     POINT2Coord(wp.ptMinPosition, &Status->IconPoint);
02658 
02659     // Update the mini/maxi flags.  Note that it is possible for IsMinised and IsMaximised
02660     // to both be TRUE, if a maximised window has been iconised (but NOT if an iconised
02661     // window has been maximised!).
02662     if (wp.showCmd == SW_SHOWMINIMIZED)
02663     {
02664         Status->IsMinimised = TRUE;
02665     }
02666     else if (wp.showCmd == SW_SHOWMAXIMIZED)
02667     {
02668         Status->IsMinimised = FALSE;
02669         Status->IsMaximised = TRUE;
02670     }
02671     else // must be SW_SHOWNORMAL, ie. "restored"
02672     {
02673         Status->IsMinimised = Status->IsMaximised = FALSE;
02674     }
02675 #endif
02676 }
02677 
02678 
02679 /********************************************************************************************
02680 >   void CCamView::ShowScrollers(BOOL ShowOrHide)
02681 
02682     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
02683     Created:    2/11/94
02684     Inputs:     -
02685     Outputs:    -
02686     Returns:    -
02687     Purpose:    Hide or Show Scrollers.
02688     Errors:     -
02689     SeeAlso:    -
02690 ********************************************************************************************/
02691 
02692 void CCamView::ShowScrollers(BOOL Show)
02693 {
02694     // Set flags and Show/Hide the Scrollers
02695     bool bShow = Show ? true : false;
02696     VScrollBar->Show(bShow);
02697     HScrollBar->Show(bShow);
02698     Status->ScrollersVisible = Show;
02699 
02700     // call OnSize directly to force new layout 
02701     wxSize Size;
02702     m_pFrame->GetSize(&Size.x, &Size.y);
02703     TRACEUSER("Gerry", _T("Force an OnSize here (%d, %d)\n"), Size.x, Size.y);
02704 
02705     wxSizeEvent evSize(Size, 0);
02706     OnSize(evSize);
02707 }
02708 
02709 
02710 
02711 /********************************************************************************************
02712 >   void CCamView::ShowRulers(BOOL ShowOrHide)
02713 
02714     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
02715     Created:    2/11/94
02716     Inputs:     -
02717     Outputs:    -
02718     Returns:    -
02719     Purpose:    Hide or Show Rulers.
02720     Errors:     -
02721     SeeAlso:    -
02722 ********************************************************************************************/
02723 
02724 void CCamView::ShowRulers(BOOL Show) 
02725 {
02726 // WEBSTER - markn 15/1/97
02727 // No rulers in Webster
02728 #ifndef WEBSTER
02729 #if !defined(EXCLUDE_FROM_RALPH)
02730     if (!VRuler||!HRuler)
02731         return;
02732 
02733     // Set flags and Show/Hide the Rulers
02734     if (VRuler)
02735         VRuler->ShowRuler(Show);
02736 
02737     if (HRuler)
02738         HRuler->ShowRuler(Show);
02739 
02740     if (OGadget)
02741         OGadget->ShowGadget(Show);
02742 
02743     Status->RulersVisible = Show;
02744 
02745     // call OnSize directly to force new layout 
02746     wxSize Size=wxDefaultSize;
02747     m_pFrame->GetSize(&Size.x, &Size.y);
02748     wxSizeEvent evSize(Size, 0);
02749     OnSize(evSize);
02750 #endif
02751 #endif // WEBSTER
02752 }
02753 
02754 
02755 
02756 /*********************************************************************************************
02757 >   BOOL CCamView::AreRulersVisible()
02758 
02759     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 
02760     Created:    ages ago
02761     Inputs:     -
02762     Outputs:    -
02763     Returns:    Ruler Visible state.
02764     Purpose:    -
02765     Errors:     -
02766     Scope:      Public
02767 
02768 **********************************************************************************************/ 
02769 
02770 BOOL CCamView::AreRulersVisible()
02771 {
02772 #if !defined(EXCLUDE_FROM_RALPH)
02773     if(Status)
02774         return Status->RulersVisible;
02775 #endif
02776     return FALSE;       
02777 };
02778         
02779 /*********************************************************************************************
02780 >   BOOL CCamView::AreScrollersVisible()
02781 
02782     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 
02783     Created:    ages ago
02784     Inputs:     -
02785     Outputs:    -
02786     Returns:    Scroller Visible state.
02787     Purpose:    -
02788     Errors:     -
02789     Scope:      Public
02790 
02791 **********************************************************************************************/ 
02792 
02793 BOOL CCamView::AreScrollersVisible()
02794 { 
02795     if(Status)
02796         return Status->ScrollersVisible;
02797     return FALSE;       
02798 }
02799 
02800 
02801 /*********************************************************************************************
02802 >   BOOL CCamView::IsMouseOverRuler()
02803 
02804     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> 
02805     Created:    1/10/95
02806     Inputs:     -
02807     Outputs:    -
02808     Returns:    enum MouseOverRulerHit can be   OVER_NO_RULERS,
02809                                                 OVER_HORIZONTAL,
02810                                                 OVER_VERTICAL,
02811                                                 OVER_ORIGIN_GADGET.
02812     Purpose:    -
02813     Errors:     -
02814     Scope:      Public
02815 
02816 **********************************************************************************************/ 
02817 
02818 MouseOverRulerHit CCamView::IsMouseOverRuler()
02819 { 
02820 #if !defined(EXCLUDE_FROM_RALPH)
02821     // check that we have some rulers
02822     if (!HRuler||!VRuler||!OGadget)
02823         return OVER_NO_RULERS;
02824 
02825     // Find the window the pointer is over
02826     wxWindow* pWindow = ::wxChildWindowFromPoint(::wxGetMousePosition(), false, -1);
02827 
02828     // check the HWND against the rulers
02829     if (pWindow == (wxWindow*)HRuler)
02830         return OVER_HORIZONTAL;
02831     else if (pWindow == (wxWindow*)VRuler)
02832         return OVER_VERTICAL;
02833     else if (pWindow == (wxWindow*)OGadget)
02834         return OVER_ORIGIN_GADGET;
02835 #endif
02836 
02837     return OVER_NO_RULERS;      
02838  };
02839 
02840 
02841 
02842 
02843 /*********************************************************************************************
02844 >   afx_msg void CCamView::OnLButtonDown(UINT32 nFlags, wxPoint point)
02845 
02846     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02847     Created:    ages ago
02848     Inputs:     Flags describing which buttons & keys were down when the message was sent;
02849                 the coordinates of the mouse cursor.
02850     Outputs:    -
02851     Returns:    -
02852     Purpose:    Called by MFC upon receipt of a left-button-down mouse message.  Finds out
02853                 which other buttons are down (eg. SHIFT) and passes the message on to the kernel.
02854                 Note that the mouse message will have originally come from the RendWnd object, a
02855                 child window of ScreenView.
02856     Errors:     -
02857     Scope:      Protected
02858     SeeAlso:    class CRendWnd; CCamView::HandleDragEvent()
02859 
02860 **********************************************************************************************/ 
02861 
02862 void CCamView::OnLButtonDown( wxMouseEvent &event )
02863 {
02864     DontSkipNextMouse();
02865     // If the event is not from the RenderWindow then skip it
02866 //TRACEUSER("Phil", _T("OnLButtonDown\n"));
02867     INT32 nID = event.GetId();
02868     if (nID != WID_RENDERWINDOW)
02869     {
02870 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
02871         event.Skip();
02872         return;
02873     }
02874 
02875     wxPoint point = event.GetPosition();
02876     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags(event);
02877 
02878 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
02879 // WEBSTER - markn 25/4/97
02880 // No pen stuff required in Webster
02881 // Taken out by vector stroking code Neville 2/10/97
02882 #ifdef VECTOR_STROKING
02883     // Setup pressure if pen active
02884     (Camelot.GetPressurePen())->CheckMouseMessage(WM_LBUTTONDOWN, point);
02885 #endif // VECTOR_STROKING
02886 #endif
02887 
02888     // Support triple clicks
02889     wxRect ClickBounds( LastDoubleClickPos.x - LocalEnvironment::GetXMouseDoubleClickMove(),
02890                         LastDoubleClickPos.y - LocalEnvironment::GetYMouseDoubleClickMove(),
02891                         LocalEnvironment::GetXMouseDoubleClickMove() * 2,
02892                         LocalEnvironment::GetYMouseDoubleClickMove() * 2 );
02893     
02894     MonotonicTime ThisClickTime( event.GetTimestamp() );
02895     MonotonicTime ClickGap(LocalEnvironment::GetMouseDoubleClickDelay());
02896 
02897     // Is click within allowed movement rectangle and permitted time delay
02898     INT32 TimeDelay = (ThisClickTime - TimeOfLastClick);
02899     if( ClickBounds.Inside( point ) && ( TimeDelay <= (INT32)ClickGap ) )
02900         ThisSingleIsTriple = TRUE;
02901     else
02902         ThisSingleIsTriple = FALSE;
02903 
02904     // Deal with the click
02905     HandleDragEvent( MK_LBUTTON, nFlags, point, CLICKTYPE_SINGLE );
02906 
02907     TimeOfLastClick.Sample();
02908 }
02909 
02910 /*********************************************************************************************
02911 >   afx_msg void CCamView::OnMButtonDown(UINT32 nFlags, wxPoint point)
02912 
02913     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02914     Created:    ages ago
02915     Inputs:     Flags describing which buttons & keys were down when the message was sent;
02916                 the coordinates of the mouse cursor.
02917     Outputs:    -
02918     Returns:    -
02919     Purpose:    Called by MFC upon receipt of a middle-button-down mouse message.  Finds out
02920                 which other buttons are down (eg. SHIFT) and passes the message on to the kernel.
02921                 Note that the mouse message will have originally come from the RendWnd object, a
02922                 child window of ScreenView.
02923     Errors:     -
02924     Scope:      Protected
02925     SeeAlso:    class CRendWnd; CCamView::HandleDragEvent()
02926 
02927 **********************************************************************************************/ 
02928 
02929 void CCamView::OnMButtonDown( wxMouseEvent &event )
02930 {
02931     DontSkipNextMouse();
02932     // If the event is not from the RenderWindow then skip it
02933     INT32 nID = event.GetId();
02934     if (nID != WID_RENDERWINDOW)
02935     {
02936 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
02937         event.Skip();
02938         return;
02939     }
02940 
02941     wxPoint point = event.GetPosition();
02942     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags(event);
02943 
02944 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
02945 // WEBSTER - markn 25/4/97
02946 // No pen stuff required in Webster
02947 // Taken out by vector stroking code Neville 2/10/97
02948 #ifdef VECTOR_STROKING
02949     (Camelot.GetPressurePen())->CheckMouseMessage(WM_MBUTTONDOWN, point);
02950 #endif // VECTOR_STROKING
02951 #endif
02952     HandleDragEvent(MK_MBUTTON, nFlags, point, CLICKTYPE_SINGLE);
02953 }
02954 
02955 /*********************************************************************************************
02956 >   afx_msg void CCamView::OnRButtonDown(UINT32 nFlags, wxPoint point)
02957 
02958     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02959     Created:    ages ago
02960     Inputs:     Flags describing which buttons & keys were down when the message was sent;
02961                 the coordinates of the mouse cursor.
02962     Outputs:    -
02963     Returns:    -
02964     Purpose:    Same as for CCamView::OnLButtonDown(), but for the right mouse button.
02965     Errors:     -
02966     Scope:      Protected
02967     SeeAlso:    class CRendWnd; CCamView::HandleDragEvent(); CCamView::OnLButtonDown()
02968 
02969 **********************************************************************************************/ 
02970 
02971 void CCamView::OnRButtonDown( wxMouseEvent &event )
02972 {
02973     DontSkipNextMouse();
02974     // If the event is not from the RenderWindow then skip it
02975     INT32 nID = event.GetId();
02976     if (nID != WID_RENDERWINDOW)
02977     {
02978 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
02979         event.Skip();
02980         return;
02981     }
02982 
02983     wxPoint point = event.GetPosition();
02984     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags(event);
02985 
02986 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
02987 // WEBSTER - markn 25/4/97
02988 // No pen stuff required in Webster
02989 // Taken out by vector stroking code Neville 2/10/97
02990 #ifdef VECTOR_STROKING
02991     (Camelot.GetPressurePen())->CheckMouseMessage( WM_RBUTTONDOWN, event.GetPosition() );
02992 #endif // VECTOR_STROKING
02993 #endif
02994     HandleDragEvent(MK_RBUTTON, nFlags, point, CLICKTYPE_SINGLE);
02995 }
02996 
02997 
02998 /*********************************************************************************************
02999 >   afx_msg void CCamView::OnLButtonUp(UINT32 nFlags, wxPoint point)
03000 
03001     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03002     Created:    ages ago
03003     Inputs:     Flags describing which buttons & keys were down when the message was sent;
03004                 the coordinates of the mouse cursor
03005     Outputs:    -
03006     Returns:    -
03007     Purpose:    Passes the event on to HandleButtonUp()
03008     Errors:     -
03009     Scope:      Protected
03010     SeeAlso:    class CRendWnd; CCamView::OnLButtonDown(); CCamView::GetClickMods();
03011                 DocView::DragFinished(); CCamView::HandleButtonUp()
03012 
03013 **********************************************************************************************/ 
03014 
03015 void CCamView::OnLButtonUp(wxMouseEvent &event)
03016 {
03017     DontSkipNextMouse();
03018     // If the event is not from the RenderWindow then skip it
03019 //TRACEUSER("Phil", _T("OnLButtonUp\n"));
03020     INT32 nID = event.GetId();
03021     if (nID != WID_RENDERWINDOW)
03022     {
03023 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
03024         event.Skip();
03025         return;
03026     }
03027 
03028     HandleButtonUp(MK_LBUTTON, event);
03029 }
03030 
03031 
03032 
03033 
03034 /*********************************************************************************************
03035 >   afx_msg void CCamView::OnMButtonUp(UINT32 nFlags, wxPoint point)
03036 
03037     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03038     Created:    ages ago
03039     Inputs:     Flags describing which buttons & keys were down when the message was sent;
03040                 the coordinates of the mouse cursor.
03041     Outputs:    -
03042     Returns:    -
03043     Purpose:    Passes the event on to HandleButtonUp().
03044     Errors:     -
03045     Scope:      Protected
03046     SeeAlso:    class CRendWnd; CCamView::OnMButtonDown(); CCamView::GetClickMods();
03047                 DocView::DragFinished(); CCamView::HandleButtonUp()
03048 
03049 **********************************************************************************************/ 
03050 
03051 void CCamView::OnMButtonUp(wxMouseEvent &event)
03052 {
03053     DontSkipNextMouse();
03054     // If the event is not from the RenderWindow then skip it
03055     INT32 nID = event.GetId();
03056     if (nID != WID_RENDERWINDOW)
03057     {
03058 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
03059         event.Skip();
03060         return;
03061     }
03062 
03063     HandleButtonUp(MK_MBUTTON, event);
03064 }
03065 
03066 
03067 
03068 
03069 /*********************************************************************************************
03070 >   afx_msg void CCamView::OnRButtonUp(UINT32 nFlags, wxPoint point)
03071 
03072     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03073     Created:    ages ago
03074     Inputs:     Flags describing which buttons & keys were down when the message was sent;
03075                 the coordinates of the mouse cursor.
03076     Outputs:    -
03077     Returns:    -
03078     Purpose:    Same as CCamView::OnLButtonUp(), but for the right mouse button.
03079     Errors:     -
03080     Scope:      Protected
03081     SeeAlso:    class CRendWnd; CCamView::OnRButtonDown(); CCamView::GetClickMods();
03082                 DocView::DragFinished(); CCamView::HandleButtonUp()
03083 
03084 **********************************************************************************************/ 
03085 
03086 void CCamView::OnRButtonUp( wxMouseEvent &event )
03087 {   
03088     DontSkipNextMouse();
03089     // If the event is not from the RenderWindow then skip it
03090     INT32 nID = event.GetId();
03091     if (nID != WID_RENDERWINDOW)
03092     {
03093 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
03094         event.Skip();
03095         return;
03096     }
03097 
03098     HandleButtonUp(MK_RBUTTON, event);
03099 } 
03100 
03101 
03102 
03103 
03104 /*********************************************************************************************
03105 >   afx_msg void CCamView::OnLButtonDblClk(UINT32 nFlags, wxPoint point)
03106 
03107     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03108     Created:    ages ago
03109     Inputs:     Flags describing which buttons & keys were down when the message was sent;
03110                 the coordinates of the mouse cursor.
03111     Outputs:    -
03112     Returns:    -
03113     Purpose:    Passes a left-button double-click to CCamView::HandleDragEvent().
03114     Errors:     -
03115     Scope:      Protected
03116     SeeAlso:    class CRendWnd; CCamView::HandleDragEvent()
03117 
03118 **********************************************************************************************/ 
03119 
03120 void CCamView::OnLButtonDblClk(wxMouseEvent &event)
03121 {
03122     DontSkipNextMouse();
03123     // If the event is not from the RenderWindow then skip it
03124     INT32 nID = event.GetId();
03125     if (nID != WID_RENDERWINDOW)
03126     {
03127 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
03128         event.Skip();
03129         return;
03130     }
03131 
03132     wxPoint point = event.GetPosition();
03133     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags(event);
03134 
03135     // Support quad clicks
03136     wxRect ClickBounds( LastDoubleClickPos.x-LocalEnvironment::GetXMouseDoubleClickMove(),
03137                         LastDoubleClickPos.y-LocalEnvironment::GetYMouseDoubleClickMove(),
03138                         LastDoubleClickPos.x+LocalEnvironment::GetXMouseDoubleClickMove(),
03139                         LastDoubleClickPos.y+LocalEnvironment::GetYMouseDoubleClickMove());
03140     MonotonicTime ThisClickTime( event.GetTimestamp() );
03141     MonotonicTime ClickGap(LocalEnvironment::GetMouseDoubleClickDelay());
03142     // Is click within allowed movement rectangle and permitted time delay
03143     INT32 TimeDelay = (ThisClickTime - TimeOfLastClick);
03144     if (ClickBounds.Inside( point ) && (TimeDelay <= (INT32)ClickGap))
03145         ThisDoubleIsQuad = TRUE;
03146     else
03147         ThisDoubleIsQuad = FALSE;
03148 
03149     HandleDragEvent(MK_LBUTTON, nFlags, point, CLICKTYPE_DOUBLE);
03150 
03151     TimeOfLastClick.Sample();
03152     LastDoubleClickPos = point;
03153 }
03154 
03155 
03156 
03157 
03158 /*********************************************************************************************
03159 >   afx_msg void CCamView::OnMButtonDblClk(UINT32 nFlags, wxPoint point)
03160 
03161     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03162     Created:    ages ago
03163     Inputs:     Flags describing which buttons & keys were down when the message was sent;
03164                 the coordinates of the mouse cursor.
03165     Outputs:    -
03166     Returns:    -
03167     Purpose:    Passes a middle-button double-click to CCamView::HandleDragEvent().
03168     Errors:     -
03169     Scope:      Protected
03170     SeeAlso:    class CRendWnd; CCamView::HandleDragEvent()
03171 
03172 **********************************************************************************************/ 
03173 
03174 void CCamView::OnMButtonDblClk(wxMouseEvent &event)
03175 {
03176     DontSkipNextMouse();
03177     // If the event is not from the RenderWindow then skip it
03178     INT32 nID = event.GetId();
03179     if (nID != WID_RENDERWINDOW)
03180     {
03181 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
03182         event.Skip();
03183         return;
03184     }
03185 
03186     wxPoint point = event.GetPosition();
03187     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags(event);
03188 
03189     HandleDragEvent(MK_MBUTTON, nFlags, point, CLICKTYPE_DOUBLE);
03190 }
03191 
03192 
03193 
03194 
03195 /*********************************************************************************************
03196 >   afx_msg void CCamView::OnRButtonDblClk(UINT32 nFlags, wxPoint point)
03197 
03198     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03199     Created:    ages ago
03200     Inputs:     Flags describing which buttons & keys were down when the message was sent;
03201                 the coordinates of the mouse cursor
03202     Outputs:    -
03203     Returns:    -
03204     Purpose:    Same as CCamView::OnLButtonDblClk(), bit for the right button.
03205     Errors:     -
03206     Scope:      Protected
03207     SeeAlso:    class CRendWnd; CCamView::OnLButtonDblClk()
03208 
03209 **********************************************************************************************/ 
03210 
03211 void CCamView::OnRButtonDblClk( wxMouseEvent &event )
03212 {
03213     DontSkipNextMouse();
03214     // If the event is not from the RenderWindow then skip it
03215     INT32 nID = event.GetId();
03216     if (nID != WID_RENDERWINDOW)
03217     {
03218 //      TRACEUSER("Gerry", _T("Ignoring mouse event in window %d\n"), nID);
03219         event.Skip();
03220         return;
03221     }
03222 
03223     wxPoint point = event.GetPosition();
03224     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags(event);
03225 
03226     HandleDragEvent(MK_RBUTTON, nFlags, point, CLICKTYPE_DOUBLE);
03227 }
03228 
03229 
03230 /*********************************************************************************************
03231 >   afx_msg void CCamView::OnMouseWheel(UINT32 nFlags, short zDelta, wxPoint pt)
03232 
03233     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03234     Created:    25/10/2000
03235     Purpose:    
03236     Scope:      Protected
03237 
03238 **********************************************************************************************/ 
03239 
03240 void CCamView::OnMouseWheel( wxMouseEvent &event )
03241 {
03242     DontSkipNextMouse();
03243     HandleMouseWheelEvent( event );
03244 }
03245 
03246 /*********************************************************************************************
03247 >   afx_msg void CCamView::OnMouseMove(UINT32 nFlags, wxPoint point)
03248 
03249     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03250     Created:    ages ago
03251     Inputs:     Flags describing which buttons & keys were down when the message was sent;
03252                 the coordinates of the mouse cursor.
03253     Outputs:    -
03254     Returns:    -
03255     Purpose:    Packages up OIL-layer mouse-move messages before passing them on to
03256                 DocView::DragPointerMove().  If ScreenView is not in "drag mode" the event is
03257                 passed to our DocView, which will forward it to the current tool.  Otherwise,
03258                 checks if a CLICKTYPE_DRAG message has been sent to the kernel, sending one if
03259                 it hasn't (this smooths the difference between Windows and RISC OS, the former
03260                 system providing little support for drag operations).
03261     Errors:     -
03262     Scope:      Protected
03263     SeeAlso:    class CRendWnd; CCamView::HandleDragEvent(); DocView::DragPointerMove();
03264                 CCamView::GetClickMods(); CCamView::HandleDragScrolling();
03265                 DocView::OnMouseMove()
03266 **********************************************************************************************/ 
03267 
03268 void CCamView::OnMouseMove( wxMouseEvent &event )
03269 {
03270     // Ignore if system is disabled
03271     if (CCamApp::IsDisabled())
03272         return;                             // If the system is disabled, ignore
03273 
03274 //TRACEUSER("Phil", _T("OnMouseMove %d %d %x\n"), event.LeftIsDown(), event.ShiftDown(), pCurrentDragOp);
03275     wxPoint point = event.GetPosition();
03276     
03277     // Only respond to real mouse move messages
03278     if (point == CurrentMousePos)
03279         return;
03280 
03281     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags(event);
03282     
03283     // Ignore mouse moves if we're not the foreground window.
03284     if (pDocView != DocView::GetSelected())
03285     {
03286         return;
03287     }
03288 
03289     StatusLine* pStatusLine=NULL;
03290     // flag that the StatusLine's mouse position field needs updating
03291 #ifndef RALPH
03292 
03293     pStatusLine=GetApplication()->GetpStatusLine();
03294     if (pStatusLine)
03295         pStatusLine->FlagMousePosNeedsUpdating();
03296 #endif
03297 
03298     SetCurrentStates();
03299 
03300     wxMouseState WXCMS = ::wxGetMouseState();
03301     wxPoint CurrentMousePosition(WXCMS.GetX(), WXCMS.GetY());
03302     // Make a number representing the current button and control key state - we don't use this for anything
03303     // other than seeing whether it has changed
03304     INT32 CurrentMouseState =
03305         (WXCMS.LeftDown()   ?1:0) |
03306         (WXCMS.MiddleDown() ?2:0) |
03307         (WXCMS.RightDown()  ?4:0) |
03308         (WXCMS.ControlDown()?8:0) |
03309         (WXCMS.ShiftDown()  ?16:0) |
03310         (WXCMS.AltDown()    ?32:0) |
03311         (WXCMS.MetaDown()   ?64:0);
03312 #if 0
03313     TRACEUSER("amb", _T("CCamView:OnMouseMove XY (%d,%d) was (%d,%d) State %2x was %2x"),
03314         CurrentMousePosition.x,
03315         CurrentMousePosition.y,
03316         m_LastMousePosition.x,
03317         m_LastMousePosition.y,
03318         CurrentMouseState,
03319         m_LastMouseState);
03320 #endif
03321     INT32 CurrentTimestamp = event.GetTimestamp();
03322 
03323     BOOL SkipThis = FALSE;
03324     // wxWidgets compliant version of the PeekMessage code
03325     if (!DragKeepAccuracy && s_MouseMoveEliminationPeriod)
03326     {
03327         // What the windows version did was look ahead in the message queue for further
03328         // mouse moves. We don't have the luxury of that, so we do something slightly
03329         // different, which is that we look at where the mouse pointer has gone.
03330         // If it's moved, we know another mouse move event will be generated. So there
03331         // is the possibility of ignoring this one. We do this if the mouse BUTTON
03332         // state has not changed, the new mouse position is over the current window,
03333         // and some external event hasn't happened (normally a keypress)
03334 
03335         // If this isn't a motion event or the button state has changed, don't skip this
03336         // event, or the next pure move
03337         if ((event.GetEventType() != wxEVT_MOTION) || (CurrentMouseState != m_LastMouseState))
03338         {
03339             // Don't skip the next mouse event and don't skip this one
03340             m_CouldSkipNextMouse = FALSE;
03341         }
03342         else
03343         {
03344             m_CouldSkipNextMouse = TRUE; // next mouse move is a candidate for skipping
03345 
03346             // we know the buttons are in the same position as before (and the modifiers)
03347             // and this is solely a motion event - a candidate to be skipped
03348             if (m_CouldSkipNextMouse && (CurrentMousePosition != m_LastMousePosition) /*&& (CurrentMousePosition != event.GetPosition())*/)
03349             {
03350                 // OK, we know the mouse is moving. Insert a point every 20ms regardless
03351                 if ((CurrentTimestamp - m_LastMouseUsedTimestamp) < s_MouseMoveEliminationPeriod)
03352                 {
03353                     SkipThis = TRUE;
03354                 }
03355             }
03356         }
03357     }
03358     else
03359     {
03360         m_CouldSkipNextMouse = FALSE;
03361     }
03362 
03363     m_LastMouseState = CurrentMouseState;
03364     m_LastMousePosition = CurrentMousePosition;
03365 
03366     if (SkipThis)
03367     {
03368         return;
03369     }
03370 
03371     m_LastMouseUsedTimestamp = CurrentTimestamp;
03372 
03373 PORTNOTE("other","Remove PeekMessage related code")
03374 #ifndef EXCLUDE_FROM_XARALX
03375     // Only discard mouse move messages if the initiator of the drag has requested this.
03376     if (!DragKeepAccuracy)
03377     {
03378         // Due to problems with auto-repeat on modifier keys, we can lag a long way behind
03379         // with mouse messages, so we discard all except the most recent mouse move messages.
03380         // However we stop discarding mouse move messages if we come across any other mouse
03381         // messages such as button up/down events.
03382         MSG Msg;
03383         BOOL FoundMsg = FALSE;
03384 
03385         for(;;)
03386         {
03387             // We have to test that the window handles match because of a bug in PeekMessage (we 
03388             // get messages which aren't for the window we specified, strangely).
03389 
03390             if (::PeekMessage(&Msg, m_hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE) &&
03391                 (m_hWnd == Msg.hwnd) && 
03392                 (Msg.message == WM_MOUSEMOVE))
03393             {
03394                 // Found a mouse move message on the queue...
03395                 // Remember it then discard it.
03396                 nFlags = (UINT32) Msg.wParam;
03397 
03398                 // Have to cast to INT8 so we get correct sign-extension.
03399                 point.x = (INT8) LOWORD(Msg.lParam);
03400                 point.y = (INT8) HIWORD(Msg.lParam);
03401 
03402                 // Discard the message
03403                 PeekMessage(&Msg, m_hWnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE);
03404                 FoundMsg = TRUE;
03405             }
03406             else
03407             {
03408                 // Either: there are no messages, or it's not for our window, or it's a mouse
03409                 // event which is not a mouse *move* event - whatever it is, stop looking
03410                 // for mouse events.
03411                 break;
03412             }
03413         }
03414 
03415         // If we found any other mouse messages, use the data from the most recent one and
03416         // ignore the others.
03417         if (FoundMsg)
03418         {
03419             ENSURE(m_hWnd == Msg.hwnd, "Bad message in OnMouseMove");
03420             nFlags = (UINT32) Msg.wParam;
03421             point.x = (INT8) LOWORD(Msg.lParam);
03422             point.y = (INT8) HIWORD(Msg.lParam);
03423 
03424         
03425         }
03426     }
03427     
03428     // Slow mouse reponse due to key auto-repeat msgs?
03429     //
03430     // We could be experiencing delayed mouse move messages due to the message
03431     // queue getting flooded with key auto-repeat msgs.
03432     //
03433     // To overcome this, we remove all mouse move messages, keeping only the most 
03434     // recent msg's coords & flags.
03435     // 
03436     // Stripping the message cue in this way means we get less mouse moves to drag handlers, hence less accurate
03437     // mouse move data.  But, as we only do this if we get an auto-repeated key stroke, accuracy should not be
03438     // a problem, even for the freehand tool.  Freehand drags have two key modifiers (Alt for straught line and
03439     // Shift for rubbing out) that only require the latest mouse move event
03440 
03441     MSG Msg;
03442     // Has there been a key msg during the mouse move?
03443     if (::PeekMessage(&Msg, m_hWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE))
03444     {
03445         // Have a look at the key msg (use KeyPressSysMsg to turn the msg into a system-independant format)
03446         KeyPressSysMsg KeySysMsg(&Msg);
03447 
03448         // Is the key msg an auto-repeated key press (i.e. previously down)?
03449         if (KeySysMsg.IsValid() && KeySysMsg.PrevDown)
03450         {
03451             // Auto repeat key msg found, so get the latest mouse move msg
03452             // Note: We don't remove the msg from the queue, it may need to be processed elsewhere (e.g. button-ups)
03453             while (::PeekMessage(&Msg, m_hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE))
03454             {
03455                 // Is the mouse msg a mouse move msgs?
03456                 if (Msg.message == WM_MOUSEMOVE)
03457                 {
03458                     // Found a mouse move message on the queue so remember it 
03459                     nFlags = (UINT32) Msg.wParam;
03460 
03461                     // Have to cast to INT8 so we get correct sign-extension.
03462                     point.x = (INT8) LOWORD(Msg.lParam);
03463                     point.y = (INT8) HIWORD(Msg.lParam);
03464 
03465                     // Remove the mouse move msg, and get the next mouse msg in the queue
03466                     ::PeekMessage(&Msg, m_hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
03467                 }
03468                 else
03469                 {
03470                     // We have got a mouse msg that's not a mouse move msg, so break out of 'while' loop
03471                     // This could be a button-up msg, in which case we should stop looking for
03472                     // mouse moves as they may be irrelevent to the current drag
03473                     break;  
03474                 }
03475             }
03476         }
03477     }
03478 #endif
03479 
03480 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
03481 // WEBSTER - markn 25/4/97
03482 // No pen stuff required in Webster
03483 // Taken out by vector stroking code Neville 2/10/97
03484 #ifdef VECTOR_STROKING
03485 
03486     // Now check the Mouse Message to see if it has any pressure information
03487     (Camelot.GetPressurePen())->CheckMouseMessage(WM_MOUSEMOVE, point);
03488 #endif // VECTOR_STROKING
03489 #endif
03490 
03491     // Set the DocView (and Document)
03492 //  pDocView->SetCurrent();
03493 
03494 
03495     // Find out which buttons/keys are down.
03496     GetClickMods(event, &LastClickMods);
03497 
03498     // Are we dragging at the moment?
03499     if (pCurrentDragOp)
03500     {
03501         // Yes, but just check that the drag isn't "paused" while we do an OLE drag outside the window
03502         if (GetRenderWindow()->GetCapture() == GetRenderWindow())
03503         {
03504             // Check if we need to scroll this view.
03505             HandleDragScrolling(point);
03506 
03507             WinCoord wpoint(point.x, point.y);
03508             OilCoord CurDragOilPoint = wpoint.ToOil(pDocView, TRUE);
03509 //          TRACEUSER("Gerry", _T("DragMove (%d, %d)\n"), (INT32)CurDragOilPoint.x, (INT32)CurDragOilPoint.y);
03510             // Send an on-going drag event to the kernel.
03511             pDocView->DragPointerMove(pCurrentDragOp, CurDragOilPoint, LastClickMods);
03512         }
03513     }
03514     else
03515     {
03516         // We are not dragging at the moment, but are we about to start a drag?  If the
03517         // last mouse event was a single click, the same buttons are down, and the mouse
03518         // has either moved (3 or more), then a drag is beginning.
03519         INT32   dx  = point.x - LastClickPoint.x;
03520         INT32   dy  = point.y - LastClickPoint.y;
03521         INT32   dz2 = (dx * dx) + (dy * dy);
03522         if ((nFlags & FirstClickButton) && (dz2 >= (DragLatency * DragLatency)))
03523         {
03524             // Inform the kernel that a drag is starting.
03525             HandleDragEvent(FirstClickButton, nFlags, LastClickPoint, CLICKTYPE_DRAG);
03526         }
03527         else
03528         {
03529             WinCoord wpoint(point.x, point.y);
03530             // We are not dragging, just moving the mouse around, so pass the position 
03531             // of the mouse to the tool, giving it an opportunity to set the cursor etc.
03532             pDocView->OnMouseMove( wpoint.ToOil(pDocView, TRUE), LastClickMods);        
03533         }
03534     }
03535 
03536     // Remember the last position of the mouse passed on to the kernel.  The position
03537     // passed on any subsequent DragPointerIdle events must be the same as this!
03538     CurrentMousePos = point;
03539 
03540 #if !defined(EXCLUDE_FROM_RALPH)
03541     // if status line has not already been updated by someone calling CSnap::Snap(), call
03542     // CSnap::Snap(), snapping to grid only, to update status line (and ruler mouse followers)
03543     if (pStatusLine && pStatusLine->MousePosNeedsUpdating())
03544     {
03545         OilCoord OilPos=((WinCoord*)&point)->ToOil(pDocView, TRUE);
03546         DocCoord DocPos(0,0);
03547         Spread*  pSpread=pDocView->OilToSpreadCoord(OilPos,&DocPos);
03548         if (pSpread)
03549             pDocView->Snap(pSpread,&DocPos,TRUE,TRUE);
03550     }
03551 #endif
03552 }
03553 
03554 /*********************************************************************************************
03555 >   void CCamView::OnSetCursor(wxSetCursorEvent& event)
03556 
03557     Author:     Luke_Hart (Xara Group Ltd) <camelotdev@xara.com>
03558     Created:    08/02/06
03559     Inputs:     The event.
03560     Outputs:    -
03561     Returns:    -
03562     Purpose:    Eat the cursor update requests to stop anyone else playing with them, this is 
03563                 needed on MSW or the cursor reverts to the normal arrow.
03564     Errors:     -
03565     Scope:      Protected
03566     SeeAlso:    
03567 
03568 **********************************************************************************************/ 
03569 
03570 void CCamView::OnSetCursor( wxSetCursorEvent& event )
03571 {
03572 //  TRACEUSER("Gerry", _T("CCamView::OnSetCursor"));
03573 #if !defined(EXCLUDE_FROM_XARALX)
03574     // Child windows assume responsibility for setting their own cursor.
03575     if( event.GetEventObject() == RenderWindow )
03576     {
03577 #endif
03578         // Ignore if system is disabled
03579         if (CCamApp::IsDisabled())
03580             return;                         // If the system is disabled, ignore
03581 
03582         SetCurrentStates();
03583 
03584         Cursor* pCursor = NULL;
03585         
03586         if (IsTopmost() ||
03587             CursorStack::GIsActive(Cursor::Busy) ||
03588             CursorStack::GIsActive(Cursor::Progress))
03589         {
03590             // The view window is active, or the machine is busy on a slow task, so we must show
03591             // the cursor on the top of the cursor stack.
03592             pCursor = CursorStack::GetActive();
03593 //          TRACEUSER("Gerry", _T("Setting CursorStack::GetActive (0x%08x)"), pCursor);
03594         }
03595         else
03596         {
03597             // This view is overlapped and the machine isn't busy, so show a normal arrow cursor.
03598 //          TRACEUSER("Gerry", _T("Setting Cursor::Arrow"));
03599             pCursor = Cursor::Arrow;
03600         }
03601     
03602         if( NULL != pCursor )
03603         {
03604 //          TRACEUSER("Gerry", _T("Setting event cursor to 0x%08x"), pCursor->Handle());
03605             event.SetCursor( *(pCursor->Handle()) );
03606         }
03607 
03608 #if !defined(EXCLUDE_FROM_XARALX)
03609     }
03610     else
03611     if( event.GetEventObject() == Corner )
03612         Corner->OnSetCursor( event );
03613 #endif
03614 }
03615 
03616 
03617 /*********************************************************************************************
03618 >   void CCamView::OnScroll(wxSizeEvent &event)
03619 
03620     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03621     Created:    ages ago
03622     Inputs:     The wxScrollEvent object
03623     Outputs:    -
03624     Returns:    -
03625     Purpose:    Handles all the scroll events.
03626     Errors:     -
03627     SeeAlso:    
03628 
03629 
03630 **********************************************************************************************/ 
03631 
03632 void CCamView::OnScroll(wxScrollEvent &event)
03633 {
03634 //  TRACEUSER("Gerry", _T("CCamView::OnScroll  Orient = %d  Position = %d\n"), event.GetOrientation(), event.GetPosition());
03635 
03636     wxEventType Type = event.GetEventType();
03637 
03638 /*  if (Type == wxEVT_SCROLL_CHANGED)
03639     {
03640         TRACEUSER("Gerry", _T("wxEVT_SCROLL_CHANGED\n"));
03641         if (event.GetOrientation() == wxHORIZONTAL)
03642         {
03643             TRACEUSER("Gerry", _T("Horizontal = %d\n"), event.GetPosition());
03644         }
03645         else
03646         {
03647             TRACEUSER("Gerry", _T("Vertical = %d\n"), event.GetPosition());
03648         }
03649     }*/
03650 
03651     if (Type == wxEVT_SCROLL_LINEUP)
03652     {
03653 //      TRACEUSER("Gerry", _T("wxEVT_SCROLL_LINEUP\n"));
03654         CWinScroller* pBar = NULL;
03655         if (event.GetOrientation() == wxHORIZONTAL)
03656             pBar = HScrollBar;
03657         else
03658             pBar = VScrollBar;
03659         if (pBar)
03660             pBar->SetThumbPosition(pBar->GetThumbPosition() - 20);
03661     }
03662     else if (Type == wxEVT_SCROLL_LINEDOWN)
03663     {
03664 //      TRACEUSER("Gerry", _T("wxEVT_SCROLL_LINEDOWN\n"));
03665         CWinScroller* pBar = NULL;
03666         if (event.GetOrientation() == wxHORIZONTAL)
03667             pBar = HScrollBar;
03668         else
03669             pBar = VScrollBar;
03670         if (pBar)
03671             pBar->SetThumbPosition(pBar->GetThumbPosition() + 20);
03672     }
03673 
03674 //  TRACEUSER("Gerry", _T("Pos = (%d, %d)\n"), HPos, VPos);
03675     SetCurrentStates();
03676     if (Status && fSetupDone)
03677     {
03678         WorkCoord temp;
03679         GetScrollOffset(&temp);
03680         Status->SetScrollPos(temp);
03681         ScrollTo(temp);
03682     }
03683 }
03684 
03685 
03686 /*********************************************************************************************
03687 >   afx_msg void CCamView::OnSize(wxSizeEvent &event)
03688 
03689     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03690     Created:    ages ago
03691     Inputs:     A flag indicating whether the window is maximised, minimised
03692                 etc., the width and height of the ScreenView client area.
03693     Outputs:    -
03694     Returns:    -
03695     Purpose:    Resizes and repositions all child windows to fit the new size
03696                 of the ScreenView.  Updates the ViewState object with the
03697                 size and position of the view, in an OS-independent manner.
03698                 Resets the scroller's page and line size, and forces an
03699                 immediate redraw of all affected windows.
03700     Errors:     -
03701     Scope:      Protected
03702     SeeAlso:    CScroller::CalcPosFromParentClient(); CScroller::SetPageSize();
03703                 CScroller::SetLineSize(); class CRendWnd; class CScrollerCorner;
03704                 struct ViewState; DocView::ViewStateChanged()
03705 
03706 
03707 **********************************************************************************************/ 
03708 
03709 void CCamView::OnSize( wxSizeEvent &event )
03710 {
03711     TRACEUSER("Gerry", _T("CCamView::OnSize(%d, %d)\n"), event.m_size.x, event.m_size.y);
03712 
03713     // This is called early, so if pDocView is null do nothing
03714     if( NULL == pDocView )
03715         return;
03716 
03717     SetCurrentStates();
03718 
03719     Document* pCurDoc = Document::GetCurrent();
03720     DocView* pCurView = DocView::GetCurrent();
03721 
03722     wxSize NewSize( event.GetSize() );
03723 //  TRACEUSER("Gerry", _T("CCamView::OnSize Size = (%d, %d)\n"), NewSize.x, NewSize.y);
03724 
03725     wxRect ClientRect = m_pFrame->GetClientRect();
03726     wxRect RenderRect = ClientRect;
03727 
03728     // Check for irrelevant or potty messages.
03729     if (NewSize.x <= 0 || NewSize.y <= 0)
03730     {
03731         TRACE(_T("Bad size in CCamView::OnSize(%d, %d)\n"), NewSize.x, NewSize.y);
03732         return;
03733     }
03734 
03735     if (Status->RulersVisible)
03736     {
03737         // Get size of rulers and shove the left and top of the RenderRect in
03738         WinRect hRect, vRect, oRect;
03739 
03740         HRuler->CalcPosFromParentClient(&hRect);
03741         HRuler->SetSize(hRect);
03742         HRuler->PositionLegend();
03743         
03744         RenderRect.y += hRect.GetHeight();
03745         RenderRect.height -= hRect.GetHeight();
03746             
03747         VRuler->CalcPosFromParentClient(&vRect);
03748         VRuler->SetSize(vRect);
03749 
03750         RenderRect.x += vRect.GetWidth();
03751         RenderRect.width -= vRect.GetWidth();
03752 
03753         OGadget->CalcPosFromParentClient(&oRect);
03754         OGadget->SetSize(oRect);
03755     }
03756 
03757     if (Status->ScrollersVisible)
03758     {
03759         // Resize and reposition the proportional scrollers.
03760 
03761         wxSize HScrSize;
03762         HScrollBar->GetBestSize(&HScrSize.x, &HScrSize.y);
03763 //      TRACEUSER("Gerry", _T("HScroll BestSize = (%d, %d)\n"), HScrSize.x, HScrSize.y);
03764         wxSize VScrSize;
03765         VScrollBar->GetBestSize(&VScrSize.x, &VScrSize.y);
03766 //      TRACEUSER("Gerry", _T("VScroll BestSize = (%d, %d)\n"), VScrSize.x, VScrSize.y);
03767 
03768         wxRect HScrRect(RenderRect.x, ClientRect.height - HScrSize.y, RenderRect.width - VScrSize.x, HScrSize.y);
03769 //      TRACEUSER("Gerry", _T("HScrRect = (%d, %d) [%d, %d]\n"), HScrRect.x, HScrRect.y, HScrRect.width, HScrRect.height);
03770         HScrollBar->SetSize(HScrRect);
03771 
03772         wxRect VScrRect(ClientRect.width - VScrSize.x, RenderRect.y, VScrSize.x, RenderRect.height - HScrSize.y);
03773 //      TRACEUSER("Gerry", _T("VScrRect = (%d, %d) [%d, %d]\n"), VScrRect.x, VScrRect.y, VScrRect.width, VScrRect.height);
03774         VScrollBar->SetSize(VScrRect);
03775 
03776         // Reposition the corner window at the bottom-right.
03777         wxRect CornerRect(VScrRect.x, HScrRect.y, VScrRect.width, HScrRect.height);
03778 //      Corner->SetSize(CornerRect);
03779 
03780         // Adjust the RenderRect to account for the scroll bars
03781         RenderRect.width -= VScrSize.x;
03782         RenderRect.height -= HScrSize.y;
03783         ScrollBarSize = max(VScrSize.x, HScrSize.y);
03784     }
03785 
03786     wxRect OldRect = RenderWindow->GetRect();
03787 //  TRACEUSER("Gerry", _T("OldRect = (%d, %d) [%d, %d]\n"), OldRect.x, OldRect.y, OldRect.width, OldRect.height);
03788 
03789     // Resize/reposition the rendering window.
03790     CurrentSize = RenderRect;
03791 //  TRACEUSER("Gerry", _T("RenderRect = (%d, %d) [%d, %d]\n"), RenderRect.x, RenderRect.y, RenderRect.width, RenderRect.height);
03792     RenderWindow->SetSize(RenderRect);
03793 
03794     // Update the rest of the window placement information.
03795     UpdateViewPosition();
03796 
03797     // Calculate the work area, page & line sizes etc etc.
03798 //  FIXED16 PixelWidth, PixelHeight;
03799 //  pDocView->GetPixelSize(&PixelWidth, &PixelHeight);
03800 
03801 //  XLONG x1 = CurrentSize.GetWidth() * PixelWidth;
03802 //  XLONG x2 = CurrentSize.GetHeight() * PixelHeight;
03803 //  HScrollBar->SetPageSize(x1);
03804 //  VScrollBar->SetPageSize(x2);
03805 //  HScrollBar->SetLineSize(x1 / xlong(10) + xlong(1)); 
03806 //  VScrollBar->SetLineSize(x2 / xlong(10) + xlong(1));
03807 
03808     SetWorkAreaExtent(Status->WorkAreaExtent, FALSE);
03809 
03810     // Make sure the scroll offsets are valid - if we resize the bottom of the window
03811     // when at the extreme bottom of the view, then the scroll offsets should be
03812     // changed - we use the scrollers' own integrity checks to do this automatically.
03813     // Don't do this until the setup flag is TRUE, so we don't overwrite scroll offsets
03814     // that have been reloaded.
03815     if (fSetupDone)
03816     {
03817         TRACEUSER("Gerry", _T("fSetupDone so setting scroll offsets\n"));
03818         WorkCoord CurrScrollPos;
03819         GetScrollOffset(&CurrScrollPos);
03820         SetScrollOffset(CurrScrollPos, TRUE);
03821     }
03822 
03823     // Inform the associated DocView object that something has happened.
03824     pDocView->ViewStateChanged();
03825     pCurDoc->SetCurrent();
03826     pCurView->SetCurrent();
03827 }
03828 
03829 
03830 /*********************************************************************************************
03831 >   void CCamView::OnDragIdle(wxTimerEvent& event)
03832 
03833     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03834     Created:    ages ago
03835     Inputs:     The elapsed timer's numeric identifier (not used).
03836     Outputs:    -
03837     Returns:    -
03838     Purpose:    Sends DragPointerIdle "events" to the kernel, when dragging.  As Windows
03839                 doesn't support such "idle" messages, the OIL drag system sets up a timer
03840                 when a drag starts, and sends idle messages every time the timer elapses,
03841                 until the drag is finished.
03842     Errors:     -
03843     Scope:      Protected
03844     SeeAlso:    CCamView::HandleDragEvent(); DocView::DragPointerMove();
03845                 CCamView::GetClickMods();
03846 
03847 **********************************************************************************************/ 
03848 
03849 void CCamView::OnDragIdle(wxTimerEvent& event)
03850 {
03851     DontSkipNextMouse();
03852     // Ignore if system is disabled
03853     if (CCamApp::IsDisabled())
03854         return;                             // If the system is disabled, ignore
03855 
03856     // This window should never get a timer event that does not occur between calls to
03857     // StartDrag() and EndDrag().
03858 //  ENSURE(pCurrentDragOp != 0, "CCamView::StartDrag: pCurrentDragOp is null");
03859 
03860     // Find out which keys/buttons are being held down at the moment.  The mouse buttons
03861     // are more difficult, as they may have been swapped.
03862     UINT32 nFlags = ClickModifiers::SynthesizeMouseEventFlags();
03863 
03864     SetCurrentStates();
03865 
03866     if (pCurrentDragOp == NULL)
03867     {
03868         // We are not dragging at the moment, so check for a time-out condition to 
03869         // start a drag:
03870         // If a mouse button is down, and the timer has expired, then start a drag.
03871         if (LastClickType!=CLICKTYPE_NONE
03872             && (nFlags & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
03873             && DragTimer.Elapsed(DragDelay)
03874             && GetCurrentMousePos(NULL)
03875             )
03876         {
03877             // Inform the kernel that a drag is starting.
03878             HandleDragEvent(FirstClickButton, nFlags, LastClickPoint, CLICKTYPE_DRAG);
03879         }
03880     }
03881     else
03882     {
03883         // If we're doing an OLE drag and drop operation, then our DragOperation is still
03884         // active, but we have lost the Mouse Capture, so we should not update anything.
03885         // If the user drags back into our view window, the OLE drag will be shut down
03886         // and we will be given back our mouse capture so we can continue as if nothing
03887         // had happened. This just stops us scrolling while the OLE system is in charge!
03888         if (GetRenderWindow()->GetCapture() == GetRenderWindow())
03889         {
03890             WorkCoord OldScrollOffset;
03891             GetScrollOffset(&OldScrollOffset);
03892 
03893             // Check if we need to scroll the screen . . .
03894             HandleDragScrolling(CurrentMousePos);
03895 
03896             // We need to know if we have scrolled
03897             WorkCoord NewScrollOffset;
03898             GetScrollOffset(&NewScrollOffset);
03899             BOOL bScrolled = (NewScrollOffset.x != OldScrollOffset.x) || (NewScrollOffset.y != OldScrollOffset.y);
03900 
03901             // The above call may have aborted the current DragOp, so we must check if it is NULL
03902             if (pCurrentDragOp != NULL)
03903             {
03904                 // Now "fake" a mouse event for the kernel . . .
03905                 LastClickMods = ClickModifiers::GetClickModifiers(nFlags);
03906                 OilCoord CurDragOilPoint = ((WinCoord*)&CurrentMousePos)->ToOil(pDocView, TRUE);
03907                 if (bScrolled)
03908                 {
03909 //                  TRACEUSER("Gerry", _T("DragMove (%d, %d)\n"), (INT32)CurDragOilPoint.x, (INT32)CurDragOilPoint.y);
03910                     pDocView->DragPointerMove(pCurrentDragOp, CurDragOilPoint, LastClickMods);
03911                 }
03912                 else
03913                 {
03914 //                  TRACEUSER("Gerry", _T("DragIdle (%d, %d)\n"), (INT32)CurDragOilPoint.x, (INT32)CurDragOilPoint.y);
03915                     pDocView->DragPointerIdle(pCurrentDragOp, CurDragOilPoint, LastClickMods);
03916                 }
03917             }
03918         }
03919         else
03920         {
03921             // We don't own the capture - but if the user was OLE dragging and has dragged back into our
03922             // view window, then the OLE drag will have been cancelled, and we need to recapture the
03923             // mouse so that we can continue processing the drag as if nothing happened. Our OLE DropSource
03924             // will set our OLERecaptureMouse flag if it cancels itself and wishes us to continue...
03925             if (OLERecaptureMouse)
03926             {
03927                 GetRenderWindow()->CaptureMouse();
03928                 OLERecaptureMouse = FALSE;      // Only capture it back once!
03929             }
03930         }
03931     }
03932 }
03933 
03934 /*********************************************************************************************
03935 >   void CCamView::ScrollTo(const WorkCoord& offset)
03936 
03937     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
03938     Created:    ages ago
03939     Inputs:     The position, in WorkCoords, that the top-left corner of the view is to
03940                 move to.
03941     Outputs:    -
03942     Returns:    -
03943     Purpose:    Scroll the client area of the window to the specified position.  The offset
03944                 must be converted to OS coordinates before being passed to Windows.  If the
03945                 new position of the view does not overlap the old position then the client
03946                 area is completely redrawn.  Otherwise, the Windows USER module is called
03947                 to scroll the window.
03948     Errors:     -
03949     Scope:      Private
03950     SeeAlso:    CCamView::SetScrollPos()
03951 
03952 **********************************************************************************************/ 
03953 
03954 void CCamView::ScrollTo(const WorkCoord& offset)
03955 {
03956 //  TRACEUSER("Gerry", _T("CCamView::ScrollTo(%d, %d)\n"), (INT32)offset.x, (INT32)offset.y);
03957     // Calculate the difference between where we are and where we want to be.  Notice
03958     // the asymmetry in the calculations, to account for the Windows coordinate origin
03959     // being in the top-left, not the bottom-left.
03960     FIXED16 PixelWidth, PixelHeight;
03961     pDocView->GetPixelSize(&PixelWidth, &PixelHeight);
03962     INT32 dx = ((offset.x - OldOffset.x) / PixelWidth.MakeLong() );
03963     INT32 dy = ((OldOffset.y - offset.y) / PixelHeight.MakeLong() );
03964     if (dx == 0 && dy == 0)
03965     {
03966 //      TRACEUSER("Gerry", _T("No change\n"));
03967         return;
03968     }
03969     
03970     // Scroll part of, or redraw the whole of, the client area.
03971     if (Abs(dx) >= CurrentSize.GetRight() || Abs(dy) >= CurrentSize.GetBottom() )
03972     {
03973 //      TRACEUSER("Gerry", _T("Full refresh\n"));
03974         GetRenderWindow()->Refresh(true);
03975     }
03976     else
03977     {
03978 //      TRACEUSER("Gerry", _T("ScrollWindow(%d, %d)\n"), -dx, -dy);
03979         GetRenderWindow()->ScrollWindow(-dx, -dy);
03980     }
03981     
03982 #if !defined(EXCLUDE_FROM_RALPH)
03983     if (Status->RulersVisible)
03984     {
03985         if(HRuler)
03986             HRuler->ScrollRuler(-dx);
03987         if(VRuler)
03988             VRuler->ScrollRuler(-dy);
03989 
03990     }
03991 #endif
03992 
03993     // Remember this scroll offset, which corresponds to what will be drawn on the screen,
03994     // and force an immediate repaint of the invalid area.
03995     OldOffset = offset;
03996     GetRenderWindow()->Update();
03997 //  TRACEUSER("Gerry", _T("Done update\n"));
03998 
03999 #if !defined(EXCLUDE_FROM_RALPH)    // && !defined(EXCLUDE_FROM_XARALX)
04000     // Make sure that the system will update the state of gadgets after this, some of
04001     // which may now be "greyed" because what they apply to is no longer visible etc.
04002     // This is the best place to put this, as all scroll requests, whether they come
04003     // from the user or are internally generated, go through this function.
04004     DialogBarOp::SetSystemStateChanged(TRUE);
04005 #endif
04006 }
04007 
04008 
04009 
04010 /********************************************************************************************
04011 >   static void CCamView::wxPoint2Coord(const wxPoint& point, Coord* pcoord)
04012 
04013     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04014     Created:    7/4/94
04015     Inputs:     -
04016     Outputs:    -
04017     Returns:    -
04018     Purpose:    Converts a wxPoint to a kernel Coord.
04019     Errors:     -
04020     SeeAlso:    -
04021 ********************************************************************************************/
04022 
04023 void CCamView::wxPoint2Coord(const wxPoint& point, Coord* pcoord)
04024 {
04025     pcoord->x = point.x;
04026     pcoord->y = point.y;
04027 }
04028 
04029 
04030 
04031 /********************************************************************************************
04032 >   static void CCamView::Coord2wxPoint(const Coord& coord, wxPoint* ppoint)
04033 
04034     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04035     Created:    7/4/94
04036     Inputs:     -
04037     Outputs:    -
04038     Returns:    -
04039     Purpose:    Converts a kernel Coord to a wxPoint.
04040     Errors:     -
04041     SeeAlso:    -
04042 ********************************************************************************************/
04043 
04044 void CCamView::Coord2wxPoint(const Coord& coord, wxPoint* ppoint)
04045 {
04046     ppoint->x = (INT32) coord.x;
04047     ppoint->y = (INT32) coord.y;
04048 }
04049 
04050 
04051 
04052 /********************************************************************************************
04053 >   static void CCamView::wxRect2Rect(const wxRect& rect, Rect* pkrect)
04054 
04055     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04056     Created:    7/4/94
04057     Inputs:     -
04058     Outputs:    -
04059     Returns:    -
04060     Purpose:    Converts a wxRect into a kernel Rect.
04061     Errors:     -
04062     SeeAlso:    -
04063 ********************************************************************************************/
04064 
04065 void CCamView::wxRect2Rect(const wxRect& rect, Rect* pkrect)
04066 {
04067     pkrect->lo.x = rect.GetLeft();
04068     pkrect->lo.y = rect.GetTop();
04069     pkrect->hi.x = rect.GetLeft() + rect.GetWidth();
04070     pkrect->hi.y = rect.GetTop() + rect.GetHeight();
04071 }
04072 
04073 
04074 /********************************************************************************************
04075 >   static void CCamView::Rect2wxRect(const Rect& krect, wxRect* prect)
04076 
04077     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04078     Created:    7/4/94
04079     Inputs:     -
04080     Outputs:    -
04081     Returns:    -
04082     Purpose:    Converts a kernel Rect into a wxRect.
04083     Errors:     -
04084     SeeAlso:    -
04085 ********************************************************************************************/
04086 
04087 void CCamView::Rect2wxRect(const Rect& krect, wxRect* prect)
04088 {
04089     prect->x = (INT32) krect.lo.x;
04090     prect->y = (INT32) krect.lo.y;
04091     prect->width = (INT32) krect.Width();
04092     prect->height = (INT32) krect.Height();
04093 }
04094 
04095 
04096 
04097 /********************************************************************************************
04098 >   void CCamView::HandleDragEvent(UINT32 Button, UINT32 nFlags, wxPoint point, ClickType t) const
04099 >   void CCamView::HandleDragEvent(UINT32 Button, ClickModifiers clickmods, wxPoint point, ClickType t)
04100 
04101     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04102     Created:    ages ago
04103     Inputs:     Button - the actual button being pressed for a click/double click event.
04104                 nFlags - The mouse button flags
04105                 clickmods - The kernel abstraction of the modifiers
04106                 point - the coordinate of the mouse cursor
04107                 t -  the kind of mouse event (button up/down, move, drag start/finish etc.)
04108     Outputs:    -
04109     Returns:    -
04110     Purpose:    Gathers together Windows information about a mouse event and passes it on to
04111                 the kernel, by calling DocView::OnClick()
04112                 HandleDragEvent needs to be called from OnTimer code so rather than 
04113                 synthesizing a wxMouseEvent object this function has been left taking 
04114                 non-wx params
04115     Errors:     -
04116     Scope:      Private
04117     SeeAlso:    CCamView::GetClickMods(); CCamView::OnLButtonDown(); CCamView::OnRButtonDown()
04118                 DocView::OnClick()
04119 
04120 ********************************************************************************************/ 
04121 
04122 /********************************************************************************************
04123 
04124 Technical notes (by Tim):
04125 
04126 The Button is parameter is necessary, because sometimes when we get the *first* button
04127 down event, nFlags has more than one mouse button bit set.  This only happens when you
04128 rampantly click buttons very quickly but nevertheless we *do* need to know which button
04129 was pressed, otherwise we never release the drag event and we end up with button-up-drag
04130 city.
04131 
04132 I assume this is due to some latency in Windows, e.g., it gets a button down event, and
04133 while preparing it goes and reads the mouse button state and meanwhile another button has
04134 been pressed so we get a button down event with nFlags indicating more than one button
04135 is down.
04136 
04137 ********************************************************************************************/ 
04138 
04139 void CCamView::HandleDragEvent(UINT32 Button, UINT32 nFlags, wxPoint point, ClickType t)
04140 {
04141     // Find out which buttons etc are down.
04142     ClickModifiers clickmods = ClickModifiers::GetClickModifiers(nFlags);
04143 
04144     HandleDragEvent(Button, clickmods, point, t);
04145 }
04146 
04147 void CCamView::HandleDragEvent(UINT32 Button, ClickModifiers clickmods, wxPoint point, ClickType t)
04148 {
04149     if (DocView::GetSelected() != pDocView)
04150     {
04151 //      TRACEUSER( "JustinF", _T("Ignored drag-event cos not in the selected view\n"));
04152         // If selected doc is null, let's select it anyway.
04153         if (DocView::GetSelected() == NULL)
04154         {
04155             // We're in a weird state that should never happen but does - a document
04156             // has the focus, but isn't selected
04157             Document* pKDoc =NULL;
04158             if(pDocView)
04159                 pKDoc = pDocView->GetDoc();
04160 
04161             if (pKDoc)
04162             {
04163                 Document::SetSelectedViewAndSpread(pKDoc, pDocView, NULL);
04164             }
04165             
04166         }
04167         return; 
04168     }
04169 
04170     SetCurrentStates();
04171 
04172     // Find out which buttons etc are down.
04173     LastClickMods = clickmods;
04174 
04175     // If it's the first single click, then reset the drag delay timer, and ask for a 
04176     // Windows timer.
04177     if (((t == CLICKTYPE_SINGLE) || (t == CLICKTYPE_DOUBLE)) && 
04178         (FirstClickButton == 0))
04179     {
04180         // Remember this event.
04181         LastClickPoint = point;
04182         LastClickType = t;
04183         LastClickButton = Button;
04184         FirstClickButton = Button;
04185         DragTimer.Sample();
04186 
04187 #if (_OLE_VER >= 0x200)
04188         // The user's doing something so don't update any container docs
04189         CCamDoc::ResetContainerUpdateTimer();
04190 #endif
04191 
04192         // Ask the system for a timer.
04193         // The timer is used to generate DragPointerIdle events, which are not directly
04194         // supported by Windows.
04195         UINT32 rate = 100;
04196 PORTNOTE("other","Removed reading of keyboard autorepeat rate")
04197 #ifndef EXCLUDE_FROM_XARALX
04198         ::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &rate, 0);
04199 #endif
04200 
04201         m_DragIdleTimer.Start(rate);
04202     }
04203 
04204     if (DragOpInvoke)
04205     {
04206         OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(DragOpToken);
04207 
04208         ERROR3IF_PF(pOpDesc == NULL,("FindOpDescriptor(%s) failed",(TCHAR*)DragOpToken));
04209 
04210         if (pOpDesc != NULL)
04211             pOpDesc->Invoke(pDragOpParam);
04212 
04213         // Reset the vars ready for the next call to InvokeDragOp()
04214         DragOpInvoke = FALSE;
04215         pDragOpParam = NULL;
04216     }
04217     else
04218     {
04219         // Convert the click position to OIL coordinates before passing to the kernel.
04220         //  pDocView->SetCurrent();
04221         WinCoord wpoint(point.x, point.y);
04222         pDocView->OnClick( ( (WinCoord *)&point )->ToOil(pDocView, TRUE), t, LastClickMods);
04223     }
04224 }                                                             
04225 
04226 
04227 
04228 /********************************************************************************************
04229 >   BOOL CCamView::HandleMouseWheelEvent(UINT32 nFlags, short zDelta, wxPoint pt)
04230     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
04231     Created:    25/10/2000
04232     Purpose:    Handle MouseWheel for Scroll document and Zoom operations
04233                 Also dispatches a message to the Gallery the mouse is over, if any...
04234     Inputs:     nFlags - The mouse flags
04235                 zDelta - movement of the mousewheel
04236                 pt - the coordinate of the mouse cursor
04237 ********************************************************************************************/ 
04238 
04239 BOOL CCamView::HandleMouseWheelEvent( wxMouseEvent &event )
04240 {
04241     // Reasons Why This Is Done As It Is...
04242     // ************************************
04243     //
04244     // The WM_MOUSEWHEEL message is only ever sent to the window with focus. Galleries
04245     // never have the focus, even though they show they have (their windows are highlighted)
04246     // as this is done using rendering onto a blank window (as is their grey-ing out)
04247     // As a result of this, a Gallery is never sent a WM_MOUSEWHEEL message.
04248     // We therefore need to trap the message (here is as good a place as any) and check if the
04249     // user was actually over a gallery...
04250     // Finding out if they are over a Gallery SHOULD have been quite easy (eg WindowFromPoint())
04251     // EXCEPT that we don't create the Galleries in any sensible manner, thus they aren't
04252     // children of the current window - they are children of the Program Manager - sensible...
04253     // So, when we ask for the appropriate HWND it returns a nonsense value... Anyhow, the
04254     // following code gets around this and gives us the real HWND of the Gallery underneath the
04255     // mouse, OR returns NULL if no bar was found.
04256     // In the case where we get the Gallery HWND, we dispatch a message to scroll up/down according
04257     // to mousewheel delta. In the case where we have no HWND we check if the mouse lies within the
04258     // currently selected view and if it does, then scroll appropriately.
04259     // If anyone can see an easier way, then let me know!!!
04260     // Matt 1/11/00
04261 
04262     INT32 zDelta = event.GetWheelRotation();
04263     INT32 zStep = event.GetWheelDelta();
04264 
04265     PORTNOTETRACE("other","CCamView::HandleMouseWheelEvent - removed gallery bits");
04266 #ifndef EXCLUDE_FROM_XARALX
04267     // We need to know if the mouse pointer is over a Gallery, and if it is what the
04268     // HWND of that Gallery is, so that I can send it a scroll message...
04269     HWND OverBar = GetMainFrame()->IsScreenPointInBar(pt);
04270 
04271     if (OverBar)
04272     {
04273         if (zDelta < 0)
04274         {
04275             BROADCAST_TO_CLASS(DialogMsg(OverBar, DIM_MOUSEWHEEL_DOWN, 256), DialogOp);
04276         }
04277         else
04278         {
04279             BROADCAST_TO_CLASS(DialogMsg(OverBar, DIM_MOUSEWHEEL_UP, 256), DialogOp);
04280         }
04281     }
04282     else
04283 #endif
04284     {
04285         //Preliminary Checks...
04286         if (DocView::GetSelected() != pDocView)
04287         {
04288             // If selected doc is null, let's select it anyway.
04289             if (DocView::GetSelected() == NULL)
04290             {
04291                 // We're in a weird state that should never happen but does - a document
04292                 // has the focus, but isn't selected
04293                 Document* pKDoc =NULL;
04294                 if(pDocView)
04295                 {
04296                     pKDoc = pDocView->GetDoc();
04297                 }
04298 
04299                 if (pKDoc)
04300                 {
04301                     Document::SetSelectedViewAndSpread(pKDoc, pDocView, NULL);
04302                 }
04303             
04304             }
04305             return FALSE;   
04306         }
04307 
04308         SetCurrentStates();
04309 
04310         // We now need to work out if the Mouse is currently over part of the document - if it isn't
04311         // then we should ignore the message and let something else handle it...
04312         Spread* pSpread = Document::GetSelectedSpread();
04313         if (pSpread == NULL)    {   return FALSE;   }
04314 
04315         DocCoord MousePos;
04316         if(!DocView::GetCurrentMousePos(&pSpread, &MousePos))
04317         {
04318             return FALSE;
04319         }
04320 
04321 
04322 #if (_OLE_VER >= 0x200)
04323         // The user's doing something so don't update any container docs
04324         CCamDoc::ResetContainerUpdateTimer();
04325 #endif
04326 
04327         //If the user is holding down CTRL whilst scrolling the wheel, then we should do the standard zoom-in/out
04328         if (event.ControlDown())
04329         {
04330 //          TRACEUSER( "Matt", _T("MouseWheel + CTRL = Zoom, in ScreenView\n"));
04331 
04332             // Try to create an instance of the zoom operation.
04333             OpZoom* pZoomOp = new OpZoom;
04334             if (pZoomOp == NULL)
04335             {
04336                 // We ran out of memory, so sorry.
04337                 InformError(_R(IDE_NOMORE_MEMORY));
04338                 return FALSE;
04339             }
04340 
04341             DocCoord DocMouse = MousePos.ToDoc(pSpread, pDocView);
04342             WorkCoord WorkMouse;
04343             WorkMouse = DocMouse.ToWork(pSpread, pDocView);
04344 
04345             // Get the current view's scaling factor as a rounded precentage.
04346             INT32 nOldScalePercent = ((pDocView->GetViewScale() * 100) + FIXED16_DBL(0.5)).MakeInt();
04347 
04348             // Zoom in or out around the mouse position...
04349             if (zDelta > 0)
04350             {
04351                 // Search backwards until we find a higher zoom, or the end of the table
04352                 for (INT32 i = cZoomTableSize - 1; i >= 0; i--)
04353                 {
04354                     // Found a higher zoom?  If so, set it, remember it's position and return.
04355                     if (nOldScalePercent < pZoomOp->GetPresetZoomPercent(i))
04356                     {
04357                         // Do the zoom.  We will (optionally) end the operation.
04358                         pDocView->SetZoomTableIndex(i);
04359                         pZoomOp->MouseWheelZoomAtPoint(WorkMouse, pZoomOp->GetPresetZoomScale(i), FALSE);
04360                         break;
04361                     }
04362                 }
04363             }
04364             else
04365             {
04366                 // Search forwards through the zoom table until we find a lower zoom factor
04367                 for (INT32 i = 0; i < cZoomTableSize; i++)
04368                 {
04369                     // Found a lower zoom?  If so, set it, remember it's position in the zoom table
04370                     if (nOldScalePercent > pZoomOp->GetPresetZoomPercent(i))
04371                     {
04372                         // Do the zoom.  We will (optionally) end the operation.
04373                         pDocView->SetZoomTableIndex(i);
04374                         pZoomOp->MouseWheelZoomAtPoint(WorkMouse, pZoomOp->GetPresetZoomScale(i), FALSE);
04375                         break;
04376                     }
04377                 }
04378             }
04379 
04380             // Tidy away...
04381             delete pZoomOp;
04382 
04383             return TRUE;
04384         }
04385         else
04386         {
04387             // The CTRL key was not pressed, so we should simply (is anything simple around here)
04388             // scroll the viewport up/down. (OR left/right if SHIFT is held down - Matt 16/11/2000)
04389 
04390             if (event.ShiftDown())
04391             {
04392                 // Get the current Horizontal Scroll Position, increment it by a zoom-dependent amount
04393                 // and set the Horizontal Scroll Position to be this value, flagging it to redraw...
04394                 ScrollBy(-(zDelta/zStep) * 20, 0);
04395             }
04396             else
04397             {
04398                 // Get the current Vertical Scroll Position, increment it by a zoom-dependent amount
04399                 // and set the Vertical Scroll Position to be this value, flagging it to redraw...
04400                 ScrollBy(0, -(zDelta/zStep) * 20);
04401             }
04402 
04403             // NOTE : If we wanted to be really flash, we could make the scroll distance affected by the
04404             // user's settings in the Control Panel - ie, default is to scroll 3 lines on 120 zDelta, but
04405             // can be adjusted so we could look at that value...
04406         }
04407         // tell everyone we've changed the screen
04408         BROADCAST_TO_ALL(ScreenChangeMsg());
04409     }
04410 
04411     // If we get to here, then we must have handled the MouseWheel, so return true...
04412     return TRUE;
04413 }
04414 
04415 
04416 
04417 /*********************************************************************************************
04418 >   void CCamView::HandleButtonUp(UINT32 nFlags, wxPoint point)
04419 
04420     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04421     Created:    9th Sept 1993
04422     Inputs:     Button - which mouse button has been released.
04423                 nFlags - The mouse button flags.
04424                 point - the coordinate of the mouse cursor.
04425     Outputs:    -
04426     Returns:    -
04427     Purpose:    Finishes the current drag, if there is one, by elucidating the state of
04428                 the buttons etc and calling DragDFinished() in the kernel (DocView).  Called
04429                 whenever a mouse button is released.
04430     Errors:     -
04431     Scope:      Private
04432     SeeAlso:    CCamView::GetClickMods(); CCamView::OnLButtonDown(); CCamView::OnRButtonDown()
04433                 DocView::OnClick()
04434 
04435 **********************************************************************************************/ 
04436 
04437 void CCamView::HandleButtonUp(UINT32 Button, wxMouseEvent &event)
04438 {
04439     //Graham 18/6/96: Changed the logical conditions of this function
04440     //to support clicks with one mouse button while another button is
04441     //dragging
04442     
04443     if (DocView::GetSelected() != pDocView)
04444     {
04445         ENSURE(pCurrentDragOp == NULL, "Drag operation in a view that isn't 'selected' !!");
04446 //      TRACEUSER( "JustinF", _T("Ignored button-up cos not in the selected view\n"));
04447         return;
04448     }
04449 
04450     // Set Current states...
04451     SetCurrentStates();
04452 
04453     //Graham: Here's the change - in the logical conditions only. The actual
04454     //functions called are the same.
04455 
04456     WinCoord            point;
04457     event.GetPosition( &point.x, &point.y );
04458 
04459     //Was the button that went up the first one that went down?
04460     if (Button==FirstClickButton)
04461     {
04462         //Yes it was.
04463         //Is there a drag currently running?
04464         if (pCurrentDragOp != NULL)
04465         {
04466             // Yes there is.
04467             // Release the capture and terminate the drag.  Note that we try to release
04468             // the mouse capture as soon as possible after a drag has finished, in case the
04469             // DragFinished method below brings up a dialog box or something.
04470             if (GetRenderWindow() && GetRenderWindow()->GetCapture()==GetRenderWindow())
04471                 GetRenderWindow()->ReleaseMouse();
04472             pDocView->DragFinished(pCurrentDragOp, ((WinCoord*) &point)->ToOil(pDocView, TRUE), 
04473                                LastClickMods, TRUE);
04474 
04475 
04476             // Now cater for the special case that the user used the PushCentreTool Click Modifier
04477             // and they didn't move the mouse - this means they either wanted to Centre the
04478             // view about the cursor, ZoomIn() or ZoomOut() depending on the modifiers....
04479             if ((LastClickPoint == CurrentMousePos) && LastClickMods.PushCentreTool)
04480             {
04481                 // Did we want to ZoomIn()?
04482                 if( event.ControlDown() )
04483                 {
04484                     OpZoom* pZoomOp = new OpZoom;
04485                     ERROR3IF(!pZoomOp,"Couldn't create pZoomOp");
04486 
04487                     // Find the mid-point of the view, in work coordinates...
04488                     WorkRect wrView = pDocView->GetViewRect();
04489                     WorkCoord wcMidView((wrView.lo.x + wrView.hi.x) / 2, (wrView.lo.y + wrView.hi.y) / 2);
04490 
04491                     pZoomOp->ZoomIn(wcMidView);
04492                 }
04493                 // Did we want to ZoomOut()?
04494                 else if( event.ShiftDown() )
04495                 {
04496                     OpZoom* pZoomOp = new OpZoom;
04497                     ERROR3IF(!pZoomOp,"Couldn't create pZoomOp");
04498 
04499                     // Find the mid-point of the view, in work coordinates...
04500                     WorkRect wrView = pDocView->GetViewRect();
04501                     WorkCoord wcMidView((wrView.lo.x + wrView.hi.x) / 2, (wrView.lo.y + wrView.hi.y) / 2);
04502 
04503                     pZoomOp->ZoomOut(wcMidView);
04504                 }
04505                 else
04506                 {
04507                     // Then we must have wanted to centre the screen about the cursor...
04508 
04509                     DocCoord MousePos;
04510                     Spread *pSpread = Document::GetSelectedSpread();
04511                     if(!DocView::GetCurrentMousePos(&pSpread, &MousePos))
04512                     {
04513                         return;
04514                     }
04515 
04516 
04517                     WorkCoord testwork(MousePos.ToWork(pSpread, pDocView));
04518 
04519 
04520                     // Find out where the middle of the current view is...
04521                     DocRect ViewRect = (pDocView->GetDocViewRect(pSpread)).ToSpread(pSpread, pDocView);
04522                     DocCoord ViewMidPoint(0,0);
04523                     ViewMidPoint.x = INT32(ViewRect.lo.x + (ViewRect.hi.x - ViewRect.lo.x)/2.0);
04524                     ViewMidPoint.y = INT32(ViewRect.lo.y - (ViewRect.lo.y - ViewRect.hi.y)/2.0);
04525 
04526                     // Work out what the offset between the centre of the screen and the MousePos is...
04527                     DocCoord Offset = MousePos - ViewMidPoint;
04528 
04529                     WorkCoord ScrollOffset;
04530                     WorkCoord WorkOffset;
04531 
04532                     WorkOffset.x = (XLONG) (MakeXLong(Offset.x) * pDocView->GetViewScale());
04533                     WorkOffset.y = (XLONG) (MakeXLong(Offset.y) * pDocView->GetViewScale());
04534 
04535                     ScrollOffset = pDocView->GetScrollOffsets();
04536                     ScrollOffset.x = ScrollOffset.x + WorkOffset.x;
04537                     ScrollOffset.y = ScrollOffset.y + WorkOffset.y;
04538 
04539                     if (ScrollOffset.x < (XLONG) 0) ScrollOffset.x = (XLONG) 0;
04540                     if (ScrollOffset.y > (XLONG) 0) ScrollOffset.y = (XLONG) 0;
04541 
04542                     // Scroll the screen to centre about the cursor!
04543                     pDocView->SetScrollOffsets(ScrollOffset, TRUE);
04544                 }
04545             }
04546         }
04547         else
04548         {
04549             // No there isn't.
04550             // Kill the timer started in HandleDragEvent(), 
04551             // as we don't want to wait for a drag anymore.
04552             m_DragIdleTimer.Stop();
04553 
04554             FirstClickButton = 0;
04555 
04556             //Then pass the Up-Click message to CCamView::OnClick
04557             pDocView->OnClick(((WinCoord*) &point)->ToOil(pDocView, TRUE), CLICKTYPE_UP, LastClickMods);
04558         }
04559     }
04560     else
04561     {
04562         //No, the button that went up was not the first one to go down.
04563         //In that case, we expect the first button that went down is still down and
04564         //hence there is a drag running.
04565         //Is there a drag running?
04566         if (pCurrentDragOp != NULL)
04567         {
04568             //Yes, as expected.
04569             //Pass the Up-Click message to CCamView::OnClick
04570             pDocView->OnClick(((WinCoord*) &point)->ToOil(pDocView, TRUE), CLICKTYPE_UP, LastClickMods);
04571         }
04572         //If not, something odd has happened - perhaps the user has clicked fast
04573         //with the mouse. This need not worry us but we should not do anything
04574         //with the up-click message.
04575         //The only problem that could occur is if we are in a button-up-drag. This
04576         //is handled below.
04577         
04578     }
04579 
04580     //Ensure there is not a button-up drag in progress
04581     //That is, there is a drag in progress AND no buttons down
04582 //  ERROR3IF((Operation::GetCurrentDragOp()==NULL)&&(nFlags & ~(MK_SHIFT | MK_CONTROL) == 0),
04583 //      "CCamView::HandleButtonUp - drag operation in progress but no buttons down");
04584 }
04585 
04586 // The following is Justin's original logical conditions, commented out, in case
04587 // anyone needs them or if the above doesn't work
04588 /*  // Are we in a real mess, Mr User?
04589     if (Button != FirstClickButton)
04590     {
04591 //      TRACEUSER( "JustinF", _T("Ignored button-up cos different button went down\n"));
04592         return;
04593     }
04594 
04595     
04596 
04597     // Are we currently running a drag operation.
04598     if (pCurrentDragOp != NULL)
04599     {
04600         // Yes, so release the capture and terminate the drag.  Note that we try to release
04601         // the mouse capture as soon as possible after a drag has finished, in case the
04602         // DragFinished method below brings up a dialog box or something.
04603         ::ReleaseCapture();
04604         pDocView->DragFinished(pCurrentDragOp, ((WinCoord*) &point)->ToOil(pDocView, TRUE), 
04605                                LastClickMods, TRUE);
04606     }
04607     else
04608     {
04609         // No.  Is this the button that was pressed first?  If so, kill the timer started in
04610         // HandleDragEvent(), as we don't want to wait for a drag anymore.
04611         if (Button == FirstClickButton)
04612         {
04613             ::FixKillTimer(m_hWnd, 1);
04614             FirstClickButton = 0;
04615         }
04616         else
04617         {
04618             // NB. the test above should prevent this ENSURE going off . . .
04619             ENSURE((nFlags & ~(MK_SHIFT | MK_CONTROL)) == 0,
04620                    "No buttons down - Welcome to Button-Up-Drag City!");
04621         }
04622 
04623         // Send a button-up event if we weren't running a drag.
04624         pDocView->OnClick(((WinCoord*) &point)->ToOil(pDocView, TRUE), CLICKTYPE_UP, LastClickMods);
04625 
04626     }*/
04627 
04628 
04629 
04630 /*********************************************************************************************
04631 >   BOOL CCamView::InvokeDragOp(String_256 OpToken,UINT32 Flags,wxPoint point,OpParam* pParam)
04632 >   BOOL CCamView::InvokeDragOp(String_256 OpToken,ClickModifiers clickmods,wxPoint point,OpParam* pParam)
04633 
04634     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04635     Created:    21/9/95
04636     Inputs:     OpToken = Op token of op to invoke
04637                 pParam  = ptr to a param block that's passed to the op
04638                           NOTE! Object at *pParam must have a long life time.  I.e. do NOT
04639                                 call this func with ptr to a local OpParam var
04640                 Flags   = flags that specify which modifiers were down during the click
04641                 clickmods = Kernel abstraction of modifiers
04642                 point   = screen coord of the start of the drag
04643     Outputs:    -
04644     Returns:    Returns TRUE if successful.  Returns FALSE if not
04645     Purpose:    This func provides a mechanism that allows a drag op to be invoked as if it has been started
04646                 as a result of clicking in the view.  This allows drag ops to be invoked that aren't
04647                 associated to a given tool.
04648 
04649                 This allows a drag op to be started directly, instead of being a result of a tool handling
04650                 the click.  This allows you to write drag ops in the usual way.
04651 
04652                 If pParam is NULL, the op's Do() function will be called.  If pParam != NULL, the op's
04653                 DoWithParam(pParam) func will be called.  Either way, Operation::StartDrag() should be
04654                 called as a result.
04655 
04656                 It was introduced to allow the rulers to create guidelines undoably, no matter what
04657                 tool you are in.  See winoil\oilruler.cpp & kernel\guides.cpp & OpGuideLine
04658 
04659     Errors:     -
04660     Scope:      -
04661     SeeAlso:    -
04662                           
04663 **********************************************************************************************/ 
04664 /*  Implementation notes:
04665 
04666     It does this:
04667         Posts itself a WM_LBUTTONDOWN message with the flags and point provided
04668     NOTE: Not any more! Now calls HandleDragEvent directly...
04669 
04670     and in HandleDragEvent()
04671         Creates an instance of the op specified by OpToken
04672         Calls the DragStart() virt func, that should call Operation::StartDrag() at some point
04673 */
04674 
04675 BOOL CCamView::InvokeDragOp(String_256* pOpToken,OpParam* pParam,UINT32 Flags,wxPoint point)
04676 {
04677     DragOpToken  = *pOpToken;
04678     pDragOpParam = pParam;
04679     DragOpInvoke = TRUE;
04680 
04681     // NOTE: May need to post a pseudo mouse event here if some of the subtleties of click
04682     // handling are required, but this works fine for simple drags
04683     HandleDragEvent(MK_LBUTTON, Flags, point, CLICKTYPE_SINGLE);
04684 
04685     return TRUE;
04686 }
04687 
04688 BOOL CCamView::InvokeDragOp(String_256* pOpToken, OpParam* pParam, ClickModifiers clickmods, wxPoint point)
04689 {
04690     DragOpToken  = *pOpToken;
04691     pDragOpParam = pParam;
04692     DragOpInvoke = TRUE;
04693 
04694     // NOTE: May need to post a pseudo mouse event here if some of the subtleties of click
04695     // handling are required, but this works fine for simple drags
04696     HandleDragEvent(MK_LBUTTON, clickmods, point, CLICKTYPE_SINGLE);
04697 
04698     return TRUE;
04699 }
04700 
04701 
04702 
04703 
04704 
04705 
04706 
04707 
04708 /********************************************************************************************
04709 
04710 >   BOOL CCamView::ChangeDragType(DragType Type)
04711 
04712     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
04713     Created:    3/4/95
04714     Inputs:     Type - the type of drag to change to
04715     Returns:    TRUE
04716     Purpose:    Allows someone to change the type of a drag (eg have Auto Scrolling on
04717                 in some situations, but not in others). This function is mostly called from
04718                 the Kernel (DocView) version of the same function
04719     SeeAlso:    DocView::ChangeDragType
04720 
04721 ********************************************************************************************/
04722 
04723 BOOL CCamView::ChangeDragType(DragType Type)
04724 {
04725     // Change the current drag type
04726     CurrentDragType = Type;
04727     m_OLELastOutTime.Sample();
04728     OLERecaptureMouse = FALSE;
04729 
04730     return TRUE;
04731 }
04732 
04733 
04734 /*********************************************************************************************
04735 >   void CCamView::HandleDragScrolling(wxPoint point)
04736 
04737     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04738     Created:    20th Sept 1993
04739     Inputs:     The current position of the mouse cursor.
04740     Outputs:    -
04741     Returns:    -
04742     Purpose:    Checks if the view window needs to be scrolled because the cursor has been
04743                 dragged outside the window.  The window will be scrolled if the current
04744                 mode is AUTO_SCROLL (and the Scroll Lock key isn't latched!!).  The scrolling
04745                 itself is done by calling the routine in DocView, not ScreenView, so that the
04746                 kernel has fair warning to remove any blobbies before the blit is done.
04747                 
04748                 Called when ScreenView receives mouse-move messages and timer ("mouse-idle")
04749                 messages.  Also handles DEFERRED_SCROLLING.
04750     Errors:     -
04751     Scope:      Private
04752     SeeAlso:    CCamView::OnMouseMove; CCamView::OnTimer
04753 
04754 **********************************************************************************************/ 
04755 
04756 void CCamView::HandleDragScrolling(wxPoint point)
04757 {
04758     // First we check for the type that does nothing and get out quick
04759     if (CurrentDragType == DRAGTYPE_NOSCROLL)
04760         return;
04761 
04762     // Get the size of the view.  We may have to deflate the rectangle a little here, if the
04763     // bottom-right edges of the view coincide with the bottom-right edges of the screen,
04764     // otherwise it is not possible to auto-scroll to the right or down as the mouse never
04765     // leaves the view window.
04766 
04767     WinRect wrSize = CurrentSize;
04768 //  TRACEUSER("Gerry", _T("wrSize = (%d, %d) [%d, %d]\n"), wrSize.x, wrSize.y, wrSize.width, wrSize.height);
04769 //  TRACEUSER("Gerry", _T("Point = (%d, %d)\n"), point.x, point.y);
04770     point = GetRenderWindow()->ClientToScreen( point );
04771     point = GetFrame()->ScreenToClient( point );
04772 
04773 //  TRACEUSER("Gerry", _T("AdjPoint = (%d, %d)\n"), point.x, point.y);
04774     
04775     // This is used to allow guidelines to be deleted by dropping on to the rulers - normally
04776     // we would start to auto scroll at this point which is a little off putting..
04777     if (AutoScrollExcludeRulers && CurrentDragType != DRAGTYPE_OLESCROLL)
04778     {
04779         UINT32 RulerWidth = OILRuler::GetWidth();
04780 //      wrSize.left -= RulerWidth;
04781 //      wrSize.top -= RulerWidth;
04782         wrSize.SetLeft(wrSize.GetLeft()-RulerWidth);
04783         wrSize.SetTop(wrSize.GetTop()-RulerWidth);
04784     }
04785 
04786     // Now check for deferred scrolling
04787     if (CurrentDragType == DRAGTYPE_DEFERSCROLL)
04788     {
04789         // If the mouse is within the window, and we are performing deferred-scrolling
04790         // then we can change over to auto-scrolling.
04791         if (!wrSize.IsEmpty() && wrSize.Inside(point))
04792         {
04793             CurrentDragType = DRAGTYPE_AUTOSCROLL;
04794             AutoScrollExcludeRulers = TRUE;
04795         }
04796         return;
04797     }
04798 
04799     // Initialise Deltas...
04800     INT32 dx = 0;
04801     INT32 dy = 0;
04802 
04803     WinRect Outer = wrSize;
04804 
04805     // Set auto-scroll region to be one scrollbar width within the current view
04806     // (as per The Windows Interface Guidelines Chapter 5).
04807     wrSize.Inflate(-ScrollBarSize,-ScrollBarSize);
04808 
04809     // Has the mouse moved outside there bounds?
04810     if (!wrSize.IsEmpty() && !wrSize.Inside(point))
04811     {
04812         BOOL bCalcDeltas = TRUE;
04813 #if !defined(EXCLUDE_FROM_XARALX)
04814         if (CurrentDragType == DRAGTYPE_OLESCROLL)
04815         {
04816             if (Outer.Inside(point))        // and still inside visible window
04817             {
04818                 // If we've not been in the OLE scroll region for long enough
04819                 if (!m_OLELastOutTime.Elapsed(100))
04820                 {
04821                     bCalcDeltas = FALSE;
04822                 }
04823             }
04824             else
04825             {
04826                 // We've dragged beyond the OLE scroll area, so we can now convert the drag
04827                 // into an OLE export drag if we so desire.
04828                 HandleOleDragOutOfView(point);
04829                 bCalcDeltas = FALSE;
04830             }
04831         }
04832 #endif
04833         if (bCalcDeltas)
04834         {
04835             // The mouse is outside the view, and we have to scroll the view
04836             // proportionate to how far outside it is.
04837             CalcScrollDeltas(point,wrSize,&dx,&dy);
04838             TRACEUSER("Gerry", _T("ScrollDeltas = (%d, %d)\n"), dx, dy);
04839         }
04840     }
04841 #if !defined(EXCLUDE_FROM_XARALX)
04842     else if (CurrentDragType == DRAGTYPE_OLESCROLL)
04843     {
04844         // We're not in the OLE scroll region so reset the timer
04845         m_OLELastOutTime.Sample();
04846     }
04847 #endif
04848 
04849     //------------------------------------
04850     // Now do the scroll if necessary...
04851     // If dx<>0 or dy<>0 and scroll lock is disabled
04852 
04853     // Test if the SCROLL LOCK key has been set.
04854     if( !wxGetKeyState( CAMKEY(SCROLL) ) && !(dx==0 && dy==0))
04855     {
04856         // Set Current states...
04857         SetCurrentStates();
04858 
04859         // Do the scroll
04860         ScrollBy(dx, dy);
04861     }
04862 }
04863 
04864 
04865 /*********************************************************************************************
04866 >   static void CCamView::GetClickMods(wxMouseEvent &event, ClickModifiers* p)
04867 
04868     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
04869     Created:    ages ago
04870     Inputs:     The mouse event passed by wx to a mouse message-handler function.
04871     Outputs:    Changes the ClickModifier to reflect the button flags.
04872     Returns:    -
04873     Purpose:    Helps convert an OIL-layer mouse event into a form acceptable to the kernel.
04874                 Sets the fields of the ClickModifier according to which button is down/up,
04875                 whether the SHIFT, CONTROL, or ALT key is held down etc.  Note that as the
04876                 fields of a ClickModifier are only one bit wide, we must be carefule when
04877                 assigning the (integer) results of logical tests to them.
04878     Errors:     -
04879     Scope:      Public
04880     SeeAlso:    CCamView::HandleDragEvent()
04881 **********************************************************************************************/ 
04882 
04883 void CCamView::GetClickMods(wxMouseEvent &event, ClickModifiers* p)
04884 {
04885     *p = ClickModifiers::GetClickModifiers(event);
04886 }
04887 
04888 
04889 /*********************************************************************************************
04890 >   void CCamView::CalcScrollDeltas(wxPoint point, WinRect wrSize, INT32* dx, INT32* dy)
04891 
04892     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> (from Justin)
04893     Created:    22/9/96
04894     Inputs:     point   The current position of the mouse cursor.
04895                 wrSize  The rectangle controlling scrolling.
04896     Outputs:    dx      The amount to scroll in the X axis.
04897                 dy      The amount to scroll in the Y axis.
04898     Returns:    -
04899     Purpose:    Calculates the scroll deltas due to the current mouse position being
04900                 outside the allowed rectangle.
04901                 Helper function.
04902     Errors:     -
04903     Scope:      Protected
04904     SeeAlso:    CCamView::HandleDragScrolling
04905 
04906 **********************************************************************************************/ 
04907 
04908 void CCamView::CalcScrollDeltas(wxPoint point, WinRect wrSize, INT32* dx, INT32* dy)
04909 {
04910     if( point.x < wrSize.GetLeft() )
04911         *dx = max(point.x - wrSize.GetLeft(), -ScrollBarSize);
04912     else if( point.x >= wrSize.GetRight() )
04913         *dx = min(point.x - wrSize.GetRight(), ScrollBarSize);
04914     else
04915         *dx = 0;
04916 
04917     if( point.y < wrSize.GetTop() )
04918         *dy = max(point.y - wrSize.GetTop(), -ScrollBarSize);
04919     else if( point.y >= wrSize.GetBottom() )
04920         *dy = min(point.y - wrSize.GetBottom(), ScrollBarSize);
04921     else
04922         *dy = 0;
04923 }
04924 
04925 
04926 /*********************************************************************************************
04927 >   void CCamView::ScrollBy(INT32 dx, INT32 dy)
04928 
04929     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> (from Justin)
04930     Created:    22/9/96
04931     Inputs:     dx      The amount to scroll in the X axis.
04932                 dy      The amount to scroll in the Y axis.
04933     Returns:    -
04934     Purpose:    Scrolls the view by asking the DocView to do it so it can remove 
04935                 and replace blobs.
04936     Errors:     -
04937     Scope:      Protected
04938 
04939 **********************************************************************************************/ 
04940 
04941 void CCamView::ScrollBy(INT32 dx, INT32 dy)
04942 {
04943     // If we're not scrolling then don't bother
04944     if (dx == 0 && dy == 0)
04945         return;
04946 
04947     // Convert these pixel values into a WorkCoord offset, add to the
04948     // scroll position and update the scroll bars etc.  Note that the
04949     // y offset is subtracted as the y-axis is reversed compared to
04950     // Windows . . .
04951     WorkCoord offset;
04952     GetScrollOffset(&offset);
04953 //  TRACEUSER("Gerry", _T("OldOffset = (%d, %d)\n"), (INT32)offset.x, (INT32)offset.y);
04954 
04955     FIXED16 PixelWidth, PixelHeight;
04956     pDocView->GetPixelSize(&PixelWidth, &PixelHeight);
04957     offset.x += dx * PixelWidth;
04958     offset.y -= dy * PixelHeight;
04959 
04960     WorkRect wrScrollRect = GetMaxScrollRect();
04961     if (offset.x < wrScrollRect.lo.x)   offset.x = wrScrollRect.lo.x;
04962     if (offset.y < wrScrollRect.lo.y)   offset.y = wrScrollRect.lo.y;
04963     if (offset.x > wrScrollRect.hi.x)   offset.x = wrScrollRect.hi.x;
04964     if (offset.y > wrScrollRect.hi.y)   offset.y = wrScrollRect.hi.y;
04965 //  TRACEUSER("Gerry", _T("NewOffset = (%d, %d)\n"), (INT32)offset.x, (INT32)offset.y);
04966 
04967     // By calling DocView to do the scroll we give it a chance to remove
04968     // any blobbies it might have put on the screen.  Note that the scrollers
04969     // will prevent any overscroll.
04970     pDocView->SetScrollOffsets(offset, TRUE);
04971 }
04972 
04973 
04974 /********************************************************************************************
04975 >   WorkRect CCamView::GetMaxScrollRect() const
04976 
04977     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04978     Created:    31/May/2006
04979     Inputs:     -
04980     Outputs:    -
04981     Returns:    WorkRect describing legal area for scroll offsets
04982     Purpose:    Find the legal area in which scroll offsets can exist
04983     Errors:     -
04984     SeeAlso:    -
04985 ********************************************************************************************/
04986 
04987 WorkRect CCamView::GetMaxScrollRect() const
04988 {
04989     WorkRect wrScrollRect = Status->WorkAreaExtent;
04990 
04991     FIXED16 PixelWidth, PixelHeight;
04992     pDocView->GetPixelSize(&PixelWidth, &PixelHeight);
04993 
04994     WorkCoord WindowSize;
04995     WindowSize.x = CurrentSize.GetWidth() * PixelWidth;
04996     WindowSize.y = CurrentSize.GetHeight() * PixelHeight;
04997 
04998     if (WindowSize.x > wrScrollRect.hi.x)       // If window wider than document
04999         wrScrollRect.hi.x = wrScrollRect.lo.x;  // no horz scrolling is possible
05000     else
05001         wrScrollRect.hi.x -= WindowSize.x;      // Restrict scrollable area to ensure view never sees outside workarea
05002 
05003     if (WindowSize.y < wrScrollRect.lo.y)       // If window wider than document
05004         wrScrollRect.lo.y = wrScrollRect.hi.y;  // no vert scrolling is possible
05005     else
05006         wrScrollRect.lo.y += WindowSize.y;      // Restrict scrollable area to ensure view never sees outside workarea
05007 
05008     return wrScrollRect;
05009 }
05010 
05011 
05012 /********************************************************************************************
05013 >   BOOL CCamView::IsTopmost() const
05014 
05015     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
05016     Created:    17/11/93
05017     Inputs:     -
05018     Outputs:    -
05019     Returns:    TRUE if this view is the active view.
05020     Purpose:    Tests if this ScreenView is the active view, ie. is on top of all other views.
05021     Errors:     -
05022     SeeAlso:    -
05023 ********************************************************************************************/
05024 
05025 BOOL CCamView::IsTopmost() const
05026 {
05027     return( wxGetApp().CCamApp::GetDocumentManager()->GetCurrentView() == this );
05028 }
05029 
05030 
05031 /********************************************************************************************
05032 >   static DocView* CCamView::GetDocViewFromWindow(wxWindow* pWindow)
05033 
05034     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
05035     Created:    28/7/94
05036     Inputs:     The handle of the render window to find.
05037     Outputs:    -
05038     Returns:    A pointer to the DocView associated with a render window, or NULL if
05039                 there isn't one.
05040     Purpose:    Given a window handle of a ScreenView render window, this function will
05041                 return a pointer to the kernel DocView object that renders into that
05042                 window, or NULL if there isn't one.
05043     Errors:     -
05044     SeeAlso:    -
05045 ********************************************************************************************/
05046 
05047 DocView *CCamView::GetDocViewFromWindow(wxWindow *pWindow)
05048 {
05049     // For all kernel documents in existence . . .
05050     List* pDocList = &(GetApplication()->Documents);
05051     for (Document* pKernelDoc = (Document*) pDocList->GetHead();
05052          pKernelDoc != NULL;
05053          pKernelDoc = (Document*) pDocList->GetNext(pKernelDoc))
05054     {
05055         if (pKernelDoc->IsARalphDoc())
05056         {
05057             // a bit unpleasent - only works because Ralph Docs have only one view..
05058             // get the first (and only) docview
05059             DocView * pDocView = pKernelDoc->GetFirstDocView();
05060             // check handles
05061             if (pDocView)
05062                 if( pDocView->GetRenderWindow() == pWindow )
05063                     return pDocView;
05064         }
05065         else
05066         {
05067              // Convert from a kernel document to an OIL document.
05068             CCamDoc* pCamDoc = pKernelDoc->GetOilDoc();
05069 
05070             wxNode *node = pCamDoc->GetViews().GetFirst();
05071             while (node)
05072             {
05073                 // Compare the handle of the view's render window to the given handle,
05074                 // returning the associated DocView if they match.
05075                 CCamView* pCamView = (CCamView*) node->GetData();
05076 
05077                 // Not interested unless it is a ScreenView (it could be a print preview view)
05078 //              if (pCamView->IsKindOf(RUNTIME_CLASS(CCamView)))
05079 //              {
05080                     if (pCamView->GetRenderWindow() == pWindow)
05081                     {
05082                         return pCamView->pDocView;
05083                     }
05084 //              }
05085                 node = node->GetNext();
05086             }
05087         }
05088     } 
05089 
05090     // Couldn't find the handle, so return nothing.
05091     return NULL;
05092 }   
05093 
05094 
05095 /*********************************************************************************************
05096 >   BOOL CCamView::CreateDragTarget(DragInformation * DragInfo)
05097 
05098     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
05099     Created:    21/1/95
05100     Inputs:     DragInfo : details about the current drag
05101     Outputs:    -
05102     Purpose:    will create drag targets for appropriate drags
05103     Errors:     -
05104 
05105 **********************************************************************************************/ 
05106 
05107 BOOL CCamView::CreateDragTarget(DragInformation * DragInfo)
05108 {
05109 #if !defined(EXCLUDE_FROM_RALPH)
05110     // TEMPORARY - only create drag targets for the selected (frontmost/input-focus)
05111     // DocView. This stops us allowing colour drags to go into the wrong document
05112     // if the user ctrl-tabs to a different window during the drag.
05113     // Ideally, drags will be allowed, but the colour will be copied to the destination
05114     // document before being applied, but currently we don't have time to implement all that
05115     if (pDocView != DocView::GetSelected())
05116         return FALSE;
05117 
05118     if (DragInfo->CanDropOnPage())
05119     {
05120         // If the drag can be dropped onto an object or the page, then we will accept it
05121         ViewDragTarget * NewTarget;
05122         NewTarget = new ViewDragTarget(RenderWindow,NULL,DragInfo);
05123         return TRUE;
05124     }
05125 #endif
05126     return FALSE;
05127 }
05128 
05129 
05130 /********************************************************************************************
05131 >   static DocView* CCamView::GetDocViewFromHwnd(CWindowID WindowID)
05132 
05133     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
05134     Created:    28/7/94
05135     Inputs:     The handle of the render window to find.
05136     Outputs:    -
05137     Returns:    A pointer to the DocView associated with a render window, or NULL if
05138                 there isn't one.
05139     Purpose:    Given a window handle of a ScreenView render window, this function will
05140                 return a pointer to the kernel DocView object that renders into that
05141                 window, or NULL if there isn't one.
05142     Errors:     -
05143     SeeAlso:    -
05144 ********************************************************************************************/
05145 
05146 DocView *CCamView::GetDocViewFromWindowID( CWindowID WindowID )
05147 {
05148     // For all kernel documents in existence . . .
05149     List* pDocList = &(GetApplication()->Documents);
05150     for (Document* pKernelDoc = (Document*) pDocList->GetHead();
05151          pKernelDoc != NULL;
05152          pKernelDoc = (Document*) pDocList->GetNext(pKernelDoc))
05153     {
05154 
05155         DocView * pDocView = pKernelDoc->GetFirstDocView();
05156         
05157         while (pDocView)
05158         {
05159             if ( pDocView->GetRenderWindow() == WindowID )
05160                 return pDocView;
05161             pDocView = pKernelDoc->GetNextDocView(pDocView);
05162         }
05163     } 
05164 
05165     // Couldn't find the handle, so return nothing.
05166     return NULL;
05167 }   
05168 
05169 
05170 bool CCamView::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
05171 {
05172     // Set the correct docivew (and hence document)
05173     pDocView->SetCurrent();
05174 
05175     // Create the drop info object
05176     FileDropInfo DropInfo(WinCoord(x, y));
05177     List* pList = DropInfo.GetFileList();
05178 
05179     size_t Index;
05180     for (Index = 0; Index < filenames.GetCount(); Index++)
05181     {
05182         wxString TempStr(filenames[Index]);
05183 
05184         // A bit of a nasty hack here to work around a bug in wxWidgets
05185         // Filenames with multibyte characters are not correctly decoded
05186         // into the wxString so it still contains multi-byte sequences
05187         // We will check if all the chars are single byte and if so,
05188         // force it into a char buffer and convert using wxConvFileName
05189         // This should mean that this code will not interfere if someone
05190         // fixes wxWidgets
05191         UINT32 i = 0;
05192         while (TempStr[i] != 0 && (TempStr[i] & 0xFF) == TempStr[i])
05193             i++;
05194 
05195         if (TempStr[i] == 0)
05196         {
05197             // All the chars are bytes so try sticking them into a char array 
05198             // and converting them with wxConvFileName
05199             char* pBuf = (char*)CCMalloc(i + 1);
05200             if (pBuf)
05201             {
05202                 i = 0;
05203                 while (TempStr[i] != 0)
05204                 {
05205                     pBuf[i] = (char)(TempStr[i] & 0xFF);
05206                     i++;
05207                 }
05208                 pBuf[i] = 0;
05209 
05210                 TempStr = wxConvFileName->cMB2WX(pBuf);
05211                 CCFree(pBuf);
05212             }
05213         }
05214 
05215         String_256 Str(TempStr);
05216 
05217         StringListItem* pItem = new StringListItem(Str);
05218         if (pItem)
05219             pList->AddTail(pItem);
05220     }
05221 
05222     // Invoke the dropped files operation
05223     OpDescriptor *pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_DROPPEDFILE);
05224     if (pOpDesc)
05225         pOpDesc->Invoke((OpParam *) &DropInfo);
05226 
05227     return(true);
05228 }
05229 
05230 
05231 /********************************************************************************************
05232 
05233 >   void ViewDragTarget::ViewDragTarget() 
05234      
05235     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05236     Created:    12/1/95       
05237     Inputs:     -
05238     Outputs:    -
05239     Returns:    -
05240     Purpose:    Constructor
05241     Errors:     -
05242     SeeAlso:    -
05243 
05244 ********************************************************************************************/
05245 ViewDragTarget::ViewDragTarget(wxWindow* TheWindow, wxRect *ClientArea, DragInformation* pDragInfo)
05246         : OilDragTarget(TheWindow,ClientArea)
05247 {
05248     pThisDoc =  CCamView::GetDocViewFromWindow(TheWindow);
05249     OverOutline = FALSE;
05250     OverNode = NULL;
05251 
05252     pCurrentDragInfo = pDragInfo;
05253 
05254     DocView::GetCurrentMousePos(&pSpread, &DropPos);
05255     
05256     // Find out the Magnetic Line Radius preference from its owner
05257     LineRad = NodeRenderableBounded::MagneticLineRadius;
05258     
05259     // Scale it according to the ScaleFactor.
05260     if (pThisDoc!=NULL)
05261     {
05262         // Get the Scale factor and modify the magnetic radius
05263         double Scale = pThisDoc->GetViewScale().MakeDouble();
05264         LineRad = (INT32) ((double)LineRad / Scale);
05265     }
05266 
05267 }
05268 
05269 
05270 
05271 /********************************************************************************************
05272 
05273 >   void ViewDragTarget::GetCursorID()
05274 
05275     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05276     Created:    10/1/95
05277     Purpose:    Base Method to set cursor over this target
05278 
05279 
05280 ********************************************************************************************/
05281 
05282 UINT32 ViewDragTarget::GetCursorID()
05283 {
05284     ERROR2IF(pCurrentDragInfo==NULL,FALSE,"No DragInfo available when getting Cursor");
05285 
05286     return pCurrentDragInfo->GetCursorID(this);
05287 }
05288 
05289 
05290 
05291 /********************************************************************************************
05292 
05293 >   virtual BOOL ViewDragTarget::GetStatusLineText(String_256 * TheText)
05294 
05295     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05296     Created:    15/1/95
05297     Returns:    Whether String is valid
05298     Purpose:    provide status line text for this target
05299    
05300 ********************************************************************************************/
05301 
05302 
05303 BOOL ViewDragTarget::GetStatusLineText(String_256 * TheText)
05304 {
05305     ERROR2IF(TheText==NULL,FALSE,"NULL string in GetStatusLineText()");
05306     ERROR2IF(pCurrentDragInfo==NULL,FALSE,"No DragInfo available when getting Status Text");
05307 
05308     return pCurrentDragInfo->GetStatusLineText(TheText, this);
05309 }
05310 
05311 /********************************************************************************************
05312 
05313 >   BOOL ViewDragTarget::GetDropInfo(PageDropInfo* pDropInfo)
05314  
05315     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05316     Created:    25/3/95       
05317     Inputs:     -
05318     Outputs:    -
05319     Returns:    -
05320     Purpose:    Get info about the current drag state of this target
05321     Errors:     -
05322     SeeAlso:    -
05323 
05324 ********************************************************************************************/
05325 
05326 BOOL ViewDragTarget::GetDropInfo(PageDropInfo* pDropInfo)
05327 {
05328     ERROR2IF(pDropInfo==NULL,FALSE,"NULL DropInfo pass to GetDropInfo()");
05329 
05330     pDropInfo->pDocView = pThisDoc;
05331     pDropInfo->pDoc     = pThisDoc->GetDoc();
05332     pDropInfo->pSpread  = pSpread;
05333     pDropInfo->DropPos  = DropPos;
05334 
05335     pDropInfo->TargetHit    = OverTarget;
05336     pDropInfo->pObjectHit   = OverNode;
05337 
05338     return TRUE;
05339 }
05340 
05341 /********************************************************************************************
05342 
05343 >   void ViewDragTarget::ProcessEvent(DragEventType Event,
05344                         DragInformation *pDragInfo,
05345                         wxPoint *pMousePos, KeyPress* pKeyPress) 
05346      
05347     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05348     Created:    12/1/95       
05349     Inputs:     -
05350     Outputs:    -
05351     Returns:    -
05352     Purpose:    Event Handler for View Drag target 
05353     Errors:     -
05354     SeeAlso:    -
05355 
05356 ********************************************************************************************/
05357 
05358 BOOL ViewDragTarget::ProcessEvent(DragEventType Event,
05359                         DragInformation *pDragInfo,
05360                         wxPoint *pMousePos, KeyPress* pKeyPress)
05361 {
05362     switch (Event)
05363     {
05364         case DRAGEVENT_INITIALISE:
05365             break;
05366         case DRAGEVENT_DEINITIALISE:
05367             break;
05368         case DRAGEVENT_ABORT:
05369             break;
05370         case DRAGEVENT_KEYPRESS:
05371             break;
05372         case DRAGEVENT_COMPLETED:
05373             {
05374                 // Do another HitTest check
05375                 OverNode = NULL;
05376                 DocView::GetCurrentMousePos(&pSpread, &DropPos);
05377                 OverTarget = pThisDoc->IsPointerOverNode(&OverNode,LineRad,FALSE,TRUE);
05378     
05379                 if (!OverNode) OverTarget = NO_TARGET;
05380     
05381                 // call doc dragfinished to do whatever is needed
05382                 return pThisDoc->DM_DragFinished(pDragInfo,this);
05383                 break;
05384             }
05385         case DRAGEVENT_MOUSESTOPPED:
05386         case DRAGEVENT_MOUSEMOVED:
05387         case DRAGEVENT_MOUSEIDLE:
05388             {
05389                 OverNode = NULL;
05390                 DocView::GetCurrentMousePos(&pSpread, &DropPos);
05391                 OverTarget = pThisDoc->IsPointerOverNode(&OverNode,LineRad, TRUE, TRUE);
05392     
05393                 if (!OverNode) OverTarget = NO_TARGET;
05394     
05395                 return TRUE;
05396                 break;
05397             }
05398         default:
05399             break;
05400     }
05401     return FALSE;
05402 }
05403 
05404 
05405 CViewFileDropTarget::CViewFileDropTarget(CCamView* pView)
05406 {
05407     m_pView = pView;
05408 }
05409 
05410 CViewFileDropTarget::~CViewFileDropTarget()
05411 {
05412 }
05413 
05414 bool CViewFileDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
05415 {
05416     return(m_pView->OnDropFiles(x, y, filenames));
05417 }
05418 

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