gridtool.cpp

Go to the documentation of this file.
00001 // $Id: gridtool.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 grid tool
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 //#include "range.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "markn.h"
00107 //#include "simon.h"
00108 //#include "viewrc.h"
00109 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "cursor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "csrstack.h"
00114 #include "osrndrgn.h"
00115 //#include "resource.h"
00116 //#include "barsdlgs.h"
00117 #include "paper.h"
00118 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 //#include "undoop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 //#include "bars.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "chapter.h"
00123 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 #include "oilfiles.h"
00125 #include "camelot.h"
00126 #include "mainfrm.h"
00127 //#include "convert.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 //#include "units.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00129 //#include "msg.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00130 //#include "opdesc.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00131 #include "cutop.h"
00132 #include "progress.h"
00133 #include "bubbleid.h"
00134 
00135 #include "gridtool.h"
00136 
00137 //#include "will2.h"
00138 
00139 DECLARE_SOURCE( "$Revision: 1282 $" );
00140 
00141 CC_IMPLEMENT_DYNCREATE( OpGrid,          UndoableOperation )
00142 CC_IMPLEMENT_DYNCREATE( OpGridNewResize, OpGrid )
00143 CC_IMPLEMENT_DYNCREATE( OpGridSelection, OpGrid )
00144 CC_IMPLEMENT_DYNCREATE( OpGridChange,    OpGrid )
00145 CC_IMPLEMENT_DYNCREATE( OpGridDelete,    OpGrid )
00146 CC_IMPLEMENT_DYNCREATE( OpGridCut,       OpGrid )
00147 CC_IMPLEMENT_DYNCREATE( OpGridCopy,      OpGrid )
00148 CC_IMPLEMENT_DYNCREATE( OpGridPaste,     OpGrid )
00149 CC_IMPLEMENT_DYNCREATE( OpGridDuplicate, OpGrid )
00150 CC_IMPLEMENT_DYNCREATE( GridInfoBarOp,   InformationBarOp )
00151 
00152 static OpState NoClipboardOpGetState(String_256*, OpDescriptor*);
00153 
00154 #define new CAM_DEBUG_NEW     
00155 
00156 static struct
00157 {
00158     GridType    Type;
00159     UINT32      IDS;
00160 } GridTypeList[NUM_GRID_TYPES] = 
00161 {
00162     { RECTANGULAR,  _R(IDS_RECTANGULAR) },
00163     { ISOMETRIC,    _R(IDS_ISOMETRIC) }
00164 };
00165 
00166 // These are still char* while we wait for resource technology to be developed for modules
00167 char* GridTool::FamilyName  = "Grid Tools";
00168 char* GridTool::ToolName    = "Grid Tool";
00169 char* GridTool::Purpose     = "Grid manipulation";
00170 char* GridTool::Author      = "Mark Neves";
00171 
00172 Spread*         GridTool::SpreadClicked         = NULL;
00173 NodeGrid*       GridTool::LastGridClicked       = NULL;
00174 NodeGrid*       GridTool::GridClicked           = NULL;
00175 GridBlobType    GridTool::GridBlobClicked       = NoGridBlob;
00176 DocCoord        GridTool::PointClicked;
00177 //BOOL          GridTool::CurrentTool           = FALSE;
00178 UINT32          GridTool::LastStatusID          = 0;
00179 GridInfoBarOp*  GridTool::pGridInfoBarOp        = NULL;
00180 Document*       GridTool::pDocument             = NULL;
00181 
00182 BOOL            OpGridNewResize::StartADrag = TRUE;
00183 BOOL            OpGridNewResize::EndTheDrag = TRUE;
00184 
00185 static MILLIPOINT abs(MILLIPOINT n) { if (n<0) return (0-n); else return (n);}
00186 static MILLIPOINT sgn(MILLIPOINT n) { if (n<0) return (-1);  else return (1);}
00187 
00188 CC_IMPLEMENT_MEMDUMP( GridTool, Tool_v1 )
00189 
00190 /********************************************************************************************
00191 
00192 >   GridTool::GridTool()
00193 
00194     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00195     Created:    18/2/94
00196     Purpose:    Constructor - does nothing.
00197                 Other initialisation is done in GridTool::Init which is called by the Tool Manager
00198     SeeAlso:    GridTool::Init
00199 
00200 ********************************************************************************************/
00201 
00202 GridTool::GridTool()
00203 {
00204     pcCurrentCursor = NULL;
00205 }
00206 
00207 /********************************************************************************************
00208 
00209 >   GridTool::~GridTool()
00210 
00211     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00212     Created:    18/2/94
00213     Purpose:    Destructor (Virtual). Does nothing.
00214 
00215 ********************************************************************************************/
00216 
00217 GridTool::~GridTool()
00218 {
00219     // Dummy destructor
00220 
00221 //  if (IsUserName("MarkN")) TRACE( _T("~GridTool()\n"));
00222 
00223 }
00224 
00225 
00226 
00227 /********************************************************************************************
00228 
00229 >   BOOL GridTool::Init( INT32 Pass )
00230 
00231     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00232     Created:    18/2/94
00233     Returns:    FALSE if it does not want to be created, TRUE otherwise
00234     Purpose:    Used to check if the Tool was properly constructed
00235     SeeAlso:    GridTool::GridTool
00236 
00237 ********************************************************************************************/
00238 
00239 BOOL GridTool::Init()
00240 {
00241 //  if (IsUserName("MarkN")) TRACE( _T("\nGridTool::Init called\n"));
00242 //  if (IsUserName("MarkN")) TRACE( _T("Creating grid tool info bar\n"));
00243 
00244     // Declare ops and only succeed if all declarations succeed
00245     BOOL ok = ( OpGridNewResize::Declare() && 
00246                 OpGridSelection::Declare() && 
00247                 OpGridChange::Declare());
00248 
00249 
00250     // This section reads in the infobar definition and creates an instance of
00251     // GridInfoBarOp.  Also pGridInfoBarOp, the ptr to my infobar, as set up
00252     // after the infobar is successfully read and created.
00253     if (ok)
00254     {
00255         CCResTextFile       file;               // Resource File
00256         GridInfoBarOpCreate BarCreate;          // Object that creates GridInfoBarOp objects
00257 
00258                 ok = file.open(_R(IDM_GRID_BAR), _R(IDT_INFO_BAR_RES));     // Open resource
00259         if (ok) ok = DialogBarOp::ReadBarsFromFile(file,BarCreate); // Read and create info bar
00260         if (ok) file.close();                                       // Close resource
00261 
00262         ENSURE(ok,"Unable to load gridbar.ini from resource\n"); 
00263 
00264         if (ok)
00265         {
00266             // Info bar now exists.  Now get a pointer to it
00267             String_32 str = String_32(_R(IDS_GRIDTOOL_INFOBARNAME));
00268             DialogBarOp* pDialogBarOp = DialogBarOp::FindDialogBarOp(str);
00269 
00270                     ok = (pDialogBarOp != NULL);
00271             if (ok) ok = pDialogBarOp->IsKindOf(CC_RUNTIME_CLASS(GridInfoBarOp));
00272             if (ok) pGridInfoBarOp = (GridInfoBarOp*)pDialogBarOp;
00273 
00274             ENSURE(ok,"Couldn't find grid tool info bar");
00275         }
00276     }
00277 
00278     return (ok);
00279 }
00280 
00281 
00282 /********************************************************************************************
00283 
00284 >   void GridTool::Describe(void *InfoPtr)
00285 
00286     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00287     Created:    18/2/94
00288     Inputs:     InfoPtr -   A pointer to a tool info block. It is passed cast to void* as
00289                             the version of the tool is unknown at this point. Later versions 
00290                             of the Tool class may have more items in this block, that this 
00291                             tool will not use
00292     Outputs:    InfoPtr -   The structure pointed to by InfoPtr will have had all the info
00293                             that this version of the Tool knows about
00294     Purpose:    Allows the tool manager to extract information about the tool
00295 
00296 ********************************************************************************************/
00297 
00298 void GridTool::Describe(void *InfoPtr)
00299 {
00300     // Cast structure into the latest one we understand.
00301     ToolInfo_v1 *Info = (ToolInfo_v1 *) InfoPtr;
00302 
00303     Info -> InfoVersion = 1;
00304     
00305     Info -> InterfaceVersion = GetToolInterfaceVersion();  // You should always have this line.
00306         
00307     // These are all arbitrary at present.
00308     Info -> Version = 1;
00309     Info -> ID      = GetID();
00310     Info -> TextID  = _R(IDS_GRID_TOOL);
00311 
00312     Info -> Family  = FamilyName;
00313     Info -> Name    = ToolName;
00314     Info -> Purpose = Purpose;
00315     Info -> Author  = Author;
00316 
00317     Info -> InfoBarDialog = _R(IDD_GRIDTOOL);
00318     Info -> BubbleID = _R(IDBBL_GRID_TOOLBOX);
00319 }
00320 
00321 UINT32 GridTool::GetID()
00322 {
00323     return TOOLID_GRID;
00324 }
00325 
00326 
00327 // The Rectangle Tools EventHandlers
00328 
00329 
00330 
00331 /********************************************************************************************
00332 
00333 >   virtual void GridTool::SelectChange(BOOL isSelected)
00334 
00335     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00336     Created:    18/2/94
00337     Inputs:     isSelected  - TRUE  = tool has been selected
00338                             - FALSE = tool has been deselected
00339     Outputs:    -
00340     Returns:    -
00341     Purpose:    Creates/destroys/pushes/pops the rectangle tool's cursor.
00342     Errors:     Debug warning if creating the cursor fails.
00343     SeeAlso:    -
00344 
00345 ********************************************************************************************/
00346 
00347 void GridTool::SelectChange(BOOL isSelected)
00348 {
00349     if (isSelected)
00350     {
00351         // Make sure my idea of the current document is correct
00352         GridTool::SetDoc(Document::GetCurrent());
00353 
00354         if (!CreateCursors()) return;
00355 
00356         CurrentCursorID = CursorStack::GPush(pcNormalGridCursor, FALSE);        // Push cursor but don't display now
00357         pcCurrentCursor = pcNormalGridCursor;
00358 
00359         // Make all grids visible
00360         if (DocView::GetSelected() != NULL)
00361         {
00362             if (!DocView::GetSelected()->GetShowGridState())
00363                 NodeGrid::ForceRedrawAllGrids();    // Redraw all grids
00364             else
00365                 RenderAllGridBlobs();               // Just EOR their blobs on
00366         }
00367 
00368         GridTool::FindCurrentSpread();
00369         //CurrentTool = TRUE;
00370 
00371         // Create and display the tool's info bar
00372         pGridInfoBarOp->Create();
00373 
00374 
00375         OpDescriptor* pOpDesc;
00376 
00377         // Find the pre-registered OpDescs that we're interested in and
00378         // alias them with an alternative op and GetState
00379         pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_DELETE);
00380         if (pOpDesc != NULL) pOpDesc->AliasOperation(CC_RUNTIME_CLASS(OpGridDelete),OpGridDelete::GetState);
00381 
00382         pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_CUT);
00383         if (pOpDesc != NULL) pOpDesc->AliasOperation(CC_RUNTIME_CLASS(OpGridCut),NoClipboardOpGetState);
00384 
00385         pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_COPY);
00386         if (pOpDesc != NULL) pOpDesc->AliasOperation(CC_RUNTIME_CLASS(OpGridCopy),NoClipboardOpGetState);
00387 
00388         pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_PASTE);
00389         if (pOpDesc != NULL) pOpDesc->AliasOperation(CC_RUNTIME_CLASS(OpGridPaste),NoClipboardOpGetState);
00390 
00391         pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_DUPLICATE);
00392         if (pOpDesc != NULL) pOpDesc->AliasOperation(CC_RUNTIME_CLASS(OpGridDuplicate),OpGridDuplicate::GetState);
00393     }
00394     else
00395     {
00396         // Deselection - destroy the tool's cursors, if they exist.
00397         if (pcCurrentCursor != NULL)
00398         {
00399             CursorStack::GPop(CurrentCursorID);
00400             delete pcNormalGridCursor;
00401             delete pcOverGridCursor;
00402             delete pcOverBlobCursorUD;
00403             delete pcOverBlobCursorLR;
00404             delete pcOverBlobCursorTL;
00405             delete pcOverBlobCursorTR;
00406             pcCurrentCursor = NULL;
00407             CurrentCursorID = 0;
00408         }
00409         // EOR off all grid blobs before exiting
00410         if (DocView::GetSelected() != NULL)
00411         {
00412             if (!DocView::GetSelected()->GetShowGridState())
00413                 NodeGrid::ForceRedrawAllGrids();
00414             else
00415                 RenderAllGridBlobs();
00416         }
00417 
00418         // Remove the info bar from view by deleting the actual underlying window
00419         pGridInfoBarOp->Delete();
00420         //CurrentTool = FALSE;
00421         SpreadClicked = NULL;
00422     }
00423 }
00424 
00425 /********************************************************************************************
00426 
00427 >   static void GridTool::SetDoc(Document* pThisDoc)
00428 
00429     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00430     Created:    15/7/94
00431     Inputs:     pThisDoc = ptr to a document.  This should be the current doc.
00432     Outputs:    -
00433     Returns:    -
00434     Purpose:    Updates the grid tool's idea of what is the relevant doc.
00435                 If the doc is different to the last one we had, then make sure the default
00436                 units are correct for this doc, and init the controls in the info bar
00437                 to take into account the new doc.
00438                 
00439                 This function relies on being called properly when the current doc changes.
00440                 This is done via the grid tool infobar message handler
00441     SeeAlso:    -
00442 
00443 ********************************************************************************************/
00444 
00445 void GridTool::SetDoc(Document* pThisDoc)
00446 {
00447     if (GridTool::pDocument != pThisDoc)
00448     {
00449         GridTool::pDocument = pThisDoc;
00450         if (GridTool::pDocument != NULL)
00451             NodeGrid::SetDefaultUnits(GridTool::pDocument->GetDocUnitList()->GetPageUnits());
00452         else
00453             NodeGrid::SetDefaultUnits(NOTYPE);
00454 
00455         GridTool::FindCurrentSpread();
00456         pGridInfoBarOp->InitControls();
00457         pGridInfoBarOp->DisplayDefaultGridInfo();
00458     }
00459 }
00460 
00461 
00462 /********************************************************************************************
00463 
00464 >   BOOL GridTool::CreateCursors()
00465 
00466     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00467     Created:    12/5/94
00468     Inputs:     -
00469     Outputs:    -
00470     Returns:    TRUE if all the grid tool cursors have been successfully created
00471     Purpose:    Creates all the grid tool cursors
00472     SeeAlso:    -
00473 
00474 ********************************************************************************************/
00475 
00476 BOOL GridTool::CreateCursors()
00477 {
00478     // This tool has just been selected.  Create the cursors.
00479     pcNormalGridCursor  = new Cursor(this, _R(IDC_GRIDTOOLCURSOR));
00480     pcOverGridCursor    = new Cursor(this, _R(IDC_MOVEBEZIERCURSOR));
00481     pcOverBlobCursorUD  = new Cursor(_R(IDC_SIZENS));
00482     pcOverBlobCursorLR  = new Cursor(_R(IDC_SIZEWE));
00483     pcOverBlobCursorTL  = new Cursor(_R(IDC_SIZENWSE));
00484     pcOverBlobCursorTR  = new Cursor(_R(IDC_SIZENESW));
00485 
00486     if ( pcNormalGridCursor==NULL       ||  !pcNormalGridCursor->IsValid()  ||
00487          pcOverGridCursor==NULL         ||  !pcOverGridCursor->IsValid()    ||
00488          pcOverBlobCursorUD==NULL       ||  !pcOverBlobCursorUD->IsValid()  ||
00489          pcOverBlobCursorLR==NULL       ||  !pcOverBlobCursorLR->IsValid()  ||
00490          pcOverBlobCursorTL==NULL       ||  !pcOverBlobCursorTL->IsValid()  ||
00491          pcOverBlobCursorTR==NULL       ||  !pcOverBlobCursorTR->IsValid())
00492     {
00493         if (IsUserName("MarkN")) TRACE( _T("Couldn't create grid tool cursors!\n"));
00494 
00495         if (pcNormalGridCursor != NULL) delete pcNormalGridCursor;
00496         if (pcOverGridCursor   != NULL) delete pcOverGridCursor;
00497         if (pcOverBlobCursorUD != NULL) delete pcOverBlobCursorUD;
00498         if (pcOverBlobCursorLR != NULL) delete pcOverBlobCursorLR;
00499         if (pcOverBlobCursorTL != NULL) delete pcOverBlobCursorTL;
00500         if (pcOverBlobCursorTR != NULL) delete pcOverBlobCursorTR;
00501         return FALSE;
00502     }
00503     else
00504         return TRUE;
00505 }
00506 
00507 /********************************************************************************************
00508 
00509 >   static void GridTool::FindCurrentSpread()
00510 
00511     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00512     Created:    14/5/94
00513     Inputs:     -
00514     Outputs:    -
00515     Returns:    -
00516     Purpose:    Tries to find a spread that can be considered the current spread in
00517                 relation to the grid tool
00518     SeeAlso:    -
00519 
00520 ********************************************************************************************/
00521 
00522 void GridTool::FindCurrentSpread()
00523 {
00524     Spread* pSpreadWithSelGrids   = NULL;
00525     Spread* pSpreadWithSelObjects = NULL;
00526 
00527     if (GridTool::GetDoc() != NULL)     // if there's a current doc, rock and roll
00528     {
00529         // Now we need to scan all spreads throughout this doc view's doc.
00530 
00531         Chapter* pChapter = Node::FindFirstChapter(GridTool::GetDoc());
00532         while (pChapter != NULL && pSpreadWithSelGrids == NULL)
00533         {
00534             // For each chapter in the doc...
00535             Node* pNode = pChapter->FindFirstChild();
00536             while (pNode != NULL && pSpreadWithSelGrids == NULL)
00537             {
00538                 // If the child node of the chapter is a spread...
00539                 if (pNode->IsKindOf(CC_RUNTIME_CLASS(Spread)))
00540                 {
00541                     Spread* pSpread = (Spread*)pNode;
00542                     if (HasSpreadSelGrids(pSpread))
00543                         pSpreadWithSelGrids = pSpread;
00544                 }
00545                 pNode = pNode->FindNext();
00546             }
00547             pChapter = pChapter->FindNextChapter();
00548         }
00549 
00550         if (pSpreadWithSelGrids == NULL)
00551         {
00552             // Obtain the current selections
00553             Range Sel(*(GetApplication()->FindSelection()));
00554     
00555             // Find the first selected object.
00556             Node* FirstSelected = Sel.FindFirst();
00557 
00558             // If there isn't one, then there is no spread with sel objects
00559             // Otherwise get the selected object's parent spread
00560             if (FirstSelected != NULL)
00561                 pSpreadWithSelObjects = (Spread*)FirstSelected->FindParent(CC_RUNTIME_CLASS(Spread));
00562         }
00563     }
00564 
00565     if (pSpreadWithSelGrids != NULL)
00566         SpreadClicked = pSpreadWithSelGrids;
00567     else
00568         SpreadClicked = pSpreadWithSelObjects;
00569 }    
00570 
00571 
00572         
00573 /********************************************************************************************
00574 
00575 >   static BOOL GridTool::HasSpreadSelGrids(Spread* pSpread)
00576 
00577     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00578     Created:    14/5/94
00579     Inputs:     pSpread  = spread to look at
00580     Returns:    TRUE if spread contains at least one selected grid
00581     Purpose:    Tells you the 'selected grids' state of the given spread
00582     SeeAlso:    -
00583 
00584 ********************************************************************************************/
00585 
00586 BOOL GridTool::HasSpreadSelGrids(Spread* pSpread)
00587 {
00588     // scan the children of the spread for grids
00589     Node* pNode = pSpread->FindFirstChild();
00590     while (pNode != NULL)
00591     {
00592         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
00593         {
00594             // we now have a ptr to a grid, so render those blobs
00595             NodeGrid* pGrid = (NodeGrid*)pNode;
00596             if (!pGrid->IsDisabled() && pGrid->IsGridSelected())
00597                 return TRUE;
00598         }
00599         pNode = pNode->FindNext();
00600     }
00601     return FALSE;
00602 }
00603 
00604 /********************************************************************************************
00605 
00606 >   void GridTool::UpdateInfoBar()
00607 
00608     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00609     Created:    25/2/94
00610     Purpose:    Update the GridTool's controls on the info bar.
00611     SeeAlso:    GridTool::HandleInfoBarMessage
00612 
00613 ********************************************************************************************/
00614 
00615 //void GridTool::UpdateInfoBar()
00616 //{ 
00617 //  if (IsUserName("MarkN")) TRACE( _T("UpdateInfoBar\n"));
00618 //}
00619 
00620 
00621 
00622 /********************************************************************************************
00623 
00624 >   void GridTool::HandleInfoBarMessage(CDlgMessage DlgMsg, CGadgetID Gadget)
00625 
00626     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00627     Created:    25/2/94
00628     Inputs:     DlgMsg - the dialog message type.
00629                 Gadget - ID of the info bar gadget that caused the event.
00630     Purpose:    Handles UI events from the Zoom Tool's gadgets on the info bar.
00631     SeeAlso:    GridTool::UpdateInfoBar
00632 
00633 ********************************************************************************************/
00634 
00635 //void GridTool::HandleInfoBarMessage(CDlgMessage DlgMsg, CGadgetID Gadget)
00636 //{
00637 //  if (IsUserName("MarkN")) TRACE( _T("DlgMsg = %ld , Gadget = %ld\n"),DlgMsg,Gadget);
00638 
00639 /*  switch (Gadget)
00640     {
00641 
00642     }
00643 */
00644 //}
00645 
00646 /********************************************************************************************
00647 
00648 >   void GridTool::RenderAllGridBlobs()
00649 
00650     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00651     Created:    21/2/94
00652     Inputs:     -
00653     Returns:    -
00654     Purpose:    Shows the grid blobs of all the grids in the current view
00655     SeeAlso:    
00656 
00657 ********************************************************************************************/
00658 
00659 void GridTool::RenderAllGridBlobs()
00660 {
00661     DocView* pDocView = DocView::GetCurrent();          // Get ptr to current doc view
00662     if (pDocView == NULL) return;                       // If no current doc, return
00663     if (pDocView->GetDoc() == NULL) return;             // If no doc attached to current view, return
00664     Document* pDoc = pDocView->GetDoc();                // get ptr to the doc
00665     pDoc->SetCurrent();                                 // Make sure this doc becomes the current doc
00666 
00667 
00668     // Now we need to scan all spreads throughout the current doc view's doc.
00669 
00670     Chapter* pChapter = Node::FindFirstChapter(pDoc);
00671     while (pChapter != NULL)
00672     {
00673         // For each chapter in the doc...
00674         Node* pNode = pChapter->FindFirstChild();
00675         while (pNode != NULL)
00676         {
00677             // If the child node of the chapter is a spread...
00678             if (pNode->IsKindOf(CC_RUNTIME_CLASS(Spread)))
00679             {
00680                 Spread* pSpread = (Spread*)pNode;
00681 
00682                 DocRect BB = pSpread->GetPasteboardRect();
00683                 pSpread->DocCoordToSpreadCoord(&BB);
00684 
00685                 // BB is now the bounding rect of the spread
00686                 // Now render all grids within this spread
00687                 RenderGridBlobsInSpread(pDocView,pSpread,&BB);
00688             }
00689             pNode = pNode->FindNext();
00690         }
00691         pChapter = pChapter->FindNextChapter();
00692     }
00693 }    
00694         
00695 /********************************************************************************************
00696 
00697 >   void GridTool::RenderGridBlobsInSpread(DocView *pDocView,Spread* pSpread,DocRect* pDocRect)
00698 
00699     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00700     Created:    22/2/94
00701     Inputs:     pDocView = ptr to the doc view to render grid blobs in
00702                 pSpread  = spread containing grids to be rendered
00703                 pDocRect = bounding rect of spread defining which area of the spread view needs updating
00704     Returns:    -
00705     Purpose:    EORs the blobs of all the grids in the given spread viewed through the given doc view
00706     SeeAlso:    
00707 
00708 ********************************************************************************************/
00709 
00710 void GridTool::RenderGridBlobsInSpread(DocView* pDocView,Spread* pSpread,DocRect* pDocRect)
00711 {
00712 
00713     // Get a render region on the spread.  We need to render EORd stuff on top of the current view
00714     RenderRegion* pRender = pDocView->RenderOnTop(pDocRect,pSpread,UnclippedEOR);
00715 
00716     while (pRender != NULL)
00717     {
00718         // scan the children of the spread for grids
00719         Node* pNode = pSpread->FindFirstChild();
00720         while (pNode != NULL)
00721         {
00722             if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
00723             {
00724                 // we now have a ptr to a grid, so render those blobs
00725                 NodeGrid* pGrid = (NodeGrid*)pNode;
00726                 RenderGridBlobs(pRender,pGrid);
00727                 // if the grid is selected, show this by rendering the select blobs
00728                 if (pGrid->IsGridSelected() && !pGrid->IsDefault())
00729                     RenderGridSelectBlobs(pRender,pGrid);
00730             }
00731             pNode = pNode->FindNext();
00732         }
00733 
00734         // get the next render region
00735         pRender = pDocView->GetNextOnTop(pDocRect);
00736     }
00737 }
00738 
00739 /********************************************************************************************
00740 
00741 >   void GridTool::RenderGridBlobs(RenderRegion* pRender,NodeGrid* pGrid)
00742 
00743     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00744     Created:    22/2/94
00745     Inputs:     pRender = ptr to a render region
00746                 pGrid   = ptr to the grid node
00747     Returns:    -
00748     Purpose:    Renders the blobs (i.e. the bounding rect) of the given grid.
00749     SeeAlso:    
00750 
00751 ********************************************************************************************/
00752 
00753 void GridTool::RenderGridBlobs(RenderRegion* pRender,NodeGrid* pGrid)
00754 {
00755     if (!pGrid->IsDefault())
00756     {
00757         DocRect Rect = pGrid->GetBoundingRect();
00758 
00759         pRender->SetLineColour(COLOUR_GRID);
00760         pRender->SetFillColour(COLOUR_TRANS);
00761         pRender->DrawRect(&Rect);
00762     }
00763 }
00764 
00765 /********************************************************************************************
00766 
00767 >   void GridTool::RenderGridBlobs(NodeGrid* pGrid)
00768 
00769     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00770     Created:    22/2/94
00771     Inputs:     pGrid = ptr to a grid
00772     Returns:    -
00773     Purpose:    EORs the bounding rectangle blob of the given grid.
00774                 The routine works out what spread it belongs to and tries to render the blobs
00775                 in the current doc view.
00776     SeeAlso:    
00777 
00778 ********************************************************************************************/
00779 
00780 void GridTool::RenderGridBlobs(NodeGrid* pGrid)
00781 {
00782     DocView* pDocView;
00783     Spread* pSpread;
00784     DocRect Rect;
00785     
00786     // Get the current doc view, the parent spread of the grid, and the spread bounds
00787     if (!GetGridBlobRenderVars(pGrid,&pDocView,&pSpread,&Rect)) return;
00788 
00789 //  DocRect BB = pGrid->GetBoundingRect();   // get local copy of grid bounds
00790 
00791     // Start a 'render on top' loop so we can EOR our select blobs on
00792     RenderRegion* pRender = pDocView->RenderOnTop(&Rect,pSpread,UnclippedEOR);
00793 
00794     // Render grid EOR select blobs for each render region
00795     while (pRender != NULL)
00796     {
00797         RenderGridBlobs(pRender,pGrid);
00798         pRender = pDocView->GetNextOnTop(&Rect);
00799     }
00800 }
00801 
00802 /********************************************************************************************
00803 
00804 >   void GridTool::RenderGridSelectBlobs(RenderRegion* pRender,NodeGrid* pGrid)
00805 
00806     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00807     Created:    22/2/94
00808     Inputs:     pRender = ptr to a render region
00809                 pGrid   = ptr to a grid node
00810     Returns:    -
00811     Purpose:    Shows the selection blobs of the given grid in the given render region
00812     SeeAlso:    
00813 
00814 ********************************************************************************************/
00815 
00816 void GridTool::RenderGridSelectBlobs(RenderRegion* pRender,NodeGrid* pGrid)
00817 {
00818     if (!pGrid->IsDefault())
00819     {
00820         // Make sure the line and fill colours are correct
00821         pRender->SetLineColour(COLOUR_NONE);
00822         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
00823 
00824         for(INT32 i = BottomLeft;i < NumGridBlobTypes;i++)
00825             pRender->DrawBlob(pGrid->GetBlobCoord((GridBlobType)i),BT_UNSELECTED);
00826     }
00827 }
00828 
00829 /********************************************************************************************
00830 
00831 >   void GridTool::RenderGridSelectBlobs(NodeGrid* pGrid)
00832 
00833     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00834     Created:    22/2/94
00835     Inputs:     pGrid = ptr to a grid
00836     Returns:    -
00837     Purpose:    Shows the selection blobs of the given grid.
00838                 The routine works out what spread it belongs to and tries to render the blobs
00839                 in the current doc view.
00840     SeeAlso:    
00841 
00842 ********************************************************************************************/
00843 
00844 void GridTool::RenderGridSelectBlobs(NodeGrid* pGrid)
00845 {
00846     DocView* pDocView;
00847     Spread* pSpread;
00848     DocRect Rect;
00849     
00850     // Get the current doc view, the parent spread of the grid, and the spread bounds
00851     if (!GetGridBlobRenderVars(pGrid,&pDocView,&pSpread,&Rect)) return;
00852 
00853 //  DocRect BB = pGrid->GetBoundingRect();   // get local copy of grid bounds
00854 
00855     // Start a 'render on top' loop so we can EOR our select blobs on
00856     RenderRegion* pRender = pDocView->RenderOnTop(&Rect,pSpread,UnclippedEOR);
00857 
00858     // Render grid EOR select blobs for each render region
00859     while (pRender != NULL)
00860     {
00861         RenderGridSelectBlobs(pRender,pGrid);
00862         pRender = pDocView->GetNextOnTop(&Rect);
00863     }
00864 }
00865 
00866 /********************************************************************************************
00867 
00868 >   void GridTool::RenderAllGridBlobs(NodeGrid* pGrid)
00869 
00870     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00871     Created:    22/2/94
00872     Inputs:     pGrid = ptr to a grid
00873     Returns:    -
00874     Purpose:    Renders the full compliment of blobs for the given grid.
00875                 This means bounding rect AND select blobs are rendered.
00876                 The routine works out what spread it belongs to and tries to render the blobs
00877                 in the current doc view.
00878     SeeAlso:    
00879 
00880 ********************************************************************************************/
00881 
00882 void GridTool::RenderAllGridBlobs(NodeGrid* pGrid)
00883 {
00884     RenderGridBlobs(pGrid);
00885     RenderGridSelectBlobs(pGrid);
00886 }
00887 
00888 
00889 
00890 /********************************************************************************************
00891 
00892 >   BOOL GridTool::GetGridBlobRenderVars(NodeGrid* pGrid,DocView** ppDocView,Spread** ppSpread,DocRect* pDocRect)
00893 
00894     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00895     Created:    22/2/94
00896 
00897     Inputs:     pGrid       = ptr to grid in question
00898                 ppDocView   = ptr to ptr to a DocView
00899                 ppSpread    = ptr to ptr to a spread
00900                 pDocRect    = ptr to the spread's bounding box
00901 
00902     Outputs:    Puts a ptr to the current doc view into *ppDocView
00903                 Puts the ptr to the parent spread of the grid into *ppSpread
00904                 Puts bounding DocRect of spread into *pDocRect
00905 
00906     Returns:    TRUE  - The vars are good, so go and render
00907                 FALSE - Something was not found, so outputs are invalid
00908 
00909     Purpose:    Gets the vars required to render the blobs of a grid
00910     SeeAlso:    
00911 
00912 ********************************************************************************************/
00913 
00914 BOOL GridTool::GetGridBlobRenderVars(NodeGrid* pGrid,DocView** ppDocView,Spread** ppSpread,DocRect* pDocRect)
00915 {
00916     // Get current doc view.  If there isn't one, fail
00917     *ppDocView = DocView::GetCurrent();
00918     if (*ppDocView == NULL) return (FALSE);
00919     
00920     // Get parent spread. If there isn't one, fail
00921     *ppSpread = pGrid->FindParentSpread();
00922     if (*ppSpread == NULL) return (FALSE);
00923 
00924     // Get spread bounds and translate to spread coords
00925     *pDocRect = (*ppSpread)->GetPasteboardRect();
00926     (*ppSpread)->DocCoordToSpreadCoord(pDocRect);
00927     
00928     return (TRUE);
00929 }
00930 
00931 
00932 
00933 
00934 /********************************************************************************************
00935 
00936 >   void GridTool::RenderToolBlobs(Spread* pSpread,DocRect* pDocRect)
00937 
00938     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00939     Created:    22/2/94
00940     Inputs:     pSpread  = ptr to a spread
00941                 pDocRect = ptr to DocRect of spread to render in
00942     Returns:    -
00943     Purpose:    Handles the RenderToolBlobs method.
00944                 Renders the tool's blobs into the current doc view.
00945     SeeAlso:    
00946 
00947 ********************************************************************************************/
00948 
00949 void GridTool::RenderToolBlobs(Spread* pSpread,DocRect* pDocRect)
00950 {
00951 //  if (IsUserName("MarkN")) TRACE( _T("GridTool::RenderToolBlobs\n"));
00952 
00953     // Render into the selected doc view
00954     DocView* pDocView = DocView::GetSelected();
00955     if (pDocView != NULL)
00956         RenderGridBlobsInSpread(pDocView,pSpread,pDocRect);
00957 }
00958 
00959 /********************************************************************************************
00960 
00961 >   void GridTool::CurrentDocViewChange(Spread* pSpread,DocRect* pRect)
00962 
00963     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00964     Created:    12/5/94
00965     Inputs:     -
00966     Returns:    -
00967     Purpose:    To handle a CurrentDocViewChange event for the Grid Tool.
00968     SeeAlso:    -
00969 
00970 ********************************************************************************************/
00971 
00972 //void GridTool::CurrentDocViewChange()
00973 //{
00974 //  if (IsUserName("MarkN")) TRACE( _T("GridTool::CurrentDocViewChange\n"));
00975 //}
00976 
00977 /********************************************************************************************
00978 
00979 >   void GridTool::SelectedDocViewChange(Spread* pSpread,DocRect* pRect)
00980 
00981     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00982     Created:    12/5/94
00983     Inputs:     -
00984     Returns:    -
00985     Purpose:    To handle a SelectedDocViewChange event for the Grid Tool.
00986     SeeAlso:    -
00987 
00988 ********************************************************************************************/
00989 
00990 //void GridTool::SelectedDocViewChange()
00991 //{
00992 //  if (IsUserName("MarkN")) TRACE( _T("GridTool::SelectedDocViewChange\n"));
00993 //}
00994 
00995 /********************************************************************************************
00996 
00997 >   static void GridTool::ForceRedraw(Spread* pSpread,DocRect Rect)
00998 
00999     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01000     Created:    3/3/94
01001     Inputs:     pPSpread = ptr to a spread, dude!
01002                 Rect - The region that needs the blobs to be drawn
01003     Purpose:    Forces a blob-inclusive redraw on the rect given in Spread.
01004                 If the Rect is empty or invalid, no redraw is forced
01005                 The redraw happens in the current view (if there is one).
01006 
01007 ********************************************************************************************/
01008 
01009 void GridTool::ForceRedraw(Spread* pSpread,DocRect Rect)
01010 {
01011     // Is it a wank spread? Then stick it where the sun don't shine!
01012     if (pSpread == NULL) return;
01013 
01014     // No selected view? Then no dice!
01015     DocView* pDocView = DocView::GetSelected();
01016     if (pDocView == NULL) return;
01017 
01018     // Bad rect?
01019     if (Rect.IsEmpty() || !Rect.IsValid()) return;
01020 
01021     DocRect BlobSize;   // Will old the size of a scaled blob
01022 
01023     // Add the size of a blob to the top corner of the bounding rectangle
01024     OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), Rect.HighCorner(), 
01025                                 BT_SELECTEDLARGEST, &BlobSize);
01026     Rect.IncludePoint( BlobSize.HighCorner() );
01027 
01028     // add the size of a blob to the bottom corner of the bounding rectangle
01029     OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), Rect.LowCorner(), 
01030                                 BT_SELECTEDLARGEST, &BlobSize);
01031     Rect.IncludePoint( BlobSize.LowCorner() );
01032 
01033 
01034     // Uncomment the next two lines for total spread area redraw
01035     //Rect = pSpread->GetPasteboardRect();
01036     //pSpread->DocCoordToSpreadCoord(&Rect);
01037 
01038 
01039     // redraw it 
01040     pDocView->ForceRedraw(pSpread,Rect);
01041 }
01042 
01043 /********************************************************************************************
01044 
01045 >   static void GridTool::ForceRedraw(NodeGrid* pGrid)
01046 
01047     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01048     Created:    3/3/94
01049     Inputs:     pGrid = ptr to grid to force a redraw on
01050     Purpose:    Forces a blob-inclusive redraw on the the given grid.
01051                 If the Rect is empty or invalid, no redraw is forced
01052                 The redraw happens in the current view (if there is one).
01053 
01054 ********************************************************************************************/
01055 
01056 void GridTool::ForceRedraw(NodeGrid* pGrid)
01057 {
01058     ForceRedraw(pGrid->FindParentSpread(),pGrid->GetBlobBoundingRect());
01059 }
01060 
01061 
01062 /********************************************************************************************
01063 
01064 >   BOOL GridTool::WhichGridClicked(Spread* pSpread,const DocCoord& PointerPos,NodeGrid** ppGrid)
01065 
01066     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01067     Created:    22/2/94
01068     Inputs:     pSpread    = ptr to a spread
01069                 PointerPos = pointer pos in spread coords
01070     Outputs:    *ppGrid    - see 'Returns'
01071     Returns:    TRUE  - *ppGrid = ptr to the NodeGrid which contains the point
01072                 FALSE - *ppGrid = NULL
01073     Purpose:    Scans the grids in the spread to see which one was clicked in (if any)
01074                 Disabled grids are ignored.
01075     SeeAlso:    
01076 
01077 ********************************************************************************************/
01078 
01079 BOOL GridTool::WhichGridClicked(Spread* pSpread,const DocCoord& PointerPos,NodeGrid** ppGrid)
01080 {
01081     // Init reference vars
01082     *ppGrid = NULL;
01083 
01084     // Start from the last node in the spread, so top grid is checked before the one behind it, etc
01085     Node* pNode = pSpread->FindLastChild();
01086     while ((pNode != NULL) && (*ppGrid == NULL))
01087     {
01088         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
01089         {
01090             NodeGrid* pGrid = (NodeGrid*)pNode;
01091             
01092             if (!pGrid->IsDisabled())
01093             {
01094                 if (pGrid->GetBoundingRect().ContainsCoord(PointerPos))
01095                     *ppGrid = pGrid;
01096             }
01097         }
01098         // Scan back along the sibling list
01099         pNode = pNode->FindPrevious();
01100     }
01101     // Return whether a grid was found or not
01102     return (*ppGrid != NULL);
01103 }
01104 
01105 /********************************************************************************************
01106 
01107 >   BOOL GridTool::WhichGridBlobClicked(Spread* pSpread,const DocCoord& PointerPos,
01108                                         NodeGrid** ppGrid,GridBlobType* pGridBlob)
01109 
01110     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01111     Created:    23/2/94
01112     Inputs:     pSpread    = ptr to a spread
01113                 PointerPos = pointer pos in spread coords
01114     Outputs:    *ppGrid    - see 'Returns'
01115                 *pGridBlob - see 'Returns'
01116     Returns:    TRUE  - *ppGrid    = ptr to the NodeGrid which contains the point
01117                         *pGridBlob = the grid blob that was clicked
01118                 FALSE - *ppGrid    = NULL
01119                         *pGridBlob = NoGridBlob
01120     Purpose:    Scans the grids in the spread to see which grid select blob was clicked (if any)
01121     SeeAlso:    
01122 
01123 ********************************************************************************************/
01124 
01125 BOOL GridTool::WhichGridBlobClicked(Spread* pSpread,const DocCoord& PointerPos,
01126                                         NodeGrid** ppGrid,GridBlobType* pGridBlob)
01127 {
01128     // Init reference vars
01129     *ppGrid     = NULL;
01130     *pGridBlob = NoGridBlob;
01131 
01132     DocView *pDocView = DocView::GetCurrent();
01133     if (pDocView==NULL) return FALSE;
01134 
01135     // Start from the last node in the spread, so top grid is checked before the one behind it, etc
01136     Node* pNode = pSpread->FindLastChild();
01137     while ((pNode != NULL) && (*ppGrid == NULL))
01138     {
01139         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
01140         {
01141             NodeGrid* pGrid = (NodeGrid*)pNode;
01142             
01143             if (pGrid->IsGridSelected() && !pGrid->IsDisabled())
01144             {
01145                 DocRect CornerBlob;
01146                 DocCoord BlobCoord;
01147 
01148                 for (INT32 i=BottomLeft;(i<NumGridBlobTypes) && (*ppGrid == NULL);i++)
01149                 {
01150                     BlobCoord = pGrid->GetBlobCoord((GridBlobType)i);
01151                     OSRenderRegion::GetBlobRect(pDocView->GetViewScale(),BlobCoord,BT_SELECTEDLARGEST,&CornerBlob);
01152 
01153                     // Check for collision with the control points
01154                     if (CornerBlob.ContainsCoord(PointerPos))
01155                     {
01156                         *ppGrid = pGrid;
01157                         *pGridBlob = (GridBlobType)i;
01158                     }
01159                 }
01160             }
01161         }
01162         // Scan back along the sibling list
01163         pNode = pNode->FindPrevious();
01164     }
01165     // Return whether a grid was found or not
01166     return (*ppGrid != NULL);
01167 }
01168 
01169 /********************************************************************************************
01170 
01171 >   static void GridTool::ClearSelection(Spread* pSpread)
01172 
01173     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01174     Created:    22/2/94
01175     Inputs:     pSpread = ptr to a spread (can cope with pSpread == NULL)
01176     Returns:    -
01177     Purpose:    Scans the grids in the spread and clears the selection bit.
01178                 If the selection bit of a grid is set from TRUE to FALSE, the selection blobs
01179                 of that grid are also updated
01180     SeeAlso:    
01181 
01182 ********************************************************************************************/
01183 
01184 void GridTool::ClearSelection(Spread* pSpread)
01185 {
01186     // A NULL spread is a possibility
01187     if (pSpread == NULL) return;
01188 
01189     Node* pNode = pSpread->FindLastChild();
01190     while (pNode != NULL)
01191     {
01192         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
01193         {
01194             NodeGrid* pGrid = (NodeGrid*)pNode;
01195             
01196             if (pGrid->IsGridSelected())
01197             {
01198                 RenderGridSelectBlobs(pGrid);
01199                 pGrid->SetGridSelected(FALSE);
01200             }
01201         }
01202         pNode = pNode->FindPrevious();
01203     }
01204 }
01205 
01206 /********************************************************************************************
01207 
01208 >   void GridTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
01209                         Spread* pSpread )
01210 
01211     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01212     Created:    18/2/94
01213     Inputs:     PointerPos  -   The DocCoord of the point where the mouse button was clicked
01214                 Click       -   Describes the type of click that was detected. 
01215                 ClickMods   -   Indicates which buttons caused the click and which modifers were
01216                                 pressed at the same time
01217                 pSpread     -   The spread in which the click happened
01218     Returns:    -
01219     Purpose:    To handle a Mouse Click event for the Grid Tool.
01220                 It handles grid creation, selection and translation
01221     SeeAlso:    Tool::MouseClick; ClickType; ClickModifiers
01222 
01223 ********************************************************************************************/
01224 
01225 void GridTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
01226                         Spread* pSpread )
01227 {
01228     if (ClickMods.Menu) return;                         // Don't do anything if the user clicked the Menu button
01229 
01230     ENSURE(pSpread != NULL,"GridTool::OnClick pSpread == NULL!!!!!");
01231 
01232     // Make sure this click is one that we want
01233     if ( Click == CLICKTYPE_SINGLE || Click == CLICKTYPE_DOUBLE)
01234     {
01235         // If click appears on a different spread than the last click, clear
01236         // the selection from the previous spread
01237         if (SpreadClicked != pSpread)   ClearSelection(SpreadClicked);
01238 
01239         if (SpreadClicked == NULL && pSpread != NULL)
01240             pGridInfoBarOp->EnableGadget(_R(IDC_MAKEGRID),TRUE);
01241 
01242         // make a note of the click pos and spread
01243         PointClicked  = PointerPos;
01244         SpreadClicked = pSpread;
01245 
01246         // Get the grid and blob clicked on...
01247         // The following two functions work out which grid was clicked on, and if a grid
01248         // was clicked on, which blob (if any) was clicked
01249         // NOTE : The result of these function calls are stored in GridClicked & GridBlobClicked
01250 
01251         if (!WhichGridBlobClicked(SpreadClicked,PointClicked,&GridClicked,&GridBlobClicked))
01252             WhichGridClicked(SpreadClicked,PointClicked,&GridClicked);
01253 
01254 
01255         // The following decides how the click will be processed
01256 
01257         if (GridClicked != NULL)
01258         {
01259             // Display grid info in the info bar
01260             ENSURE(pGridInfoBarOp != NULL,"GridTool::OnClick - pGridInfoBarOp == NULL!");
01261             pGridInfoBarOp->DisplayGridInfo(GridClicked);
01262     
01263             if (!GridClicked->IsDefault())
01264             {
01265                 if (GridBlobClicked == NoGridBlob)
01266                 {
01267                     if (GridClicked->IsGridSelected() && !ClickMods.Adjust)
01268                     {
01269                         // A left click on a selected grid starts a drag on the selection
01270                     }
01271                     else
01272                     {
01273                         // if clicked with right mouse button, toggle grid's select state
01274                         if (ClickMods.Adjust)
01275                             GridClicked->SetGridSelected(!GridClicked->IsGridSelected());
01276                         else
01277                         {
01278                             // Otherwise clear selection, then set clicked grid to be selected
01279                             ClearSelection(SpreadClicked);
01280                             GridClicked->SetGridSelected(TRUE);
01281                         }
01282     
01283                         // Render the grid select blobs to reflect the change in its select state
01284                         RenderGridSelectBlobs(GridClicked);
01285                         NodeGrid::RecalcNumSelectedGrids(SpreadClicked);
01286                         DialogBarOp::SetSystemStateChanged();
01287                     }
01288                 }
01289             }
01290             else
01291             {
01292                 ClearSelection(SpreadClicked);
01293                 GridClicked->SetGridSelected(TRUE);
01294                 GridBlobClicked = NoGridBlob;
01295                 GridClicked     = NULL;
01296                 NodeGrid::RecalcNumSelectedGrids(SpreadClicked);
01297                 DialogBarOp::SetSystemStateChanged();
01298             }
01299         }
01300         else
01301         {
01302             // if no grid clicked on, clear the selection
01303             ClearSelection(SpreadClicked);
01304             NodeGrid::RecalcNumSelectedGrids(SpreadClicked);
01305             DialogBarOp::SetSystemStateChanged();
01306         }
01307 
01308         // Make sure pointer shape and status bar text are correct
01309         OnMouseMove(PointerPos, pSpread, ClickMods);
01310 
01311         // Make sure the controls are shaded correctly
01312         pGridInfoBarOp->EnableControls();
01313     }
01314 
01315     if ( Click == CLICKTYPE_DRAG )
01316     {
01317         if ((GridClicked != NULL) && (GridBlobClicked == NoGridBlob))
01318         {
01319             // Is it a drag on a selected grid using the left mouse button?
01320             if (GridClicked->IsGridSelected() && !ClickMods.Adjust)
01321             {
01322                 // Drag the selection around
01323                 OpGridSelection* pOpGridSelection = new OpGridSelection;
01324                 if (pOpGridSelection != NULL)
01325                 {
01326                     // Start the drag operation and pass in the Anchor Point to the push operation
01327                     pOpGridSelection->DoDrag(SpreadClicked,PointClicked,GridClicked);
01328                 }
01329             }
01330         }
01331         else
01332         {
01333             // Create/Resize a grid
01334             OpGridNewResize* pOpGridNewResize = new OpGridNewResize;
01335             if (pOpGridNewResize != NULL)
01336             {
01337                 if (GridBlobClicked == NoGridBlob)      // if no blob clicked, we're creating a new grid
01338                     ClearSelection(SpreadClicked);      // so clear selection
01339 
01340                 // Start the drag operation
01341                 OpGridNewResize::StartADrag = TRUE;
01342                 OpGridNewResize::EndTheDrag = TRUE;
01343                 pOpGridNewResize->DoDrag(SpreadClicked,GridClicked,GridBlobClicked,PointClicked);
01344             }
01345         }
01346     }
01347 }
01348 
01349 /********************************************************************************************
01350 
01351 >   void GridTool::OnMouseMove( DocCoord PointerPos,Spread* pSpread, ClickModifiers mods )
01352 
01353     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01354     Created:    
01355     Inputs:     PointerPos  -   The DocCoord of the point where the mouse has moved to
01356                 pSpread     -   The spread in which the move occurred
01357                 mods        -   which buttons/keys are down
01358     Returns:    TRUE if it handled the Click, FALSE otherwise
01359     Purpose:    To handle a Mouse Move event for the Grid Tool.
01360                 It changes the cursor dependant on were it is in relation to grids in the spread
01361                 The status bar is filled with a relevent piece of text
01362     SeeAlso:    Tool::MouseClick; ClickType; ClickModifiers
01363 
01364 ********************************************************************************************/
01365 
01366 void GridTool::OnMouseMove(DocCoord PointerPos,Spread* pSpread, ClickModifiers mods)
01367 {
01368 //  if (IsUserName("MarkN")) TRACE( _T("GridTool::OnMouseMove\n"));
01369 
01370     NodeGrid*       pGrid;
01371     GridBlobType    GridBlob;
01372     Cursor*         pCursor=NULL;
01373     UINT32          StatusID = _R(IDS_NOGRID);
01374 
01375     // Is pointer over a grid blob?
01376     if (WhichGridBlobClicked(pSpread,PointerPos,&pGrid,&GridBlob))
01377     {
01378         switch (GridBlob)
01379         {
01380             case BottomLeft     :   pCursor  = pcOverBlobCursorTR;
01381                                     StatusID = _R(IDS_BOTTOMLEFTHANDLE);
01382                                     break;
01383             case TopRight       :   pCursor  = pcOverBlobCursorTR;
01384                                     StatusID = _R(IDS_TOPRIGHTHANDLE);
01385                                     break;
01386             case TopLeft        :   pCursor  = pcOverBlobCursorTL;
01387                                     StatusID = _R(IDS_TOPLEFTHANDLE);
01388                                     break;
01389             case BottomRight    :   pCursor  = pcOverBlobCursorTL;
01390                                     StatusID = _R(IDS_BOTTOMRIGHTHANDLE);
01391                                     break;
01392             case LeftMiddle     :   pCursor  = pcOverBlobCursorLR;
01393                                     StatusID = _R(IDS_LEFTHANDLE);
01394                                     break;
01395             case RightMiddle    :   pCursor  = pcOverBlobCursorLR;
01396                                     StatusID = _R(IDS_RIGHTHANDLE);
01397                                     break;
01398             case TopMiddle      :   pCursor  = pcOverBlobCursorUD;
01399                                     StatusID = _R(IDS_TOPHANDLE);
01400                                     break;
01401             case BottomMiddle   :   pCursor  = pcOverBlobCursorUD;
01402                                     StatusID = _R(IDS_BOTTOMHANDLE);
01403                                     break;
01404         }
01405     }
01406     else
01407     {
01408         // If not, see if it is over a grid
01409         if (WhichGridClicked(pSpread,PointerPos,&pGrid))
01410         {
01411             if (pGrid->IsDefault())
01412             {
01413                 pCursor = pcNormalGridCursor;
01414                 if (pGrid->IsGridSelected())
01415                     StatusID = _R(IDS_SELDEFAULT);
01416                 else
01417                     StatusID = _R(IDS_UNSELDEFAULT);
01418             }
01419             else
01420             {
01421                 pCursor = pcOverGridCursor;
01422                 if (pGrid->IsGridSelected())
01423                     StatusID = _R(IDS_SELGRID);
01424                 else
01425                     StatusID = _R(IDS_UNSELGRID);
01426             }
01427         }
01428         else
01429         {
01430             pCursor = pcNormalGridCursor;
01431             StatusID = _R(IDS_NOGRID);
01432         }
01433     }
01434 
01435     if (pCursor != pcCurrentCursor)
01436     {
01437         // We're using the wrong shape!! 
01438         pcCurrentCursor = pCursor;
01439         CursorStack::GSetTop(pcCurrentCursor, CurrentCursorID);
01440     }
01441 
01442     GridTool::DisplayStatusBarHelp(StatusID);
01443 }
01444 
01445 /********************************************************************************************
01446 
01447 >   static void GridTool::ToggleDefaultGrid()
01448 
01449     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01450     Created:    12/5/94
01451     Inputs:     pSpread = spread in which to make the Default grid
01452     Outputs:    -
01453     Returns:    -
01454     Purpose:    Creates a grid covering the whole spread.  The grid is
01455                 defined using the default parameters.
01456     SeeAlso:    -
01457 
01458 ********************************************************************************************/
01459 
01460 void GridTool::ToggleDefaultGrid()
01461 {
01462     if (SpreadClicked == NULL) return;
01463 
01464     // scan the children of the current spread for grids
01465     Node* pNode = SpreadClicked->FindFirstChild();
01466     while (pNode != NULL)
01467     {
01468         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
01469         {
01470             // we now have a ptr to a grid, so render those blobs
01471             NodeGrid* pGrid = (NodeGrid*)pNode;
01472             if (pGrid->IsDefault())
01473             {
01474                 if (pGrid->IsDisabled())
01475                 {
01476                     pGrid->SetDisabled(FALSE);
01477                     ForceRedraw(pGrid);
01478                     ClearSelection(SpreadClicked);
01479                     pGrid->SetGridSelected(TRUE);
01480                 }
01481                 else
01482                 {
01483                     ForceRedraw(pGrid);
01484                     pGrid->SetDisabled(TRUE);
01485                 }
01486             }
01487         }
01488         pNode = pNode->FindNext();
01489     }
01490 }
01491 
01492 /********************************************************************************************
01493 
01494 >   static void GridTool::DisplayStatusBarHelp(UINT32 StatusID)
01495 
01496     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01497     Created:    16/5/94
01498     Inputs:     StatusID = ID of status help string
01499     Outputs:    -
01500     Returns:    -
01501     Purpose:    Displays the given status help string in the status bar
01502     SeeAlso:    -
01503 
01504 ********************************************************************************************/
01505 
01506 void GridTool::DisplayStatusBarHelp(UINT32 StatusID)
01507 {
01508 //  if (LastStatusID != StatusID)
01509 //  {
01510         String_256 StatusMsg("");
01511         StatusMsg.Load(StatusID);
01512         GetApplication()->UpdateStatusBarText(&StatusMsg);
01513         LastStatusID = StatusID;
01514 //  }
01515 }
01516 
01517 
01518 /********************************************************************************************
01519 
01520 >   static void GridTool::DisplayGridInfo(NodeGrid* pGrid)
01521 
01522     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01523     Created:    17/5/94
01524     Inputs:     pGrid = ptr to grid to display in
01525     Outputs:    -
01526     Returns:    -
01527     Purpose:    Displays the given grid's info in the infobar
01528     SeeAlso:    -
01529 
01530 ********************************************************************************************/
01531 
01532 void GridTool::DisplayGridInfo(NodeGrid* pGrid)
01533 {
01534     pGridInfoBarOp->DisplayGridInfo(pGrid);
01535 }
01536 
01537 
01538 /********************************************************************************************
01539 
01540 >   NodeGrid* OpGrid::DoDuplicateGrid(NodeGrid* pGrid)
01541 
01542     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01543     Created:    27/7/94
01544     Inputs:     pGrid,
01545                 AttDir,
01546                 pContextNode,
01547                 pSrcSpread,
01548                 pDestSpread,
01549                 FRedraw,
01550                 XDelta,
01551                 YDelta
01552     Outputs:    -
01553     Returns:    ptr the new grid which is a duplicate of the given grid
01554                 Returns NULL if unable to duplicate the node
01555     Purpose:    Duplicates the given grid and sticks it in a document node tree
01556                 Should be called from an operation's Do function as undo information is
01557                 generated.
01558     SeeAlso:    -
01559 
01560 ********************************************************************************************/
01561 
01562 NodeGrid* OpGrid::DoDuplicateGrid(  NodeGrid* pGrid,
01563                                         AttachNodeDirection AttDir,
01564                                         Node*   pContextNode,
01565                                         Spread* pSrcSpread,
01566                                         Spread* pDestSpread,
01567                                         BOOL    FRedraw,
01568                                         INT32   XDelta,
01569                                         INT32   YDelta)
01570 {
01571     BOOL        ok=FALSE;
01572     NodeGrid*   pNewGrid;
01573     DocRect     OldRect,NewRect;
01574 
01575     OldRect = pGrid->GetBoundingRect();
01576     NewRect = OldRect;
01577     NewRect.Translate(XDelta,YDelta);
01578 
01579     switch (pGrid->GetGridType())
01580     {
01581         case RECTANGULAR    : ALLOC_WITH_FAIL(pNewGrid,(new NodeGridRect()),this); break;
01582         case ISOMETRIC      : ALLOC_WITH_FAIL(pNewGrid,(new NodeGridIso()), this); break;
01583     }
01584 
01585     ok = (pNewGrid != NULL);
01586     if (ok) ok = DoInsertNewNode(pNewGrid,pContextNode,AttDir,TRUE);
01587     if (ok) ok = DoInvalidateNodeRegion(pNewGrid, TRUE);
01588     if (ok) ok = DoInvalidateNodeRegion(pGrid,    TRUE);
01589 
01590     if (ok)
01591     {
01592         pNewGrid->SetGridParams(pGrid->GetDivisions(),pGrid->GetSubdivisions(),pGrid->GetUnits());
01593         pNewGrid->SetGridSelected(pGrid->IsGridSelected());
01594         NodeGrid::RecalcNumSelectedGrids(pDestSpread);
01595 
01596         if (FRedraw)
01597         {
01598             GridTool::ForceRedraw(pSrcSpread, OldRect);
01599             GridTool::ForceRedraw(pDestSpread,NewRect);
01600         }
01601 
01602         if (!FRedraw) GridTool::RenderAllGridBlobs(pNewGrid);
01603         pNewGrid->SetBoundingRect(NewRect);
01604         if (!FRedraw) GridTool::RenderAllGridBlobs(pNewGrid);
01605     }
01606 
01607     if (!ok) 
01608         return (NULL); 
01609     else 
01610         return (pNewGrid);
01611 }
01612 
01617 
01619 //  The GridNewResize Operation
01620 //
01621 // This operation is responsible for creating and resizing grids.
01622 
01623 
01624 
01625 /********************************************************************************************
01626 
01627 >   OpGridNewResize::OpGridNewResize()
01628 
01629     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01630     Created:    18/2/94
01631     Purpose:    Constructor. 
01632 
01633 ********************************************************************************************/
01634 
01635 OpGridNewResize::OpGridNewResize()
01636 {
01637 }
01638 
01639 /********************************************************************************************
01640 
01641 >   OpGridNewResize::~OpGridNewResize()
01642 
01643     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01644     Created:    18/2/94
01645     Purpose:    Destructor.
01646 
01647 ********************************************************************************************/
01648 
01649 OpGridNewResize::~OpGridNewResize()
01650 {
01651 }
01652 
01653 
01654 /********************************************************************************************
01655 
01656 >   void OpGridNewResize::DoDrag(   Spread* pSpread,NodeGrid* pGrid,GridBlobType Blob,
01657                                     DocCoord PointClicked)
01658     
01659     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01660     Created:    23/2/94
01661     Inputs:     pSpread         - The spread that the drag was started on
01662                 pGrid           - The grid clicked on (or NULL if no grid clicked on)
01663                 Blob            - The select blob clicked on (or NoGridBlob if no blob clicked)
01664                 PointClicked    - starting position of the drag
01665     Purpose:    Starts dragging from the coordinate passed in.
01666                 This op either created a new grid on the page (if Blob == NoGridBlob) or resizes 
01667                 pGrid using the Blob provided.
01668 
01669 ********************************************************************************************/
01670 
01671 void OpGridNewResize::DoDrag(   Spread* pSpread,NodeGrid* pGrid,GridBlobType Blob,
01672                                 DocCoord PointClicked)
01673 {
01674     DocView::SnapCurrent(pSpread,&PointClicked);
01675 
01676     // We haven't shown a grid in the infobar yet, so set these to NULL
01677     PreOpDisplayedGrid  = NULL;
01678     PostOpDisplayedGrid = NULL;
01679 
01680     SpreadClicked   = pSpread;
01681     GridClicked     = pGrid;
01682     GridBlobClicked = Blob;
01683 
01684     if (GridBlobClicked == NoGridBlob)
01685         // Creating a new grid at this point, so drag and anchor points are the same
01686         DragPoint = AnchorPoint = PointClicked;
01687     else
01688     {
01689         // Here we are resizing the given grid using the given blob point
01690         ENSURE(GridClicked != NULL,"Oops! GridClicked == NULL && GridBlobClicked != NoGridBlob");
01691 
01692         // The following works out which points should be used as drag and anchor points
01693         // It assumes that the four corner points are defined in a specific way. If the GridBlobType
01694         // definition changes, then this code will have to change
01695         GridBlobType DragBlob   = (GridBlobType) ((INT32)GridBlobClicked % 4);
01696         GridBlobType AnchorBlob = (GridBlobType) (((INT32)DragBlob+2) % 4);
01697 
01698         // The anchor point is always the coord of the anchor blob
01699         AnchorPoint = GridClicked->GetBlobCoord(AnchorBlob);
01700 
01701         if (GridBlobClicked < LeftMiddle)
01702             // if we have clicked on a corner blob, the drag point is wherever the mouse is
01703             DragPoint = PointClicked;
01704         else
01705         {
01706             // Otherwise, the drag point has to be constrained either horizontally or vertically
01707             // depending on which mid point has been clicked
01708             DragPoint = GridClicked->GetBlobCoord(DragBlob);
01709 
01710             if (((INT32)GridBlobClicked % 2) == 0)
01711                 DragPoint.x = PointClicked.x;
01712             else
01713                 DragPoint.y = PointClicked.y;
01714         }
01715         RenderMyDragBlobs();
01716     }
01717 
01718     // And tell the Dragging system that we need drags to happen
01719     if (OpGridNewResize::StartADrag) StartDrag( DRAGTYPE_AUTOSCROLL );
01720 }
01721 
01722 
01723 
01724 
01725 /********************************************************************************************
01726 
01727 >   void OpGridNewResize::DragPointerMove( DocCoord PointerPos, ClickModifiers ClickMods, 
01728                                    Spread* pSpread, BOOL bSolidDrag)
01729     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01730     Created:    18/2/94
01731     Inputs:     PointerPos - The current position of the mouse in Doc Coords
01732                 ClickMods  - Which key modifiers are being pressed
01733                 pSpread    - The spread that the mouse pointer is over
01734     Purpose:    Takes the pointer position and calculates the new dragged outline of the EORd
01735                 bounding box
01736     SeeAlso:    ClickModifiers
01737 
01738 ********************************************************************************************/
01739 
01740 void OpGridNewResize::DragPointerMove( DocCoord PointerPos, ClickModifiers ClickMods, 
01741                                    Spread* pSpread, BOOL bSolidDrag)
01742 {
01743 //  if (IsUserName("MarkN")) TRACE( _T("\n\nOpGridNewResize::DragPointerMove()\n"));
01744 
01745     // First Rub out the old box
01746     RenderMyDragBlobs();
01747 
01748     // Update the box and draw in the new one
01749     if (pSpread != SpreadClicked)
01750         PointerPos = MakeRelativeToSpread(SpreadClicked, pSpread, PointerPos);
01751 
01752     DocView::SnapCurrent(pSpread,&PointerPos);
01753 
01754     if (GridBlobClicked < LeftMiddle)
01755     // If dragging a corner blob, the drag point is the same as the mouse position
01756         DragPoint = PointerPos;
01757     else
01758     {
01759         // Otherwise, constrain the drag point depending on which mid line blob was clicked
01760         if (((INT32)GridBlobClicked % 2) == 0)
01761             DragPoint.x = PointerPos.x;
01762         else
01763             DragPoint.y = PointerPos.y;
01764     }
01765 
01766     // Render the new drag box
01767     RenderMyDragBlobs();
01768 }
01769 
01770 
01771 
01772 /********************************************************************************************
01773 
01774 >   void OpGridNewResize::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 
01775                                 Spread* pSpread, BOOL Success, BOOL bSolidDrag)
01776 
01777     
01778     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01779     Created:    18/2/94
01780     Inputs:     PointerPos - The position of the mouse at the end of the drag
01781                 ClickMods - the key modifiers being pressed
01782                 pSpread - The spread that the drag finished on
01783                 Success - TRUE if the drag was terminated properly, FALSE if it
01784                 was ended with the escape key being pressed
01785     Purpose:    Ends the drag.
01786                 Either creates a new grid or resizes GridClicked depending on the state of affairs
01787                 when the drag started
01788     SeeAlso:    ClickModifiers
01789 
01790 ********************************************************************************************/
01791 
01792 void OpGridNewResize::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 
01793                                 Spread* pSpread, BOOL Success, BOOL bSolidDrag)
01794 {
01795     BOOL ok = Success;          // The OK flag. If this is TRUE, it is safe to continue the operation
01796 
01797     // Put the hour glass up as we have to
01798     BeginSlowJob();
01799 
01800     if (ok) DocView::SnapCurrent(pSpread,&PointerPos);  // Snap the point
01801 
01802     // Check for an artificially created drag.  If it is artificial, then DragPointerMove
01803     // has never been called so update DragPoint to be PointerPos.
01804     if (!OpGridNewResize::EndTheDrag) DragPoint = PointerPos;
01805 
01806     // First Rub out the old box
01807     RenderMyDragBlobs();
01808 
01809     // Get a ptr to a doc view
01810     DocView* pDocView = DocView::GetSelected();         // Get ptr to selected doc view
01811     if (ok) ok = (pDocView != NULL);                    // Check we've got a doc view
01812 
01813     UINT32 IDS = 0;
01814 
01815     // Has the user gone anywhere with the drag?
01816     if (ok) ok = (DragPoint != AnchorPoint);
01817 
01818     NodeGrid* pNewGrid = NULL;              // This will point to the new grid
01819     NodeGrid* pOldGrid = NULL;              // This will point to the grid being altered (if applicable)
01820 
01821     if (ok)
01822     {
01823 //      BOOL FRedraw = pDocView->GetShowGridState(); // FRedraw = TRUE if we need to cause redraws after change
01824         BOOL FRedraw = TRUE;
01825         
01826         DocRect ScaledBlob; // Will hold a scaled blob at coord (0,0)
01827         OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), DocCoord(0,0), BT_SELECTEDLARGEST, &ScaledBlob);
01828 
01829         // This lump of code makes sure that the minimum grid size created is not less than the width of a blob
01830         MILLIPOINT dx = AnchorPoint.x - DragPoint.x;
01831         MILLIPOINT dy = AnchorPoint.y - DragPoint.y;
01832         if (abs(dx) < ScaledBlob.Width())  DragPoint.x = AnchorPoint.x + (ScaledBlob.Width() *sgn(dx));
01833         if (abs(dy) < ScaledBlob.Height()) DragPoint.y = AnchorPoint.y + (ScaledBlob.Height()*sgn(dy));
01834 
01835 
01836         // Build the rectangle of the drag box at the end of the drag
01837         DocRect Rect(   min(AnchorPoint.x, DragPoint.x),min(AnchorPoint.y, DragPoint.y),
01838                         max(AnchorPoint.x, DragPoint.x),max(AnchorPoint.y, DragPoint.y) );
01839                                   
01840     
01841         DocRect OldRect = DocRect(0,0,0,0);     // Old rectangle coords used when resizing GridClicked
01842 
01843         GridType            CreateGridType;     // The type of grid we need to create
01844         Node*               ContextNode;        // Context of the new grid's placing
01845         AttachNodeDirection AttachDir;          // How the ContextNode is used to place new grid
01846 
01847         if (GridBlobClicked == NoGridBlob)      // No blob clicked, so we're creating a new grid
01848         {
01849             CreateGridType  = NodeGrid::GetDefaultGridType();
01850             ContextNode     = SpreadClicked;
01851             AttachDir       = LASTCHILD;
01852             OpType          = NEW;
01853         }
01854         else                                    // Blob clicked, so new grid is edited form of old grid
01855         {
01856             pOldGrid        = GridClicked;
01857             OldRect         = pOldGrid->GetBoundingRect();
01858             GridTool::RenderAllGridBlobs(pOldGrid);
01859 
01860             CreateGridType  = pOldGrid->GetGridType();
01861             ContextNode     = pOldGrid;
01862             AttachDir       = NEXT;
01863             OpType          = RESIZE;
01864         }
01865 
01866         switch (CreateGridType)                 // Create the new grid of the right type
01867         {
01868             case RECTANGULAR    : ALLOC_WITH_FAIL(pNewGrid,(new NodeGridRect()),this); break;
01869             case ISOMETRIC      : ALLOC_WITH_FAIL(pNewGrid,(new NodeGridIso()), this); break;
01870         }
01871 
01872         ok = (pNewGrid != NULL);
01873         if (ok)                         ok = DoInsertNewNode(pNewGrid,ContextNode,AttachDir,TRUE);
01874         if (ok)                         ok = DoInvalidateNodeRegion(pNewGrid,TRUE);
01875         if (ok && (pOldGrid != NULL))   ok = DoInvalidateNodeRegion(pOldGrid,TRUE);
01876         if (ok && (pOldGrid != NULL))   ok = DoHideNode(pOldGrid,TRUE);
01877 
01878         if (ok)
01879         {
01880             // Initialise the new grid based on whether we have an old grid or not
01881             if (pOldGrid == NULL)
01882             {   
01883                 pNewGrid->SetGridParams(NodeGrid::GetDefaultDivisions(),NodeGrid::GetDefaultSubdivisions(),NodeGrid::GetDefaultUnits());
01884 //              pNewGrid->SetInitialBounds(Rect);
01885                 pNewGrid->SetDefault(FALSE);
01886                 pNewGrid->SetDisabled(FALSE);
01887                 pNewGrid->SetGridSelected(TRUE);
01888             }
01889             else
01890             {
01891                 pNewGrid->SetGridParams(pOldGrid->GetDivisions(),pOldGrid->GetSubdivisions(),pOldGrid->GetUnits());
01892 //              pNewGrid->ChangeBounds(Rect);
01893                 pNewGrid->SetGridSelected(pOldGrid->IsGridSelected());
01894             }
01895 
01896             NodeGrid::RecalcNumSelectedGrids(SpreadClicked);
01897 
01898             // Tell the NodeGrid of the new bounds
01899             pNewGrid->SetBoundingRect(Rect);
01900 
01901             // Redraw the old and new positions of the grid. 
01902             // GridTool::ForceRedraw will do nothing if Rect is empty or invalid
01903 
01904             if (FRedraw)
01905             {
01906                 GridTool::ForceRedraw(SpreadClicked,Rect);
01907                 GridTool::ForceRedraw(SpreadClicked,OldRect);
01908             }
01909             else
01910                 GridTool::RenderAllGridBlobs(pNewGrid);
01911 
01912             // Show the new grid's info in the info bar
01913             GridInfoBarOp* pGridInfoBarOp = GridTool::GetGridInfoBarOp();
01914             if (pGridInfoBarOp != NULL)
01915             {
01916                 PreOpDisplayedGrid = pGridInfoBarOp->GetLastGridDisplayed();
01917                 pGridInfoBarOp->EnableControls();
01918                 GridTool::DisplayGridInfo(pNewGrid);
01919                 PostOpDisplayedGrid = pNewGrid;
01920             }
01921         }
01922     }
01923 
01924     if (!ok)
01925     {
01926         if (pNewGrid != NULL) delete pNewGrid;
01927         if (IDS > 0) InformError(IDS,_R(IDS_OK));
01928         FailAndExecute();
01929     }
01930 
01931     // If it's a real drag event, end the drag.
01932     if (OpGridNewResize::EndTheDrag)
01933         EndDrag();
01934 
01935     // End the op
01936     End();
01937 }
01938 
01939 
01940 
01941 /********************************************************************************************
01942 
01943 >   virtual void OpGridNewResize::RenderMyDragBlobs()
01944 
01945     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01946     Created:    18/2/94
01947     Inputs:     Rect    - The region that needs the blobs to be drawn
01948                 pSpread - The spread that the drawing will happen on
01949     Purpose:    Draws an EORed rectangle defined by AnchorPoint and DragPoint
01950 
01951 ********************************************************************************************/
01952 
01953 void OpGridNewResize::RenderMyDragBlobs()
01954 {
01955 //  if (IsUserName("MarkN")) TRACE( _T("OpGridNewResize::RenderMyDragBlobs()\n"));
01956 
01957     DocRect Rect = DocRect( min(AnchorPoint.x, DragPoint.x),min(AnchorPoint.y, DragPoint.y),
01958                             max(AnchorPoint.x, DragPoint.x),max(AnchorPoint.y, DragPoint.y) );
01959 
01960     RenderDragBlobs(Rect,SpreadClicked, FALSE);     
01961 }
01962 
01963 
01964 
01965 /********************************************************************************************
01966 
01967 >   void OpGridNewResize::RenderDragBlobs(DocRect Rect,Spread* pSpread, BOOL bSolidDrag)
01968 
01969     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01970     Created:    18/2/94
01971     Inputs:     Rect    - The region that needs the blobs to be drawn
01972                 pSpread - The spread that the drawing will happen on
01973     Purpose:    Draws an EORed rectangle defined by AnchorPoint and DragPoint
01974 
01975 ********************************************************************************************/
01976 
01977 void OpGridNewResize::RenderDragBlobs(DocRect Rect,Spread* pSpread, BOOL bSolidDrag)
01978 {
01979 //  if (IsUserName("MarkN")) TRACE( _T("OpGridNewResize::RenderDragBlobs()\n"));
01980 
01981     DocRect RubberBox = DocRect( min(AnchorPoint.x,DragPoint.x),min(AnchorPoint.y,DragPoint.y),
01982                                  max(AnchorPoint.x,DragPoint.x),max(AnchorPoint.y,DragPoint.y) );
01983         
01984     RenderRegion* pRegion = DocView::RenderOnTop( &Rect, pSpread, UnclippedEOR );
01985 
01986     while ( pRegion != NULL )
01987     {
01988         // Set the line colour and Draw the rect
01989         pRegion -> SetLineColour( COLOUR_XORDRAG );
01990 
01991         // Draw the rectangle
01992         pRegion -> DrawDragRect( &RubberBox );
01993 
01994         // Get the Next render region
01995         pRegion = DocView::GetNextOnTop( &Rect );
01996     }
01997 }
01998 
01999 
02000 
02001 /********************************************************************************************
02002 
02003 >   BOOL OpGridNewResize::Declare()
02004 
02005     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02006     Created:    18/2/94
02007     Returns:    TRUE if all went OK, FALSE otherwise
02008     Purpose:    Adds the operation to the list of all known operations
02009 
02010 ********************************************************************************************/
02011 
02012 BOOL OpGridNewResize::Declare()
02013 {
02014     return (RegisterOpDescriptor(
02015                                 0, 
02016                                 _R(IDS_GRID_TOOL),
02017                                 CC_RUNTIME_CLASS(OpGridNewResize), 
02018                                 OPTOKEN_GRIDNEWRESIZE,
02019                                 OpGridNewResize::GetState,
02020                                 0,          /* help ID */
02021                                 _R(IDBBL_NOOP), /* bubble ID */
02022                                 0           /* bitmap ID */
02023                                 ));
02024 }
02025 
02026 
02027 /********************************************************************************************
02028 
02029 >   static OpState OpGridNewResize::GetState(String_256* Description, OpDescriptor*)
02030 
02031     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02032     Created:    18/2/94
02033     Outputs:    Description - GetState fills this string with an approriate description
02034                 of the current state of the push tool
02035     Returns:    The state of the operation, so that menu items (ticks and greying can be
02036                 done properly
02037     Purpose:    Find out the state of the operation at the specific time
02038 
02039 ********************************************************************************************/
02040 
02041 OpState OpGridNewResize::GetState(String_256* Description, OpDescriptor*)
02042 {
02043     OpState Grid;
02044     
02045     return Grid;
02046 }
02047 
02048 /********************************************************************************************
02049 
02050 >   virtual void OpGridNewResize::GetOpName(String_256* OpName) 
02051 
02052     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02053     Created:    21/2/94
02054     Inputs:     -
02055     Outputs:    The undo string for the operation
02056     Returns:    
02057     Purpose:    The GetOpName fn is overridden so that we return back a description 
02058                 appropriate to the type of attribute that the operation applies. 
02059                     
02060     Errors:     -
02061     SeeAlso:    -
02062 
02063 ********************************************************************************************/
02064 
02065 void OpGridNewResize::GetOpName(String_256* OpName) 
02066 { 
02067     switch (OpType)
02068     {
02069         case NEW:       *OpName = String_256(_R(IDS_GRID_UNDO_NEW));    break;
02070         case RESIZE:    *OpName = String_256(_R(IDS_GRID_UNDO_RESIZE)); break;
02071     }
02072 }  
02073 
02074 
02076 //  The Grid selection Operation
02077 
02078 
02079 
02080 /********************************************************************************************
02081 
02082 >   OpGridSelection::OpGridSelection()
02083 
02084     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02085     Created:    24/2/94
02086     Purpose:    Constructor. 
02087 
02088 ********************************************************************************************/
02089 
02090 OpGridSelection::OpGridSelection()
02091 {
02092 }
02093 
02094 /********************************************************************************************
02095 
02096 >   OpGridSelection::~OpGridSelection()
02097 
02098     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02099     Created:    24/2/94
02100     Purpose:    Destructor.
02101 
02102 ********************************************************************************************/
02103 
02104 OpGridSelection::~OpGridSelection()
02105 {
02106 }
02107 
02108 
02109 /********************************************************************************************
02110 
02111 >   DocRect OpGridSelection::GetSelectedGridBounds(Spread* pSpread)
02112     
02113     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02114     Created:    22/8/94
02115     Inputs:     pSpread - The spread containing the grid you're interested in
02116     Outputs:    -
02117     Returns:    The DocRect which is the union of the bounds of each of the selected grids.
02118     Purpose:    Goes through all the selected grids in the given spread, returning the union.
02119                 Used to ensure the snapping of selected grids to grids works.
02120 
02121 ********************************************************************************************/
02122 
02123 DocRect OpGridSelection::GetSelectedGridBounds(Spread* pSpread)
02124 {
02125     DocRect rect;
02126 
02127     Node* pNode = pSpread->FindLastChild();
02128     Node* pPrevNode;
02129     while (pNode != NULL)
02130     {
02131         pPrevNode = pNode->FindPrevious();
02132 
02133         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
02134         {
02135             NodeGrid* pGrid = (NodeGrid*)pNode;
02136             
02137             if (pGrid->IsGridSelected() && !pGrid->IsDefault())
02138                 rect = rect.Union(pGrid->GetBoundingRect());
02139         }
02140         pNode = pPrevNode;
02141     }
02142 
02143     return (rect);
02144 }
02145 
02146 /********************************************************************************************
02147 
02148 >   void OpGridSelection::DoDrag(Spread* pSpread,DocCoord PointClicked)
02149     
02150     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02151     Created:    23/2/94
02152     Inputs:     pSpread         - The spread that the drag was started on
02153                 PointClicked    - starting position of the drag
02154     Purpose:    Starts dragging from the coordinate passed in.
02155 
02156 ********************************************************************************************/
02157 
02158 void OpGridSelection::DoDrag(Spread* pSpread,DocCoord PointClicked,NodeGrid* GridClicked)
02159 {
02160     // The last grid shown in the infobar before this op must be GridClicked
02161     PreOpDisplayedGrid  = GridClicked;
02162     // The dragged version of GridClicked is yet to be determined
02163     PostOpDisplayedGrid = NULL;
02164 
02165     SpreadClicked   = pSpread;
02166     SpreadDrag      = pSpread;
02167     StartPoint      = PointClicked;
02168     DragPoint       = PointClicked;
02169 
02170     NodeGrid::ResetDocRectSnap();
02171 
02172     StartRect = GetSelectedGridBounds(pSpread);
02173     DragRect  = StartRect;
02174     //DocView::SnapCurrent(pSpread,&DragRect,StartPoint,DragPoint);
02175 
02176     RenderMyDragBlobs();
02177 
02178     // And tell the Dragging system that we need drags to happen
02179     StartDrag( DRAGTYPE_AUTOSCROLL );
02180 }
02181 
02182 
02183 
02184 
02185 /********************************************************************************************
02186 
02187 >   void OpGridSelection::DragPointerMove( DocCoord PointerPos, ClickModifiers ClickMods, 
02188                                    Spread* pSpread, BOOL bSolidDrag)
02189     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02190     Created:    24/2/94
02191     Inputs:     PointerPos - The current position of the mouse in Doc Coords
02192                 ClickMods  - Which key modifiers are being pressed
02193                 pSpread    - The spread that the mouse pointer is over
02194     Purpose:    Takes the pointer position of the corner of the rectangle being dragged
02195                 and redisplays the outline rectangle
02196     SeeAlso:    ClickModifiers
02197 
02198 ********************************************************************************************/
02199 
02200 void OpGridSelection::DragPointerMove( DocCoord PointerPos, ClickModifiers ClickMods, 
02201                                    Spread* pSpread, BOOL bSolidDrag)
02202 {
02203         // First Rub out the old boxes
02204         RenderMyDragBlobs();
02205 
02206         DocCoord PrevDragPoint = DragPoint;
02207 
02208         DragPoint  = PointerPos;
02209         SpreadDrag = pSpread;
02210 
02211         DragRect = StartRect;
02212         DragRect.Translate(DragPoint.x - StartPoint.x , DragPoint.y - StartPoint.y);
02213         DocView::SnapCurrent(pSpread,&DragRect,PrevDragPoint,DragPoint);
02214 
02215         RenderMyDragBlobs();
02216 }
02217 
02218 
02219 
02220 /********************************************************************************************
02221 
02222 >   void OpGridSelection::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 
02223                                 Spread* pSpread, BOOL Success, BOOL bSolidDrag)
02224 
02225     
02226     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02227     Created:    24/2/94
02228     Inputs:     PointerPos - The position of the mouse at the end of the drag
02229                 ClickMods - the key modifiers being pressed
02230                 pSpread - The spread that the drag finished on
02231                 Success - TRUE if the drag was terminated properly, FALSE if it
02232                 was ended with the escape key being pressed
02233     Purpose:    Ends the drag and translates the selected grids. It also ends the
02234                 operation.
02235                 Assumes that DragPointerMove() has been called during the drag
02236     SeeAlso:    ClickModifiers
02237 
02238 ********************************************************************************************/
02239 
02240 void OpGridSelection::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods, 
02241                                 Spread* pSpread, BOOL Success, BOOL bSolidDrag)
02242 {
02243     BOOL ok = Success;          // The OK flag. If this is TRUE, it is safe to continue the operation
02244 
02245     // Put the hour glass up as we have to
02246     BeginSlowJob();
02247 
02248     INT32 XDelta = DragRect.lo.x - StartRect.lo.x;
02249     INT32 YDelta = DragRect.lo.y - StartRect.lo.y;
02250 
02251     BOOL FRedraw = FALSE;
02252     UINT32 SelCount = 0;
02253     UINT32 IDS = 0;
02254 
02255     DocView* pDocView = DocView::GetSelected();         // Get ptr to current doc view
02256     if (pDocView != NULL)
02257         FRedraw = pDocView->GetShowGridState();     
02258     
02259     FRedraw = TRUE;
02260 
02261     // First Rub out the old boxes
02262     RenderMyDragBlobs();
02263 
02264     Node* pNode = SpreadClicked->FindLastChild();
02265     Node* pPrevNode;
02266     while (pNode != NULL && ok)
02267     {
02268         pPrevNode = pNode->FindPrevious();
02269 
02270         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
02271         {
02272             NodeGrid* pOldGrid = (NodeGrid*)pNode;
02273             
02274             if (pOldGrid->IsGridSelected() && !pOldGrid->IsDefault())
02275             {
02276                 AttachNodeDirection AttDir;
02277                 Node*               pContextNode;
02278                 NodeGrid*           pNewGrid;
02279                 Spread*             pSrcSpread = SpreadClicked;
02280                 Spread*             pDestSpread;
02281                 DocRect             OldRect,NewRect;
02282 
02283                 SelCount++;
02284 
02285                 if (SpreadClicked == SpreadDrag)
02286                 {
02287                     pContextNode = pOldGrid;
02288                     AttDir       = NEXT;
02289                     pDestSpread  = SpreadClicked;
02290                 }
02291                 else
02292                 {
02293                     pContextNode = SpreadDrag;
02294                     AttDir       = LASTCHILD;
02295                     pDestSpread  = SpreadDrag;
02296                 }
02297 
02298                 pNewGrid = DoDuplicateGrid( pOldGrid,AttDir,pContextNode,
02299                                             pSrcSpread,pDestSpread,FRedraw,
02300                                             XDelta,YDelta);
02301                 ok = (pNewGrid != NULL);
02302                 if (ok) ok = DoHideNode(pOldGrid,TRUE);
02303                 
02304                 if (ok)
02305                 {
02306                     if (pOldGrid == PreOpDisplayedGrid)
02307                     {
02308                         GridTool::DisplayGridInfo(pNewGrid);
02309                         PostOpDisplayedGrid = pNewGrid;
02310                     }
02311                 }
02312             }
02313         }
02314         pNode = pPrevNode;
02315     }
02316 
02317     if (!ok)
02318     {
02319         if (IDS > 0) InformError( IDS, _R(IDS_OK) );
02320         FailAndExecute();
02321     }
02322 
02323     Plural = (SelCount > 1);
02324 
02325     // End the Drag                             
02326     EndDrag();
02327 
02328     // End the op
02329     End();
02330 }
02331 
02332 /********************************************************************************************
02333 
02334 >   virtual void OpGridSelection::RenderMyDragBlobs()
02335 
02336     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02337     Created:    24/2/94
02338     Inputs:     
02339     Purpose:    Draws an EORed rectangle for all selected grids in SpreadClicked
02340 
02341 ********************************************************************************************/
02342 
02343 void OpGridSelection::RenderMyDragBlobs()
02344 {
02345 /*
02346     DocRect SpreadRect = SpreadClicked->GetPasteboardRect();
02347     SpreadClicked->DocCoordToSpreadCoord(&SpreadRect);
02348 
02349     RenderDragBlobs(SpreadRect,SpreadClicked);
02350 */
02351     DocRect SpreadRect = SpreadDrag->GetPasteboardRect();
02352     SpreadDrag->DocCoordToSpreadCoord(&SpreadRect);
02353 
02354     RenderDragBlobs(SpreadRect,SpreadDrag, FALSE);
02355 }
02356 
02357 /********************************************************************************************
02358 
02359 >   virtual void OpGridSelection::RenderDragBlobs(DocRect Rect,Spread* pSpread, BOOL bSolidDrag)
02360 
02361     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02362     Created:    24/2/94
02363     Inputs:     Rect = Rect to render drag blobs in
02364                 pSpread = ptr to spread to render drag blobs in
02365     Purpose:    Draws an EORed rectangle for all selected grids using the given params
02366 
02367 ********************************************************************************************/
02368 
02369 void OpGridSelection::RenderDragBlobs(DocRect Rect,Spread* pSpread, BOOL bSolidDrag)
02370 {
02371     //MILLIPOINT    dx = DragPoint.x - StartPoint.x;
02372     //MILLIPOINT    dy = DragPoint.y - StartPoint.y;
02373     MILLIPOINT  dx = DragRect.lo.x - StartRect.lo.x;
02374     MILLIPOINT  dy = DragRect.lo.y - StartRect.lo.y;
02375     DocRect     GridRect;
02376 
02377     RenderRegion* pRegion = DocView::RenderOnTop( NULL/*&Rect*/, pSpread, UnclippedEOR );
02378 
02379     while ( pRegion != NULL )
02380     {
02381         // Set the line colour 
02382         pRegion -> SetLineColour( COLOUR_XORDRAG );
02383 
02384         Node* pNode = SpreadClicked->FindLastChild();
02385         while (pNode != NULL)
02386         {
02387             if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
02388             {
02389                 NodeGrid* pGrid = (NodeGrid*)pNode;
02390             
02391                 if (pGrid->IsGridSelected())
02392                 {
02393                     GridRect = pGrid->GetBoundingRect();
02394                     GridRect.Translate(dx,dy);
02395                     pRegion->DrawDragRect(&GridRect);
02396                 }
02397             }
02398             pNode = pNode->FindPrevious();
02399         }
02400 
02401         // Get the Next render region
02402         pRegion = DocView::GetNextOnTop( &Rect );
02403     }
02404 }
02405 
02406 
02407 
02408 /********************************************************************************************
02409 
02410 >   BOOL OpGridSelection::Declare()
02411 
02412     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02413     Created:    24/2/94
02414     Returns:    TRUE if all went OK, False otherwise
02415     Purpose:    Adds the operation to the list of all known operations
02416 
02417 ********************************************************************************************/
02418 
02419 BOOL OpGridSelection::Declare()
02420 {
02421     return (RegisterOpDescriptor(
02422                                 0, 
02423                                 _R(IDS_GRID_TOOL),
02424                                 CC_RUNTIME_CLASS(OpGridSelection), 
02425                                 OPTOKEN_GRIDSELECTION,
02426                                 OpGridSelection::GetState,
02427                                 0,          /* help ID */
02428                                 _R(IDBBL_NOOP), /* bubble ID */
02429                                 0           /* bitmap ID */
02430                                 ));
02431 }
02432 
02433 
02434 /********************************************************************************************
02435 
02436 >   static OpState OpGridSelection::GetState(String_256* Description, OpDescriptor*)
02437 
02438     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02439     Created:    24/2/94
02440     Outputs:    Description - GetState fills this string with an approriate description
02441                 of the current state of the push tool
02442     Returns:    The state of the operation, so that menu items (ticks and greying can be
02443                 done properly
02444     Purpose:    Find out the state of the operation at the specific time
02445 
02446 ********************************************************************************************/
02447 
02448 OpState OpGridSelection::GetState(String_256* Description, OpDescriptor*)
02449 {
02450     OpState Grid;
02451     
02452     return Grid;
02453 }
02454 
02455 /********************************************************************************************
02456 
02457 >   virtual void OpGridSelection::GetOpName(String_256* OpName) 
02458 
02459     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02460     Created:    16/3/94
02461     Inputs:     -
02462     Outputs:    The undo string for the operation
02463     Returns:    
02464     Purpose:    The GetOpName fn is overridden so that we return back a description 
02465                 appropriate to the type of attribute that the operation applies. 
02466                     
02467     Errors:     -
02468     SeeAlso:    -
02469 
02470 ********************************************************************************************/
02471 
02472 void OpGridSelection::GetOpName(String_256* OpName) 
02473 { 
02474     if (Plural)
02475         *OpName = String_256(_R(IDS_GRID_UNDO_SELECTS));
02476     else
02477         *OpName = String_256(_R(IDS_GRID_UNDO_SELECT));
02478 }  
02479 
02480 
02481 //-----------------------------------------
02482 
02483 /********************************************************************************************
02484 
02485 >   OpGridChange::OpGridChange()
02486 
02487     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02488     Created:    17/3/94
02489     Purpose:    Constructor. 
02490 
02491 ********************************************************************************************/
02492 
02493 OpGridChange::OpGridChange()
02494 {
02495 }
02496 
02497 /********************************************************************************************
02498 
02499 >   OpGridChange::~OpGridChange()
02500 
02501     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02502     Created:    17/3/94
02503     Purpose:    Destructor.
02504 
02505 ********************************************************************************************/
02506 
02507 OpGridChange::~OpGridChange()
02508 {
02509 }
02510 
02511 
02512 /********************************************************************************************
02513 
02514 >   BOOL OpGridChange::Declare()
02515 
02516     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02517     Created:    17/3/94
02518     Returns:    TRUE if all went OK, False otherwise
02519     Purpose:    Adds the operation to the list of all known operations
02520 
02521 ********************************************************************************************/
02522 
02523 BOOL OpGridChange::Declare()
02524 {
02525     return (RegisterOpDescriptor(
02526                                 0, 
02527                                 _R(IDS_GRID_TOOL),
02528                                 CC_RUNTIME_CLASS(OpGridChange), 
02529                                 OPTOKEN_GRIDCHANGE,
02530                                 OpGridChange::GetState,
02531                                 0,          /* help ID */
02532                                 _R(IDBBL_NOOP), /* bubble ID */
02533                                 0           /* bitmap ID */
02534                                 ));
02535 }
02536 
02537 
02538 /********************************************************************************************
02539 
02540 >   static OpState OpGridChange::GetState(String_256* Description, OpDescriptor*)
02541 
02542     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02543     Created:    17/3/94
02544     Outputs:    Description - GetState fills this string with an approriate description
02545                 of the current state of the push tool
02546     Returns:    The state of the operation, so that menu items (ticks and greying can be
02547                 done properly
02548     Purpose:    Find out the state of the operation at the specific time
02549 
02550 ********************************************************************************************/
02551 
02552 OpState OpGridChange::GetState(String_256* Description, OpDescriptor*)
02553 {
02554     OpState Grid;
02555     
02556     return Grid;
02557 }
02558 
02559 /********************************************************************************************
02560 
02561 >   void OpGridChange::GetOpName(String_256* OpName) 
02562 
02563     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02564     Created:    17/3/94
02565     Inputs:     -
02566     Outputs:    The undo string for the operation
02567     Returns:    
02568     Purpose:    The GetOpName fn is overridden so that we return back a description 
02569                 appropriate to the type of attribute that the operation applies. 
02570                     
02571     Errors:     -
02572     SeeAlso:    -
02573 
02574 ********************************************************************************************/
02575 
02576 void OpGridChange::GetOpName(String_256* OpName) 
02577 { 
02578     *OpName = String_256(ChangeGridUndoIDS);
02579 }  
02580 
02581 
02582 /********************************************************************************************
02583 
02584 >   void OpGridChange::ChangeSelectedGrids(ChangeGrid* pChangeGrid)
02585 
02586     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02587     Created:    17/3/94
02588     Inputs:     pChGrid = ptr to a ChangeGrid class for changing the selected grids in some way
02589     Returns:    -
02590     Purpose:    Changes all the selected grids using the given ChangeGrid object
02591     SeeAlso:    
02592 
02593 ********************************************************************************************/
02594 
02595 void OpGridChange::DoChangeSelectedGrids(ChangeGrid* pChangeGrid)
02596 {
02597     // We haven't shown a grid in the infobar yet, so set these to NULL
02598     PreOpDisplayedGrid  = NULL;
02599     PostOpDisplayedGrid = NULL;
02600 
02601     Spread* SpreadClicked = GridTool::GetSpreadClicked();
02602 
02603     GridInfoBarOp* pGridInfoBarOp = GridTool::GetGridInfoBarOp();
02604     if (pGridInfoBarOp != NULL)
02605         PreOpDisplayedGrid = pGridInfoBarOp->GetLastGridDisplayed();
02606 
02607     BOOL    ok = (SpreadClicked != NULL);
02608     if (ok) ok = (pChangeGrid   != NULL);
02609 
02610     if (ok)
02611     {
02612         // scan the children of the spread for grids
02613         Node* pNode = SpreadClicked->FindFirstChild();
02614         while (pNode != NULL && ok)
02615         {
02616             Node* pNodeCurrent = pNode;
02617             pNode = pNode->FindNext();
02618 
02619             if (pNodeCurrent->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
02620             {
02621                 // we now have a ptr to a grid, so render those blobs
02622                 NodeGrid* pGrid = (NodeGrid*)pNodeCurrent;
02623 
02624                 if (pGrid->IsGridSelected())
02625                 {
02626                     GridTool::ForceRedraw(pGrid);
02627                     ok = DoChangeGrid(pGrid,pChangeGrid);
02628                 }
02629             }
02630         }
02631     }
02632 
02633     if (!ok)
02634         FailAndExecute();
02635     else
02636     {
02637         ChangeGridUndoIDS = pChangeGrid->GetUndoIDS();
02638         if (PostOpDisplayedGrid != NULL)
02639             GridTool::DisplayGridInfo(PostOpDisplayedGrid);
02640     }
02641 
02642     delete pChangeGrid;
02643 
02644     End();
02645 }
02646 
02647 /********************************************************************************************
02648 
02649 >   BOOL OpGridChange::DoChangeGrid(NodeGrid* pOldGrid,ChangeGrid* pChangeGrid)
02650 
02651     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02652     Created:    17/3/94
02653     Inputs:     pOldGrid = ptr to a grid in the tree to change
02654                 pChangeGrid = ptr to a grid changing object
02655     Returns:    -
02656     Purpose:    Changes the given grid to reflect the default grid values of the grid tool.
02657     SeeAlso:    
02658 
02659 ********************************************************************************************/
02660  
02661 BOOL OpGridChange::DoChangeGrid(NodeGrid* pOldGrid,ChangeGrid* pChangeGrid)
02662 {
02663     DocRect DummyRect;
02664     NodeGrid* pNewGrid;
02665     BOOL ok = TRUE;
02666     
02667     switch (pChangeGrid->GetGridType(pOldGrid))
02668     {
02669         case RECTANGULAR    : ALLOC_WITH_FAIL(pNewGrid,(new NodeGridRect()),this); break;
02670         case ISOMETRIC      : ALLOC_WITH_FAIL(pNewGrid,(new NodeGridIso()), this); break;
02671     }
02672 
02673     ok = (pNewGrid != NULL);
02674     if (ok) ok = DoInsertNewNode(pNewGrid,pOldGrid,NEXT,TRUE);
02675     if (ok) ok = DoInvalidateNodeRegion(pOldGrid, TRUE);
02676     if (ok) ok = DoHideNode(pOldGrid,TRUE);
02677 
02678     if (ok)
02679     {
02680         pNewGrid->SetGridParams(pOldGrid->GetDivisions(),
02681                                 pOldGrid->GetSubdivisions(),
02682                                 pOldGrid->GetUnits());
02683 
02684         pChangeGrid->Change(pNewGrid);
02685         PostOpDisplayedGrid = pNewGrid;
02686 
02687         pNewGrid->SetBoundingRect(pOldGrid->GetBoundingRect());
02688         pNewGrid->SetGridSelected(pOldGrid->IsGridSelected());
02689         pNewGrid->SetDefault(pOldGrid->IsDefault());
02690     }
02691 
02692     return (ok);
02693 }
02694 
02695 //----------------------------------------
02696 //----------------------------------------
02697 //----------------------------------------
02698 
02699 /********************************************************************************************
02700 
02701 >   void ChangeGridUnits::Change(NodeGrid* pGrid)
02702 
02703     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02704     Created:    14/3/94
02705     Inputs:     pGrid = ptr to a grid in the tree
02706     Returns:    -
02707     Purpose:    Changes the given grid's units to the default setting.
02708     SeeAlso:    
02709 
02710 ********************************************************************************************/
02711 
02712 void ChangeGridUnits::Change(NodeGrid* pGrid)
02713 {
02714     pGrid->SetGridParams(   pGrid->GetDivisions(),
02715                             pGrid->GetSubdivisions(),
02716                             NodeGrid::GetDefaultUnits());
02717 }
02718 
02719 GridType ChangeGridUnits::GetGridType(NodeGrid* pGrid) { return pGrid->GetGridType(); }
02720 
02721 UINT32 ChangeGridUnits::GetUndoIDS() { return _R(IDS_GRID_UNDO_UNITS); }
02722 
02723 /********************************************************************************************
02724 
02725 >   void ChangeGridDivisions::Change(NodeGrid* pGrid)
02726 
02727     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02728     Created:    14/3/94
02729     Inputs:     pGrid = ptr to a grid in the tree
02730     Returns:    -
02731     Purpose:    Changes the given grid's divisions to the default setting.
02732     SeeAlso:    
02733 
02734 ********************************************************************************************/
02735 
02736 void ChangeGridDivisions::Change(NodeGrid* pGrid)
02737 {
02738     pGrid->SetGridParams(   NodeGrid::GetDefaultDivisions(),
02739                             pGrid->GetSubdivisions(),
02740                             pGrid->GetUnits());
02741 }
02742 
02743 GridType ChangeGridDivisions::GetGridType(NodeGrid* pGrid) { return pGrid->GetGridType(); }
02744 
02745 UINT32 ChangeGridDivisions::GetUndoIDS() { return _R(IDS_GRID_UNDO_DIVS); }
02746 
02747 /********************************************************************************************
02748 
02749 >   void ChangeGridSubdivisions::Change(NodeGrid* pGrid)
02750 
02751     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02752     Created:    14/3/94
02753     Inputs:     pGrid = ptr to a grid in the tree
02754     Returns:    -
02755     Purpose:    Changes the given grid's subdivisions to the default setting.
02756     SeeAlso:    
02757 
02758 ********************************************************************************************/
02759 
02760 void ChangeGridSubdivisions::Change(NodeGrid* pGrid)
02761 {
02762     pGrid->SetGridParams(   pGrid->GetDivisions(),
02763                             NodeGrid::GetDefaultSubdivisions(),
02764                             pGrid->GetUnits());
02765 }
02766 
02767 GridType ChangeGridSubdivisions::GetGridType(NodeGrid* pGrid) { return pGrid->GetGridType(); }
02768 
02769 UINT32 ChangeGridSubdivisions::GetUndoIDS() { return _R(IDS_GRID_UNDO_SUBDIVS); }
02770 
02771 /********************************************************************************************
02772 
02773 >   void ChangeGridType::Change(NodeGrid* pGrid)
02774 
02775     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02776     Created:    14/3/94
02777     Inputs:     pGrid = ptr to a grid in the tree
02778     Returns:    -
02779     Purpose:    This does nothing as changing the type of grid doesn't change the other params
02780     SeeAlso:    
02781 
02782 ********************************************************************************************/
02783 
02784 void ChangeGridType::Change(NodeGrid* pGrid)
02785 {
02786 }
02787 
02788 GridType ChangeGridType::GetGridType(NodeGrid* pGrid) { return NodeGrid::GetDefaultGridType(); }
02789 
02790 UINT32 ChangeGridType::GetUndoIDS() { return _R(IDS_GRID_UNDO_TYPE); }
02791 
02792 //-----------------------------------------
02793 
02794 
02795 
02796 
02797 //----------------------------------------------
02798 //----------------------------------------------
02799 //----------------------------------------------
02800 //----------------------------------------------
02801 
02802 /********************************************************************************************
02803 
02804 >   MsgResult GridInfoBarOp::Message(Msg* Message) 
02805 
02806     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>  / Converted to new Message handler by SimonM
02807     Created:    28/4/94
02808     Inputs:     Message: The message to handle
02809     Outputs:    -
02810     Returns:    -
02811     Purpose:    Grid info bar dialog message handler
02812     Errors:     -
02813     SeeAlso:    -
02814 
02815 ********************************************************************************************/
02816 
02817 MsgResult GridInfoBarOp::Message(Msg* Message) 
02818 {
02819 //  if (IsUserName("MarkN")) TRACE( _T("GridInfoBarOp::Message()\n"));
02820 
02821     if (IS_OUR_DIALOG_MSG(Message))
02822     {
02823         DialogMsg* Msg = (DialogMsg*)Message;
02824 
02825         // Check if the message is a CANCEL
02826         if (Msg->DlgMsg == DIM_CANCEL)
02827         {
02828             Close(); // Close the dialog 
02829         }
02830         else if (Msg->DlgMsg == DIM_CREATE)
02831         {
02832             // Initialise the controls 
02833             InitControls();
02834             DisplayDefaultGridInfo();
02835         }
02836         else
02837         {
02838             ChangeGrid* pChangeGrid = NULL;
02839 
02840             //if (IsUserName("MarkN")) TRACE( _T("Msg->GadgetID = %ld\n"),Msg->GadgetID);
02841 
02842             switch (Msg->GadgetID)
02843             {
02844                 case _R(IDC_UNITS):
02845                 {
02846                     switch (Msg->DlgMsg)
02847                     {
02848                         case DIM_SELECTION_CHANGED :
02849                         {
02850                             WORD Index;
02851                             GetValueIndex(_R(IDC_UNITS),&Index); 
02852                             DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
02853                             if ((Index >= 0) && (Index < pDocUnitList->GetNumUnits()))
02854                             {
02855                                 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
02856                                 Unit* pUnit = pDocUnitList->FindUnit(Index);
02857                                 NodeGrid::SetDefaultUnits(pUnit->GetUnitType());
02858                                 pChangeGrid = new ChangeGridUnits;
02859                             }
02860                         }
02861                         break;
02862                     }
02863                 }
02864                 break;
02865 
02866                 case _R(IDC_GRIDTYPE):
02867                 {
02868                     switch (Msg->DlgMsg)
02869                     {
02870                         case DIM_SELECTION_CHANGED:
02871                         {
02872                             WORD Index;  
02873                             GetValueIndex(_R(IDC_GRIDTYPE),&Index); 
02874                             if ((Index >= 0) && (Index <= NUM_GRID_TYPES))
02875                             {
02876                                 NodeGrid::SetDefaultGridType(GridTypeList[Index].Type);
02877                                 pChangeGrid = new ChangeGridType;
02878                             }
02879                         }
02880                         break;
02881                     }
02882                 }
02883                 break;
02884 
02885                 case _R(IDC_DIVISIONS):
02886                 {
02887                     //if (IsUserName("MarkN")) TRACE( _T("_R(IDC_DIVISIONS) - Msg->DlgMsg = %ld\n"),Msg->DlgMsg);
02888                     switch (Msg->DlgMsg)
02889                     {
02890                         case DIM_SELECTION_CHANGED:
02891                         {
02892                             WORD Index;  
02893                             GetValueIndex(_R(IDC_DIVISIONS),&Index); 
02894                             //if (IsUserName("MarkN")) TRACE( _T("Divisions Index = %ld\n"),Index);
02895 
02896                             BOOL Valid=TRUE;
02897                             double Div;
02898 
02899                             if (Index < 0)
02900                             {
02901                                 String_32 StrVal = GetStringGadgetValue(_R(IDC_DIVISIONS),&Valid); 
02902                                 camSscanf((TCHAR*)StrVal,"%NLf",&Div);
02903                             }
02904                             else
02905                                 Div = Index+1;
02906 
02907                             if (Valid)
02908                             {
02909                                 NodeGrid::SetDefaultDivisions(Div);
02910                                 pChangeGrid = new ChangeGridDivisions;
02911                             }
02912                         }
02913                         break;                                                 
02914                     }
02915                 }
02916                 break;
02917 
02918                 case _R(IDC_SUBDIVISIONS):
02919                 {
02920                     //if (IsUserName("MarkN")) TRACE( _T("_R(IDC_SUBDIVISIONS) - Msg->DlgMsg = %ld\n"),Msg->DlgMsg);
02921                     switch (Msg->DlgMsg)
02922                     {
02923                         case DIM_SELECTION_CHANGED:
02924                         {
02925                             WORD Index;  
02926                             GetValueIndex(_R(IDC_SUBDIVISIONS),&Index); 
02927                             //if (IsUserName("MarkN")) TRACE( _T("Divisions Index = %ld\n"),Index);
02928 
02929                             BOOL Valid=TRUE;
02930                             UINT32 Subdiv;
02931 
02932                             if (Index < 0)
02933                             {
02934                                 String_32 StrVal = GetStringGadgetValue(_R(IDC_SUBDIVISIONS),&Valid); 
02935                                 camSscanf((TCHAR*)StrVal,"%ld",&Subdiv);
02936                             }
02937                             else
02938                                 Subdiv = Index+1;
02939 
02940                             if (Valid)
02941                             {
02942                                 NodeGrid::SetDefaultSubdivisions(Subdiv);
02943                                 pChangeGrid = new ChangeGridSubdivisions;
02944                             }
02945                         }
02946                         break;                                                 
02947                     }
02948                 }
02949                 break;
02950 
02951                 case _R(IDC_MAKEGRID) :
02952                 {
02953                     //if (IsUserName("MarkN")) TRACE( _T("_R(IDC_MAKEGRID) - Msg->DlgMsg = %ld\n"),Msg->DlgMsg);
02954                     switch (Msg->DlgMsg)
02955                     {
02956                         case DIM_LFT_BN_CLICKED:
02957                         {
02958                             GridTool::ToggleDefaultGrid();
02959                             // Make sure the controls are shaded correctly
02960                             EnableControls();
02961                         }
02962                         break;                                                 
02963                     }
02964                 }
02965                 break;
02966             }
02967 
02968             if (pChangeGrid != NULL)
02969             {
02970                 OpGridChange* pOpGridChange = new OpGridChange;
02971                 if (pOpGridChange != NULL)
02972                     pOpGridChange->DoChangeSelectedGrids(pChangeGrid);
02973             }
02974         }
02975     }
02976     else if (MESSAGE_IS_A(Message,OpMsg))   // Check for undo/redo
02977     {
02978         OpMsg* pOpMsg = (OpMsg*)Message;
02979 
02980         if (pOpMsg->MsgType == OpMsg::AFTER_UNDO || pOpMsg->MsgType == OpMsg::AFTER_REDO)
02981         {
02982             if (pOpMsg->pOp != NULL)
02983             {
02984                 NodeGrid* pNodeGrid = NULL;
02985 
02986                 if (pOpMsg->pOp->IsKindOf(CC_RUNTIME_CLASS(OpGrid)))
02987                 {
02988                     NodeGrid::RecalcNumSelectedGrids(GridTool::GetSpreadClicked());
02989 
02990                     GridInfoBarOp* pGridInfoBarOp = GridTool::GetGridInfoBarOp();
02991                     if (pGridInfoBarOp != NULL)
02992                         pGridInfoBarOp->EnableControls();
02993 
02994                     OpGrid* pOpGrid = (OpGrid*)(pOpMsg->pOp);
02995 
02996                     if (pOpMsg->MsgType == OpMsg::AFTER_UNDO)
02997                         pNodeGrid = pOpGrid->GetPreOpDisplayedGrid();
02998                     
02999                     if (pOpMsg->MsgType == OpMsg::AFTER_REDO)
03000                         pNodeGrid = pOpGrid->GetPostOpDisplayedGrid();
03001 
03002                     if (pNodeGrid != NULL)
03003                         DisplayGridInfo(pNodeGrid);
03004                 }
03005             }
03006         }
03007     }
03008     else if (MESSAGE_IS_A(Message,UnitMsg))     // Check for changes in the units system
03009     {
03010         UnitMsg* pUnitMsg = (UnitMsg*)Message;
03011         BOOL UpdateInfoBar = FALSE;
03012         Unit* pThisUnit = NULL;
03013 
03014         switch (pUnitMsg->MsgType)
03015         {
03016             case UnitMsg::BEFOREDELETE:
03017             case UnitMsg::NEW:
03018             case UnitMsg::CHANGED:
03019                 pThisUnit = pUnitMsg->pDocUnitList->FindUnit(pUnitMsg->ThisUnitType);
03020                 break;
03021         }
03022                 
03023         switch (pUnitMsg->MsgType)
03024         {
03025             case UnitMsg::BEFOREDELETE:
03026                 if (NodeGrid::GetDefaultUnits() == pUnitMsg->ThisUnitType)
03027                     NodeGrid::SetDefaultUnits(pThisUnit->GetBaseUnitType());
03028                 break;
03029 
03030             case UnitMsg::NEW:
03031             case UnitMsg::CHANGED:
03032             case UnitMsg::AFTERDELETE:
03033                 UpdateInfoBar = TRUE;
03034                 break;
03035         }
03036 
03037         if (UpdateInfoBar)
03038         {
03039             InitControls();
03040             if (LastGridDisplayed == NULL)
03041                 DisplayDefaultGridInfo();
03042             else
03043                 DisplayGridInfo(LastGridDisplayed);
03044         }
03045 
03046         ProcessGridUnitMsg* pGridProc = new ProcessGridUnitMsg(pUnitMsg);
03047         if (pGridProc != NULL)
03048         {
03049             NodeGrid::ProcessAllGrids(pGridProc);
03050             delete pGridProc;
03051         }
03052     }
03053     else if (MESSAGE_IS_A(Message,DocChangingMsg))  // Check for changes in the units system
03054     {
03055 /*
03056         DocChangingMsg* pDocChangingMsg = (DocChangingMsg*)Message;
03057         Document* pDoc = pDocChangingMsg->pChangingDoc;
03058 
03059         switch (pDocChangingMsg->State)
03060         {
03061             case DocChangingMsg::DocState::SELECTED:
03062                 GridTool::SetDoc(pDoc);
03063                 break;
03064                 
03065             case DocChangingMsg::DocState::UNSELECTED:
03066             case DocChangingMsg::DocState::KILLED:
03067                 if (GridTool::GetDoc() == pDoc)
03068                     GridTool::SetDoc(NULL);
03069                 break; 
03070         }
03071 */
03072         DocChangingMsg* pDocChangingMsg = (DocChangingMsg*)Message;
03073 
03074         switch (pDocChangingMsg->State)
03075         {
03076             case DocChangingMsg::DocState::SELCHANGED:
03077                 GridTool::SetDoc(pDocChangingMsg->pNewDoc);
03078                 break; 
03079         }
03080     }
03081 
03082     // Pass the message on
03083     return (InformationBarOp::Message(Message));
03084 }    
03085 
03086 /********************************************************************************************
03087 
03088 >   void GridInfoBarOp::InitControls()
03089 
03090     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03091     Created:    28/4/94
03092     Inputs:     -
03093     Outputs:    -
03094     Returns:    -
03095     Purpose:    Inits all the controls in the info bar.
03096                 Called immediately after the bar is created when the grid tool
03097                 becomes the current tool.
03098     SeeAlso:    -
03099 
03100 ********************************************************************************************/
03101 
03102 void GridInfoBarOp::InitControls()
03103 {
03104     //if (!GridTool::IsCurrentTool()) return;
03105     if (Tool::GetCurrentID() != TOOLID_GRID) return;
03106     if (GridTool::GetDoc() == NULL) return;
03107 
03108     INT32 i;
03109 
03110     DeleteAllValues(_R(IDC_UNITS));
03111     DeleteAllValues(_R(IDC_GRIDTYPE));
03112 
03113     DocUnitList* pDocUnitList = GridTool::GetDoc()->GetDocUnitList();
03114 
03115     for (i=0; i < pDocUnitList->GetNumUnits(); i++)
03116     {
03117         Unit* pUnit   = pDocUnitList->FindUnit(i);
03118         String_32 Str = pUnit->GetToken();
03119         TCHAR* p = Str;
03120         String_256 Str256 = p;
03121         SetStringGadgetValue(_R(IDC_UNITS),&Str256,FALSE,i);
03122     }
03123 
03124     for (i=0; i<NUM_GRID_TYPES; i++)
03125     {
03126         String_32 Str = String_32(GridTypeList[i].IDS);
03127         SetStringGadgetValue(_R(IDC_GRIDTYPE),&Str,FALSE,i);  
03128     }
03129 
03130     INT32 l=1;
03131     for (i=0; i<10; i++,l++)
03132     {
03133         SetLongGadgetValue(_R(IDC_DIVISIONS),   l,FALSE,i);
03134         SetLongGadgetValue(_R(IDC_SUBDIVISIONS),l,FALSE,i);
03135     }
03136 
03137     EnableControls();
03138 }           
03139 
03140 /********************************************************************************************
03141 
03142 >   void GridInfoBarOp::EnableControls()
03143 
03144     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03145     Created:    17/5/94
03146     Inputs:     -
03147     Outputs:    -
03148     Returns:    -
03149     Purpose:    Enables or disables the controls depending on the current context, i.e.
03150                 the controls are disabled if there is no selection, etc.
03151     SeeAlso:    -
03152 
03153 ********************************************************************************************/
03154 
03155 void GridInfoBarOp::EnableControls()
03156 {
03157     //if (!GridTool::IsCurrentTool()) return;
03158     if (Tool::GetCurrentID() != TOOLID_GRID) return;
03159 
03160     Spread* pSpread = GridTool::GetSpreadClicked();
03161     BOOL    enable  = ((NodeGrid::GetNumSelectedGrids() > 0) && (pSpread != NULL));
03162 
03163     EnableGadget(_R(IDC_DIVISIONS),     enable);
03164     EnableGadget(_R(IDC_SUBDIVISIONS),  enable);
03165     EnableGadget(_R(IDC_UNITS),         enable);
03166     EnableGadget(_R(IDC_GRIDTYPE),      enable);
03167 
03168     EnableGadget(_R(IDC_MAKEGRID),pSpread != NULL); 
03169 }           
03170 
03171 /********************************************************************************************
03172 
03173 >   void GridInfoBarOp::DisplayDefaultGridInfo()
03174 
03175     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03176     Created:    1/3/94
03177     Purpose:    Set the controls on the info bar to reflect the default grid tool values.
03178                 Moved from GridTool to GridInfoBarOp on 28/4/94 by MarkN.
03179     SeeAlso:    
03180 
03181 ********************************************************************************************/
03182 
03183 void GridInfoBarOp::DisplayDefaultGridInfo()
03184 {
03185     DisplayGridInfo(    NodeGrid::GetDefaultDivisions(),
03186                         NodeGrid::GetDefaultUnits(),
03187                         NodeGrid::GetDefaultSubdivisions(),
03188                         NodeGrid::GetDefaultGridType());
03189 
03190     LastGridDisplayed = NULL;
03191 }
03192 
03193 
03194 /********************************************************************************************
03195 
03196 >   void GridInfoBarOp::DisplayGridInfo(NodeGrid* pGrid)
03197 
03198     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03199     Created:    1/3/94
03200     Inputs:     pGrid = ptr to grid who's info will be displayed in the infobar
03201     Purpose:    Set the GridTool's controls on the info bar.
03202                 Moved from GridTool to GridInfoBarOp on 28/4/94 by MarkN.
03203     SeeAlso:    
03204 
03205 ********************************************************************************************/
03206 
03207 void GridInfoBarOp::DisplayGridInfo(NodeGrid* pGrid)
03208 {
03209     //if (!GridTool::IsCurrentTool()) return;
03210     if (Tool::GetCurrentID() != TOOLID_GRID) return;
03211 
03212     DisplayGridInfo(    pGrid->GetDivisions(),
03213                         pGrid->GetUnits(),
03214                         pGrid->GetSubdivisions(),
03215                         pGrid->GetGridType());
03216 
03217     LastGridDisplayed = pGrid;
03218 
03219     //SetDimensionGadgetValue(_R(IDC_DIVISIONS),(MILLIPOINT)pGrid->GetMainStep(),pGrid);
03220 }
03221 
03222 
03223 /********************************************************************************************
03224 
03225 >   void GridInfoBarOp::DisplayGridInfo(double Divisions, UnitType Units, UINT32 Subdivisions, GridType GType)
03226 
03227     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03228     Created:    1/3/94
03229     Inputs:     Divisions       = Number of 'Units' between each main grid point
03230                 Units           = The units used to calc main grid point spacing
03231                 Subdivisions    = Number of sub-points between each main point
03232                 GType           = Type of grid (See GridType for a list of these)
03233     Purpose:    Set the GridTool's controls on the info bar.
03234                 Moved from GridTool to GridInfoBarOp on 28/4/94 by MarkN.
03235     SeeAlso:    
03236 
03237 ********************************************************************************************/
03238 
03239 void GridInfoBarOp::DisplayGridInfo(double Divisions, UnitType Units, UINT32 Subdivisions, GridType GType)
03240 {
03241     //if (!GridTool::IsCurrentTool()) return;
03242     if (Tool::GetCurrentID() != TOOLID_GRID) return;
03243 
03244     INT32 i;
03245 
03246     if (Units != NOTYPE)
03247     {
03248         DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
03249         SetSelectedValueIndex(_R(IDC_UNITS),pDocUnitList->FindUnitIndex(Units));
03250     }
03251 
03252 /*  if (pDocUnitList != NULL)
03253     {
03254         String_32 Str = pDocUnitList->GetToken(Units);
03255         TCHAR* p = Str;
03256         String_256 Str256 = p;
03257         SetStringGadgetValue(_R(IDC_UNITS),&Str256,FALSE,-1);
03258     }
03259 */
03260     for (i=0;i<NUM_GRID_TYPES;i++)
03261         if (GridTypeList[i].Type == GType)
03262             SetSelectedValueIndex(_R(IDC_GRIDTYPE),i);
03263 
03264     String_16 StringVal;
03265     TCHAR CharString[20];
03266 
03267     camSprintf(CharString, _T("%.2g"), (double) Divisions);
03268     StringVal = CharString;
03269     SetStringGadgetValue(_R(IDC_DIVISIONS), &StringVal, FALSE, -1);
03270 
03271     camSprintf(CharString, _T("%ld"), (INT32) Subdivisions);
03272     StringVal = CharString;
03273     SetStringGadgetValue(_R(IDC_SUBDIVISIONS), &StringVal, FALSE,-1);
03274 }
03275 
03276 //----------------------------------------------------
03277 //----------------------------------------------------
03278 //----------------------------------------------------
03279 //----------------------------------------------------
03280 //----------------------------------------------------
03281 
03282 // ------------------------------------------------------------------------------------------
03283 // OpGridDelete methods
03284             
03285 /********************************************************************************************
03286 
03287 >   static OpState  OpGridDelete::GetState(String_256*, OpDescriptor*)
03288 
03289     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03290     Created:    19/7/94
03291     Inputs:     -
03292     Outputs:    -
03293     Returns:    The state of the OpGridDelete
03294     Purpose:    For finding OpGridDelete's state. 
03295                 
03296     Errors:     -
03297     SeeAlso:    -
03298 
03299 ********************************************************************************************/
03300 
03301 OpState OpGridDelete::GetState(String_256* UIDescription, OpDescriptor*)
03302 {
03303     OpState OpSt;
03304     String_256 DisableReason; 
03305 
03306     // Ensure that a document exists
03307     if (GridTool::GetDoc() == NULL)
03308     {
03309         // There is no current document
03310         OpSt.Greyed = TRUE;
03311         // Load reason why operation is disabled
03312         DisableReason = String_256(_R(IDS_NO_DOC));
03313         *UIDescription = DisableReason;      
03314     }
03315     else
03316     {
03317         Spread* pSpread = GridTool::GetSpreadClicked();
03318         BOOL    enable  = ((NodeGrid::GetNumNonDefaultSelectedGrids() > 0) && (pSpread != NULL));
03319 
03320         if (!enable)
03321         {
03322             OpSt.Greyed = TRUE; 
03323             // Load reason why operation is disabled
03324             DisableReason = String_256(_R(IDS_NO_OBJECTS_SELECTED));
03325             *UIDescription = DisableReason;                                       
03326         }
03327     }
03328 
03329     return (OpSt);
03330 }
03331 
03332 /********************************************************************************************
03333 
03334 >   void OpGridDelete::Do(OpDescriptor*)
03335 
03336     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03337     Created:    19/7/94
03338     Inputs:     OpDescriptor (unused)
03339     Outputs:    -
03340     Returns:    -
03341     Purpose:    Performs the Delete operation. 
03342                 
03343     Errors:     -
03344     SeeAlso:    -
03345 
03346 ********************************************************************************************/
03347     
03348 void OpGridDelete::Do(OpDescriptor*)
03349 {   
03350     // We haven't shown a grid in the infobar yet, so set these to NULL
03351     PreOpDisplayedGrid  = NULL;
03352     PostOpDisplayedGrid = NULL;
03353 
03354     Spread* SpreadClicked = GridTool::GetSpreadClicked();
03355 
03356     GridInfoBarOp* pGridInfoBarOp = GridTool::GetGridInfoBarOp();
03357     if (pGridInfoBarOp != NULL)
03358         PreOpDisplayedGrid = pGridInfoBarOp->GetLastGridDisplayed();
03359 
03360     BOOL ok = (SpreadClicked != NULL);
03361     UINT32 SelCount=0;
03362 
03363     if (ok)
03364     {
03365         // scan the children of the spread for grids
03366         Node* pNode = SpreadClicked->FindFirstChild();
03367         while (pNode != NULL && ok)
03368         {
03369             Node* pNodeCurrent = pNode;
03370             pNode = pNode->FindNext();
03371 
03372             if (pNodeCurrent->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
03373             {
03374                 // we now have a ptr to a grid, so render those blobs
03375                 NodeGrid* pGrid = (NodeGrid*)pNodeCurrent;
03376 
03377                 if (pGrid->IsGridSelected() && !pGrid->IsDefault())
03378                 {
03379                     SelCount++;
03380                     GridTool::ForceRedraw(pGrid);
03381                             ok = DoInvalidateNodeRegion(pGrid, TRUE);
03382                     if (ok) ok = DoHideNode(pGrid,TRUE);
03383                 }
03384             }
03385         }
03386     }
03387 
03388     if (!ok)
03389         FailAndExecute();
03390     else
03391     {
03392         NodeGrid::RecalcNumSelectedGrids(SpreadClicked);
03393         pGridInfoBarOp->EnableControls();
03394     }
03395 
03396     Plural = (SelCount > 1);
03397 
03398     End();
03399 }           
03400 
03401 /********************************************************************************************
03402 
03403 >   void OpGridDelete::GetOpName(String_256* OpName) 
03404 
03405     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03406     Created:    19/7/94
03407     Inputs:     -
03408     Outputs:    The undo string for the operation
03409     Returns:    
03410     Purpose:    The GetOpName fn is overridden so that we return back a description 
03411                 appropriate to the type of attribute that the operation applies. 
03412                     
03413     Errors:     -
03414     SeeAlso:    -
03415 
03416 ********************************************************************************************/
03417 
03418 void OpGridDelete::GetOpName(String_256* OpName) 
03419 { 
03420     if (Plural)
03421         *OpName = String_256(_R(IDS_GRID_UNDO_DELETES));
03422     else
03423         *OpName = String_256(_R(IDS_GRID_UNDO_DELETE));
03424 }  
03425 
03426 // ------------------------------------------------------------------------------------------
03427 // OpGridDuplicate methods
03428             
03429 /********************************************************************************************
03430 
03431 >   static OpState  OpGridDuplicate::GetState(String_256*, OpDescriptor*)
03432 
03433     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03434     Created:    27/7/94
03435     Inputs:     -
03436     Outputs:    -
03437     Returns:    The state of the OpGridDuplicate
03438     Purpose:    For finding OpGridDuplicate's state. 
03439                 
03440     Errors:     -
03441     SeeAlso:    -
03442 
03443 ********************************************************************************************/
03444 
03445 OpState OpGridDuplicate::GetState(String_256* UIDescription, OpDescriptor*)
03446 {
03447     return (OpGridDelete::GetState(UIDescription,NULL));
03448 }
03449 
03450 /********************************************************************************************
03451 
03452 >   void OpGridDuplicate::Do(OpDescriptor*)
03453 
03454     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03455     Created:    27/7/94
03456     Inputs:     OpDescriptor (unused)
03457     Outputs:    -
03458     Returns:    -
03459     Purpose:    Performs the Delete operation. 
03460                 
03461     Errors:     -
03462     SeeAlso:    -
03463 
03464 ********************************************************************************************/
03465     
03466 void OpGridDuplicate::Do(OpDescriptor*)
03467 {   
03468     // We haven't shown a grid in the infobar yet, so set these to NULL
03469     PreOpDisplayedGrid  = NULL;
03470     PostOpDisplayedGrid = NULL;
03471 
03472     Spread* SpreadClicked = GridTool::GetSpreadClicked();
03473 
03474     GridInfoBarOp* pGridInfoBarOp = GridTool::GetGridInfoBarOp();
03475     if (pGridInfoBarOp != NULL)
03476         PreOpDisplayedGrid = pGridInfoBarOp->GetLastGridDisplayed();
03477 
03478     BOOL ok = (SpreadClicked != NULL);
03479     UINT32 SelCount=0;
03480 
03481     if (ok)
03482     {
03483         // scan the children of the spread for grids
03484         Node* pNode = SpreadClicked->FindFirstChild();
03485         while (pNode != NULL && ok)
03486         {
03487             Node* pNodeCurrent = pNode;
03488             pNode = pNode->FindNext();
03489 
03490             if (pNodeCurrent->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
03491             {
03492                 // we now have a ptr to a grid, so render those blobs
03493                 NodeGrid* pGrid = (NodeGrid*)pNodeCurrent;
03494 
03495                 if (pGrid->IsGridSelected() && !pGrid->IsDefault())
03496                 {
03497                     SelCount++;
03498 
03499                     NodeGrid* pNewGrid = DoDuplicateGrid(   pGrid,NEXT,pGrid,
03500                                                             SpreadClicked,SpreadClicked,TRUE,
03501                                                             28346,-28346);
03502 
03503                     ok = (pNewGrid != NULL);
03504 
03505                     if (ok)
03506                     {
03507                         pGrid->SetGridSelected(FALSE);
03508                         if (pGrid == PreOpDisplayedGrid)
03509                         {
03510                             GridTool::DisplayGridInfo(pNewGrid);
03511                             PostOpDisplayedGrid = pNewGrid;
03512                         }
03513                     }
03514                 }
03515             }
03516         }
03517     }
03518 
03519     if (!ok)
03520         FailAndExecute();
03521     else
03522     {
03523         NodeGrid::RecalcNumSelectedGrids(SpreadClicked);
03524         pGridInfoBarOp->EnableControls();
03525     }
03526 
03527     Plural = (SelCount > 1);
03528 
03529     End();
03530 }           
03531 
03532 /********************************************************************************************
03533 
03534 >   void OpGridDuplicate::GetOpName(String_256* OpName) 
03535 
03536     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03537     Created:    27/7/94
03538     Inputs:     -
03539     Outputs:    The undo string for the operation
03540     Returns:    
03541     Purpose:    The GetOpName fn is overridden so that we return back a description 
03542                 appropriate to the type of attribute that the operation applies. 
03543                     
03544     Errors:     -
03545     SeeAlso:    -
03546 
03547 ********************************************************************************************/
03548 
03549 void OpGridDuplicate::GetOpName(String_256* OpName) 
03550 { 
03551     if (Plural)
03552         *OpName = String_256(_R(IDS_GRID_UNDO_DUPS));
03553     else
03554         *OpName = String_256(_R(IDS_GRID_UNDO_DUP));
03555 }  
03556 
03557 //--------------------------------------
03558 //--------------------------------------
03559 //--------------------------------------
03560 
03561 /********************************************************************************************
03562 
03563 >   static OpState NoClipboardOpGetState(String_256*, OpDescriptor*)
03564 
03565     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03566     Created:    27/7/94
03567     Inputs:     -
03568     Outputs:    -
03569     Returns:    OpState.Greyed == TRUE, and a description of why is returned in the string
03570     Purpose:    General "There are no clipboard ops" get state function for aliased Cut, Copy
03571                 and Paste operations.               
03572     Errors:     -
03573     SeeAlso:    -
03574 
03575 ********************************************************************************************/
03576 
03577 static OpState NoClipboardOpGetState(String_256* UIDescription, OpDescriptor*)
03578 {
03579     OpState OpSt;
03580     String_256 DisableReason; 
03581 
03582     // You cant have a small car that's good on the open road - You can with a Nissan
03583     // You cant cut a grid to the clipboard - Not even Nissan can help you there mate!
03584     OpSt.Greyed = TRUE;
03585     // Load reason why operation is disabled
03586     DisableReason = String_256(_R(IDS_NO_GRID_CLIPBOARD_OPS));
03587     *UIDescription = DisableReason;      
03588 
03589     return (OpSt);
03590 }
03591 

Generated on Sat Nov 10 03:47:39 2007 for Camelot by  doxygen 1.4.4