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