00001 // $Id: slicetool.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // Implementation of the Slice tool 00099 00100 // standard includes for a tool 00101 #include "camtypes.h" 00102 #include "oilfiles.h" 00103 #include "csrstack.h" 00104 //#include "viewrc.h" 00105 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 //#include "markn.h" 00108 00109 #include "layer.h" // knowing about layers 00110 //#include "document.h" // being able to get the spread - in camtypes.h [AUTOMATICALLY REMOVED] 00111 #include "slice.h" // for the export slices op 00112 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 //#include "ink.h" // knowing about ink nodes - in camtypes.h [AUTOMATICALLY REMOVED] 00114 #include "sprdmsg.h" // SpreadMsg 00115 #include "layermsg.h" // the layer messaging 00116 00117 #include "barcreationdlg.h" // for the create dlg 00118 00119 #include "slicetool.h" // <******* Remember to change to include the tool's header file 00120 //#include "sliceres.h" // most of the resources that this tool uses 00121 //#include "simon.h" // some string resources 00122 00123 // for the use of wix temple attribs 00124 //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00125 //#include "attrval.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00126 #include "userattr.h" 00127 #include "tmpltatr.h" 00128 00129 // named set stuff 00130 #include "ngcore.h" 00131 #include "ngitem.h" 00132 #include "ngsentry.h" 00133 00134 #include "selall.h" // for OPTOKEN_EDITSELECTNONE 00135 #include "bitfilt.h" // for the get spread bounds 00136 00137 #include "slicehelper.h" 00138 #include "opdupbar.h" // bar duplication 00139 #include "blobs.h" // for the blob manager? 00140 00141 #include "selector.h" // for OpSelectorDragBox 00142 #include "guides.h" // for NodeGuideline 00143 #include "keypress.h" // for KeyPress 00144 #include "basebar.h" // for BaseBar 00145 #include "nodetxts.h" // for TextStory 00146 #include "opdragbx.h" // for OpDragBox 00147 #include "progress.h" // for BeginSlowJob() 00148 00149 #include "vkextra.h" // for CAMKEY(CC_)... key defs 00150 //#include "justin.h" // for _R(IDS_SLICE_MODE0) etc. 00151 //#include "will2.h" // for _R(IDS_SELOPTIONS) 00152 //#include "resource.h" // for _R(IDS_OUT_OF_MEMORY) and _R(IDS_OK) 00153 00154 //#include "clikdrag.h" // for _R(IDS_TRANSLTRANS_)... 00155 00156 #include "opdupbar.h" // for the showlayer stuff 00157 00158 // enable slice-tool blobs. 00159 #define SLICETOOL_BLOBS 00160 00161 void UpdateCurrentStateGadget(); // forward def 00162 00163 DECLARE_SOURCE( "$Revision: 1282 $" ); 00164 00165 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 00166 #define MAX(a, b) ((a) < (b) ? (b) : (a)) 00167 #define CURSORID_UNSET 5000 00168 00169 CC_IMPLEMENT_MEMDUMP(SliceTool, DragTool) 00170 CC_IMPLEMENT_DYNCREATE(SliceInfoBarOp, InformationBarOp) 00171 CC_IMPLEMENT_DYNCREATE(OpSliceDragBox, OpSelectorDragBox) 00172 CC_IMPLEMENT_DYNCREATE(OpSliceTranslate, TransOperation) 00173 00174 // Must come after the last CC_IMPLEMENT.. macro 00175 #define new CAM_DEBUG_NEW 00176 00177 // These are still char* while we wait for resource technology to be developed for modules 00178 char* SliceTool::FamilyName = "Slice Tools"; 00179 char* SliceTool::ToolName = "Slice Tool"; 00180 char* SliceTool::Purpose = "Slice manipulation"; 00181 char* SliceTool::Author = "Simon K"; 00182 00183 // Init those other useful static vars 00184 BOOL SliceTool::CurrentTool = FALSE; 00185 SliceInfoBarOp* SliceTool::pSliceInfoBarOp = NULL; 00186 00187 // global variable to remember what bar we were working on between switching tools 00188 String_256 g_BarName; 00189 00190 /******************************************************************************************** 00191 00192 > SliceTool::SliceTool() 00193 00194 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00195 Created: 3/10/94 00196 Purpose: Default Constructor. 00197 Other initialisation is done in SliceTool::Init which is called by the Tool Manager 00198 SeeAlso: SliceTool::Init 00199 00200 ********************************************************************************************/ 00201 00202 SliceTool::SliceTool() 00203 { 00204 // initialise all our member pointers to NULL. 00205 00206 pcNormalSliceCursor = NULL; 00207 pcAdjustCursor = NULL; 00208 pcUnderCursor = NULL; 00209 pcInsideCursor = NULL; 00210 pcUnderAdjustCursor = NULL; 00211 pcInsideAdjustCursor = NULL; 00212 pcLeafCursor = NULL; 00213 pcLeafAdjustCursor = NULL; 00214 00215 pcCurrentCursor = NULL; 00216 pcALLCursor = NULL; 00217 pcHorzGuideCursor = NULL; 00218 pcVertGuideCursor = NULL; 00219 00220 StartSpread = NULL; 00221 SelectionSpread = NULL; 00222 SelectRange = NULL; 00223 00224 pClickSimpleNode = NULL; 00225 pClickCompoundNode = NULL; 00226 pLastClickNode = NULL; 00227 pPreProcClickNode = NULL; 00228 } 00229 00230 /******************************************************************************************** 00231 00232 > SliceTool::~SliceTool() 00233 00234 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00235 Created: 3/10/94 00236 Purpose: Destructor (Virtual). Does nothing. 00237 00238 ********************************************************************************************/ 00239 00240 SliceTool::~SliceTool() 00241 { 00242 } 00243 00244 00245 /******************************************************************************************** 00246 00247 > BOOL SliceTool::Init( INT32 Pass ) 00248 00249 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00250 Created: 3/10/94 00251 Returns: FALSE if it does not want to be created, TRUE otherwise 00252 Purpose: Used to check if the Tool was properly constructed 00253 SeeAlso: SliceTool::SliceTool 00254 00255 ********************************************************************************************/ 00256 00257 BOOL SliceTool::Init() 00258 { 00259 // declare all ops used by SliceTool. 00260 BOOL ok = OpSliceDragBox::Declare(); 00261 if (ok) ok = OpSliceTranslate::Declare(); 00262 ERROR2IF(!ok, FALSE, "Couldn't Declare all Ops in SliceTool::Init."); 00263 00264 // This section reads in the infobar definition and creates an instance of 00265 // SliceInfoBarOp. Also pSliceInfoBarOp, the ptr to the tool's infobar, is set up 00266 // after the infobar is successfully read and created. 00267 if (ok) 00268 { 00269 CCResTextFile file; // Resource File 00270 SliceInfoBarOpCreate BarCreate; // Object that creates SliceInfoBarOp objects 00271 00272 ok = file.open(_R(IDM_SLICE_BAR), _R(IDT_INFO_BAR_RES)); // Open resource 00273 if (ok) ok = DialogBarOp::ReadBarsFromFile(file,BarCreate); // Read and create info bar 00274 if (ok) file.close(); // Close resource 00275 00276 ENSURE(ok,"Unable to load Slicebar.ini from resource\n"); 00277 00278 if (ok) 00279 { 00280 // Info bar now exists. Now get a pointer to it 00281 String_32 str = String_32(_R(IDS_SLICETOOL_INFOBARNAME)); 00282 DialogBarOp* pDialogBarOp = DialogBarOp::FindDialogBarOp(str); 00283 00284 ok = (pDialogBarOp != NULL); 00285 if (ok) ok = pDialogBarOp->IsKindOf(CC_RUNTIME_CLASS(SliceInfoBarOp)); 00286 if (ok) pSliceInfoBarOp = (SliceInfoBarOp*)pDialogBarOp; 00287 00288 ENSURE(ok,"Error finding the Slice tool info bar"); 00289 } 00290 } 00291 00292 // Get a permanent pointer to the application's SelRange object. 00293 SelectRange = GetApplication()->FindSelection(); 00294 00295 // init the global var with the first bar name to create - ie Bar1 00296 g_BarName.MakeMsg(_R(IDS_BARNAME), 1); 00297 00298 return (ok); 00299 } 00300 00301 00302 /******************************************************************************************** 00303 00304 > void SliceTool::Describe(void *InfoPtr) 00305 00306 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00307 Created: 3/10/94 00308 Inputs: InfoPtr - A pointer to a tool info block. It is passed cast to void* as 00309 the version of the tool is unknown at this point. Later versions 00310 of the Tool class may have more items in this block, that this 00311 tool will not use 00312 Outputs: InfoPtr - The structure pointed to by InfoPtr will have had all the info 00313 that this version of the Tool knows about 00314 Purpose: Allows the tool manager to extract information about the tool 00315 00316 ********************************************************************************************/ 00317 00318 void SliceTool::Describe(void *InfoPtr) 00319 { 00320 // Cast structure into the latest one we understand. 00321 ToolInfo_v1 *Info = (ToolInfo_v1 *) InfoPtr; 00322 00323 Info->InfoVersion = 1; 00324 00325 Info->InterfaceVersion = GetToolInterfaceVersion(); // You should always have this line. 00326 00327 // These are all arbitrary at present. 00328 Info->Version = 1; 00329 Info->ID = GetID(); 00330 Info->TextID = _R(IDS_SLICE_TOOL); 00331 00332 Info->Family = FamilyName; 00333 Info->Name = ToolName; 00334 Info->Purpose = Purpose; 00335 Info->Author = Author; 00336 00337 Info->BubbleID = _R(IDBBL_SLICE_TOOLBOX); 00338 } 00339 00340 /******************************************************************************************** 00341 00342 > virtual void SliceTool::SelectChange(BOOL isSelected) 00343 00344 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00345 Created: 3/10/94 00346 Inputs: isSelected - TRUE = tool has been selected 00347 - FALSE = tool has been deselected 00348 Outputs: - 00349 Returns: - 00350 Purpose: Starts up and closes down the Slice tool 00351 Errors: Debug warning if creating the cursor fails. 00352 SeeAlso: - 00353 00354 ********************************************************************************************/ 00355 00356 void SliceTool::SelectChange(BOOL isSelected) 00357 { 00358 if (isSelected) 00359 { 00360 // create the tool's cursors and push the default one onto the stack. 00361 if (!CreateCursors()) return; 00362 CurrentCursorID = CursorStack::GPush(pcNormalSliceCursor, FALSE); 00363 pcCurrentCursor = pcNormalSliceCursor; 00364 00365 // This tool is now the current one. 00366 CurrentTool = TRUE; 00367 00368 // Create and display the tool's info bar. 00369 if (pSliceInfoBarOp->Create()) 00370 pSliceInfoBarOp->SetSliceTool(this); 00371 00372 // register the Slice tool's blob preference with the app. 00373 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00374 if (pBlobMgr != NULL) 00375 { 00376 // we only use Tiny blobs. 00377 BlobStyle bsBlobs; 00378 bsBlobs.Tiny = TRUE; 00379 pBlobMgr->ToolInterest(bsBlobs); 00380 } 00381 00382 // make a note that we mustn't ignore any selection-changed messages. 00383 m_fIgnoreSelChange = FALSE; 00384 00385 // Update our info on the selection, and if necessary, render our tool blobs on. 00386 if (UpdateSelectionInfo()) 00387 pBlobMgr->RenderToolBlobsOn(this, SelectionSpread, NULL); 00388 } 00389 else 00390 { 00391 // destroy the tool's cursors, if they exist. 00392 if (pcCurrentCursor != NULL) 00393 { 00394 CursorStack::GPop(CurrentCursorID); 00395 pcCurrentCursor = NULL; 00396 CurrentCursorID = 0; 00397 } 00398 DestroyCursors(); 00399 00400 // remove the info-bar's slice-tool pointer. 00401 pSliceInfoBarOp->SetSliceTool(NULL); 00402 00403 // Remove the info bar from view by deleting the actual underlying window 00404 pSliceInfoBarOp->m_InfoBarCreated = FALSE; 00405 pSliceInfoBarOp->Delete(); 00406 00407 // ensure any tool object blobs are removed. 00408 BlobManager* BlobMgr = GetApplication()->GetBlobManager(); 00409 if (BlobMgr != NULL) 00410 { 00411 BlobStyle bsRemoves; 00412 bsRemoves.ToolObject = TRUE; 00413 BlobMgr->RemoveInterest(bsRemoves); 00414 } 00415 00416 // No longer the current tool 00417 CurrentTool = FALSE; 00418 00419 // Ensure our tool blobs have been rendered off the selected spread. 00420 BlobMgr->RenderToolBlobsOff(this, SelectionSpread, NULL); 00421 } 00422 } 00423 00424 00425 00426 /******************************************************************************************** 00427 00428 > void SliceTool::SelectionHasChanged() 00429 00430 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00431 Created: 19/10/1999 00432 Purpose: A public function, for other people to call whenever they need 00433 to let the Slice tool know that the selection has changed. 00434 00435 Allows the Slice tool to update its private information about the selection. 00436 Errors: 00437 See also: UpdateSelectionInfo(); 00438 00439 ********************************************************************************************/ 00440 void SliceTool::SelectionHasChanged() 00441 { 00442 // we sometimes ignore selection-changed messages, so that we don't get our tool-blobs 00443 // in a tizzy. 00444 if (m_fIgnoreSelChange) 00445 return; 00446 00447 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00448 if (pBlobMgr==NULL) return; 00449 00450 // ok, remove any of our previous tool blobs. 00451 pBlobMgr->RenderToolBlobsOff(this, SelectionSpread, NULL); 00452 00453 // reset our set-sel flag, to indicate that we did not change the selection. 00454 // this flag needs to be cleared whenever the selection changes, in order to 00455 // keep a record of whether we changed the selection. whenever we update the 00456 // selection from within SliceTool, we must set this flag manually *after* we 00457 // tell everyone that the selection changed. 00458 m_bSliceToolSetSel = FALSE; 00459 00460 // update the Slice tool's selection information, 00461 // and if necessary then render our tool blobs on. 00462 if (UpdateSelectionInfo()) 00463 pBlobMgr->RenderToolBlobsOn(this, SelectionSpread, NULL); 00464 } 00465 00466 00467 00468 /******************************************************************************************** 00469 00470 > void SliceTool::ViewChanged(const DocViewMsg& msg) 00471 00472 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00473 Created: 06/07/2000 00474 Inputs: 00475 Outputs: 00476 Returns: 00477 Purpose: The SliceTool's view-changed message handler. 00478 This method is called directly from the message handler of SliceInfoBarOp, 00479 which lives further down in this file. Its sole purpose is to let us redraw 00480 our blobs correctly. 00481 Errors: 00482 See also: 00483 00484 ********************************************************************************************/ 00485 void SliceTool::ViewChanged(const DocViewMsg& msg) 00486 { 00487 #ifdef SLICETOOL_BLOBS 00488 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00489 if (pBlobMgr==NULL) return; 00490 00491 switch (msg.State) 00492 { 00493 case DocViewMsg::DocViewState::SELABOUTTOCHANGE: 00494 { 00495 // Only bother rendering our tool blobs off if the new view is valid. 00496 if (msg.pNewDocView != NULL) 00497 { 00498 pBlobMgr->RenderToolBlobsOff(this, SelectionSpread, NULL); 00499 00500 // so that we don't draw tool blobs onto any new view, we must ignore any 00501 // select-change message until the new view is installed. 00502 m_fIgnoreSelChange = TRUE; 00503 } 00504 00505 break; 00506 } 00507 00508 case DocViewMsg::DocViewState::SELCHANGED: 00509 { 00510 // if the new DocView is valid, then draw our blobs onto it. 00511 if (msg.pNewDocView != NULL) 00512 if (UpdateSelectionInfo()) 00513 pBlobMgr->RenderToolBlobsOn(this, SelectionSpread, NULL); 00514 00515 // ok, the new view is now here - we can stop ignoring sel-changed messages. 00516 m_fIgnoreSelChange = FALSE; 00517 break; 00518 } 00519 00520 default: 00521 break; 00522 } 00523 #endif 00524 } 00525 00526 00527 00528 /******************************************************************************************** 00529 00530 > BOOL SliceTool::CreateCursors() 00531 00532 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00533 Created: 3/10/94 00534 Inputs: - 00535 Outputs: - 00536 Returns: TRUE if all the Slice tool cursors have been successfully created 00537 Purpose: Creates all the Slice tool cursors 00538 SeeAlso: - 00539 00540 ********************************************************************************************/ 00541 00542 BOOL SliceTool::CreateCursors() 00543 { 00544 // This tool has just been selected. Create its cursors. 00545 pcNormalSliceCursor = new Cursor(this, _R(IDC_POINTER_SLICE)); 00546 pcAdjustCursor = new Cursor(this, _R(IDC_POINTER_SLICE_ADJUST)); 00547 pcUnderCursor = new Cursor(this, _R(IDC_POINTER_SLICE_UNDER)); 00548 pcInsideCursor = new Cursor(this, _R(IDC_POINTER_SLICE_INSIDE)); 00549 pcUnderAdjustCursor = new Cursor(this, _R(IDC_POINTER_SLICE_UNDERADJUST)); 00550 pcInsideAdjustCursor= new Cursor(this, _R(IDC_POINTER_SLICE_INSIDEADJUST)); 00551 pcALLCursor = new Cursor(this, _R(IDCSR_SEL_GRADPOINT)); 00552 pcLeafCursor = new Cursor(this, _R(IDC_POINTER_SLICE_LEAF)); 00553 pcLeafAdjustCursor = new Cursor(this, _R(IDC_POINTER_SLICE_LEAFADJUST)); 00554 pcHorzGuideCursor = new Cursor(this, _R(IDCSR_SEL_HGUIDE)); 00555 pcVertGuideCursor = new Cursor(this, _R(IDCSR_SEL_VGUIDE)); 00556 00557 // now check them... 00558 BOOL ok = (pcNormalSliceCursor != NULL && pcNormalSliceCursor->IsValid()); 00559 if (ok) ok = (pcAdjustCursor != NULL && pcAdjustCursor->IsValid()); 00560 if (ok) ok = (pcUnderCursor != NULL && pcUnderCursor->IsValid()); 00561 if (ok) ok = (pcInsideCursor != NULL && pcInsideCursor->IsValid()); 00562 if (ok) ok = (pcUnderAdjustCursor != NULL && pcUnderAdjustCursor->IsValid()); 00563 if (ok) ok = (pcInsideAdjustCursor != NULL && pcInsideAdjustCursor->IsValid()); 00564 if (ok) ok = (pcALLCursor != NULL && pcALLCursor->IsValid()); 00565 if (ok) ok = (pcLeafCursor != NULL && pcLeafCursor->IsValid()); 00566 if (ok) ok = (pcLeafAdjustCursor != NULL && pcLeafAdjustCursor->IsValid()); 00567 if (ok) ok = (pcHorzGuideCursor != NULL && pcHorzGuideCursor->IsValid()); 00568 if (ok) ok = (pcVertGuideCursor != NULL && pcVertGuideCursor->IsValid()); 00569 if (!ok) 00570 DestroyCursors(); 00571 00572 return ok; 00573 } 00574 00575 /******************************************************************************************** 00576 00577 > void SliceTool::DestroyCursors() 00578 00579 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00580 Created: 3/10/94 00581 Inputs: - 00582 Outputs: - 00583 Returns: - 00584 Purpose: Destroys all the Slice tool cursors 00585 SeeAlso: - 00586 00587 ********************************************************************************************/ 00588 00589 void SliceTool::DestroyCursors() 00590 { 00591 if (pcNormalSliceCursor != NULL) delete pcNormalSliceCursor; 00592 if (pcAdjustCursor != NULL) delete pcAdjustCursor; 00593 if (pcUnderCursor != NULL) delete pcUnderCursor; 00594 if (pcInsideCursor != NULL) delete pcInsideCursor; 00595 if (pcUnderAdjustCursor != NULL) delete pcUnderAdjustCursor; 00596 if (pcInsideAdjustCursor != NULL) delete pcInsideAdjustCursor; 00597 if (pcALLCursor != NULL) delete pcALLCursor; 00598 if (pcLeafCursor != NULL) delete pcLeafCursor; 00599 if (pcLeafAdjustCursor != NULL) delete pcLeafAdjustCursor; 00600 if (pcHorzGuideCursor != NULL) delete pcHorzGuideCursor; 00601 if (pcVertGuideCursor != NULL) delete pcVertGuideCursor; 00602 } 00603 00604 /******************************************************************************************** 00605 00606 > void SliceTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 00607 Spread* pSpread ) 00608 00609 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00610 Created: 3/10/94 00611 Inputs: PointerPos - The DocCoord of the point where the mouse button was clicked 00612 Click - Describes the type of click that was detected. 00613 ClickMods - Indicates which buttons caused the click and which modifers were 00614 pressed at the same time 00615 pSpread - The spread in which the click happened 00616 Returns: - 00617 Purpose: To handle a Mouse Click event for the Slice Tool. 00618 SeeAlso: Tool::MouseClick; ClickType; ClickModifiers 00619 00620 ********************************************************************************************/ 00621 00622 void SliceTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 00623 Spread* pSpread ) 00624 { 00625 // we ignore any clicks with the Menu mouse button. 00626 if (ClickMods.Menu) 00627 return; 00628 00629 // remember the mouse position, in case we're starting a drag. 00630 if (Click == CLICKTYPE_SINGLE) 00631 { 00632 ClickStart = PointerPos; 00633 StartSpread = pSpread; 00634 } 00635 00636 // remember the click modifiers for later use in the click-processing code. 00637 this->ClickMods = ClickMods; 00638 TypeOfClick = Click; 00639 00640 // update our spread and bounds info about the selection. 00641 UpdateSelectionInfo(); 00642 00643 // refresh our ptr to the app's selection, for use in the click-processing code. 00644 SelectRange = GetApplication()->FindSelection(); 00645 RangeControl rc = SelectRange->GetRangeControlFlags(); 00646 rc.IgnoreInvisibleLayers = TRUE; 00647 SelectRange->Range::SetRangeControl(rc); 00648 00649 // we process clicks in three stages, stopping as soon as 00650 // a stage successfully processes the click. 00651 00652 // this function checks for and lets us drag guidelines. 00653 if (!PreProcessClick()) 00654 { 00655 // this function is a carry-over from the Selector tool code. 00656 // it currently does nothing. 00657 if (!ProcessObjectClick()) 00658 { 00659 // this function deals with normal mouse-click handling. 00660 PostProcessClick(); 00661 } 00662 } 00663 } 00664 00665 00666 00667 /******************************************************************* 00668 00669 > virtual BOOL SliceTool::PreProcessClick() 00670 00671 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00672 Created: 08/10/1999 00673 Inputs: 00674 Outputs: 00675 Returns: TRUE if the mouse event was handled here, 00676 FALSE otherwise. 00677 Purpose: Allows a click to be handled before going through the 00678 main click-handling code. 00679 This function checks for a clicked Node, and allows it 00680 to respond to the click. 00681 Errors: 00682 See also: SliceTool::OnClick 00683 00684 *******************************************************************/ 00685 BOOL SliceTool::PreProcessClick() 00686 { 00687 // look for a Node which may be interested in this click, and allow it to respond. 00688 pPreProcClickNode = FindPreProcessClickNode(StartSpread, ClickStart); 00689 if (pPreProcClickNode != NULL) 00690 if (pPreProcClickNode->OnClick(ClickStart, TypeOfClick, ClickMods, StartSpread)) 00691 return TRUE; 00692 00693 // no preprocess node, or it didn't want the click. 00694 return FALSE; 00695 } 00696 00697 00698 00699 /******************************************************************* 00700 00701 > virtual NodeRenderableInk* SliceTool::FindPreProcessClickNode(Spread* pSpread, 00702 DocCoord ClickPos, 00703 BOOL bInterruptible = FALSE) 00704 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00705 Created: 08/10/1999 00706 Inputs: pSpread pointer to a Spread. 00707 dcPos mouse click position in pSpread. 00708 bInterruptible whether or not this function can be 00709 aborted by mouse movement. 00710 Outputs: 00711 Returns: Pointer to a node interested in processing the OnClick message. 00712 Purpose: Scans the nodes in the spread, to see if any of them want to 00713 deal with this message before its processing continues. 00714 00715 Currently, only looks for NodeGuidelines. 00716 Errors: 00717 See also: SliceTool::PreProcessClick() 00718 00719 *******************************************************************/ 00720 NodeRenderableInk* SliceTool::FindPreProcessClickNode( Spread* pSpread, 00721 DocCoord ClickPos, 00722 BOOL bInterruptible ) 00723 { 00724 ERROR2IF(pSpread == NULL, NULL, "SliceTool::FindPreProcessClickNode- pSpread is NULL"); 00725 00726 // initialise vars. 00727 NodeRenderableInk* pFoundNode = NULL; 00728 BOOL bFound = FALSE; 00729 00730 // look for a visible, editable guides layer. 00731 Layer* pLayer = pSpread->FindFirstLayer(); 00732 while (pLayer != NULL && !bFound) 00733 { 00734 if (pLayer->IsGuide() && !pLayer->IsLocked() && pLayer->IsVisible()) 00735 { 00736 // We have a layer that's also a guide layer 00737 // Now look for the guidelines in this layer 00738 Node* pNodeInLayer = pLayer->FindFirstChild(CC_RUNTIME_CLASS(NodeGuideline)); 00739 while (pNodeInLayer != NULL && !bFound) 00740 { 00741 pFoundNode = (NodeGuideline*)pNodeInLayer; 00742 00743 // found a node - now hit-test its bounds. 00744 DocRect Rect = pFoundNode->GetBoundingRect(FALSE,TRUE); 00745 bFound = (Rect.ContainsCoord(ClickPos)); 00746 00747 pNodeInLayer = pNodeInLayer->FindNext(CC_RUNTIME_CLASS(NodeGuideline)); 00748 } 00749 } 00750 00751 pLayer = pLayer->FindNextLayer(); 00752 } 00753 00754 if (bFound) 00755 { 00756 // OK, we have found a node interested in a preprocess click 00757 // We now have to ensure that it's not being obscured visually by another node 00758 NodeRenderableInk* pNode = NULL; 00759 if (bInterruptible) 00760 { 00761 // Allow the hit-test to be interrupted if the mouse moves! 00762 Node* pInterruptedNode = NULL; 00763 pNode = NodeRenderableInk::FindSimpleAtPoint( pSpread, 00764 ClickPos, 00765 NULL, 00766 &pInterruptedNode); 00767 // If hit-test was interrupted then don't say anything about what's under the pointer! 00768 if (pInterruptedNode!=NULL) 00769 return NULL; 00770 } 00771 else 00772 { 00773 // Can't be interrupted by mouse movement so just go for it... 00774 pNode = NodeRenderableInk::FindSimpleAtPoint(pSpread,ClickPos); 00775 } 00776 00777 if (pNode) 00778 { 00779 // Find out whether the hit node is in front of the guideline or not. 00780 // If it is, then clear the Found flag. 00781 Layer* pLowerLayer = (Layer*) pFoundNode->FindParent(CC_RUNTIME_CLASS(Layer)); // The guideline layer 00782 Layer* pNodeLayer = (Layer*) pNode->FindParent(CC_RUNTIME_CLASS(Layer)); // The layer containing the node 00783 // Make sure GuideLayer comes after NodeLayer 00784 do 00785 { 00786 pLowerLayer = pLowerLayer->FindNextLayer(); // Find the layer above the last one tested 00787 } 00788 while (pLowerLayer && pLowerLayer!=pNodeLayer); // Keep going while there is a layer 00789 // and that layer isn't the one we're looking for 00790 // Get here when either we've run out of layers or we've found the layer we want 00791 if (pLowerLayer && pLowerLayer==pNodeLayer) // If found layer above guide layer 00792 bFound=FALSE; // Then flag that the guideline is obscured 00793 } 00794 } 00795 00796 if (!bFound) 00797 pFoundNode = NULL; 00798 00799 return pFoundNode; 00800 } 00801 00802 00803 00804 /******************************************************************* 00805 00806 > BOOL SliceTool::ProcessObjectClick() 00807 00808 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00809 Created: 08/10/1999 00810 Inputs: 00811 Outputs: 00812 Returns: FALSE always. 00813 Purpose: In the selector tool, this function OnClick()'s each object 00814 in the tool's range if the Selector tool is using Object blobs. 00815 We don't, so we won't. 00816 Errors: 00817 See also: SelectorTool::ProcessObjectClick 00818 00819 *******************************************************************/ 00820 BOOL SliceTool::ProcessObjectClick() 00821 { 00822 return FALSE; 00823 } 00824 00825 00826 00827 /******************************************************************* 00828 00829 > void SliceTool::PostProcessClick() 00830 00831 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00832 Created: 08/10/1999 00833 Inputs: 00834 Outputs: 00835 Returns: 00836 Purpose: Provided a click wasn't eaten by a pre- or mid- processor, 00837 we deal with it here. This passes the event on to specific 00838 handler routines, depending on its type (TypeOfClick): 00839 00840 CLICKTYPE_SINGLE HandleSingleClick 00841 CLICKTYPE_DOUBLE HandleDoubleClick 00842 CLICKTYPE_DRAG HandleDragClick 00843 CLICKTYPE_UP HandleButtonUp 00844 Errors: 00845 See also: 00846 00847 *******************************************************************/ 00848 void SliceTool::PostProcessClick() 00849 { 00850 switch (TypeOfClick) 00851 { 00852 case CLICKTYPE_SINGLE: 00853 HandleSingleClick(); 00854 break; 00855 00856 case CLICKTYPE_DOUBLE: 00857 HandleDoubleClick(); 00858 break; 00859 00860 case CLICKTYPE_DRAG: 00861 HandleDragClick(); 00862 break; 00863 00864 case CLICKTYPE_UP: 00865 HandleButtonUp(); 00866 break; 00867 00868 default: 00869 // unrecognised click-type - do nothing. 00870 break; 00871 } 00872 } 00873 00874 00875 00876 /******************************************************************* 00877 00878 > virtual void SliceTool::HandleSingleClick() 00879 00880 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00881 Created: 08/10/1999 00882 Purpose: Single mouse-click event handler. 00883 Errors: 00884 See also: 00885 00886 *******************************************************************/ 00887 void SliceTool::HandleSingleClick() 00888 { 00889 // work out what modifiers apply to this click. 00890 SetKeyDownCursor(ClickMods); 00891 00892 // Find out which object, if any, was clicked on. We hit-detect both the simple node 00893 // that was clicked and any top-level compound object it may be part of. 00894 pClickSimpleNode = NodeRenderableInk::FindSimpleAtPoint(StartSpread, ClickStart); 00895 pClickCompoundNode = NodeRenderableInk::FindCompoundFromSimple(pClickSimpleNode); 00896 } 00897 00898 00899 00900 /******************************************************************* 00901 00902 > void SliceTool::HandleDoubleClick() 00903 00904 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00905 Created: 08/10/1999 00906 Purpose: Double mouse-click event handler. 00907 Currently, passes the event to HandleSingleClick(). 00908 Errors: 00909 See also: 00910 00911 *******************************************************************/ 00912 void SliceTool::HandleDoubleClick() 00913 { 00914 HandleSingleClick(); 00915 } 00916 00917 00918 00919 /******************************************************************* 00920 00921 > void SliceTool::HandleDragClick() 00922 00923 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00924 Created: 08/10/1999 00925 Purpose: Mouse-drag event handler. 00926 Errors: 00927 See also: 00928 00929 *******************************************************************/ 00930 void SliceTool::HandleDragClick() 00931 { 00932 // check for a forced translate, and perform a translate 00933 // operation if appropriate. 00934 if (IsTranslateShortcut(ClickMods)) 00935 { 00936 if (SelectionSpread != NULL) 00937 { 00938 // There is a selection, so start a translate drag... 00939 DoTranslate(); 00940 } 00941 return; 00942 } 00943 00944 // Right, we clicked on either an object (possibly already selected) or 00945 // blank paper. First, check if there is an object at the click position. 00946 if (pClickCompoundNode == NULL) 00947 { 00948 // There is only blank paper at the click point, so assume the user is 00949 // trying to start a marquee selection drag. Run the drag-box operation. 00950 DoDragBox(); 00951 return; 00952 } 00953 00954 // Is the clicked object already selected? Note that the user may be trying to click on 00955 // a simple object selected inside a group that itself is not selected, so we must be 00956 // careful to check the state of the right nodes here. 00957 // 00958 // The logic here is: 00959 // If the clicked simple node or any of it's parents are selected 00960 // Then DON'T alter the selection to reflect the clicked object! 00961 // 00962 BOOL SimpleInSelected = FALSE; // So far haven't encountered any selected nodes 00963 Node* pNode = pClickSimpleNode; // Make a working pointer and initialise it 00964 do 00965 { 00966 if (pNode->IsSelected()) // If the working node is selected 00967 { 00968 SimpleInSelected = TRUE; // Then the simple node or one of its parents are 00969 break; // selected so we don't need to change the selection! 00970 } 00971 pNode = pNode->FindParent(); // Else check the working node's parent 00972 } 00973 while (pNode != pClickCompoundNode->FindParent());// until we've reached the compound node's parent 00974 // (Allows the compound node itself to be checked) 00975 00976 if (!SimpleInSelected) 00977 { 00978 // No. If the click was with the left button we must deselect all other objects. 00979 // If the clicked object isn't selected, we can't run a transform on it. Hence we must 00980 // select it, but we prevent it being redrawn as selected (with its little blobs). 00981 if (!ClickMods.Adjust) 00982 { 00983 // Normal click, so deselect everything before we select the clicked node... 00984 NodeRenderableInk::DeselectAll(TRUE, FALSE); 00985 } 00986 else 00987 { 00988 // We clicked with the right button, but if the click was in a different spread to 00989 // the selection we have to deselect everything anyway. 00990 Node* pNode = SelectRange->FindFirst(); 00991 if (pNode != NULL && pNode->FindParentSpread() != SelectionSpread) 00992 { 00993 // Clicked node in a different spread from previous selection, so clear selection 00994 NodeRenderableInk::DeselectAll(TRUE, FALSE); 00995 } 00996 } 00997 00998 // Now that the selection state of all other objects is dealt with, make sure the 00999 // clicked object, as well as objects sharing its name, is selected. 01000 // 01001 // Currently, SelectAllSetsOfThisNode indirectly does a SelectRange->Update(TRUE). 01002 String_256 SetName; 01003 SetName.Empty(); 01004 SliceHelper::SelectAllSetsOfThisNode(pClickCompoundNode, SetName, FALSE); 01005 if (SetName.IsEmpty()) 01006 { 01007 pClickCompoundNode->Select(TRUE); 01008 01009 // force a broadcast of the changed selection, so that our info-bar is informed. 01010 SelectRange->Update(TRUE); 01011 } 01012 } 01013 01014 // Finally, run a transform on the selected object(s). Of course, the user may not be 01015 // trying to drag the selection - if so the button will come up before a significant 01016 // drag has occurred and we can take it from there. 01017 MakeSelectionValidForDrag(); 01018 01019 // do the drag. 01020 DoTranslate(); 01021 01022 // remember that _we_ changed the selection. 01023 m_bSliceToolSetSel = TRUE; 01024 } 01025 01026 01027 01028 /******************************************************************************************** 01029 01030 > void SliceTool::HandleButtonUp() 01031 01032 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from JustinF's SelectorTool::HandleButtonUp code 01033 Created: 08/10/1999 01034 Purpose: Mouse button-up event handler. 01035 Errors: 01036 See also: 01037 01038 ********************************************************************************************/ 01039 void SliceTool::HandleButtonUp() 01040 { 01041 // if we changed the selection last, or the SelRange cannot provide a usable 01042 // last-selection then use our own record. otherwise, ask the SelRange. 01043 Node* pLastSelNode = NULL; 01044 if (m_bSliceToolSetSel && pLastClickNode != NULL) 01045 { 01046 pLastSelNode = pLastClickNode; 01047 } 01048 else 01049 { 01050 pLastSelNode = SelectRange->GetLastSelectedNode(); 01051 if ( pLastSelNode == NULL || !pLastSelNode->IsAnObject() ) 01052 pLastSelNode = pLastClickNode; 01053 } 01054 01055 // Find out what we should do with the click... 01056 ClickActionCode action = CLICKACTION_NONE; 01057 NodeRenderableInk* pActionNode = NULL; 01058 action = DetermineClickAction( &pActionNode, (NodeRenderableInk*)pLastSelNode, 01059 pClickSimpleNode, pClickCompoundNode, StartSpread, 01060 ClickStart, ClickMods ); 01061 01062 // Act upon the information... 01063 switch (action) 01064 { 01065 //-------------------------------------------------// 01066 // No action required... 01067 case CLICKACTION_NONE: 01068 break; 01069 01070 //-------------------------------------------------// 01071 // Anything that's selected must be deselected... 01072 case CLICKACTION_SELNONE: 01073 { 01074 // Don't clear selection if was an adjust click 01075 // (Change requested by Charles and Alan Burns) 01076 if (!ClickMods.Adjust) 01077 { 01078 // Markn 29/9/95: We ignore this if the click happened on a guideline. 01079 // If another type of node needs to behave like this, then a virt func in node 01080 // will be required instead of the hideous IS_A() clause in the 'if' statement 01081 if (pPreProcClickNode == NULL || !IS_A(pPreProcClickNode,NodeGuideline)) 01082 { 01083 NodeRenderableInk::DeselectAll(TRUE, TRUE); 01084 pLastClickNode = NULL; 01085 } 01086 } 01087 break; 01088 } 01089 01090 //-------------------------------------------------// 01091 // The action node must be selected or toggled... 01092 case CLICKACTION_SELNODE: 01093 case CLICKACTION_SELUNDER: 01094 case CLICKACTION_SELUNDERCYCLE: 01095 case CLICKACTION_SELUNDERFAIL: 01096 case CLICKACTION_SELUNDERFAIL2: 01097 case CLICKACTION_SELINSIDE: 01098 case CLICKACTION_SELINSIDECYCLE: 01099 case CLICKACTION_SELINSIDEFAIL: 01100 case CLICKACTION_SELINSIDEFAIL2: 01101 case CLICKACTION_SELLEAF: 01102 { 01103 ERROR3IF(pActionNode == NULL, "Action and ActionNode don't agree!"); 01104 01105 // if we aren't Adjust'ing, ensure no previous selection. 01106 if (!ClickMods.Adjust) 01107 NodeRenderableInk::DeselectAll(TRUE, FALSE); 01108 01109 // try to select all nodes sharing the same name as the clicked node. 01110 String_256 SetName; 01111 SetName.Empty(); 01112 SliceHelper::SelectAllSetsOfThisNode(pActionNode, SetName, ClickMods.Adjust); 01113 01114 // if the clicked node has no name then the above code will do nothing, 01115 // so we need to do a normal select, accounting for Adjust. 01116 if (SetName.IsEmpty()) 01117 { 01118 if (ClickMods.Adjust) 01119 { 01120 // If Adjust is applied, toggle the state of the action node. 01121 if (pActionNode->IsSelected()) 01122 pActionNode->DeSelect(TRUE); 01123 else 01124 pActionNode->Select(TRUE); 01125 } 01126 else 01127 { 01128 pActionNode->Select(TRUE); 01129 } 01130 01131 // force a broadcast of the changed selection state, so our info-bar updates. 01132 SelectRange->Update(TRUE); 01133 } 01134 01135 // update our record of the last clicked node. 01136 pLastClickNode = pActionNode; 01137 01138 // make a note that we changed the selection. 01139 m_bSliceToolSetSel = TRUE; 01140 01141 break; 01142 } 01143 //-------------------------------------------------// 01144 default: 01145 ERROR3("Unknown Click action code!"); 01146 break; 01147 }; // switch (action) 01148 01149 // Make sure the cursor reflects which keys are down, now that the mouse button has 01150 // been released. 01151 SetKeyDownCursor(ClickModifiers::GetClickModifiers()); 01152 } 01153 01154 01155 01156 /******************************************************************* 01157 01158 > virtual BOOL SliceTool::OnKeyPress(KeyPress *pKeyPress) 01159 01160 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01161 Created: 08/10/1999 01162 Inputs: pKeyPress pointer to a key-press object. 01163 Outputs: 01164 Returns: 01165 Purpose: key-press event handler. Catch CTRL/ALT/SHIFT modifiers 01166 and change the status-line/cursor appropriately. 01167 Errors: 01168 See also: 01169 01170 *******************************************************************/ 01171 BOOL SliceTool::OnKeyPress(KeyPress *pKeyPress) 01172 { 01173 // Find the current state of the "click" keyboard modifiers... 01174 ClickMods = ClickModifiers::GetClickModifiers(); 01175 01176 switch (pKeyPress->GetVirtKey()) 01177 { 01178 case CAMKEY(CC_MOD_ADJUST): // bit 0 of fKeyStates (SHIFT) 01179 case CAMKEY(CC_MOD_ALTERNATIVE): // bit 1 of fKeyStates (ALT) 01180 case CAMKEY(CC_MOD_CONSTRAIN): // bit 2 of fKeyStates (CONTROL) 01181 // apparently, this is a bodge for speed. 01182 // see SelectorTool::OnKeyPress for details :-) 01183 break; 01184 01185 case CAMKEY(TAB): // moves selection to next rendered node 01186 if (pKeyPress->IsPress()) HandleTabKey(ClickMods.Adjust); 01187 break; 01188 01189 case CAMKEY(HOME): // select first object in render order 01190 if (pKeyPress->IsPress()) 01191 { 01192 if (SelectionSpread != NULL) 01193 NodeRenderableInk::DeselectAll(); 01194 HandleTabKey(FALSE); 01195 } 01196 break; 01197 01198 case CAMKEY(END): // select last object in render order 01199 if (pKeyPress->IsPress()) 01200 { 01201 if (SelectionSpread != NULL) 01202 NodeRenderableInk::DeselectAll(); 01203 HandleTabKey(TRUE); 01204 } 01205 break; 01206 01207 default: // not interested in processing this 01208 return FALSE; 01209 } 01210 01211 // If we processed a click modifier then update the cursor and return that we processed 01212 // the keystroke. 01213 SetKeyDownCursor(ClickMods); 01214 01215 // Yes, we processed this key-event. 01216 return TRUE; 01217 } 01218 01219 01220 01221 /******************************************************************* 01222 01223 > void SliceTool::HandleTabKey(BOOL bIsShifted) 01224 01225 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01226 Created: 08/10/1999 01227 Purpose: Tab keypress event handler. 01228 Errors: 01229 See also: 01230 01231 *******************************************************************/ 01232 void SliceTool::HandleTabKey(BOOL bIsShifted) 01233 { 01234 } 01235 01236 01237 01238 /******************************************************************* 01239 01240 > void SliceTool::SetKeyDownCursor(ClickModifiers cmMods) 01241 01242 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01243 Created: 08/10/1999 01244 Inputs: 01245 Outputs: 01246 Returns: 01247 Purpose: Decodes the bit-field fKeyStates, indicating which combination 01248 of modifier keys are down, and sets the cursor appropriately. 01249 Errors: 01250 See also: 01251 01252 *******************************************************************/ 01253 void SliceTool::SetKeyDownCursor(ClickModifiers cmMods) 01254 { 01255 // Get current position information for call to change pointer shape... 01256 Spread* pSpread; 01257 DocCoord dcMousePos; 01258 if (DocView::GetCurrentMousePos(&pSpread, &dcMousePos) && 01259 Tool::GetCurrentID() == TOOLID_SLICETOOL && 01260 !BaseBar::IsDragging()) 01261 { 01262 // Call nice central routine to figure out what pointer shape to show... 01263 // (Set the status bar text while we're at it.) 01264 String_256 Str; 01265 Cursor* pPtr; 01266 FigureUserFeedback(pSpread, dcMousePos, cmMods, TRUE, &Str, &pPtr); 01267 if (CurrentCursorID != CURSORID_UNSET) 01268 CursorStack::GSetTop(pPtr, CurrentCursorID); 01269 if (!(Str.IsEmpty())) 01270 SetStatusText( &Str ); 01271 } 01272 } 01273 01274 01275 01276 /******************************************************************************************** 01277 01278 > void SliceTool::OnMouseMove( DocCoord PointerPos,Spread* pSpread, ClickModifiers ClickMod ) 01279 01280 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01281 Created: 3/10/94 01282 Inputs: PointerPos - The DocCoord of the point where the mouse has moved to 01283 pSpread - The spread in which the move occurred 01284 ClickMods - The state of the various modifiers at the time of the mouse move 01285 Returns: TRUE if it handled the Click, FALSE otherwise 01286 Purpose: To handle a Mouse Move event for the Slice Tool. 01287 SeeAlso: Tool::MouseClick; ClickType; ClickModifiers 01288 01289 ********************************************************************************************/ 01290 01291 void SliceTool::OnMouseMove(DocCoord PointerPos,Spread* pSpread,ClickModifiers ClickMods) 01292 { 01293 // Display status bar text for the current position 01294 // DisplayStatusBarHelp(PointerPos, pSpread, ClickMods); 01295 01296 // If there isn't any selection, or it's in a different spread, then do nothing. 01297 if (SelectionSpread == NULL || SelectionSpread != pSpread) return; 01298 01299 String_256 str; 01300 Cursor* pcPointerShape; 01301 01302 FigureUserFeedback(pSpread, PointerPos, ClickMods, FALSE, &str, &pcPointerShape); 01303 01304 if (!(str.IsEmpty())) 01305 SetStatusText(&str); 01306 01307 if (CurrentCursorID != CURSORID_UNSET) 01308 CursorStack::GSetTop(pcPointerShape, CurrentCursorID); 01309 } 01310 01311 01312 01313 /******************************************************************************************** 01314 > void SliceTool::MakeSelectionValidForDrag() 01315 01316 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01317 Created: 3/5/95 01318 Inputs: - 01319 Outputs: Can change the current selection, causing an immediate SelChanged message 01320 Returns: - 01321 Purpose: Runs through the selected nodes, making sure they are all happy with being 01322 dragged. Checks are:- 01323 1. Sub-Selected text characters are deselected, and their parent story (and 01324 all other nodes sharing its name) are selected instead. 01325 Errors: - 01326 SeeAlso: - 01327 ********************************************************************************************/ 01328 01329 void SliceTool::MakeSelectionValidForDrag() 01330 { 01331 SelRange *pSelection = GetApplication()->FindSelection(); 01332 RangeControl rg = pSelection->GetRangeControlFlags(); 01333 rg.IgnoreInvisibleLayers = TRUE; // oddly setting this to TRUE actually means DO INCLUDE INIVISIBLE LAYERS in the range!!! 01334 RangeControl rcOld = rg; 01335 rg.PromoteToParent = TRUE; 01336 pSelection->Range::SetRangeControl(rg); 01337 01338 Node* pNode = pSelection->FindFirst(); 01339 BOOL ChangedSelection = FALSE; 01340 01341 while (pNode != NULL) 01342 { 01343 // Push any text sub-selection up to the selected story, and make sure 01344 // that any other Nodes sharing the text-story's name are also selected. 01345 if (pNode->IsAnAbstractTextChar()) 01346 { 01347 ((NodeRenderableInk*)pNode)->DeSelect(TRUE); 01348 TextStory* pStory = (TextStory*)pNode->FindParent(CC_RUNTIME_CLASS(TextStory)); 01349 if (pStory != NULL) 01350 { 01351 String_256 SetName; 01352 SetName.Empty(); 01353 SliceHelper::SelectAllSetsOfThisNode(pStory, SetName, FALSE); 01354 if (SetName.IsEmpty()) 01355 pStory->Select(TRUE); 01356 ChangedSelection = TRUE; 01357 } 01358 } 01359 01360 pNode = pSelection->FindNext(pNode); 01361 } 01362 01363 // if we needed to change the selection, tell everyone. 01364 if (ChangedSelection) 01365 { 01366 // this call commented out, as I don't think it is required. pushing the selection 01367 // up to the letter's text-story in this way does not actually change the overall 01368 // state of the selection wrt named sets, as the story shares the same set name as 01369 // the character (always?). - Karim 25/10/1999 01370 // GetApplication()->FindSelection()->Update(TRUE); // is this call actually 01371 m_bSliceToolSetSel = TRUE; 01372 } 01373 01374 pSelection->Range::SetRangeControl(rcOld); 01375 } 01376 01377 01378 01379 /******************************************************************* 01380 01381 > void SliceTool::DoTranslate() 01382 01383 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01384 Created: 11/10/1999 01385 Inputs: 01386 Outputs: 01387 Returns: 01388 Purpose: Runs a translation tranformation drag on the selection. 01389 Errors: 01390 See also: 01391 01392 *******************************************************************/ 01393 void SliceTool::DoTranslate() 01394 { 01395 // set appropriate transform parameters... 01396 TransformData tdParams; 01397 tdParams.CentreOfTrans = ClickStart; 01398 tdParams.LeaveCopy = FALSE; 01399 tdParams.LockAspect = TRUE; 01400 tdParams.pRange = NULL; 01401 tdParams.ScaleLines = FALSE; 01402 tdParams.StartBlob = 0; 01403 tdParams.TransFills = TRUE; 01404 01405 // set drag pointer shape. 01406 if (CurrentCursorID != CURSORID_UNSET) 01407 CursorStack::GSetTop(pcALLCursor, CurrentCursorID); 01408 01409 // attempt to create a translate op. 01410 OpSliceTranslate* pSliceTransOp = new OpSliceTranslate(); 01411 if (pSliceTransOp == NULL) 01412 { 01413 InformError(_R(IDS_OUT_OF_MEMORY), _R(IDS_OK)); 01414 return; 01415 } 01416 01417 // Get the current DocView (there must be one or we wouldn't be here). 01418 DocView* pDocView = DocView::GetCurrent(); 01419 ERROR3IF(pDocView == NULL, "SliceTool::DoTranslate- Null current DocView"); 01420 01421 DocCoord dcOffset(0, 0); // Default to offsets of 0 01422 01423 // Fill a Transform Bounding Data structure up here 01424 BoundingData.x = SelectionRect.lo.x; 01425 BoundingData.y = SelectionRect.lo.y; 01426 BoundingData.Width = SelectionRect.Width(); 01427 BoundingData.Height = SelectionRect.Height(); 01428 BoundingData.XScale = (FIXED16) 1; 01429 BoundingData.YScale = (FIXED16) 1; 01430 BoundingData.Rotation = (ANGLE) 0; 01431 BoundingData.Shear = (ANGLE) 0; 01432 01433 // Run the transformation drag operation and return success code. 01434 pSliceTransOp->DragStarted(&tdParams, this, &BoundingData, ClickStart, 01435 StartSpread, ClickMods, dcOffset, NULL, DRAGTYPE_AUTOSCROLL); 01436 } 01437 01438 01439 01440 /******************************************************************* 01441 01442 > void SliceTool::DoDragBox() 01443 01444 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01445 Created: 11/10/1999 01446 Inputs: 01447 Outputs: 01448 Returns: 01449 Purpose: Runs a selector-tool drag-box operation. 01450 Errors: 01451 See also: 01452 01453 *******************************************************************/ 01454 void SliceTool::DoDragBox() 01455 { 01456 OpSliceDragBox* pOpDragBox = new OpSliceDragBox(); 01457 if (pOpDragBox == NULL) 01458 { 01459 InformError(_R(IDS_OUT_OF_MEMORY), _R(IDS_OK)); 01460 } 01461 else 01462 { 01463 pOpDragBox->StartDragBox(StartSpread, ClickStart, ClickMods); 01464 } 01465 } 01466 01467 01468 01469 /******************************************************************************************** 01470 01471 > void SliceTool::DisplayStatusBarHelp(DocCoord DocPos, Spread* pSpread, ClickModifiers ClickMods) 01472 01473 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01474 Created: 12/12/94 01475 Inputs: DocPos - the document coordinate of the point to display help on 01476 pSpread - pointer to the spread containing DocPos 01477 ClickMods - the current click modifiers 01478 Outputs: - 01479 Returns: - 01480 Purpose: Displays status help string for the given position in the status bar. 01481 SeeAlso: SliceTool::GetCurrentStatusText 01482 01483 ********************************************************************************************/ 01484 01485 void SliceTool::DisplayStatusBarHelp(DocCoord DocPos, Spread* pSpread, ClickModifiers ClickMods) 01486 { 01487 String_256 StatusMsg(""); 01488 01489 // Get a string from the underlying help function and display it. 01490 GetCurrentStatusText(&StatusMsg, pSpread, DocPos, ClickMods); 01491 GetApplication()->UpdateStatusBarText(&StatusMsg); 01492 } 01493 01494 01495 01496 /******************************************************************* 01497 01498 > BOOL SliceTool::GetStatusLineText(String_256* ptext, Spread* pSpread, 01499 DocCoord DocPos, ClickModifiers ClickMods) 01500 01501 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Phil's code for SelectorTool. 01502 Created: 11/10/1999 01503 Inputs: ptext Pointer to text string to fill in 01504 pSpread Pointer to spread containing mouse position 01505 DocPos Mouse position within spread 01506 ClickMods Click modifiers 01507 Outputs: - 01508 Returns: TRUE always, indicating that the string was updated. 01509 Purpose: Figure out what the status text for the SliceTool is at the given position 01510 on the given spread with the given click modifiers. 01511 Errors: ERROR2 if pText is NULL. 01512 See also: 01513 01514 *******************************************************************/ 01515 BOOL SliceTool::GetStatusLineText(String_256* ptext, Spread* pSpread, 01516 DocCoord DocPos, ClickModifiers ClickMods) 01517 { 01518 ERROR2IF(ptext==NULL,FALSE,"ptext is NULL!"); 01519 01520 Cursor* pcDummy; // Dummy to hold unused pointer shape computed by FigureUserFeedback 01521 FigureUserFeedback(pSpread, DocPos, ClickMods, TRUE, ptext, &pcDummy); 01522 01523 if (CurrentCursorID != CURSORID_UNSET) 01524 CursorStack::GSetTop(pcDummy,CurrentCursorID); 01525 01526 return TRUE; 01527 } 01528 01529 01530 01531 /******************************************************************************************** 01532 01533 > void SliceTool::GetCurrentStatusText(String_256* ptext, Spread* pSpread, DocCoord DocPos, ClickModifiers ClickMods) 01534 01535 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01536 Created: 12/12/94 01537 Inputs: pSpread points to a spread 01538 DocPos points to a point in a document 01539 ClickMods are the current click modifiers 01540 Outputs: Updates the string in ptext 01541 Returns: - 01542 Purpose: Selects a suitable string for the status line based on the current location 01543 (as input via the parameters). 01544 SeeAlso: SliceTool::GetStatusLineText, SliceTool::DisplayStatusBarHelp 01545 01546 ********************************************************************************************/ 01547 01548 void SliceTool::GetCurrentStatusText(String_256* ptext, Spread* pSpread, DocCoord DocPos, ClickModifiers ClickMods) 01549 { 01550 // You must use the Spread, DocCoord and ClickModifiers to select a suitable string to be 01551 // displaied in the status bar. This is usually done via some sort of switch statement. 01552 // Having selected a suitable string you should do a statement like 01553 // ptext->Load(<#Insert your string ID here #>); 01554 01555 // Delete this line when you display useful strings! 01556 ptext->Empty(); 01557 } 01558 01559 01560 01561 /******************************************************************* 01562 01563 > virtual void SliceTool::FigureUserFeedback( Spread* pSpread, 01564 DocCoord dcPos, 01565 ClickModifiers cmods, 01566 BOOL DoSlowTests, 01567 String_256* pStr, 01568 Cursor** ppPointerShape ) 01569 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01570 Created: 08/10/1999 01571 Inputs: 01572 Outputs: 01573 Returns: 01574 Purpose: This routine computes the status line help and the pointer shape for a 01575 given mouse position in the Slice tool. It does NOT set either of these 01576 values but returns them both to the caller. It's up to the caller to decide 01577 whether to use these values or not. 01578 The tests done to figure out which pointer shapes, status help (and maybe 01579 other stuff one day) is quite complex so it's most efficient to compute them 01580 all at once and then let the caller decide which ones to actually use. 01581 The precedence of pointer shapes, status messages and other user feedback is 01582 determined by the order of the checks within this function. 01583 Errors: 01584 See also: 01585 01586 *******************************************************************/ 01587 void SliceTool::FigureUserFeedback( Spread* pSpread, 01588 DocCoord dcPos, 01589 ClickModifiers cmods, 01590 BOOL DoSlowTests, 01591 String_256* pStr, 01592 Cursor** ppPointerShape ) 01593 { 01594 // Initialise the status text string and pointer shape to be "null". 01595 pStr->Empty(); 01596 *ppPointerShape = pcNormalSliceCursor; 01597 01598 if (Tool::GetCurrentID() != TOOLID_SLICETOOL) 01599 return; 01600 01601 BOOL DescribeDrag = TRUE; 01602 01603 //------------------------------------------------------------------------- 01604 // Set the pointer shape, according to the key modifiers and/or the current state. 01605 if (!cmods.Adjust && !cmods.Constrain && !cmods.Alternative1) 01606 { 01607 *ppPointerShape = pcNormalSliceCursor; 01608 Append(pStr,_R(IDS_SLICE_MODE0)); // "Normal select mode:" 01609 } 01610 01611 else if (cmods.Adjust && !cmods.Constrain && !cmods.Alternative1) 01612 { 01613 *ppPointerShape = pcAdjustCursor; 01614 Append(pStr,_R(IDS_SLICE_MODE1)); // "Adjust select:" 01615 } 01616 01617 else if (!cmods.Adjust && IsSelectUnderClick(cmods)) 01618 { 01619 *ppPointerShape = pcUnderCursor; 01620 Append(pStr,_R(IDS_SLICE_MODE2)); // "Select under:" 01621 } 01622 01623 else if (cmods.Adjust && IsSelectUnderClick(cmods)) 01624 { 01625 *ppPointerShape = pcUnderAdjustCursor; 01626 Append(pStr,_R(IDS_SLICE_MODE3)); // "Adjust select under:" 01627 } 01628 01629 else if (!cmods.Adjust && IsSelectMemberClick(cmods)) 01630 { 01631 *ppPointerShape = pcInsideCursor; 01632 Append(pStr,_R(IDS_SLICE_MODE4)); // "Force drag/Select member:" 01633 } 01634 01635 else if (cmods.Adjust && IsSelectMemberClick(cmods)) 01636 { 01637 *ppPointerShape = pcInsideAdjustCursor; 01638 Append(pStr,_R(IDS_SLICE_MODE5)); // "Force drag/Adjust select member:" 01639 } 01640 01641 else if (!cmods.Adjust && IsSelectLeafClick(cmods)) 01642 { 01643 *ppPointerShape = pcLeafCursor; 01644 Append(pStr,_R(IDS_SLICE_MODE6)); // "Select inside:" 01645 } 01646 01647 else if (cmods.Adjust && IsSelectLeafClick(cmods)) 01648 { 01649 *ppPointerShape = pcLeafAdjustCursor; 01650 Append(pStr,_R(IDS_SLICE_MODE7)); // "Adjust select inside:" 01651 } 01652 01653 else 01654 { 01655 ERROR3("SliceTool::FigureUserFeedback- out of range ClickModifiers"); 01656 return; 01657 } 01658 01659 // Check for direct drag mode and say something about it... 01660 if (IsTranslateShortcut(cmods)) 01661 { 01662 if (SelectRange->FindFirst()) 01663 { 01664 *ppPointerShape = pcALLCursor; 01665 Append(pStr,_R(IDS_SLICEINSIDE4)); // "Drag to move the selected objects" 01666 } 01667 DescribeDrag = FALSE; 01668 } 01669 01670 // See if there's a non-selectable object (guideline) under the mouse 01671 NodeRenderableInk* pPreProNode = FindPreProcessClickNode(pSpread,dcPos,TRUE); 01672 if (pPreProNode) 01673 { 01674 if (IS_A(pPreProNode,NodeGuideline)) 01675 { 01676 NodeGuideline* pGuideline = (NodeGuideline*)pPreProNode; 01677 if (pGuideline->GetType()==GUIDELINE_HORZ) 01678 { 01679 *ppPointerShape = pcHorzGuideCursor; 01680 // "Drag up or down to move guideline; Drag onto top ruler to delete it" 01681 Append(pStr,_R(IDS_SLICEHORZGUIDE)); 01682 return; 01683 } 01684 01685 if (pGuideline->GetType()==GUIDELINE_VERT) 01686 { 01687 *ppPointerShape = pcVertGuideCursor; 01688 // "Drag left or right to move guideline; Drag onto left ruler to delete it" 01689 Append(pStr,_R(IDS_SLICEVERTGUIDE)); 01690 return; 01691 } 01692 } 01693 } 01694 01695 //------------------------------------------------------------------------- 01696 // If we've got time to do the slow tests then go ahead and do them... 01697 if (DoSlowTests) 01698 { 01699 // Perform a hit-test at the mouse position and set the status bar text 01700 // accordingly. 01701 // Allow the hit-test to be interrupted if the mouse moves! 01702 Node* pInterruptedNode = NULL; 01703 NodeRenderableInk* pSimple = NodeRenderableInk::FindSimpleAtPoint(pSpread, 01704 dcPos, 01705 NULL, 01706 &pInterruptedNode); 01707 // If hit-test was interrupted then don't say anything about what's under the pointer! 01708 if (pInterruptedNode!=NULL) 01709 return; 01710 01711 NodeRenderableInk* pCompound = NodeRenderableInk::FindCompoundFromSimple(pSimple); 01712 01713 // if we changed the selection last, or the SelRange cannot provide a usable 01714 // last-selection then use our own record. otherwise, ask the SelRange. 01715 Node* pLastSelNode = NULL; 01716 if (m_bSliceToolSetSel && pLastClickNode != NULL) 01717 { 01718 pLastSelNode = pLastClickNode; 01719 } 01720 else 01721 { 01722 pLastSelNode = SelectRange->GetLastSelectedNode(); 01723 if ( pLastSelNode==NULL || !(pLastSelNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk))) ) 01724 pLastSelNode = pLastClickNode; 01725 } 01726 01727 // Find out what we should do with the click... 01728 ClickActionCode action = CLICKACTION_NONE; 01729 NodeRenderableInk* pActionNode = NULL; 01730 action = DetermineClickAction(&pActionNode,(NodeRenderableInk*)pLastSelNode, 01731 pSimple,pCompound,pSpread,dcPos,cmods); 01732 01733 // Act upon the information... 01734 switch (action) 01735 { 01736 //-------------------------------------------------// 01737 // No action required... 01738 case CLICKACTION_NONE: 01739 break; 01740 01741 //-------------------------------------------------// 01742 // Anything that's selected must be deselected... 01743 case CLICKACTION_SELNONE: 01744 if (!cmods.Adjust) 01745 { 01746 // If there are selected objects append message about clearing. 01747 if (SelectRange && SelectRange->FindFirst()) 01748 Append(pStr,_R(IDS_SLICENONE1)); // "Click to clear the selection" 01749 // Message about marquee drag 01750 if (DescribeDrag) 01751 Append(pStr,_R(IDS_SLICENONE4)); // "Drag to marquee select objects" 01752 Append(pStr,_R(IDS_SLICENONE2)); // "Move pointer over object to select" 01753 } 01754 else 01755 { 01756 // Adjust is held down so describe marquee add. 01757 if (DescribeDrag) 01758 // "Drag to marquee select objects to add to selection" 01759 Append(pStr,_R(IDS_SLICENONE5)); 01760 // "Move pointer over object to add/remove from selection" 01761 Append(pStr,_R(IDS_SLICENONE3)); 01762 } 01763 break; 01764 01765 //-------------------------------------------------// 01766 // The action node must be selected... 01767 case CLICKACTION_SELNODE: 01768 Append(pStr,cmods, 01769 _R(IDS_SLICENODE3), // "Click to select this #1%S alone; Drag to move it" 01770 _R(IDS_SLICENODE4), // "Click to select this #1%S" 01771 _R(IDS_SLICENODE5), // "Click to deselect this #1%S" 01772 pActionNode); 01773 break; 01774 case CLICKACTION_SELUNDER: 01775 Append(pStr,cmods, 01776 _R(IDS_SLICEUNDER1), // "Click to select the #1%S under the last selected object alone" 01777 _R(IDS_SLICEUNDER2), // "Click to select the #1%S under the last selected object" 01778 _R(IDS_SLICEUNDER3), // "Click to deselect the #1%S under the last selected object" 01779 pActionNode); 01780 break; 01781 case CLICKACTION_SELUNDERCYCLE: 01782 Append(pStr,cmods, 01783 _R(IDS_SLICEUNDERCYCLE1), // "Click to select the top #1%S alone; (Reached the bottom)" 01784 _R(IDS_SLICEUNDERCYCLE2), // "Click to select the top #1%S; (Reached the bottom)" 01785 _R(IDS_SLICEUNDERCYCLE3), // "Click to deselect the top #1%S; (Reached the bottom)" 01786 pActionNode); 01787 break; 01788 case CLICKACTION_SELUNDERFAIL: 01789 Append(pStr,cmods, 01790 _R(IDS_SLICEUNDERFAIL1), // "Click to select the #1%S alone; (Nothing under the last selected object)" 01791 _R(IDS_SLICEUNDERFAIL2), // "Click to select the #1%S; (Nothing under the last selected object)" 01792 _R(IDS_SLICEUNDERFAIL3), // "Click to deselect the #1%S; (Nothing under the last selected object)" 01793 pActionNode); 01794 break; 01795 case CLICKACTION_SELUNDERFAIL2: 01796 Append(pStr,cmods, 01797 _R(IDS_SLICEUNDERFAIL21), // "Click to select the #1%S alone; (The last selected object is not under the pointer)" 01798 _R(IDS_SLICEUNDERFAIL22), // "Click to select the #1%S; (The last selected object is not under the pointer)" 01799 _R(IDS_SLICEUNDERFAIL23), // "Click to deselect the #1%S; (The last selected object is not under the pointer)" 01800 pActionNode); 01801 break; 01802 case CLICKACTION_SELINSIDE: 01803 Append(pStr,cmods, 01804 _R(IDS_SLICEINSIDE1), // "Click to select the #1%S member of the last selected object alone" 01805 _R(IDS_SLICEINSIDE2), // "Click to select the #1%S member of the last selected object" 01806 _R(IDS_SLICEINSIDE3), // "Click to deselect the #1%S member of the last selected object" 01807 pActionNode); 01808 break; 01809 case CLICKACTION_SELINSIDECYCLE: 01810 Append(pStr,cmods, 01811 _R(IDS_SLICEINSIDECYCLE1), // "Click to select the top #1%S alone; (Reached the simplest object)" 01812 _R(IDS_SLICEINSIDECYCLE2), // "Click to select the top #1%S; (Reached the simplest object)" 01813 _R(IDS_SLICEINSIDECYCLE3), // "Click to deselect the top #1%S; (Reached the simplest object)" 01814 pActionNode); 01815 break; 01816 case CLICKACTION_SELINSIDEFAIL: 01817 Append(pStr, _R(IDS_SLICEINSIDEFAIL1)); // "Nothing inside this object" 01818 break; 01819 case CLICKACTION_SELINSIDEFAIL2: 01820 Append(pStr,cmods, 01821 _R(IDS_SLICEINSIDEFAIL21), // "Click to select the #1%S alone; (The pointer is not over a member of the last selected object)" 01822 _R(IDS_SLICEINSIDEFAIL22), // "Click to select the #1%S; (The pointer is not over a member of the last selected object)" 01823 _R(IDS_SLICEINSIDEFAIL23), // "Click to deselect the #1%S; (The pointer is not over a member of the last selected object)" 01824 pActionNode); 01825 break; 01826 case CLICKACTION_SELLEAF: 01827 Append(pStr,cmods, 01828 _R(IDS_SLICELEAF1), // "Click to select this #1%S alone" 01829 _R(IDS_SLICELEAF2), // "Click to select this #1%S" 01830 _R(IDS_SLICELEAF3), // "Click to deselect this #1%S" 01831 pActionNode); 01832 break; 01833 //-------------------------------------------------// 01834 default: 01835 ERROR3("Unknown Click action code!"); 01836 break; 01837 }; 01838 01839 // If we're in normal click mode (no modifiers down) then remind the user 01840 // that they can use the modifer keys... 01841 if (!cmods.Adjust && !cmods.Constrain && !cmods.Alternative1) 01842 Append(pStr,_R(IDS_SELOPTIONS)); 01843 } 01844 } 01845 01846 01847 01848 01849 /******************************************************************************************** 01850 01851 > ClickActionCode SliceTool::DetermineClickAction(NodeRenderableInk** ppActionNode, 01852 NodeRenderableInk* pLastClickNode, 01853 NodeRenderableInk* pClickSimpleNode, 01854 NodeRenderableInk* pClickCompoundNode, 01855 Spread* pStartSpread, 01856 DocCoord ClickStart, 01857 ClickModifiers ClickMods ) 01858 01859 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Phil's SelectorTool code 01860 Created: 11/10/1999 01861 Inputs: - 01862 Outputs: pNodeToSelect Pointer to pointer to node to select or NULL 01863 Returns: ActionCode describing what the click should do 01864 Purpose: Determine what action needs to be taken in response to a click. 01865 Errors: - 01866 SeeAlso: SliceTool::HandleButtonUp 01867 01868 ********************************************************************************************/ 01869 01870 SliceTool::ClickActionCode SliceTool::DetermineClickAction( NodeRenderableInk** ppActionNode, 01871 NodeRenderableInk* pLastClickNode, 01872 NodeRenderableInk* pClickSimpleNode, 01873 NodeRenderableInk* pClickCompoundNode, 01874 Spread* pStartSpread, 01875 DocCoord ClickStart, 01876 ClickModifiers ClickMods) 01877 { 01878 *ppActionNode = NULL; 01879 01880 //-------------------------------------- 01881 // Test "leaf" modifier... 01882 if (IsSelectLeafClick(ClickMods)) 01883 { 01884 // Go directly to leaf nodes! 01885 if (pClickSimpleNode != pClickCompoundNode) 01886 { 01887 *ppActionNode = pClickSimpleNode; 01888 01889 // <<<<< Inclusion by Mike 11/01/96 01890 // this stuff is to check whether any parent is responding to 01891 // AllowSelectInside() and returning FALSE. Selections will not go down 01892 // into these objects if so. 01893 01894 Node* pParentNode = pClickSimpleNode->FindParent(); 01895 while (pParentNode) 01896 { 01897 if (pParentNode->IsKindOf(CC_RUNTIME_CLASS(Layer))) 01898 break; 01899 if (pParentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk))) 01900 { 01901 if ( (!pParentNode->AllowSelectInside()) && 01902 ((NodeRenderableInk*)pParentNode)->CanSelectAsCompoundParent() 01903 ) 01904 { 01905 *ppActionNode = (NodeRenderableInk*)(pParentNode); 01906 } 01907 } 01908 if (pParentNode==pClickCompoundNode) 01909 break; 01910 pParentNode = pParentNode->FindParent(); 01911 } 01912 01913 // <<<<< End of inclusion 01914 } 01915 01916 // If we still haven't found what we're looking for 01917 // Cycle round to the top again... 01918 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_SELLEAF,CLICKACTION_SELNODE); 01919 } 01920 01921 //-------------------------------------- 01922 // Test "under" modifier... 01923 if (IsSelectUnderClick(ClickMods)) 01924 { 01925 // Try to perform a select under 01926 // First check that the context node is still under the pointer 01927 // If not then all we can do is a normal click operation... 01928 if (!ValidateLastClickUnder(pLastClickNode,pStartSpread,ClickStart)) 01929 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_SELUNDERFAIL2,CLICKACTION_SELUNDERFAIL2); 01930 01931 // Find the leaf node at the click position, but only search nodes 01932 // before the last clicked node. 01933 *ppActionNode = NodeRenderableInk::FindSimpleAtPoint(pStartSpread,ClickStart,pLastClickNode); 01934 // Then find a compound node containing the leaf, preferably a sibling 01935 // of the last clicked node. 01936 *ppActionNode = NodeRenderableInk::FindCompoundFromSimple(*ppActionNode,pLastClickNode); 01937 01938 // If the "under" node turns out to be the node we started from 01939 // return a failure code but go ahead and re-select it... 01940 // (If we failed to find anything under the last node, and the last node is the top node) 01941 if (*ppActionNode==NULL && pLastClickNode == pClickCompoundNode) 01942 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_SELUNDERFAIL,CLICKACTION_SELUNDERFAIL); 01943 01944 // If we still haven't found what we're looking for 01945 // Cycle round to the top again... 01946 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_SELUNDER,CLICKACTION_SELUNDERCYCLE); 01947 } 01948 01949 //-------------------------------------- 01950 // Test "member" modifier... 01951 if (IsSelectMemberClick(ClickMods)) 01952 { 01953 // See if the clicked simple node is a descendent of the last clicked node 01954 if (!ValidateLastClickInside(pLastClickNode,pClickSimpleNode)) 01955 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_SELINSIDEFAIL2,CLICKACTION_SELINSIDEFAIL2); 01956 01957 // If the node we're going to look inside is not compound and it's the top node 01958 // return a failure code but go ahead and re-select it... 01959 if (pLastClickNode && !pLastClickNode->IsCompound() && pLastClickNode == pClickCompoundNode) 01960 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_SELINSIDEFAIL,CLICKACTION_SELINSIDEFAIL); 01961 01962 // Try to perform a select inside 01963 *ppActionNode = NodeRenderableInk::FindInnerCompound(pClickSimpleNode,pLastClickNode); 01964 01965 // If we still haven't found what we're looking for 01966 // Cycle round to the top again... 01967 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_SELINSIDE,CLICKACTION_SELINSIDECYCLE); 01968 } 01969 01970 //-------------------------------------- 01971 // OK, so no modifiers are currently down 01972 // Just try to do a normal click action... 01973 return CycleClickAction(ppActionNode,pClickCompoundNode,CLICKACTION_NONE,CLICKACTION_SELNODE); 01974 } 01975 01976 01977 01978 /******************************************************************************************** 01979 01980 > BOOL SliceTool::ValidateLastClickUnder(NodeRenderableInk* pLastClickNode, DocCoord ClickStart) 01981 01982 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Phil's SelectorTool code 01983 Created: 11/10/1999 01984 Inputs: - 01985 Outputs: pLastClickNode Pointer to last node selected or NULL 01986 Returns: TRUE if last click node is still under the pointer (somewhere) 01987 FALSE otherwise 01988 Purpose: Validate that the last click node is still under the pointer 01989 Note! This routine can be slow depending on how deep it has to look in the 01990 tree for the last selected object. 01991 Errors: - 01992 SeeAlso: SliceTool::HandleButtonUp 01993 01994 ********************************************************************************************/ 01995 01996 BOOL SliceTool::ValidateLastClickUnder(NodeRenderableInk* pLastClickNode, Spread* pStartSpread, DocCoord ClickStart) 01997 { 01998 NodeRenderableInk* pSearchNode = NULL; 01999 do 02000 { 02001 pSearchNode = NodeRenderableInk::FindSimpleAtPoint(pStartSpread,ClickStart,pSearchNode); 02002 } 02003 while (pSearchNode && pLastClickNode!=NodeRenderableInk::FindCompoundFromSimple(pSearchNode,pLastClickNode)); 02004 02005 return (pSearchNode!=NULL); 02006 } 02007 02008 02009 02010 02011 /******************************************************************************************** 02012 02013 > BOOL SliceTool::ValidateLastClickInside(NodeRenderableInk* pLastClickNode,NodeRenderableInk* pClickSimpleNode) 02014 02015 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Phil's SelectorTool code 02016 Created: 11/10/1999 02017 Inputs: - 02018 Outputs: pLastClickNode Pointer to last node selected or NULL 02019 Returns: TRUE if the simple clicked node is inside the last clicked node somewhere 02020 FALSE otherwise 02021 Purpose: Validate that the simple node is inside the last clicked node 02022 Errors: - 02023 SeeAlso: SliceTool::HandleButtonUp 02024 02025 ********************************************************************************************/ 02026 02027 BOOL SliceTool::ValidateLastClickInside(NodeRenderableInk* pLastClickNode,NodeRenderableInk* pClickSimpleNode) 02028 { 02029 Node* pSearchNode = pClickSimpleNode; 02030 while (pSearchNode && pSearchNode!=pLastClickNode) 02031 pSearchNode = pSearchNode->FindParent(); 02032 return (pSearchNode!=NULL); 02033 } 02034 02035 02036 02037 /******************************************************************************************** 02038 02039 > ClickActionCode SliceTool::CycleClickAction(NodeRenderableInk** ppActionNode, 02040 NodeRenderableInk* pClickCompoundNode, 02041 ClickActionCode foundAction, 02042 ClickActionCode cycleAction) 02043 02044 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Phil's SelectorTool code 02045 Created: 11/10/1999 02046 Inputs: - 02047 Outputs: pNodeToSelect Pointer to pointer to node to select or NULL 02048 Returns: ActionCode describing what the click should do 02049 Purpose: Determine what action needs to be taken in response to a click. 02050 Errors: - 02051 SeeAlso: SliceTool::DetermineClickAction 02052 02053 ********************************************************************************************/ 02054 02055 SliceTool::ClickActionCode SliceTool::CycleClickAction( NodeRenderableInk** ppActionNode, 02056 NodeRenderableInk* pClickCompoundNode, 02057 ClickActionCode foundAction, 02058 ClickActionCode cycleAction ) 02059 { 02060 // If we have found a node then return the specified action code... 02061 if (*ppActionNode) 02062 { 02063 return foundAction; 02064 } 02065 // Else no suitable node so see whether the click occurred over a compound node 02066 else 02067 { 02068 // If click occurred over a compound node then we can return that 02069 // along with the alternative action code... 02070 if (pClickCompoundNode) 02071 { 02072 *ppActionNode = pClickCompoundNode; 02073 return cycleAction; 02074 } 02075 else 02076 // Else if there wasn't even a compound node we must return the information that 02077 // the click occurred over white space... 02078 { 02079 *ppActionNode = NULL; 02080 return CLICKACTION_SELNONE; 02081 } 02082 } 02083 } 02084 02085 02086 02087 /******************************************************************************************** 02088 02089 > static void SliceTool::SetStatusText(String_256* pStr) 02090 02091 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02092 Created: 13/10/94 02093 Inputs: pStr pointer to the string to display 02094 Outputs: - 02095 Returns: - 02096 Purpose: Sets the status bar text to the given string. 02097 Errors: - 02098 SeeAlso: - 02099 02100 ********************************************************************************************/ 02101 void SliceTool::SetStatusText(String_256* pStr) 02102 { 02103 GetApplication()->UpdateStatusBarText(pStr); 02104 } 02105 02106 02107 02108 /******************************************************************************************** 02109 02110 > static void SliceTool::SetStatusText(UINT32 nStringID) 02111 02112 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02113 Created: 12/10/94 02114 Inputs: nStringID the numeric identifier of the string resource 02115 Outputs: - 02116 Returns: - 02117 Purpose: Sets the status bar text to the given string. Alternative to loading the 02118 string yourself and calling the other SetStatusText function. 02119 Errors: - 02120 SeeAlso: - 02121 02122 ********************************************************************************************/ 02123 void SliceTool::SetStatusText(UINT32 nStringID) 02124 { 02125 String_256 str(nStringID); 02126 SetStatusText(&str); 02127 } 02128 02129 02130 02131 /******************************************************************************************** 02132 02133 > BOOL SliceTool::IsTranslateShortcut(ClickModifiers cmods) const 02134 02135 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02136 Created: 5/10/94 02137 Inputs: - 02138 Outputs: - 02139 Returns: TRUE if the translate shortcut keys are detected. 02140 Purpose: Detects whether the current mouse click modifiers denote the translate 02141 drag operation shortcut. 02142 Errors: - 02143 SeeAlso: - 02144 02145 ********************************************************************************************/ 02146 02147 BOOL SliceTool::IsTranslateShortcut(ClickModifiers cmods) const 02148 { 02149 return cmods.Constrain && cmods.Alternative1; 02150 } 02151 02152 02153 02154 02155 /******************************************************************************************** 02156 02157 > BOOL SliceTool::IsClickModified(ClickModifiers cmods) const 02158 02159 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02160 Created: 29/9/94 02161 Inputs: - 02162 Outputs: - 02163 Returns: TRUE if the current click is "modified". 02164 Purpose: Tests whether any of the modifiers, eg. Constrain, Adjust etc, apply to 02165 the current mouse click (as received by the OnClick function). 02166 Errors: - 02167 SeeAlso: SliceTool::HandleSingleClick 02168 02169 ********************************************************************************************/ 02170 02171 BOOL SliceTool::IsClickModified(ClickModifiers cmods) const 02172 { 02173 return cmods.Adjust || cmods.Constrain || cmods.Alternative1 || cmods.Menu; 02174 } 02175 02176 02177 02178 02179 /******************************************************************************************** 02180 02181 > BOOL SliceTool::IsSelectUnderClick(ClickModifiers cmods) const 02182 02183 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02184 Created: 14/10/94 02185 Inputs: - 02186 Outputs: - 02187 Returns: TRUE if the current click signifies the object below the clicked object 02188 should be selected, FALSE otherwise. 02189 Purpose: Decides whether the current click is modified to be an "under" click or not 02190 Errors: - 02191 SeeAlso: SliceTool::HandleSingleClick 02192 02193 ********************************************************************************************/ 02194 02195 BOOL SliceTool::IsSelectUnderClick(ClickModifiers cmods) const 02196 { 02197 return (!cmods.Constrain && cmods.Alternative1); 02198 } 02199 02200 02201 02202 02203 /******************************************************************************************** 02204 02205 > BOOL SliceTool::IsSelectMemberClick(ClickModifiers cmods) const 02206 02207 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02208 Created: 24/11/94 02209 Inputs: - 02210 Outputs: - 02211 Returns: TRUE if the last click indicated "select-inside". 02212 Purpose: Reports whether the current mouse click meant the user wanted to "select- 02213 inside" or not. 02214 Errors: - 02215 SeeAlso: SliceTool::HandleButtonUp 02216 02217 ********************************************************************************************/ 02218 02219 BOOL SliceTool::IsSelectMemberClick(ClickModifiers cmods) const 02220 { 02221 return (cmods.Constrain && cmods.Alternative1); 02222 } 02223 02224 02225 02226 /******************************************************************************************** 02227 02228 > BOOL SliceTool::IsSelectLeafClick(ClickModifiers cmods) const 02229 02230 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02231 Created: 24/11/94 02232 Inputs: - 02233 Outputs: - 02234 Returns: TRUE if the last click indicated "select-leaf". 02235 Purpose: Reports whether the current mouse click meant the user wanted to "select- 02236 leaf" or not. 02237 Errors: - 02238 SeeAlso: SliceTool::HandleButtonUp 02239 02240 ********************************************************************************************/ 02241 02242 BOOL SliceTool::IsSelectLeafClick(ClickModifiers cmods) const 02243 { 02244 return (cmods.Constrain && !cmods.Alternative1); 02245 } 02246 02247 02248 02249 /******************************************************************************************** 02250 02251 > NodeRenderableInk* SliceTool::FindFrom(NodeRenderableInk* pSimpleNode) const 02252 02253 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 02254 Created: 11/1/95 02255 Inputs: pSimpleNode the simple node to begin searching from 02256 Outputs: - 02257 Returns: The compound object the simple node is part of, if any, or pSimpleNode 02258 if it isn't. 02259 Purpose: Front-end short-hand for NodeRenderableInk::FindCompoundFromSimple 02260 Errors: - 02261 SeeAlso: NodeRenderableInk::FindCompoundFromSimple 02262 02263 ********************************************************************************************/ 02264 02265 NodeRenderableInk* SliceTool::FindFrom(NodeRenderableInk* pSimpleNode) const 02266 { 02267 return NodeRenderableInk::FindCompoundFromSimple(pSimpleNode); 02268 } 02269 02270 02271 02272 /******************************************************************************************** 02273 02274 > BOOL SliceTool::Append(String_256* pStr, ClickModifiers cmods, UINT32 resID, NodeRenderableInk* pActionNode = NULL) 02275 02276 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02277 Created: 31/5/95 02278 Inputs: - 02279 Outputs: - 02280 Returns: - 02281 Purpose: - 02282 Errors: - 02283 02284 ********************************************************************************************/ 02285 02286 BOOL SliceTool::Append(String_256* pStr, ClickModifiers cmods, 02287 UINT32 SelectID, 02288 UINT32 AddID, 02289 UINT32 RemoveID, 02290 NodeRenderableInk* pActionNode) 02291 { 02292 ERROR2IF(SelectID==0, FALSE, "Asked to append a string resource with a null ID"); 02293 02294 // Append a message to the string, preceding it with a separator if there was something 02295 // already in the string... 02296 if (!pStr->IsEmpty()) 02297 *pStr += String_256(_R(IDS_SLICE_SEPARATOR)); 02298 02299 String_256 Message; 02300 UINT32 TemplateID = 0; 02301 Message.Empty(); 02302 02303 if (!cmods.Adjust || pActionNode==NULL) 02304 TemplateID = SelectID; 02305 else 02306 { 02307 if (!pActionNode->IsSelected()) 02308 TemplateID = AddID; 02309 else 02310 TemplateID = RemoveID; 02311 } 02312 02313 if (TemplateID==0) 02314 TemplateID = SelectID; 02315 02316 if (pActionNode==NULL) 02317 *pStr += String_256(TemplateID); 02318 else 02319 { 02320 Message._MakeMsg( (TCHAR*) String_256(TemplateID), &pActionNode->Describe(FALSE) ); 02321 *pStr += Message; 02322 } 02323 02324 return TRUE; 02325 } 02326 02327 02328 02329 02330 /******************************************************************************************** 02331 02332 > BOOL SliceTool::Append(String_256* pStr, UINT32 resID) 02333 02334 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02335 Created: 31/5/95 02336 Inputs: - 02337 Outputs: - 02338 Returns: - 02339 Purpose: - 02340 Errors: - 02341 02342 ********************************************************************************************/ 02343 02344 BOOL SliceTool::Append(String_256* pStr, UINT32 StringID) 02345 { 02346 // Append a message to the string, preceding it with a separator if there was something 02347 // already in the string... 02348 if (!pStr->IsEmpty()) 02349 *pStr += String_256(_R(IDS_SLICE_SEPARATOR)); 02350 *pStr += String_256(StringID); 02351 02352 return TRUE; 02353 } 02354 02355 02356 02357 02358 /******************************************************************************************** 02359 02360 > BOOL SliceTool::Append(String_256* pStr, String_256 String) 02361 02362 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02363 Created: 31/5/95 02364 Inputs: - 02365 Outputs: - 02366 Returns: - 02367 Purpose: - 02368 Errors: - 02369 02370 ********************************************************************************************/ 02371 02372 BOOL SliceTool::Append(String_256* pStr, String_256 String) 02373 { 02374 // Append a message to the string, preceding it with a separator if there was something 02375 // already in the string... 02376 if (!pStr->IsEmpty()) 02377 *pStr += String_256(_R(IDS_SLICE_SEPARATOR)); 02378 *pStr += String; 02379 02380 return TRUE; 02381 } 02382 02383 02384 02385 02386 /******************************************************************************************** 02387 02388 > BOOL SliceTool::Append(String_256* pStr, 02389 String_256 SelectTemplate, 02390 String_256 AddTemplate, 02391 String_256 RemoveTemplate, 02392 NodeRenderableInk* pActionNode) 02393 02394 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 02395 Created: 01/06/95 02396 Inputs: - 02397 Outputs: - 02398 Returns: - 02399 Purpose: - 02400 Errors: - 02401 02402 ********************************************************************************************/ 02403 02404 BOOL SliceTool::Append(String_256* pStr, 02405 ClickModifiers cmods, 02406 String_256 SelectTemplate, 02407 String_256 AddTemplate, 02408 String_256 RemoveTemplate, 02409 NodeRenderableInk* pActionNode) 02410 { 02411 ERROR2IF(SelectTemplate.IsEmpty(), FALSE, "Asked to Append an empty message"); 02412 02413 // Append a message to the string, preceding it with a separator if there was something 02414 // already in the string... 02415 if (!pStr->IsEmpty()) 02416 *pStr += String_256(_R(IDS_SLICE_SEPARATOR)); 02417 02418 String_256 Message; 02419 String_256* pTemplate; 02420 Message.Empty(); 02421 02422 if (!cmods.Adjust || pActionNode==NULL) 02423 pTemplate = &SelectTemplate; 02424 else 02425 { 02426 if (!pActionNode->IsSelected()) 02427 pTemplate = &AddTemplate; 02428 else 02429 pTemplate = &RemoveTemplate; 02430 } 02431 02432 if (pTemplate->IsEmpty()) 02433 pTemplate = &SelectTemplate; 02434 02435 if (pActionNode==NULL) 02436 *pStr += *pTemplate; 02437 else 02438 { 02439 Message._MakeMsg( (TCHAR*) *pTemplate, &pActionNode->Describe(FALSE) ); 02440 *pStr += Message; 02441 } 02442 02443 return TRUE; 02444 } 02445 02446 02447 02448 /******************************************************************************************** 02449 02450 > virtual void SliceTool::RenderToolBlobs(Spread* pSpread, DocRect* pClipRect) 02451 02452 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 02453 Created: 06/07/2000 02454 Inputs: pSpread the spread to render blobs for - must == this->SelectionSpread. 02455 pClipRect the rect to clip to - used to prevent unnecessary drawing. 02456 02457 Purpose: Render the SliceTool's tool blob. 02458 This consists of a bounding rect identical to that used when dragging the 02459 selection (dotted, red line), around whatever is currently selected. 02460 02461 See also: SLICETOOL_BLOBS #define at the top of this file to turn this off. 02462 02463 ********************************************************************************************/ 02464 void SliceTool::RenderToolBlobs(Spread* pSpread, DocRect* pClipRect) 02465 { 02466 #ifdef SLICETOOL_BLOBS 02467 // don't bother if there's no selection spread or if we're asked to render for 02468 // a spread which isn't the selection spread. 02469 if ( SelectionSpread == NULL || 02470 pSpread != SelectionSpread ) 02471 { 02472 return; 02473 } 02474 02475 // get the selected DocView - if we can't get it, then leave now. 02476 DocView* pView = DocView::GetSelected(); 02477 if (pView == NULL) 02478 return; 02479 02480 // sorry, this isn't the neatest programming. 02481 // The size of the SliceTool blob bitmap is about 10 pixels square. 02482 // The desired distance between blob and selection is 2 pixels. 02483 INT32 BlobGap = (INT32)(2 * pView->GetScaledPixelWidth().MakeDouble()); 02484 INT32 BlobRadius = (INT32)(10 * pView->GetScaledPixelWidth().MakeDouble()); 02485 BlobRadius /= 2; 02486 02487 // the absolute position of the blob - just left and below the top of the selection rect. 02488 DocCoord dcBlobPos( m_drBlobRect.hix + (BlobGap + BlobRadius), 02489 m_drBlobRect.hiy - (BlobGap + BlobRadius) ); 02490 02491 // render the blobs for all appropriate render regions. 02492 RenderRegion* pRegion = DocView::RenderOnTop(pClipRect, pSpread, ClippedEOR); 02493 while (pRegion != NULL) 02494 { 02495 pRegion->SaveContext(); 02496 02497 // draw a bounding box around the selection. 02498 pRegion->SetLineColour(COLOUR_XORSELECT); 02499 pRegion->DrawDragBounds(&m_drBlobRect); 02500 02501 // draw a little named-set bitmap to denote what sets are selected. 02502 switch (m_SetSelectionState) 02503 { 02504 case FullSetsSelected: 02505 pRegion->DrawBitmapBlob(dcBlobPos, _R(IDBMP_SLICE_SELALL)); 02506 break; 02507 02508 case HalfSetsSelected: 02509 pRegion->DrawBitmapBlob(dcBlobPos, _R(IDBMP_SLICE_SELSOME)); 02510 break; 02511 02512 case NoSetsSelected: 02513 pRegion->DrawBitmapBlob(dcBlobPos, _R(IDBMP_SLICE_SELNONE)); 02514 break; 02515 02516 default: 02517 ERROR3("SliceTool::RenderToolBlobs; unrecognised set-selection state!"); 02518 break; 02519 } 02520 02521 pRegion->RestoreContext(); 02522 02523 // Go on to the next render region, if any. 02524 pRegion = DocView::GetNextOnTop(pClipRect); 02525 } 02526 #endif 02527 } 02528 02529 02530 02531 /******************************************************************************************** 02532 > BOOL SliceTool::UpdateSelectionInfo() 02533 02534 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from JustinF's SelectorTool::UpdateSelectionInfo() code. 02535 Created: 14/10/1999 02536 Inputs: 02537 Outputs: 02538 Returns: TRUE if there is a current selection, 02539 FALSE if no object is selected. 02540 Purpose: Updates the slice tool's record of the spread and bounding rectangle 02541 of the current selection. 02542 Errors: 02543 SeeAlso: SliceTool::SelectChange 02544 ********************************************************************************************/ 02545 BOOL SliceTool::UpdateSelectionInfo() 02546 { 02547 // Reset all our infomation about the selection to "no selection". 02548 SelectionSpread = NULL; 02549 SelectionRect.MakeEmpty(); 02550 m_drBlobRect.MakeEmpty(); 02551 02552 // we want to take controller nodes into account in this selection. 02553 RangeControl rc = SelectRange->GetRangeControlFlags(); 02554 RangeControl rcOld = rc; 02555 rc.PromoteToParent = TRUE; 02556 SelectRange->Range::SetRangeControl(rc); 02557 02558 // Go find the first node in the selection, so that we can find out about its spread 02559 Node* pFirstNode = SelectRange->FindFirst(); 02560 if (pFirstNode != NULL) 02561 { 02562 // Find the spread that the selection lives on, if any, and its bounds. 02563 SelectionSpread = pFirstNode->FindParentSpread(); 02564 if (SelectionSpread != NULL) 02565 { 02566 // Update the bounding rectangle of the selection. 02567 SelectionRect = SelectRange->GetBoundingRect(); 02568 02569 // update our tool-blob rendering info. 02570 m_drBlobRect = SelectRange->GetBoundingRectForEorDragging(); 02571 02572 // call the name-gallery to update named set info. 02573 NameGallery* pNameGallery = NameGallery::Instance(); 02574 if (pNameGallery) 02575 pNameGallery->FastUpdateNamedSetSizes(); 02576 02577 // decide what set-selection info we'll be displaying. 02578 INT32 nSetSelection = SliceHelper::DoesSelectionOnlyContainCompleteSets(); 02579 m_SetSelectionState = (nSetSelection == 1) ? FullSetsSelected : 02580 (nSetSelection == 0) ? HalfSetsSelected : 02581 NoSetsSelected; 02582 02583 if (SelectionRect.IsEmpty()) 02584 SelectionRect.Inflate(1); 02585 } 02586 } 02587 02588 SelectRange->Range::SetRangeControl(rcOld); 02589 02590 // Return TRUE if there is a selection. 02591 return SelectionSpread != NULL; 02592 } 02593 02594 02595 02596 /******************************************************************************************** 02597 02598 > virtual BOOL SliceTool::DragFinished(DragEndType det) 02599 02600 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from JustinF's SelectorTool::DragFinished 02601 Created: 14/10/1999 02602 Inputs: det a code indicating how the drag was ended, 02603 eg. did the user hit ESCAPE and cancel it? 02604 Outputs: 02605 Returns: TRUE if the drag operation should be allowed to complete, 02606 FALSE to signal that the drag should be cancelled. 02607 Purpose: Called by TransOperation when a drag is finished. 02608 Allows the SliceTool to reset its cursors and update 02609 its current selection information. 02610 Errors: 02611 SeeAlso: 02612 02613 ********************************************************************************************/ 02614 BOOL SliceTool::DragFinished(DragEndType det) 02615 { 02616 // update the current cursor. 02617 SetKeyDownCursor(ClickModifiers::GetClickModifiers()); 02618 02619 // we always leave cancelling the drag to a capricious user. 02620 return TRUE; 02621 } 02622 02623 02624 02625 //---------------------------------------------- 02626 //---------------------------------------------- 02627 //---------------------------------------------- 02628 //---------------------------------------------- 02629 02630 02631 02632 /******************************************************************************************** 02633 02634 > MsgResult SliceInfoBarOp::Message(Msg* Message) 02635 02636 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02637 Created: 3/10/94 02638 Inputs: Message = The message to handle 02639 Outputs: - 02640 Returns: - 02641 Purpose: Slice info bar dialog message handler 02642 Errors: - 02643 SeeAlso: - 02644 02645 ********************************************************************************************/ 02646 02647 MsgResult SliceInfoBarOp::Message(Msg* Message) 02648 { 02649 if (IS_OUR_DIALOG_MSG(Message)) 02650 { 02651 DialogMsg* Msg = (DialogMsg*)Message; 02652 02653 switch(Msg->DlgMsg) 02654 { 02655 case DIM_CANCEL: 02656 m_InfoBarCreated = FALSE; 02657 Close(); // close the dlg 02658 break; 02659 02660 case DIM_CREATE: 02661 m_InfoBarCreated = TRUE; 02662 // Initialise the infobar controls here 02663 // This is sent when you create the infobar in your tool startup code 02664 SetStringGadgetValue(_R(IDC_ST_STATE), _R(IDS_ROLLOVER_DEFAULT), FALSE, 0); 02665 SetStringGadgetValue(_R(IDC_ST_STATE), _R(IDS_ROLLOVER_MOUSE), FALSE, 1); 02666 SetStringGadgetValue(_R(IDC_ST_STATE), _R(IDS_ROLLOVER_CLICKED), FALSE, 2); 02667 SetStringGadgetValue(_R(IDC_ST_STATE), _R(IDS_ROLLOVER_SELECTED), FALSE, 3); 02668 SetStringGadgetValue(_R(IDC_ST_STATE), _R(IDS_ROLLOVER_ALL), FALSE, 4); 02669 SetStringGadgetValue(_R(IDC_ST_STATE), _R(IDS_ROLLOVER_NONE), TRUE, 5); 02670 UpdateCurrentStateGadget(); 02671 02672 // set up the bar name bit and grey the buttons that are selection dependant 02673 // check again for the new bar name 02674 m_TopVisibleState = -1; 02675 02676 // set the bar name 02677 //g_BarName.MakeMsg(_R(IDS_BARNAME), 1); 02678 OnSelectionChanged(); 02679 break; 02680 02681 //NB: This means someone has altered the combo box. It doesn't mean 02682 //the selection has changed! 02683 case DIM_SELECTION_CHANGED: 02684 if(Msg->GadgetID == _R(IDC_ST_STATE)) 02685 { 02686 OpParam Param(GetSelectedValueIndex(_R(IDC_ST_STATE)), 0); 02687 OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_SHOWSTATE); 02688 if (pOpDesc != NULL) 02689 pOpDesc->Invoke((OpParam*)&Param); 02690 else 02691 { 02692 ERROR3("Couldn't find OPTOKEN_SHOWSTATE op descriptor"); 02693 } 02694 UpdateCurrentStateGadget(); 02695 } 02696 break; 02697 02698 case DIM_LFT_BN_CLICKED: 02699 switch(Msg->GadgetID) 02700 { 02701 case _R(IDC_ST_EXPORT): 02702 // run the Op that does the image slicing / rollover creation 02703 // from the back end 02704 { 02705 // matt-24/08/2000 02706 // Should check first that buttons exist in this document - same code as 02707 // used in Edit section below... 02708 02709 BOOL ok = TRUE; 02710 // nothing selected then test that the bar we think we are editing exists 02711 // warn if it doesn't 02712 if (!m_EditingBar) 02713 { 02714 String_256 defaultLayerName; 02715 defaultLayerName.Load(_R(IDS_ROLLOVER_DEFAULT)); 02716 Layer * pDef = SliceHelper::FindLayerCalled(defaultLayerName); 02717 02718 if (pDef == NULL || !SliceHelper::BarNameExists(pDef, g_BarName)) 02719 { 02720 ok = FALSE; 02721 InformWarning(_R(IDS_BAR_DOESNT_EXIST)); 02722 } 02723 } 02724 02725 if (ok) 02726 { 02727 OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_IMAGESLICE); 02728 if (pOpDesc != NULL) 02729 pOpDesc->Invoke();//(OpParam*)&Param); 02730 else 02731 { 02732 ERROR3("Couldn't find OPTOKEN_IMAGESLICE op descriptor"); 02733 } 02734 } 02735 } 02736 break; 02737 02738 case _R(IDC_NEW_BAR): 02739 // Brings up the edit/create bar dlg 02740 { 02741 // find a new bar name and put it in g_BarName 02742 String_256 DefLayerName; 02743 DefLayerName.Load(_R(IDS_ROLLOVER_DEFAULT)); 02744 Layer * pDef = SliceHelper::FindLayerCalled(DefLayerName); 02745 INT32 UnusedBarID = 0; 02746 String_256 NewBarName = ""; 02747 02748 do 02749 { 02750 UnusedBarID++; 02751 NewBarName.MakeMsg(_R(IDS_BARNAME), UnusedBarID); 02752 } 02753 while (pDef && SliceHelper::BarNameExists(pDef, NewBarName)); 02754 02755 // run the op to create a new bar 02756 OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_BARCREATIONDLG); 02757 if (pOpDesc != NULL) 02758 { 02759 OpParamBarCreationDlg Param(FALSE /*Creating*/, NewBarName, SliceHelper::CountButtonsInBar(NewBarName)); 02760 pOpDesc->Invoke((OpParam*)&Param); 02761 } 02762 else 02763 { 02764 ERROR3("Couldn't find OPTOKEN_BARCREATIONDLG op descriptor"); 02765 } 02766 } 02767 break; 02768 02769 case _R(IDC_EDIT_BAR): 02770 // Brings up the edit/create bar dlg 02771 { 02772 OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_BARCREATIONDLG); 02773 if (pOpDesc != NULL) 02774 { 02775 BOOL ok = TRUE; 02776 // nothing selected then test that the bar we think we are editing exists 02777 // warn if it doesn't 02778 if (!m_EditingBar) 02779 { 02780 String_256 DefLayerName; 02781 DefLayerName.Load(_R(IDS_ROLLOVER_DEFAULT)); 02782 Layer * pDef = SliceHelper::FindLayerCalled(DefLayerName); 02783 02784 if (pDef == NULL || !SliceHelper::BarNameExists(pDef, g_BarName)) 02785 { 02786 ok = FALSE; 02787 InformWarning(_R(IDS_BAR_DOESNT_EXIST)); 02788 } 02789 } 02790 02791 if (ok) 02792 { 02793 OpParamBarCreationDlg Param(TRUE /*editing*/, g_BarName, SliceHelper::CountButtonsInBar(g_BarName)); 02794 pOpDesc->Invoke((OpParam*)&Param); 02795 } 02796 } 02797 else 02798 { 02799 ERROR3("Couldn't find OPTOKEN_BARCREATIONDLG op descriptor"); 02800 } 02801 } 02802 break; 02803 02804 case _R(IDC_STATES): 02805 // Brings up the edit/create bar dlg 02806 { 02807 OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_BARSTATESDLG); 02808 if (pOpDesc != NULL) 02809 { 02810 BOOL ok = TRUE; 02811 // nothing selected then test that the bar we think we are editing exists 02812 // warn if it doesn't 02813 if (!m_EditingBar) 02814 { 02815 String_256 DefLayerName; 02816 DefLayerName.Load(_R(IDS_ROLLOVER_DEFAULT)); 02817 Layer * pDef = SliceHelper::FindLayerCalled(DefLayerName); 02818 02819 if (pDef == NULL || !SliceHelper::BarNameExists(pDef, g_BarName)) 02820 { 02821 ok = FALSE; 02822 InformWarning(_R(IDS_BAR_DOESNT_EXIST)); 02823 } 02824 } 02825 02826 if (ok) 02827 { 02828 OpParamBarStatesDlg ParamBarStatesDlg(g_BarName); 02829 pOpDesc->Invoke(&ParamBarStatesDlg); 02830 } 02831 } 02832 } 02833 break; 02834 02835 case _R(IDC_REDEFINE_STATE): 02836 // Brings up the edit/create bar dlg 02837 { 02838 OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_BARREDEFINESTATEDLG); 02839 if (pOpDesc != NULL) 02840 { 02841 FindCurrentState(); 02842 BOOL ok = TRUE; 02843 // nothing selected then test that the bar we think we are editing exists 02844 // warn if it doesn't 02845 if (!m_EditingBar) 02846 { 02847 String_256 DefLayerName; 02848 DefLayerName.Load(_R(IDS_ROLLOVER_DEFAULT)); 02849 Layer * pDef = SliceHelper::FindLayerCalled(DefLayerName); 02850 02851 if (pDef == NULL || !SliceHelper::BarNameExists(pDef, g_BarName)) 02852 { 02853 ok = FALSE; 02854 InformWarning(_R(IDS_BAR_DOESNT_EXIST)); 02855 } 02856 } 02857 02858 if (ok) 02859 { 02860 OpParamBarRedefineStateDlg ParamBarRedefineStateDlg(g_BarName, m_TopVisibleState); 02861 pOpDesc->Invoke(&ParamBarRedefineStateDlg); 02862 } 02863 } 02864 } 02865 break; 02866 02867 case _R(IDC_LIVE): // is the stretching live or not??? 02868 { 02869 NodeBarProperty* pNodeBarProperty = (NodeBarProperty*) Document::GetCurrent()->GetSetSentinel()->FindBarProperty(); 02870 INT32 BarNumber = SliceHelper::GetBarNumberFromBarName(g_BarName); 02871 02872 if (pNodeBarProperty && BarNumber < pNodeBarProperty->HowMany()) 02873 { 02874 BarDataType NewBarData = pNodeBarProperty->Bar(BarNumber); 02875 NewBarData.IsLive = !NewBarData.IsLive; 02876 02877 NameGallery * pNameGallery = NameGallery::Instance(); 02878 if (pNameGallery) 02879 pNameGallery->FastUpdateNamedSetSizes(); 02880 02881 pNodeBarProperty->MakeChange(BarNumber, NewBarData); 02882 } 02883 } 02884 02885 break; 02886 02887 } 02888 break; 02889 } 02890 02891 } 02892 else if (m_InfoBarCreated && MESSAGE_IS_A(Message, SpreadMsg)) 02893 { 02894 SpreadMsg* pSpreadMsg = (SpreadMsg*) Message; 02895 02896 switch (pSpreadMsg->Reason) 02897 { 02898 case SpreadMsg::LAYERCHANGES: 02899 UpdateCurrentStateGadget(); 02900 break; 02901 } 02902 } 02903 else if (m_InfoBarCreated && MESSAGE_IS_A(Message, LayerMsg)) 02904 { 02905 LayerMsg *TheMsg = (LayerMsg *) Message; 02906 02907 if (TheMsg->Reason == LayerMsg::LAYER_VISIBILITY_CHANGED) 02908 { 02909 UpdateCurrentStateGadget(); 02910 } 02911 } 02912 02913 // Karim MacDonald - 20/10/1999 02914 // for whenever someone announces that they have changed the selection. 02915 // FYI, this SelChangingMsg is also sent when you do (SelRange*)->Update(TRUE). 02916 else if (m_InfoBarCreated && MESSAGE_IS_A(Message, SelChangingMsg)) 02917 { 02918 SelChangingMsg* pSelChange = (SelChangingMsg*)Message; 02919 02920 if (pSelChange->State == SelChangingMsg::SelectionState::SELECTIONCHANGED || 02921 pSelChange->State == SelChangingMsg::SelectionState::NONCOLOURATTCHANGED) 02922 { 02923 OnSelectionChanged(); 02924 } 02925 } 02926 02927 // Karim 06/07/2000 - the slice tool needs to know if the view changes. 02928 else if (MESSAGE_IS_A(Message, DocViewMsg)) 02929 { 02930 if (pSliceTool != NULL) 02931 pSliceTool->ViewChanged( *((DocViewMsg*)Message) ); 02932 } 02933 02934 // If we've changed to a different document then get rid of the dlg. 02935 else if (MESSAGE_IS_A(Message, DocChangingMsg)) 02936 { 02937 DocChangingMsg* TheMsg = (DocChangingMsg*) Message; 02938 if (TheMsg->State == DocChangingMsg::BORN || TheMsg->State == DocChangingMsg::SELCHANGED) 02939 { 02940 // this will be a new set of named sets! 02941 NameGallery * pNameGallery = NameGallery::Instance(); 02942 if (pNameGallery) 02943 pNameGallery->FastUpdateNamedSetSizes(); 02944 } 02945 } 02946 02947 // Pass the message on to the immediate Slice class 02948 return (InformationBarOp::Message(Message)); 02949 } 02950 02951 02952 /******************************************************************************************** 02953 02954 > static INT32 SliceInfoBarOp::FindCurrentState() 02955 02956 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02957 Created: 18/8/99 02958 Returns: An ID as to what layers exist and are visible 02959 from the specailly named rollover states. 02960 02961 0 = default 02962 1 = mouse 02963 2 = clicked 02964 3 = selected 02965 4 = all the above 02966 5 = doesn't exactly match any of the above 02967 02968 NB. matches the order of the combo box options 02969 02970 Purpose: Scans the layers looking at which named states are visible 02971 02972 ********************************************************************************************/ 02973 02974 INT32 SliceInfoBarOp::FindCurrentState() 02975 { 02976 // find a spread? 02977 Spread* pSelSpread = Document::GetSelectedSpread(); 02978 if (pSelSpread == NULL) 02979 return 6; 02980 02981 // init the layer pointers 02982 Layer * pLayer = pSelSpread->FindFirstLayer(); 02983 02984 BOOL ActiveState[4]; 02985 String_32 StateName[4]; 02986 02987 StateName[DEFAULT].Load(_R(IDS_ROLLOVER_DEFAULT)); // = "Default"; 02988 StateName[MOUSE].Load(_R(IDS_ROLLOVER_MOUSE)); // = "Mouse"; 02989 StateName[CLICKED].Load(_R(IDS_ROLLOVER_CLICKED)); // = "Clicked"; 02990 StateName[SELECTED].Load(_R(IDS_ROLLOVER_SELECTED)); // = "Selected"; 02991 02992 INT32 i = 0; 02993 02994 // init the bools 02995 for (i = 0; i < 4 ; i++) 02996 ActiveState[i] = FALSE; 02997 02998 m_TopVisibleState = -1; 02999 03000 while (pLayer) 03001 { 03002 for (i = 0; i < 4 ; i++) 03003 { 03004 if (pLayer->GetLayerID().CompareTo(StateName[i]) == 0) 03005 { 03006 ActiveState[i] = pLayer->IsVisible(); 03007 if (ActiveState[i]) 03008 { 03009 if (m_TopVisibleState == -1 || m_TopVisibleState > i) 03010 m_TopVisibleState = i; 03011 } 03012 } 03013 } 03014 03015 pLayer = pLayer->FindNextLayer(); 03016 } 03017 03018 03019 if (ActiveState[0] && ActiveState[1] && (ActiveState[2] || !INCLUDE_CLICKED_STATE ) && ActiveState[3]) 03020 return 4; // all states 03021 03022 if (ActiveState[0] && !ActiveState[1] && !ActiveState[2] && !ActiveState[3]) 03023 return 0; // default state 03024 03025 if (!ActiveState[0] && ActiveState[1] && !ActiveState[2] && !ActiveState[3]) 03026 return 1; // mouse state 03027 03028 if (!ActiveState[0] && !ActiveState[1] && ActiveState[2] && !ActiveState[3]) 03029 return 2; // clicked state 03030 03031 if (!ActiveState[0] && !ActiveState[1] && !ActiveState[2] && ActiveState[3]) 03032 return 3; // selected state 03033 03034 if (!ActiveState[0] && !ActiveState[1] && !ActiveState[2] && !ActiveState[3]) 03035 return 5; // no states 03036 03037 return 6; // another state 03038 } 03039 03040 /******************************************************************************************** 03041 03042 > void SliceInfoBarOp::OnSelectionChanged() 03043 03044 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03045 Created: 4/10/99 03046 Returns: - 03047 Purpose: Should be called everytime something changes the selection, 03048 so that the correct buttons are highlit and the correct 03049 text is placed in the barname edit field. 03050 ********************************************************************************************/ 03051 void SliceInfoBarOp::OnSelectionChanged() 03052 { 03053 // find out what the bar id should be - the next one to be used or the selected one 03054 Spread* pSpread = Document::GetSelectedSpread(); 03055 03056 // is it part of a animation? 03057 // test the current frame if it is a frame or a layer 03058 if (pSpread != NULL) 03059 { 03060 Layer * ActiveLayer = pSpread->FindActiveLayer(); 03061 if (ActiveLayer && ActiveLayer->IsFrame()) 03062 { 03063 // can't do lots of these things if we are in an animation 03064 EnableGadget(_R(IDC_NEW_BAR), FALSE); 03065 EnableGadget(_R(IDC_EDIT_BAR), FALSE); 03066 EnableGadget(_R(IDC_STATES), FALSE); 03067 EnableGadget(_R(IDC_LIVE), FALSE); 03068 EnableGadget(_R(IDC_ST_EXPORT), FALSE); 03069 EnableGadget(_R(IDC_ST_STATE), FALSE); 03070 } 03071 else 03072 { 03073 // get the selection 03074 Range Sel(*(GetApplication()->FindSelection())); 03075 03076 // set the range flags so it includes shadow and bevel manager nodes 03077 RangeControl rg = Sel.GetRangeControlFlags(); 03078 rg.PromoteToParent = TRUE; 03079 rg.IgnoreInvisibleLayers = TRUE; 03080 Sel.Range::SetRangeControl(rg); 03081 03082 m_EditingBar = FALSE; 03083 g_BarName = GetNextUnusedBarName(&Sel, &m_EditingBar); 03084 INT32 BarNo = SliceHelper::GetBarNumberFromBarName(g_BarName); 03085 NodeBarProperty* pNodeBarProperty = (NodeBarProperty*) Document::GetCurrent()->GetSetSentinel()->FindBarProperty(); 03086 BOOL IsBar = pNodeBarProperty && BarNo < pNodeBarProperty->HowMany(); 03087 03088 SetStringGadgetValue(_R(IDC_ST_BARNAME), &g_BarName); 03089 03090 EnableGadget(_R(IDC_NEW_BAR), !m_EditingBar && Sel.Count() >= 1); 03091 EnableGadget(_R(IDC_EDIT_BAR), TRUE /*m_EditingBar || BarNo > 0*/); 03092 EnableGadget(_R(IDC_STATES), TRUE /*m_EditingBar || BarNo > 0*/); 03093 EnableGadget(_R(IDC_LIVE), IsBar); 03094 EnableGadget(_R(IDC_ST_EXPORT), TRUE); 03095 EnableGadget(_R(IDC_ST_STATE), TRUE); 03096 03097 // set the live tick 03098 SetLongGadgetValue(_R(IDC_LIVE), IsBar && pNodeBarProperty->Bar(BarNo).IsLive); 03099 } 03100 } 03101 03102 // Karim - 19/10/1999 03103 // inform the SliceTool that the selection has changed. 03104 if (pSliceTool != NULL) 03105 pSliceTool->SelectionHasChanged(); 03106 } 03107 03108 03109 /******************************************************************************************** 03110 03111 > String_256 SliceInfoBarOp::GetNextUnusedBarName(Range * pSel, BOOL * pFromSel) 03112 03113 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03114 Created: 4/10/99 03115 Returns: The text that is the bar name to put in the bar name field 03116 Params: pSel - A pointer to the selection range 03117 pFromSel- Fills in this bool that says if the name 03118 was taken from the selection or not. 03119 Purpose: It checks the selection to see if it is part of a bar. 03120 If it was it returns that name. 03121 If not it returns the next good name to use for a bar, 03122 that isn't currently in use. 03123 ********************************************************************************************/ 03124 String_256 SliceInfoBarOp::GetNextUnusedBarName(Range * pSel, BOOL * pFromSel) 03125 { 03126 String_256 NewBarName = ""; 03127 03128 *pFromSel = FALSE; 03129 03130 Spread* pSpread = Document::GetSelectedSpread(); 03131 if (pSpread == NULL) 03132 return g_BarName; 03133 03134 if (pSel) 03135 { 03136 Node * pCurrent = pSel->FindFirst(); 03137 // for each node in the selection 03138 while (pCurrent) 03139 { 03140 // does the selection contain a named bar ? 03141 // if it does we will edit this and return it here 03142 if (ScanFromNodeForBarMembers(pCurrent, NewBarName)) 03143 { 03144 *pFromSel = TRUE; 03145 return NewBarName; 03146 } 03147 03148 pCurrent = pSel->FindNext(pCurrent); 03149 } 03150 03151 // no actual bar in selection so does the selection cross a bar? 03152 SliceHelper::BarNameInRect(pSel->GetBoundingRect(), &g_BarName); 03153 } 03154 03155 return g_BarName; // keep what we had before 03156 } 03157 03158 03159 /******************************************************************************************** 03160 03161 > BOOL SliceInfoBarOp::ScanFromNodeForBarMembers(Node * pNode, String_256 &BarName, String_256 * pButtonName) 03162 03163 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03164 Created: 4/10/99 03165 Returns: The text that is the bar name to put in the bar name field 03166 Params: pNode - The node to check from 03167 BarName - Fills in this string with the name of the bar found. 03168 pButtonName - If provided fills in the button name found in a bar. 03169 Purpose: Checks from a given node down looking for the first template attrib (set name) 03170 Once found it returns TRUE and fills in the bar name string from the question 03171 of the template attrib and if a ptr to a string was passed for the button name 03172 it fills this in too. 03173 NB. This function is RECURSIVE 03174 ********************************************************************************************/ 03175 BOOL SliceInfoBarOp::ScanFromNodeForBarMembers(Node * pNode, String_256 &BarName, String_256 * pButtonName) 03176 { 03177 if (!BarName.IsEmpty()) 03178 return TRUE; 03179 03180 if (pNode->IsAnAttribute()) 03181 { 03182 if (pNode->IsKindOf(CC_RUNTIME_CLASS(TemplateAttribute))) 03183 { 03184 BarName = SliceHelper::GetBarName((TemplateAttribute *)pNode); 03185 03186 // found a bar name? then set the button name too 03187 if (!BarName.IsEmpty() && pButtonName) 03188 *pButtonName = ((TemplateAttribute *)pNode)->GetParam(); 03189 } 03190 } 03191 else // find anything else interesting? 03192 { 03193 Node * pChildNode = pNode->FindFirstChild(); 03194 03195 while (pChildNode) 03196 { 03197 // ***recursive call*** 03198 if (ScanFromNodeForBarMembers(pChildNode, BarName, pButtonName)) 03199 return TRUE; 03200 pChildNode = pChildNode->FindNext(); 03201 } 03202 } 03203 03204 return FALSE; 03205 } 03206 03207 03208 03209 /******************************************************************************************** 03210 03211 > void SliceInfoBarOp::DealWithSingleClick(DocCoord PointerPos, 03212 ClickModifiers Mods, Spread * pSpread); 03213 03214 Author: Simon_Knight (Xara Group Ltd) <camelotdev@xara.com> from DavidMc 03215 Created: 4/10/99 & 16/6/99 03216 Inputs: 03217 Outputs: - 03218 Returns: - 03219 Purpose: Deals with a single click situation (i.e. no drag occurred) 03220 03221 ********************************************************************************************/ 03222 /* 03223 * Commented out by Karim MacDonald, 14/10/1999. 03224 * This function has been replaced by HandleClick() and the other 03225 * Handle...() functions. 03226 03227 void SliceInfoBarOp::DealWithSingleClick(DocCoord PointerPos, ClickModifiers Mods, 03228 Spread * pSpread) 03229 { 03230 // first, find out if the click is over an object 03231 NodeRenderableInk * pInk = NodeRenderableInk::FindSimpleAtPoint(pSpread, PointerPos); 03232 NodeRenderableInk * pCompound = NodeRenderableInk::FindCompoundFromSimple(pInk); 03233 03234 if (pCompound) 03235 { 03236 pInk = pCompound; 03237 } 03238 03239 // has the shift key been pressed ? 03240 BOOL bShift = Mods.Adjust; 03241 BOOL bRedraw = FALSE; 03242 SelRange Sel(*(GetApplication()->FindSelection())); 03243 03244 RangeControl rg = Sel.GetRangeControlFlags(); 03245 rg.PromoteToParent = TRUE; 03246 Sel.Range::SetRangeControl(rg); 03247 03248 DocRect RedrawRect = Sel.GetBlobBoundingRect(); 03249 03250 Document * pDoc = Document::GetCurrent(); 03251 03252 BlobManager* BlobMgr = GetApplication()->GetBlobManager(); 03253 03254 BlobStyle bs1(TRUE); 03255 BlobStyle bs2(FALSE); 03256 03257 if (pDoc && BlobMgr) 03258 { 03259 bs1 = BlobMgr->GetCurrentInterest(); 03260 BlobMgr->ToolInterest(bs2); 03261 pDoc->ForceRedraw(Document::GetSelectedSpread(), RedrawRect); 03262 } 03263 03264 if (pInk) 03265 { 03266 String_256 SetName; 03267 SetName.Empty(); 03268 03269 BOOL WasSelected = pInk->IsSelected(); 03270 03271 // change the selection 03272 if (!bShift) 03273 { 03274 NodeRenderableInk::DeselectAll(TRUE, FALSE); 03275 } 03276 03277 // set name shows the last set found 03278 // find the top shape on this layer 03279 Node *pParent = pInk->FindParent(); 03280 Node *pNode = pInk; 03281 while (!pParent->IsLayer()) 03282 { 03283 pNode = pParent; 03284 pParent = pNode->FindParent(); 03285 } 03286 SliceHelper::SelectAllSetsOfThisNode(pNode, SetName, bShift); 03287 03288 // the clicked chappie isn't in a set just select him 03289 if (SetName.IsEmpty()) 03290 { 03291 if (bShift) 03292 pInk->SetSelected(!WasSelected); 03293 else 03294 pInk->SetSelected(TRUE); 03295 } 03296 03297 GetApplication()->UpdateSelection(); 03298 03299 OnSelectionChanged(); 03300 } 03301 else 03302 { 03303 // deselect everything 03304 NodeRenderableInk::DeselectAll(TRUE, FALSE); 03305 GetApplication()->UpdateSelection(); 03306 03307 OnSelectionChanged(); 03308 } 03309 03310 // force a redraw on the area 03311 if (pDoc && BlobMgr) 03312 { 03313 BlobMgr->ToolInterest(bs1); 03314 pDoc->ForceRedraw(Document::GetSelectedSpread(), RedrawRect); 03315 } 03316 }*/ 03317 03318 03319 03320 //----------------------------------------------- 03321 //----------------------------------------------- 03322 //----------------------------------------------- 03323 //----------------------------------------------- 03324 03325 03326 03327 /******************************************************************************************** 03328 03329 > void OpSliceDragBox::StartDragBox( Spread* pSpread, 03330 DocCoord Anchor, 03331 ClickModifiers ClickMods) 03332 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpSelectorDragBox code. 03333 Created: 11/10/1999 03334 Inputs: Anchor - The position of the mouse at the start of the Drag 03335 Purpose: This is called when a Drag operation has been detected 03336 03337 ********************************************************************************************/ 03338 void OpSliceDragBox::StartDragBox(Spread* pSpread, DocCoord Anchor, ClickModifiers ClickMods) 03339 { 03340 // We had better take a note of the starting point of the drag 03341 StartSpread = pSpread; 03342 StartPoint = Anchor; 03343 LastMousePosition = Anchor; 03344 03345 // Put some helpful text in the status bar. 03346 SliceTool::SetStatusText(_R(IDS_SLICE_DRAGBOXTEXT)); 03347 03348 // And tell the Dragging system that we need drags to happen 03349 StartDrag(DRAGTYPE_AUTOSCROLL); 03350 } 03351 03352 03353 03354 /******************************************************************************************** 03355 03356 > void OpSliceDragBox::DragFinished( DocCoord PointerPos, 03357 ClickModifiers ClickMods, 03358 BOOL Success, BOOL bSolidDrag) 03359 03360 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpSelectorDragBox code. 03361 Created: 11/10/1999 03362 Inputs: PointerPos - The position of the mouse at the end of the drag 03363 ClickMods - the key modifiers being pressed 03364 Success - TRUE if the drag was terminated properly, FALSE if it 03365 was ended with the escape key being pressed 03366 Purpose: This is called when a drag operation finishes. This removes the EORed drag 03367 rect from the screen and then selects all the objects that were in it. 03368 It then goes through these objects, selecting all other objects sharing a name 03369 with any of them. 03370 SeeAlso: ClickModifiers 03371 ********************************************************************************************/ 03372 void OpSliceDragBox::DragFinished( DocCoord PointerPos, 03373 ClickModifiers ClickMods, 03374 Spread* pSpread, BOOL Success, BOOL bSolidDrag) 03375 { 03376 // Build the rectangle of the drag box at the end of the drag 03377 DocRect BoundingRect(MIN(StartPoint.x, LastMousePosition.x), 03378 MIN(StartPoint.y, LastMousePosition.y), 03379 MAX(StartPoint.x, LastMousePosition.x), 03380 MAX(StartPoint.y, LastMousePosition.y)); 03381 03382 // First Rub out the old box 03383 RenderDragBlobs(BoundingRect, StartSpread, bSolidDrag); 03384 03385 // Put the hourglass up 03386 BeginSlowJob(); 03387 03388 // we need this info in scope here, although it is used just below. 03389 SelRange* pSel = GetApplication()->FindSelection(); 03390 RangeControl rcOld = pSel->GetRangeControlFlags(); 03391 03392 // Go and try and select a few things 03393 if (Success) 03394 { 03395 // If we didn't drag with the right button then deselect everything prior to selecting 03396 // the "lasso-ed" objects. 03397 if (!ClickMods.Adjust) 03398 NodeRenderableInk::DeselectAll(TRUE, FALSE); 03399 03400 // Select the objects in the BoundingRect 03401 RangeControl rg = rcOld; 03402 rg.IgnoreInvisibleLayers = TRUE; 03403 rcOld = rg; 03404 rg.PromoteToParent = TRUE; 03405 pSel->Range::SetRangeControl(rg); 03406 SliceHelper::SelectAllSetsInRect(BoundingRect, pSpread, 03407 SliceHelper::SelStateAction::SET); 03408 03409 // End the Drag 03410 if (!EndDrag()) 03411 FailAndExecute(); 03412 } 03413 else 03414 { 03415 // Set up the flags that say it all went wrong. 03416 EndDrag(); 03417 FailAndExecute(); 03418 } 03419 03420 // return the app's selection range flags to their original state. 03421 pSel->Range::SetRangeControl(rcOld); 03422 03423 // Final end of the operation. 03424 End(); 03425 } 03426 03427 03428 03429 /******************************************************************************************** 03430 > BOOL OpSliceDragBox::Declare() 03431 03432 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpSelectorDragBox code. 03433 Created: 11/10/1999 03434 Returns: TRUE if all went OK, False otherwise. 03435 Purpose: Adds the operation to the list of all known operations. 03436 ********************************************************************************************/ 03437 BOOL OpSliceDragBox::Declare() 03438 { 03439 return RegisterOpDescriptor(0, _R(IDS_SLICE_BOX), CC_RUNTIME_CLASS(OpSliceDragBox), 03440 OPTOKEN_SLICE_DRAGBOX, OpSliceDragBox::GetState); 03441 } 03442 03443 03444 03445 /******************************************************************* 03446 03447 > OpState OpSliceDragBox::GetState(String_256*, OpDescriptor*) 03448 03449 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpSelectorDragBox code. 03450 Created: 11/10/1999 03451 Inputs: 03452 Outputs: Description GetState fills this string with an approriate description 03453 of the current state of the SliceTool. 03454 Returns: The state of the operation, so that menu items (ticks and greying) can be 03455 done properly. 03456 Purpose: Find out the state of the operation at the specific time. 03457 Errors: 03458 See also: 03459 03460 *******************************************************************/ 03461 OpState OpSliceDragBox::GetState(String_256*, OpDescriptor*) 03462 { 03463 OpState os; 03464 03465 return os; 03466 } 03467 03468 03469 03470 //----------------------------------------------- 03471 //----------------------------------------------- 03472 //----------------------------------------------- 03473 //----------------------------------------------- 03474 03475 03476 03477 RectListItem::RectListItem(DocRect source) : m_Rect(source) 03478 { 03479 // empty. 03480 } 03481 03482 03483 03484 DocRect RectListItem::GetRect() 03485 { 03486 return m_Rect; 03487 } 03488 03489 03490 03491 //----------------------------------------------- 03492 //----------------------------------------------- 03493 //----------------------------------------------- 03494 //----------------------------------------------- 03495 03496 03497 03498 /******************************************************************************************** 03499 03500 > OpSliceTranslate::OpSliceTranslate() 03501 03502 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03503 Created: 13/10/1999 03504 Purpose: Constructor. 03505 03506 ********************************************************************************************/ 03507 03508 OpSliceTranslate::OpSliceTranslate() : TransOperation() 03509 { 03510 //Set status line help 03511 StatusHelpID = _R(IDS_TRANSLTRANS_STATUS1); 03512 StatusHelpID2 = _R(IDS_TRANSLTRANS_STATUS2); 03513 CanScaleLines = FALSE; 03514 } 03515 03516 03517 03518 03519 /******************************************************************************************** 03520 03521 > void OpSliceTranslate::InitTransformImmediate(OpParam* pOpParam) 03522 03523 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03524 Created: 13/10/1999 03525 Inputs: pOpParam - The parameters that were passed into the operation 03526 Purpose: Sets up the transform ready for an immediate translation. This is called from 03527 DoWithParam() 03528 SeeAlso: TransOperation::DoWithParam() 03529 03530 ********************************************************************************************/ 03531 03532 void OpSliceTranslate::InitTransformImmediate(OpParam* pOpParam) 03533 { 03534 // Set the initial position 03535 StartPos = DocCoord(0,0); 03536 RawStartPos = StartPos; 03537 MagStartPos = StartPos; 03538 03539 // and copy the offset to translate by from Param2 03540 DocCoord* Offset = (DocCoord*)(pOpParam->Param2); 03541 LastPos.x = Offset->x; 03542 LastPos.y = Offset->y; 03543 03544 OriginalGridOffset.x=0; 03545 OriginalGridOffset.y=0; 03546 } 03547 03548 03549 /******************************************************************************************** 03550 03551 > virtual void OpSliceTranslate::InitTransformOnDrag(DocCoord PointerPos, ClickModifiers ClickMods) 03552 03553 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03554 Created: 13/10/1999 03555 Inputs: PointerPos - The position of the mouse at the start of the drag 03556 ClickMods - the keyboard modifiers that were active at the start of the drag 03557 Purpose: Sets up the parameters needed to build the transform matrix at the start 03558 of the drag. The base class version of this function does nothing. 03559 03560 ********************************************************************************************/ 03561 03562 void OpSliceTranslate::InitTransformOnDrag(DocCoord PointerPos, ClickModifiers ClickMods) 03563 { 03564 // make a note of the current mouse position 03565 LastPos = PointerPos; 03566 03567 // Record the offset from the mouse pos to the grid 03568 OriginalGridOffset = GetStartPos(); 03569 DocView::ForceSnapToGrid(StartSpread, &OriginalGridOffset); 03570 OriginalGridOffset = GetStartPos() - OriginalGridOffset; 03571 } 03572 03573 03574 03575 03576 /******************************************************************************************** 03577 03578 > virtual void OpSliceTranslate::UpdateTransformOnDrag(DocCoord PointerPos, Spread* pSpread, 03579 ClickModifiers& ClickMods) 03580 03581 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03582 Created: 13/10/1999 03583 Inputs: PointerPos - The latest position of the mouse 03584 Purpose: Updates the op's state variables (eg selection bounding rect) and 03585 its blobs whenever the mouse moves. 03586 03587 ********************************************************************************************/ 03588 03589 void OpSliceTranslate::UpdateTransformOnDrag( DocCoord PointerPos, Spread* pSpread, 03590 ClickModifiers& ClickMods ) 03591 { 03592 // get the bounding box of the dragged selection and update it's position. 03593 DocCoord Offset = PointerPos - LastPos; 03594 DocRect Bounds( BoundingData.x, BoundingData.y, 03595 BoundingData.x+BoundingData.Width, 03596 BoundingData.y+BoundingData.Height ); 03597 Bounds.lo = Bounds.lo + Offset; 03598 Bounds.hi = Bounds.hi + Offset; 03599 DocRect SnappedBounds = Bounds; 03600 03601 // if this drag is not being constrained, then see if we can snap to anything. 03602 if (!ClickMods.Constrain) 03603 { 03604 // Apply snapping to the pointer pos 03605 // First apply magnetic snapping alone 03606 if (MagneticGripPoint && DocView::SnapSelected(pSpread, &PointerPos, TRUE, FALSE)) 03607 { 03608 // Magnetic snapping worked! 03609 } 03610 else 03611 { 03612 // Magnetic snapping failed! 03613 03614 // If magnetic snapping failed then try grid snapping 03615 // on the adjusted coordinate 03616 if (ClickMods.Alternative1) 03617 { 03618 PointerPos = PointerPos - OriginalGridOffset; 03619 DocView::SnapSelected(pSpread, &PointerPos, FALSE, TRUE); 03620 PointerPos = PointerPos + OriginalGridOffset; 03621 } 03622 03623 // ok, try snapping the selection's bounds to anything in the document, 03624 // eg guidelines, other objects etc. 03625 else 03626 { 03627 if (DocView::SnapSelected(pSpread,&SnappedBounds,LastRawPos,RawPos)) 03628 PointerPos = PointerPos + (SnappedBounds.lo - Bounds.lo); 03629 03630 // right, nothing else has worked - how about trying to snap our bounding 03631 // rect to one of the bounding rects in our list? 03632 else 03633 { 03634 if (SnapRectToBoxList(pSpread, &SnappedBounds, LastRawPos, RawPos)) 03635 PointerPos = PointerPos + (SnappedBounds.lo - Bounds.lo); 03636 } 03637 } 03638 } 03639 } 03640 03641 // Update BoundingData's offset information and pass it to Bounds. 03642 INT32 dx = PointerPos.x - LastPos.x; 03643 INT32 dy = PointerPos.y - LastPos.y; 03644 BoundingData.x += dx; 03645 BoundingData.y += dy; 03646 BoundingData.XYChanged = TRUE; 03647 Bounds.lox = BoundingData.x; 03648 Bounds.loy = BoundingData.y; 03649 Bounds.hix = BoundingData.x + BoundingData.Width; 03650 Bounds.hiy = BoundingData.y + BoundingData.Height; 03651 03652 // do a collision-detection between the selection bounding rect and a list 03653 // of named-set bounding rect's we built at the start of the drag. 03654 // highlight our selection bounding rect if we collide. 03655 if (TestBoundingBoxCollision(&Bounds, pSpread)) 03656 { 03657 // new collision? if so, draw fresh blobs. 03658 if (!m_bDrawingBlobs) 03659 { 03660 m_DragRect = Bounds; 03661 m_bDrawingBlobs = TRUE; 03662 RenderDragBlobs(m_DragRect, StartSpread, FALSE); 03663 } 03664 03665 // otherwise, update the current blobs. 03666 else 03667 { 03668 // rub out old collision blobs. 03669 RenderDragBlobs(m_DragRect, StartSpread, FALSE); 03670 03671 // update the record of the selection bounds. 03672 m_DragRect = Bounds; 03673 03674 // draw new collision blobs. 03675 RenderDragBlobs(m_DragRect, StartSpread, FALSE); 03676 } 03677 } 03678 03679 // we're not presently colliding, so if we have to then 03680 // rub out any old blobs and invalidate the drag-rect. 03681 else 03682 { 03683 if (m_bDrawingBlobs) 03684 { 03685 // don't render the blobs from here anymore, and render them off. 03686 m_bDrawingBlobs = FALSE; 03687 RenderDragBlobs(m_DragRect, StartSpread, FALSE); 03688 03689 // invalidate the drag-rect, so that it won't be rendered from RenderDragBlobs(). 03690 m_DragRect.hix = m_DragRect.lox - 1; 03691 } 03692 } 03693 03694 // Make a mental note of the current position 03695 LastPos = PointerPos; 03696 03697 // Update the current spread (must do this if CanChangeSpread returns TRUE) 03698 CurrentSpread = pSpread; 03699 } 03700 03701 03702 03703 /******************************************************************************************** 03704 03705 > virtual BOOL OpSliceTranslate::CanChangeSpread() 03706 03707 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03708 Created: 05/June/2006 03709 Inputs: - 03710 Outputs: - 03711 Returns: TRUE if this transform allows the drag to be transferred to another spread 03712 Purpose: Tell the baseclass functions whether to draw drag feedback only on the start 03713 spread or to allow drag rendering to be done on other spreads too. 03714 03715 ********************************************************************************************/ 03716 03717 BOOL OpSliceTranslate::CanChangeSpread() 03718 { 03719 return TRUE; 03720 } 03721 03722 03723 /******************************************************************************************** 03724 03725 > BOOL OpSliceTranslate::SnapRectToBoxList( Spread* pSpread, DocRect* pDocRect, 03726 const DocCoord& PrevCoord, 03727 const DocCoord& CurCoord ) 03728 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03729 Created: 26/10/1999 03730 Inputs: pSpread a pointer to the relevant spread node. 03731 pDocRect a pointer to the rectangle to snap. 03732 PrevCoord a reference to the ??? 03733 CurCoord a reference to ??? 03734 Outputs: pDocRect may be moved so that it snaps to the side of one of this op's 03735 list of collision-rectangles. 03736 Returns: TRUE if pDocRect was snapped, 03737 FALSE otherwise. 03738 Purpose: Performs a snap check between the given rect and this op's own collection of 03739 collision bounding rects. The given rect is tested successively against each 03740 member of our list, and if it lies within snapping distance of any rectangle 03741 it will be shifted to snap to that rectangle. 03742 03743 This function does not live with all the other snap functions because it's 03744 use is restricted solely to the context of this operation. 03745 Errors: 03746 See also: All Snap member functions of all classes derived from NodeRenderableBounded. 03747 03748 ********************************************************************************************/ 03749 BOOL OpSliceTranslate::SnapRectToBoxList( Spread* pSpread, DocRect* pDocRect, 03750 const DocCoord& PrevCoord, 03751 const DocCoord& CurCoord ) 03752 { 03753 // iterate over our list of rectangles and check pDocRect against each one. 03754 BOOL bSnapped = FALSE; 03755 RectListItem* pCurListItem = (RectListItem*)m_lBoxes.GetHead(); 03756 while (!bSnapped && pCurListItem != NULL) 03757 { 03758 bSnapped = CSnap::SnapRectToRect(pDocRect, pCurListItem->GetRect()); 03759 pCurListItem = (RectListItem*)m_lBoxes.GetNext(pCurListItem); 03760 } 03761 03762 return bSnapped; 03763 } 03764 03765 03766 03767 /******************************************************************************************** 03768 03769 > void OpSliceTranslate::BuildMatrix() 03770 03771 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03772 Created: 13/10/1999 03773 Purpose: Builds the transform matrix required to rotate the selection about the 03774 point CentreOfRot by the required number of degrees 03775 03776 ********************************************************************************************/ 03777 03778 void OpSliceTranslate::BuildMatrix() 03779 { 03780 // Build a translation matrix by takeing the offset from the last mouse position 03781 // to the start mouse position 03782 Transform = Matrix(LastPos.x-GetStartPos().x, LastPos.y-GetStartPos().y); 03783 } 03784 03785 03786 03787 /******************************************************************************************** 03788 03789 > virtual BOOL OpSliceTranslate::ShouldPointerBeOffset() 03790 03791 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03792 Created: 13/10/1999 03793 Returns: FALSE 03794 Purpose: Tells the base class of the operation that we want our mouse coords to be 03795 left alone 03796 03797 ********************************************************************************************/ 03798 03799 BOOL OpSliceTranslate::ShouldPointerBeOffset() 03800 { 03801 return FALSE; 03802 } 03803 03804 03805 03806 03807 /******************************************************************************************** 03808 03809 > virtual void OpSliceTranslate::ConstrainDrag(DocCoord* PointerPos) 03810 03811 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03812 Created: 13/10/1999 03813 Inputs: PointerPos - The current position of the mouse that needs to be constrained 03814 Outputs: PointerPos - The position of the mouse after it has been constrained 03815 Purpose: Will constrain the mouse position to lie along rays from the centre of 03816 rotation at the constrain angle apart (45 degrees by default) 03817 03818 ********************************************************************************************/ 03819 03820 void OpSliceTranslate::ConstrainDrag(DocCoord* PointerPos) 03821 { 03822 // Lock the mouse to move along the axis or diagonally 03823 DocCoord Blobby = GetStartPos(); 03824 DocView::ConstrainToAngle(Blobby, PointerPos); 03825 } 03826 03827 03828 03829 /******************************************************************************************** 03830 03831 > BOOL OpSliceTranslate::Declare() 03832 03833 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>, from Rik's OpTranslateTrans code. 03834 Created: 13/10/1999 03835 Returns: TRUE if all went OK, False otherwise 03836 Purpose: Adds the operation to the list of all known operations 03837 03838 ********************************************************************************************/ 03839 03840 BOOL OpSliceTranslate::Declare() 03841 { 03842 return (RegisterOpDescriptor(0, _R(IDS_SLICE_MOVE), CC_RUNTIME_CLASS(OpSliceTranslate), 03843 OPTOKEN_SLICE_TRANSLATE, TransOperation::GetState)); 03844 } 03845 03846 03847 03848 /******************************************************************************************** 03849 03850 > void OpSliceTranslate::CompileCollisionBoxList() 03851 03852 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03853 Created: 12/10/1999 03854 Inputs: 03855 Outputs: Fills OpSliceTranslate::m_lBoxes with the required 03856 list of collision-test bounding boxes. 03857 Returns: 03858 Purpose: Make a list of the overall bounding rects of all named sets 03859 which have no members selected. These are used to collision 03860 detect against during the drag. 03861 Errors: 03862 See also: 03863 03864 ********************************************************************************************/ 03865 void OpSliceTranslate::CompileCollisionBoxList() 03866 { 03867 // iterate through the current list of named sets. if a named set 03868 // has no objects selected, then add its collective bounding rect 03869 // to the list of bounding rects, for collision detection. 03870 NameGallery * pNameGallery = NameGallery::Instance(); 03871 //pNameGallery->ForceUpdate(); 03872 SGUsedNames* pNames = pNameGallery ? pNameGallery->GetUsedNames() : NULL; 03873 SGNameItem* pItem = pNames ? (SGNameItem*) pNames->GetChild() : NULL; 03874 03875 m_lBoxes.DeleteAll(); 03876 while (pItem != NULL) 03877 { 03878 if (pItem->IsNoneSelected()) 03879 m_lBoxes.AddTail(new RectListItem(pItem->GetSetBounds())); 03880 03881 // get next name. 03882 pItem = (SGNameItem*)pItem->GetNext(); 03883 } 03884 } 03885 03886 03887 03888 /******************************************************************************************** 03889 03890 > BOOL OpSliceTranslate::TestBoundingBoxCollision(Rect* pTestRect) 03891 03892 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03893 Created: 12/10/1999 03894 Inputs: pTestRect the rectangle to test against each member of m_lBoxes. 03895 pSpread a pointer to the current spread, so that we can render 03896 the collided rectangle(s?) if necessary. 03897 Outputs: 03898 Returns: TRUE if a collision is detected, 03899 FALSE otherwise. 03900 Purpose: Test the given bounding rect against the list of bounding rects, 03901 m_lBoxes, and return TRUE if it overlaps any of them. 03902 03903 TODO: we may want to change this to a void function. 03904 03905 Additional: Karim MacDonald 07/02/2000 03906 This function now always returns FALSE, to prevent visual artifacts when 03907 dragging with the slice-tool, a result of the re-introduction of a dashed 03908 line around the selection during a drag. 03909 03910 Errors: ERROR2 if any parameter is NULL. 03911 See also: 03912 03913 ********************************************************************************************/ 03914 BOOL OpSliceTranslate::TestBoundingBoxCollision(DocRect* pTestRect, Spread* pSpread) 03915 { 03916 ERROR2IF(pTestRect == NULL || pSpread == NULL, FALSE, 03917 "OpSliceTranslate::TestBoundingBoxCollision- called with a NULL parameter"); 03918 03919 // iterate over the list, checking each rect against pTestRect. 03920 RectListItem* pListItem = (RectListItem*)m_lBoxes.GetHead(); 03921 BOOL bCollision = FALSE; 03922 while (!bCollision && pListItem != NULL) 03923 { 03924 bCollision = pTestRect->IsIntersectedWith(pListItem->GetRect()); 03925 03926 // get the next object in the list. 03927 if (!bCollision) 03928 pListItem = (RectListItem*)m_lBoxes.GetNext(pListItem); 03929 } 03930 03931 // return bCollision; 03932 return FALSE; 03933 } 03934 03935 03936 03937 /******************************************************************************************** 03938 03939 > void OpSliceTranslate::DragStarted( TransformData* TransData, 03940 DragTool* pTool, 03941 TransformBoundingData* pBounds, 03942 DocCoord ClickPos, 03943 Spread* pSpread, 03944 ClickModifiers ClickMods, 03945 DocCoord ClickOffset, 03946 Node* NodeToTransform, 03947 DragType dragtype ) 03948 03949 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03950 Created: 14/10/1999 03951 Inputs: see TransOperation::DragStarted 03952 Purpose: When we start a drag, we want to compile a list of bounding boxes which 03953 belong to non-selected named sets, eg if there is a group of objects called 03954 'Button One' and it is not selected, we want to add its overall bounding box 03955 to a list, so we can collision detect against it later. 03956 03957 Once that's done we call the base class, to start the drag. 03958 Errors: 03959 See also: 03960 03961 ********************************************************************************************/ 03962 void OpSliceTranslate::DragStarted( TransformData* TransData, 03963 DragTool* pTool, 03964 TransformBoundingData* pBounds, 03965 DocCoord ClickPos, 03966 Spread* pSpread, 03967 ClickModifiers ClickMods, 03968 DocCoord ClickOffset, 03969 Node* NodeToTransform, 03970 DragType dragtype ) 03971 { 03972 // compile a list of any names which are *not* used by the current selection, 03973 // and use this to compile a list of bounding boxes which we can collision-test 03974 // against during the drag, to announce if we cross any other named sets. 03975 CompileCollisionBoxList(); 03976 m_bDrawingBlobs = FALSE; 03977 03978 // call the base-class drag-start routine. 03979 TransOperation::DragStarted(TransData, pTool, pBounds, ClickPos, pSpread, ClickMods, 03980 ClickOffset, NodeToTransform, dragtype); 03981 } 03982 03983 03984 03985 /******************************************************************************************** 03986 03987 > void OpSliceTranslate::DragFinished(DocCoord dcPos, ClickModifiers ClickMods, 03988 Spread* pSpread, BOOL bSuccess, BOOL bSolidDrag) 03989 03990 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 03991 Created: 15/10/1999 03992 Inputs: dcPos 03993 ClickMods 03994 pSpread 03995 bSuccess 03996 Outputs: 03997 Returns: 03998 Purpose: Called when the selection-drag finishes, either normally or having been 03999 cancelled by the user. Performs tidy-up when the drag is over. 04000 04001 This function calls the base-class for its main functionality. 04002 Errors: 04003 See also: 04004 04005 ********************************************************************************************/ 04006 void OpSliceTranslate::DragFinished(DocCoord dcPos, ClickModifiers ClickMods, 04007 Spread* pSpread, BOOL bSuccess, BOOL bSolidDrag) 04008 { 04009 // have we finished drawing blobs, or do we need to erase them? 04010 if (m_bDrawingBlobs) 04011 { 04012 RenderDragBlobs(m_DragRect, StartSpread, bSolidDrag); // erase them. 04013 TransOperation::RenderDragBlobs(m_DragRect, StartSpread, bSolidDrag); 04014 } 04015 04016 m_lBoxes.DeleteAll(); 04017 TransOperation::DragFinished(dcPos, ClickMods, pSpread, bSuccess, bSolidDrag); 04018 } 04019 04020 04021 04022 /******************************************************************************************** 04023 04024 > void SliceInfoBarOp::UpdateCurrentStateGadget() 04025 04026 Author: Simon_Knight (Xara Group Ltd) <camelotdev@xara.com> 04027 Created: 18/2/00 04028 Returns: 04029 Purpose: Quickly scans the tree to find the layers shown then sets the drop down control 04030 which displays the current button state. 04031 Includes the #define code for including the "clicked" state or not. 04032 04033 ********************************************************************************************/ 04034 void SliceInfoBarOp::UpdateCurrentStateGadget() 04035 { 04036 INT32 state = FindCurrentState(); 04037 04038 /* // set the text in the redefine state button 04039 String_256 RedefineText = ""; 04040 String_256 Temp(_R(IDS_ROLLOVER_DEFAULT)); 04041 RedefineText += " \""; 04042 if (m_TopVisibleState == 1) 04043 Temp.Load(_R(IDS_ROLLOVER_MOUSE)); 04044 else if (m_TopVisibleState == 2) 04045 Temp.Load(_R(IDS_ROLLOVER_CLICKED)); 04046 else if (m_TopVisibleState == 3) 04047 Temp.Load(_R(IDS_ROLLOVER_SELECTED)); 04048 else if (m_TopVisibleState == 4) 04049 Temp.Load(_R(IDS_BACK_BAR)); 04050 04051 RedefineText.MakeMsg(_R(IDS_DESIGN_TEXT), (LPCSTR) Temp); 04052 SetStringGadgetValue(_R(IDC_REDEFINE_STATE), &RedefineText); 04053 */ 04054 EnableGadget(_R(IDC_REDEFINE_STATE), m_TopVisibleState != -1); 04055 04056 // set the text in the dropdown 04057 if (state >=0 && state <= 4 + INCLUDE_CLICKED_STATE) 04058 SetSelectedValueIndex(_R(IDC_ST_STATE), state); 04059 else 04060 SetStringGadgetValue(_R(IDC_ST_STATE), _R(IDS_MANY), FALSE, -1); 04061 }