grid.cpp

Go to the documentation of this file.
00001 // $Id: grid.cpp 1361 2006-06-25 16:43:38Z 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 // NodeGrid implementation, and associated classes
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 
00105 #include <math.h>
00106 
00107 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "osrndrgn.h"
00110 #include "paper.h"
00111 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "markn.h"
00113 //#include "convert.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #include "grid.h"
00116 //#include "units.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 #include "chapter.h"
00119 //#include "tool.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 
00121 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "cxftags.h"
00123 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 //#include "camfiltr.h" // BaseCamelot filter - in camtypes.h [AUTOMATICALLY REMOVED]
00125 #include "unitcomp.h"   // UnitListComponent
00126 
00127 const UINT32 MIN_PIX_RENDER_COUNT   = 10;   // Min distance between rendered grid points, in pixels
00128 const UINT32 PIX_CROSSHAIR_SIZE     = 2;    // Size of grid crosshair points, in pixels
00129 const INT32 GRID_REND_FACTOR            = 128;  // Fixed FP for rendering grid
00130 
00131 static double       mod(double n, double d) { double temp; return (modf(n/d,&temp)*d);}
00132 static double       sgn(double n)           { if (n<0) return (-1); else return (1); }
00133 
00134 static UnitType GetDominantUnit(UnitType ThisUnit);
00135 static double GetUnitMultiple(UnitType Units);
00136 
00137 #define Swap(a,b)       { (a)^=(b), (b)^=(a), (a)^=(b); }
00138 
00139 UINT32      NodeGrid::NumSelected           = 0;
00140 UINT32      NodeGrid::NumNonDefaultSelected = 0;
00141 INT32       NodeGrid::LastXDir              = 0;
00142 INT32       NodeGrid::LastYDir              = 0;
00143 
00144 UnitType    NodeGrid::DefaultUnits          = INCHES;
00145 double      NodeGrid::DefaultDivisions      = 1.0;
00146 UINT32      NodeGrid::DefaultSubdivisions   = 2;
00147 GridType    NodeGrid::DefaultGridType       = RECTANGULAR;
00148 GridType    NodeGrid::TypeForDefaultGrid    = RECTANGULAR;
00149 BOOL        NodeGrid::DefaultGridDisabled   = FALSE;
00150 
00151 //--------------------------------------------------------------------------------------------
00152 // NodeGrid methods         
00153 
00154 CC_IMPLEMENT_DYNAMIC(NodeGrid, NodeRenderablePaper)          
00155 
00156 // Declare smart memory handling in Debug builds
00157 #define new CAM_DEBUG_NEW
00158 
00159 /*********************************************************************************************
00160 
00161 >    NodeGrid::NodeGrid() 
00162 
00163      Author:    Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00164      Created:   8/2/94
00165      Inputs:    -
00166      Outputs:   
00167      Returns:   -
00168               
00169      Purpose: This constructor creates a NodeGrid linked to no other nodes, with all status
00170               flags false, and NULL bounding and pasteboard rectangles.            
00171             
00172      Errors:    
00173 
00174 **********************************************************************************************/
00175  
00176 
00177 NodeGrid::NodeGrid(): NodeRenderablePaper()
00178 {
00179     SetOrigin(0,0);   
00180     GridColour  = DocColour(COLOUR_GRID);
00181 
00182     GridFlags.Selected          = FALSE;
00183     GridFlags.RelativeOrigin    = FALSE;
00184     GridFlags.DefaultGrid       = FALSE;
00185     GridFlags.Disabled          = FALSE;
00186 
00187     GridBoundingRect = DocRect(0,0,0,0);
00188 }
00189 
00190 
00191 
00192 /***********************************************************************************************
00193 
00194 > Node* NodeGrid::SimpleCopy() // Private method  
00195 
00196     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00197     Created:    8/2/94
00198     
00199     Inputs:         - 
00200     Outputs:    
00201     Returns:    A copy of the node, or NULL if memory runs out
00202          
00203     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
00204                 The function is virtual, and must be defined for all derived classes.  
00205            
00206     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
00207                 error and the function returns NULL. 
00208  
00209         
00210     Scope:      protected       
00211 **********************************************************************************************/
00212 
00213 Node* NodeGrid::SimpleCopy()
00214 {
00215     NodeGrid* NodeCopy = new NodeGrid();   
00216     if (NodeCopy != NULL)
00217         CopyNodeContents(NodeCopy);   
00218     return (NodeCopy);
00219 }          
00220 
00221 /***********************************************************************************************
00222 >   void NodeGrid::CopyNodeContents(NodeGrid* NodeCopy)
00223 
00224     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00225     Created:    8/2/94
00226     
00227     Inputs:     - 
00228     Outputs:    A copy of this node
00229  
00230     Returns:    -
00231          
00232     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
00233               
00234     Errors:     An assertion failure will occur if NodeCopy is NULL
00235     
00236     Scope:      protected
00237                                      
00238 ***********************************************************************************************/
00239 
00240 
00241 void NodeGrid::CopyNodeContents(NodeGrid* NodeCopy)
00242 {
00243     ENSURE(NodeCopy != NULL,"Trying to copy a NodeGridRect's contents to a NULL node");  
00244     
00245     NodeRenderablePaper::CopyNodeContents(NodeCopy); 
00246 
00247     NodeCopy->XOrigin    = this->XOrigin;
00248     NodeCopy->YOrigin    = this->YOrigin;
00249     NodeCopy->GridColour = this->GridColour;
00250     NodeCopy->GridFlags  = this->GridFlags;
00251 
00252     for (INT32 i=0;i<NumGridBlobTypes;i++)
00253         NodeCopy->BlobCoords[i] = this->BlobCoords[i];
00254 }
00255 
00256 
00257 /***********************************************************************************************
00258 >   void NodeGrid::PolyCopyNodeContents(NodeGrid* pNodeCopy)
00259 
00260     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00261     Created:    18/12/2003
00262     Outputs:    -
00263     Purpose:    Polymorphically copies the contents of this node to another
00264     Errors:     An assertion failure will occur if NodeCopy is NULL
00265     Scope:      protected
00266                                      
00267 ***********************************************************************************************/
00268 
00269 void NodeGrid::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
00270 {
00271     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
00272     ENSURE(IS_A(pNodeCopy, NodeGrid), "PolyCopyNodeContents given wrong dest node type");
00273 
00274     if (IS_A(pNodeCopy, NodeGrid))
00275         CopyNodeContents((NodeGrid*)pNodeCopy);
00276 }
00277 
00278 
00279 
00280 /********************************************************************************************
00281 
00282 >   void* NodeGrid::GetDebugDetails(StringBase* Str) 
00283 
00284     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00285     Created:    8/2/94
00286     Inputs:     -
00287     Outputs:    Str: String giving debug info about the node
00288     Returns:    -
00289     Purpose:    For obtaining debug information about the Node
00290     Errors:     -
00291     SeeAlso:    -
00292 
00293 ********************************************************************************************/
00294 
00295      
00296 void NodeGrid::GetDebugDetails(StringBase* Str) 
00297 {          
00298     NodeRenderablePaper::GetDebugDetails(Str); 
00299 }
00300 
00301 /********************************************************************************************
00302 
00303 >   virtual String Describe(BOOL Plural, BOOL Verbose = TRUE)
00304 
00305     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00306     Created:    8/2/94
00307     Inputs:     Plural: Flag indicating if the string description should be plural or
00308                         singular. 
00309     Outputs:    -
00310     Retuns:     Description of the object 
00311     Purpose:    To return a description of the Node object in either the singular or the 
00312                 plural. This method is called by the DescribeRange method.
00313                 
00314                 The description will always begin with a lower case letter.   
00315                 
00316     Errors:     A resource exception will be thrown if a problem occurs when loading the 
00317                 string resource. 
00318     SeeAlso:    -
00319 
00320 ********************************************************************************************/
00321 /*
00322     Technical Notes:
00323     
00324     The String resource identifiers should be of the form: ID_<Class>_DescriptionS for the 
00325     singular description and ID_<Class>_DescriptionP for the plural. 
00326 */              
00327               
00328 String NodeGrid::Describe(BOOL /*Plural*/, BOOL /*Verbose*/) 
00329 {     
00330     ENSURE (FALSE,"The illegal function NodeGrid::Describe was called\n"); 
00331     
00332     return _T(""); // Just to keep the compiler happy
00333 }; 
00334 
00335 /***********************************************************************************************
00336 
00337 >   virtual void NodeGrid::Render(void)
00338 
00339     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00340     Created:    8/2/94
00341     Inputs:     RendRegion: Render region to render into
00342     Outputs:    -
00343     Returns:    -   
00344     Purpose:    For rendering a node
00345         
00346 ***********************************************************************************************/
00347 
00348 void NodeGrid::Render( RenderRegion* /*pRender*/ )
00349 {
00350 }
00351 
00352 /********************************************************************************************
00353 
00354 >   BOOL NodeGrid::NeedsToRender(RenderRegion *pRender)
00355 
00356     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00357     Created:    25/5/94
00358     Inputs:     pRender - A pointer to the current render region (null if none)
00359     Returns:    TRUE  => This node should be rendered,
00360                 FALSE => This node does not need to be rendered.
00361     Purpose:    This function will indicate to the caller whether or not
00362                 we want to render the given node, according to the information passed in.
00363     SeeAlso:    NodeRenderableBounded::NeedsToRender
00364 
00365 ********************************************************************************************/
00366 
00367 SubtreeRenderState NodeGrid::RenderSubtree(RenderRegion *pRender, Node** ppNextNode, BOOL bClip)
00368 {
00369     // If no cliprect supplied, assume we do need to render
00370     if (pRender==NULL || !bClip)
00371         return SUBTREE_ROOTANDCHILDREN;
00372 
00373     DocRect ClipRect = pRender->GetClipRect();
00374 
00375     return ClipRect.IsIntersectedWith(GridBoundingRect) ? SUBTREE_ROOTANDCHILDREN : SUBTREE_NORENDER;
00376 }
00377 
00378 /***********************************************************************************************
00379 
00380 > void NodeGrid::CalcGridRenderSteps(MILLIPOINT PixelWidth,double* pStep,double DomStep,UnitType Units)
00381     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00382     Created:    10/2/94
00383     Inputs:     PixelWidth  = width of a pixel in millipoints
00384                 pStep       = reference to resultant render step (IMPORTANT: holds initial step on entry)
00385                 DomStep     = the number of millipoints between each dominant division
00386                 Units       = Units used to define the render step
00387     Outputs:
00388     Returns:    -
00389     Purpose:    Works out what the step value should be used to render the grid with
00390                 the give width of a pixel and the given units of the grid.
00391     Errors:     
00392     Scope:      private
00393 
00394 **********************************************************************************************/
00395 /*  Technical note
00396     
00397     The following rules have been applied :
00398 
00399     1.  If the grid points are further apart than MIN_PIX_RENDER_COUNT pixels, then return these values,
00400         i.e. this value will look OK with the given pixel width
00401     2.  Otherwise find a grid step that is a multiple of the initial grid step, a factor of the
00402         dominant grid step, and is wider than MIN_PIX_RENDER_COUNT pixels.
00403 
00404 */
00405 
00406 void NodeGrid::CalcGridRenderSteps( MILLIPOINT PixelWidth,
00407                                     double*    pStep,   // entry = initial step, exit = modified step
00408                                     double     DomStep, // Distance between dominant steps
00409                                     UnitType   Units)   // Units of the grid
00410 {
00411     if (Units == NOTYPE) return;  // The get-out clause of the recursive contract
00412 
00413     double MinRenderWidth = (double)(PixelWidth*MIN_PIX_RENDER_COUNT);  // min distance between rendered grid points
00414 
00415     if ((DomStep < MinRenderWidth))
00416     {
00417         double ExtraDomStep = DomStep*::GetUnitMultiple(Units);
00418         CalcGridRenderSteps(PixelWidth,&DomStep,ExtraDomStep,::GetDominantUnit(Units));
00419     }
00420 
00421     double InitialStep = *pStep;
00422     double RenderStep  = *pStep;
00423 
00424     // Apply the grid step rules to RenderXStep
00425 
00426     if (RenderStep < MinRenderWidth)
00427     {
00428         while (RenderStep < MinRenderWidth)
00429         {
00430             do
00431             {
00432                 RenderStep += InitialStep;
00433             } while ((mod(DomStep,RenderStep) > (InitialStep/2)) && (RenderStep < DomStep));
00434         }
00435     }
00436 
00437     *pStep = RenderStep;
00438 }
00439 
00440 
00441 
00442 /***********************************************************************************************
00443 
00444 >   virtual BOOL NodeGrid::Snap(DocCoord* pDocCoord)
00445 
00446     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00447     Created:    8/2/94
00448     Inputs:     A DocCoord in Spread coords
00449     Outputs:    -
00450     Returns:    FALSE - ALWAYS!
00451     Purpose:    Place holder for derived classes
00452     SeeAlso:    NodeGridRect::Snap
00453         
00454 ***********************************************************************************************/
00455 
00456 BOOL NodeGrid::Snap(DocCoord* /*pDocCoord*/) 
00457 {
00458     return FALSE;
00459 }
00460 
00461 /***********************************************************************************************
00462 
00463 >   virtual BOOL NodeGrid::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord);
00464 
00465     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00466     Created:    8/2/94
00467     Inputs:     A DocRect, and two coords
00468     Outputs:    -
00469     Returns:    FALSE - ALWAYS!
00470     Purpose:    Place holder for derived classes
00471     SeeAlso:    NodeGridRect::Snap
00472         
00473 ***********************************************************************************************/
00474 
00475 BOOL NodeGrid::Snap(DocRect* /*pDocRect*/,const DocCoord& /*PrevCoord*/,const DocCoord& /*CurCoord*/)
00476 {
00477     return (FALSE);
00478 }
00479 
00480 /***********************************************************************************************
00481 
00482 > MILLIPOINT NodeGrid::SnapOrdinate(MILLIPOINT ord,double Step,MILLIPOINT origin)
00483 
00484     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00485     Created:    9/3/94
00486     Inputs:     ord     = the ordinate to snap 
00487                 Step    = distance between each snap point on the line
00488                 origin  = origin of first snap point of the line
00489     Outputs:    
00490     Returns:    Snapped version of ord
00491     Purpose:    General linear floating point ordinate snapping routine
00492     Errors:     BANG! if step = 0
00493     Scope:      protected
00494                                     
00495 
00496 ***********************************************************************************************/
00497 
00498 MILLIPOINT NodeGrid::SnapOrdinate(MILLIPOINT ord,double Step,MILLIPOINT origin)
00499 {
00500     double fp_ord   = ord;
00501 
00502     fp_ord -= origin;                       // Translate to 0
00503 
00504     double sign     = sgn(fp_ord);          // sign = 1 when fp_ord is >=0, sign = -1 when fp_ord<0
00505 
00506     fp_ord *= sign;                         // make +ve if it is -ve
00507 
00508     double dist = mod(fp_ord,Step); 
00509     if (dist > (Step/2)) dist -= Step;      // if closest to min adjacent snap point, snap to it
00510     fp_ord -= dist;
00511 
00512     fp_ord += 0.5;                          // Round up before convertion to MILLIPOINTS, and while still +ve
00513     fp_ord *= sign;                         // make -ve again if it was -ve on entry
00514     fp_ord += origin;                       // Translate back to the origin
00515 
00516     return (MILLIPOINT)fp_ord;
00517 }
00518 
00519 /***********************************************************************************************
00520 
00521 > void NodeGrid::UpdateBlobsData()
00522 
00523     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00524     Created:    23/2/94
00525     
00526     Inputs:
00527     Outputs:    
00528     Returns:
00529     Purpose:    Updates the internel select blobs data for the grid.
00530                 This involves putting the coords of all the select blobs into the BlobCoords
00531                 array of the grid
00532 
00533 **********************************************************************************************/
00534 
00535 void NodeGrid::UpdateBlobsData()
00536 {
00537     DocRect& BB = GridBoundingRect;
00538 
00539     BlobCoords[BottomLeft]  = DocCoord(BB.lo.x,BB.lo.y);
00540     BlobCoords[TopLeft]     = DocCoord(BB.lo.x,BB.hi.y);
00541     BlobCoords[TopRight]    = DocCoord(BB.hi.x,BB.hi.y);
00542     BlobCoords[BottomRight] = DocCoord(BB.hi.x,BB.lo.y);
00543 
00544     MILLIPOINT midX = BB.lo.x+((BB.hi.x-BB.lo.x)/2);
00545     MILLIPOINT midY = BB.lo.y+((BB.hi.y-BB.lo.y)/2);
00546 
00547     BlobCoords[LeftMiddle]      = DocCoord(BB.lo.x,midY);
00548     BlobCoords[RightMiddle]     = DocCoord(BB.hi.x,midY);
00549     BlobCoords[TopMiddle]       = DocCoord(midX,BB.hi.y);
00550     BlobCoords[BottomMiddle]    = DocCoord(midX,BB.lo.y);
00551 }
00552 
00553 /***********************************************************************************************
00554 
00555 > DocCoord NodeGrid::GetBlobCoord(GridBlobType GridBlob)
00556 
00557     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00558     Created:    23/2/94
00559     
00560     Inputs:     The blob type whos coord is required
00561     Outputs:    
00562     Returns:    The coord of that blob
00563     Purpose:    Returns the coord of the required blob of the grid
00564 
00565 **********************************************************************************************/
00566 
00567 DocCoord NodeGrid::GetBlobCoord(GridBlobType GridBlob)
00568 {
00569     return BlobCoords[GridBlob];
00570 }
00571 
00572 /***********************************************************************************************
00573 
00574 > void NodeGrid::SetBoundingRect(const DocRect& Rect)
00575 
00576     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00577     Created:    23/2/94
00578     Inputs:     The bounding rect for grid
00579     Outputs:    
00580     Returns:
00581     Purpose:    Sets the bounding rect of the grid, plus any other data that is needed.
00582                 Should call this after the Node's bounds has been set up using something like
00583                 SetInitialBounds.
00584 
00585 **********************************************************************************************/
00586 
00587 void NodeGrid::SetBoundingRect(const DocRect& Rect)
00588 {
00589     GridBoundingRect = Rect;
00590     UpdateBlobsData();
00591 }
00592 
00593 /***********************************************************************************************
00594 
00595 > DocRect NodeGrid::GetBoundingRect()
00596 
00597     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00598     Created:    23/2/94
00599     Inputs:     
00600     Outputs:    
00601     Returns:    The bounding rect for grid
00602     Purpose:    Returns the bounding rect of the grid.
00603 
00604 **********************************************************************************************/
00605 
00606 DocRect NodeGrid::GetBoundingRect()
00607 {
00608     return GridBoundingRect;
00609 }
00610 
00611 /***********************************************************************************************
00612 
00613 > DocRect NodeGrid::GetBlobBoundingRect()
00614 
00615     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00616     Created:    15/3/94
00617     Inputs:     
00618     Outputs:    
00619     Returns:    The blob bounding rect for grid
00620     Purpose:    Returns the blob bounding rect of the grid.
00621 
00622 **********************************************************************************************/
00623 
00624 DocRect NodeGrid::GetBlobBoundingRect()
00625 {
00626     // Find the paths bounding rectangle
00627     DocRect Rect = GridBoundingRect;
00628 
00629     // And if we can find the selected view, add on the size of a selection blob
00630     DocView* pDocView = DocView::GetSelected();
00631     if ( pDocView != NULL )
00632     {
00633         DocRect BlobSize;
00634         
00635         // Add the size of a blob to the top corner of the bounding rectangle
00636         OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), Rect.HighCorner(), 
00637                                     BT_SELECTEDLARGEST, &BlobSize);
00638         Rect.IncludePoint( BlobSize.HighCorner() );
00639         
00640         // add the size of a blob to the bottom corner of the bounding rectangle
00641         OSRenderRegion::GetBlobRect(pDocView->GetViewScale(), Rect.LowCorner(), 
00642                                     BT_SELECTEDLARGEST, &BlobSize);
00643         Rect.IncludePoint( BlobSize.LowCorner() );
00644     }
00645 
00646     return Rect;
00647 }
00648 
00649 /***********************************************************************************************
00650 
00651 > void NodeGrid::SetOrigin(MILLIPOINT X,MILLIPOINT Y)
00652 
00653     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00654     Created:    1/3/94
00655     Inputs:     The new (X,Y) origin of the grid
00656     Outputs:    
00657     Returns:    -
00658     Purpose:    Used for setting the origin of the grid.
00659 
00660 **********************************************************************************************/
00661 
00662 void NodeGrid::SetOrigin(MILLIPOINT X,MILLIPOINT Y)
00663 {
00664     XOrigin = X;
00665     YOrigin = Y;
00666 
00667     // a bit of a bodge, but for v1.1 the user origin will be permenently linked to the grid origin
00668     // (during import the grid may not yet be in the tree and has no parent spread - eek!)
00669     Node* pNode = FindParent();
00670     while (pNode!=NULL && pNode->IsSpread() == FALSE)
00671         pNode = pNode->FindParent();
00672     if (pNode!=NULL)
00673         ((Spread*)pNode)->SetUserOrigin(DocCoord(X,Y));
00674 }
00675 
00676 
00677 /***********************************************************************************************
00678 
00679 > void NodeGrid::GetOrigin(MILLIPOINT* pX,MILLIPOINT* pY)
00680 
00681     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00682     Created:    1/3/94
00683     Inputs:     Pointers to MILLIPOINT vars.
00684     Outputs:    *pX = X Origin of grid
00685                 *pY = Y Origin of grid
00686     Returns:    -
00687     Purpose:    Used for retrieving the origin of the grid.
00688 
00689 **********************************************************************************************/
00690 
00691 void NodeGrid::GetOrigin(MILLIPOINT* pX,MILLIPOINT* pY)
00692 {
00693     *pX = XOrigin;
00694     *pY = YOrigin;
00695 }
00696 
00697 /***********************************************************************************************
00698 
00699 > BOOL NodeGrid::IsGridSelected() const
00700 
00701     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00702     Created:    14/5/94
00703     Inputs:     -
00704     Outputs:    -
00705     Returns:    TRUE if grid is selected
00706     Purpose:    Find out if the grid is selected
00707 
00708 **********************************************************************************************/
00709 
00710 BOOL NodeGrid::IsGridSelected() const
00711 { 
00712     // Grids have their own special selected flag.
00713     return GridFlags.Selected;
00714 }
00715 
00716 /***********************************************************************************************
00717 
00718 > void NodeGrid::SetGridSelected(BOOL selected)
00719 
00720     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00721     Created:    14/5/94
00722     Inputs:     selected - if TRUE, the grid selected flag is set, else it is cleared
00723     Outputs:    -
00724     Returns:    -
00725     Purpose:    Change the grid's selected flag
00726 
00727 **********************************************************************************************/
00728 
00729 void NodeGrid::SetGridSelected(BOOL selected)
00730 {
00731     BOOL OldState = GridFlags.Selected;
00732     GridFlags.Selected = selected;
00733 
00734     if (OldState != selected)
00735     {
00736         if (selected)
00737             NodeGrid::NumSelected++;
00738         else
00739             NodeGrid::NumSelected--;
00740     }
00741 }
00742 
00743 /***********************************************************************************************
00744 
00745 > BOOL NodeGrid::IsDefault() const
00746 
00747     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00748     Created:    14/5/94
00749     Inputs:     -
00750     Outputs:    -
00751     Returns:    TRUE if grid is a Default grid
00752     Purpose:    Find out if the grid is a Default grid, i.e. one that covers a spread
00753                 completely.  These behave slightly differently in the selection model
00754 
00755 **********************************************************************************************/
00756 BOOL NodeGrid::IsDefault() const
00757 { 
00758     return GridFlags.DefaultGrid;       
00759 }
00760 
00761 /***********************************************************************************************
00762 
00763 > void NodeGrid::SetDefault(BOOL Default)
00764 
00765     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00766     Created:    14/5/94
00767     Inputs:     Default - if TRUE, the grid Default flag is set, else it is cleared
00768     Outputs:    -
00769     Returns:    -
00770     Purpose:    Change the grid's Default flag
00771 
00772 **********************************************************************************************/
00773 
00774 void NodeGrid::SetDefault(BOOL Default)
00775 { 
00776     GridFlags.DefaultGrid = Default;
00777 }
00778 
00779 /***********************************************************************************************
00780 
00781 > BOOL NodeGrid::IsDisabled() const
00782 
00783     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00784     Created:    14/5/94
00785     Inputs:     -
00786     Outputs:    -
00787     Returns:    TRUE if grid is disabled
00788     Purpose:    Find out if the grid is disabled.
00789                 A disabled grid does not render and cannot be snapped to.  
00790                 This mechanism is used to disable Default grids without deleting 
00791                 them from the tree.
00792 
00793 **********************************************************************************************/
00794 BOOL NodeGrid::IsDisabled() const
00795 { 
00796     return GridFlags.Disabled;
00797 }
00798 
00799 /***********************************************************************************************
00800 
00801 > void NodeGrid::SetDisabled(BOOL disabled)
00802 
00803     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00804     Created:    14/5/94
00805     Inputs:     disabled - if TRUE, the grid disabled flag is set, else it is cleared
00806     Outputs:    -
00807     Returns:    -
00808     Purpose:    Change the grid's disabled flag.
00809                 Also, if the grid is disabled, its selected flag is cleared as a disabled
00810                 grid cannot be selected.
00811 
00812 **********************************************************************************************/
00813 
00814 void NodeGrid::SetDisabled(BOOL disabled)
00815 { 
00816     GridFlags.Disabled   = disabled;        
00817     if (disabled) SetGridSelected(FALSE);
00818 }
00819 
00820 /***********************************************************************************************
00821 
00822 > static void NodeGrid::RecalcNumSelectedGrids(Spread* pSpread)
00823 
00824     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00825     Created:    17/5/94
00826     Inputs:     pSpread = ptr to spread that can contain selected grids.
00827     Outputs:    -
00828     Returns:    -
00829     Purpose:    Recalculates the number of selected grids there are in the given spread.
00830 
00831 **********************************************************************************************/
00832 
00833 void NodeGrid::RecalcNumSelectedGrids(Spread* pSpread)
00834 {
00835     if (pSpread == NULL) return;
00836 
00837     NodeGrid::NumSelected = 0;
00838     NodeGrid::NumNonDefaultSelected = 0;
00839 
00840     // Start from the last node in the spread
00841     Node* pNode = pSpread->FindLastChild();
00842     while (pNode != NULL)
00843     {
00844         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
00845         {
00846             NodeGrid* pGrid = (NodeGrid*)pNode;
00847             
00848             if (pGrid->IsGridSelected() && !pGrid->IsDisabled())
00849             {
00850                 NodeGrid::NumSelected++;
00851 
00852                 if (!pGrid->IsDefault())
00853                     NodeGrid::NumNonDefaultSelected++;
00854             }
00855         }
00856         // Scan back along the sibling list
00857         pNode = pNode->FindPrevious();
00858     }
00859 }
00860 
00861 //--------------------------------------------------------------------------------------------
00862                                        
00863 #ifdef _DEBUG
00864  
00865 void NodeGrid::ShowDebugTreeDetails() const
00866 {                                 
00867     NodeRenderablePaper::ShowDebugTreeDetails(); 
00868 }  
00869 #endif
00870 
00871 void NodeGrid::DumpRect(DocRect& R,TCHAR* S)
00872 {
00873 #ifdef _DEBUG
00874     TRACEUSER( "MarkN", _T("%s.lo.x = %ld\n"),  S,R.lo.x );
00875     TRACEUSER( "MarkN", _T("%s.lo.y = %ld\n"),  S,R.lo.y);
00876     TRACEUSER( "MarkN", _T("%s.hi.x = %ld\n"),  S,R.hi.x);
00877     TRACEUSER( "MarkN", _T("%s.hi.y = %ld\n\n"),S,R.hi.y);
00878 #endif
00879 }
00880 
00881 
00882 /********************************************************************************************
00883 >   virtual double NodeGrid::CalcDivisions(BOOL Scale)
00884 
00885     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00886     Created:    17/10/95
00887     Inputs:     Scale - account for scaling (only FALSE when saving for doc compatibility)
00888     Returns:    Number of Units between each main grid point
00889     Purpose:    Used to get the number of Units between each main grid point.
00890     Note:       No longer uses 'Divisions' as this is a cached value which is not updated when
00891                 unit scaling is changed. Dynamically caclulating this overcomes this problem
00892                 Divisons has not been removed from the class as it also entails removing all
00893                 code setting the value. I have proposed the whole system needs revamping!
00894 ********************************************************************************************/
00895 
00896 double NodeGrid::CalcDivisions(BOOL Scale)
00897 {
00898     double   Spacing = GetMainStep();
00899     UnitType Units   = GetUnits(Scale);
00900     BOOL ok = TRUE;
00901     String_256 Str;
00902 
00903     if (Scale==FALSE)
00904         ok = Convert::MillipointsToString(Spacing,Units,&Str,10);
00905     else
00906     {
00907         DimScale* pDimScale = DimScale::GetPtrDimScale(this);
00908         ERROR2IF(pDimScale==NULL,FALSE,"NodeGridRect::CalcDivisions() - pDimScale==NULL");
00909         ok = pDimScale->ConvertToUnits(Spacing,&Str,TRUE,10,Units);
00910     }
00911 
00912     double   Divs;
00913     UnitType DummyUnits;
00914     if (ok) ok=Convert::StringToComponents(Str, &Divs, &DummyUnits);
00915     if (!ok) Divs=1;
00916 
00917     return Divs;
00918 }
00919 
00920 
00921 //--------------------------------------------------------------------------------------------
00922 //--------------------------------------------------------------------------------------------
00923 
00924 // NodeGridRect methods         
00925 
00926 CC_IMPLEMENT_DYNAMIC(NodeGridRect, NodeGrid)          
00927 
00928 /*********************************************************************************************
00929 
00930 >    NodeGridRect::NodeGridRect() 
00931 
00932      Author:    Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00933      Created:   8/2/94
00934      Inputs:    -
00935      Outputs:   
00936      Returns:   -
00937               
00938      Purpose: This constructor creates a NodeGridRect linked to no other nodes, with all status
00939               flags false, and NULL bounding and pasteboard rectangles.            
00940             
00941      Errors:    
00942 
00943 **********************************************************************************************/
00944  
00945 
00946 NodeGridRect::NodeGridRect(): NodeGrid()
00947 {   
00948     Units       = INCHES;
00949     Divisions   = 1.0;
00950     Subdivisions= 2;
00951 
00952     MainXStep = 72000.0;
00953     SubXStep  = MainXStep/Subdivisions;
00954     MainYStep = MainXStep;
00955     SubYStep  = SubXStep;
00956 }                    
00957     
00958   
00959 /********************************************************************************************
00960 
00961 >   String NodeGridRect::Describe(BOOL Plural, BOOL Verbose = TRUE)
00962 
00963     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00964     Created:    8/2/94
00965     Inputs:     Plural: Flag indicating if the string description should be plural or
00966                         singular. 
00967     Outputs:    -
00968     Retuns:     Description of the object 
00969     Purpose:    To return a description of the Node object in either the singular or the 
00970                 plural. This method is called by the DescribeRange method.
00971                 
00972                 The description will always begin with a lower case letter.   
00973                 
00974     Errors:     A resource exception will be thrown if a problem occurs when loading the 
00975                 string resource. 
00976     SeeAlso:    -
00977 
00978 ********************************************************************************************/
00979 /*
00980     Technical Notes:
00981     
00982     The String resource identifiers should be of the form: ID_<Class>_DescriptionS for the 
00983     singular description and ID_<Class>_DescriptionP for the plural. 
00984 */              
00985               
00986 String NodeGridRect::Describe(BOOL Plural, BOOL Verbose) 
00987 {   
00988 
00989     if (Plural)
00990         return (String(_R(IDS_GRIDRECT_DESCRP)));
00991     else
00992         return (String(_R(IDS_GRIDRECT_DESCRS)));
00993 }; 
00994  
00995 
00996 /***********************************************************************************************
00997 
00998 >   void NodeGridRect::Render(RenderRegion* pRender)
00999 
01000     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01001     Created:    8/2/94
01002     Inputs:     pRender = a render region
01003     Outputs:    -
01004     Returns:    - 
01005     Purpose:    Renders the rectangular grid item
01006                 
01007     Errors:     -
01008     SeeAlso:    -
01009 
01010 ***********************************************************************************************/
01011 
01012 void NodeGridRect::Render( RenderRegion* pRender )
01013 {      
01014 #if !defined(EXCLUDE_FROM_RALPH)
01015 //  static INT32 bbb=0;
01016 //  if (IsUserName("MarkN")) TRACE( _T("\n-------------------------------------------------------------------\n"));
01017 //  if (IsUserName("MarkN")) TRACE( _T("NodeGridRect::Render - %ld\n\n"),bbb++);
01018 
01019     // See if the render region likes grids to be drawn....
01020     if (!pRender->WantsGrids())
01021         return;
01022 
01023     // If the grid is disabled, don't bother either
01024     if (IsDisabled())
01025         return;
01026 
01027     View* pView = pRender->GetRenderView();
01028     if ((pView == NULL) || (!IS_A(pView, DocView)))
01029         // No docview to render to.
01030         return;
01031 
01032     DocView *pDocView = (DocView *) pView;
01033 
01034     if (!pDocView->GetShowGridState() && Tool::GetCurrentID() != TOOLID_GRID) return;
01035 
01036     // Set up attributes for drawing grid points
01037     pRender->SaveContext();
01038 // Don't set line attributes because grid points are now plotted used filled rects
01039 //  pRender->SetLineWidth(0);                               // Means single-pixel lines
01040 //  pRender->SetLineColour(GridColour);                     // Grid blobs are in this colour
01041 
01042     // Set fill attributes for grid point rectangle plotting...
01043     pRender->SetLineWidth(0);
01044     pRender->SetLineColour(COLOUR_TRANS); 
01045     pRender->SetFillColour(GridColour);
01046         
01047     DocRect ClipRect = pRender->GetClipRect();              // Get the current clip rect
01048     DocRect RendRect;
01049 
01050     RendRect.lo.x = max(GridBoundingRect.lo.x,ClipRect.lo.x);   // hi and lo renderable grid points
01051     RendRect.lo.y = max(GridBoundingRect.lo.y,ClipRect.lo.y);   // derived from the clip rect and the 
01052     RendRect.hi.x = min(GridBoundingRect.hi.x,ClipRect.hi.x);   // node's bounding rect
01053     RendRect.hi.y = min(GridBoundingRect.hi.y,ClipRect.hi.y);
01054     
01055     if (RendRect.IsValid())
01056     {
01057         MILLIPOINT PixelWidth = pRender->GetScaledPixelWidth(); // the width of a single pixel 
01058 
01059         RenderMainPoints(pRender,RendRect,PixelWidth);          // Render the main grid points (crosshairs)
01060         RenderSubPoints(pRender,RendRect,PixelWidth);           // Render the sub grid points (dots)
01061     }
01062 
01063     pRender->RestoreContext();
01064 #endif
01065 }  
01066 
01067 /***********************************************************************************************
01068 
01069 > void NodeGridRect::RenderMainPoints(RenderRegion* pRender,DocRect RendRect,MILLIPOINT PixelWidth)
01070 
01071     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01072     Created:    9/2/94
01073     
01074     Inputs:     pRender     = region to render to
01075                 RendRect    = Rectangle defining the renderable portion of the grid
01076                 PixelWidth  = width of a pixel in millipoints
01077     Outputs:    
01078     Returns:
01079     Purpose:    Renders the main grid points within the given renderable rectangle
01080     Errors:     
01081     Scope:      private
01082 
01083 ***********************************************************************************************/
01084 
01085 void NodeGridRect::RenderMainPoints(RenderRegion* pRender,DocRect RendRect,MILLIPOINT PixelWidth)
01086 {
01087 #if !defined(EXCLUDE_FROM_RALPH)
01088     // Set the fp render step values to be the underlying main grid step value
01089     double fp_RenderXStep = MainXStep;
01090     double fp_RenderYStep = MainYStep;
01091 
01092     // Calculate the step for rendering the grid in relation to the width of a pixel and the
01093     // factors of the dominant unit
01094     CalcGridRenderSteps(PixelWidth,&fp_RenderXStep,fp_RenderXStep*::GetUnitMultiple(Units),Units);
01095     CalcGridRenderSteps(PixelWidth,&fp_RenderYStep,fp_RenderYStep*::GetUnitMultiple(Units),Units);
01096 
01097     // Snap the render rect to these adjusted steps so we render all points within the renderable
01098     // portion of the grid
01099     Snap(&RendRect.lo,fp_RenderXStep,fp_RenderYStep);
01100     Snap(&RendRect.hi,fp_RenderXStep,fp_RenderYStep);
01101 
01102     ENSURE(RendRect.IsValid(),"RendRect is invalid in NodeGridRect::RenderMainPoints");
01103         
01104     // Get fixed point versions of the fp values for speedy grid rendering
01105     MILLIPOINT RenderXStep = (MILLIPOINT)((fp_RenderXStep * GRID_REND_FACTOR)+0.5);
01106     MILLIPOINT RenderYStep = (MILLIPOINT)((fp_RenderYStep * GRID_REND_FACTOR)+0.5);
01107 
01108 //  DumpRect(RendRect,"RendRect");
01109 
01110     // Convert RendRect to fixed point values
01111     RendRect.lo.x *= GRID_REND_FACTOR;
01112     RendRect.lo.y *= GRID_REND_FACTOR;
01113     RendRect.hi.x *= GRID_REND_FACTOR;
01114     RendRect.hi.y *= GRID_REND_FACTOR;
01115 
01116     DocRect ScaledBB = GridBoundingRect;
01117     ScaledBB.lo.x *= GRID_REND_FACTOR;
01118     ScaledBB.lo.y *= GRID_REND_FACTOR;
01119     ScaledBB.hi.x *= GRID_REND_FACTOR;
01120     ScaledBB.hi.y *= GRID_REND_FACTOR;
01121 
01122     // Make sure the render rectangle region doesn't lie outside the bounding rect
01123     while (RendRect.lo.x <  ScaledBB.lo.x) RendRect.lo.x += RenderXStep;
01124     while (RendRect.lo.y <  ScaledBB.lo.y) RendRect.lo.y += RenderYStep;
01125     while (RendRect.hi.x >= ScaledBB.hi.x) RendRect.hi.x -= RenderXStep;
01126     while (RendRect.hi.y >= ScaledBB.hi.y) RendRect.hi.y -= RenderYStep;
01127 
01128     RendRect.hi.x += GRID_REND_FACTOR; // compensate for errors (i.e. add the bodge factor)
01129     RendRect.hi.y += GRID_REND_FACTOR; // compensate for errors
01130 
01131     // Render those grid points boy!
01132 
01133     DocCoord GridPoint,TrueGridPoint;
01134 
01135     const MILLIPOINT Pix = pRender->GetScaledPixelWidth();
01136 //  const MILLIPOINT PixBy2 = Pix/2;
01137     const MILLIPOINT Length = PIX_CROSSHAIR_SIZE * Pix;
01138 
01139     for (GridPoint.x=RendRect.lo.x;GridPoint.x<=RendRect.hi.x;GridPoint.x+=RenderXStep)
01140     {
01141         for (GridPoint.y=RendRect.lo.y;GridPoint.y<=RendRect.hi.y;GridPoint.y+=RenderYStep)
01142         {
01143             // Scale the fixed point grid coord down to get the true coord of the grid point
01144             TrueGridPoint.x = (GridPoint.x+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01145             TrueGridPoint.y = (GridPoint.y+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01146 
01147 //          pRender->DrawCross(TrueGridPoint, PIX_CROSSHAIR_SIZE);
01148             // Phil says: Don't use DrawPixel because it can't be trusted to plot the
01149             // same pixel under GDI as it does under GDraw!
01150             // Instead draw two rectangles centered around the required coord.
01151             DocRect Horz(TrueGridPoint.x-Length,TrueGridPoint.y,TrueGridPoint.x+Length+Pix,TrueGridPoint.y+Pix);
01152             pRender->DrawRect(&Horz);
01153 
01154             DocRect Vert(TrueGridPoint.x,TrueGridPoint.y-Length,TrueGridPoint.x+Pix,TrueGridPoint.y+Length+Pix);
01155             pRender->DrawRect(&Vert);
01156 
01157         }
01158     }
01159 #endif
01160 }
01161 
01162 
01163 /***********************************************************************************************
01164 
01165 > void NodeGridRect::RenderSubPoints(RenderRegion* pRender,DocRect RendRect,MILLIPOINT PixelWidth)
01166 
01167     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01168     Created:    9/2/94
01169     
01170     Inputs:     pRender     = region to render to
01171                 RendRect    = Rectangle defining the renderable portion of the grid
01172                 PixelWidth  = width of a pixel in millipoints
01173     Outputs:    
01174     Returns:
01175     Purpose:    Renders the sub grid points within the given renderable rectangle
01176     Errors:     
01177     Scope:      private
01178 
01179 ***********************************************************************************************/
01180 
01181 void NodeGridRect::RenderSubPoints(RenderRegion* pRender,DocRect RendRect,MILLIPOINT PixelWidth)
01182 {
01183 #if !defined(EXCLUDE_FROM_RALPH)
01184     // Set the fp render step values to be the underlying sub grid step value
01185     double fp_RenderXStep = SubXStep;
01186     double fp_RenderYStep = SubYStep;
01187 
01188     // Calculate the step for rendering the grid in relation to the width of a pixel and the
01189     // factors of the dominant unit
01190     CalcGridRenderSteps(PixelWidth,&fp_RenderXStep,MainXStep,Units);
01191     CalcGridRenderSteps(PixelWidth,&fp_RenderYStep,MainYStep,Units);
01192 
01193     // If the render step is greater than the main step then don't render the sub grid
01194     if (fp_RenderXStep >= MainXStep) return;
01195     if (fp_RenderYStep >= MainYStep) return;
01196 
01197     // Snap the render rect to the render steps so we render all points within the renderable
01198     // portion of the grid
01199 
01200     Snap(&RendRect.lo,fp_RenderXStep,fp_RenderYStep);
01201     Snap(&RendRect.hi,fp_RenderXStep,fp_RenderYStep);
01202 
01203     ENSURE(RendRect.IsValid(),"RendRect is invalid in NodeGridRect::RenderSubPoints");
01204 
01205     // Get fixed point versions of the fp values for speedy grid rendering
01206     MILLIPOINT RenderXStep = (MILLIPOINT)((fp_RenderXStep * GRID_REND_FACTOR)+0.5);
01207     MILLIPOINT RenderYStep = (MILLIPOINT)((fp_RenderYStep * GRID_REND_FACTOR)+0.5);
01208 
01209     // Convert RendRect to fixed point values
01210     RendRect.lo.x *= GRID_REND_FACTOR;
01211     RendRect.lo.y *= GRID_REND_FACTOR;
01212     RendRect.hi.x *= GRID_REND_FACTOR;
01213     RendRect.hi.y *= GRID_REND_FACTOR;
01214 
01215     DocRect ScaledBB = GridBoundingRect;
01216     ScaledBB.lo.x *= GRID_REND_FACTOR;
01217     ScaledBB.lo.y *= GRID_REND_FACTOR;
01218     ScaledBB.hi.x *= GRID_REND_FACTOR;
01219     ScaledBB.hi.y *= GRID_REND_FACTOR;
01220 
01221     // Make sure the render rectangle region doesn't lie outside the bounding rect
01222     while (RendRect.lo.x <  ScaledBB.lo.x) RendRect.lo.x += RenderXStep;
01223     while (RendRect.lo.y <  ScaledBB.lo.y) RendRect.lo.y += RenderYStep;
01224     while (RendRect.hi.x >= ScaledBB.hi.x) RendRect.hi.x -= RenderXStep;
01225     while (RendRect.hi.y >= ScaledBB.hi.y) RendRect.hi.y -= RenderYStep;
01226 
01227     RendRect.hi.x += GRID_REND_FACTOR; // compensate for errors (i.e. add the bodge factor)
01228     RendRect.hi.y += GRID_REND_FACTOR; // compensate for errors
01229 
01230     // Go ahead punk, render those points                                                   
01231 
01232     DocCoord GridPoint,TrueGridPoint;
01233 
01234     const MILLIPOINT Pix = pRender->GetScaledPixelWidth();
01235 //  const MILLIPOINT PixBy2 = Pix/2;
01236 
01237     for (GridPoint.x=RendRect.lo.x;GridPoint.x<=RendRect.hi.x;GridPoint.x+=RenderXStep)
01238     {
01239         for (GridPoint.y=RendRect.lo.y;GridPoint.y<=RendRect.hi.y;GridPoint.y+=RenderYStep)
01240         {
01241             // Scale the fixed point grid coord down to get the true coord of the grid point
01242             TrueGridPoint.x = (GridPoint.x+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01243             TrueGridPoint.y = (GridPoint.y+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01244 
01245 //          pRender->DrawPixel(TrueGridPoint);
01246             // Phil says: Don't use DrawPixel because it can't be trusted to plot the
01247             // same pixel under GDI as it does under GDraw!
01248             // Instead draw a rectangle 1*1 pixels around the required coord.
01249             DocRect Pixel(  TrueGridPoint.x,
01250                             TrueGridPoint.y,
01251                             TrueGridPoint.x+Pix,
01252                             TrueGridPoint.y+Pix);
01253             pRender->DrawRect(&Pixel);
01254         }
01255     }
01256 #endif
01257 }
01258 
01259 /***********************************************************************************************
01260 
01261 > BOOL NodeGridRect::Snap(DocCoord* pDocCoord)
01262 
01263     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01264     Created:    9/2/94
01265     Inputs:     pDocCoord   = a coord in Spread coords
01266     Outputs:    
01267     Returns:    TRUE    - the DocCoord has been snapped to the grid.
01268                 FALSE   - the DocCoord has not been processed.
01269                                                          
01270     Purpose:    Snaps to given coord to the nearest grid point.  If it is not appropriate to snap
01271                 the coord to the grid (at the moment this means the coord lies outside the grid object's
01272                 bounding box), then FALSE is returned.
01273     Errors:        
01274     Scope:      public
01275            
01276 **********************************************************************************************/
01277 
01278 BOOL NodeGridRect::Snap(DocCoord* pDocCoord)
01279 {
01280     if (IsDisabled()) return FALSE;
01281 
01282     ENSURE(SubXStep !=0,"SubXStep ==0 in NodeGridRect::Snap");
01283     ENSURE(SubYStep !=0,"SubYStep ==0 in NodeGridRect::Snap");
01284 
01285     if (!GridBoundingRect.ContainsCoord(DocCoord(pDocCoord->x,pDocCoord->y)))
01286         return (FALSE);
01287 
01288     MILLIPOINT x = SnapOrdinate(pDocCoord->x,SubXStep,XOrigin);
01289     MILLIPOINT y = SnapOrdinate(pDocCoord->y,SubYStep,YOrigin);
01290 
01291     if (!GridBoundingRect.ContainsCoord(DocCoord(x,y)))
01292         return (FALSE);
01293 
01294     pDocCoord->x = x;
01295     pDocCoord->y = y;
01296 
01297     return (TRUE);
01298 }
01299 
01300 /***********************************************************************************************
01301 
01302 > BOOL NodeGridRect::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
01303 
01304     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01305     Created:    9/2/94
01306     Inputs:     pDocCoord   - the rectangle to snap
01307                 StartDrag   - Start coord of drag
01308                 EndDrag     - End coord of drag
01309     Outputs:    
01310     Returns:    TRUE    - the DocRect been snapped to the grid.
01311                 FALSE   - the DocRect has not been processed.
01312                                                          
01313     Purpose:    Snaps the given rect to the nearest position on the grid, preserving its width
01314                 and height.
01315                 The coords of the rect used for the snapping are determined by the PrevCoord and
01316                 CurCoord coords supplied.  This is done to allow the user to control how a
01317                 selection rectangle is snapped to the grid by the direction of his/her last mouse 
01318                 movement.
01319                 To force the bottom left hand corner of the rect to be snapped, 
01320                 supply PrevCoord=(0,0) and CurCoord(-1,-1).
01321     Scope:      public
01322            
01323 **********************************************************************************************/
01324 
01325 BOOL NodeGridRect::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
01326 {
01327     if (IsDisabled()) return FALSE;
01328 
01329     ENSURE(SubXStep !=0,"SubXStep ==0 in NodeGridRect::Snap");
01330     ENSURE(SubYStep !=0,"SubYStep ==0 in NodeGridRect::Snap");
01331     
01332     INT32 xdir = CurCoord.x - PrevCoord.x;
01333     INT32 ydir = CurCoord.y - PrevCoord.y;
01334     INT32 x,y,prevx, prevy;
01335     
01336     if (LastXDir == 0)  LastXDir = xdir;
01337     if (xdir == 0)      xdir = LastXDir;
01338     LastXDir = xdir;
01339 
01340     if (xdir <= 0) x = pDocRect->lo.x; else x = pDocRect->hi.x;
01341 
01342     if (LastYDir == 0)  LastYDir = ydir;
01343     if (ydir == 0)      ydir = LastYDir;
01344     LastYDir = ydir;
01345 
01346     if (ydir <= 0) y = pDocRect->lo.y; else y = pDocRect->hi.y;
01347 
01348     if (!GridBoundingRect.ContainsCoord(DocCoord(x,y)))
01349         return (FALSE);
01350 
01351     prevx   = x;
01352     prevy   = y;
01353     x       = SnapOrdinate(x,SubXStep,XOrigin);
01354     y       = SnapOrdinate(y,SubYStep,YOrigin);
01355 
01356     if (!GridBoundingRect.ContainsCoord(DocCoord(x,y)))
01357         return (FALSE);
01358 
01359     pDocRect->Translate(x-prevx,y-prevy);
01360 
01361     return (TRUE);
01362 }
01363 /***********************************************************************************************
01364 
01365 > BOOL NodeGridRect::Snap(DocCoord* pDocCoord,double XStep,double YStep)
01366 
01367     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01368     Created:    9/2/94
01369     Inputs:     pDocCoord   - the coord to snap
01370                 XStep       - the x step to use when snapping the point
01371                 YStep       - the y step to use when snapping the point
01372     Outputs:    
01373     Returns:    TRUE    - the DocCoord has been snapped to the grid.
01374                 FALSE   - the DocCoord has not been processed.
01375                                                          
01376     Purpose:    Same as Snap(pDocCoord), except the coord is snapped to grid points at the given intervals
01377     Errors:        
01378     Scope:      public
01379            
01380 **********************************************************************************************/
01381 
01382 BOOL NodeGridRect::Snap(DocCoord* pDocCoord,double XStep,double YStep)
01383 {
01384     if (IsDisabled()) return FALSE;
01385 
01386     ENSURE(XStep!=0,"XStep==0 in NodeGridRect::Snap(pDocCoord,XStep,YStep");
01387     ENSURE(YStep!=0,"YStep==0 in NodeGridRect::Snap(pDocCoord,XStep,YStep"); 
01388 
01389     pDocCoord->x = SnapOrdinate(pDocCoord->x,XStep,XOrigin);
01390     pDocCoord->y = SnapOrdinate(pDocCoord->y,YStep,YOrigin);
01391 
01392     return (TRUE);
01393 }
01394 
01395 
01396 /***********************************************************************************************
01397 
01398 > Node* NodeGridRect::SimpleCopy() // Private method  
01399 
01400     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01401     Created:    8/2/94
01402     
01403     Inputs:         - 
01404     Outputs:    
01405     Returns:    A copy of the node, or NULL if memory runs out
01406          
01407     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
01408                 The function is virtual, and must be defined for all derived classes.  
01409            
01410     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
01411                 error and the function returns NULL. 
01412  
01413         
01414     Scope:      protected       
01415 **********************************************************************************************/
01416 
01417 Node* NodeGridRect::SimpleCopy()
01418 {
01419     NodeGridRect* NodeCopy = new NodeGridRect();   
01420     if (NodeCopy != NULL)
01421         CopyNodeContents(NodeCopy);   
01422     return (NodeCopy);
01423 }          
01424 
01425 /***********************************************************************************************
01426 >   void NodeGridRect::CopyNodeContents(NodeGridRect* NodeCopy)
01427 
01428     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01429     Created:    8/2/94
01430     
01431     Inputs:     - 
01432     Outputs:    A copy of this node
01433  
01434     Returns:    -
01435          
01436     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
01437               
01438     Errors:     An assertion failure will occur if NodeCopy is NULL
01439     
01440     Scope:      protected
01441                                      
01442 ***********************************************************************************************/
01443 
01444 
01445 void NodeGridRect::CopyNodeContents(NodeGridRect* NodeCopy)
01446 {
01447     ENSURE(NodeCopy != NULL,"Trying to copy a NodeGridRect's contents to a NULL node");  
01448     NodeGrid::CopyNodeContents(NodeCopy); 
01449 
01450     NodeCopy->MainXStep     = this->MainXStep;
01451     NodeCopy->MainYStep     = this->MainYStep;
01452     NodeCopy->SubXStep      = this->SubXStep;   
01453     NodeCopy->SubYStep      = this->SubYStep;   
01454 
01455     NodeCopy->Units         = this->Units;
01456     NodeCopy->Divisions     = this->Divisions;
01457     NodeCopy->Subdivisions  = this->Subdivisions;
01458 }
01459 
01460 
01461 /***********************************************************************************************
01462 >   void NodeGridRect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01463 
01464     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01465     Created:    18/12/2003
01466     Outputs:    -
01467     Purpose:    Polymorphically copies the contents of this node to another
01468     Errors:     An assertion failure will occur if NodeCopy is NULL
01469     Scope:      protected
01470                                      
01471 ***********************************************************************************************/
01472 
01473 void NodeGridRect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01474 {
01475     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
01476     ENSURE(IS_A(pNodeCopy, NodeGridRect), "PolyCopyNodeContents given wrong dest node type");
01477 
01478     if (IS_A(pNodeCopy, NodeGridRect))
01479         CopyNodeContents((NodeGridRect*)pNodeCopy);
01480 }
01481 
01482 
01483 
01484 /********************************************************************************************
01485 
01486 >   void* NodeGridRect::GetDebugDetails(StringBase* Str) 
01487 
01488     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01489     Created:    8/2/94
01490     Inputs:     -
01491     Outputs:    Str: String giving debug info about the node
01492     Returns:    -
01493     Purpose:    For obtaining debug information about the Node
01494     Errors:     -
01495     SeeAlso:    -
01496 
01497 ********************************************************************************************/
01498 
01499      
01500 void NodeGridRect::GetDebugDetails(StringBase* Str) 
01501 {          
01502     NodeGrid::GetDebugDetails(Str); 
01503 }
01504  
01505           
01506 //--------------------------------------------------------------------------------------------
01507                                        
01508 #ifdef _DEBUG
01509  
01510 void NodeGridRect::ShowDebugTreeDetails() const
01511 {                                 
01512     TRACE( _T("NodeGridRect::ShowDebugTreeDetails() ")); 
01513     Node::ShowDebugTreeDetails(); 
01514 }  
01515 
01516 #endif
01517  
01518 //--------------------------------------------------------------------------------------------
01519 
01520 /********************************************************************************************
01521 >   BOOL NodeGridRect::SetGridParams(double Div,UINT32 Subdiv,UnitType NewUnits, BOOL Scale=TRUE)
01522 
01523     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01524     Created:    16/10/95
01525     Inputs:     Div      - Number of Units between each main grid point
01526                 Subdiv   - Number of subdivisions between each main grid point
01527                 NewUnits - The units the grid is defined in
01528                 Scale    - account for unit scaling (only FALSE when loading for compatibility with old docs)
01529     Returns:    FALSE if fails
01530     Purpose:    Defines the grid.
01531 ********************************************************************************************/
01532 
01533 BOOL NodeGridRect::SetGridParams(double Div, UINT32 Subdiv, UnitType NewUnits, BOOL Scale)
01534 {
01535     if (Div < 0)
01536     {
01537         ERROR3("NodeGridRect::SetGridParams() - Div < 0!");
01538         Div = 0.0;
01539     }
01540     if (Subdiv < 1)
01541     {
01542         ERROR3("NodeGridRect::SetGridParams() - SubDiv < 1!");
01543         Subdiv = 1;
01544     }
01545 
01546     DimScale* pDimScale = DimScale::GetPtrDimScale(this);
01547     ERROR2IF(pDimScale==NULL,FALSE,"NodeGridRect::SetGridParams() - pDimScale==NULL");
01548 
01549     // set the raw values in the grid - but only set units if scaling turned off
01550     // (except if scaling is not to be accounted for  - ie during loading for compatibility with old docs - yuk!)
01551     Divisions    = Div;
01552     Subdivisions = Subdiv;
01553     if (Scale==FALSE || pDimScale->GetScaleUnits()==NOTYPE)
01554         Units = NewUnits;
01555 
01556     // convert the divisions and units into a millipoint grid spacing (accounting for unit scaling) - yuk!
01557     double GridSpacing=0;
01558     if (Scale)
01559     {
01560         BOOL ok = pDimScale->ComponentsToMillipoint(&GridSpacing, Divisions, GetUnits());
01561         if (!ok) return FALSE;
01562     }
01563     else
01564     {
01565         DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
01566         ERROR2IF(pDocUnitList==NULL,FALSE,"DimScale::ComponentsToMillipoint() - pDocUnitList==NULL");
01567         Unit* pUnit = pDocUnitList->FindUnit(Units);
01568         ERROR2IF(pUnit==NULL,FALSE,"DimScale::ComponentsToMillipoint() - pUnit==NULL");
01569         GridSpacing = Div * pUnit->GetMillipoints();
01570     }
01571 
01572     if (GridSpacing<1)
01573     {
01574         ERROR3("NodeGridRect::SetGridParams() - GridSpacing < 1!");
01575         GridSpacing=1;
01576     }
01577 
01578     MainXStep = GridSpacing;
01579     SubXStep  = MainXStep/Subdivisions;
01580     if (SubXStep<1)
01581     {
01582         ERROR3("NodeGridRect::SetGridParams() - SubXStep < 1!");
01583         SubXStep=1;
01584     }
01585 
01586     MainYStep = MainXStep;
01587     SubYStep  = SubXStep;
01588     
01589     return TRUE;
01590 }
01591 
01592 
01593 /********************************************************************************************
01594 >   double NodeGridRect::GetDivisions(BOOL Scale=TRUE)
01595 
01596     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01597     Created:    17/10/95
01598     Inputs:     Scale - account for scaling (only FALSE when saving for doc compatibility)
01599     Returns:    Number of Units between each main grid point
01600     Purpose:    Used to get the number of Units between each main grid point.
01601 ********************************************************************************************/
01602 
01603 double NodeGridRect::GetDivisions(BOOL Scale)
01604 {
01605     return NodeGrid::CalcDivisions(Scale);
01606 }
01607 
01608 
01609 /********************************************************************************************
01610 
01611 >   UINT32 NodeGridRect::GetSubdivisions()
01612 
01613     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01614     Created:    1/3/94
01615     Inputs:     -
01616     Outputs:    -
01617     Returns:    Num subdivisions
01618     Purpose:    Used to get the number of subdivisions between each main grid point.
01619     Errors:     -
01620     SeeAlso:    -
01621 
01622 ********************************************************************************************/
01623 
01624 UINT32 NodeGridRect::GetSubdivisions()
01625 {
01626     return Subdivisions;
01627 }
01628 
01629 
01630 /********************************************************************************************
01631 >   UnitType NodeGridRect::GetUnits(BOOL Scale=TRUE)
01632 
01633     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01634     Created:    20/10/95
01635     Inputs:     Scale - account for unit scaling (only FALSE when saving for compatibility with old docs)
01636     Returns:    Units used by the grid
01637     Purpose:    Gets the units used by the grid
01638 ********************************************************************************************/
01639 
01640 UnitType NodeGridRect::GetUnits(BOOL Scale)
01641 {
01642     DimScale* pDimScale = DimScale::GetPtrDimScale(this);
01643     ERROR2IF(pDimScale==NULL,NOTYPE,"NodeGridRect::GetUnits() - pDimScale==NULL");
01644 
01645     // if scaling turned on return scale units
01646     // (except if scaling is not to be accounted for  - ie during saving for compatibility with old docs)
01647     UnitType ScaleUnits = pDimScale->GetScaleUnits();
01648     if (Scale && ScaleUnits!=NOTYPE)
01649         return ScaleUnits;
01650 
01651     return Units;
01652 }
01653 
01654 
01655 //--------------------------------------------------------------------------------------------
01656 //--------------------------------------------------------------------------------------------
01657 
01658 // NodeGridIso methods         
01659 
01660 CC_IMPLEMENT_DYNAMIC(NodeGridIso, NodeGrid)          
01661 
01662 /*********************************************************************************************
01663 
01664 >    NodeGridRect::NodeGridIso() 
01665 
01666      Author:    Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01667      Created:   15/2/94
01668      Inputs:    -
01669      Outputs:   
01670      Returns:   -
01671               
01672      Purpose: This constructor creates a NodeGridIso linked to no other nodes, with all status
01673               flags false, and NULL bounding and pasteboard rectangles.            
01674             
01675      Errors:    
01676 
01677 **********************************************************************************************/
01678  
01679 
01680 NodeGridIso::NodeGridIso(): NodeGrid()
01681 {   
01682     Units        = INCHES;
01683     Divisions    = 1.0;
01684     Subdivisions = 4;
01685 
01686     MainStep = 72000.0;
01687     SubStep = MainStep/Subdivisions;
01688 }                    
01689     
01690   
01691 /********************************************************************************************
01692 
01693 >   String NodeGridIso::Describe(BOOL Plural, BOOL Verbose = TRUE)
01694 
01695     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01696     Created:    15/2/94
01697     Inputs:     Plural: Flag indicating if the string description should be plural or
01698                         singular. 
01699     Outputs:    -
01700     Retuns:     Description of the object 
01701     Purpose:    To return a description of the Node object in either the singular or the 
01702                 plural. This method is called by the DescribeRange method.
01703                 
01704                 The description will always begin with a lower case letter.   
01705                 
01706     Errors:     A resource exception will be thrown if a problem occurs when loading the 
01707                 string resource. 
01708     SeeAlso:    -
01709 
01710 ********************************************************************************************/
01711 /*
01712     Technical Notes:
01713     
01714     The String resource identifiers should be of the form: ID_<Class>_DescriptionS for the 
01715     singular description and ID_<Class>_DescriptionP for the plural. 
01716 */              
01717               
01718 String NodeGridIso::Describe(BOOL Plural, BOOL Verbose) 
01719 {   
01720     if (Plural)
01721         return (String(_R(IDS_GRIDISO_DESCRP)));
01722     else
01723         return (String(_R(IDS_GRIDISO_DESCRS)));
01724 }; 
01725  
01726 
01727 /***********************************************************************************************
01728 
01729 >   void NodeGridIso::Render(RenderRegion* pRender)
01730 
01731     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01732     Created:    15/2/94
01733     Inputs:     pRender = a render region
01734     Outputs:    -
01735     Returns:    - 
01736     Purpose:    Renders the isometric grid item
01737                 
01738     Errors:     -
01739     SeeAlso:    -
01740 
01741 ***********************************************************************************************/
01742 
01743 void NodeGridIso::Render( RenderRegion* pRender )
01744 {      
01745 #if !defined(EXCLUDE_FROM_RALPH)
01746     if (IsDisabled()) return;
01747 
01748     View* pView = pRender->GetRenderView();
01749     if ((pView == NULL) || (!IS_A(pView, DocView)))
01750         // No docview to render to.
01751         return;
01752 
01753     DocView *pDocView = (DocView *) pView;
01754 
01755     if (!pDocView->GetShowGridState() && Tool::GetCurrentID() != TOOLID_GRID) return;
01756 
01757     // Set up attributes for drawing grid points
01758     pRender->SaveContext();
01759 // Don't setup for line rendering because grid points now rendered as filled rects...
01760 //  pRender->SetLineWidth(0);                               // Means single-pixel lines
01761 //  pRender->SetLineColour(GridColour);                     // Grid blobs are in this colour
01762 
01763     // Setup for rendering grid point rects...
01764     pRender->SetLineWidth(0);
01765     pRender->SetLineColour(COLOUR_TRANS); 
01766     pRender->SetFillColour(GridColour);
01767         
01768     DocRect ClipRect = pRender->GetClipRect();              // Get the current clip rect
01769     DocRect RendRect;
01770 
01771     RendRect.lo.x = max(GridBoundingRect.lo.x,ClipRect.lo.x);   // hi and lo renderable grid points
01772     RendRect.lo.y = max(GridBoundingRect.lo.y,ClipRect.lo.y);   // derived from the clip rect and the 
01773     RendRect.hi.x = min(GridBoundingRect.hi.x,ClipRect.hi.x);   // node's bounding rect
01774     RendRect.hi.y = min(GridBoundingRect.hi.y,ClipRect.hi.y);
01775 
01776     if (RendRect.IsValid())
01777     {
01778         MILLIPOINT PixelWidth = pRender->GetScaledPixelWidth(); // the width of a single pixel 
01779 
01780         RenderPoints(pRender,RendRect,PixelWidth);          // Render the grid points (crosshairs and sub grid dots)
01781     }
01782 
01783     pRender->RestoreContext();
01784 #endif
01785 }  
01786 
01787 /***********************************************************************************************
01788 
01789 > void NodeGridIso::RenderPoints(RenderRegion* pRender,DocRect RendRect,MILLIPOINT PixelWidth)
01790 
01791     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01792     Created:    15/2/94
01793     
01794     Inputs:     pRender     = region to render to
01795                 RendRect    = Rectangle defining the renderable portion of the grid
01796                 PixelWidth  = width of a pixel in millipoints
01797     Outputs:    
01798     Returns:
01799     Purpose:    Renders the grid points within the given renderable rectangle
01800     Errors:     
01801     Scope:      private
01802 
01803 ***********************************************************************************************/
01804 
01805 void NodeGridIso::RenderPoints(RenderRegion* pRender,DocRect RendRect,MILLIPOINT PixelWidth)
01806 {
01807 #if !defined(EXCLUDE_FROM_RALPH)
01808     TRACEUSER( "MarkN", _T("\n------------------\nNodeGridIso::RenderPoints\n\n"));
01809 
01810     // Set the fp render step value to be the underlying main grid step value
01811     double fp_MainRenderStep = MainStep;
01812 
01813     // Calculate the step for rendering the grid in relation to the width of a pixel and the
01814     // multiples of the dominant unit
01815     CalcGridRenderSteps(PixelWidth,&fp_MainRenderStep,fp_MainRenderStep*::GetUnitMultiple(Units),Units);
01816 
01817     // Snap the render rect to these adjusted steps so we render all points within the renderable
01818     // portion of the grid
01819 
01820     Snap(&RendRect.lo,fp_MainRenderStep);
01821     Snap(&RendRect.hi,fp_MainRenderStep);
01822     BOOL YOffAdjust = FALSE; // YOffAdjust = FALSE because we have snapped exactly to the main grid
01823     
01824     if (RendRect.lo.x > RendRect.hi.x) Swap(RendRect.lo.x,RendRect.hi.x);
01825     if (RendRect.lo.y > RendRect.hi.y) Swap(RendRect.lo.y,RendRect.hi.y);
01826 
01827     ENSURE(RendRect.IsValid(),"RendRect is invalid in NodeGridIso::RenderPoints");
01828 
01829     // Set the fp sub render step value to be the underlying sub grid step value
01830     double fp_SubRenderStep = SubStep;
01831     CalcGridRenderSteps(PixelWidth,&fp_SubRenderStep,fp_MainRenderStep,Units);
01832     if (fp_SubRenderStep >= fp_MainRenderStep)  fp_SubRenderStep = 0;
01833 
01834     // Get fixed point versions of the fp values for speedy grid rendering
01835     MILLIPOINT MainRenderStep = (MILLIPOINT)((fp_MainRenderStep * GRID_REND_FACTOR)+0.5);
01836     MILLIPOINT SubRenderStep  = (MILLIPOINT)((fp_SubRenderStep  * GRID_REND_FACTOR)+0.5);
01837 
01838     // Convert RendRect to fixed point values
01839     RendRect.lo.x *= GRID_REND_FACTOR;
01840     RendRect.lo.y *= GRID_REND_FACTOR;
01841     RendRect.hi.x *= GRID_REND_FACTOR;
01842     RendRect.hi.y *= GRID_REND_FACTOR;
01843 
01844     DocRect ScaledBB = GridBoundingRect;
01845     ScaledBB.lo.x *= GRID_REND_FACTOR;
01846     ScaledBB.lo.y *= GRID_REND_FACTOR;
01847     ScaledBB.hi.x *= GRID_REND_FACTOR;
01848     ScaledBB.hi.y *= GRID_REND_FACTOR;
01849 
01850     RendRect.Inflate(MainRenderStep); YOffAdjust = !YOffAdjust;
01851 
01852     // Make sure the render rectangle region doesn't lie outside the bounding rect
01853     while (RendRect.lo.x <  ScaledBB.lo.x) { RendRect.lo.x += MainRenderStep; YOffAdjust = !YOffAdjust; }
01854     while (RendRect.lo.y <  ScaledBB.lo.y)   RendRect.lo.y += MainRenderStep;
01855     while (RendRect.hi.x >  ScaledBB.hi.x)   RendRect.hi.x -= MainRenderStep;
01856     while (RendRect.hi.y >  ScaledBB.hi.y)   RendRect.hi.y -= MainRenderStep;
01857 
01858     RendRect.lo.x -= MainRenderStep;  YOffAdjust = !YOffAdjust;     // Need to plot to left of BB for sub grid dots
01859     RendRect.lo.y -= MainRenderStep;                            // Need to plot underneath BB for sub grid dots
01860 
01861     RendRect.hi.x += GRID_REND_FACTOR; // compensate for errors (i.e. add the bodge factor)
01862     RendRect.hi.y += GRID_REND_FACTOR; // compensate for errors
01863 
01864     RendRect.hi.y += MainRenderStep;
01865 
01866     // Render those grid points boy!
01867 
01868     DocCoord    GridPoint,TrueGridPoint;
01869     MILLIPOINT  yoff;
01870 
01871     const MILLIPOINT Pix = pRender->GetScaledPixelWidth();
01872 //  const MILLIPOINT PixBy2 = Pix/2;
01873     const MILLIPOINT Length = PIX_CROSSHAIR_SIZE * Pix;
01874 
01875     for (GridPoint.x=RendRect.lo.x;GridPoint.x<=RendRect.hi.x;GridPoint.x+=MainRenderStep)
01876     {
01877         if (YOffAdjust) yoff = MainRenderStep/2; else yoff = 0;
01878 
01879         RendRect.lo.y += yoff;
01880         RendRect.hi.y += yoff;
01881 
01882         for (GridPoint.y=RendRect.lo.y;GridPoint.y<=RendRect.hi.y;GridPoint.y+=MainRenderStep)
01883         {
01884             if (ScaledBB.ContainsCoord(GridPoint))
01885             {
01886                 // Scale the fixed point grid coord down to get the true coord of the grid point
01887                 TrueGridPoint.x = (GridPoint.x+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01888                 TrueGridPoint.y = (GridPoint.y+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01889 
01890 //              pRender->DrawCross(TrueGridPoint,PIX_CROSSHAIR_SIZE);
01891                 // Phil says: Don't use DrawPixel because it can't be trusted to plot the
01892                 // same pixel under GDI as it does under GDraw!
01893                 // Instead draw two rectangles centered around the required coord.
01894                 DocRect Horz(TrueGridPoint.x-Length, TrueGridPoint.y,TrueGridPoint.x+Length+Pix,TrueGridPoint.y+Pix);
01895                 pRender->DrawRect(&Horz);
01896 
01897                 DocRect Vert(TrueGridPoint.x, TrueGridPoint.y-Length,TrueGridPoint.x+Pix,TrueGridPoint.y+Length+Pix);
01898                 pRender->DrawRect(&Vert);
01899             }
01900 
01901             if (SubRenderStep != 0) 
01902                 RenderSubPoints(pRender,GridPoint,MainRenderStep,SubRenderStep,PixelWidth,ScaledBB);
01903         }
01904 
01905         RendRect.lo.y -= yoff;
01906         RendRect.hi.y -= yoff;
01907 
01908         YOffAdjust = !YOffAdjust;
01909     }
01910 #endif
01911 }
01912 
01913 
01914 /***********************************************************************************************
01915 
01916 > void NodeGridIso::RenderSubPoints(RenderRegion* pRender,
01917                                     const DocCoord& MainGridPoint,
01918                                     MILLIPOINT MainRenderStep,
01919                                     MILLIPOINT SubRenderStep,
01920                                     MILLIPOINT PixelWidth,
01921                                     DocRect&   ScaledBB)
01922 
01923     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01924     Created:    15/2/94
01925     
01926     Inputs:     pRender         = region to render to
01927                 MainGridPoint   = coord of a main grid cross hair point   (Scaled up by GRID_REND_FACTOR)
01928                 MainRenderStep  = step for rendering the main grid points (Scaled up by GRID_REND_FACTOR)
01929                 SubRenderStep   = step for rendering the sub grid points  (Scaled up by GRID_REND_FACTOR)
01930                 PixelWidth      = width of a single pixel
01931                 ScaledBB        = The bounding rect of grid scaled up by GRID_REND_FACTOR
01932     Outputs:    
01933     Returns:
01934     Purpose:    Renders the sub grid points from the given main point
01935     Errors:     
01936     Scope:      private
01937 
01938 ***********************************************************************************************/
01939 
01940 void NodeGridIso::RenderSubPoints(  RenderRegion* pRender,
01941                                     const DocCoord& MainGridPoint,
01942                                     MILLIPOINT MainRenderStep,
01943                                     MILLIPOINT SubRenderStep,
01944                                     MILLIPOINT /*PixelWidth*/,
01945                                     DocRect&   ScaledBB)
01946 {
01947 #if !defined(EXCLUDE_FROM_RALPH)
01948     DocCoord SubGridPoint,TrueSubGridPoint;
01949     MILLIPOINT maxx,maxy;
01950 
01951     // Render the vertical sub grid dots from this point to the one above
01952     SubGridPoint.x = MainGridPoint.x;
01953     SubGridPoint.y = MainGridPoint.y+SubRenderStep;
01954     maxy = MainGridPoint.y+MainRenderStep;
01955 
01956     const MILLIPOINT Pix = pRender->GetScaledPixelWidth();
01957 //  const MILLIPOINT PixBy2 = Pix/2;
01958 
01959     while (SubGridPoint.y < maxy)
01960     {
01961         if (ScaledBB.ContainsCoord(SubGridPoint))
01962         {
01963             // Scale the fixed point grid coord down to get the true coord of the grid point
01964             TrueSubGridPoint.x = (SubGridPoint.x+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01965             TrueSubGridPoint.y = (SubGridPoint.y+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01966 //          pRender->DrawPixel(TrueSubGridPoint);
01967             // Phil says: Don't use DrawPixel because it can't be trusted to plot the
01968             // same pixel under GDI as it does under GDraw!
01969             // Instead draw a rectangle 1*1 pixels around the required coord.
01970             DocRect Pixel(  TrueSubGridPoint.x,
01971                             TrueSubGridPoint.y,
01972                             TrueSubGridPoint.x+Pix,
01973                             TrueSubGridPoint.y+Pix);
01974             pRender->DrawRect(&Pixel);
01975         }
01976         SubGridPoint.y += SubRenderStep;
01977     }
01978 
01979     // Render the diagonal dots from this point to the one to the right and up
01980     SubGridPoint.x = MainGridPoint.x+SubRenderStep;
01981     SubGridPoint.y = MainGridPoint.y+(SubRenderStep/2);
01982     maxx = MainGridPoint.x+MainRenderStep;
01983 
01984     while (SubGridPoint.x < maxx)
01985     {
01986         if (ScaledBB.ContainsCoord(SubGridPoint))
01987         {
01988             // Scale the fixed point grid coord down to get the true coord of the grid point
01989             TrueSubGridPoint.x = (SubGridPoint.x+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01990             TrueSubGridPoint.y = (SubGridPoint.y+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
01991 
01992 //          pRender->DrawPixel(TrueSubGridPoint);
01993             // Phil says: Don't use DrawPixel because it can't be trusted to plot the
01994             // same pixel under GDI as it does under GDraw!
01995             // Instead draw a rectangle 1*1 pixels around the required coord.
01996             DocRect Pixel(  TrueSubGridPoint.x,
01997                             TrueSubGridPoint.y,
01998                             TrueSubGridPoint.x+Pix,
01999                             TrueSubGridPoint.y+Pix);
02000             pRender->DrawRect(&Pixel);
02001         }
02002         SubGridPoint.x += SubRenderStep;
02003         SubGridPoint.y += SubRenderStep/2;
02004     }
02005 
02006     // Render the diagonal dots from this point to the one to the right and down
02007     SubGridPoint.x = MainGridPoint.x+SubRenderStep;
02008     SubGridPoint.y = MainGridPoint.y-(SubRenderStep/2);
02009     maxx = MainGridPoint.x+MainRenderStep;
02010 
02011     while (SubGridPoint.x < maxx)
02012     {
02013         if (ScaledBB.ContainsCoord(SubGridPoint))
02014         {
02015             // Scale the fixed point grid coord down to get the true coord of the grid point
02016             TrueSubGridPoint.x = (SubGridPoint.x+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
02017             TrueSubGridPoint.y = (SubGridPoint.y+(GRID_REND_FACTOR/2)) / GRID_REND_FACTOR;
02018 
02019 //          pRender->DrawPixel(TrueSubGridPoint);
02020             // Phil says: Don't use DrawPixel because it can't be trusted to plot the
02021             // same pixel under GDI as it does under GDraw!
02022             // Instead draw a rectangle 1*1 pixels around the required coord.
02023             DocRect Pixel(  TrueSubGridPoint.x,
02024                             TrueSubGridPoint.y,
02025                             TrueSubGridPoint.x+Pix,
02026                             TrueSubGridPoint.y+Pix);
02027             pRender->DrawRect(&Pixel);
02028         }
02029         SubGridPoint.x += SubRenderStep;
02030         SubGridPoint.y -= SubRenderStep/2;
02031     }
02032 #endif
02033 }
02034 
02035 
02036 /***********************************************************************************************
02037 
02038 > BOOL NodeGridIso::Snap(DocCoord* pDocCoord)
02039 
02040     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02041     Created:    15/2/94
02042     Inputs:     pDocCoord   = a coord in Spread coords
02043     Outputs:    
02044     Returns:    TRUE    - the DocCoord has been snapped to the grid.
02045                 FALSE   - the DocCoord has not been processed.
02046                                                          
02047     Purpose:    Snaps to given coord to the nearest grid point.  If it is not appropriate to snap
02048                 the coord to the grid (at the moment this means the coord lies outside the grid object's
02049                 bounding box), then FALSE is returned.
02050     Errors:        
02051     Scope:      public
02052            
02053 **********************************************************************************************/
02054 
02055 BOOL NodeGridIso::Snap(DocCoord* pDocCoord)
02056 {
02057     if (IsDisabled()) return FALSE;
02058 
02059     ENSURE(MainStep!=0,"MainStep==0 in NodeGridIso::Snap");
02060     ENSURE(SubStep !=0,"SubStep ==0 in NodeGridIso::Snap");
02061 
02062     if (!GridBoundingRect.ContainsCoord(DocCoord(pDocCoord->x,pDocCoord->y)))
02063         return (FALSE);
02064 
02065     MILLIPOINT x = SnapOrdinate(pDocCoord->x,SubStep,XOrigin);
02066     MILLIPOINT y = SnapOrdinate(pDocCoord->y,SubStep,CalcYOrigin(pDocCoord->x,SubStep));
02067 
02068     if (!GridBoundingRect.ContainsCoord(DocCoord(x,y)))
02069         return (FALSE);
02070 
02071     pDocCoord->x = x;
02072     pDocCoord->y = y;
02073 
02074     return (TRUE);
02075 }
02076 
02077 /***********************************************************************************************
02078 
02079 > BOOL NodeGridIso::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
02080 
02081     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02082     Created:    15/2/94
02083     Inputs:     pDocCoord   - the rectangle to snap
02084                 StartDrag   - Start coord of drag
02085                 EndDrag     - End coord of drag
02086     Outputs:    
02087     Returns:    TRUE    - the DocRect been snapped to the grid.
02088                 FALSE   - the DocRect has not been processed.
02089 
02090     Purpose:    Snaps the given rect to the nearest position on the grid, preserving its width
02091                 and height.
02092                 The coords of the rect used for the snapping are determined by the PrevCoord and
02093                 CurCoord coords supplied.  This is done to allow the user to control how a
02094                 selection rectangle is snapped to the grid by the direction of his/her last mouse 
02095                 movement.
02096                 To force the bottom left hand corner of the rect to be snapped, 
02097                 supply PrevCoord=(0,0) and CurCoord(-1,-1).
02098     Scope:      public
02099            
02100 **********************************************************************************************/
02101 
02102 BOOL NodeGridIso::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
02103 {
02104     if (IsDisabled()) return FALSE;
02105 
02106     ENSURE(MainStep!=0,"MainStep==0 in NodeGridIso::Snap");
02107     ENSURE(SubStep !=0,"SubStep ==0 in NodeGridIso::Snap");
02108     
02109     INT32 xdir = CurCoord.x - PrevCoord.x;
02110     INT32 ydir = CurCoord.y - PrevCoord.y;
02111     INT32 x,y,prevx, prevy;
02112     
02113     if (LastXDir == 0)  LastXDir = xdir;
02114     if (xdir == 0)      xdir = LastXDir;
02115     LastXDir = xdir;
02116 
02117     if (xdir <= 0) x = pDocRect->lo.x; else x = pDocRect->hi.x;
02118 
02119     if (LastYDir == 0)  LastYDir = ydir;
02120     if (ydir == 0)      ydir = LastYDir;
02121     LastYDir = ydir;
02122 
02123     if (ydir <= 0) y = pDocRect->lo.y; else y = pDocRect->hi.y;
02124 
02125     if (!GridBoundingRect.ContainsCoord(DocCoord(x,y)))
02126         return (FALSE);
02127 
02128     prevx   = x;
02129     prevy   = y;
02130     x       = SnapOrdinate(x,SubStep,XOrigin);
02131     y       = SnapOrdinate(y,SubStep,CalcYOrigin(x,SubStep));
02132 
02133     if (!GridBoundingRect.ContainsCoord(DocCoord(x,y)))
02134         return (FALSE);
02135 
02136     pDocRect->Translate(x-prevx,y-prevy);
02137 
02138     return (TRUE);
02139 }
02140 
02141 /***********************************************************************************************
02142 
02143 > BOOL NodeGridIso::Snap(DocCoord* pDocCoord,MILLIPOINT Step)
02144 
02145     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02146     Created:    9/2/94
02147     Inputs:     pDocCoord   - the coord to snap
02148                 XStep       - the step to use when snapping the point
02149     Outputs:    
02150     Returns:    TRUE    - the DocCoord has been snapped to the grid.
02151                 FALSE   - the DocCoord has not been processed.
02152                                                          
02153     Purpose:    Same as Snap(pDocCoord), except the coord is snapped to grid points at the given intervals
02154     Errors:        
02155     Scope:      public
02156            
02157 **********************************************************************************************/
02158 
02159 BOOL NodeGridIso::Snap(DocCoord* pDocCoord,double Step)
02160 {
02161     if (IsDisabled()) return FALSE;
02162 
02163     ENSURE(Step!=0,"Step==0 in NodeGridIso::Snap");
02164 
02165     pDocCoord->x = SnapOrdinate(pDocCoord->x,Step,XOrigin);
02166     pDocCoord->y = SnapOrdinate(pDocCoord->y,Step,CalcYOrigin(pDocCoord->x,Step));
02167 
02168     return (TRUE);
02169 }
02170 
02171 
02172 /***********************************************************************************************
02173 
02174 > MILLIPOINT NodeGridIso::CalcYOrigin(MILLIPOINT x,double Step)
02175 
02176     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02177     Created:    16/2/94
02178     Inputs:     x    = Snapped x coord
02179                 Step = step rate of underlying grid
02180     Outputs:    
02181     Returns:    The Y origin that should be used to snap Y coords to the grid
02182     Purpose:    The Y origin used for snapping Y coords alternates between YOrigin and YOrigin+(Step/2)
02183                 depending on a point's snapped x coord. This function returns the correct one to use.
02184     Errors:
02185     Scope:      private
02186 
02187 **********************************************************************************************/
02188 
02189 MILLIPOINT NodeGridIso::CalcYOrigin(MILLIPOINT x,double Step)
02190 {
02191     double xdist = mod((double)(x-XOrigin),Step*2); 
02192     if (xdist<0) xdist = 0-xdist;
02193 
02194     if ((xdist > (Step/2)) && (xdist < ((Step*2)-(Step/2))) )
02195         return YOrigin+((MILLIPOINT)((Step/2)+0.5));
02196     else
02197         return YOrigin;
02198 
02199 
02200 /*
02201     MILLIPOINT xdist =  abs((x-XOrigin) % (Step*2));
02202 
02203     if ((xdist > (Step/2)) && (xdist < ((Step*2)-(Step/2))) )
02204         return YOrigin+(Step/2);
02205     else
02206         return YOrigin;
02207 */
02208 }
02209 
02210 /***********************************************************************************************
02211 
02212 > Node* NodeGridIso::SimpleCopy() // Private method  
02213 
02214     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02215     Created:    15/2/94
02216     
02217     Inputs:         - 
02218     Outputs:    
02219     Returns:    A copy of the node, or NULL if memory runs out
02220          
02221     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
02222                 The function is virtual, and must be defined for all derived classes.  
02223            
02224     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
02225                 error and the function returns NULL. 
02226  
02227         
02228     Scope:      public
02229 **********************************************************************************************/
02230 
02231 Node* NodeGridIso::SimpleCopy()
02232 {
02233     NodeGridIso* NodeCopy = new NodeGridIso();   
02234     if (NodeCopy != NULL)
02235         CopyNodeContents(NodeCopy);   
02236     return (NodeCopy);
02237 }          
02238 
02239 /***********************************************************************************************
02240 >   void NodeGridIso::CopyNodeContents(NodeGridIso* NodeCopy)
02241 
02242     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02243     Created:    15/2/94
02244     
02245     Inputs:     - 
02246     Outputs:    A copy of this node
02247  
02248     Returns:    -
02249          
02250     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
02251               
02252     Errors:     An assertion failure will occur if NodeCopy is NULL
02253     
02254     Scope:      protected
02255                                      
02256 ***********************************************************************************************/
02257 
02258 
02259 void NodeGridIso::CopyNodeContents(NodeGridIso* NodeCopy)
02260 {
02261     ENSURE(NodeCopy != NULL,"Trying to copy a NodeGridIso's contents to a NULL node");  
02262     NodeGrid::CopyNodeContents(NodeCopy); 
02263 
02264     NodeCopy->MainStep      = this->MainStep;
02265     NodeCopy->SubStep       = this->SubStep;    
02266 
02267     NodeCopy->Units         = this->Units;
02268     NodeCopy->Divisions     = this->Divisions;
02269     NodeCopy->Subdivisions  = this->Subdivisions;
02270 }
02271 
02272 
02273 /***********************************************************************************************
02274 >   void NodeGridIso::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
02275 
02276     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02277     Created:    18/12/2003
02278     Outputs:    -
02279     Purpose:    Polymorphically copies the contents of this node to another
02280     Errors:     An assertion failure will occur if NodeCopy is NULL
02281     Scope:      protected
02282                                      
02283 ***********************************************************************************************/
02284 
02285 void NodeGridIso::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
02286 {
02287     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
02288     ENSURE(IS_A(pNodeCopy, NodeGridIso), "PolyCopyNodeContents given wrong dest node type");
02289 
02290     if (IS_A(pNodeCopy, NodeGridIso))
02291         CopyNodeContents((NodeGridIso*)pNodeCopy);
02292 }
02293 
02294 
02295 
02296 /********************************************************************************************
02297 
02298 >   void* NodeGridIso::GetDebugDetails(StringBase* Str) 
02299 
02300     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02301     Created:    15/2/94
02302     Inputs:     -
02303     Outputs:    Str: String giving debug info about the node
02304     Returns:    -
02305     Purpose:    For obtaining debug information about the Node
02306     Errors:     -
02307     SeeAlso:    -
02308 
02309 ********************************************************************************************/
02310 
02311      
02312 void NodeGridIso::GetDebugDetails(StringBase* Str) 
02313 {          
02314     NodeGrid::GetDebugDetails(Str); 
02315 }
02316  
02317           
02318 //--------------------------------------------------------------------------------------------
02319                                        
02320 #ifdef _DEBUG
02321  
02322 void NodeGridIso::ShowDebugTreeDetails() const
02323 {                                 
02324     TRACE( _T("NodeGridIso::ShowDebugTreeDetails() ")); 
02325     Node::ShowDebugTreeDetails(); 
02326 }  
02327 
02328 #endif
02329  
02330 //--------------------------------------------------------------------------------------------
02331 
02332 /********************************************************************************************
02333 >   BOOL NodeGridIso::SetGridParams(double Div,UINT32 Subdiv,UnitType NewUnits, BOOL Scale=TRUE)
02334 
02335     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02336     Created:    16/10/95
02337     Inputs:     Div      - Number of Units between each main step of the grid
02338                 Subdiv   - Number of subdivisions between each main grid point
02339                 NewUnits - The units the grid is defined in
02340                 Scale    - account for unit scaling (only FALSE when loading for compatibility with old docs)
02341     Returns:    FALSE if fails
02342     Purpose:    Defines the grid.
02343 ********************************************************************************************/
02344 
02345 BOOL NodeGridIso::SetGridParams(double Div,UINT32 Subdiv,UnitType NewUnits, BOOL Scale)
02346 {
02347     if (Div < 0)
02348     {
02349         ERROR3("NodeGridIso::SetGridParams() - Div < 0!");
02350         Div = 0.0;
02351     }
02352     if (Subdiv < 1)
02353     {
02354         ERROR3("NodeGridIso::SetGridParams() - SubDiv < 1!");
02355         Subdiv = 1;
02356     }
02357 
02358     DimScale* pDimScale = DimScale::GetPtrDimScale(this);
02359     ERROR2IF(pDimScale==NULL,FALSE,"NodeGridRect::SetGridParams() - pDimScale==NULL");
02360 
02361     // set the raw values in the grid - but only set units if scaling turned off
02362     // (except if scaling is not to be accounted for  - ie during loading for compatibility with old docs - yuk!)
02363     Divisions    = Div;
02364     Subdivisions = Subdiv;
02365     if (Scale==FALSE || pDimScale->GetScaleUnits()==NOTYPE)
02366         Units = NewUnits;
02367 
02368     // convert the divisions and units into a millipoint grid spacing (accounting for unit scaling) - yuk!
02369     double GridSpacing=0;
02370     if (Scale)
02371     {
02372         BOOL ok = pDimScale->ComponentsToMillipoint(&GridSpacing, Divisions, GetUnits());
02373         if (!ok) return FALSE;
02374     }
02375     else
02376     {
02377         DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
02378         ERROR2IF(pDocUnitList==NULL,FALSE,"DimScale::ComponentsToMillipoint() - pDocUnitList==NULL");
02379         Unit* pUnit = pDocUnitList->FindUnit(Units);
02380         ERROR2IF(pUnit==NULL,FALSE,"DimScale::ComponentsToMillipoint() - pUnit==NULL");
02381         GridSpacing = Div * pUnit->GetMillipoints();
02382     }
02383 
02384     if (GridSpacing<1)
02385     {
02386         ERROR3("NodeGridIso::SetGridParams() - GridSpacing < 1!");
02387         GridSpacing=1;
02388     }
02389 
02390     MainStep = GridSpacing;
02391     SubStep  = MainStep/Subdivisions;
02392     if (SubStep<1)
02393     {
02394         ERROR3("NodeGridIso::SetGridParams() - SubXStep < 1!");
02395         SubStep=1;
02396     }
02397 
02398     return TRUE;
02399 }
02400 
02401 
02402 /********************************************************************************************
02403 >   double NodeGridIso::GetDivisions(BOOL Scale=TRUE)
02404 
02405     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02406     Created:    17/10/95
02407     Inputs:     Scale - account for scaling (only FALSE when saving for doc compatibility)
02408     Returns:    Number of Units between each main grid point
02409     Purpose:    Used to get the number of Units between each main grid point.
02410 ********************************************************************************************/
02411 
02412 double NodeGridIso::GetDivisions(BOOL Scale)
02413 {
02414     return NodeGrid::CalcDivisions(Scale);
02415 }
02416 
02417 
02418 /********************************************************************************************
02419 
02420 >   UINT32 NodeGridIso::GetSubdivisions()
02421 
02422     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02423     Created:    1/3/94
02424     Inputs:     -
02425     Outputs:    -
02426     Returns:    Num subdivisions
02427     Purpose:    Used to get the number of subdivisions between each main grid point.
02428     Errors:     -
02429     SeeAlso:    -
02430 
02431 ********************************************************************************************/
02432 
02433 UINT32 NodeGridIso::GetSubdivisions()
02434 {
02435     return Subdivisions;
02436 }
02437 
02438 /********************************************************************************************
02439 >   UnitType NodeGridIso::GetUnits(BOOL Scale=TRUE)
02440 
02441     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02442     Created:    20/10/95
02443     Inputs:     Scale - account for unit scaling (only FALSE when saving for compatibility with old docs)
02444     Returns:    Units used by the grid
02445     Purpose:    Gets the units used by the grid
02446 ********************************************************************************************/
02447 
02448 UnitType NodeGridIso::GetUnits(BOOL Scale)
02449 {
02450     DimScale* pDimScale = DimScale::GetPtrDimScale(this);
02451     ERROR2IF(pDimScale==NULL,NOTYPE,"NodeGridIso::GetUnits() - pDimScale==NULL");
02452 
02453     // if scaling turned on return scale units
02454     // (except if scaling is not to be accounted for  - ie during saving for compatibility with old docs)
02455     UnitType ScaleUnits = pDimScale->GetScaleUnits();
02456     if (Scale && ScaleUnits!=NOTYPE)
02457         return ScaleUnits;
02458 
02459     return Units;
02460 }
02461 
02462 
02463 //---------------------------------------------
02464 //---------------------------------------------
02465 
02466 /********************************************************************************************
02467 
02468 >   static void NodeGrid::ProcessAllGrids(ProcessGrid* pProcessGrid)
02469 
02470     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02471     Created:    18/7/94
02472     Inputs:     pProcessGrid = ptr to the object that will process each grid in the current doc
02473     Returns:    -
02474     Purpose:    Processes all the grids in the current doc using the grid processing object
02475                 provided as a parameter
02476     SeeAlso:    -
02477 
02478 ********************************************************************************************/
02479 
02480 void NodeGrid::ProcessAllGrids(ProcessGrid* pProcessGrid)
02481 {
02482     ERROR3IF(Document::GetSelected() == NULL,"What, no doc? Surely some mistake!");
02483 
02484     pProcessGrid->pDoc = Document::GetSelected();
02485     if (pProcessGrid->pDoc == NULL) return;
02486 
02487     // Now we need to scan all spreads throughout the current doc
02488 
02489     pProcessGrid->pChapter = Node::FindFirstChapter(pProcessGrid->pDoc);
02490     while (pProcessGrid->pChapter != NULL)
02491     {
02492         // For each chapter in the doc...
02493         Node* pNode = pProcessGrid->pChapter->FindFirstChild();
02494         while (pNode != NULL)
02495         {
02496             // If the child node of the chapter is a spread...
02497             if (pNode->IsKindOf(CC_RUNTIME_CLASS(Spread)))
02498                 ProcessGridsInSpread(pProcessGrid,(Spread*)pNode);
02499     
02500             pNode = pNode->FindNext();
02501         }
02502         pProcessGrid->pChapter = pProcessGrid->pChapter->FindNextChapter();
02503     }
02504 }    
02505 
02506 
02507 /********************************************************************************************
02508 
02509 >   static void NodeGrid::ProcessGridsInSpread(ProcessGrid* pProcessGrid,Spread* pSpread)
02510 
02511     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02512     Created:    18/7/94
02513     Inputs:     pProcessGrid = ptr to the object that will process each grid in the current doc
02514                 pSpread      = spread containing grids to be processed
02515     Returns:    -
02516     Purpose:    Processes all grids in this spread using the given grid processor param
02517     SeeAlso:    -
02518 
02519 ********************************************************************************************/
02520 
02521 void NodeGrid::ProcessGridsInSpread(ProcessGrid* pProcessGrid,Spread* pSpread)
02522 {
02523     pProcessGrid->pSpread = pSpread;
02524 
02525     // scan the children of the spread for grids
02526     Node* pNode = pSpread->FindFirstChild();
02527     while (pNode != NULL)
02528     {
02529         if (pNode->IsKindOf(CC_RUNTIME_CLASS(NodeGrid)))
02530             // we now have a ptr to a grid, so process it
02531             pProcessGrid->Process((NodeGrid*)pNode);
02532 
02533         pNode = pNode->FindNext();
02534     }
02535 }
02536 
02537 //-------
02538 //-------
02539 //-------
02540 
02541 /********************************************************************************************
02542 
02543 >   void ProcessGridForceRedraw::Process(NodeGrid* pGrid)
02544 
02545     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02546     Created:    18/7/94
02547     Inputs:     pGrid = the grid to force a redraw on
02548     Returns:    -
02549     Purpose:    Forces a redraw on the given grid
02550     SeeAlso:    -
02551 
02552 ********************************************************************************************/
02553 
02554 void ProcessGridForceRedraw::Process(NodeGrid* pGrid)
02555 {
02556     if (!pGrid->IsDisabled())
02557     {
02558         // Get ptr to selected doc view
02559         DocView* pDocView = DocView::GetSelected();
02560 
02561         // If there's a selected docview, redraw!
02562         if (pDocView != NULL)
02563             pDocView->ForceRedraw(pSpread,pGrid->GetBlobBoundingRect());
02564     }
02565 }
02566 
02567 //--------
02568 //--------
02569 //--------
02570 
02571 /********************************************************************************************
02572 
02573 >   ProcessGridUnitMsg::ProcessGridUnitMsg(UnitMsg* pThisUnitMsg)
02574 
02575     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02576     Created:    18/7/94
02577     Inputs:     pUnitMsg = ptr to the unit msg
02578     Returns:    -
02579     Purpose:    THE constructor for this class
02580                 This assigns pThisUnitMsg to the member var pUnitMsg ready for its
02581                 Process method to be called vai NodeGrid::ProcessAllGrids()
02582     SeeAlso:    -
02583 
02584 ********************************************************************************************/
02585 
02586 ProcessGridUnitMsg::ProcessGridUnitMsg(UnitMsg* pThisUnitMsg)
02587 {
02588     pUnitMsg = pThisUnitMsg;
02589 }
02590 
02591 /********************************************************************************************
02592 
02593 >   void ProcessGridUnitMsg::Process(NodeGrid* pGrid)
02594 
02595     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02596     Created:    18/7/94
02597     Inputs:     pGrid = the grid to process
02598     Returns:    -
02599     Purpose:    Checks to see if the grid is using the unit specified in the UnitMsg
02600                 member var, and if so changes it if the unit is about to be deleted
02601     SeeAlso:    -
02602 
02603 ********************************************************************************************/
02604 
02605 void ProcessGridUnitMsg::Process(NodeGrid* pGrid)
02606 {
02607     switch (pUnitMsg->MsgType)
02608     {
02609         case (UnitMsg::BEFOREDELETE) :
02610         {
02611             UnitType OldUnitType = pUnitMsg->ThisUnitType;
02612 
02613             if (pGrid->GetUnits() == OldUnitType)
02614             {
02615                 double   Div         = pGrid->GetDivisions();
02616                 UINT32   SubDiv      = pGrid->GetSubdivisions();
02617                 Unit*    pThisUnit   = pUnitMsg->pDocUnitList->FindUnit(OldUnitType);
02618                 UnitType NewUnitType = pThisUnit->GetBaseUnitType();
02619 
02620                 ENSURE(NewUnitType != NOTYPE,"Er, deleting a unit that has no base type");
02621 
02622                 Div = Convert::ConvertToNewUnits(Div,OldUnitType,NewUnitType);
02623             
02624                 pGrid->SetGridParams(Div,SubDiv,NewUnitType);
02625             }
02626         }
02627         break;
02628 
02629         case (UnitMsg::CHANGED) :
02630         {
02631             UnitType ChangedUnitType = pUnitMsg->ThisUnitType;
02632 
02633             if (pGrid->GetUnits() == ChangedUnitType)
02634             {
02635                 double   Div         = pGrid->GetDivisions();
02636                 UINT32   SubDiv      = pGrid->GetSubdivisions();
02637 
02638                 pGrid->SetGridParams(Div,SubDiv,ChangedUnitType);
02639 
02640                 if (!pGrid->IsDisabled())
02641                 {
02642                     // Get ptr to selected doc view
02643                     DocView* pDocView = DocView::GetSelected();
02644 
02645                     // If there's a selected docview, redraw!
02646                     if (pDocView != NULL)
02647                         pDocView->ForceRedraw(pGrid->FindParentSpread(),pGrid->GetBlobBoundingRect());
02648                 }
02649 
02650                 //GridTool::ForceRedraw(pGrid);
02651             }
02652         }
02653         break;
02654         default: break;
02655     }   
02656 }
02657 
02658 /********************************************************************************************
02659 
02660 >   static void NodeGrid::ForceRedrawAllGrids()
02661 
02662     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02663     Created:    19/10/94
02664     Inputs:     -
02665     Returns:    -
02666     Purpose:    Forces a redraw on all the grids in the current view
02667     SeeAlso:    
02668 
02669 ********************************************************************************************/
02670 
02671 void NodeGrid::ForceRedrawAllGrids()
02672 {
02673     ProcessGridForceRedraw ProcGrid;
02674     NodeGrid::ProcessAllGrids(&ProcGrid);
02675 }    
02676 
02677 /********************************************************************************************
02678 >   static void NodeGrid::MakeDefaultGrid(Spread* pSpread, BOOL Scale=TRUE)
02679 
02680     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02681     Created:    12/5/94
02682     Inputs:     pSpread = spread in which to make the Default grid
02683                 Scale - account for unit scaling (only FALSE when loading for doc compatibility)
02684     Purpose:    Creates a grid covering the whole spread.  The grid is
02685                 defined using the default parameters.
02686 ********************************************************************************************/
02687 
02688 void NodeGrid::MakeDefaultGrid(Spread* pSpread, BOOL Scale)
02689 {
02690     if (pSpread != NULL)
02691     {
02692         NodeGrid* pNewGrid = NULL;              // This will point to the new grid
02693         switch (GetDefaultGridType())           // Create the new grid of the right type
02694         {
02695             case RECTANGULAR    : pNewGrid = new NodeGridRect(); break;
02696             case ISOMETRIC      : pNewGrid = new NodeGridIso(); break;
02697             default: break; // we check it below
02698         }
02699 
02700         if (pNewGrid != NULL)
02701         {
02702             // Build the grid rectangle to completely cover the pasteboard
02703             DocRect Rect = pSpread->GetPasteboardRect(FALSE);
02704             pSpread->DocCoordToSpreadCoord(&Rect);
02705 
02706             pNewGrid->AttachNode(pSpread, LASTCHILD); 
02707 //          pNewGrid->SetInitialBounds(Rect);
02708             pNewGrid->SetBoundingRect(Rect);            // Tell the NodeGrid of the new bounds
02709             pNewGrid->SetDefault(TRUE);
02710             pNewGrid->SetDisabled(GetDefaultGridDisabled());
02711 
02712             // Set the grid (and user coord) origin to the bottom left corner of the 1st page
02713 //          DocRect PageRect;
02714 //          if (pSpread->GetPagesRect(&PageRect))
02715 //              pNewGrid->SetOrigin(PageRect.lo.x, PageRect.lo.y);
02716 
02717             // Set the grid params to the default grid settings
02718             // If the default unit type is NOTYPE, get the page units from the doc unit list
02719             // of the current document
02720             UnitType Units = GetDefaultUnits();
02721             if (Units == NOTYPE)
02722             {
02723                 // Get the node's dic unit list
02724                 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
02725 
02726                 ENSURE(pDocUnitList != NULL,"No doc unit list attached to this doc yet");
02727                 if (pDocUnitList != NULL)
02728                     Units = pDocUnitList->GetPageUnits();       // Set to the page units.
02729             }
02730 
02731             if (Units != NOTYPE)
02732                 pNewGrid->SetGridParams(GetDefaultDivisions(),GetDefaultSubdivisions(),Units,Scale);
02733         }
02734     }
02735 }
02736 
02737 /********************************************************************************************
02738 
02739 >   static void NodeGrid::ResetDocRectSnap()
02740 
02741     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02742     Created:    20/10/94
02743     Inputs:     -
02744     Outputs:    -
02745     Returns:    -
02746     Purpose:    Call this before starting a drag that will use the DocRect version of the snap function
02747     SeeAlso:    -
02748 
02749 ********************************************************************************************/
02750 
02751 void NodeGrid::ResetDocRectSnap()
02752 { 
02753     LastXDir = LastYDir = 0; 
02754 }
02755 
02756 //----------------------------------------------
02757 // Moved these from the class def in grid.h so that they are no longer in-line,
02758 // hence allowing them to be called from DLLs
02759 
02760 UINT32      NodeGrid::GetNumSelectedGrids()             { return NumSelected; }
02761 UINT32      NodeGrid::GetNumNonDefaultSelectedGrids()   { return NumNonDefaultSelected; }
02762 
02763 GridType    NodeGrid::GetTypeForDefaultGrid()   { return TypeForDefaultGrid; }
02764 BOOL        NodeGrid::GetDefaultGridDisabled()  { return DefaultGridDisabled; }
02765 double      NodeGrid::GetDefaultDivisions()     { return DefaultDivisions; }
02766 UINT32      NodeGrid::GetDefaultSubdivisions()  { return DefaultSubdivisions; }
02767 UnitType    NodeGrid::GetDefaultUnits()         { return DefaultUnits; }
02768 GridType    NodeGrid::GetDefaultGridType()      { return DefaultGridType; }
02769 
02770 void        NodeGrid::SetTypeForDefaultGrid(GridType GType)     { TypeForDefaultGrid    = GType; }
02771 void        NodeGrid::SetDefaultGridDisabled(BOOL state)        { DefaultGridDisabled   = state; }
02772 void        NodeGrid::SetDefaultDivisions(double Div)           { DefaultDivisions      = Div; }
02773 void        NodeGrid::SetDefaultSubdivisions(UINT32 Sub)            { DefaultSubdivisions   = Sub; }
02774 void        NodeGrid::SetDefaultUnits(UnitType UType)           { DefaultUnits          = UType; }
02775 void        NodeGrid::SetDefaultGridType(GridType   GType)      { DefaultGridType       = GType; }
02776 
02777 //--------------------------------------------------------------------
02778 //--------------------------------------------------------------------
02779 // Support functions for unit processing
02780 //--------------------------------------------------------------------
02781 //--------------------------------------------------------------------
02782 
02783 static UnitType GetDominantUnit(UnitType ThisUnit)
02784 {
02785 //  for (INT32 u=0;(u<NUM_DEFAULT_UNIT_TYPES) && (UnitDataList[u].Units != Units);u++) ;
02786 //  if (u >= NUM_DEFAULT_UNIT_TYPES) return NOTYPE; else return UnitDataList[u].DominantUnit;
02787 
02788     DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
02789     Unit* pThisUnit = pDocUnitList->FindUnit(ThisUnit);
02790     double NumMills = pThisUnit->GetMillipoints();
02791 
02792     UnitType ThisUnitBaseType = pThisUnit->GetBaseUnitType();
02793     if (ThisUnitBaseType != NOTYPE)
02794     {
02795         Unit*  pBaseUnit = pDocUnitList->FindUnit(pThisUnit->GetBaseUnitType());
02796 
02797         if (NumMills < pBaseUnit->GetMillipoints())
02798             return (pBaseUnit->GetUnitType());
02799     }
02800 
02801     INT32 NumUnits = pDocUnitList->GetNumUnits();
02802     INT32 u;
02803     double   ResultMills = 1.7E308;
02804     UnitType ResultUnitType = NOTYPE;
02805 
02806     for (u=0;u < NumUnits;u++)
02807     {
02808         Unit* pUnit = pDocUnitList->FindUnit(u);
02809         UnitType BaseUnitType = pUnit->GetBaseUnitType();
02810 
02811         if (BaseUnitType != NOTYPE)
02812         {
02813             if (BaseUnitType == ThisUnit)
02814             {
02815                 double m = pUnit->GetMillipoints();
02816                 if ((m > NumMills) && (m < ResultMills))
02817                 {
02818                     ResultMills = m;
02819                     ResultUnitType = pUnit->GetUnitType();
02820                 }
02821             }
02822         }
02823     }
02824 
02825     return ResultUnitType;
02826 }
02827 
02828 static double GetUnitMultiple(UnitType Units)
02829 {
02830 //  for (INT32 u=0;(u<NUM_DEFAULT_UNIT_TYPES) && (UnitDataList[u].Units != Units);u++) ;
02831 //  if (u >= NUM_DEFAULT_UNIT_TYPES) return 1; else return UnitDataList[u].Multiple;
02832 
02833     UnitType DomUnitType = ::GetDominantUnit(Units);
02834 
02835     if (DomUnitType == NOTYPE)
02836         return 2.0;
02837 
02838     DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
02839     Unit* pUnit    = pDocUnitList->FindUnit(Units);
02840     Unit* pDomUnit = pDocUnitList->FindUnit(DomUnitType);
02841     double Multiple;
02842     
02843     if (pUnit->GetBaseUnitType() == pDomUnit->GetUnitType())
02844         Multiple = pUnit->GetBaseDenominator()  / pUnit->GetBaseNumerator();
02845     else
02846         Multiple = pDomUnit->GetBaseNumerator() / pDomUnit->GetBaseDenominator();
02847 
02848     if (Multiple <= 1.0)
02849         return 2.0;
02850     else
02851         return Multiple;
02852 }
02853 
02854 /*
02855 static struct 
02856 {
02857     UnitType    Units;
02858     TCHAR*      Suffix;
02859     UINT32      Multiple;
02860     UnitType    DominantUnit;
02861 } UnitDataList[NUM_DEFAULT_UNIT_TYPES] = 
02862 {
02863     { MILLIMETRES,  "mm", 10,   CENTIMETRES },
02864     { CENTIMETRES,  "cm", 100,  METRES      },
02865     { METRES,       "m" , 1000, NOTYPE      },
02866     { INCHES,       "in", 12,   FEET        },
02867     { FEET,         "ft", 3,    YARDS       },
02868     { YARDS,        "yd", 1760, NOTYPE      },
02869     { COMP_POINTS,  "pt", 72,   PICAS       },
02870     { PICAS,        "pi", 6,    INCHES      },
02871     { MILLIPOINTS,  "mp", 1000, COMP_POINTS }
02872 };
02873 */
02874 
02875 
02876 //static TCHAR* GetUnitSuffix(UnitType Units)
02877 //{
02878 //  for (INT32 u=0;(u<NUM_DEFAULT_UNIT_TYPES) && (UnitDataList[u].Units != Units);u++) ;
02879 //  if (u >= NUM_DEFAULT_UNIT_TYPES) return ""; else return UnitDataList[u].Suffix;
02880 
02881 //  Unit* pUnit = pDocUnitList->FindUnit(DomUnitType);
02882 //  String_32 Spec = pUnit->GetSpecifier();
02883 //  return ((TCHAR*)Spec);
02884 //}
02885 
02886 //-------------
02887 //---------------------------------------------------------------
02888 //---------------------------------------------------------------
02889 //---------------------------------------------------------------
02890 
02891 /********************************************************************************************
02892 
02893 >   virtual BOOL NodeGrid::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
02894 
02895     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02896     Created:    6/8/96
02897     Inputs:     pFilter = ptr to the filter
02898     Returns:    TRUE if record is written, FALSE if not
02899     Purpose:    Writes the grid record to the filter (if it's required)
02900     SeeAlso:    Node::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
02901 
02902 ********************************************************************************************/
02903 
02904 BOOL NodeGrid::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
02905 {
02906     // do nothing in the web format
02907     return FALSE;
02908 }
02909 
02910 //--------------------------------------------------------------
02911 // See NodeGrid::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
02912 //
02913 BOOL NodeGrid::WritePreChildrenNative(BaseCamelotFilter* pFilter)
02914 {
02915 #ifdef DO_EXPORT
02916     BOOL RecordWritten = TRUE;
02917 
02918     // Write out the page sizes etc for this spread
02919     if (RecordWritten) RecordWritten = WriteGridAndRulerSettings(pFilter);
02920     if (RecordWritten) RecordWritten = WriteGirdAndRulerOrigin(pFilter);
02921 
02922     return RecordWritten;
02923 #else
02924     return TRUE;
02925 #endif //DO_EXPORT
02926 }
02927 
02928 /********************************************************************************************
02929 
02930 >   BOOL NodeGrid::WriteGridAndRulerSettings(BaseCamelotFilter* pFilter)
02931 
02932     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02933     Created:    6/8/96
02934     Input:      pFilter = ptr to the filter to export to
02935     Outputs:    -
02936     Returns:    TRUE if ok, FALSE otherwise
02937     Purpose:    Exports the settings for the grid and rulers to the filter.
02938                 This is the default grid, as this acts as the settings for the grid,
02939                 as you would expect, and the page rulers.
02940     SeeAlso:    NodeGrid::WritePreChildrenNative; NodeGrid::WritePreChildrenWeb;
02941 
02942 ********************************************************************************************/
02943 
02944 BOOL NodeGrid::WriteGridAndRulerSettings(BaseCamelotFilter* pFilter)
02945 {
02946 #ifdef DO_EXPORT
02947     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
02948 
02949     BOOL ok = FALSE;
02950     
02951     // Only write out this set of details if it is the default grid
02952     if (IsDefault())
02953     {
02954         // Go and get the numbers out of the grid
02955         // BODGE - old builds (hence docs) save the grid spacing in divisions and units but don't
02956         // account for unit scaling, so as not to change doc format new docs do the same so we must
02957         // read the grid 'Divisions' with scaling turned off - yuk!
02958         // But surely, it is safer to save out the units unscaled!
02959         BOOL Scale = FALSE;
02960         double   Divisions    = GetDivisions(Scale);
02961         UnitType Unit         = GetUnits(Scale);
02962         UINT32     SubDivisions = GetSubdivisions();
02963         GridType TypeOfGrid   = GetGridType();
02964         
02965         // Convert the unittype into a reference
02966         UnitListComponent * pUnitsComponent = pFilter->GetUnitDocComponent();
02967         ERROR2IF(pUnitsComponent == NULL,FALSE,"WriteGridAndRulerSettings No units doc component present");
02968 
02969         INT32 UnitsRef = pUnitsComponent->GetWriteUnitReference(Unit, pFilter);
02970 
02971         CXaraFileRecord Rec(TAG_GRIDRULERSETTINGS, TAG_GRIDRULERSETTINGS_SIZE);
02972 
02973         ok = Rec.Init();
02974 
02975         if (ok) ok = Rec.WriteINT32(UnitsRef);  
02976         if (ok) ok = Rec.WriteDOUBLE(Divisions);    
02977         if (ok) ok = Rec.WriteUINT32(SubDivisions); 
02978         if (ok) ok = Rec.WriteBYTE((BYTE)TypeOfGrid);   
02979 
02980         // Finally, write the record out to file
02981         // In the process get the record number that this was written out as
02982         INT32 RecordNumber = 0L;
02983         if (ok) RecordNumber = pFilter->Write(&Rec);
02984 
02985         // If we have had a problem at any of the stages then return that to the caller
02986         if (!ok || RecordNumber <= 0)
02987             ok = FALSE;
02988     } 
02989 
02990     return ok;
02991 #else
02992     return TRUE;
02993 #endif //DO_EXPORT
02994 }
02995 
02996 /********************************************************************************************
02997 
02998 >   BOOL Spread::WriteGirdAndRulerOrigin(BaseCamelotFilter* pFilter)
02999 
03000     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03001     Created:    6/8/96
03002     Input:      pFilter = ptr to the filter to export to
03003     Outputs:    -
03004     Returns:    TRUE if ok, FALSE otherwise
03005     Purpose:    Exports the origin for the grid and ruler to the filter.
03006                 This is the default grid, as this acts as the settings for the grid,
03007                 as you would expect, and the page rulers.
03008     SeeAlso:    NodeGrid::WritePreChildrenNative; NodeGrid::WritePreChildrenWeb;
03009 
03010 ********************************************************************************************/
03011 
03012 BOOL NodeGrid::WriteGirdAndRulerOrigin(BaseCamelotFilter* pFilter)
03013 {
03014 #ifdef DO_EXPORT
03015     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
03016 
03017     BOOL ok = FALSE;
03018     
03019     // Only write out this set of details if it is the default grid
03020     if (IsDefault())
03021     {
03022         // Read the grid (user) origin
03023         DocCoord Origin(0,0);
03024         GetOrigin(&Origin.x, &Origin.y);
03025         
03026         // We will now translate this to be relative to the page origin, as it will be displayed
03027         // to the user
03028         Spread* pSpread = pFilter->GetSpread();
03029         DocCoord PageRelGridOrigin = Origin;
03030         if (pSpread)
03031             pSpread->SpreadCoordToPagesCoord(&PageRelGridOrigin, Origin);
03032 
03033         CXaraFileRecord Rec(TAG_GRIDRULERORIGIN, TAG_GRIDRULERORIGIN_SIZE);
03034 
03035         ok = Rec.Init();
03036 
03037         // Write out the origin
03038         if (ok) ok = Rec.WriteCoord(PageRelGridOrigin); 
03039 
03040         // Finally, write the record out to file
03041         // In the process get the record number that this was written out as
03042         INT32 RecordNumber = 0L;
03043         if (ok) RecordNumber = pFilter->Write(&Rec);
03044 
03045         // If we have had a problem at any of the stages then return that to the caller
03046         if (!ok || RecordNumber <= 0)
03047             ok = FALSE;
03048     } 
03049 
03050 
03051     return ok;
03052 #else
03053     return TRUE;
03054 #endif //DO_EXPORT
03055 }
03056 

Generated on Sat Nov 10 03:45:28 2007 for Camelot by  doxygen 1.4.4