rsmooth.cpp

Go to the documentation of this file.
00001 // $Id: rsmooth.cpp 1492 2006-07-20 19:19:48Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // Implementation file containing routines to control the interactive smoothing
00099 // of selected path regions
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 #include "rsmooth.h"
00107 #include "nodepath.h"
00108 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include <math.h>
00110 //#include "mike.h"
00111 //#include "undoop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "objchge.h"
00114 #include "nodeblnd.h"
00115 #include "nodebldr.h"
00116 #include "ophist.h"
00117 
00118 CC_IMPLEMENT_DYNCREATE( OpRetroSmooth, SelOperation )
00119 
00120 DECLARE_SOURCE("$Revision: 1492 $");
00121 
00122 // Declare smart memory handling in Debug builds
00123 #define new CAM_DEBUG_NEW
00124 
00125 
00126 /********************************************************************************************
00127 
00128 >   RetroSmooth::RetroSmooth()
00129 
00130     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00131     Created:    11/11/94
00132     Purpose:    RetroSmooth constructor
00133                 Sets default values for internal variables used by the RetroSmooth
00134                 class.
00135     SeeAlso:    -
00136 
00137 ********************************************************************************************/
00138 
00139 RetroSmooth::RetroSmooth()
00140 {
00141     pRetroNode = NULL;
00142     pRetroSpread = NULL;
00143     RetroSmoothAcc = SMOOTH_MIN;
00144     RetroSmoothing = FALSE;
00145     RetroPathCRC = 0;
00146     RetroSelCRC = 0;
00147     RetroSmoothPercent = 0;
00148 
00149     m_bRender = TRUE;
00150 }
00151 
00152 
00153 
00154 /********************************************************************************************
00155 
00156 >   BOOL RetroSmooth::Initialise()
00157 
00158     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00159     Created:    11/11/94
00160     Inputs:     -
00161     Returns:    TRUE    - then the retro smooth initialisation has succedded
00162                 FALSE   - then no memory to perform the retro smooth. The caller should
00163                           abort the operation.
00164     Purpose:    Initialise various internal lists of data used by the retrosmooth class.
00165 
00166 ********************************************************************************************/
00167 
00168 BOOL RetroSmooth::Initialise()
00169 {
00170     BOOL ok = RetroPath.Initialise(12,12);
00171     if (ok) ok = RetroEorPath.Initialise(12,12);
00172     if (ok) ok = RetroEorRegion.Initialise(12,12);
00173     return ok;
00174 }
00175 
00176 
00177 
00178 /********************************************************************************************
00179 
00180 >   void RetroSmooth::Changing(NodePath* pNodePath, Spread* pSpread, double smooth)
00181 
00182     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00183     Created:    11/11/94
00184     Inputs:     pNodePath   = pointer to a node path to smooth
00185                 pSpread     = pointer to the nodes spread
00186                 smooth      = smoothness level to use
00187     Returns:
00188     Purpose:    This function is called when a change has occured to the retrosmooth input
00189                 control device, and it wishes to inform the retrosmoother. The function takes
00190                 a node and spread and renders a new smoothed eor'd version of the path to
00191                 the display device. No changes occur to the NodePath provided. All changes
00192                 occur internally to this smooth class.
00193                 If this is the first of a sequence of calls to the changing function,
00194                 a cached version of the path is created, along with information about the
00195                 selected regions within the path. On subsequent calls, the cached version
00196                 of the path will be used to create a smooth display path. 
00197 
00198 ********************************************************************************************/
00199 
00200 void RetroSmooth::Changing(NodePath* pNodePath, Spread* pSpread, double smooth)
00201 {
00202 /*
00203     // Find the docview that we are looking at
00204     DocView* pDocView = DocView::GetCurrent();
00205 
00206     // Refit the path - First work out the current error factor
00207     double ScaleFactor = (pDocView->GetViewScale()).MakeDouble();
00208     double ErrorLevel = (64 + (160*smooth)) / ScaleFactor;
00209     RetroSmoothAcc = ErrorLevel * ErrorLevel;
00210 */
00211 
00212     // calculate a useful smooth accuracy
00213     double newacc = SMOOTH_MIN + (SMOOTH_MAX - SMOOTH_MIN)*pow((smooth/100), 3.0);
00214 
00215     if (newacc == RetroSmoothAcc)
00216         return;
00217 
00218     // keep track of some variables for later
00219     RetroSmoothAcc = newacc;
00220     RetroSmoothPercent = smooth;
00221     pRetroSpread = pSpread;
00222 
00223     // if this is the first call to us then do the setup
00224     if (!RetroSmoothing)
00225         if (!RetroSmooth::Starting(pNodePath))
00226             return;
00227 
00228     // finally we are in a position to start retro activity.
00229     RetroSmoothing = TRUE;
00230     RetroSmooth::Update();      
00231 
00232 }
00233 
00234 
00235 
00236 /********************************************************************************************
00237 
00238 >   void RetroSmooth::Finished()
00239 
00240     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00241     Created:    11/11/94
00242     Inputs:     -
00243     Returns:    -
00244     Purpose:    This function should be called to terminate the retro smooth action. The
00245                 data cached during the calls to RetroSmooth::Changing() will now be used to
00246                 actually affect the path held in the document.
00247 
00248 ********************************************************************************************/
00249 
00250 void RetroSmooth::Finished()
00251 {
00252     // if no retro path, just do nothing
00253     if (!pRetroNode || !RetroSmoothing)
00254         return;
00255     // tidy up after retro smoothing
00256     RetroEorRegion.Empty();
00257     RecordPathRegions(&RetroEorPath);
00258     RetroPathCRC = RetroEorPath.CalcCRC();
00259     RetroSelCRC = RetroEorPath.CalcSelectedCRC();
00260     RetroSmoothing = FALSE;
00261 
00262     // finally create an op to really smooth the tree object
00263     // path and execute it.
00264     OpRetroSmooth* pOpRetroSmooth = new OpRetroSmooth;
00265     if (pOpRetroSmooth != NULL)
00266         pOpRetroSmooth->DoRetroSmooth(pRetroNode, &RetroEorPath, RetroSmoothAcc);
00267 }
00268 
00269 
00270 /********************************************************************************************
00271 
00272 >   void RetroSmooth::Invalidate()
00273 
00274     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00275     Created:    22/11/94
00276     Inputs:     -
00277     Returns:    -
00278     Purpose:    Invalidates all cached information about the currently active retro
00279                 smoothing path. Cached paths and region buffers are compacted.
00280 
00281 ********************************************************************************************/
00282 
00283 void RetroSmooth::Invalidate()
00284 {
00285     pRetroNode = NULL;
00286     pRetroSpread = NULL;
00287     RetroSmoothAcc = SMOOTH_MIN;
00288     RetroSmoothing = FALSE;
00289     RetroPathCRC = 0;
00290     RetroSelCRC = 0;
00291 
00292     RetroPath.ClearPath(TRUE);  
00293     RetroEorPath.ClearPath(TRUE);
00294     RetroEorRegion.Empty();
00295 }
00296 
00297 
00298 /********************************************************************************************
00299 
00300 >   double RetroSmooth::ReturnCachedAccuracy(Path* pPath)
00301 
00302     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00303     Created:    23/11/94
00304     Inputs:     pPath = pointer to a path 
00305     Returns:    a percentage value for the current smoothness of this curve
00306     Purpose:    This function can be used to determin the smoothness of any curve. It will
00307                 simply check for a match between the path given and an internal cached
00308                 representation. If a match is found the current smoothness is returned, ie
00309                 the last value passed to the RetroSmooth::Changing() function. If no match
00310                 is found a value of 0 is returned, meaning the curve has not been smoothed. 
00311 
00312 ********************************************************************************************/
00313 
00314 double RetroSmooth::ReturnCachedAccuracy(Path* pPath)
00315 {
00316     // calculate the cyclic redundancy for this path.
00317     INT32 new_crc = pPath->CalcCRC();
00318     INT32 sel_crc = pPath->CalcSelectedCRC();
00319 
00320     if ((RetroPathCRC == new_crc) && (RetroSelCRC == sel_crc))
00321         return RetroSmoothPercent;
00322 
00323     return 0;
00324 }
00325 
00326 
00327 
00328 /********************************************************************************************
00329 
00330     BOOL RetroSmooth::Starting(NodePath* pDocNodePath)
00331 
00332     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00333     Created:    11/11/94
00334     Inputs:     pDocNodePath = pointer to a node path to smooth
00335     Returns:
00336     Purpose:    Set up the internal data structures for this new NodePath. This allows us
00337                 to continue resmoothing the path given new smooth values, until the outside
00338                 world calls RetroSmooth::Finished. We cache the path and its selected regions
00339                 to help us with some hairy redraw problems.
00340     SeeAlso:    RetroSmooth::Update()
00341 
00342 ********************************************************************************************/
00343 
00344 BOOL RetroSmooth::Starting(NodePath* pDocNodePath)
00345 {
00346     if (pRetroSpread == NULL)
00347         return FALSE;
00348 
00349     // calculate the cyclic redundancy for this path.
00350     INT32 new_crc = pDocNodePath->InkPath.CalcCRC();
00351     INT32 sel_crc = pDocNodePath->InkPath.CalcSelectedCRC();
00352 
00353     if (!new_crc)
00354         return FALSE;
00355 
00356     if ((RetroPathCRC == new_crc) && (RetroSelCRC == sel_crc))
00357     {
00358         pRetroNode = pDocNodePath;
00359         TranslateRetroData(&(pDocNodePath->InkPath));
00360         return TRUE;
00361     }
00362 
00363     // if our data doesn't match the path given then we are now
00364     // in the situation where we need to reto smooth a new path
00365     // if there are no selected points in the path then we have
00366     // nothing to retro smooth
00367     if (!sel_crc)
00368         return FALSE;
00369 
00370     return NewPathToSmooth(pDocNodePath);
00371 }
00372 
00373 
00374 /********************************************************************************************
00375 
00376     void RetroSmooth::TranslateRetroData(Path* pPath)
00377 
00378     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00379     Created:    22/11/94
00380     Inputs:     pPath = a path to translate the cached retro path to
00381     Returns:    -
00382     Purpose:    Translate the retro path data to the origin of pPath 
00383 
00384 ********************************************************************************************/
00385 
00386 void RetroSmooth::TranslateRetroData(Path* pPath)
00387 {
00388     ENSURE(pPath !=NULL, "NULL path passed to RetroSmooth::TranslateRetroData()");
00389 
00390     if (pPath == NULL)
00391         return;
00392 
00393     if (pPath->GetNumCoords() <= 0)
00394         return;
00395 
00396     DocCoord* Coords = pPath->GetCoordArray();
00397     DocCoord* RCoords = RetroPath.GetCoordArray();
00398 
00399     INT32 transx = Coords[0].x - RCoords[0].x;
00400     INT32 transy = Coords[0].y - RCoords[0].y;
00401 
00402     RetroPath.Translate(transx,transy);
00403     RetroEorPath.Translate(transx,transy);
00404 }
00405 
00406 
00407 
00408 /********************************************************************************************
00409 
00410     void RetroSmooth::Update()
00411 
00412     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00413     Created:    11/11/94
00414     Inputs:     -
00415     Returns:    -
00416     Purpose:    We have been given a new smooth value. We need to resmooth our internal
00417                 data and render an eor version to the display device.
00418                 What we try to do (to avoid hideous eoring problems) is this
00419                 (1) Create a temporary path and copy our cached path data to it
00420                 (2) Create a temp region list to save smoothed region start end indexes
00421                 (3) Go through a loop smoothing each region in the temp eor path
00422                     whilst recording the new smoothed region indexes as we go.
00423                 (4) Check this new data against our previous cached eorpath and region
00424                     list. 
00425                 (5) If all match then
00426                         do nothing as the smoothed path has not changed since the last
00427                         smooth even though we know the smooth value has.
00428                     else
00429                         render the cached eor path to the output device, removing the item
00430                         copy the temporary eor path and region list to the cache eor
00431                         path and region list
00432                         render the cached eor path to the output device
00433                 (6) exit    
00434 
00435 ********************************************************************************************/
00436 
00437 void RetroSmooth::Update()
00438 {
00439     INT32 numcoords = RetroPath.GetNumCoords();
00440 
00441     // create a temp path to smooth
00442     Path RenderPath;
00443     if (!RenderPath.Initialise(numcoords, 12))
00444         return;
00445     RenderPath.CloneFrom(RetroPath);
00446 
00447     DynArray TempRegions;
00448     if (!TempRegions.Initialise(RetroEorRegion.NumItems(),12))
00449         return;
00450 
00451     INT32 Region = 0;
00452     INT32 index = 0;
00453     INT32 start,end;
00454     // now scan the path for regions of interest
00455     while ((index<numcoords) && RenderPath.FindSelectionLimits(index,&start,&end))
00456     {
00457         INT32 nstart = start;
00458         INT32 nend = end;
00459         RenderPath.ExpandRange(&nstart,&nend,1);
00460 
00461         Set region;
00462         region.first = nstart;
00463         region.last = nend;
00464         region.Finclusive = !(nstart<start);
00465         region.Linclusive = !(nend>end);
00466 
00467         INT32 sel=0;
00468         if (nstart<start) sel |= 1;
00469         if (nend>end) sel |= 2;
00470         if (sel==0) sel=4;
00471 
00472         if (nstart != nend)
00473         {
00474             if (RetroSmoothAcc != SMOOTH_MIN)
00475             {
00476                 BOOL ok = RenderPath.SmoothSection(nstart,&region.last,RetroSmoothAcc,sel);
00477                 if (!ok)
00478                     return;
00479             }
00480 
00481             if (!TempRegions.AddItem(region))
00482                 return;
00483 
00484             Region++;
00485         }
00486 
00487         numcoords = RenderPath.GetNumCoords();
00488         index = region.last;
00489 
00490         if (!RenderPath.FindNextEndPoint(&index))
00491             index=numcoords;
00492     }
00493 
00494     // now we've smoothed the path, we need to check to see if its worth
00495     // updating the version on screen.
00496 
00497     INT32 new_crc = RenderPath.CalcCRC();
00498     if (new_crc != RetroPathCRC)
00499     {
00500         // get rid of the old eor path and put the new path back on again.
00501         if (RenderRegions())
00502         {
00503             RetroEorPath.CloneFrom(RenderPath);
00504             RetroEorRegion.CloneFrom(&TempRegions);
00505             RenderRegions();
00506             RetroPathCRC = new_crc;
00507         }
00508     }
00509 }
00510 
00511 
00512 
00513 /********************************************************************************************
00514 
00515     statci BOOL RetroSmooth::FinishedNoUndo(NodePath* pNodePath, double SmoothValue)
00516 
00517     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00518     Created:    11/11/94
00519     Inputs:     pNodePath   = pointer to a node path to use, the should generally be the same
00520                 nodepath that was previously passed in to Changing()
00521                 
00522     Returns:    TRUE if successful, FALSE otherwise
00523     Purpose:    Finishes off the smoothing operation by replacing the path in pNodePath with
00524                 the Retropath that we have generated.  This differs from the regular Finished
00525                 function because it does not alter the tree and it does not launch an operation,
00526                 therefore it is not undoable.
00527                 
00528     See Also:   If you want to know why it had to be non-undoable look at the implementation
00529                 of OpDrawBrush, where it is used in this way.
00530 ********************************************************************************************/
00531 
00532 BOOL RetroSmooth::FinishedNoUndo(NodePath* pNodePath)
00533 {
00534     ERROR2IF(pNodePath == NULL, FALSE, "pNodePath is NULL in RetroSmooth::RetroSmoothNoUndo");
00535     
00536     BOOL ok = TRUE;
00537 
00538 #ifdef _DEBUG
00539     ok = RetroEorPath.CheckPathValid();
00540 #endif
00541 
00542     if (ok)
00543     {
00544         pNodePath->InkPath.ClearPath(FALSE);
00545         pNodePath->InkPath.CopyPathDataFrom(&RetroEorPath);
00546     }
00547     RetroEorPath.ClearPath(FALSE);
00548 
00549     return ok;
00550 }
00551     
00552 
00553 /********************************************************************************************
00554 
00555     void RetroSmooth::SetRenderFlag(BOOL Value)
00556 
00557     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00558     Created:    12/4/2000
00559     Inputs:     Value - the value to set the flag
00560     Returns:
00561     Purpose:    This sets the flag that says whether or not to bother doing EOR rendering.
00562                 
00563     Notes:      You may wish to set the flag to false if you are using the retrosmoother separately
00564                 from the Bezier tool.  It will mean that you can call one-off smoothing procedures
00565                 without having to put up with all those blobs being rendered.
00566 
00567 ********************************************************************************************/
00568 
00569 void RetroSmooth::SetRenderFlag(BOOL Value)
00570 {
00571     m_bRender = Value;
00572 }
00573 
00574 
00575 /********************************************************************************************
00576 
00577     BOOL RetroSmooth::NewPathToSmooth(NodePath* pNodePath)
00578 
00579     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00580     Created:    11/11/94
00581     Inputs:     pNodePath   = pointer to a node path to use.
00582     Returns:
00583     Purpose:    Given a new document node path object, we need to initialise various
00584                 buffers to hold temporary data.
00585                 
00586     Notes:      We keep a copy of the path data to refer back to each time a retro smooth
00587                 changing message comes through. This allows us to go back to the original
00588                 shape of the curve and smooth from that each time the user starts dragging
00589                 the slider around, on the same path.
00590                 We also keep a transient copy of the path that we are actually smoothing
00591                 so that we can draw and undraw the sections which are changing.
00592 
00593 ********************************************************************************************/
00594 
00595 BOOL RetroSmooth::NewPathToSmooth(NodePath* pNodePath)
00596 {
00597     pRetroNode = pNodePath;
00598 
00599     // clear the path elements but dont bother moving memory
00600     RetroPath.ClearPath(FALSE); 
00601     RetroEorPath.ClearPath(FALSE);
00602 
00603     // take a local copy of some useful variables
00604     Path* pPath = &(pNodePath->InkPath);
00605     INT32 numcoords = pPath->GetNumCoords();
00606 
00607     if (RetroPath.MakeSpaceInPath(numcoords))
00608     {
00609         if (RetroEorPath.MakeSpaceInPath(numcoords))
00610         {
00611             RetroPath.CopyPathDataFrom(pPath);
00612             RetroEorPath.CopyPathDataFrom(pPath);
00613         }
00614         else
00615         {
00616             RetroPath.Compact();
00617             return FALSE;
00618         }
00619     }
00620     else
00621         return FALSE;
00622 
00623     // clear any regions
00624     RetroEorRegion.Empty();
00625 
00626     // try to record the path regions
00627     if (!RecordPathRegions(pPath))
00628     {
00629         RetroPath.ClearPath(TRUE);
00630         RetroEorPath.ClearPath(TRUE);
00631         return FALSE;
00632     }
00633 
00634     return TRUE;
00635 }
00636 
00637 
00638 
00639 /********************************************************************************************
00640 
00641     BOOL RetroSmooth::RenderRegions()
00642 
00643     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00644     Created:    11/11/94
00645     Inputs:     -
00646     Returns:    TRUE    - then regions have been eor rendered
00647                 FALSE   - then no regions have been rendered
00648     Purpose:    Scan through the cached region list, rendering the path and blobs in
00649                 each region.
00650 
00651     Extra Note: Diccon 12/4/2000 I want to use the RetroSmoother as a one-off smoothing 
00652                 procedure without the EOR Rendering, therefore I have added an extra flag
00653                 which returns TRUE from this function without actually rendering anything.
00654 ********************************************************************************************/
00655 
00656 BOOL RetroSmooth::RenderRegions()
00657 {
00658     // if our flag is set then just return 
00659     if (!m_bRender)
00660         return TRUE;
00661 
00662     // check we've actually got a region to render  
00663     INT32 numregions = RetroEorRegion.NumItems();
00664     if (!numregions)
00665         return TRUE;
00666 
00667     INT32 regionsize = FindMasterRegion();
00668     if (!regionsize)
00669         return FALSE;
00670 
00671     // create a render path to copy sections into
00672     Path RenderPath;       
00673     if (!RenderPath.Initialise(regionsize,12))
00674         return FALSE;
00675 
00676     // Go into a RenderOnTop loop
00677     RenderRegion* pRegion = DocView::RenderOnTop(NULL, pRetroSpread, ClippedEOR);
00678     while (pRegion!=NULL)
00679     {
00680         // render each region by copying the section into our temp path
00681         // and rendering each of these.     
00682         INT32 reg = numregions;
00683         while (reg>0)
00684         {
00685             reg--;
00686 
00687             INT32 start = RetroEorRegion[reg].first;
00688             if (!RetroEorRegion[reg].Finclusive)
00689                 RetroEorPath.FindNextEndPoint(&start);
00690 
00691             INT32 end = RetroEorRegion[reg].last;
00692             if (!RetroEorRegion[reg].Linclusive)
00693                 RetroEorPath.FindPrev(&end);
00694 
00695             INT32 length = end - start + 1;
00696             if (length>0)
00697             {
00698                 // make a path to render
00699                 if (RetroEorPath.MakePathFromSection(start, length, &RenderPath))
00700                 {
00701                     RenderPath.RenderPathBlobs(pRegion);
00702                     // set a colour during our render
00703 //                  pRegion->SetLineColour(COLOUR_XOREDIT);
00704 //                  pRegion->SetLineWidth(0);
00705 //                  pRegion->DrawPath(&RenderPath);
00706                     RenderPath.ClearPath(FALSE);
00707                 }
00708             }
00709         }
00710         pRegion = DocView::GetNextOnTop(NULL);
00711     }
00712 
00713     return TRUE;
00714 }
00715 
00716 
00717 /********************************************************************************************
00718 
00719     INT32 RetroSmooth::FindMasterRegion()
00720 
00721     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00722     Created:    11/11/94
00723     Inputs:
00724     Returns:    The largest region
00725     Purpose:    Scans the region list and finds the region with the greatest number of
00726                 coordinates in it, returning that number
00727 
00728 ********************************************************************************************/
00729 
00730 INT32 RetroSmooth::FindMasterRegion()
00731 {
00732     INT32 numcoords = RetroEorRegion.NumItems();
00733     INT32 largest=0;
00734 
00735     for (INT32 i=0; i<numcoords; i++)
00736     {
00737         INT32 length = RetroEorRegion[i].last - RetroEorRegion[i].first +1;
00738         if (length>largest)
00739             largest = length;
00740     }
00741     return largest;
00742 }
00743 
00744 
00745 
00746 /********************************************************************************************
00747 
00748     BOOL RetroSmooth::MatchRegions(NodePath* pNodePath)
00749 
00750     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00751     Created:    11/11/94
00752     Inputs:     pNodePath - a nodepath object pointer
00753     Returns:    TRUE    - if the selected regions within pNodePath match those of our
00754                           cached path.
00755                 FALSE   - if no match is found.
00756 
00757     Purpose:    Scan through the path data in pNodePath and match selected regions
00758                 with our cached version. If the regions match, then we may be able to
00759                 use our previously cached none smooth path as the source for a new
00760                 retro active smooth, rather than pNodePath.
00761 
00762 ********************************************************************************************/
00763 
00764 BOOL RetroSmooth::MatchRegions(NodePath* pNodePath)
00765 {
00766     // ok, scan through all sel regions in this cached
00767     // object and match against those in the searchpath
00768     // if they all match, then return true.
00769 
00770     
00771     return TRUE;
00772 }
00773 
00774 
00775 /********************************************************************************************
00776 
00777 >   BOOL RetroSmooth::RecordPathRegions(Path* pPath)
00778 
00779     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00780     Created:    11/11/94
00781     Inputs:     pPath =
00782     Returns:
00783     Purpose:    Record the selected regions of the path on the original regions list
00784                 or the smoothed regions
00785 
00786 ********************************************************************************************/
00787 
00788 BOOL RetroSmooth::RecordPathRegions(Path* pPath)
00789 {
00790     INT32 index = 0;
00791     INT32 ncoords = pPath->GetNumCoords();
00792 
00793     // The reasons are deeply rooted why I'm about to use a doccoord class
00794     // to hold two longs which represent the start and end of a region.
00795     // Its because I cannot use 'templates' at the moment to define an
00796     // associative array, so the dynamic array class I'm about to used is
00797     // typed to hold doccoords instead of generic 'types'.
00798 
00799     INT32 start;
00800     INT32 end;
00801     
00802     while ( (index<ncoords) && pPath->FindSelectionLimits(index,&start,&end) )
00803     {
00804         Set PtSet;
00805         PtSet.first = start;
00806         PtSet.last = end;
00807 
00808         pPath->ExpandRange(&PtSet.first,&PtSet.last,1);
00809 
00810         PtSet.Finclusive = !(PtSet.first<start);
00811         PtSet.Linclusive = !(PtSet.last>end);
00812 
00813         if (!RetroEorRegion.AddItem(PtSet))
00814         {
00815             index = -1;
00816             break;
00817         }
00818         index=PtSet.last;
00819         if (!pPath->FindNextEndPoint(&index))
00820             index=ncoords;
00821     }
00822 
00823     // make sure we've tidied up incase of failure
00824     if (index==-1)
00825     {
00826         RetroEorRegion.Empty();
00827         return FALSE;
00828     }
00829 
00830     return TRUE;
00831 }
00832 
00833 
00834 /********************************************************************************************
00835 
00836     void RetroSmooth::AlterRegion(INT32 index, INT32 newstart, INT32 newend) 
00837 
00838     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00839     Created:    16/11/94
00840     Purpose:    Alters a specific regions start,end indexes.
00841 
00842 ********************************************************************************************/
00843 
00844 void RetroSmooth::AlterRegion(INT32 index, INT32 newstart, INT32 newend)
00845 {
00846     Set set;
00847     set.first = newstart;
00848     set.last = newend;
00849     set.Finclusive = TRUE;
00850     set.Linclusive = TRUE;
00851     RetroEorRegion[index] = set;
00852 }
00853 
00854 
00855 /********************************************************************************************
00856 
00857 >   OpRetroSmooth::OpRetroSmooth() 
00858 
00859     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00860     Created:    18/11/94
00861     Purpose:    OpRetroSmooth() constructor
00862     SeeAlso:    -
00863 
00864 ********************************************************************************************/
00865 
00866 OpRetroSmooth::OpRetroSmooth()
00867 {
00868     // Dummy constructor
00869 }
00870   
00871 
00872 
00873 /********************************************************************************************
00874 
00875 >   BOOL OpRetroSmooth::Init()
00876 
00877     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00878     Created:    26/7/94
00879     Inputs:     -
00880     Outputs:    -
00881     Returns:    TRUE if the operation could be successfully initialised 
00882                 FALSE if no more memory could be allocated 
00883                 
00884     Purpose:    OpRetroSmooth initialiser method
00885     Errors:     ERROR will be called if there was insufficient memory to allocate the 
00886                 operation.
00887     SeeAlso:    -
00888 
00889 ********************************************************************************************/
00890 
00891 BOOL OpRetroSmooth::Init()
00892 {
00893     return (RegisterOpDescriptor(0,                                 // tool ID
00894                                 _R(IDS_RETROSMOOTHOP),                  // string resource ID
00895                                 CC_RUNTIME_CLASS(OpRetroSmooth),    // runtime class for Op
00896                                 OPTOKEN_RETROSMOOTH,            // Ptr to token string
00897                                 OpRetroSmooth::GetState,            // GetState function
00898                                 0,                                  // help ID
00899                                 _R(IDBBL_RETROSMOOTHOP),                // bubble help ID
00900                                 0                                   // resource ID =0
00901                                 ));
00902 
00903 }               
00904 
00905 
00906 /********************************************************************************************
00907 
00908 >   OpState OpRetroSmooth::GetState(String_256*, OpDescriptor*)
00909 
00910     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00911     Created:    20/10/94
00912     Inputs:     -
00913     Outputs:    -
00914     Returns:    The state of the OpRetroSmooth
00915     Purpose:    For finding the OpRetroSmooth state. 
00916     Errors:     -
00917     SeeAlso:    -
00918 
00919 ********************************************************************************************/
00920 
00921 OpState OpRetroSmooth::GetState(String_256* UIDescription, OpDescriptor*)
00922 {
00923     OpState OpSt;
00924     // Always enabled at the moment.
00925     return OpSt;
00926 }
00927 
00928 /********************************************************************************************
00929 
00930 >   void OpRetroSmooth::GetOpName(String_256* OpName)
00931 
00932     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00933     Created:    20/10/94
00934     Inputs:     -
00935     Outputs:    The undo string for the operation
00936     Returns:    
00937     Purpose:    The GetOpName fn is overridden so that we return back a description
00938                 appropriate to the type of attribute that the operation applies.
00939                     
00940 ********************************************************************************************/
00941 
00942 void OpRetroSmooth::GetOpName(String_256* OpName)
00943 {
00944     *OpName = String_256(_R(IDS_UNDO_RETROSMOOTHOP));
00945 }
00946 
00947 
00948 
00949 /********************************************************************************************
00950 
00951 >   void OpRetroSmooth::DoRetroSmooth(NodePath* pThisNode, double smoothacc)
00952 
00953     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00954     Created:    29/9/94
00955     Inputs:     pThisNode = pointer to a path node in the tree to smooth
00956                 smoothacc = accuracy value to smooth to
00957     Outputs:    -
00958     Returns:    -
00959     Purpose:    This operation will smooth a node path given an accuracy. It will create a
00960                 new node in the tree after the node specified and hide node passed if all 
00961                 is succesfull.
00962 
00963 ********************************************************************************************/
00964     
00965 void OpRetroSmooth::DoRetroSmooth(NodePath* pThisNode, Path* pPath, double smoothacc)
00966 {
00967     BOOL ok;
00968     // remember the selection before the operation
00969     if (!DoStartSelOp(FALSE,FALSE))
00970     {
00971         FailAndExecute(); End(); return;
00972     }
00973 
00974     // also check for blends needing to be re-initialised
00975     NodeBlender * pBlender = NULL;
00976     NodeBlend * pBlend = NULL;
00977     NodeBlend* pOrigBlend = NULL;
00978     pBlender = (NodeBlender *)pThisNode->FindNext(CC_RUNTIME_CLASS(NodeBlender));
00979     if (!pBlender) pBlender = (NodeBlender *)pThisNode->FindPrevious(CC_RUNTIME_CLASS(NodeBlender));
00980     
00981     if (pBlender)
00982     {   
00983         pBlend = (NodeBlend *)pBlender->FindParent();
00984         //pBlend->forOpRetroSmooth = FALSE;
00985         pOrigBlend = pBlend;
00986     }
00987 
00988     // Invalidate the region
00989     CALL_WITH_FAIL( DoInvalidateNodeRegion(pThisNode, TRUE, FALSE), this, ok);
00990     if (!ok)
00991     {
00992         FailAndExecute(); End(); return;
00993     }
00994 
00995     ObjChangeFlags cFlags;
00996     cFlags.ReplaceNode = TRUE;
00997     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,pThisNode,this);
00998     if (pThisNode->AllowOp(&ObjChange))
00999     {
01000         // create the new node path
01001         CALL_WITH_FAIL( DoMakeNodeFromPath(pThisNode, pPath, NEXT, TRUE), this, ok);
01002         if (!ok)
01003         {
01004             FailAndExecute(); End(); return;
01005         }
01006 
01007         // see if were part of a blend ....
01008 
01009         pBlender = (NodeBlender *)pThisNode->FindNext(CC_RUNTIME_CLASS(NodeBlender));
01010 
01011         if (pBlender)
01012         {
01013             pBlend = (NodeBlend *)pBlender->FindParent();
01014 
01015             if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), pBlender, TRUE, TRUE) != AC_OK)
01016             {
01017                 ERROR2RAW("Couldn't Initialise blend action");
01018             }
01019 
01020             // re-insert this action at the head of the list
01021             
01022             pBlender->Reinit((NodeRenderableInk*) pThisNode->FindNext (), pBlender->GetNodeEnd(), FALSE);
01023 
01024             // Invalidate the region
01025             CALL_WITH_FAIL( DoInvalidateNodeRegion(pBlender, TRUE, FALSE), this, ok);
01026             if (!ok)
01027             {
01028                 FailAndExecute(); End(); return;
01029             }
01030         }
01031         else
01032         {
01033             pBlender = (NodeBlender *)pThisNode->FindPrevious(CC_RUNTIME_CLASS(NodeBlender));
01034 
01035             if (pBlender)
01036             {
01037                 pBlend = (NodeBlend *)pBlender->FindParent();
01038 
01039                 if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), pBlender, TRUE, TRUE) != AC_OK)
01040                 {
01041                     ERROR2RAW("Couldn't Initialise blend action");
01042                 }
01043 
01044                 // re-insert this action at the head of the list
01045                 
01046                 pBlender->Reinit(pBlender->GetNodeStart(), (NodeRenderableInk*) pThisNode->FindNext (), FALSE);
01047 
01048                 // Invalidate the region
01049                 CALL_WITH_FAIL( DoInvalidateNodeRegion(pBlender, TRUE, FALSE), this, ok);
01050                 if (!ok)
01051                 {
01052                     FailAndExecute(); End(); return;
01053                 }
01054             }
01055         }
01056 
01057         if (pBlender)
01058         {
01059             NodeBlend* ptrBlend = (NodeBlend*) pBlender->FindParent ();
01060 
01061             ERROR3IF (!IS_A (ptrBlend, NodeBlend), "NodeBlend is not a NodeBlend!");
01062 
01063             BOOL done = FALSE;
01064             NodeBlender* ptrNode = ptrBlend->FindFirstBlender ();
01065 
01066             while (!done)
01067             {
01068                 if (ptrNode != pBlender)
01069                 {
01070                     if (ptrNode->GetNodeStart () == pThisNode)
01071                     {
01072                         if (InitBlendAction::InitOnBlender(this, GetUndoActionList(), ptrNode, TRUE, TRUE) != AC_OK)
01073                         {
01074                             ERROR2RAW("Couldn't Initialise blend action");
01075                         }
01076                         
01077                         ptrNode->Reinit((NodeRenderableInk*) pThisNode->FindNext (), NULL, FALSE);
01078                     }
01079                     if (ptrNode->GetNodeEnd () == pThisNode)
01080                     {
01081                         if (InitBlendAction::InitOnBlender(this, GetUndoActionList(),  ptrNode, TRUE, TRUE) != AC_OK)
01082                         {
01083                             ERROR2RAW("Couldn't Initialise blend action");
01084                         }
01085 
01086                         ptrNode->Reinit(NULL, (NodeRenderableInk*) pThisNode->FindNext (), FALSE);
01087                     }
01088 
01089                     // Invalidate the region
01090                     CALL_WITH_FAIL( DoInvalidateNodeRegion(ptrNode, TRUE, FALSE), this, ok);
01091                     if (!ok)
01092                     {
01093                         FailAndExecute(); End(); return;
01094                     }
01095                 }
01096 
01097                 ptrNode = ptrBlend->FindNextBlender (ptrNode);
01098 
01099                 if (!ptrNode)
01100                 {
01101                     done = TRUE;
01102                 }
01103             }
01104         }
01105 
01106         ObjChange.Define(OBJCHANGE_FINISHED,cFlags,pThisNode,this);
01107         if (!UpdateChangedNodes(&ObjChange))
01108         {
01109             FailAndExecute(); End(); return;
01110         }
01111 
01112         // Now we've formed a smoothed path, let's hide the original
01113         CALL_WITH_FAIL( DoHideNode(pThisNode,TRUE), this, ok);
01114         if (!ok)
01115         {
01116             FailAndExecute(); End(); return;
01117         }
01118     }
01119     //pOrigBlend->forOpRetroSmooth = FALSE;
01120     // DoSmoothNodePath(pThisNode,smoothacc),this,ok);
01121     End();
01122 }   
01123 
01124 
01125 
01126 /********************************************************************************************
01127 
01128 >   DynArray::DynArray()
01129 
01130     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01131     Created:    16/11/94
01132     Purpose:    DynArray constructor
01133 
01134 ********************************************************************************************/
01135 
01136 DynArray::DynArray()
01137 {
01138     UsedSlots = 0;
01139     UnusedSlots = 0;
01140     SlotInitSize = 0;
01141     SlotAllocSize = 0;
01142 
01143     BlockHandle = BAD_MHANDLE;
01144 }
01145 
01146 
01147 /********************************************************************************************
01148 
01149 >   DynArray::~DynArray()
01150 
01151     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01152     Created:    16/11/94
01153     Purpose:    Destructor - releases the memory that the template class has 
01154                 been using to store items in.
01155 
01156 ********************************************************************************************/
01157 
01158 DynArray::~DynArray()
01159 {
01160     if (BlockHandle != BAD_MHANDLE)
01161     ReleaseBlock(BlockHandle);
01162 }
01163 
01164 
01165 /********************************************************************************************
01166 
01167 >   BOOL DynArray::Initialise(INT32 inititems, INT32 newitems)
01168 
01169     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01170     Created:    16/11/94
01171     Inputs:     inititems = The number of items of  the list can hold initially
01172                 newitems  = The number of items to allocate for each time we run 
01173                             out of space
01174     Returns:    TRUE if we got all the memory we needed, FALSE if not
01175     Purpose:    Allocates memory for a list to hold a particular type of object
01176     Errors:     Can fail if it runs out of memory. The function will return
01177                 FALSE
01178 
01179 ********************************************************************************************/
01180 
01181 BOOL DynArray::Initialise(INT32 inititems, INT32 newitems)
01182 {
01183     ERROR3IF((newitems & 3),"DynArray::Initialise called with none quad byte 'new' multiple"); 
01184 
01185     if (inititems<12)
01186         inititems=12;
01187 
01188     if (newitems<12)
01189         newitems=12;
01190 
01191     if (BlockHandle == BAD_MHANDLE)
01192         BlockHandle = ClaimBlock(sizeof(ITEM_TYPE)*inititems);
01193     else
01194     {
01195         // some ones initialising an already existant buffer
01196         // so lets just resize it to fit.
01197         INT32 SizeDiff = (UsedSlots+UnusedSlots)    - inititems;
01198         BOOL ok;
01199         if (SizeDiff>0)
01200             ok = IncreaseBlock(BlockHandle,sizeof(ITEM_TYPE)*SizeDiff);
01201         else
01202         {
01203             SizeDiff = -SizeDiff;
01204             ok = DecreaseBlock(BlockHandle,sizeof(ITEM_TYPE)*SizeDiff);
01205         }
01206         if (!ok)
01207             return FALSE;
01208     }
01209     
01210     if (BlockHandle==BAD_MHANDLE)
01211         return FALSE;
01212         
01213     UsedSlots = 0;
01214     UnusedSlots = inititems;
01215     SlotInitSize = inititems;
01216     SlotAllocSize = newitems;
01217 
01218     return TRUE;
01219 }
01220 
01221 
01222 
01223 /********************************************************************************************
01224 
01225 >   TYPE_ITEM* DynArray::GetFirstItem()
01226 
01227     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01228     Created:    16/11/94
01229     Inputs:     -
01230     Returns:    a pointer to the start of this dynamic array.
01231     Purpose:    Get a pointer to the start of this array. The ptr can then be used in
01232                 conjunction with the [] operator to access the stored values with array
01233                 operations.
01234 
01235 ********************************************************************************************/
01236 
01237 ITEM_TYPE* DynArray::GetFirstItem()
01238 {
01239     return ((ITEM_TYPE*)DescribeHandle(BlockHandle));
01240 }
01241 
01242 
01243 
01244 /********************************************************************************************
01245 
01246 >   BOOL DynArray::MakeSpaceInList(const INT32 NumSlots)
01247 
01248     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01249     Created:    16/11/94
01250     Inputs:     NumSlots = the number of slots to ensure free
01251     Returns:    TRUE if NumSlots are now freely available
01252                 FALSE if unable to ensure NumSlots of free space.
01253     Purpose:    Ensure that there are NumSlots free within this dynamic array.
01254 
01255 ********************************************************************************************/
01256 
01257 BOOL DynArray::MakeSpaceInList(const INT32 NumSlots)
01258 {
01259     if (UnusedSlots<NumSlots)
01260     {
01261         INT32 Needed = NumSlots-UnusedSlots+SlotAllocSize;
01262         if (!IncreaseBlock(BlockHandle,sizeof(ITEM_TYPE)*Needed))
01263             return FALSE;
01264         UnusedSlots += Needed;
01265     }
01266     return TRUE;
01267 }
01268 
01269 
01270 /********************************************************************************************
01271 
01272 >   BOOL DynArray::AddItem(ITEM_TYPE& item)
01273 
01274     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01275     Created:    16/11/94
01276     Inputs:     a reference to an item to store in the array
01277     Returns:    TRUE if the item was successfully stored
01278                 FALSE if the item could not be stored due to lack of memory
01279     Purpose:    Store the array item by increasing the size of the array by one item
01280                 and placing the item at this position.
01281 
01282 ********************************************************************************************/
01283 
01284 BOOL DynArray::AddItem(ITEM_TYPE& item)
01285 {
01286     if (!MakeSpaceInList(1))
01287         return FALSE;
01288 
01289     ITEM_TYPE* List = (ITEM_TYPE*) DescribeHandle(BlockHandle);
01290 
01291     List[UsedSlots] = item;
01292 
01293     UsedSlots++;
01294     UnusedSlots--;
01295 
01296     return TRUE;
01297 }
01298 
01299 
01300 
01301 /********************************************************************************************
01302 
01303 >   void DynArray::Empty(BOOL compress = TRUE)
01304 
01305     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01306     Created:    16/11/94
01307     Inputs:     -
01308     Returns:    -
01309     Purpose:    Remove all stored items from this array. All array accesses via the 
01310                 [] operator will now be faulted. Use AddItem() to begin reconstructing
01311                 values in the array.
01312 
01313 ********************************************************************************************/
01314 
01315 void DynArray::Empty(BOOL compress)
01316 {
01317     if (UsedSlots>0)
01318     {
01319         // reset the path definitions
01320         UnusedSlots+=UsedSlots;
01321         UsedSlots=0;
01322 
01323         // make sure we compress memory if necessary
01324         if (compress)
01325             Compact();                      // ignore any error coming from here
01326     }   
01327 }
01328 
01329 
01330 
01331 /********************************************************************************************
01332 
01333 >   void DynArray:::DeleteItems(INT32 firstitem, INT32 numitems)
01334 
01335     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01336     Created:    16/11/94
01337     Inputs:     first item  = an index of the first item to start the deletion at (0..n-1)
01338                 num items   = the number of items to delete (0<=n<=NumItems)
01339     Returns:    -
01340     Purpose:    Delete a set of items from this dynamic array.
01341 
01342                 Example:
01343 
01344                       0 1 2 3 4 5 6 7 8 9                                  0 1 2 3 4 5
01345                 L = [ 9,8,7,6,5,4,3,2,1,0 ]     DeleteItems(3, 4)    L = [ 9,8,7,2,1,0 ]
01346 
01347 ********************************************************************************************/
01348 
01349 void DynArray::DeleteItems(INT32 firstitem, INT32 numitems)
01350 {
01351     ENSURE(firstitem<UsedSlots, "Specified position is off end of array in DynArray::DeleteItems");
01352     ENSURE(firstitem>=0, "Specified position is off begining of array in DynArray::DeleteItems");
01353 
01354     if (numitems<=0)
01355         return;
01356 
01357     ITEM_TYPE* List = (ITEM_TYPE*) DescribeHandle(BlockHandle);
01358 
01359     INT32 Moving = UsedSlots-(firstitem+numitems);
01360 
01361     if (Moving>0)
01362         memmove((void*)(&List[firstitem]), (void*)(&List[firstitem+numitems]), Moving*sizeof(ITEM_TYPE));
01363 
01364     UsedSlots   -= numitems;
01365     UnusedSlots += numitems;
01366 
01367     Compact();
01368 }
01369 
01370 
01371 /********************************************************************************************
01372 
01373 >   void DynArray::Compact()
01374 
01375     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01376     Created:    16/11/94
01377     Inputs:     -
01378     Returns:    -
01379     Purpose:    Checks for excessive amounts of unused space left at the end of a dynamic 
01380                 array, (possibly left from a Empty(FALSE) call)  and removes it. The quantity
01381                 of space removed is always an exact multiple of newitems (See Initialise())
01382 
01383 ********************************************************************************************/
01384 
01385 void DynArray::Compact()
01386 {
01387     INT32 unused = UnusedSlots / SlotAllocSize;
01388     unused-=1;
01389     if (unused>0)
01390     {
01391         if (DecreaseBlock(BlockHandle, sizeof(ITEM_TYPE)*(unused*SlotAllocSize)))
01392             UnusedSlots-=unused*SlotAllocSize;
01393     }
01394 }
01395 
01396 
01397 /********************************************************************************************
01398 
01399 >   ITEM_TYPE& DynArray::operator[](const INT32 i)
01400 
01401     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01402     Created:    16/11/94
01403     Inputs:     i = the index of an item in this dynamic array 
01404     Returns:    A reference to the indexed item in this dynamic array
01405     Purpose:    Overload the array operator to allow array access functionality for this
01406                 dynamic set of items. This functions provides both item reteival and item
01407                 assignment for example
01408                 MyArray[i] = item,      item = MyArray[i]
01409     Errors:     Access or assignment will be faulted if the index i is outside the range
01410                 of items stored in the array.
01411 
01412 ********************************************************************************************/
01413 
01414 ITEM_TYPE& DynArray::operator[](const INT32 i)
01415 {
01416     ENSURE(i>=0 && i<UsedSlots, "index out of range in Template list operator[]");
01417     ITEM_TYPE* List = (ITEM_TYPE*) DescribeHandle(BlockHandle);
01418     return (List[i]);
01419 }
01420 
01421 
01422 /********************************************************************************************
01423 
01424 >   BOOL DynArray::CloneFrom(ITEM_TYPE* SourceArray)
01425 
01426     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01427     Created:    16/11/94
01428     Inputs:     SourceArray = pointer to a source dynamic array 
01429     Returns     TRUE    if successful
01430                 FALSE   if unable in increase the size of this dynamic array to cope with all
01431                         data in the supplied array.
01432     Purpose:    Replace the data within this dynamic array with that of the other array
01433                 supplied
01434 
01435 ********************************************************************************************/
01436 
01437 BOOL DynArray::CloneFrom(DynArray* SourceArray)
01438 {
01439     // Make space to copy all the data from the other path into this one
01440     INT32 SlotsToCopy = SourceArray->UsedSlots;
01441     INT32 SlotsToAdd = SlotsToCopy-UsedSlots;
01442 
01443     if (SlotsToAdd>0)
01444     {
01445         if (!MakeSpaceInList(SlotsToAdd))
01446             return FALSE;
01447     }
01448 
01449     // Get the arrays
01450     ITEM_TYPE* pSource = (ITEM_TYPE*) DescribeHandle(SourceArray->BlockHandle);
01451     ITEM_TYPE* pDestin = (ITEM_TYPE*) DescribeHandle(BlockHandle);
01452 
01453     memmove((void*)(pDestin), (void*)(pSource), SlotsToCopy*sizeof(ITEM_TYPE));
01454 
01455     // Now update the array variables
01456     UsedSlots += SlotsToAdd;
01457     UnusedSlots -= SlotsToAdd;
01458 
01459     return TRUE;
01460 }

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