selector.cpp

Go to the documentation of this file.
00001 // $Id: selector.cpp 1740 2006-09-05 11:08:36Z luke $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // The Selector Tool
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 
00105 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "stockcol.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 #include "csrstack.h"
00108 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "oilkeys.h"
00111 #include "oilfiles.h"
00112 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "osrndrgn.h"
00114 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #include "nodedoc.h"
00116 //#include "selmsg.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "docvmsg.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "selector.h"
00121 #include "selinfo.h"
00122 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "progress.h"
00124 #include "keypress.h"
00125 #include "vkextra.h"
00126 #include "insertnd.h"
00127 #include "nodetxts.h"
00128 
00129 #include "tranlate.h"
00130 #include "opscale.h"
00131 #include "opscale2.h"
00132 #include "opsquash.h"
00133 #include "opshear.h"
00134 #include "opflip.h"
00135 #include "oprotate.h"
00136 #include "guides.h"
00137 #include "layer.h"
00138 //#include "basebar.h"
00139 
00140 //#include "resource.h"
00141 //#include "viewrc.h"
00142 //#include "justin.h"
00143 //#include "markn.h"
00144 //#include "mario.h"
00145 //#include "rik.h"
00146 //#include "selstr.h"
00147 
00148 //#include "will2.h"
00149 //#include "oleprefs.h"
00150 #include "menuops.h"
00151 
00152 // knowledge of these classes is required by tab-selection.
00153 // remove these if/when the Iterate...() methods are virtual-ised.
00154 #include "nodebldr.h"
00155 
00156 
00157 //Matt 11/11/00 - I only wanted a function from the next line...
00158 #include "slicehelper.h"    //For helper functions
00159 
00160 //But I had to include all of these to get it to work!!...
00161 //#include "cxfrech.h"      //For CamelotRecordHandler - in camtypes.h [AUTOMATICALLY REMOVED]
00162 #include "userattr.h"       //For UserAttr
00163 #include "tmpltatr.h"       //For TemplateAttribute
00164 
00165 #include "cartprov.h"
00166 
00167 
00168 DECLARE_SOURCE( "$Revision: 1740 $" );
00169 
00170 // Karim 09/08/2000 - enable the new tab selection-iteration code.
00171 #define NEW_SELECTION_TAB_ITERATION
00172 
00173 #define MIN(a, b)   ((a) < (b) ? (a) : (b))
00174 #define MAX(a, b)   ((a) < (b) ? (b) : (a))
00175 #define CURSORID_UNSET 5000
00176 
00177 // Macro defining whether text should come from resources or should be direct...
00178 #define T(res,string) res
00179 //#define T(res,string) string  //<<<<
00180 
00181 // These are still char* while we wait for resource technology to be developed for modules
00182 TCHAR* SelectorTool::FamilyName = _T("Selection Tools");
00183 TCHAR* SelectorTool::ToolName   = _T("Selector Tool");
00184 TCHAR* SelectorTool::Purpose    = _T("Selecting objects and editing the selection");
00185 TCHAR* SelectorTool::Author     = _T("Justin Flude & Phil Martin");
00186 
00187 SelectorInfoBarOp* SelectorTool::pInfoBarOp = NULL;
00188 BOOL SelectorTool::fSelectorIsCaching = FALSE;
00189 
00190 INT32 SelectorTool::CursorStackID= CURSORID_UNSET;
00191 BOOL SelectorTool::bNormalClickCheckProfileDialog = FALSE;
00192 BOOL SelectorTool::bGlineSAllowed = TRUE;
00193 
00194 
00195 /*********************************************************************************************
00196 
00197     Preference: BlobBorder
00198     Section:    Selection Blob Sizes
00199     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00200     Range:      0 ... 10 (millimetres)
00201     Purpose:    Determines how wide a border, in millimetres, to inflate the bounding
00202                 rectangle of the selected object, when drawing blobs around it.  The
00203                 default is 4 mm.
00204 
00205 **********************************************************************************************/
00206 
00207 INT32 SelectorTool::nBlobBorder = 4;
00208 
00209 // This defines the number of millipoints in a millimetre.
00210 const MILLIPOINT nMPperMM = 2835L;
00211 
00212 
00213 
00214 /*********************************************************************************************
00215 
00216     Preference: InitialBlobs
00217     Section:    Selector Tool
00218     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00219     Range:      0 ... UINT_MAX
00220     Purpose:    Determines which blobs should be initially displayed.  This should really be
00221                 done by the blob manager!
00222 
00223 **********************************************************************************************/
00224 
00225 unsigned SelectorTool::fBlobPref = 1;       // by default, show only bounds/rotate blobs
00226 
00227 
00228 
00229 /*********************************************************************************************
00230 
00231     Preference: AllowCorelToggleClick
00232     Section:    Selector Tool
00233     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00234     Range:      FALSE ... TRUE
00235     Purpose:    If TRUE (the default) allows a single click on a selected object to toggle
00236                 between bounds blobs & rotate blobs, for compatibility with Corel Draw.  This
00237                 toggling option not allowed when Object blobs are shown, it would be a pain.
00238 
00239 **********************************************************************************************/
00240 
00241 BOOL SelectorTool::fAllowCorelToggleClick = TRUE;
00242 
00243 
00244 
00245 /*********************************************************************************************
00246 
00247     Preference: SelectUnderLikeArtWorks
00248     Section:    Selector Tool
00249     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00250     Range:      FALSE ... TRUE
00251     Purpose:    If TRUE then the select-under feature, Alt-Click, works exactly like ArtWorks,
00252                 so that an Alt-Click on an unselected object selects that object rather than
00253                 the object underneath.  If FALSE then Alt-Click always selects an object
00254                 underneath the clicked object, irrespective of whether the clicked object
00255                 was selected or not.  The default is FALSE, as this is consistent with the
00256                 way that select-inside works.
00257 
00258 **********************************************************************************************/
00259 
00260 BOOL SelectorTool::fSelectUnderLikeArtWorks = FALSE;
00261 
00262 
00263 
00264 /*********************************************************************************************
00265 
00266     Preference: SlaveLineWidthToButton
00267 
00268     Section:    Selector Tool
00269     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00270     Created:    26/2/96
00271 
00272     Range:      Boolean
00273     Purpose:    Controls whether attributes (line widths mainly) are considered when 
00274                 calculating bounding rectangles for objects. This is used when displaying
00275                 and editing width/height information in the infobar.
00276 
00277                 If TRUE, the "Scale Line Widths" button will also control the behaviour
00278                 of the function SelectorInfoBarOp::DontConsiderAttrs() - if the button is
00279                 depressed, Attrs will not be considered, and vice versa.
00280 
00281                 If FALSE, the behaviour will be fixed, and controlled by the preference
00282                 "ConsiderLineWidths" in the "Selector Tool" section.
00283 
00284                 The default setting (TRUE) is to determine the state from the button setting.
00285 
00286     Notes:      This preference is read by our associated SelectorInfoBarOp
00287                 This preference is not currently written by camelot
00288 
00289 **********************************************************************************************/
00290 
00291 BOOL SelectorTool::fSlaveLineWidthToButton = TRUE;
00292 
00293 
00294 
00295 /*********************************************************************************************
00296 
00297     Preference: ConsiderLineWidths
00298 
00299     Section:    Selector Tool
00300     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00301     Created:    26/2/96
00302 
00303     Range:      Boolean
00304     Purpose:    Controls whether attributes (line widths mainly) are considered when 
00305                 calculating bounding rectangles for objects. This is used when displaying
00306                 and editing width/height information in the infobar.
00307 
00308                 This preference is IGNORED if the "SlaveLineWidthToButton" pref is TRUE.
00309 
00310                 The default setting (FALSE) is to ignore line widths in these displays.
00311 
00312     Notes:      This preference is read by our associated SelectorInfoBarOp
00313                 This preference is not currently written by camelot
00314 
00315 **********************************************************************************************/
00316 
00317 BOOL SelectorTool::fConsiderLineWidths = FALSE;
00318 
00319 
00320 
00321 /*********************************************************************************************
00322 
00323     Preference: fUseScalingFix
00324 
00325     Section:    Selector Tool
00326     Author:     Harrison_Ainsworth (Xara Group Ltd) <camelotdev@xara.com>
00327     Created:    13/11/97
00328 
00329     Range:      Boolean
00330     Purpose:    Controls whether my scaling fix is used
00331 
00332                 The default setting (FALSE) is to *not* use the new scaling fix
00333 
00334     Notes:      This preference is read by our associated SelectorInfoBarOp
00335                 This preference is not currently written by camelot
00336 
00337 **********************************************************************************************/
00338 
00339 BOOL SelectorTool::fUseScalingFix = FALSE;
00340 
00341 
00342 
00343 /*********************************************************************************************
00344 
00345     Preference: bPageDoubleClickOpenFile
00346 
00347     Section:    Selector Tool
00348     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00349     Created:    31/05/2005
00350 
00351     Range:      Boolean
00352     Purpose:    Controls whether double-clicking on the page will show the Open dialog
00353 
00354 **********************************************************************************************/
00355 
00356 BOOL SelectorTool::bPageDoubleClickOpenFile = FALSE;
00357 
00358 
00359 
00360 // This is our own permanent pointer to the blob manager.
00361 BlobManager* SelectorTool::pBlobManager = NULL;
00362 
00363 // Run-time type checking etc etc
00364 CC_IMPLEMENT_DYNCREATE(OpSelectorDragBox, Operation)
00365 CC_IMPLEMENT_DYNCREATE(OpDragRotateCentre, Operation)
00366 CC_IMPLEMENT_MEMDUMP(SelectorTool, DragTool)
00367 
00368 // report memory line info
00369 #define new  CAM_DEBUG_NEW
00370 
00371 
00372 
00373 /********************************************************************************************
00374 
00375 >   SelectorTool::SelectorTool()
00376 
00377     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00378     Created:    21/6/93
00379     Purpose:    Dummy Constructor - sets member pointers to NULL and initialises the
00380                 record of which blobs are displayed (initially only "tiny" blobs).
00381     SeeAlso:    SelectorTool::Init
00382 
00383 ********************************************************************************************/
00384 
00385 SelectorTool::SelectorTool()
00386   : //pInfoBarOp(NULL),
00387     fRotateCentreIsValid(FALSE),
00388     eCurrentBlobs(BOUNDS_BLOBS),
00389     fShowToolBlobs(TRUE),
00390     fValidSelectedBlob(FALSE)
00391 {
00392     // initialise all our member pointers to NULL.
00393 
00394     SelectionSpread = NULL;
00395     SelectRange     = NULL;
00396     StartSpread     = NULL;
00397 
00398     pClickSimpleNode    = NULL;
00399     pClickCompoundNode  = NULL;
00400     pLastClickNode      = NULL;
00401     pPreProcClickNode   = NULL;
00402 
00403     pNormalCursor       = NULL;
00404     pAdjustCursor       = NULL;
00405     pUnderCursor        = NULL;
00406     pInsideCursor       = NULL;
00407     pUnderAdjustCursor  = NULL;
00408     pInsideAdjustCursor = NULL;
00409     pLeafCursor         = NULL;
00410     pLeafAdjustCursor   = NULL;
00411 
00412     pALLCursor          = NULL;
00413     pNWSECursor         = NULL;
00414     pNESWCursor         = NULL;
00415     pNSCursor           = NULL;
00416     pWECursor           = NULL;
00417     pGradFillCursor     = NULL;
00418     pDragRotateCursor   = NULL;
00419     pHorzGuideCursor    = NULL;
00420     pVertGuideCursor    = NULL;
00421 
00422     bGlineSAllowed      = TRUE;
00423     m_bComputeAreaDetails   = FALSE;
00424 
00425     // Pre-load the resource we're going to use
00426     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_6) );
00427     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_3) );
00428     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_1) );
00429     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_8) );
00430     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_45) );
00431     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_45) );
00432     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_27) );
00433     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_27) );
00434     (CamArtProvider::Get())->FindBitmap( _R(IDBMP_HANDLE_CENTRE) );
00435 }
00436 
00437 
00438 
00439 /********************************************************************************************
00440 
00441 >   virtual SelectorTool::~SelectorTool()
00442 
00443     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00444     Created:    21/6/93
00445     Purpose:    Destructor (Virtual). Does nothing.
00446 
00447 ********************************************************************************************/
00448 
00449 SelectorTool::~SelectorTool()
00450 {
00451     // empty
00452 }
00453 
00454 
00455 
00456 /********************************************************************************************
00457 
00458 >   virtual BOOL SelectorTool::Init()
00459 
00460     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00461     Created:    21/6/93
00462     Returns:    FALSE if it does not want to be created, TRUE otherwise
00463     Purpose:    Used to check if the Tool was properly constructed
00464     SeeAlso:    SelectorTool::SelectorTool
00465 
00466 ********************************************************************************************/
00467 
00468 BOOL SelectorTool::Init()
00469 {
00470 /*  // Claim the left Alt for our tool.
00471     ToolKeyClaimDetails Mods;
00472     Mods.Value = 0;
00473     Mods.Keys.Alternative1 = TRUE;
00474     ClaimToolKey((Tool*) this, Mods);
00475 */
00476     // Read in the preferences.
00477     if (!ReadPrefs())
00478     {
00479         TRACE( _T("Couldn't read Selector tool's preferences!\n"));
00480         return FALSE;
00481     }
00482 
00483     // Declare the OpDescriptors of each transform.
00484     if (!OpTranslateTrans::Declare() ||
00485         !OpRotateTrans::Declare() ||
00486         !OpScaleTrans::Declare() ||
00487 //      !OpScale2Trans::Declare() ||
00488         !OpShearTrans::Declare() ||
00489         !OpSquashTrans::Declare() ||
00490         !OpFlipTrans::Declare() ||
00491         !OpSelectorDragBox::Declare() ||
00492         !OpDragRotateCentre::Declare())
00493     {
00494         ENSURE(FALSE, "Couldn't 'declare' all OpDescriptors in SelectorTool::Init");
00495         return FALSE;
00496     }
00497 
00498     // This should be set to NULL by default. It will be set properly below, if
00499     // everthing is working as it should
00500     pInfoBarOp = new SelectorInfoBarOp;
00501     
00502     // In the debug version make sure we can create a bar.
00503     ENSURE(pInfoBarOp != NULL, "Failed to create selector tool info-bar");
00504     if (pInfoBarOp == NULL) return FALSE;
00505 
00506     // Get a permanent pointer to the blob manager.
00507     pBlobManager = GetApplication()->GetBlobManager();
00508     ENSURE(pBlobManager != NULL, "Selector tool: couldn't get blob manager");
00509     if (pBlobManager == NULL) return FALSE;
00510 
00511     // Get a permanent pointer to the application's SelRange object.
00512     SelectRange = GetApplication()->FindSelection();
00513 
00514     // set the initial state of the blob buttons
00515     bsBlobStyle.Object   = (fBlobPref & 2) != 0;
00516     bsBlobStyle.Fill     = (fBlobPref & 4) != 0;
00517     bsBlobStyle.Artistic = (fBlobPref & 8) != 0;
00518     bsBlobStyle.ToolObject = TRUE;
00519     bsBlobStyle.Effect  = FALSE;
00520 
00521     // Object blobs & Tiny blobs are mutually exclusive.
00522     bsBlobStyle.Tiny     = !bsBlobStyle.Object;
00523     
00524     // If we are displaying tool blobs then decide whether they are bounds or rotate blobs.
00525     fShowToolBlobs = (fBlobPref & 1) != 0;
00526     eCurrentBlobs = (pInfoBarOp->InRotateMode()) ? ROTATE_BLOBS : BOUNDS_BLOBS;
00527     
00528     // Success!!
00529     return TRUE;
00530 }
00531 
00532 
00533 
00534 /********************************************************************************************
00535 
00536 >   static BOOL SelectorTool::ReadPrefs()
00537 
00538     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00539     Created:    15/8/94
00540     Inputs:     -
00541     Outputs:    -
00542     Returns:    TRUE if successful.
00543     Purpose:    Reads settings concerning the selector tool from the .INI file.
00544     Errors:     -
00545     SeeAlso:    SelectorTool::Init
00546 
00547 ********************************************************************************************/
00548 
00549 BOOL SelectorTool::ReadPrefs()
00550 {
00551     return  Camelot.DeclareSection(TEXT("Selector Tool"), 10) &&
00552             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("BlobBorder"),
00553                                 &nBlobBorder, 0, 10) &&
00554             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("LockAspect"),
00555                                 &SelectorInfoBarOp::fLockAspect, FALSE, TRUE) &&
00556 //         Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("LeaveCopy"),
00557 //                             &SelectorInfoBarOp::fLeaveCopy,  FALSE, TRUE) &&
00558 //         Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("TransFills"),
00559 //                             &SelectorInfoBarOp::fTransFills, FALSE, TRUE) &&
00560             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("ScaleLines"),
00561                                 &SelectorInfoBarOp::fScaleLines, FALSE, TRUE) &&
00562             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("InitialBlobs"),
00563                                 &SelectorTool::fBlobPref, 0, UINT_MAX) &&
00564             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("AllowCorelToggleClick"),
00565                                 &SelectorTool::fAllowCorelToggleClick, FALSE, TRUE) &&
00566             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("SelectUnderLikeArtWorks"),
00567                                 &SelectorTool::fSelectUnderLikeArtWorks, FALSE, TRUE) &&
00568 
00569             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("SlaveLineWidthToButton"), &fSlaveLineWidthToButton) &&
00570             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("ConsiderLineWidths"), &fConsiderLineWidths) &&
00571             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("UseScalingFix"), &fUseScalingFix) &&
00572             Camelot.DeclarePref(TEXT("Selector Tool"), TEXT("PageDoubleClickOpenFile"), &bPageDoubleClickOpenFile)
00573             ;
00574 }
00575 
00576 
00577 
00578 /********************************************************************************************
00579 
00580 >   virtual void SelectorTool::Describe(void *InfoPtr)
00581 
00582     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00583     Created:    21/6/93
00584     Inputs:     InfoPtr - A pointer to a tool info block. It is passed cast to void* as
00585                 the version of the tool is unknown at this point. Later versions of the
00586                 Tool class may have more items in this block, that this tool will not use
00587     Outputs:    InfoPtr - The structure pointed to by InfoPtr will have had all the info
00588                 that this version of the Tool knows about
00589     Purpose:    Allows the tool manager to extract information about the tool
00590 
00591 ********************************************************************************************/
00592 
00593 void SelectorTool::Describe(void *InfoPtr)
00594 {
00595     // Cast structure into the latest one we understand.
00596     ToolInfo_v1* Info = (ToolInfo_v1*) InfoPtr;
00597     Info->InfoVersion = 1;
00598     
00599     // You should always have this line.
00600     Info->InterfaceVersion = GetToolInterfaceVersion();  
00601         
00602     // These are all arbitrary at present.
00603     Info->Version = 1;
00604     Info->ID      = GetID();
00605     Info->TextID  = _R(IDS_SELECTOR_TOOL);
00606         
00607     Info->Family  = FamilyName;
00608     Info->Name    = ToolName;
00609     Info->Purpose = Purpose;
00610     Info->Author  = Author;
00611 //  Info->ToolBoxBitmap = _R(IDB_SELR_TOOLBOX);
00612 //  Info->ToolBoxBitmapActive = _R(IDB_SELR_TOOLBOX_ACTIVE);
00613     
00614     Info->InfoBarDialog = 0;
00615     Info->BubbleID = _R(IDBBL_SEL_TOOLICON);
00616 }
00617 
00618 
00619 
00620 /********************************************************************************************
00621 
00622 >   virtual void SelectorTool::SelectChange(BOOL isSelected)
00623 
00624     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00625     Created:    24/11/93
00626     Inputs:     isSelected  -   TRUE if this tool is becoming current, FALSE
00627                                 otherwise
00628     Purpose:    Called whenever this tool is selected or deselected.
00629 
00630                 Performs jobs related to changing tools, eg changing the cursor to a
00631                 selector cursor, changing the displayed tool blobs to selector tool blobs,
00632                 changing the preferences for BlobManager-rendered blobs.
00633 
00634     Errors:     Debug warning if creating the cursor fails.
00635 
00636 ********************************************************************************************/
00637 
00638 void SelectorTool::SelectChange(BOOL isSelected)
00639 {
00640     if (isSelected)
00641     {
00642         // Load the grad-fill cursor etc.
00643         pGradFillCursor     = new Cursor(this, _R(IDCSR_SEL_GRADPOINT));
00644         pNormalCursor       = new Cursor(this, _R(IDCSR_SEL_NORMAL));
00645         pAdjustCursor       = new Cursor(this, _R(IDCSR_SEL_ADJUST));
00646         pUnderCursor        = new Cursor(this, _R(IDCSR_SEL_UNDER));
00647         pInsideCursor       = new Cursor(this, _R(IDCSR_SEL_INSIDE));
00648         pUnderAdjustCursor  = new Cursor(this, _R(IDCSR_SEL_UNDERADJUST));
00649         pInsideAdjustCursor = new Cursor(this, _R(IDCSR_SEL_INSIDEADJUST));
00650         pALLCursor          = new Cursor(this, _R(IDCSR_SEL_GRADPOINT));
00651         pLeafCursor         = new Cursor(this, _R(IDCSR_SEL_LEAF));
00652         pLeafAdjustCursor   = new Cursor(this, _R(IDCSR_SEL_LEAFADJUST));
00653         pNWSECursor         = new Cursor(this, _R(IDCSR_SIZENWSE));
00654         pNESWCursor         = new Cursor(this, _R(IDCSR_SIZENESW));
00655         pNSCursor           = new Cursor(this, _R(IDCSR_SIZENS));
00656         pWECursor           = new Cursor(this, _R(IDCSR_SIZEWE));
00657         pDragRotateCursor   = new Cursor(this, _R(IDCSR_SEL_GRADPOINT));
00658         pHorzGuideCursor    = new Cursor(this, _R(IDCSR_SEL_HGUIDE));
00659         pVertGuideCursor    = new Cursor(this, _R(IDCSR_SEL_VGUIDE));
00660         
00661         // This tool has just been selected.  Push an appropriate cursor.
00662         CursorStackID = CursorStack::GPush(pNormalCursor);
00663 
00664         // Initially we know of no selection, above or below.
00665         SelectionSpread = NULL;
00666         pClickSimpleNode = NULL;
00667         pClickCompoundNode = NULL;
00668         pLastClickNode = NULL;
00669         pPreProcClickNode = NULL;
00670 
00671         // Reset these flags used within the click logic etc.
00672         fIsBlobDrag = fPossibleToggleClick = fIgnoreSelChange = FALSE;
00673         fAllowIdleProcessing = fMouseHasMoved = TRUE;
00674 
00675         // Create and display my info bar please
00676         if (pInfoBarOp != NULL)
00677         {
00678             pInfoBarOp->pSelectorTool = this;
00679             if(pInfoBarOp->WindowID == NULL)
00680             {
00681                 // set its pointer to me and call its create() function to get it to set its
00682                 // controls
00683                 pInfoBarOp->Create();
00684             }
00685             else
00686             {
00687                 pInfoBarOp->Open();
00688                 pInfoBarOp->MakeCurrent();
00689             }
00690         }
00691 
00693         // Version 1.0 of Camelot doesn't have ArtLines, so make sure their blobs
00694         // are always OFF.
00695         bsBlobStyle.Artistic = FALSE;
00696         bsBlobStyle.Effect  = FALSE;
00698         
00699         // Which blobs do I want displayed
00700 // >>>> Commented on advice from Rik
00701 //      if (Document::GetCurrent() != NULL)
00702 //      {
00703             // Tell the blob manager about our blobs.
00704             if (pBlobManager != NULL)
00705                 pBlobManager->ToolInterest(bsBlobStyle);
00706 //      }
00707 
00708         // Note that whenever we switch to the selector we always start in bounds
00709         // rather than rotate mode.
00710         eCurrentBlobs = BOUNDS_BLOBS;
00711         SelectorInfoBarOp::fRotateMode = FALSE;
00712         if (pInfoBarOp != NULL)
00713         {
00714             // Make sure the info-bar reflects the state of this.
00715             pInfoBarOp->SetRotateMode(SelectorInfoBarOp::fRotateMode);
00716         }
00717 
00718         // Get the initial selection, if any, and render the blobs.
00719         if (UpdateSelectionInfo()) pBlobManager->RenderToolBlobsOn(this, SelectionSpread, NULL);
00720     }
00721     else
00722     {
00723         // Deselection - pop the tool's cursor(s).
00724         CursorStack::GPop(CursorStackID);
00725         CursorStackID=CURSORID_UNSET;
00726 
00727         // Delete the grad-fill cursor etc.
00728         delete pGradFillCursor;
00729         delete pNormalCursor;
00730         delete pInsideCursor;
00731         delete pAdjustCursor;
00732         delete pUnderCursor;
00733         delete pUnderAdjustCursor;
00734         delete pInsideAdjustCursor;
00735         delete pLeafCursor;
00736         delete pLeafAdjustCursor;
00737         delete pALLCursor;
00738         delete pNWSECursor;
00739         delete pNESWCursor;
00740         delete pNSCursor;
00741         delete pWECursor;
00742         delete pDragRotateCursor;
00743         delete pHorzGuideCursor;
00744         delete pVertGuideCursor;
00745         
00746         // Use this flag to avoid an unsightly redraw when simply changing tools.
00747         fSelectorIsCaching = TRUE;
00748         
00749         // Hide and destroy the info bar.
00750         if (pInfoBarOp != NULL)
00751         {
00752             // Make sure that the info bars pointer here is set to null and close itself down.
00753             // But NOT if the application is on the way out
00754             if (pInfoBarOp->HasWindow() && !GetApplication()->CamelotIsDying() )
00755                 pInfoBarOp->Close();
00756             pInfoBarOp->pSelectorTool = NULL;
00757             pInfoBarOp->Delete();
00758         }
00759 
00760         fSelectorIsCaching = FALSE;
00761         
00762         // ensure any tool object blobs are removed.
00763         if (pBlobManager != NULL)
00764         {
00765             BlobStyle bsRemoves;
00766             bsRemoves.ToolObject = TRUE;
00767             pBlobManager->RemoveInterest(bsRemoves);
00768         }
00769 
00770         // If there is a spread with the selection on it, there is still a view,
00771         // and the tool blobs are being displayed, then render them off
00772         pBlobManager->RenderToolBlobsOff(this, SelectionSpread, NULL);
00773     }
00774 }
00775 
00776 /********************************************************************************************
00777 
00778 >   static void SelectorTool::UnCacheInfoBar(BOOL Force)
00779 
00780     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00781     Created:    13/10/94
00782     Inputs:     Force Flag - will be deleted even if current
00783     Outputs:    -
00784     Returns:    -
00785     Purpose:    deletes the cached infobar and sets it's ID to NULL -this is normally called
00786                 when the selector is not the current tool - 
00787                 it can be forced however(on close down etc..)
00788     Errors:     -
00789     SeeAlso:    -
00790 
00791 ********************************************************************************************/
00792 
00793 void SelectorTool::UnCacheInfoBar(BOOL Force)
00794 {
00795     if (pInfoBarOp)
00796     {
00797         // normally we would only uncache the infobar if we were not the current tool
00798         // but there are occasions when we might need to force it
00799         if (pInfoBarOp->pSelectorTool == NULL || Force)
00800         { 
00801             pInfoBarOp->Delete();   
00802             pInfoBarOp->WindowID = NULL;
00803         }
00804     }
00805 }
00806 
00807 
00808 
00809 
00810 /********************************************************************************************
00811 
00812 >   virtual void SelectorTool::OnMouseMove(DocCoord dcPos, Spread* pSpread, ClickModifiers mods)
00813 
00814     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00815     Created:    31/8/94
00816     Inputs:     dcPos       the current position of the mouse (spread coord)
00817                 pSpread     the spread containing the mouse
00818                 mods        the mouse modifiers, eg. Adjust, Constrain etc
00819     Outputs:    -
00820     Returns:    -
00821     Purpose:    Called by the tool system for the current tool when the mouse is moved
00822                 outside of a drag.  Checks if the mouse is over one of the tool's blobs,
00823                 changing the cursor appropriately if it is.
00824     Errors:     -
00825     SeeAlso:    SelectorTool::ChangeCursor; SelectorTool::IsNearBlob
00826 
00827 ********************************************************************************************/
00828 
00829 void SelectorTool::OnMouseMove(DocCoord dcPos, Spread* pSpread, ClickModifiers mods)
00830 {
00831     // Note that the mouse has moved so we know to update the status-bar text on the next
00832     // idle event.
00833     fMouseHasMoved = TRUE;
00834 
00835     // Make sure the cursor reflects which keys are down.  It is possible for the modifier
00836     // keys to change state without key-events being generated, so we must check this on
00837     // every mouse move.
00838 //  ResetCursorNow();
00839     // Make sure the cursor reflects which keys are down.  It is possible for the modifier
00840     // keys to change state without key-events being generated, so we must check this on
00841     // every mouse move.
00842     // (That means prepare the global vars for us by GetClickModifiers in FigureUserFeedback)
00843 //  StartSpread = pSpread;
00844 //  ClickMods = mods;
00845 //  ClickStart = dcPos;
00846 
00847     // If there isn't any selection, or it's in a different spread, then do nothing.
00848 //  if (SelectionSpread == NULL || SelectionSpread != pSpread)
00849 //      return;
00850     
00851     String_256 str;
00852     Cursor* pPointerShape;
00853 
00854     FigureUserFeedback(pSpread, dcPos, mods, FALSE, &str, &pPointerShape);
00855 
00856     if (!(str.IsEmpty()))
00857         SetStatusText(&str);
00858 
00859     if (CursorStackID!=CURSORID_UNSET)
00860         CursorStack::GSetTop(pPointerShape,CursorStackID);
00861 }
00862 
00863 
00864 
00865 /********************************************************************************************
00866 
00867 >   virtual BOOL SelectorTool::OnKeyPress(KeyPress* pKey)
00868 
00869     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00870     Created:    22/11/94
00871     Inputs:     pKey            pointer to a key-press object representing a keystroke.
00872     Outputs:    -
00873     Returns:    TRUE if the key-event is handled, FALSE if not.
00874     Purpose:    Called when a key is pressed of released.  If the key is a "click modifier"
00875                 such as the ALT or CTRL key then the cursor is changed to indicate whatever
00876                 the tool can do with that modifier.
00877     Errors:     -
00878     SeeAlso:    -
00879 
00880 ********************************************************************************************/
00881 
00882 BOOL SelectorTool::OnKeyPress(KeyPress* pKey)
00883 {
00884     // Find the current state of the "click" keyboard modifiers...
00885     ClickMods = ClickModifiers::GetClickModifiers();
00886 
00887     switch (pKey->GetVirtKey())
00888     {
00889 
00890 // >>>> BODGE! These cases are only here to prevent the messages
00891 //              being passed on to other key handlers (very slow!)
00892     case CAMKEY(CC_MOD_ADJUST):                     // bit 0 of fKeyStates (SHIFT)
00893         break;
00894 
00895     case CAMKEY(CC_MOD_ALTERNATIVE):                    // bit 1 of fKeyStates (ALT)
00896         break;
00897 
00898     case CAMKEY(CC_MOD_CONSTRAIN):                  // bit 2 of fKeyStates (CONTROL)
00899         break;
00900 // >>>> End
00901 
00902     case CAMKEY(TAB):                               // moves selection to next rendered node
00903         if( pKey->IsConstrain() )
00904             return FALSE;           // We have other uses for Ctrl+Tab (switch document)
00905 
00906         if (pKey->IsPress()) HandleTabKey(ClickMods.Adjust);
00907         break;
00908 
00909     case CAMKEY(1):                                 // toggle tool blobs
00910         if (pKey->IsModified()) 
00911         {
00912             // if Ctrl/Alt/Shift is down, pass the message on to another handler
00913             // instead of 'absorbing' the keypress
00914             return FALSE;
00915         }
00916         if (pKey->IsPress() && !pKey->IsModified())
00917         {
00918             BoundsButtonChange();
00919             if (pInfoBarOp != NULL)
00920             {
00921                 pInfoBarOp->SetLongGadgetValue(_R(IDC_SEL_SHOWBOUNDSBLOBS), fShowToolBlobs, FALSE);
00922             }
00923         }
00924         break;
00925 
00926     case CAMKEY(2):                                 // toggle edit blobs
00927         if (pKey->IsModified()) 
00928         {
00929             return FALSE;
00930         }
00931         if (pKey->IsPress() && !pKey->IsModified())
00932         {
00933             BlobStyle bs(TRUE);
00934             SelectionBlobChange(bs);
00935             if (pInfoBarOp != NULL)
00936             {
00937                 pInfoBarOp->SetLongGadgetValue(_R(IDC_SEL_SHOWOBJECTBLOBS), bsBlobStyle.Object, FALSE);
00938             }
00939         }
00940         break;
00941 
00942     case CAMKEY(3):                                 // toggle fill blobs
00943         if (pKey->IsModified()) 
00944         {
00945             return FALSE;
00946         }
00947         if (pKey->IsPress() && !pKey->IsModified())
00948         {
00949             BlobStyle bs(FALSE, FALSE, TRUE);
00950             SelectionBlobChange(bs);
00951             if (pInfoBarOp != NULL)
00952             {
00953                 pInfoBarOp->SetLongGadgetValue(_R(IDC_SEL_SHOWFILLBLOBS), bsBlobStyle.Fill, FALSE);
00954             }
00955         }
00956         break;
00957 
00958     case CAMKEY(HOME):                              // select first object in render order
00959         if (pKey->IsPress())
00960         {
00961             if (SelectionSpread != NULL) NodeRenderableInk::DeselectAll();
00962             HandleTabKey(FALSE);
00963         }
00964         break;
00965 
00966     case CAMKEY(END):                               // select last object in render order
00967         if (pKey->IsPress())
00968         {
00969             if (SelectionSpread != NULL) NodeRenderableInk::DeselectAll();
00970             HandleTabKey(TRUE);
00971         }
00972         break;
00973 
00974     case CAMKEY(4):                                 // toggle bounds/rotate blobs
00975         if (pKey->IsModified()) 
00976         {
00977             return FALSE;
00978         }
00979         if (pKey->IsPress() && !pKey->IsModified())
00980         {
00981             RotateButtonChange(SelectorInfoBarOp::fRotateMode = !SelectorInfoBarOp::fRotateMode);
00982             if (pInfoBarOp != NULL)
00983             {
00984                 pInfoBarOp->SetLongGadgetValue(_R(IDC_SEL_ROTATEBUTTON), SelectorInfoBarOp::fRotateMode,
00985                                                FALSE);
00986             }
00987         }
00988         break;
00989 
00990     default:                                    // not interested in processing this
00991         return FALSE;
00992     }   
00993 
00994     // If we processed a click modifier then update the cursor and return that we processed
00995     // the keystroke.
00996         SetKeyDownCursor(ClickMods);
00997 
00998     // Yes, we processed this key-event.
00999     return TRUE;
01000 }
01001 
01002 
01003 
01004 /********************************************************************************************
01005 
01006 >   void SelectorTool::SetKeyDownCursor(ClickModifiers cmods)
01007 
01008     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01009     Created:    1/12/94
01010     Inputs:     -
01011     Outputs:    -
01012     Returns:    -
01013     Purpose:    Decodes the bit-field fKeyStates, indicating which combination of modifier
01014                 keys are down, and sets the cursor appropriately.
01015     Errors:     -
01016     SeeAlso:    SelectorTool::OnKeyPress; SelectorTool::OnMouseMove
01017 
01018 ********************************************************************************************/
01019 
01020 void SelectorTool::SetKeyDownCursor(ClickModifiers cmods)
01021 {
01022     // Get current position information for call to change pointer shape...
01023     Spread*  pSpread;
01024     DocCoord dcMousePos;
01025     if( DocView::GetCurrentMousePos( &pSpread, &dcMousePos ) &&
01026         Tool::GetCurrentID()== TOOLID_SELECTOR )
01027 PORTNOTE("other", "Removed bar drag usage")
01028 #ifndef EXCLUDE_FROM_XARALX
01029         && !BaseBar::IsDragging())
01030 #endif
01031     {
01032 //      StartSpread = pSpread;
01033 //      ClickStart = dcMousePos;
01034         // Call nice central routine to figure out what pointer shape to show...
01035         // (Set the status bar text while we're at it.)
01036         String_256 Str;
01037         Cursor* pPtr;
01038         FigureUserFeedback(pSpread, dcMousePos, cmods, TRUE, &Str, &pPtr);
01039         if (CursorStackID!=CURSORID_UNSET)
01040             CursorStack::GSetTop(pPtr,CursorStackID);
01041         if (!(Str.IsEmpty()))
01042             SetStatusText( &Str );
01043     }
01044 }
01045 
01046 
01047 
01048 /********************************************************************************************
01049 
01050 >   void SelectorTool::ResetCursorNow()
01051 
01052     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01053     Created:    13/1/95
01054     Inputs:     -
01055     Outputs:    -
01056     Returns:    -
01057     Purpose:    Called when a mouse button-up event or end-of-drag event occurs.  It resets
01058                 the cursor according to which modifier keys are up or down, without a key
01059                 event having to take place.
01060     Errors:     -
01061     SeeAlso:    SelectorTool::SetKeyDownCursor; SelectorTool::HandleDragClick;
01062                 SelectorTool::HandleButtonUp; SelectorTool::OnMouseMove
01063 
01064 ********************************************************************************************/
01065 
01066 void SelectorTool::ResetCursorNow()
01067 {
01068     // Make sure the cursor reflects which keys are down.  It is possible for the modifier
01069     // keys to change state without key-events being generated, so we must check this on
01070     // every mouse move.
01071     SetKeyDownCursor(ClickModifiers::GetClickModifiers());
01072 }
01073 
01074 
01075 
01076 /********************************************************************************************
01077 
01078 >   static void SelectorTool::AllowIdleWork(BOOL fIsAllowed)
01079 
01080     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01081     Created:    14/10/94
01082     Inputs:     fIsAllowed          if TRUE then the tool will act on idle events, if FALSE
01083                                     the tool will ignore idle events.
01084     Outputs:    -
01085     Returns:    -
01086     Purpose:    Turns idle processing on or off.  During idle events the selector tool
01087                 updates the status bar, so if a drag operation, for instance, wants to
01088                 place its own text in the status bar while it is running it should call
01089                 this function at its start and at its end.
01090     Errors:     -
01091     SeeAlso:    SelectorTool::OnIdle
01092 
01093 ********************************************************************************************/
01094 
01095 void SelectorTool::AllowIdleWork(BOOL fIsAllowed)
01096 {
01097     // Make sure the selector is the current tool.
01098     ERROR3IF(Tool::GetCurrent() == NULL || Tool::GetCurrent()->GetID() != TOOLID_SELECTOR,
01099                 "Selector isn't current tool in SelectorTool::AllowIdleWork");
01100 
01101     if (Tool::GetCurrent() != NULL && Tool::GetCurrent()->GetID() == TOOLID_SELECTOR)
01102     {
01103         // Set the flag.
01104 #ifndef SELECTION_AREA_FEATURE
01105         ((SelectorTool*) Tool::GetCurrent())->fAllowIdleProcessing = fIsAllowed;
01106 #else
01107         ((SelectorTool*) Tool::GetCurrent())->fAllowIdleProcessing = fIsAllowed;
01108 //      ((SelectorTool*) Tool::GetCurrent())->fAllowIdleProcessing = (fIsAllowed || m_bComputeAreaDetails);
01109 #endif
01110     }
01111 // >>>>
01112 //((SelectorTool*) Tool::GetCurrent())->fAllowIdleProcessing = FALSE;
01113 }
01114 
01115 
01116 
01117 /********************************************************************************************
01118 
01119 >   virtual BOOL SelectorTool::OnIdle()
01120 
01121     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01122     Created:    12/10/94
01123     Inputs:     -
01124     Outputs:    -
01125     Returns:    TRUE if idle events are still required (currently always returns TRUE).
01126     Purpose:    Called on idle events.  Performs hit-detection on the current mouse position
01127                 and updates the status-bar text accordingly.
01128     Errors:     -
01129     SeeAlso:    -
01130 
01131 ********************************************************************************************/
01132 
01133 BOOL SelectorTool::OnIdle()
01134 {
01135 #ifdef SELECTION_AREA_FEATURE
01136     if (m_bComputeAreaDetails)
01137     {
01138         BOOL bNeedsMoreTime = SelectRange->GetAreaDetailsWhileIdle(&xlSelectionArea, &xlSelectionPerim);
01139         if (!bNeedsMoreTime)
01140         {
01141             pInfoBarOp->SetEdit_OnSelectionChange();
01142             pInfoBarOp->UpdateAllRecords();
01143