brshattr.cpp

Go to the documentation of this file.
00001 // $Id: brshattr.cpp 1688 2006-08-10 12:05:20Z gerry $
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 
00099 // Brush Attribute implementation
00100 
00101 #include "camtypes.h"
00102 #include "brshattr.h"
00103 #include "brshcomp.h"
00104 //#include "rik.h"     // for the strings
00105 //#include "basestr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 #include "samplist.h"
00107 
00108 // Native file load/save includes
00109 //#include "camfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 #include "cxftags.h"
00113 //#include "tim.h"          // For _R(IDE_FILE_WRITE_ERROR)
00114 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 
00116 // various includes
00117 #include "lineattr.h"
00118 #include "ndbldpth.h"  // for cpathpointinfo
00119 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "nodepath.h"
00121 #include "blendatt.h"
00122 #include "pbecomea.h"
00123 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 #include "brpress.h"
00125 #include "pen.h"
00126 //#include "colormgr.h"
00127 //#include "freehand.h"
00128 #include "progress.h"
00129 #include "nodetext.h"
00130 #include "nodetxtl.h" // for our text bodges
00131 #include "nodetxts.h"
00132 #include "ppbrush.h"
00133 
00134 #ifdef NEWFASTBRUSHES
00135     #include "nodebmp.h"
00136 #endif
00137 
00138 
00139 CC_IMPLEMENT_DYNCREATE(AttrBrushType, NodeAttribute)
00140 CC_IMPLEMENT_DYNAMIC(BrushAttrValue, AttributeValue)
00141 CC_IMPLEMENT_DYNAMIC(BrushAttrRecordHandler, CamelotRecordHandler);
00142 
00143 
00144 // Declare smart memory handling in Debug builds
00145 #define new CAM_DEBUG_NEW   
00146 
00147 
00148 /*-------------------------------------------------------------------------------------------
00149 ---------------------------------------------------------------------------------------------
00150 --------------------------------BrushAttrValue class implementation--------------------------
00151 --------------------------------------------------------------------------------------------*/
00152 
00153 
00154 /********************************************************************************************
00155 
00156 >   BrushAttrValue::BrushAttrValue(PathProcessorBrush *pPathProcessor = NULL);
00157 
00158     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00159     Created:    13/12/99
00160 
00161     Inputs:     -
00162     Purpose:    Default Constuctor for BrushAttrValue
00163 
00164 ********************************************************************************************/
00165 
00166 BrushAttrValue::BrushAttrValue()
00167 {
00168 #ifdef NEWFASTBRUSHES
00169     pCachedBitmap = NULL;
00170 #endif
00171     m_pProcessor = NULL;
00172 #ifdef BRUSHPOINTSCACHE
00173     m_pCachedPoints = NULL;
00174 #endif
00175     m_pTimeStampList = NULL;
00176     
00177     m_pPressureVals = NULL;
00178     m_CachedBRect = DocRect(0,0,0,0);
00179 
00180     m_pPressureSampler = NULL;
00181 }
00182 
00183 
00184 
00185 /********************************************************************************************
00186 
00187 >   BrushAttrValue::BrushAttrValue(PathProcessorBrush *pPathProcessor = NULL);
00188 
00189     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00190     Created:    13/12/99
00191 
00192     Inputs:     pPathProcessor - the stroke path-processor which will do the stroking
00193                 effect "applied" by this attribute. NULL indicates that this attribute
00194                 does no stroking (i.e. that the path should have an old-style "line")
00195 
00196                 NOTE that this object is NOW OWNED by this BrushAttrValue, and will be
00197                 deleted when the attribute value is deleted.
00198 
00199     Purpose:    Default Constuctor for BrushAttrValue
00200 
00201 ********************************************************************************************/
00202 
00203 BrushAttrValue::BrushAttrValue(PathProcessorBrush *pPathProcessor)
00204 {
00205 #ifdef NEWFASTBRUSHES
00206     pCachedBitmap = NULL;
00207 #endif
00208     // Remember our processor, and let it know that we "own" it
00209     m_pProcessor = pPathProcessor;
00210 //  if (m_pProcessor != NULL)
00211 //      m_pProcessor->SetParentAttribute(this);
00212 #ifdef BRUSHPOINTSCACHE
00213     m_pCachedPoints = NULL;
00214 #endif
00215     m_pTimeStampList = NULL;
00216 
00217 
00218     m_pPressureVals  = NULL;
00219     m_CachedBRect = DocRect(0,0,0,0);
00220 
00221     m_pPressureSampler = NULL;
00222 }
00223 
00224 
00225 /********************************************************************************************
00226 
00227 >   BrushAttrValue::~BrushAttrValue()
00228 
00229     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00230     Created:    13/12/99
00231 
00232     Purpose:    Destructor
00233                 Deletes any attached PathProcessor (see the constructor)
00234 
00235 ********************************************************************************************/
00236 
00237 BrushAttrValue::~BrushAttrValue()
00238 {
00239 #ifdef NEWFASTBRUSHES
00240     if (pCachedBitmap != NULL)
00241     {
00242         delete (pCachedBitmap->GetBitmap ());
00243         delete (pCachedBitmap);
00244         pCachedBitmap = NULL;
00245     }
00246 #endif
00247     if (m_pProcessor != NULL)
00248     {
00249         delete m_pProcessor;
00250         m_pProcessor = NULL;
00251     }
00252     FlushCache();
00253     FlushTimeStampCache();
00254     FlushPressureCache();
00255 
00256 }
00257 
00258 
00259 
00260 /********************************************************************************************
00261 
00262 >   static BOOL BrushAttrValue::Init(void)
00263 
00264     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00265     Created:    13/12/99
00266 
00267     Returns:    TRUE if it initilised successfully
00268 
00269     Purpose:    Registers a default attribute of this type with the attribute manager
00270 
00271 ********************************************************************************************/
00272 
00273 BOOL BrushAttrValue::Init(void)
00274 {
00275     // The default attribute is one that has no effect (i.e. produces old-style "lines")
00276     BrushAttrValue *pAttr = new BrushAttrValue;
00277     if (pAttr == NULL)
00278         return FALSE;
00279 
00280     UINT32 ID = AttributeManager::RegisterDefaultAttribute(CC_RUNTIME_CLASS(AttrBrushType),
00281                                                             pAttr);
00282 
00283     if (ID == ATTR_BAD_ID)
00284         return FALSE;
00285     ENSURE(ID == ATTR_BRUSHTYPE, "Incorrect ID for attribute!");
00286 
00287     //ERROR2IF(ID == ATTR_BAD_ID, FALSE, "Bad ID when Initialising BrushAttrValue");
00288     //ENSURE(ID == ATTR_BRUSHTYPE, "Incorrect Attribute ID");
00289     return(TRUE);
00290 }
00291 
00292 
00293 
00294 /********************************************************************************************
00295 
00296 >   virtual void BrushAttrValue::Render(RenderRegion *pRegion,  BOOL Temp)
00297 
00298     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00299     Created:    13/12/99
00300 
00301     Inputs:     pRegion - the render region to render this attribute into.
00302                 
00303     Purpose:    Sets the BrushAttrValue attribute for the given render region.
00304 
00305     Notes:      This attribute makes itself current in the render region, and
00306                 also (possibly) adds a PathProcessor to handle stroking of
00307                 all future rendered paths (until the attr is "restored")
00308 
00309     SeeAlso:    BrushAttrValue::Restore
00310 
00311 ********************************************************************************************/
00312 
00313 void BrushAttrValue::Render(RenderRegion *pRegion, BOOL Temp)
00314 {
00315     // Stack the current attribute and set ourselves up as the new one
00316     pRegion->SaveAttribute(ATTR_BRUSHTYPE, this, Temp);
00317     
00318 #ifdef BRUSHPOINTSCACHE
00319     // if we don't yet have a cache then make one here
00320     if (m_pCachedPoints == NULL)
00321         InitialisePointsCache();
00322 #endif
00323 
00324     // Find if we have a path processor to do the stroking, and if we do, 
00325     // stack a copy of it (a copy must be used to be thread-safe & bgrender-safe)
00326     if (m_pProcessor != NULL)
00327     {
00328     //  TRACEUSER("Diccon", _T("Rendering brush attribute\n") );
00329     
00330         // make a clone and push it onto the stack
00331         PathProcessorBrush *pNewProcessor = m_pProcessor->Clone();
00332         if (pNewProcessor != NULL)
00333         {
00334             //TRACEUSER("Diccon", _T("Pushing path processor\n") );
00335 #ifdef NEWFASTBRUSHES
00336             pNewProcessor->SetLinkedAttribute (this);
00337 #endif
00338             pRegion->PushPathProcessor(pNewProcessor);
00339         }
00340         
00341     }
00342 }
00343 
00344 
00345 
00346 /********************************************************************************************
00347 
00348 >   virtual void BrushAttrValue::Restore(RenderRegion *pRegion, BOOL Temp)
00349 
00350     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00351     Created:    13/12/99
00352 
00353     Inputs:     pRegion - the render region to restore the attribute into.
00354                 Temp    - TRUE if this is a temporary attribute, FALSE if it is
00355                           permanent (e.g. it's in a document tree).
00356 
00357     Purpose:    Restores the BrushAttrValue attribute for the given render region. 
00358 
00359     Notes:      This attribute makes sure it removes any PathProcessor it added
00360                 to handle path stroking in BrushAttrValue::Render
00361 
00362 ********************************************************************************************/
00363 
00364 void BrushAttrValue::Restore(RenderRegion *pRegion, BOOL Temp)
00365 {
00366     pRegion->RestoreAttribute(ATTR_BRUSHTYPE, this, Temp);
00367 }
00368 
00369 
00370 
00371 /********************************************************************************************
00372 
00373 >   void BrushAttrValue::GoingOutOfScope(RenderRegion *pRegion)
00374 
00375     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00376     Created:    9/1/97
00377 
00378     Inputs:     pRegion - the render region the attribute is in use by
00379 
00380     Purpose:    A sister function to Render()
00381 
00382                 This is called by a render region when an attribute goes out of
00383                 scope, i.e. when the attribute is no longer in use and is popped
00384                 off the stack for the last time. (Do NOT confuse this with being
00385                 pushed onto the render stack when overridden by another attr)
00386 
00387                 It gives the attribute a chance to remove any PathProcessor(s)
00388                 it added to the RenderRegion when it was Render()ed.
00389 
00390     Notes:      This attribute makes sure it removes any PathProcessor it added
00391                 to handle path stroking in BrushAttrValue::Render
00392 
00393     SeeAlso:    BrushAttrValue::Render()
00394 
00395 ********************************************************************************************/
00396 
00397 void BrushAttrValue::GoingOutOfScope(RenderRegion *pRegion)
00398 {
00399     if (m_pProcessor != NULL)
00400     {
00401         //TRACEUSER("Diccon", _T("Popping path processor\n") );
00402         pRegion->PopPathProcessor();
00403     }
00404 }
00405 
00406 
00407 
00408 /********************************************************************************************
00409 
00410 >   virtual void BrushAttrValue::SimpleCopy(AttributeValue *pValue)
00411 
00412     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00413     Created:    13/12/99
00414 
00415     Inputs:     pValue - pointer to the AttributeValue to copy
00416 
00417     Purpose:    See AttributeValue::SimpleCopy
00418 
00419 ********************************************************************************************/
00420 
00421 void BrushAttrValue::SimpleCopy(AttributeValue *pValue)
00422 {
00423     ERROR3IF(!IS_A(pValue, BrushAttrValue),
00424                 "Invalid Attribute value passed to BrushAttrValue::SimpleCopy");
00425 
00426     // Just uses the assignment operator
00427     *this = *((BrushAttrValue *) pValue);
00428 
00429 
00430 
00431 }
00432 
00433 /********************************************************************************************
00434 
00435 >   BOOL BrushAttrValue::Blend(BlendAttrParam* pBlendParam)
00436 
00437     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00438     Created:    17/3/2000
00439     Inputs:     pBlendParam - contains the blend info, 
00440     Outputs:    pBlendParama -  containing the blended attributes
00441     Returns:    TRUE - Blend went ok, the blended attr val is valid; FALSE if not.
00442     Purpose:    Blends between two brush attributes. In fact at the moment it just blends
00443                 between the parameters in the two path processors.  At some point it should
00444                 also blend between the ink objects and attributes.
00445             
00446     Errors:     Out of memory.
00447 
00448 ********************************************************************************************/
00449 
00450 BOOL BrushAttrValue::Blend(BlendAttrParam* pBlendParam)
00451 {
00452     ERROR2IF(pBlendParam == NULL, FALSE, "BlendAttrParam is NULL in BrushAttrValue::Blend");
00453 
00454     // First get the fill that we are blending to
00455     BrushAttrValue* pOtherBrush = 
00456                 (BrushAttrValue*)pBlendParam->GetOtherAttrVal();
00457     if (pOtherBrush == NULL)
00458         return FALSE;
00459 
00460     // it is ok if we have null path processors as that merely indicates a default line
00461     PathProcessorBrush* pOtherPPB = pOtherBrush->GetPathProcessor();
00462     PathProcessorBrush* pThisPPB = GetPathProcessor();
00463 
00464     // Now make a new object of the same type as this one
00465     //CCRuntimeClass* ObjectType = GetRuntimeClass();
00466     BrushAttrValue* pNewAttr = new BrushAttrValue; //(BrushAttrValue*)ObjectType->CreateObject();
00467 
00468     if (pNewAttr == NULL)
00469     {
00470         // Fail if we couldn't create the new fill
00471         pBlendParam->SetBlendedAttrVal(NULL);
00472         return FALSE;
00473     }
00474 
00475     // Make the new fill an exact copy of this one
00476     pNewAttr->SimpleCopy(this);
00477 
00478     // make a new path processor
00479     PathProcessorBrush* pBlendedPPB = new PathProcessorBrush;
00480     
00481     if (pBlendedPPB == NULL)
00482     {
00483         delete pNewAttr;
00484         return FALSE;
00485     }
00486     
00487     pBlendedPPB->SetBrushDefinition(BrushHandle_NoBrush);
00488 
00489     // find out what point along the blend we are at
00490     double BlendRatio = pBlendParam->GetBlendRatio();
00491 
00492     // we need to ask the brush component to make a blended brush definition for us
00493     Document* pDoc = Document::GetCurrent();
00494     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
00495     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
00496     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");  
00497     
00498     // don't want to blend the variables any more, lets just copy them
00499     BrushDefinition* pThisDef = GetBrushDefinition();
00500     BrushDefinition* pOtherDef = pOtherBrush->GetBrushDefinition();
00501     BrushHandle ThisHandle = BrushHandle_NoBrush;
00502     BrushHandle OtherHandle = BrushHandle_NoBrush;
00503 
00504     if (pThisPPB != NULL)
00505         ThisHandle = pThisPPB->GetBrushDefinitionHandle();
00506 
00507     if (pOtherPPB != NULL)
00508         OtherHandle = pOtherPPB->GetBrushDefinitionHandle();
00509     
00510     if (BlendRatio <= 0.5)
00511     {
00512         {
00513             if (pThisDef != NULL)
00514             {
00515                 // if we have a ppb then copy the data across
00516                 if (pThisPPB != NULL)
00517                 {
00518                     BrushData ThisData;
00519                     pThisPPB->CopyBrushData(&ThisData);
00520                     pBlendedPPB->CopyDataFromObject(&ThisData); 
00521                 }
00522                 else // otherwise go with the definition
00523                     pThisDef->CopyDataToProcessor(pBlendedPPB);
00524                 
00525                 pBlendedPPB->SetBrushDefinition(GetBrushHandle());
00526                 pBlendedPPB->SetMaxScaling(pThisDef->GetMaxScaling());
00527             }
00528             else
00529             {
00530                 // turns out we're not really a brush so delete our processor
00531                 delete pBlendedPPB;
00532                 pBlendedPPB = NULL;
00533             }
00534         }
00535     }
00536     else
00537     {
00538     /*  if (ThisHandle == OtherHandle)
00539         {
00540             if (pOtherPPB != NULL)
00541             {
00542                 delete pBlendedPPB;
00543                 pBlendedPPB = pOtherPPB->Clone();
00544             }
00545             //pBlendedPPB->SetBrushDefinition(BrushHandle_NoBrush);
00546         }
00547         else */
00548         {
00549             if (pOtherDef != NULL)
00550             {
00551                 if (pOtherPPB != NULL)
00552                 {
00553                     BrushData OtherData;
00554                     pOtherPPB->CopyBrushData(&OtherData);
00555                     pBlendedPPB->CopyDataFromObject(&OtherData);
00556 
00557                     // little hack that we need to ensure the scaling is correct
00558                     AttrBrushType* pAttrBrush = pOtherPPB->GetParentAttribute();
00559                     if (pAttrBrush != NULL)
00560                     {
00561                         MILLIPOINT LineWidth = pAttrBrush->GetAppliedLineWidth();
00562                         pOtherPPB->ScaleToValue(LineWidth);
00563                     }
00564 
00565                 }
00566                 else
00567                     pOtherDef->CopyDataToProcessor(pBlendedPPB);
00568                 pBlendedPPB->SetMaxScaling(pOtherDef->GetMaxScaling());
00569             }
00570             else
00571             {
00572                 // special case to deal with blend between a brushed and non=brushed object
00573                 delete pBlendedPPB;
00574                 pBlendedPPB = NULL;
00575                 pNewAttr->SetPathProcessor(NULL);
00576                 pBlendParam->SetBlendedAttrVal(pNewAttr);
00577                 return TRUE;
00578             }
00579             pBlendedPPB->SetBrushDefinition(pOtherBrush->GetBrushHandle());
00580         }
00581     }
00582 
00583     // trudge through all the variables and blend them
00584     /*
00585     // blend scaling variables
00586     double BlendedScaling = BlendDouble(m_pProcessor->GetBrushScaling(), pOtherPPB->GetBrushScaling(), BlendRatio);
00587     pBlendedPPB->SetBrushScaling(BlendedScaling);
00588     double BlendedScalingIncr = BlendDouble(m_pProcessor->GetBrushScalingIncr(), pOtherPPB->GetBrushScalingIncr(), BlendRatio);
00589     pBlendedPPB->SetBrushScalingIncr(BlendedScalingIncr);
00590 
00591     // blend spacing variables
00592     MILLIPOINT BlendedSpacing = BlendINT32(m_pProcessor->GetSpacing(), pOtherPPB->GetSpacing(), BlendRatio);
00593     pBlendedPPB->SetSpacing(BlendedSpacing);
00594     MILLIPOINT BlendedSpacingIncrConst = BlendINT32(m_pProcessor->GetSpacingIncrConst(), pOtherPPB->GetSpacingIncrConst(), BlendRatio);
00595     pBlendedPPB->SetSpacingIncrConst(BlendedSpacingIncrConst);
00596     double BlendedSpacingIncrProp = BlendDouble(m_pProcessor->GetSpacingIncrProp(), pOtherPPB->GetSpacingIncrProp(), BlendRatio);
00597     pBlendedPPB->SetSpacingIncrProp(BlendedSpacingIncrProp);
00598     UINT32 BlendedSpacingMaxRand = BlendUINT32(m_pProcessor->GetSpacingMaxRand(), pOtherPPB->GetSpacingMaxRand(), BlendRatio);
00599     pBlendedPPB->SetSpacingMaxRand(BlendedSpacingMaxRand);
00600 
00601     // for the random seed don't blend, just use one or the other 
00602     if (BlendRatio <= 0.5)
00603         pBlendedPPB->SetSpacingRandSeed(m_pProcessor->GetSpacingRandSeed());
00604     else
00605         pBlendedPPB->SetSpacingRandSeed(pOtherPPB->GetSpacingRandSeed());
00606 
00607     // Offset variables
00608     MILLIPOINT BlendedOffsetValue = BlendINT32(m_pProcessor->GetPathOffsetValue(), pOtherPPB->GetPathOffsetValue(), BlendRatio);
00609     pBlendedPPB->SetPathOffsetValue(BlendedOffsetValue);
00610     MILLIPOINT BlendedOffsetIncrConst = BlendINT32(m_pProcessor->GetPathOffsetIncrConst(), pOtherPPB->GetPathOffsetIncrConst(), BlendRatio);
00611     pBlendedPPB->SetPathOffsetIncrConst(BlendedOffsetIncrConst);
00612     double BlendedOffsetIncrProp = BlendDouble(m_pProcessor->GetPathOffsetIncrProp(), pOtherPPB->GetPathOffsetIncrProp(), BlendRatio);
00613     pBlendedPPB->SetPathOffsetIncrProp(BlendedOffsetIncrProp);
00614     UINT32 BlendedOffsetMaxRand = BlendUINT32(m_pProcessor->GetOffsetValueMaxRand(), pOtherPPB->GetOffsetValueMaxRand(), BlendRatio);
00615     pBlendedPPB->SetOffsetValueMaxRand(BlendedOffsetMaxRand);
00616 
00617     // don't blend offset type, just use one or the other, likewise random seed
00618     if (BlendRatio <= 0.5)
00619     {
00620         pBlendedPPB->SetPathOffsetType(m_pProcessor->GetPathOffsetType());
00621         pBlendedPPB->SetOffsetTypeRandSeed(m_pProcessor->GetOffsetTypeRandSeed());
00622         pBlendedPPB->SetOffsetValueRandSeed(m_pProcessor->GetOffsetValueRandSeed());
00623     }
00624     else
00625     {
00626         pBlendedPPB->SetPathOffsetType(pOtherPPB->GetPathOffsetType());
00627         pBlendedPPB->SetOffsetTypeRandSeed(pOtherPPB->GetOffsetTypeRandSeed());
00628         pBlendedPPB->SetOffsetValueRandSeed(pOtherPPB->GetOffsetValueRandSeed());
00629     }
00630 
00631     // rotation 
00632     double BlendedRotateAngle = BlendDouble(m_pProcessor->GetRotationAngle(), pOtherPPB->GetRotationAngle(), BlendRatio);
00633     pBlendedPPB->SetRotationAngle(BlendedRotateAngle);
00634     
00635     // do all the flags at once
00636     if (BlendRatio <= 0.5)
00637     {
00638         pBlendedPPB->SetRotated(m_pProcessor->IsRotated());
00639         pBlendedPPB->SetTiling(m_pProcessor->IsTiled());
00640         pBlendedPPB->SetUseLocalFillColour(m_pProcessor->GetUseLocalFillColour());
00641         pBlendedPPB->SetScaleToLineWidth(m_pProcessor->IsScalingToLineWidth());
00642         pBlendedPPB->SetBrushDefinition(m_pProcessor->GetBrushDefinitionHandle());
00643     }
00644     else
00645     {
00646         pBlendedPPB->SetRotated(pOtherPPB->IsRotated());
00647         pBlendedPPB->SetTiling(pOtherPPB->IsTiled());
00648         pBlendedPPB->SetUseLocalFillColour(pOtherPPB->GetUseLocalFillColour());
00649         pBlendedPPB->SetScaleToLineWidth(pOtherPPB->IsScalingToLineWidth());
00650         pBlendedPPB->SetBrushDefinition(pOtherPPB->GetBrushDefinitionHandle());
00651     }
00652     */
00653     // whew, think thats the lot, now attach the processor to the new attribute
00654     pNewAttr->SetPathProcessor(pBlendedPPB);
00655 
00656     // and attach the attribute to the blend param
00657     pBlendParam->SetBlendedAttrVal(pNewAttr);
00658 
00659     return TRUE;
00660 }
00661 
00662 
00663 
00664 /********************************************************************************************
00665 
00666 >   BOOL BrushAttrValue::DoBecomeA(BecomeA* pBecomeA, Node* pParent)
00667 
00668     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00669     Created:    17/3/2000
00670     Inputs:     pBecomeA - the object that tells us what to become, and recieves the results
00671                 pParent - the node that this attribute is applied to
00672     Outputs:    
00673     Returns:    TRUE if everything went ok,
00674     Purpose:    To convert our brush into its individual paths and attributes, works in a very
00675                 similar way to the bounding box, by finding the paths of our parent node and
00676                 asking our path processor to do the calculations
00677         
00678 ********************************************************************************************/
00679 
00680 BOOL BrushAttrValue::DoBecomeA(BecomeA* pBecomeA, Node* pParent)
00681 {
00682     ERROR2IF(pBecomeA == NULL, FALSE, "BecomeA pointer is NULL in BrushAttrValue::DoBecomeA");
00683     ERROR2IF(pParent == NULL, FALSE, "Parent node is NULL in BrushAttrValue::DoBecomeA");
00684 
00685     if (m_pProcessor == NULL)
00686         return FALSE;
00687 
00688     BOOL Success = FALSE;
00689 //  UINT32 Dummy = 0;
00690     // if we have a nodepath then we can simply use its member path, otherwise we
00691     // have to ask it to become a nodepath
00692     if (pParent->IsNodePath())
00693     {   
00694         // we have a special calculation for nodepaths, because we can use their path
00695         Success =  m_pProcessor->DoBecomeA(pBecomeA, &((NodePath*)pParent)->InkPath, pParent);
00696     }
00697     else
00698     {
00699         BecomeA TestBecomeAPath(BECOMEA_TEST, CC_RUNTIME_CLASS(NodePath));
00700         if (pParent->CanBecomeA(&TestBecomeAPath))
00701         {
00702             // we must be applied to some arbitrary shape.  The thing is that we need to have
00703             // a path to pass to the PPB, so want to get a passback of all the paths in 
00704             // the node 
00705             
00706             // we need to allocate a path
00707             Path* pPath = new Path;
00708             if (pPath != NULL && pPath->Initialise())
00709             {
00710                 PathBecomeA BecomeAPath(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), NULL, FALSE, pPath);
00711                 if (pParent->DoBecomeA(&BecomeAPath))
00712                 {
00713                     Success =  m_pProcessor->DoBecomeA(pBecomeA, pPath, pParent);
00714                 }
00715                 delete pPath;
00716             }
00717         }
00718     }
00719     return Success;
00720 }
00721 
00722 /********************************************************************************************
00723 
00724 >   static UINT32 BrushAttrValue::BlendUINT32(UINT32 First, UINT32 Second, double BlendRatio)
00725 
00726     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00727     Created:    13/12/99
00728     Inputs:     First - the first number to blend
00729                 Second - the second number to blend
00730                 BlendRatio - the proportion of first to second number
00731     Returns:    the blended result
00732 
00733     Purpose:    to blend between two numbers and return the result
00734 
00735 ********************************************************************************************/
00736 
00737 UINT32 BrushAttrValue::BlendUINT32(UINT32 First, UINT32 Second, double BlendRatio)
00738 {   
00739     double InvRatio = 1 - BlendRatio;
00740     double BlendedVal = ((double)First * InvRatio) + ((double)Second*BlendRatio);
00741 
00742     return (UINT32)BlendedVal;
00743 }
00744 
00745 
00746 /********************************************************************************************
00747 
00748 >   static INT32 BrushAttrValue::BlendINT32(INT32 First, INT32 Second, double BlendRatio)
00749 
00750     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00751     Created:    13/12/99
00752     Inputs:     First - the first number to blend
00753                 Second - the second number to blend
00754                 BlendRatio - the proportion of first to second number
00755     Returns:    the blended result
00756 
00757     Purpose:    to blend between two numbers and return the result
00758 
00759 ********************************************************************************************/
00760 
00761 INT32 BrushAttrValue::BlendINT32(INT32 First, INT32 Second, double BlendRatio)
00762 {
00763     double InvRatio = 1 - BlendRatio;
00764     double BlendedVal = ((double)First * InvRatio) + ((double)Second*BlendRatio);
00765 
00766     return (INT32)BlendedVal;
00767 
00768 }
00769 
00770 
00771 /********************************************************************************************
00772 
00773 >   static double BrushAttrValue::BlendDouble(double First, double Second, double BlendRatio)
00774 
00775     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00776     Created:    13/12/99
00777     Inputs:     First - the first number to blend
00778                 Second - the second number to blend
00779                 BlendRatio - the proportion of first to second number
00780     Returns:    the blended result
00781 
00782     Purpose:    to blend between two numbers and return the result
00783 
00784 ********************************************************************************************/
00785 
00786 double BrushAttrValue::BlendDouble(double First, double Second, double BlendRatio)
00787 {
00788     double InvRatio = 1 - BlendRatio;
00789     double BlendedVal = ((double)First * InvRatio) + ((double)Second*BlendRatio);
00790 
00791     return BlendedVal;
00792 
00793 }
00794 
00795 
00796 /********************************************************************************************
00797 
00798 >   void BrushAttrValue::InitialisePointsCache()
00799 
00800     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00801     Created:    13/12/99
00802 
00803     Inputs:     -
00804 
00805     Purpose:    allocates the map to store cached points
00806 
00807 ********************************************************************************************/
00808 
00809 void BrushAttrValue::InitialisePointsCache()
00810 {
00811     
00812 #ifdef BRUSHPOINTSCACHE
00813     // get rid of the existing one (if there is one)
00814     FlushCache();
00815     //allocate a new map
00816     m_pCachedPoints = new PointsMap;
00817 PORTNOTE("other","Not use hash based map, InitHashTable makes no sense")
00818 #ifndef EXCLUDE_FROM_XARALX
00819     if (m_pCachedPoints != NULL)
00820         m_pCachedPoints->InitHashTable(1277);       // Init hash table size to a suitably large prime number
00821 #endif
00822 #endif
00823     
00824 }
00825 
00826 
00827 /********************************************************************************************
00828 
00829 >   void BrushAttrValue::SetPointsCache(PointsMap * pMap)
00830 
00831     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00832     Created:    13/12/99
00833 
00834     Inputs:     pointer to list to use as cache
00835 
00836     Purpose:    sets the cache member variable
00837 ********************************************************************************************/
00838 
00839 void BrushAttrValue::SetCache(PointsMap* pMap)
00840 {
00841 #ifdef BRUSHPOINTSCACHE
00842     FlushCache();
00843     m_pCachedPoints = pMap;
00844 #endif
00845 }
00846 
00847 
00848 /********************************************************************************************
00849 
00850 >   void BrushAttrValue::SetPressureCache(CDistanceSampler *pSampler)
00851 
00852     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00853     Created:    13/12/99
00854 
00855     Inputs:     pointer to array to use as cache
00856 
00857     Purpose:    sets the pressure array memeber variable
00858 ********************************************************************************************/
00859 
00860 void BrushAttrValue::SetPresssureCache(CDistanceSampler *pSampler)
00861 {
00862     // Do we want to delete any existing cache?
00863     if (m_pPressureSampler != NULL)
00864     {
00865         delete m_pPressureSampler;
00866     }
00867     m_pPressureSampler = pSampler;
00868 }
00869 
00870 
00871 /********************************************************************************************
00872 
00873 >   void BrushAttrValue::FlushPressureCache()
00874 
00875     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00876     Created:    13/12/99
00877     Inputs:     -
00878     Returns:    -
00879     Purpose:    clears out and deletes the cache of pressure values
00880 ********************************************************************************************/
00881 
00882 void BrushAttrValue::FlushPressureCache()
00883 {
00884     if (m_pPressureSampler != NULL)
00885     {
00886         delete m_pPressureSampler;
00887         m_pPressureSampler = NULL;
00888     }
00889 }
00890 /********************************************************************************************
00891 
00892 >   PressureArray* BrushAttrValue::GetPressureCache()
00893 
00894     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00895     Created:    13/12/99
00896 
00897     Returns:    the pressure cache
00898 
00899     Purpose:    as above
00900 ********************************************************************************************/
00901 
00902 CDistanceSampler* BrushAttrValue::GetPressureCache()
00903 {
00904     return m_pPressureSampler;
00905 }
00906 
00907 
00908 /********************************************************************************************
00909 
00910 >   UINT32 BrushAttrValue::GetPressureValue(UINT32 Index)
00911 
00912     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00913     Created:    13/12/99
00914 
00915     Returns:    the pressure value at that index, or PRESSURE_INVALID if index is out of range
00916 
00917     Purpose:    as above
00918 ********************************************************************************************/
00919 
00920 UINT32 BrushAttrValue::GetPressureValue(UINT32 Index)
00921 {
00922     if (m_pPressureVals == NULL)
00923         return PRESSURE_INVALID;
00924     if (Index >= (UINT32)m_pPressureVals->size())
00925         return PRESSURE_INVALID;
00926 
00927     PressureItem Item = (*m_pPressureVals)[Index];
00928     return Item.m_Pressure;
00929 }
00930 
00931 
00932 /********************************************************************************************
00933 
00934 >   BOOL BrushAttrValue::SetPressureValue(UINT32 Index, UINT32 Value)
00935 
00936     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00937     Created:    13/12/99
00938     Inputs:     Index - the index in to the array
00939                 Value - the value to set
00940     Returns:    TRUE if all went well
00941 
00942     Purpose:    as above
00943 ********************************************************************************************/
00944 
00945 BOOL BrushAttrValue::SetPressureValue(UINT32 Index, PressureItem Value)
00946 {
00947     if (m_pPressureVals == NULL)
00948         return FALSE;
00949 
00950     size_t              NumValues = m_pPressureVals->size();
00951     if (Index > NumValues)
00952         return FALSE;
00953 
00954     // if index is one greater than our current size then we can expanf
00955     if (Index == NumValues)
00956         m_pPressureVals->push_back( Value );
00957     else
00958         (*m_pPressureVals)[Index] = Value;
00959 
00960     return FALSE;
00961 }
00962 
00963 
00964 
00965 
00966 /********************************************************************************************
00967 
00968 >   static void BrushAttrValue::ShuffleArrayUp(PressureArray* pArray, UINT32 StartIndex)
00969 
00970     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00971     Created:    13/12/99
00972     Inputs:     pArray - the array to shuffle
00973                 StartIndex - the index to shuffle from
00974                 
00975     Returns:    -
00976 
00977     Purpose:    shuffles each element in the array up by one, assumes that there is already 
00978                 a spare element at the top of the array.
00979 ********************************************************************************************/
00980 
00981 void BrushAttrValue::ShuffleArrayUp(PressureArray* pPressure, UINT32 StartIndex)
00982 {
00983     if (pPressure == NULL)
00984     {
00985         ERROR3("Pressure array is NULL");
00986         return;
00987     }
00988 
00989     size_t              NumValues = pPressure->size();
00990     if (StartIndex >= NumValues)
00991     {
00992         ERROR3("Start index is greater than size of array");
00993         return;
00994     }
00995     
00996     // we count down from the top value and move
00997     // each one up, recall that the extra array element has already been allocated
00998     PressureItem Item;
00999     for( size_t i = NumValues - 2; i >= StartIndex; i-- )
01000     {
01001         Item = (*pPressure)[i];
01002     //  if (i+1 >= NumValues)
01003     //  {
01004     //      TRACEUSER("Diccon", _T("Adding array element at %d\n"), i+1);
01005     //      pPressure->SetAtGrow(i+1, Item);
01006     //  }
01007     //  else
01008             (*pPressure)[i] = Item;
01009     }
01010 }
01011 
01012 
01013 
01014 /********************************************************************************************
01015 
01016 >   void BrushAttrValue::CalculatePressureArrayProportionalDistances(MILLIPOINT PathLength)
01017 
01018     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01019     Created:    13/12/99
01020     Inputs:     The length of the path to which this attribute applies
01021     Returns:    -
01022     Purpose:    Only use when we are utilising the path stamping cache.  This fn. proceeds
01023                 through the list and works out the proportional distance along the path for
01024                 each object.
01025     See Also:   TimeStampBrushPoint 
01026 ********************************************************************************************/
01027 
01028 void BrushAttrValue::CalculatePressureArrayProportions(MILLIPOINT PathLength)
01029 {
01030     if (m_pPressureVals == NULL || PathLength <= 0)
01031     {
01032         ERROR3("Error in calculating proportional distance");
01033         return;
01034     }
01035     PressureItem Item;
01036     for (size_t i = 0; i < m_pPressureVals->size(); i++)
01037     {
01038         Item = (*m_pPressureVals)[i];
01039         if (Item.m_Distance > PathLength)
01040             ERROR3("Item distance is greater than path length in BrushAttrValue::CalculatePressureArrayProportions");
01041         Item.m_Proportion = Item.m_Distance  / (double) PathLength;
01042         (*m_pPressureVals)[i] =  Item;
01043     }
01044 }
01045 
01046 /********************************************************************************************
01047 
01048 >   bool BrushAttrValue::DeletePressurePoints(MILLIPOINT Start, MILLIPOINT End, SampleArray* pRemovedPoints)
01049 
01050     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01051     Created:    6/10/99
01052     Inputs:     Start - distance from which to delete
01053                 End - the distance to stop deleting at
01054                 pRemovedPoints - an array to put the deleted points in (defaults to null)
01055     Returns:    TRUE if successful, FALSE if not
01056     Purpose:    removes points from the Pressure Sampler list between the provided distances
01057     SeeAlso:    -
01058 
01059 ********************************************************************************************/
01060 
01061 BOOL BrushAttrValue::DeletePressurePoints(MILLIPOINT StartDistance, MILLIPOINT EndDistance, 
01062                                            SampleArray* pRemovedPoints)
01063 {
01064     if (StartDistance <0 || EndDistance < 0 || EndDistance <= StartDistance)
01065     {
01066         ERROR3("Invalid inputs to BrushAttrValue::DeletePressureingPoints");
01067         return FALSE;
01068     }
01069 
01070     if (m_pPressureSampler == NULL)
01071         return FALSE;
01072 
01073     // find out what indexes correspond to our distances
01074     INT32 StartIndex = m_pPressureSampler->GetInternalIndexFromDistance(StartDistance);
01075     INT32 EndIndex   = m_pPressureSampler->GetInternalIndexFromDistance(EndDistance);
01076 
01077     if (StartIndex == -1 || EndIndex == -1)
01078     {
01079         ERROR3("Attempting to remove from over the end of the array");
01080         return FALSE;
01081     }
01082     INT32 NumPoints = EndIndex - StartIndex;
01083     if (NumPoints == 0)
01084         return TRUE;  // ours not to reason why...
01085 
01086     // set the size of the sample array
01087     if (pRemovedPoints != NULL)
01088         pRemovedPoints->resize( NumPoints );
01089 
01090     // ask the sampler to do its thing
01091     return m_pPressureSampler->RemoveData(StartIndex, EndIndex, pRemovedPoints);
01092 }
01093 
01094 
01095 /********************************************************************************************
01096 
01097 >   bool BrushAttrValue::DeletePressurePoints(MILLIPOINT Start, UINT32 NumPoints, PressureList* pList = NULL) 
01098 
01099     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01100     Created:    6/10/99
01101     Inputs:     StartIndex - the index where we want to start deleting
01102                 NumPoints - the number to delete
01103                 pRemovedPoints - an array to put the deleted points in (defaults to null)
01104     Returns:    TRUE if successful, FALSE if not
01105     Purpose:    removes points from the Pressure Sampler between the provided distances
01106     SeeAlso:    -
01107 
01108 ********************************************************************************************/
01109 
01110 BOOL BrushAttrValue::DeletePressurePoints(UINT32 StartIndex, size_t NumPoints, 
01111                                            SampleArray* pRemovedPoints)
01112 {
01113     if (NumPoints < 1)
01114     {
01115         TRACEUSER( "Diccon", _T("Num points = %d in DeletePressurePoints\n"), NumPoints);
01116         return FALSE;
01117     }
01118 
01119     if (m_pPressureSampler == NULL)
01120         return FALSE;
01121 
01122     UINT32 EndIndex = StartIndex + NumPoints;
01123 
01124     // check that this doesn't overrun the array
01125     if (EndIndex > m_pPressureSampler->GetNumItems())
01126     {
01127         ERROR3("Attempting to remove over the end of the array");
01128         return FALSE;
01129     }
01130 
01131     // set the size of the sample array
01132     if (pRemovedPoints != NULL)
01133         pRemovedPoints->resize( NumPoints );
01134 
01135     // set the retrieval rate
01136     m_pPressureSampler->SetRetrievalSampleRate(1.0);
01137 
01138     // ask the sampler to do its thing
01139     return m_pPressureSampler->RemoveData(StartIndex, EndIndex, pRemovedPoints);
01140     
01141 }
01142 
01143 
01144 /********************************************************************************************
01145 
01146 >   bool Bru5shAttrValue::AddPressurePoints(PressureList* pNewPoints, MILLIPOINT Start) 
01147 
01148     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01149     Created:    6/10/99
01150     Inputs:     pNewPoints - the points to add
01151                 Start - distance from which to add the points, note that if this is negative then
01152                 all the new points will be added to the very start
01153             
01154     Returns:    TRUE if successful, FALSE if not
01155     Purpose:    inserts the list of points after the distance given
01156     SeeAlso:    -
01157 
01158 ********************************************************************************************/
01159     
01160 BOOL BrushAttrValue::AddPressurePoints(CSampleData* pNewPoints, MILLIPOINT StartDistance)
01161 {
01162     // couple of checks
01163     if (pNewPoints == NULL)
01164     {
01165         ERROR3("Invalid inputs to BrushAttrValue::AddPressurePoints");
01166         return FALSE;
01167     }
01168 
01169     if (m_pPressureSampler == NULL)
01170         return FALSE;
01171     
01172     // find out where we're inserting
01173     INT32 StartIndex = m_pPressureSampler->GetInternalIndexFromDistance(StartDistance);
01174     if (StartIndex == -1)
01175     {
01176         ERROR3("Attempting to insert over the end of the array in BrushAttrValue::AddPressurePoints");
01177         return FALSE;
01178     }
01179 
01180     // ask the sampler to insert for us
01181     return m_pPressureSampler->InsertNewData((UINT32)StartIndex, pNewPoints);
01182 }
01183 
01184 
01185 /********************************************************************************************
01186 
01187 >   BOOL BrushAttrValue::AddPressurePoints(PressureList* pNewPoints, UINT32 StartIndex)
01188 
01189     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01190     Created:    6/10/99
01191     Inputs:     pNewPoints - the points to add
01192                 StartIndex - the TimeStampList::iterator    in the list where we want to insert the new points
01193             
01194     Returns:    TRUE if successful, FALSE if not
01195     Purpose:    inserts the list of points after the index given
01196     SeeAlso:    -
01197 
01198 ********************************************************************************************/
01199     
01200 BOOL BrushAttrValue::AddPressurePoints(CSampleData* pNewPoints, UINT32 StartIndex)
01201 {
01202     if (pNewPoints == NULL)
01203     {
01204         ERROR3("Invalid inputs to BrushAttrValue::AddPressurePoints");
01205         return FALSE;
01206     }
01207 
01208     if (m_pPressureSampler == NULL)
01209         return FALSE;
01210 
01211     if (StartIndex > m_pPressureSampler->GetNumItems())
01212     {
01213         ERROR3("Attempting to insert over the end of the array in BrushAttrValue::AddPressurePoints");
01214         return FALSE;
01215     }
01216 
01217     return m_pPressureSampler->InsertNewData(StartIndex, pNewPoints);
01218 }
01219 
01220 
01221 
01222 
01223 /********************************************************************************************
01224 
01225 >   void BrushAttrValue::SetPressureUpdateType(ListUpdateType Update) 
01226 
01227     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01228     Created:    6/10/99
01229     Inputs:     Update can be:
01230                 UPDATE_NONE, 
01231                 UPDATE_LIST - means that points have been added or removed to the Pressureing list
01232                 UPDATE_PROPORTION - means that the underlying path has changed but our list has not
01233                 UPDATE_TimeStampList::iterator  - means (usually) that the path has been reversed but our points are the same
01234                 UPDATE_LISTANDTimeStampList::iterator   - take a guess
01235     Returns:    -
01236     Purpose:    These flags determine what will happen in the NodePathUpdate function which is called
01237                 after the freehand/brush or bezier tool is used to edit a brushed nodepath
01238     SeeAlso:    -
01239 
01240 ********************************************************************************************/
01241 
01242 void BrushAttrValue::SetPressureUpdateType(ListUpdateType Update)
01243 {
01244     m_PressureUpdateType = Update;
01245 }
01246 
01247 
01248 /********************************************************************************************
01249 
01250 >   ListUpdateType GetPressureUpdateType()
01251 
01252     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01253     Created:    6/10/99
01254     Inputs:     -
01255     Returns:    the member, described above
01256     Purpose:    As above
01257     SeeAlso:    -
01258 
01259 ********************************************************************************************/
01260 
01261 ListUpdateType BrushAttrValue::GetPressureUpdateType()
01262 {
01263     return m_PressureUpdateType;
01264 }
01265 
01266 
01267         
01268 /********************************************************************************************
01269 
01270 
01271 >   BOOL BrushAttrValue::CopyPressureList()
01272 
01273     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01274     Created:    22/5/2000
01275     Inputs:     -
01276     Returns:    pointer to a newly allocated pressure cache, or NULL if it fails
01277     Purpose:    To make a carbon copy of our pressure cache and all the items in it. To be used
01278                 as part of the operator= sequence.
01279 
01280     SeeAlso:    BrushAttrValue::operator=
01281 ********************************************************************************************/
01282 
01283 CDistanceSampler* BrushAttrValue::CopyPressureCache()
01284 {
01285     if (m_pPressureSampler == NULL)
01286         return NULL;
01287 
01288     return m_pPressureSampler->MakeCopy();
01289 }
01290 
01291 
01292 
01293 /********************************************************************************************
01294 
01295 >   INT32 BrushAttrValue::GetPressureListIndexAtDistance(MILLIPOINT Distance)
01296 
01297     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01298     Created:    23/5/2000
01299     Inputs:     Distance - the distance along the path that we wish to find the pressure
01300                 list index for
01301             
01302     Returns:    the index into our pressure list, or -1 for an error
01303     Purpose:    Finds the pressure list index corresponding to the brush object that would
01304                 appear at Distance along the brushed path.  Or rather asks the processor to 
01305                 do it.
01306     SeeAlso:    PathProcessorBrush::GetObjectCountToDistance
01307 
01308 ********************************************************************************************/
01309     
01310 INT32 BrushAttrValue::GetPressureListIndexAtDistance(MILLIPOINT Distance)
01311 {
01312     // some safety checks
01313     if (m_pPressureSampler == NULL)
01314         return -1;
01315 
01316     if (Distance < 0 )
01317         return -1;
01318 
01319     if (m_pProcessor == NULL)
01320         return -1;
01321 
01322     INT32 Index = m_pPressureSampler->GetInternalIndexFromDistance(Distance);
01323     
01324     return Index;
01325 }
01326 
01327 
01328 /*------------------------------------------------------------------------------------------
01329 ------------Time Stamp List functions---------------------------------------------------------
01330 --------------------------------------------------------------------------------------------*/
01331 
01332 
01333 /********************************************************************************************
01334 
01335 >   void BrushAttrValue::SetTimeStampList(TimeStampList* pList)
01336 
01337     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01338     Created:    13/12/99
01339 
01340     Inputs:     pointer to list to use as cache
01341 
01342     Purpose:    sets the timestamp cache member variable
01343 ********************************************************************************************/
01344 
01345 void BrushAttrValue::SetTimeStampList(TimeStampList* pList)
01346 {
01347     m_pTimeStampList = pList;
01348 }
01349 
01350 
01351 /********************************************************************************************
01352 
01353 >   BOOL BrushAttrValue::IsTimeStamping
01354 
01355     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01356     Created:    13/12/99
01357 
01358     Inputs:     -
01359     Returns:    TRUE if we are using the timestamp cache, FALSE otherwise (we never use both)
01360     Purpose:    as above
01361 ********************************************************************************************/
01362 
01363 BOOL BrushAttrValue::IsTimeStamping()
01364 {
01365     return (m_pTimeStampList != NULL);
01366 }
01367 
01368 
01369 /********************************************************************************************
01370 
01371 >   void BrushAttrValue::CalculateProportionalDistances(MILLIPOINT PathLength)
01372 
01373     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01374     Created:    13/12/99
01375     Inputs:     The length of the path to which this attribute applies
01376     Returns:    -
01377     Purpose:    Only use when we are utilising the path stamping cache.  This fn. proceeds
01378                 through the list and works out the proportional distance along the path for
01379                 each object.
01380     See Also:   TimeStampBrushPoint 
01381 ********************************************************************************************/
01382 
01383 void BrushAttrValue::CalculateProportionalDistances(MILLIPOINT PathLength)
01384 {
01385     if (m_pTimeStampList == NULL || PathLength <= 0)
01386     {
01387         ERROR3("Error in calculating proportional distance");
01388         return;
01389     }
01390 
01391     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01392     TimeStampList::iterator LastPos = ListPos;
01393     TimeStampBrushPoint TSBP;
01394     while( ListPos != m_pTimeStampList->end() )
01395     {
01396         LastPos = ListPos;
01397         TSBP = *ListPos; ++ListPos;
01398         TSBP.WorkOutProportion( PathLength );
01399         *LastPos = TSBP;
01400     }
01401 }
01402 
01403 
01404 /********************************************************************************************
01405 
01406 >   void BrushAttrValue::FlushTimeStampCache()
01407 
01408     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01409     Created:    13/12/99
01410     Inputs:     -
01411     Returns:    -
01412     Purpose:    deletes the timestamp cache if we have one
01413 ********************************************************************************************/
01414 
01415 void BrushAttrValue::FlushTimeStampCache()
01416 {
01417     if (m_pTimeStampList != NULL)
01418     {
01419         m_pTimeStampList->clear();
01420         delete m_pTimeStampList;
01421         m_pTimeStampList = NULL;
01422     }
01423 }
01424 
01425 
01426 /********************************************************************************************
01427 
01428 >   void BrushAttrValue::TransformTimeStamp(TransformBase& Transform) 
01429 
01430     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01431     Created:    6/10/99
01432     Inputs:     the transformation to perform
01433     Returns:    -
01434     Purpose:    transforms all the points in the timestamping cache
01435     SeeAlso:    -
01436 
01437 ********************************************************************************************/
01438 
01439 void BrushAttrValue::TransformTimeStampList(TransformBase& Trans)
01440 {
01441     if (m_pTimeStampList == NULL)
01442         return;
01443 
01444     // pretty straightforward, just get the points out of the list and transform them
01445     TimeStampBrushPoint TSBP;
01446     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01447 
01448     while( ListPos != m_pTimeStampList->end() )
01449     {
01450         TimeStampList::iterator OldPos = ListPos;
01451         TSBP = *ListPos; ++ListPos;
01452         Trans.Transform(&TSBP.m_Point, 1);
01453         *OldPos = TSBP;
01454     }
01455 
01456     
01457 
01458 }
01459 
01460 
01461 /********************************************************************************************
01462 
01463 >   bool BrushAttrValue::DeleteTimeStampPoints(MILLIPOINT Start, MILLIPOINT End) 
01464 
01465     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01466     Created:    6/10/99
01467     Inputs:     Start - distance from which to delete
01468                 End - the distance to stop deleting at
01469     Returns:    TRUE if successful, FALSE if not
01470     Purpose:    removes points from the timestamping list between the provided distances
01471     SeeAlso:    -
01472 
01473 ********************************************************************************************/
01474 
01475 BOOL BrushAttrValue::DeleteTimeStampPoints(MILLIPOINT StartDistance, MILLIPOINT EndDistance, 
01476                                            TimeStampList* pRemovedPoints)
01477 {
01478     if (StartDistance <0 || EndDistance < 0 || EndDistance <= StartDistance)
01479     {
01480         ERROR3("Invalid inputs to BrushAttrValue::DeleteTimeStampingPoints");
01481         return FALSE;
01482     }
01483 
01484     if (m_pTimeStampList == NULL)
01485         return FALSE;
01486 
01487     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01488     TimeStampList::iterator LastPos = ListPos;
01489     TimeStampBrushPoint     TSBP;
01490     MILLIPOINT              Distance = 0;
01491     INT32                       count = 0;
01492     INT32                       removecount = 0;
01493     TRACEUSER( "Diccon", _T("Deleting from %d, to %d\n"), StartDistance, EndDistance );
01494     TRACEUSER( "Diccon", _T("Num points pre-remove = %d\n"), m_pTimeStampList->size() );
01495     while( ListPos != m_pTimeStampList->end() )
01496     {
01497         LastPos = ListPos;
01498         TSBP = *ListPos; ++ListPos;
01499         Distance = TSBP.m_Distance;
01500         //TRACEUSER("Diccon", _T("Count %d, Distance = %d\n"), count, Distance);
01501         if (Distance >= StartDistance && Distance <= EndDistance)
01502         {
01503             // if we're sending the removed points back, add this one to the list
01504             if (pRemovedPoints != NULL)
01505                 pRemovedPoints->push_back( TSBP );
01506 
01507             // remove it from the main list
01508             m_pTimeStampList->erase( LastPos );
01509             removecount++;
01510             TRACEUSER("Diccon", _T("Removing point %d\n"), count);
01511         }
01512         count++;
01513     }
01514     TRACEUSER("Diccon", _T("Removed %d points\n"), removecount);
01515 
01516     return TRUE;
01517 }
01518 
01519 
01520 /********************************************************************************************
01521 
01522 >   bool BrushAttrValue::DeleteTimeStampPoints(MILLIPOINT Start, UINT32 NumPoints, TimeStampList* pList = NULL) 
01523 
01524     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01525     Created:    6/10/99
01526     Inputs:     Start - distance from which to delete
01527                 NumPoints - the number to delete
01528                 pList - a list to put the deleted points in (defaults to null)
01529     Returns:    TRUE if successful, FALSE if not
01530     Purpose:    removes points from the timestamping list between the provided distances
01531     SeeAlso:    -
01532 
01533 ********************************************************************************************/
01534 
01535 BOOL BrushAttrValue::DeleteTimeStampPoints(MILLIPOINT StartDistance, UINT32 NumPoints, 
01536                                            TimeStampList* pRemovedPoints)
01537 {
01538     if (StartDistance <0 || NumPoints < 1)
01539     {
01540         ERROR3("Invalid inputs to BrushAttrValue::DeleteTimeStampingPoints");
01541         return FALSE;
01542     }
01543 
01544     if (m_pTimeStampList == NULL)
01545         return FALSE;
01546 
01547     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01548     TimeStampList::iterator LastPos = ListPos;
01549     TimeStampBrushPoint     TSBP;
01550     MILLIPOINT              Distance = 0;
01551     UINT32                      count = 0;
01552     NumPoints --;
01553     while( ListPos != m_pTimeStampList->end() )
01554     {
01555         LastPos = ListPos;
01556         TSBP = *ListPos; ++ListPos;
01557         Distance = TSBP.m_Distance;
01558         count++;
01559         if (Distance >= StartDistance)
01560         {
01561             
01562             TimeStampList::iterator RemPos = LastPos;
01563             while( NumPoints && LastPos != m_pTimeStampList->end() )
01564             {
01565                 TRACEUSER("Diccon", _T("Removing point %d\n"), count);
01566                 if (count == m_pTimeStampList->size())
01567                 {
01568                     //INT32 i = 1; // why is this here AMB 2006-01-31
01569                 }
01570                 // if we're sending the removed points back, add this one to the list
01571                 if (pRemovedPoints != NULL)
01572                     pRemovedPoints->push_back(TSBP);
01573                 RemPos = LastPos;
01574                 TSBP = *LastPos; ++LastPos;
01575                 TimeStampBrushPoint Test = *RemPos;
01576         //      TRACEUSER("Diccon", _T("Removing point at %d\n"), Test.m_Distance);
01577                 // remove it from the main list
01578                 m_pTimeStampList->erase( RemPos );
01579                 NumPoints--;
01580                 count++;
01581             }
01582         
01583         }
01584         if (NumPoints <= 0 || LastPos == m_pTimeStampList->end())
01585             break;
01586     }
01587     return TRUE;
01588 }
01589 
01590 /********************************************************************************************
01591 
01592 >   bool Bru5shAttrValue::AddTimeStampPoints(TimeStampList* pNewPoints, MILLIPOINT Start) 
01593 
01594     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01595     Created:    6/10/99
01596     Inputs:     pNewPoints - the points to add
01597                 Start - distance from which to add the points, note that if this is negative then
01598                 all the new points will be added to the very start
01599             
01600     Returns:    TRUE if successful, FALSE if not
01601     Purpose:    inserts the list of points after the distance given
01602     SeeAlso:    -
01603 
01604 ********************************************************************************************/
01605     
01606 BOOL BrushAttrValue::AddTimeStampPoints(TimeStampList* pNewPoints, MILLIPOINT StartDistance)
01607 {
01608     if (pNewPoints == NULL)
01609     {
01610         ERROR3("Invalid inputs to BrushAttrValue::DeleteTimeStampingPoints");
01611         return FALSE;
01612     }
01613 
01614     if (m_pTimeStampList == NULL)
01615         return FALSE;
01616 
01617     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01618     TimeStampList::iterator LastPos = ListPos;
01619     
01620     TimeStampBrushPoint TSBP;
01621     TimeStampBrushPoint NewPoint;
01622     MILLIPOINT Distance;
01623     
01624     TRACEUSER("Diccon", _T("Num points pre-add = %d\n"), m_pTimeStampList->size());
01625 
01626     // first find the TimeStampList::iterator   at which we want to insert the new points
01627     if (StartDistance > 0)
01628     {
01629         while( ListPos != m_pTimeStampList->end() )
01630         {
01631             LastPos = ListPos;
01632             TSBP = *ListPos; ++ListPos;
01633             Distance = TSBP.m_Distance;
01634             if (Distance > StartDistance)
01635                 break;
01636                 
01637         }
01638     }
01639     else
01640         LastPos = m_pTimeStampList->begin();
01641 
01642     TimeStampList::iterator NewListPos = pNewPoints->begin();
01643 
01644     while( NewListPos != m_pTimeStampList->end() )
01645     {
01646         // get the point from the new list
01647         NewPoint = *NewListPos; ++NewListPos;
01648                 
01649         // insert it into the old list, recall that LastPos stores the element just before
01650         // StartDistance was exceeded
01651         if (StartDistance > 0)
01652         {
01653             m_pTimeStampList->insert( LastPos, NewPoint );
01654             // increment our list position
01655             ++LastPos;
01656         }
01657         else
01658             m_pTimeStampList->push_front( NewPoint );
01659     }
01660 
01661     TRACEUSER("Diccon", _T("Ended with %d points\n"), m_pTimeStampList->size());
01662 
01663     return TRUE;
01664 }
01665 
01666 /********************************************************************************************
01667 
01668 >   bool BrushAttrValue::RecalculateTimeStampList(Path* pPath)
01669 
01670     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01671     Created:    6/10/99
01672     Inputs:     pPath - the path of the nodepath of this timestamped brush
01673                 
01674             
01675     Returns:    TRUE if successful, FALSE if not
01676     Purpose:    If time stamped lists are edited they can get out of shape, call this function
01677                 to make sure the list is all in order.  Note that it can be a bit slow
01678                 Extra note, depending on exactly how the path was edited our update method differs.
01679                 RepositionPointsByProportion is used when the path was edited by no points were
01680                 added or removed from the timestamping list.  If points were added then the other
01681                 method should be used.
01682     SeeAlso:    -
01683 
01684 ********************************************************************************************/
01685 
01686 BOOL BrushAttrValue::RecalculateTimeStampList(Path* pPath)
01687 {
01688     if (m_pTimeStampList == NULL)
01689         return TRUE;
01690     if (pPath == NULL)
01691         return FALSE;
01692     BOOL Retval = TRUE;
01693     switch (m_TimeStampUpdateType)
01694     {
01695         case UPDATE_NONE:
01696             break;
01697         case UPDATE_PROPORTION:
01698             if (!RepositionPointsByProportion(pPath))
01699                 Retval = FALSE;
01700         break;
01701         case UPDATE_LIST:
01702             if (!RecalculateDistances(pPath))
01703             {
01704                 Retval =  FALSE;
01705                 break;
01706             }
01707             if (!SortTimeStampingList())
01708             {
01709                 Retval = FALSE;
01710                 break;
01711             }
01712         //  if (!RecalculateTangents(pPath))
01713         //  {
01714         //      Retval = FALSE;
01715         //      break;
01716         //  }
01717         break;
01718         case UPDATE_POSITION:
01719             if (!RepositionPointsByPosition(pPath))
01720                 Retval = FALSE;
01721         break;
01722         case UPDATE_LISTANDPOSITION:
01723             if (!RepositionPointsByPosition(pPath))
01724             {
01725                 Retval = FALSE;
01726                 break;
01727             }
01728             if (!RecalculateDistances(pPath))
01729             {
01730                 Retval =  FALSE;
01731                 break;
01732             }
01733             if (!SortTimeStampingList())
01734             {
01735                 Retval = FALSE;
01736                 break;
01737             }
01738         //  if (!RecalculateTangents(pPath))
01739         //  {
01740         //      Retval = FALSE;
01741         //      break;
01742         //  }
01743         break;
01744     }           
01745 
01746 //  if (!GetRidOfCrapFromList(pPath))
01747 //      return FALSE;
01748     return Retval;
01749 }
01750 
01751 
01752 
01753 /********************************************************************************************
01754 
01755 >   bool BrushAttrValue::RecalculateDistances(Path* pPath)
01756 
01757     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01758     Created:    6/10/99
01759     Inputs:     pPath - the path of the nodepath of this timestamped brush
01760                 
01761             
01762     Returns:    TRUE if successful, FALSE if not
01763     Purpose:    for a timestamped brush, this fn. goes along the path and recalculates 
01764                 the distances of the coordinates along the line.  
01765     SeeAlso:    -
01766 
01767 ********************************************************************************************/
01768 
01769 BOOL BrushAttrValue::RecalculateDistances(Path* pPath)
01770 {
01771     if (pPath == NULL || m_pTimeStampList == NULL)
01772     {
01773         ERROR3("Input pointers are NULL");
01774         return FALSE;
01775     }
01776 
01777     double PathLength = (MILLIPOINT)pPath->GetPathLength();
01778     MILLIPOINT Distance;
01779     
01780     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01781     TimeStampList::iterator LastPos;
01782     TimeStampBrushPoint TSBPoint;
01783 
01784     while( ListPos != m_pTimeStampList->end() )
01785     {
01786         LastPos = ListPos;
01787         TSBPoint = *ListPos; ++ListPos;
01788         // get the distance along the path
01789         if (pPath->GetDistanceToPoint(TSBPoint.m_Point, &Distance))
01790         {
01791             TSBPoint.m_Distance = Distance;
01792             TSBPoint.m_Proportion = (double)TSBPoint.m_Distance / PathLength;
01793         //  TRACEUSER("Diccon", _T("New Prop: %f\n"), TSBPoint.m_Proportion);
01794             *LastPos = TSBPoint;
01795         }
01796         else
01797             TRACEUSER("Diccon", _T("Point %d, %d, not found in line\n"), TSBPoint.m_Point.x, TSBPoint.m_Point.y);
01798     }
01799     
01800     return TRUE;
01801 }
01802 
01803 /********************************************************************************************
01804 
01805 >   bool BrushAttrValue::RecalculateTangents(Path* pPath)
01806 
01807     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01808     Created:    6/10/99
01809     Inputs:     pPath - the path of the nodepath of this timestamped brush
01810                 
01811             
01812     Returns:    TRUE if successful, FALSE if not
01813     Purpose:    for a timestamped brush, this fn. goes along the path and recalculates 
01814                 the tangents of the coordinates along the line.  
01815     SeeAlso:    -
01816 
01817 ********************************************************************************************/
01818 
01819 BOOL BrushAttrValue::RecalculateTangents(Path* pPath)
01820 {
01821     if (pPath == NULL || m_pTimeStampList == NULL)
01822     {
01823         ERROR3("Input pointers are NULL");
01824         return FALSE;
01825     }
01826 
01827 //  double PathLength = (MILLIPOINT)pPath->GetPathLength();
01828     
01829     double Tangent;
01830     DocCoord DummyCoord;
01831 
01832     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01833     TimeStampBrushPoint TSBPoint;
01834 
01835     while( ListPos != m_pTimeStampList->end() )
01836     {
01837         TSBPoint = *ListPos; ++ ListPos;
01838         // we need to use GetPointAtDistance to retrieve the tangent
01839         if (pPath->GetPointAtDistance(TSBPoint.m_Distance, &DummyCoord, &Tangent))
01840             TSBPoint.m_Tangent = Tangent;
01841     
01842     }
01843     return TRUE;
01844 }   
01845 
01846 
01847 /********************************************************************************************
01848 
01849 >   bool BrushAttrValue::SortTimeStampingList()
01850 
01851     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01852     Created:    6/10/99
01853     Inputs:     -
01854     Returns:    TRUE if successful, FALSE if not
01855     Purpose:    The TimeStamping points lists can become rather disorderly if you edit them a 
01856                 lot.  This function sorts them by order of distance using quicksort.  Make sure you call 
01857                 RecalculateDistances() first.
01858     SeeAlso:    -
01859 
01860 ********************************************************************************************/
01861 
01862 BOOL BrushAttrValue::SortTimeStampingList()
01863 {
01864     if (m_pTimeStampList == NULL)
01865         return FALSE;
01866 
01867     // first we need to copy the elements out of the list into an array
01868     size_t NumElements = m_pTimeStampList->size();
01869     
01870     // make the array
01871     TimeStampBrushPoint* pPointArray = new TimeStampBrushPoint[NumElements];
01872     if (pPointArray == NULL)
01873         return FALSE;
01874 
01875     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01876 
01877     TimeStampBrushPoint PointInfo;
01878     UINT32 Counter = 0;
01879 
01880     // copy the points into the array
01881     while( ListPos != m_pTimeStampList->end() )
01882     {
01883         PointInfo = *ListPos; ++ListPos;
01884 
01885         pPointArray[Counter++] = PointInfo;
01886     }
01887 
01888     // quick sort 'em
01889     qsort((void*)pPointArray, NumElements, sizeof(TimeStampBrushPoint), TimeStampBrushPoint::ComparePointInfo);
01890 
01891 
01892     // now put 'em back in the list
01893     m_pTimeStampList->clear();
01894     
01895     for (unsigned i = 0; i < NumElements; i++)
01896     {
01897         m_pTimeStampList->push_back(pPointArray[i]);
01898     
01899     //  TRACEUSER("Diccon", _T("Sorted distance = %d\n"), pPointArray[i].m_Distance);
01900     }
01901 
01902     delete pPointArray;
01903     return TRUE;
01904 }   
01905 
01906 
01907 /********************************************************************************************
01908 
01909 >   bool BrushAttrValue::GetRidOfCrapFromList(Path* pPath)
01910 
01911     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01912     Created:    6/10/99
01913     Inputs:     pPath = the path that this timestamped brush supposedly follows
01914     Returns:    TRUE if successful, FALSE if not
01915     Purpose:    The TimeStamping points lists can become rather disorderly if you edit them a 
01916                 lot.  My woefully inadequate undo/redo actions for editing them can still leave
01917                 some rogue points hanging around. This function proceeds through the list
01918                 removing any points that are not on the path.
01919     SeeAlso:    -
01920 
01921 ********************************************************************************************/
01922 
01923 BOOL BrushAttrValue::GetRidOfCrapFromList(Path* pPath)
01924 {
01925     if (m_pTimeStampList == NULL || pPath == NULL)
01926         return FALSE;
01927 
01928     TimeStampBrushPoint Point;
01929     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01930     TimeStampList::iterator LastPos = ListPos;
01931     MILLIPOINT Distance;
01932 
01933     while( ListPos != m_pTimeStampList->end() )
01934     {
01935         LastPos = ListPos;
01936         Point = *ListPos; ++ListPos;
01937         if (!pPath->GetDistanceToPoint(Point.m_Point, &Distance))
01938         {
01939             m_pTimeStampList->erase( LastPos );
01940             TRACEUSER("Diccon", _T("Removing point at %d\n"), Point.m_Distance);
01941         }
01942     }
01943     return TRUE;
01944 }
01945 
01946 
01947 /********************************************************************************************
01948 
01949 >   bool BrushAttrValue::RepositionPointsByProportion(Path* pPath)
01950 
01951     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01952     Created:    6/10/99
01953     Inputs:     pPath = the path that this timestamped brush supposedly follows
01954     Returns:    TRUE if successful, FALSE if not
01955     Purpose:    This function moves all the points in the timestamping list to their proportional
01956                 TimeStampList::iterator along pPath. 
01957 
01958     SeeAlso:    -
01959 
01960 ********************************************************************************************/
01961 
01962 BOOL BrushAttrValue::RepositionPointsByProportion(Path* pPath)
01963 {
01964     if (m_pTimeStampList == NULL || pPath == NULL)
01965         return FALSE;
01966 
01967     TimeStampBrushPoint Point;
01968     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
01969     TimeStampList::iterator LastPos = ListPos;
01970     
01971     double PathLength = pPath->GetPathLength();
01972     MILLIPOINT PointDistance = 0;
01973     double Tangent = 0;
01974     DocCoord NewPosition;
01975     UINT32 Counter = 0;
01976 
01977     while( ListPos != m_pTimeStampList->end() )
01978     {
01979         LastPos = ListPos;
01980         Point = *ListPos; ++ListPos;
01981         // work out the new distance along the given path with the existing proportion
01982         PointDistance = (MILLIPOINT)(Point.m_Proportion * PathLength);
01983         if (PointDistance >= 0)
01984         {
01985             // get the coordinate and tangent for this distance
01986             if (pPath->GetPointAtDistance(PointDistance, &NewPosition, &Tangent))
01987             {
01988                 // assign the new data to the point
01989                 Point.m_Point = NewPosition;
01990                 Point.m_Tangent = Tangent;
01991                 Point.m_Distance = PointDistance;
01992                 // put the point back in the list
01993                 *LastPos = Point;
01994             }
01995             else
01996             {
01997                 TRACEUSER("Diccon", _T("Failed to find point on line with distance %d\n"), PointDistance);
01998             }
01999         }
02000         else
02001         {
02002             TRACEUSER("Diccon", _T("Negative path distance at point %d\n"), Counter);
02003         }
02004         Counter++;
02005     }
02006     return TRUE;
02007 }
02008 
02009 
02010 /********************************************************************************************
02011 
02012 >   bool BrushAttrValue::RepositionPointsByPosition(Path* pPath)
02013 
02014     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02015     Created:    6/10/99
02016     Inputs:     pPath = the path that this timestamped brush supposedly follows
02017     Returns:    TRUE if successful, FALSE if not
02018     Purpose:    This function assumes that all the points in the timestamping list are in the
02019                 path but that their distance and proportion information is incorrect.  Therefore
02020                 it runs through the list and finds the correct distance and proportion.
02021                 This is useful for those times when the path editing functions conveniently decide to 
02022                 go and reverse the paths because they feel like it.  
02023 
02024     SeeAlso:    -
02025 
02026 ********************************************************************************************/
02027 
02028 BOOL BrushAttrValue::RepositionPointsByPosition(Path* pPath)
02029 {
02030     if (m_pTimeStampList == NULL || pPath == NULL)
02031         return FALSE;
02032 
02033     TimeStampBrushPoint Point;
02034     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
02035     TimeStampList::iterator LastPos = ListPos;
02036     
02037     double PathLength = pPath->GetPathLength();
02038     MILLIPOINT PointDistance = 0;
02039 //  double Tangent = 0;
02040     DocCoord NewPosition;
02041     UINT32 Counter = 0;
02042 
02043     while( ListPos != m_pTimeStampList->end() )
02044     {
02045         LastPos = ListPos;
02046         Point = *ListPos; ++ListPos;
02047     
02048         if (pPath->GetDistanceToPoint(Point.m_Point, &PointDistance))
02049         {
02050             Point.m_Distance = PointDistance;
02051             Point.m_Proportion = (double)PointDistance / PathLength;
02052             // put the point back in the list
02053             *LastPos = Point;
02054         }
02055         else
02056         {
02057             TRACEUSER("Diccon", _T("Failed to get distance to point at %d\n"), Counter);
02058         }
02059         Counter++;
02060     }
02061     return TRUE;
02062 }
02063 
02064 
02065 
02066 /********************************************************************************************
02067 
02068 >   TimeStampList* BrushAttrValue::CopyTimeStampList()
02069 
02070     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02071     Created:    22/5/2000
02072 
02073     Returns:    Pointer to the new list, or null if it fails
02074 
02075     Purpose:    Copy our timestamping list
02076 
02077     SeeAlso:    operator=
02078 
02079 ********************************************************************************************/
02080 
02081 TimeStampList* BrushAttrValue::CopyTimeStampList()
02082 {
02083     if (m_pTimeStampList == NULL)
02084         return NULL;
02085     // allocate a new list of our own
02086     TimeStampList* pCopyList = new TimeStampList;
02087     if (pCopyList != NULL)
02088     {
02089         TimeStampBrushPoint TBSP;
02090         TimeStampList::iterator ListPos = m_pTimeStampList->begin();
02091         // copy the points
02092         while( ListPos != m_pTimeStampList->end() )
02093         {
02094             TBSP = *ListPos; ++ListPos;
02095             pCopyList->push_back(TBSP);
02096         }   
02097     }
02098     return pCopyList;
02099 }
02100 
02101 /********************************************************************************************
02102 
02103 >   virtual NodeAttribute *BrushAttrValue::MakeNode()
02104 
02105     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02106     Created:    13/12/99
02107 
02108     Returns:    Pointer to the new node, or NULL if out of memory.
02109 
02110     Purpose:    Make a new attribute node for this type of attr value - see base class
02111 
02112     SeeAlso:    AttributeValue::MakeNode
02113 
02114 ********************************************************************************************/
02115 
02116 NodeAttribute *BrushAttrValue::MakeNode()
02117 {
02118     // Create new attribute node
02119     AttrBrushType *pAttr = new AttrBrushType;
02120     if (pAttr == NULL)
02121         return NULL;
02122 
02123     // Copy attribute value (if any) into the new node.
02124     if (pAttr->GetAttributeValue() != NULL)
02125         pAttr->GetAttributeValue()->SimpleCopy(this);
02126 
02127 
02128     return(pAttr);
02129 }
02130 
02131 
02132 
02133 /********************************************************************************************
02134 
02135 >   virtual BOOL BrushAttrValue::IsDifferent(AttributeValue *pAttr)
02136 
02137     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02138     Created:    13/12/99
02139 
02140     Purpose:    Determines if this AttrValue is different from the given one
02141 
02142     Errors:     ERROR3 if the two attributes are not of the same type
02143 
02144     SeeAlso:    AttributeValue::IsDifferent
02145 
02146 ********************************************************************************************/
02147 
02148 BOOL BrushAttrValue::IsDifferent(AttributeValue *pAttr)
02149 {
02150     ERROR3IF(!pAttr->IsKindOf(CC_RUNTIME_CLASS(BrushAttrValue)),
02151                 "Different attribute types in BrushAttrValue::IsDifferent()");
02152 
02153     // Check they are NOT the same using the == operator
02154     return ( !(*((BrushAttrValue *)pAttr) == *this) );
02155 }
02156 
02157 
02158 
02159 /********************************************************************************************
02160 
02161 >   virtual BrushAttrValue &BrushAttrValue::operator=(BrushAttrValue &Attrib)
02162 
02163     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02164     Created:    13/12/99
02165 
02166     Inputs:     Attrib - the attribute to copy
02167 
02168     Purpose:    Assignment operator
02169 
02170 ********************************************************************************************/
02171 
02172 BrushAttrValue &BrushAttrValue::operator=(BrushAttrValue &Attrib)
02173 {
02174     // Get rid of our old processor (if any)
02175     if (m_pProcessor != NULL)
02176         delete m_pProcessor;
02177     m_pProcessor = NULL;
02178 
02179     // Copy the other attr's processor. If this fails, we'll get back a NULL pointer,
02180     // and will simply "convert" into a simple no-stroke attribute.
02181     if (Attrib.m_pProcessor != NULL)
02182         m_pProcessor = Attrib.m_pProcessor->Clone();
02183 
02184     // if we're timestamping then we need to clone the list of points
02185     if (Attrib.IsTimeStamping())
02186         m_pTimeStampList = CopyTimeStampList();
02187 
02188     // if we have pressure data then we need to copy that also
02189     m_pPressureSampler = Attrib.CopyPressureCache();
02190 
02191     return(*this);
02192 }
02193 
02194 
02195 
02196 /********************************************************************************************
02197 
02198 >   virtual INT32 BrushAttrValue::operator==(const BrushAttrValue &Attrib)
02199 
02200     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02201     Created:    13/12/99
02202 
02203     Inputs:     Attrib - the attribute to compare this attribute with
02204 
02205     Returns:    TRUE if the attributes are considered equal
02206 
02207     Purpose:    Comparison operator
02208 
02209 ********************************************************************************************/
02210 
02211 INT32 BrushAttrValue::operator==(const BrushAttrValue &Attrib)
02212 {
02213     ERROR3IF(!Attrib.IsKindOf(CC_RUNTIME_CLASS(BrushAttrValue)),
02214                 "Other attribute value isn't an BrushAttrValue");
02215 
02216     BrushAttrValue *Other = (BrushAttrValue *) &Attrib;
02217 
02218     // two attributes can never have the same timestamp or pressure caches
02219     // If that is the case then why is it checking the points cache and 
02220     // not the pressure cache!?? I'm changing this to check the "correct" cache
02221     // Gerry (21/11/05)
02222 
02223     // The points cache doesn't get copied in the = operator so don't check it
02224 //  if (GetCache() != NULL && GetCache()->GetCount() != 0)
02225 //      return(FALSE);
02226 //  if (Other->GetCache() != NULL && Other->GetCache()->GetCount != 0)
02227 //      return(FALSE);
02228 
02229     if (GetPressureCache() != NULL && GetPressureCache()->GetCount() != 0)
02230         return(FALSE);
02231     if (Other->GetPressureCache() != NULL && Other->GetPressureCache()->GetCount() != 0)
02232         return(FALSE);
02233 
02234     if (m_pTimeStampList != NULL && m_pTimeStampList->size() != 0)
02235         return FALSE;
02236     if (Other->GetTimeStampList() != NULL && Other->GetTimeStampList()->size() != 0)
02237         return FALSE;
02238 
02239     // Equal if they both have same processor (only applies if they are both NULL)
02240     if (m_pProcessor == Other->GetPathProcessor())
02241         return(TRUE);
02242 
02243     // Otherwise, if one of them is NULL, they can't be the same
02244     if (m_pProcessor == NULL || Other->GetPathProcessor() == NULL)
02245         return(FALSE);
02246 
02247     // Finally, ask the processors if they are of the same type
02248     return(!m_pProcessor->IsDifferent(Other->GetPathProcessor()));
02249 }
02250 
02251 
02252 
02253 /********************************************************************************************
02254 
02255 >   void BrushAttrValue::SetPathProcessor(PathProcessorStroke *pNewProcessor)
02256 
02257     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02258     Created:    13/12/99
02259 
02260     Inputs:     pNewProcessor - The new PathProcessorStroke to be used by this attr.
02261                 May be NULL, in which case it sets "old style lines" stroking mode.
02262 
02263     Purpose:    To set the path processor used by this object. The processor is now
02264                 "owned" by this attribute, and will be auto-deleted upon destruction
02265 
02266 ********************************************************************************************/
02267 
02268 void BrushAttrValue::SetPathProcessor(PathProcessorBrush *pNewProcessor)
02269 {
02270     if (m_pProcessor != NULL)
02271         delete m_pProcessor;
02272     m_pProcessor = pNewProcessor;
02273 
02274 }
02275 
02276 
02277 /********************************************************************************************
02278 
02279 >   void BrushAttrValue::ScaleToLineWidth(MILLIPOINT Width)
02280 
02281     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02282     Created:    13/12/99
02283 
02284     Inputs:     Width - the width to set
02285 
02286     Purpose:    asks the processor to scale to this line width.  Note that the relevant flag
02287                 must also be set
02288 
02289 ********************************************************************************************/
02290 
02291 void BrushAttrValue::ScaleToLineWidth(MILLIPOINT Width)
02292 {
02293     if (m_pProcessor != NULL)
02294     {
02295         BOOL Pressure = m_pPressureSampler != NULL;
02296         m_pProcessor->ScaleToValue(Width, !Pressure);
02297     }
02298 }
02299 
02300 /********************************************************************************************
02301 
02302 >   BrushDefinition* BrushAttrValue::GetBrushDefintion()
02303 
02304     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02305     Created:    13/12/99
02306 
02307     Inputs:     -
02308     Outputs:    -
02309     Returns:    The brush definition used by our path processor, or null if we haven't been
02310                 assigned one yet
02311     Purpose:    as above
02312 
02313 ********************************************************************************************/
02314 
02315 BrushDefinition* BrushAttrValue::GetBrushDefinition()
02316 {
02317     if (m_pProcessor != NULL)
02318     {
02319         return m_pProcessor->GetOurBrushDefinition();
02320     }
02321     return NULL;
02322 }
02323 
02324 
02325 /********************************************************************************************
02326 
02327 >   BrushHandle BrushAttrValue::GetBrushHandle() 
02328 
02329     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02330     Created:    6/10/99
02331     Inputs:     -
02332     Returns:    handle of the brush definition used by this brush (can be NULL)
02333     Purpose:    interface to the pathprocessor
02334     SeeAlso:    -
02335 
02336 ********************************************************************************************/
02337 
02338 BrushHandle BrushAttrValue::GetBrushHandle()
02339 {
02340     if (m_pProcessor == NULL)
02341         return BrushHandle_NoBrush;
02342     return m_pProcessor->GetBrushDefinitionHandle();
02343 }
02344 
02345 
02346 /*********************************************************************************************
02347 
02348 >    DocRect BrushAttrValue::SetCachedRect(DocRect Rect)
02349 
02350      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02351      Created:   4/4/95
02352      Inputs:    Rect - the bounding rect of this attribute
02353      Outputs:   -
02354      Returns:   
02355      Purpose:   This is designed to be called by the path processor, which calculates the
02356                 bounding rect of this attribute, arbitrarily setting bounding rects by other
02357                 objects is not recommended
02358 **********************************************************************************************/
02359        
02360 void BrushAttrValue::SetCachedRect(DocRect Rect)
02361 {
02362     m_CachedBRect = Rect;
02363 }
02364 
02365 
02366 /*********************************************************************************************
02367 
02368 >    void BrushAttrValue::TransformCachedRect(TransformBase& Trans)
02369 
02370      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02371      Created:   4/4/95
02372      Inputs:    Trans - the transformation to perform
02373      Outputs:   -
02374      Returns:   
02375      Purpose:   Because it takes such a long time to calculate the bounding rect of a brushed object
02376                 we prefer to calculate it once and then simply transform it.
02377 **********************************************************************************************/
02378        
02379 void BrushAttrValue::TransformCachedRect(TransformBase& Trans)
02380 {
02381 
02382     
02383     // if we have offsets from the path then simply transforming it doesn't work,
02384     // better to recalculate it
02385     if (m_pProcessor != NULL)
02386     {
02387         if (m_pProcessor->GetPathOffsetType() != OFFSET_NONE)
02388             m_CachedBRect.MakeEmpty();
02389     }
02390 
02391     if (!m_CachedBRect.IsEmpty())
02392     {
02393         DocCoord Coords[4];
02394         Coords[0].x = m_CachedBRect.lo.x;   Coords[0].y = m_CachedBRect.lo.y;
02395         Coords[1].x = m_CachedBRect.hi.x;   Coords[1].y = m_CachedBRect.lo.y;
02396         Coords[2].x = m_CachedBRect.hi.x;   Coords[2].y = m_CachedBRect.hi.y;
02397         Coords[3].x = m_CachedBRect.lo.x;   Coords[3].y = m_CachedBRect.hi.y;
02398 
02399         Trans.Transform(Coords,4);
02400     
02401         m_CachedBRect.lo.x = min(min(Coords[0].x,Coords[1].x), min(Coords[2].x,Coords[3].x));
02402         m_CachedBRect.hi.x = max(max(Coords[0].x,Coords[1].x), max(Coords[2].x,Coords[3].x));
02403         m_CachedBRect.lo.y = min(min(Coords[0].y,Coords[1].y), min(Coords[2].y,Coords[3].y));
02404         m_CachedBRect.hi.y = max(max(Coords[0].y,Coords[1].y), max(Coords[2].y,Coords[3].y));
02405     }
02406     
02407 }
02408 /*********************************************************************************************
02409 
02410 >    DocRect NodeAttribute::GetAttrBoundingRect(NodeRenderableInk* pParent)
02411 
02412      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02413      Created:   4/4/95
02414      Inputs:    pParent, the parent Ink node that this attribute will effect.
02415      Outputs:   -
02416      Returns:   The Bounding rect of the attribute (NULL rectangle is it doesn't have any).
02417      Purpose:   Virtual function for determining the bounding rect of an attribute.  It achieves this
02418                 by giving a path to the path processor which tells it the bounding rect.
02419             
02420      SeeAlso:   NodeAttribute::EffectsParentBounds
02421 
02422 **********************************************************************************************/
02423        
02424 DocRect BrushAttrValue::GetAttrBoundingRect(NodeRenderableInk* pParent, CCAttrMap* pAttribMap)
02425 {
02426     BrushDefinition* pBrushDef = GetBrushDefinition();
02427     if (pBrushDef == NULL)
02428         return DocRect(0, 0, 0, 0);
02429 
02430     // get the biggest BBox of the brush objects
02431     DocRect BRect = pBrushDef->GetLargestBoundingBox();
02432     DocRect ReturnRect(0,0,0,0);
02433     
02434 //  if (!m_CachedBRect.IsEmpty())
02435     //  return m_CachedBRect;
02436     
02437     
02438     // get our path processor
02439     PathProcessorBrush* pPPB = GetPathProcessor();
02440     if (pPPB == NULL)
02441         return DocRect(0,0,0,0);
02442 
02443     if (m_pTimeStampList != NULL)
02444     {
02445         ReturnRect =  pPPB->TimeStampBoundingBox();
02446         m_CachedBRect = ReturnRect;
02447         return ReturnRect;
02448     }
02449 
02450     if (pParent->IsNodePath())
02451     {   
02452 #ifdef NEWFASTBRUSHES
02453         if (pCachedBitmap)
02454         {
02455             ReturnRect = pCachedBitmap->GetBoundingRect ();
02456         }
02457         else
02458         {
02459 #endif
02460         // we have a special calculation for nodepaths, because we can use their path
02461         ReturnRect =  pPPB->CalculateBoundingBox(&((NodePath*)pParent)->InkPath, pParent);
02462 #ifdef NEWFASTBRUSHES
02463         }
02464 #endif
02465         m_CachedBRect = ReturnRect;
02466         return ReturnRect;
02467     }
02468 
02469     BecomeA TestBecomeAPath(BECOMEA_TEST, CC_RUNTIME_CLASS(NodePath));
02470     if (pParent->CanBecomeA(&TestBecomeAPath))
02471     {
02472         // we must be applied to some arbitrary shape.  The thing is that we need to have
02473         // a path to pass to the PPB, so want to get a passback of all the paths in 
02474         // the node 
02475         
02476         // we need to allocate a path
02477         Path* pPath = new Path;
02478         if (pPath != NULL && pPath->Initialise())
02479         {
02480             PathBecomeA BecomeAPath(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), NULL, FALSE, pPath);
02481             if (pParent->DoBecomeA(&BecomeAPath))
02482             {
02483                 ReturnRect =  pPPB->CalculateBoundingBox(pPath, pParent);
02484             }
02485             delete pPath;
02486         }
02487         m_CachedBRect = ReturnRect;
02488         return ReturnRect;
02489     }
02490 
02491     if (pParent->IsATextChar())
02492     {   
02493         // text always has to be different doesn't it..
02494     
02495         // create a format region to keep an attribute stack
02496         FormatRegion FRegion;
02497         FormatRegion* pFormatRegion=&FRegion;
02498 
02499         if (!pFormatRegion->Init(pParent))
02500         {
02501             ERROR3("Failed to init format region");
02502             return ReturnRect;
02503         }
02504 
02505         pFormatRegion->SaveContext();
02506 
02507         NodePath* pNodePath = NULL;
02508         TextChar* pTextChar = (TextChar*)pParent;
02509         pTextChar->RenderChildAttrs(pFormatRegion);
02510         
02511         // create a nodepath that we can use to give the the PPB
02512         if (pTextChar->CreateNodePath(&pNodePath, pFormatRegion))
02513         {
02514             if (pNodePath != NULL)
02515             {
02516                 ReturnRect = pPPB->CalculateBoundingBox(&(pNodePath->InkPath), pParent);
02517                 delete pNodePath;
02518             }
02519         }
02520         pFormatRegion->RestoreContext();
02521     
02522         m_CachedBRect = ReturnRect;
02523         return ReturnRect;
02524     }
02525 
02526     // Still nothing? Last resort time.  
02527     if (ReturnRect.IsEmpty())
02528     {
02529         ReturnRect = pParent->GetBoundingRect(TRUE);
02530     
02531         double Scaling = 1.0;
02532         PathProcessorBrush* pPathProc = GetPathProcessor();
02533     
02534         if (pPathProc != NULL)
02535             Scaling = pPathProc->GetBrushScaling();
02536         // hack it a bit just to make sure
02537         if (!ReturnRect.IsEmpty())
02538             ReturnRect.Inflate((MILLIPOINT)((BRect.Width() / 2) * Scaling) , (MILLIPOINT)((BRect.Height() / 2) * Scaling));
02539 
02540         if (pPathProc->GetPathOffsetType() != OFFSET_NONE)
02541             ReturnRect.Inflate(pPathProc->GetPathOffsetValue(), pPathProc->GetPathOffsetValue());
02542     }
02543 
02544     m_CachedBRect = ReturnRect;
02545     return ReturnRect;
02546 }   
02547 
02548 
02549 
02550 
02551 /********************************************************************************************
02552 
02553 > static void BrushAttrValue::RotateBounds(double Angle, DocRect* pBounds)
02554 
02555     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02556     Created:    8/2/2000
02557     Inputs:     Bounds = the bounds to rotate
02558                 Angle  = the angle in degrees by which to rotate it by
02559     Outputs:    Bounds is updated
02560     Returns:    TRUE, unless you try to pass in a dud rect
02561     Purpose:    The bounds are updated to contain the rotated version
02562     SeeAlso:    -
02563 
02564 ********************************************************************************************/
02565 
02566 BOOL BrushAttrValue::RotateBounds(double Angle, DocRect* pBounds, DocCoord* pCentre)
02567 {
02568     ERROR2IF(pBounds == NULL, FALSE, "DocRect is NULL");
02569 //  if (Angle != 0.0)
02570     {
02571 
02572         DocCoord BBCentre;
02573         if (pCentre == NULL)
02574             BBCentre = pBounds->Centre();
02575         else
02576             BBCentre = *pCentre;
02577 
02578         DocCoord Coords[4];
02579         Coords[0].x = pBounds->lo.x;    Coords[0].y = pBounds->lo.y;
02580         Coords[1].x = pBounds->hi.x;    Coords[1].y = pBounds->lo.y;
02581         Coords[2].x = pBounds->hi.x;    Coords[2].y = pBounds->hi.y;
02582         Coords[3].x = pBounds->lo.x;    Coords[3].y = pBounds->hi.y;
02583 
02584         Trans2DMatrix Rotate(BBCentre,Angle);
02585         Rotate.Transform(Coords,4);
02586 
02587         pBounds->lo.x = min(min(Coords[0].x,Coords[1].x), min(Coords[2].x,Coords[3].x));
02588         pBounds->hi.x = max(max(Coords[0].x,Coords[1].x), max(Coords[2].x,Coords[3].x));
02589         pBounds->lo.y = min(min(Coords[0].y,Coords[1].y), min(Coords[2].y,Coords[3].y));
02590         pBounds->hi.y = max(max(Coords[0].y,Coords[1].y), max(Coords[2].y,Coords[3].y));
02591     }
02592     return TRUE;
02593 }
02594 
02595 /********************************************************************************************
02596 
02597 >   MILLIPOINT BrushAttrValue::GetDefaultLineWidth(BOOL IgnorePressure)
02598 
02599     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02600     Created:    13/12/99
02601 
02602     Inputs:     -
02603     Outputs:    -
02604     Returns:    the default line width as defined by the largest bounding box of the brush definition,
02605                 or -1 if this attribute has no brush definition
02606     Purpose:    as above
02607 
02608 ********************************************************************************************/
02609 
02610 MILLIPOINT BrushAttrValue::GetDefaultLineWidth(BOOL IgnorePressure)
02611 {
02612     if (m_pProcessor == NULL)
02613         return - 1;
02614 
02615     return m_pProcessor->GetBrushSize(IgnorePressure);
02616 }
02617 
02618 /********************************************************************************************
02619 
02620 >   void BrushAttrValue::FlushCache() 
02621 
02622     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02623     Created:    6/10/99
02624     Inputs:     -
02625     Returns:    -
02626     Purpose:    clears out the cached points
02627     SeeAlso:    -
02628 
02629 ********************************************************************************************/
02630 
02631 void BrushAttrValue::FlushCache()
02632 {
02633 #ifdef BRUSHPOINTSCACHE
02634     if (m_pCachedPoints != NULL)
02635     {
02636         m_pCachedPoints->clear();
02637         delete m_pCachedPoints;
02638         m_pCachedPoints = NULL;
02639     }
02640 
02641 #endif
02642 
02643 }
02644 
02645 /********************************************************************************************
02646 
02647 >   void BrushAttrValue::TransformCache(TransformBase& Trans)
02648 
02649     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
02650     Created:    6/11/2000
02651     Inputs:     transfromation matrix
02652     Returns:    -
02653     Purpose:    transforms the cached path.  Attempts to optimise straight transform case.
02654     SeeAlso:    -
02655 
02656 ********************************************************************************************/
02657 
02658 void BrushAttrValue::TransformCache(TransformBase& Trans)
02659 {
02660     if (m_pCachedPoints)
02661     {
02662         BrushPointInfo  PointInfo;
02663         PointsMap::iterator pos = m_pCachedPoints->begin();
02664 
02665         TransformBase *pBase = &Trans;
02666         if (pBase->IS_KIND_OF(Trans2DMatrix))
02667         {
02668             Trans2DMatrix* transMatrix = (Trans2DMatrix*) pBase;
02669             // check for a change in aspect
02670             if (transMatrix->GetMatrix().IsTranslation())
02671             {
02672                 // optimise translate ....
02673 
02674                 DocCoord trans = transMatrix->GetTranslation ();
02675 
02676                 while( pos != m_pCachedPoints->end() )
02677                 {
02678                     pos->second.m_Point.x += trans.x;
02679                     pos->second.m_Point.y += trans.y;
02680 
02681                     ++pos;
02682                 }
02683             }
02684             else
02685             {
02686                 while( pos != m_pCachedPoints->end() )
02687                 {
02688                     Trans.Transform( &pos->second.m_Point, 1 );
02689 
02690                     ++pos;
02691                 }
02692             }
02693         }
02694         else
02695         {
02696             while( pos != m_pCachedPoints->end() )
02697             {
02698                 Trans.Transform( &pos->second.m_Point, 1 );
02699 
02700                 ++pos;
02701             }
02702         }
02703     }
02704 }
02705 
02706 
02707 
02708 /********************************************************************************************
02709 
02710 >   void BrushAttrValue::SetTimeStampUpdateType(ListUpdateType Update) 
02711 
02712     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02713     Created:    6/10/99
02714     Inputs:     Update can be:
02715                 UPDATE_NONE, 
02716                 UPDATE_LIST - means that points have been added or removed to the timestamping list
02717                 UPDATE_PROPORTION - means that the underlying path has changed but our list has not
02718                 UPDATE_TimeStampList::iterator  - means (usually) that the path has been reversed but our points are the same
02719                 UPDATE_LISTANDTimeStampList::iterator   - take a guess
02720     Returns:    -
02721     Purpose:    These flags determine what will happen in the NodePathUpdate function which is called
02722                 after the freehand/brush or bezier tool is used to edit a brushed nodepath
02723     SeeAlso:    -
02724 
02725 ********************************************************************************************/
02726 
02727 void BrushAttrValue::SetTimeStampUpdateType(ListUpdateType Update)
02728 {
02729     m_TimeStampUpdateType = Update;
02730 }
02731 
02732 
02733 /********************************************************************************************
02734 
02735 >   ListUpdateType GetTimeStampUpdateType()
02736 
02737     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02738     Created:    6/10/99
02739     Inputs:     -
02740     Returns:    the member, described above
02741     Purpose:    As above
02742     SeeAlso:    -
02743 
02744 ********************************************************************************************/
02745 
02746 ListUpdateType BrushAttrValue::GetTimeStampUpdateType()
02747 {
02748     return m_TimeStampUpdateType;
02749 }
02750 
02751         
02752 /********************************************************************************************
02753 
02754 
02755 >   BOOL BrushAttrValue::WriteTimeStampList(BaseCamelotFilter *pFilter)
02756 
02757     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02758     Created:    13/12/99
02759     Inputs:     pfilter - filter to write to
02760     Returns:    TRUE if the list is correctly written
02761     Purpose:    If this brush uses timestamping then this function writes the timestamped
02762                 list to the filter provided.  
02763 
02764     SeeAlso:    AttrBrushType::WritePreChildrenNative; BrushAttrRecordHandler::HandleRecord
02765 
02766 ********************************************************************************************/
02767 
02768 BOOL BrushAttrValue::WriteTimeStampList(BaseCamelotFilter* pFilter)
02769 {
02770     ERROR2IF(pFilter == NULL, FALSE, "Filter is NULL in BrushAttrValue::WriteTimeStampList");
02771 
02772     if (m_pTimeStampList == NULL)
02773         return TRUE; // return TRUE else we'll spring an error
02774 
02775     INT32 NumObjects = (INT32)m_pTimeStampList->size();
02776     // make ourselves a record
02777     CXaraFileRecord Record ( static_cast<INT32> ( TAG_TIMESTAMPBRUSHDATA ),
02778                              static_cast<INT32> ( TAG_TIMESTAMPBRUSHDATA_SIZE ) );
02779     BOOL ok = Record.Init();
02780 
02781     // the first entry in the record is how many objects there are
02782     if (ok) ok = Record.WriteINT32(NumObjects);
02783     
02784     // now write the data
02785     TimeStampBrushPoint ListItem;
02786     TimeStampList::iterator ListPos = m_pTimeStampList->begin();
02787     while( ok && ListPos != m_pTimeStampList->end() )
02788     {
02789         ListItem = *ListPos; ++ListPos;
02790         ok = ListItem.WriteNative(&Record);
02791     }
02792 
02793     if (ok) ok = pFilter->Write(&Record);
02794 
02795     return ok;
02796 }
02797 
02798         
02799 /********************************************************************************************
02800 
02801 
02802 >   BOOL BrushAttrValue::WritePressureData(BaseCamelotFilter *pFilter)
02803 
02804     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02805     Created:    13/12/99
02806     Inputs:     pfilter - filter to write to
02807     Returns:    TRUE if the list is correctly written
02808     Purpose:    If this attribute contains pressure data then it will write out that data to 
02809                 the filter provided.
02810 
02811     SeeAlso:    AttrBrushType::WritePreChildrenNative; BrushAttrRecordHandler::HandleRecord
02812 
02813 ********************************************************************************************/
02814 
02815 BOOL BrushAttrValue::WritePressureData(BaseCamelotFilter* pFilter)
02816 {
02817     ERROR2IF(pFilter == NULL, FALSE, "Filter is NULL in BrushAttrValue::WriteTimeStampList");
02818 
02819     if (m_pPressureSampler == NULL)
02820         return TRUE; // return TRUE else we'll spring an error
02821 
02822     // make ourselves a record
02823     CXaraFileRecord Record ( static_cast<INT32> ( TAG_BRUSHPRESSURESAMPLEDATA ),
02824                              static_cast<INT32> ( TAG_BRUSHSAMPLEDATA_SIZE ) );
02825     BOOL ok = Record.Init();
02826 
02827     if (ok) ok = m_pPressureSampler->WriteNative(&Record);
02828 
02829     if (ok) ok = pFilter->Write(&Record);
02830 
02831     return ok;
02832 
02833 }
02834 
02835 /*--------------------------------------------------------------------------
02836 ----------------------------------------------------------------------------
02837             AttrBrushType class
02838 */
02839 
02840 
02841 /********************************************************************************************
02842 
02843 >   AttrBrushType::AttrBrushType()
02844 
02845     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02846     Created:    7/1/97
02847 
02848     Purpose:    Default constructor for AttrBrushType
02849 
02850 ********************************************************************************************/
02851 
02852 AttrBrushType::AttrBrushType()
02853 {
02854     m_pFreeTool = NULL;
02855     m_pLocalStrokeColour = NULL;
02856     m_pBlendedStrokeColour = NULL;
02857     m_LocalTranspType = 0;
02858     m_LocalTranspValue = 0;
02859 }
02860 
02861 
02862 
02863 /********************************************************************************************
02864 
02865 >   AttrBrushType::AttrBrushType(Node *ContextNode,
02866                                         AttachNodeDirection Direction,
02867                                         BOOL Locked,
02868                                         BOOL Mangled,
02869                                         BOOL Marked,
02870                                         BOOL Selected)
02871     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02872     Created:    7/1/97
02873 
02874     Purpose:    Constructs an AttrBrushType Attribute
02875 
02876 ********************************************************************************************/
02877 
02878 AttrBrushType::AttrBrushType(Node *ContextNode,
02879                                     AttachNodeDirection Direction,
02880                                     BOOL Locked,
02881                                     BOOL Mangled,
02882                                     BOOL Marked,
02883                                     BOOL Selected)
02884                 : NodeAttribute(ContextNode, Direction, Locked, Mangled, Marked, Selected)
02885 {
02886     m_pFreeTool = NULL;
02887     m_pLocalStrokeColour = NULL;
02888     m_pBlendedStrokeColour = NULL;
02889     m_LocalTranspType = 0;
02890     m_LocalTranspValue = 0;
02891 }
02892 
02893 
02894 /********************************************************************************************
02895 
02896 >   AttrBrushType::~AttrBrushType()
02897     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02898     Created:    7/1/97
02899 
02900     Purpose:    destructor
02901 
02902 ********************************************************************************************/
02903 
02904 AttrBrushType::~AttrBrushType()
02905 {
02906     // if we are a blended attribute then our processor must destroy its blended brushdefinition
02907     /*PathProcessorBrush* pPPB =*/ m_Value.GetPathProcessor();
02908     
02909     // ask our attrval to delete its path processor
02910     m_Value.SetPathProcessor(NULL);
02911     
02912 }
02913 
02914 
02915 /********************************************************************************************
02916 
02917 >   virtual void AttrBrushType::Render(RenderRegion *pRender)
02918 
02919     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02920     Created:    7/1/97
02921 
02922     Purpose:    Renders this attribute (by simply calling the Render function of
02923                 its contained AttributeValue)
02924 
02925 ********************************************************************************************/
02926 
02927 void AttrBrushType::Render(RenderRegion *pRender)
02928 {
02929 
02930     // what it says
02931     FindNearestStrokeTransp();
02932 
02933     // tell the processor who it belongs to 
02934     PathProcessorBrush* pPPB = m_Value.GetPathProcessor();
02935     if (pPPB != NULL)
02936         pPPB->SetParentAttribute(this);
02937 
02938     if (m_pFreeTool != NULL)
02939     {
02940         String_32 ProgressString = _T("Processing Brush");
02941         Progress Hourglass(&ProgressString, -1, FALSE);
02942         TRACEUSER("Diccon", _T("About to do first render\n") );
02943     
02944         GetAttributeValue()->Render(pRender);
02945 
02946         // if we have pressure then we must invalidate our parent nodepath
02947         Node* pParent = FindParent();
02948         if (pParent != NULL && pParent->IsNodePath() && ContainsPressureCache())
02949         {
02950             ((NodeRenderableInk*)pParent)->InvalidateBoundingRect();
02951         }
02952         m_pFreeTool = NULL;
02953     }
02954     else
02955     {
02956 #ifdef NEWFASTBRUSHES
02957         BrushAttrValue* pAttr = (BrushAttrValue*) GetAttributeValue();
02958         pAttr->SetBoundsParent (FindParent ());
02959 #endif
02960         GetAttributeValue()->Render(pRender);
02961     }
02962 }
02963 
02964 /********************************************************************************************
02965 
02966 >   SubtreeRenderState AttrBrushType::RenderSubtree(RenderRegion *pRender, Node** ppNextNode, BOOL bClip = TRUE)
02967 
02968     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02969     Created:    07/02/94
02970     Inputs:     pRender - A pointer to the current render region
02971     Returns:    TRUE  => This node should be rendered,
02972                 FALSE => This node does not need to be rendered.
02973     Purpose:    Basically we want to avoid the situation of recursive path processing for 
02974                 brushes.  Therefore if there is already a path processor of the same type
02975                 as this one on the stack then we should not render
02976 
02977     SeeAlso:    Node::NeedsToRender
02978 
02979 ********************************************************************************************/
02980 
02981 SubtreeRenderState AttrBrushType::RenderSubtree(RenderRegion *pRender, Node** ppNextNode, BOOL bClip)
02982 {
02983 //  BOOL Retval = TRUE;
02984     PathProcessorBrush* pPPB = GetPathProcessor();
02985     if (pPPB != NULL)
02986     {
02987         // pRender can legally be null, but we don't want to proliferate passing null pointers around
02988         if (pRender != NULL && pPPB->IsThisPathProcessorOnTheStack(pRender))
02989             return SUBTREE_NORENDER;
02990     }
02991 
02992     return SUBTREE_ROOTONLY;
02993 }
02994 
02995 
02996 /*********************************************************************************************
02997 
02998 >    BOOL AttrBrushType::EffectsParentBounds() const
02999 
03000      Author:    Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03001      Created:   20/12/99
03002      Inputs:    -
03003      Outputs:   -
03004      Returns:   TRUE if the node will effect the bounds of it's parent.
03005      Purpose:   Virtual function for determining if the node will effect it's parent bounds.
03006                 eg. ArrowHeads.
03007      SeeAlso:   NodeAttribute::GetAttrBoundingRect
03008 
03009 **********************************************************************************************/
03010        
03011 BOOL AttrBrushType::EffectsParentBounds()
03012 {
03013     return TRUE;
03014 }
03015 
03016 
03017 /*********************************************************************************************
03018 
03019 >    DocRect AttrBrushType::GetAttrBoundingRect(NodeRenderableInk* pParent)
03020 
03021      Author:    Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03022      Created:   20/12/99
03023      Inputs:    pParent, the parent Ink node that this attribute will effect.
03024                 pAttribMap - not used
03025      Outputs:   -
03026      Returns:   The Bounding rect of the attribute (NULL rectangle is it doesn't have any).
03027      Purpose:   Virtual function for determining the bounding rect of an attribute.
03028                 Simply calls the brush value which does the calculation
03029      SeeAlso:   NodeAttribute::EffectsParentBounds
03030 
03031 **********************************************************************************************/
03032        
03033 DocRect AttrBrushType::GetAttrBoundingRect(NodeRenderableInk* pParent, CCAttrMap* pAttribMap )
03034 {
03035     ERROR2IF(pParent == NULL, DocRect(0,0,0,0) , "Parent node is NULL in AttrBrushType::GetAttrBoundingRect");
03036 
03037     BrushAttrValue* pVal = (BrushAttrValue*)GetAttributeValue();
03038     if (pVal == NULL)
03039         return DocRect(0, 0, 0, 0);
03040     else
03041     {
03042         // bit of a hack - the PPB needs to know that we are its parents, and if we have not yet rendered then
03043         // it may not know that yet
03044         PathProcessorBrush* pPPB = pVal->GetPathProcessor();
03045         if (pPPB != NULL)
03046         {
03047             pPPB->SetParentAttribute(this);
03048             
03049             // set the line width
03050             MILLIPOINT Width = GetAppliedLineWidth();
03051             if (Width > 500)
03052             {
03053                 SetValueToScaleTo(Width);
03054             }
03055             else
03056                 return DocRect(0, 0, 0, 0);  // if its too small then just return as we'll generate infinite objects
03057         }
03058         
03059     }
03060     return pVal->GetAttrBoundingRect(pParent);
03061 
03062 }
03063 
03064 /***********************************************************************************************
03065 
03066 >   virtual void AttrBrushType::CopyNodeContents(AttrBrushType *NodeCopy)
03067 
03068     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03069     Created:    13/12/99
03070 
03071     Outputs:    NodeCopy - returned containing a copy of this node
03072          
03073     Purpose:    Copies the node's contents to the node pointed to by NodeCopy
03074 
03075 ***********************************************************************************************/
03076 
03077 void AttrBrushType::CopyNodeContents(AttrBrushType *NodeCopy)
03078 {
03079     // Let the base class do its bit
03080     NodeAttribute::CopyNodeContents(NodeCopy);
03081 
03082     // And then copy our Value
03083     *(NodeCopy->GetAttributeValue()) = *(GetAttributeValue());
03084 }
03085 
03086 
03087 
03088 /***********************************************************************************************
03089 >   void AttrBrushType::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03090 
03091     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03092     Created:    18/12/2003
03093     Outputs:    -
03094     Purpose:    Polymorphically copies the contents of this node to another
03095     Errors:     An assertion failure will occur if NodeCopy is NULL
03096     Scope:      protected
03097                                      
03098 ***********************************************************************************************/
03099 
03100 void AttrBrushType::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03101 {
03102     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
03103     ENSURE(IS_A(pNodeCopy, AttrBrushType), "PolyCopyNodeContents given wrong dest node type");
03104 
03105     if (IS_A(pNodeCopy, AttrBrushType))
03106         CopyNodeContents((AttrBrushType*)pNodeCopy);
03107 }
03108 
03109 
03110 
03111 /***********************************************************************************************
03112 
03113 >   virtual INT32 AttrBrushType::operator==(const NodeAttribute &NodeAttrib); 
03114 
03115     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03116     Created:    13/12/99
03117 
03118     Inputs:     NodeAttrib - The node to compare this node to
03119     Returns:    TRUE if the nodes are considered equal
03120 
03121     Purpose:    Comparison operator - determines if the AttributeValues of both objects are ==
03122 
03123 ***********************************************************************************************/
03124 
03125 INT32 AttrBrushType::operator==(const NodeAttribute &NodeAttrib)
03126 {
03127     // First check they are of the same type
03128     if (((NodeAttribute*)&NodeAttrib)->GetAttributeType() != GetAttributeType())
03129         return FALSE;
03130 
03131     // Make a more sensible pointer
03132     AttrBrushType *Attr = (AttrBrushType *) &NodeAttrib;
03133 
03134     // Now let the AttributeValues compare themselves
03135     return( *((BrushAttrValue *) Attr->GetAttributeValue())  ==
03136             *((BrushAttrValue *) GetAttributeValue()) );
03137 }
03138 
03139 
03140 
03141 /********************************************************************************************
03142 
03143 >   virtual Node *AttrBrushType::SimpleCopy()
03144 
03145     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03146     Created:    13/12/99
03147 
03148     Returns:    A copy of the node, or NULL if memory runs out 
03149 
03150     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
03151                 The function is virtual, and must be defined for all derived classes.  
03152 
03153 ********************************************************************************************/
03154 
03155 Node *AttrBrushType::SimpleCopy()
03156 {
03157     AttrBrushType* NodeCopy = new AttrBrushType;
03158     if (NodeCopy == NULL)
03159         return(NULL);
03160 
03161     // Call the base class
03162     NodeAttribute::CopyNodeContents(NodeCopy);
03163 
03164     // And call our AttributeValue to copy itself too
03165     NodeCopy->GetAttributeValue()->SimpleCopy(GetAttributeValue());
03166     
03167     // tell the new path processor who is boss
03168     PathProcessorBrush* pPPB = NodeCopy->GetPathProcessor();
03169     if (pPPB != NULL)
03170         pPPB->SetParentAttribute(NodeCopy);
03171 
03172     return(NodeCopy);
03173 }
03174 
03175 
03176 
03177 /********************************************************************************************
03178 
03179 >   virtual UINT32 AttrBrushType::GetAttrNameID(void)
03180 
03181     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03182     Created:    13/12/99
03183 
03184     Returns:    Attribute description string-resource ID
03185 
03186     Purpose:    Retrieves a string resource ID describing this attribute
03187 
03188 ********************************************************************************************/
03189 
03190 UINT32 AttrBrushType::GetAttrNameID(void)
03191 {
03192     return(_R(IDS_ATTRBRUSH));
03193 }
03194 
03195 /********************************************************************************************
03196 >   virtual BOOL AttrStokeType::NeedsTransparency() const
03197 
03198     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03199     Created:    7/2/97
03200     Inputs:     -
03201     Outputs:    -
03202     Returns:    TRUE if this Attribute requires transparency mode to render properly.
03203     Purpose:    Strokes like the airbrush require transparency to be turned on to work.
03204     Errors:     -
03205 ********************************************************************************************/
03206 
03207 BOOL AttrBrushType::NeedsTransparency() const
03208 {
03209     BOOL SoWeDoReallyNeedTransparencyThenDoWe = FALSE;
03210     
03211     PathProcessorBrush *pPathProc = m_Value.GetPathProcessor();
03212     if(pPathProc != NULL)
03213     {
03214         SoWeDoReallyNeedTransparencyThenDoWe = pPathProc->NeedsTransparency();
03215     }
03216 
03217     return SoWeDoReallyNeedTransparencyThenDoWe;
03218 }
03219 
03220 
03221 /********************************************************************************************
03222 
03223 >   virtual void AttrBrushType::GetDebugDetails(StringBase *Str)
03224 
03225     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03226     Created:    13/12/99
03227 
03228     Outputs:    On return, Str is filled in with details on this node
03229 
03230     Purpose:    Produces debug details about this node
03231 
03232 ********************************************************************************************/
03233 
03234 void AttrBrushType::GetDebugDetails(StringBase *Str)
03235 {
03236 #ifdef _DEBUG
03237     NodeAttribute::GetDebugDetails(Str);
03238 
03239     String_256 TempStr;
03240     TempStr._MakeMsg( _T("\r\nBrush #1%s\r\n"),
03241                         (m_Value.GetPathProcessor() == NULL) ? _T("old-style line") : _T("new stroke:") );
03242     *Str += TempStr;
03243 
03244     if (m_Value.GetPathProcessor() != NULL)
03245     {
03246         TempStr._MakeMsg( _T("  #1%s\r\n"),
03247                             m_Value.GetPathProcessor()->GetRuntimeClass()->GetClassName() );
03248         *Str += TempStr;
03249     }
03250 
03251     //TempStr._MakeMsg("\r\nNeedsTransparency=#1%s\r\n", NeedsTransparency() ? "TRUE" : "FALSE");
03252     //*Str += TempStr;
03253 
03254     TempStr._MakeMsg( _T("\r\nDefinition Handle=#1%d\r\n"), GetBrushHandle() );
03255     *Str += TempStr;
03256 #endif
03257 }
03258 
03259 /********************************************************************************************
03260 
03261 >   BOOL AttrBrushType::Blend(BlendAttrParam* pBlendParam)
03262 
03263     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03264     Created:    17/3/2000
03265     Inputs:     pBlendParam - contains the blend info, 
03266     Outputs:    pBlendParama -  containing the blended attributes
03267     Returns:    TRUE - Blend went ok, the blended attr val is valid; FALSE if not.
03268     Purpose:    Blends between two brush attributes. In fact at the moment it just blends
03269                 between the parameters in the two path processors.  At some point it should
03270                 also blend between the ink objects and attributes.
03271             
03272     Errors:     Out of memory.
03273 
03274 ********************************************************************************************/
03275 
03276 BOOL AttrBrushType::Blend(BlendAttrParam* pBlendParam)
03277 {
03278     // Check entry param isn't NULL
03279     ERROR3IF(pBlendParam == NULL,"NULL entry param");
03280     if (pBlendParam == NULL) return FALSE;
03281 
03282     // Get the Value member to blend to the Value member of the other NodeAttribute.
03283     // If it succeeds, ask the blended Value to make a NodeAttribute out of itself.
03284 
03285     if (GetAttributeValue()->Blend(pBlendParam))
03286     {
03287         // Get the blended attr val. After this call, the ptr is our reponsibility
03288         // so we have to delete it if it's no longer needed
03289         AttributeValue* pBlendedAttrVal = pBlendParam->GetBlendedAttrVal();
03290 
03291         if (pBlendedAttrVal != NULL)
03292         {
03293             // We have a blended attr val, so ask it to make a NodeAttribute out of itself
03294             // and set the pBlendParam's blended NodeAttribute ptr to it
03295             NodeAttribute* pBlendedAttr = pBlendedAttrVal->MakeNode();
03296             pBlendParam->SetBlendedAttr(pBlendedAttr);
03297 
03298             if (pBlendedAttr != NULL)
03299             {
03300                 // We were able to make a blended NodeAttribute
03301                 // so delete the blended attr val, and return TRUE
03302                 ((BrushAttrValue*)pBlendedAttrVal)->SetPathProcessor(NULL);
03303                 delete pBlendedAttrVal;
03304                 return TRUE;
03305             }
03306             else
03307             {
03308                 // Couldn't make a blended NodeAttribute, so give the blended attr val back
03309                 // and return FALSE
03310                 pBlendParam->SetBlendedAttrVal(pBlendedAttrVal);
03311                 return FALSE;
03312             }
03313         }
03314     }
03315 
03316     return FALSE;
03317 }
03318 
03319 
03320 
03321 /********************************************************************************************
03322 
03323 >   virtual BOOL AttrBrushType::DoBecomeA(BecomeA* pBecomeA, Node* pParent)
03324 
03325     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03326     Created:    17/3/2000
03327     Inputs:     pBecomeA - the becomeA object that tells us what to do
03328                 pParent - the node that this attribute is applied to
03329     Outputs:    
03330     Returns:    TRUE if everything went ok,
03331     Purpose:    Its a little unusual for attributes to have their own dobecomea function but 
03332                 the brush requires one because the node that it is applied to will not know 
03333                 anything about it.  It is designed to be called by the node that has this 
03334                 brush applied to it.
03335                 Note that all the real work goes on in the attribute value and path processor.
03336 
03337 ********************************************************************************************/
03338 
03339 BOOL AttrBrushType::DoBecomeA(BecomeA* pBecomeA, Node* pParent)
03340 {
03341     ERROR2IF(pBecomeA == NULL, FALSE, "BecomeA pointer is NULL in AttrBrushType::DoBecomeA");
03342     ERROR2IF(pParent == NULL, FALSE, "Parent node is NULL in AttrBrushType::DoBecomeA");
03343     PathProcessorBrush* pPPB = m_Value.GetPathProcessor();
03344     if (pPPB)
03345         pPPB->SetParentAttribute(this);
03346     
03347     return m_Value.DoBecomeA(pBecomeA, pParent);
03348 }
03349 
03350 /********************************************************************************************
03351 
03352 >   virtual UINT32 AttrBrushType::GetNodeSize() const
03353 
03354     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03355     Created:    13/12/99
03356 
03357     Returns:    The size of this node, in bytes
03358 
03359     Purpose:    For finding the size of the node, in bytes
03360 
03361 ********************************************************************************************/
03362 
03363 UINT32 AttrBrushType::GetNodeSize() const
03364 {
03365     return(sizeof(AttrBrushType));
03366 }
03367 
03368 
03369 /********************************************************************************************
03370 
03371 >   virtual UINT32 AttrBrushType::GetNodeSize() const
03372 
03373     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03374     Created:    13/12/99
03375 
03376     Returns:    The size of this node, in bytes
03377 
03378     Purpose:    For finding the size of the node, in bytes
03379 
03380 ********************************************************************************************/
03381 
03382 String_32 AttrBrushType::GetBrushName()
03383 {
03384     String_32 Name = TEXT(" ");
03385 
03386     BrushDefinition* pDef = GetBrushDefinition();
03387     if (pDef != NULL)
03388     {
03389         String_32* pName = pDef->GetLineName();
03390         if (pName != NULL)
03391             Name = *pName;
03392     }
03393     return Name;
03394 }
03395 
03396 /********************************************************************************************
03397 
03398 >   void AttrBrushType::FindNearestStrokeColour()
03399 
03400     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03401     Created:    13/12/99
03402 
03403     Returns:    -
03404 
03405     Purpose:    Locates the nearest stroke colour attribute, takes the colour and stores
03406                 it in our member variable.  Note that it also converts the colour if it is
03407                 an IndexedColour.
03408 
03409 ********************************************************************************************/
03410 
03411 void AttrBrushType::FindNearestStrokeColour()
03412 {
03413     NodeRenderableInk* pParent = (NodeRenderableInk*)FindParent();
03414     if (pParent == NULL)
03415     {
03416     //  ERROR3("Wheres my parent?!");  Might be a default, so don't error
03417         return;
03418     }
03419     // if its a controller we want its ink node
03420     if (pParent->IsCompoundClass())
03421     {
03422         NodeRenderableInk* pInk = ((NodeCompound*)pParent)->GetInkNodeFromController();
03423         if (pInk)
03424             pParent = pInk;
03425     }
03426     
03427     
03428     NodeAttribute* pStrokeColour = NULL;
03429     
03430     // get the attribute
03431     pParent->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), &pStrokeColour);
03432 
03433     if (pStrokeColour == NULL)
03434         return;
03435 
03436     // get the stroke colour
03437     StrokeColourAttribute* pVal = (StrokeColourAttribute*)pStrokeColour->GetAttributeValue();
03438     if (pVal != NULL)
03439     {
03440         // we're only interested in the actual colour
03441         m_pLocalStrokeColour = &(pVal->Colour);
03442     }
03443     else
03444         TRACEUSER("Diccon", _T("Unable to find local stroke colour\n") );
03445 
03446 }
03447 
03448 
03449 /********************************************************************************************
03450 
03451 >   void AttrBrushType::FindNearestStrokeTransp()
03452 
03453     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03454     Created:    13/12/99
03455     Returns:    -
03456     Purpose:    Finds the local stroke transparency and caches the transparency value and type
03457 ********************************************************************************************/
03458 
03459 void AttrBrushType::FindNearestStrokeTransp()
03460 {
03461     m_LocalTranspValue = 0;
03462     m_LocalTranspType = 0;
03463 
03464     NodeRenderableInk* pParent = (NodeRenderableInk*)FindParent();
03465     if (pParent == NULL || !pParent->IsAnObject())
03466     {
03467     //  ERROR3("Wheres my parent?!");  Might be a default, so don't error
03468         return;
03469     }
03470 
03471     // if its a controller we want its ink node
03472     if (pParent->IsCompoundClass())
03473     {
03474         NodeRenderableInk* pInk = ((NodeCompound*)pParent)->GetInkNodeFromController();
03475         if (pInk)
03476             pParent = pInk;
03477     }
03478 
03479     NodeAttribute* pStrokeTransp = NULL;
03480 
03481     // get the attribute
03482     pParent->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeTransp), &pStrokeTransp, FALSE);
03483 
03484     if (pStrokeTransp == NULL)
03485         return;
03486 
03487     // get the stroke transparency
03488     StrokeTranspAttribute* pVal = (StrokeTranspAttribute*)pStrokeTransp->GetAttributeValue();
03489     if (pVal != NULL)
03490     {
03491         // we're only interested in the actual colour
03492         m_LocalTranspValue = *pVal->GetStartTransp();
03493         m_LocalTranspType = pVal->GetTranspType();
03494     }   
03495 }
03496 
03497 /********************************************************************************************
03498 
03499 >   DocColour AttrBrushType::GetLocalStrokeColour()
03500 
03501     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03502     Created:    13/12/99
03503 
03504     Returns:    the colour of the stroke that this attribute is applied to, or a default 'blank'
03505                 colour if we don't have a stroke
03506 
03507     Purpose:    Returns either the blended or local stroke colour.  Given that the blended colour
03508                 is null unless we are in a blend it takes priority when it does exist.
03509 
03510 ********************************************************************************************/
03511 
03512 DocColour AttrBrushType::GetLocalStrokeColour()
03513 {
03514     DocColour Col;
03515     if (m_pBlendedStrokeColour != NULL)
03516         Col = * m_pBlendedStrokeColour;
03517     else if (m_pLocalStrokeColour != NULL)
03518         Col = *m_pLocalStrokeColour;
03519 
03520     return Col;
03521 }
03522 
03523 
03524 /********************************************************************************************
03525 
03526 >   void AttrBrushType::SetBlendedStrokeColour(DocColour* pCol)
03527 
03528     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03529     Created:    13/12/99
03530     Inputs:     pointer to stroke colour in the blend
03531     Returns:    -
03532     Purpose:    Tells the attribute that pCol is the stroke colour for the current blend step.
03533 ********************************************************************************************/
03534 
03535 void AttrBrushType::SetBlendedStrokeColour(DocColour* pCol)
03536 {
03537     m_pBlendedStrokeColour = pCol;
03538 }
03539 
03540 
03541 /********************************************************************************************
03542 
03543 >   UINT32 AttrBrushType::GetLocalTranspValue()
03544 
03545     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03546     Created:    13/12/99
03547 
03548     Returns:    the value of the local stroke transparency that we cached
03549     Purpose:    -
03550 ********************************************************************************************/
03551 
03552 UINT32 AttrBrushType::GetLocalTranspValue()
03553 {
03554     return m_LocalTranspValue;
03555 }
03556 
03557 
03558 /********************************************************************************************
03559 
03560 >   DocColour AttrBrushType::GetLocalStrokeColour()
03561 
03562     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03563     Created:    13/12/99
03564 
03565     Returns:    the type of the local stroke transparency that we cached
03566     Purpose:    -
03567 ********************************************************************************************/
03568 
03569 UINT32 AttrBrushType::GetLocalTranspType()
03570 {
03571     return m_LocalTranspType;
03572 }
03573 
03574 /********************************************************************************************
03575 
03576 >   BrushDefinition* AttrBrushType::GetBrushDefinition() 
03577 
03578     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03579     Created:    6/10/99
03580     Inputs:     -
03581     Returns:    the brush definition used by this brush (can be NULL)
03582     Purpose:    interface to the BrushAttrValue
03583     SeeAlso:    -
03584 
03585 ********************************************************************************************/
03586 
03587 BrushDefinition* AttrBrushType::GetBrushDefinition()
03588 {
03589     return m_Value.GetBrushDefinition();
03590 }
03591 
03592 
03593 /********************************************************************************************
03594 
03595 >   BrushHandle AttrBrushType::GetBrushHandle() 
03596 
03597     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03598     Created:    6/10/99
03599     Inputs:     -
03600     Returns:    handle of the brush definition used by this brush (can be NULL)
03601     Purpose:    interface to the BrushAttrValue
03602     SeeAlso:    -
03603 
03604 ********************************************************************************************/
03605 
03606 BrushHandle AttrBrushType::GetBrushHandle()
03607 {
03608     return m_Value.GetBrushHandle();
03609 }
03610 
03611 
03612 /********************************************************************************************
03613 
03614 >   virtual BOOL AttrBrushType::IsABrush() const
03615 
03616     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03617     Created:    13/12/99
03618     Returns:    TRUE
03619     Purpose:    For identifying this as a brush attribute
03620 
03621 ********************************************************************************************/
03622 
03623 BOOL AttrBrushType::IsABrush() const
03624 {
03625     return TRUE;
03626 }
03627 
03628 
03629 /********************************************************************************************
03630 
03631 >   MILLIPOINT AttrBrushType::GetDefaultLineWidth(BOOL IgnorePressure) 
03632 
03633     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03634     Created:    6/10/99
03635     Inputs:     -
03636     Returns:    the height of the largest object in this brush
03637     Purpose:    convenient interface to the attribute value
03638     SeeAlso:    -
03639 
03640 ********************************************************************************************/
03641 
03642 MILLIPOINT AttrBrushType::GetDefaultLineWidth(BOOL IgnorePressure)
03643 {
03644     return m_Value.GetDefaultLineWidth(IgnorePressure);
03645 }
03646 
03647 /********************************************************************************************
03648 
03649 >   BOOL AttrBrushType::SetSpacing(MILLIPOINT NewSpacing) 
03650 
03651     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03652     Created:    6/10/99
03653     Inputs:     the spacing value to set
03654     Returns:    TRUE if successful, FALSE if not
03655     Purpose:    To set the spacing between brush objects
03656     SeeAlso:    -
03657 
03658 ********************************************************************************************/
03659 
03660 BOOL AttrBrushType::SetSpacing(MILLIPOINT NewSpacing)
03661 {
03662     PathProcessorBrush* pPathProc = m_Value.GetPathProcessor();
03663     if (pPathProc == NULL)
03664         return FALSE;
03665 
03666 
03667     return pPathProc->SetSpacing(NewSpacing);
03668 }
03669 
03670 
03671 /********************************************************************************************
03672 
03673 >   MILLIPOINT AttrBrushType::GetScaling() 
03674 
03675     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03676     Created:    6/10/99
03677     Inputs:     -
03678     Returns:    the current brush spacing value
03679     Purpose:    -
03680     SeeAlso:    -
03681 
03682 ********************************************************************************************/
03683 
03684 MILLIPOINT AttrBrushType::GetSpacing()
03685 {
03686     PathProcessorBrush* pPathProc = m_Value.GetPathProcessor();
03687     if (pPathProc == NULL)
03688         return -1;
03689     return (MILLIPOINT)pPathProc->GetSpacing();
03690 }
03691 
03692 
03693 
03694 /********************************************************************************************
03695 
03696 >   BOOL AttrBrushType::SetScaling(double NewScaling) 
03697 
03698     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03699     Created:    6/10/99
03700     Inputs:     the scaling value to set
03701     Returns:    TRUE if successful, FALSE if not
03702     Purpose:    To set the brush scaling
03703     SeeAlso:    -
03704 
03705 ********************************************************************************************/
03706 
03707 BOOL AttrBrushType::SetScaling(double NewScale)
03708 {
03709     PathProcessorBrush* pPPB = m_Value.GetPathProcessor();
03710     if (pPPB == NULL)
03711         return FALSE;
03712     return pPPB->SetBrushScaling(NewScale);
03713 }
03714 
03715 /********************************************************************************************
03716 
03717 >   BOOL AttrBrushType::SetPathOffsetType(PathOffset NewOffsetType) 
03718 
03719     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03720     Created:    6/10/99
03721     Inputs      Offset - the offset type to set
03722     Returns:    - 
03723     Purpose:    to set the offset type for this brush
03724 ********************************************************************************************/
03725 
03726 BOOL AttrBrushType::SetPathOffsetType(PathOffset NewOffsetType)
03727 {
03728     PathProcessorBrush* pPathProc = m_Value.GetPathProcessor();
03729     if (pPathProc == NULL)
03730         return FALSE;
03731     pPathProc->SetPathOffsetType(NewOffsetType);
03732     return TRUE;
03733 }
03734 
03735 /********************************************************************************************
03736 
03737 >   BOOL AttrBrushType::SetPathOffsetValue(MILLIPOINT Value) 
03738 
03739     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03740     Created:    6/10/99
03741     Inputs      Value - the offset value to set
03742     Returns:    - 
03743     Purpose:    to set the offset distance for this brush
03744 ********************************************************************************************/
03745 
03746 BOOL AttrBrushType::SetPathOffsetValue(MILLIPOINT NewValue)
03747 {
03748     PathProcessorBrush* pPathProc = m_Value.GetPathProcessor();
03749     if (pPathProc == NULL)
03750         return FALSE;
03751     pPathProc->SetPathOffsetValue(NewValue);
03752     return TRUE;
03753 }
03754 
03755 
03756 /********************************************************************************************
03757 
03758 >   BOOL AttrBrushType::SetTiling(BOOL Value) 
03759 
03760     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03761     Created:    6/10/99
03762     Inputs:     whether or not the brush tiles
03763     Returns:    TRUE if successful, FALSE otherwise
03764     Purpose:    When a brush tiles it means that the attribute types:
03765                 - 3 colour fill
03766                 - 4 colour fill
03767                 - bitmap fill
03768                 are only rendered once per brush, rather than for every brush step
03769     SeeAlso:    -
03770 
03771 ********************************************************************************************/
03772 
03773 BOOL AttrBrushType::SetTiled(BOOL Tiled)
03774 {
03775     PathProcessorBrush* pPathProc = m_Value.GetPathProcessor();
03776     if (pPathProc == NULL)
03777         return FALSE;
03778     pPathProc->SetTiling(Tiled);
03779     return TRUE;
03780 }
03781 
03782 
03783 /********************************************************************************************
03784 
03785 >   BOOL AttrBrushType::SetRotateAngle(double Angle) 
03786 
03787     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03788     Created:    6/10/99
03789     Inputs:     the angle of rotation to set
03790     Returns:    TRUE if the angle is within the stated bounds
03791     Purpose:    as above
03792     SeeAlso:    -
03793 
03794 ********************************************************************************************/
03795 
03796 BOOL AttrBrushType::SetRotateAngle(double NewAngle)
03797 {
03798     PathProcessorBrush* pPathProc = m_Value.GetPathProcessor();
03799     if (pPathProc == NULL)
03800         return FALSE;
03801     return pPathProc->SetRotationAngle(NewAngle);
03802 }
03803 
03804 
03805 /********************************************************************************************
03806 
03807 >   BOOL AttrBrushType::SetRotated(BOOL Value) 
03808 
03809     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03810     Created:    6/10/99
03811     Inputs:     whether or not the brush rotates
03812     Returns:    -
03813     Purpose:    as above
03814     SeeAlso:    -
03815 
03816 ********************************************************************************************/
03817 
03818 BOOL AttrBrushType::SetRotated(BOOL Rotated)
03819 {
03820     PathProcessorBrush* pPathProc = m_Value.GetPathProcessor();
03821     if (pPathProc == NULL)
03822         return FALSE;
03823     pPathProc->SetRotated(Rotated);
03824     return TRUE;
03825 }
03826 
03827 
03828 /********************************************************************************************
03829 
03830 >   PathProcessorBrush* AttrBrushType::GetPathProcessor() 
03831 
03832     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03833     Created:    6/10/99
03834     Inputs:     -
03835     Returns:    the path processor belonging to the attribute value
03836     Purpose:    as above
03837     SeeAlso:    -
03838 
03839 ********************************************************************************************/
03840 
03841 PathProcessorBrush* AttrBrushType::GetPathProcessor()
03842 {
03843     return m_Value.GetPathProcessor();
03844 }
03845 
03846 
03847 
03848 /********************************************************************************************
03849 
03850 >   void AttrBrushType::InitialiseBrushData() 
03851 
03852     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03853     Created:    6/10/99
03854     Inputs:     -
03855     Returns:    -
03856     Purpose:    retrieves data from the path processor and puts it into our brushdata object
03857     SeeAlso:    -
03858 
03859 ********************************************************************************************/
03860 
03861 void AttrBrushType::InitialiseBrushData()
03862 {
03863     PathProcessorBrush* pPPB = GetPathProcessor();
03864     if (pPPB != NULL)
03865         pPPB->CopyBrushData(&m_BrushData);
03866 }
03867 
03868 
03869 
03870 /********************************************************************************************
03871 
03872 >   BrushData AttrBrushType::GetBrushData() 
03873 
03874     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03875     Created:    6/10/99
03876     Inputs:     -
03877     Returns:    our brush data object
03878     Purpose:    gets the latest data from our path processor, copies it into our BrushData object 
03879                 which is then returned;
03880     SeeAlso:    -
03881 
03882 ********************************************************************************************/
03883 
03884 BrushData AttrBrushType::GetBrushData()
03885 {
03886     InitialiseBrushData();
03887     return m_BrushData;
03888 }
03889 
03890 
03891 
03892 /********************************************************************************************
03893 
03894 >   void AttrBrushType::SetBrushData(BrushData Data) 
03895 
03896     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03897     Created:    6/10/99
03898     Inputs:     Data object to set
03899     Returns:    -
03900     Purpose:    Not quite sure why you would use this, as there is no link from the brush data object
03901                 to the path processor at the moment.  hmm
03902     SeeAlso:    -
03903 
03904 ********************************************************************************************/
03905 
03906 void AttrBrushType::SetBrushData(BrushData Data)
03907 {
03908     m_BrushData = Data;
03909 }
03910 
03911 
03912 /********************************************************************************************
03913 
03914 >   void AttrBrushType::GetMaxScalingFromDefinition()
03915 
03916     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03917     Created:    6/10/99
03918     Inputs:     -
03919     Returns:    -
03920     Purpose:    Obtains the max scaling value from the brush definition and sets it to the
03921                 path processor.  This is not needed upon brush creation however it is required
03922                 if you are importing a brush.
03923     SeeAlso:    -
03924 
03925 ********************************************************************************************/
03926 
03927 void AttrBrushType::GetMaxScalingFromDefinition()
03928 {
03929     BrushDefinition* pBrushDef = GetBrushDefinition();
03930     if (pBrushDef != NULL)
03931     {
03932         double Max = pBrushDef->GetMaxScaling();
03933         PathProcessorBrush* pPPB = GetPathProcessor();
03934         if (pPPB != NULL)
03935             pPPB->SetMaxScaling(Max);
03936     }
03937 }
03938 
03939 
03940 /********************************************************************************************
03941 
03942 >   BOOL AttrBrushType::CanUsePointsCache() 
03943 
03944     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03945     Created:    6/10/99
03946     Inputs:     -
03947     Returns:    TRUE if the we are allowed to use the points cache in the brushattrvalue, 
03948                 FALSE if not.
03949     Purpose:    We are not allowed to use the points cache if this attribute is applied to multiple
03950                 ink nodes as a part of a group.  The reason for this is that the paths of the ink
03951                 nodes are passed in to the path processor one by one, this means that the points
03952                 along the first path are cached, and because the cache exists these points are 
03953                 re-used for all subsequent ink objects, meaning that only the first object gets
03954                 drawn.
03955                 Further conditions may be added to this at a later date.
03956     See also:   PathProcessorBrush::GetPointAtDistance          
03957 
03958 ********************************************************************************************/
03959 
03960 BOOL AttrBrushType::CanUsePointsCache()
03961 {
03962     Node* pParent = FindParent();
03963     if (pParent != NULL)
03964     {
03965         if  (pParent->IsCompound()
03966             || pParent->IsABaseTextClass()
03967             || pParent->IsAContour()
03968             )
03969         return FALSE;
03970     }
03971 
03972     return TRUE;
03973 }
03974 
03975 /********************************************************************************************
03976 
03977 >   void AttrBrushType::GetCurrentLineWidth() 
03978 
03979     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03980     Created:    6/10/99
03981     Inputs:     -
03982     Returns:    the width of the nearest linewidth attribute, or -1 if there isn't one (unlikely)
03983     Purpose:    as above
03984     SeeAlso:    -
03985 
03986 ********************************************************************************************/
03987 
03988 MILLIPOINT AttrBrushType::GetAppliedLineWidth()
03989 {
03990     MILLIPOINT ReturnVal = 0;
03991     //first get the parent
03992     NodeRenderableInk* pInk = (NodeRenderableInk*)FindParent();
03993 
03994     // if we're under a nodeshadow controller then we need to ask it for the right ink node
03995     if (pInk != NULL && pInk->IsCompoundClass())
03996     {
03997         NodeRenderableInk* pInkNode = ((NodeCompound*)pInk)->GetInkNodeFromController();
03998         if (pInkNode)
03999             pInk = pInkNode;
04000     }
04001 
04002     if (pInk != NULL)
04003     {
04004         // find the applied AttrLineWidth
04005         NodeAttribute* pAttr = NULL;
04006         BOOL Found = pInk->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrLineWidth), &pAttr);
04007         if (Found && (pAttr != NULL))
04008         {
04009             LineWidthAttribute* pVal = (LineWidthAttribute*)((AttrLineWidth*)pAttr)->GetAttributeValue();
04010             if (pVal != NULL)
04011                 ReturnVal = pVal->LineWidth;
04012         }
04013 
04014         // double check that we don't have a transparent stroke colour
04015         AttrStrokeColour* pStrokeCol = NULL;
04016         pInk->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), (NodeAttribute**)&pStrokeCol, FALSE);
04017         if (pStrokeCol)
04018         {
04019             if (pStrokeCol->Value.Colour.IsTransparent())
04020                 ReturnVal = 0;
04021         }
04022     }
04023 
04024     return ReturnVal;
04025 }
04026 
04027 /********************************************************************************************
04028 
04029 >   void AttrBrushType::SetValueToScaleTo(MILLIPOINT Value) 
04030 
04031     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04032     Created:    6/10/99
04033     Inputs:     linewidth to scale to
04034     Returns:    -
04035     Purpose:    as above
04036     SeeAlso:    -
04037 
04038 ********************************************************************************************/
04039 
04040 void AttrBrushType::SetValueToScaleTo(MILLIPOINT Value)
04041 {
04042     m_Value.ScaleToLineWidth(Value);
04043 }
04044 
04045 
04046 /********************************************************************************************
04047 
04048 >   void AttrBrushType::SetUseLocalTransp(BOOL UseTransp) 
04049 
04050     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04051     Created:    6/10/99
04052     Inputs:     whether or not to use local transparency
04053     Returns:    -
04054     Purpose:    interface to the PPB, sets a member
04055     SeeAlso:    PathProcessorBrush::RenderAttributes
04056 
04057 ********************************************************************************************/
04058 
04059 void AttrBrushType::SetUseLocalTransp(BOOL UseTransp)
04060 {
04061     PathProcessorBrush* pPPB = m_Value.GetPathProcessor();
04062     if (pPPB)
04063         pPPB->SetUseLocalTransp(UseTransp);
04064 }
04065 
04066 /********************************************************************************************
04067 
04068 >   void AttrBrushType::Transform(TransformBase& Transform) 
04069 
04070     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04071     Created:    6/10/99
04072     Inputs:     the transformation to perform
04073     Returns:    -
04074     Purpose:    Currently this simply flushes the cached points map.
04075     SeeAlso:    -
04076 
04077 ********************************************************************************************/
04078 
04079 void AttrBrushType::Transform(TransformBase &Trans)
04080 {
04081 #ifdef NEWFASTBRUSHES
04082     if (m_Value.GetCachedBitmap ())
04083     {
04084         m_Value.GetCachedBitmap ()->Transform (Trans);
04085     }
04086 //  else
04087 //  {
04088 #endif
04089     
04090     if (!Trans.bSolidDrag)
04091     {
04092         // CGS:  my new TransformCache function is three
04093         // times faster than doing it this way!
04094         m_Value.TransformCache(Trans);
04095         m_Value.TransformTimeStampList(Trans);
04096         m_Value.TransformCachedRect(Trans);
04097     }
04098     else
04099     {
04100         // Phil, 10/03/2004
04101         // It may be faster but it doesn't do the job properly during solid dragging.
04102         // The following version works better for solid dragging and ought to be
04103         // reasonably fast because it still uses the cached bounding rect
04104         FlushCache();
04105         m_Value.TransformCachedRect(Trans);
04106     }
04107 
04108 //#ifdef NEWFASTBRUSHES
04109 //}
04110 //#endif
04111 
04112 }
04113 
04114 /********************************************************************************************
04115 
04116 >   void AttrBrushType::FlushCache() 
04117 
04118     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04119     Created:    6/10/99
04120     Inputs:     -
04121     Returns:    -
04122     Purpose:    interface to the BrushAttrValue, tells it to flush the cache of its path processor
04123     SeeAlso:    -
04124 
04125 ********************************************************************************************/
04126 
04127 void AttrBrushType::FlushCache()
04128 {
04129     m_Value.FlushCache();   
04130 }
04131 
04132 
04133 /********************************************************************************************
04134 
04135 >   BOOL AttrBrushType::OnReplaceAttribute(AttrBrushType* pOther)
04136 
04137     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04138     Created:    6/10/99
04139     Inputs:     pOther - the attribute we are about to replace
04140     Returns:    TRUE if successful, FALSE otherwise
04141     Purpose:    If we are applying this attribute to a node that already has a brush attribute then
04142                 we wish to retain certain information,so copy it over before we do the replacing.
04143     SeeAlso:    -
04144 
04145 ********************************************************************************************/
04146 
04147 BOOL AttrBrushType::OnReplaceAttribute(AttrBrushType* pOther)
04148 {
04149     ERROR2IF(pOther == NULL, FALSE, "Null input pointer to AttrBrushType::OnReplaceAttribute");
04150 
04151     PathProcessorBrush* pOldPPB = pOther->GetPathProcessor();
04152     PathProcessorBrush* pNewPPB = GetPathProcessor();
04153     if (pOldPPB != NULL && pNewPPB != NULL)
04154     {
04155         pNewPPB->SetUseLocalFillColour(pOldPPB->GetUseLocalFillColour());
04156         pNewPPB->SetUseNamedColours(pOldPPB->GetUseNamedColours());
04157     }
04158 
04159     // if we have a pressure cache then we want to copy that, also use local colour flags
04160     CDistanceSampler* pPressure = pOther->GetPressureCache();
04161     if (pPressure)
04162     {
04163         CDistanceSampler* pCopyPressure = pPressure->MakeCopy();
04164         if (pCopyPressure)
04165             SetPressureCache(pCopyPressure);
04166     }
04167 
04168     return TRUE;
04169 }
04170 
04171 /********************************************************************************************
04172 
04173 >   void AttrBrushType::NodePathUpdated(Path* pPAth) 
04174 
04175     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04176     Created:    6/10/99
04177     Inputs:     InkPath of the nodepath
04178     Returns:    -
04179     Purpose:    interface to the BrushAttrValue, called when a nodepath is updated, either flushes
04180                 the cache or recalculates the timestamping points distances
04181     SeeAlso:    -
04182 
04183 ********************************************************************************************/
04184 
04185 void AttrBrushType::NodePathUpdated(Path* pPath)
04186 {
04187     // so far as coordinates go, if we are not timestamping then we just flush our cache
04188     if (!IsTimeStamping())
04189         m_Value.FlushCache();
04190     else
04191         m_Value.RecalculateTimeStampList(pPath);
04192 
04193     
04194     // clear our cached bounding rect
04195     m_Value.SetCachedRect(DocRect(0,0,0,0));
04196 }   
04197 
04198 
04199 /********************************************************************************************
04200 
04201 >   BOOL AttrBrushType::IsParentSelected(); 
04202 
04203     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04204     Created:    6/10/99
04205     Inputs:     -
04206     Returns:    TRUE if any ancestor of the brush attribute is selected, FALSE otherwise
04207     Purpose:    To find out if this brush belongs to an ink node that is selected. We simpy
04208                 scan up the tree until we find a selected node or hit the layer.
04209     SeeAlso:    -
04210 
04211 ********************************************************************************************/
04212 
04213 BOOL AttrBrushType::IsParentSelected()
04214 {
04215     BOOL Retval = FALSE;
04216     Node* pParent = FindParent();
04217     while (pParent != NULL && !pParent->IsLayer())
04218     {
04219         if (pParent->IsSelected())
04220         {
04221             Retval = TRUE;
04222             break;
04223         }
04224         pParent = pParent->FindParent();
04225     }
04226     return Retval;
04227 }
04228 
04229 /********************************************************************************************
04230 
04231 >   void AttrBrushType::SetCache(PointsMap* pMap) 
04232 
04233     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04234     Created:    6/10/99
04235     Inputs:     -
04236     Returns:    -
04237     Purpose:    interface to the BrushAttrValue, sets the cache
04238     SeeAlso:    -
04239 
04240 ********************************************************************************************/
04241 
04242 void AttrBrushType::SetCache(PointsMap* pMap)
04243 {
04244     m_Value.SetCache(pMap);
04245 }
04246 
04247 /********************************************************************************************
04248 
04249 >   PointsMap* AttrBrushType::GetCache() 
04250 
04251     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04252     Created:    6/10/99
04253     Inputs:     -
04254     Returns:    pointer to the points map of the brushattrvalue
04255     Purpose:    interface to the BrushAttrValue, gets the cache
04256     SeeAlso:    -
04257 
04258 ********************************************************************************************/
04259 
04260 PointsMap* AttrBrushType::GetCache()
04261 {
04262     return m_Value.GetCache();
04263 }
04264 
04265 
04266 /********************************************************************************************
04267 
04268 >   PressureArray* AttrBrushType::GetPressureCache() 
04269 
04270     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04271     Created:    6/10/99
04272     Inputs:     -
04273     Returns:    pointer to the points map of the brushattrvalue
04274     Purpose:    interface to the BrushAttrValue, gets the pressure cache
04275     SeeAlso:    -
04276 
04277 ********************************************************************************************/
04278 
04279 BOOL AttrBrushType::ContainsPressureCache()
04280 {
04281     return (m_Value.GetPressureCache() != NULL);
04282 }
04283 
04284 /********************************************************************************************
04285 
04286 >   PressureArray* AttrBrushType::GetPressureCache() 
04287 
04288     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04289     Created:    6/10/99
04290     Inputs:     -
04291     Returns:    pointer to the points map of the brushattrvalue
04292     Purpose:    interface to the BrushAttrValue, gets the pressure cache
04293     SeeAlso:    -
04294 
04295 ********************************************************************************************/
04296 
04297 CDistanceSampler* AttrBrushType::GetPressureCache()
04298 {
04299     return m_Value.GetPressureCache();
04300 }
04301 
04302 
04303 /********************************************************************************************
04304 
04305 >   void AttrBrushType::SetPressureCache(PressureArray* pArray) 
04306 
04307     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04308     Created:    6/10/99
04309     Inputs:     array holding pressure values
04310     Returns:    -
04311     Purpose:    interface to the BrushAttrValue, sets the cache
04312     SeeAlso:    -
04313 
04314 ********************************************************************************************/
04315 
04316 void AttrBrushType::SetPressureCache(CDistanceSampler* pCache)
04317 {
04318     m_Value.SetPresssureCache(pCache);
04319 }
04320 
04321 /********************************************************************************************
04322 
04323 >   BOOL AttrBrushType::ReversePressureCache()
04324 
04325     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04326     Created:    23/5/2000
04327     Inputs:     -
04328     Outputs:    -
04329     Returns:    TRUE if all went well, otherwise false
04330     Purpose:    Asks the attribute value to reverse its pressure list
04331     See Also:   BrushAttrValue::ReversePressureList
04332 ********************************************************************************************/
04333 
04334 BOOL AttrBrushType::ReversePressureCache()
04335 {
04336     CDistanceSampler* pCache = GetPressureCache();
04337     return pCache->ReverseData();
04338 }
04339 
04340 /********************************************************************************************
04341 
04342 >   TimeStampList* AttrBrushType::GetTimeStampList() 
04343 
04344     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04345     Created:    6/10/99
04346     Inputs:     -
04347     Returns:    pointer to the timestamp points list of the brushattrvalue
04348     Purpose:    interface to the BrushAttrValue, gets the cache
04349     SeeAlso:    -
04350 
04351 ********************************************************************************************/
04352 
04353 TimeStampList* AttrBrushType::GetTimeStampList()
04354 {
04355     return m_Value.GetTimeStampList();
04356 }
04357 
04358 /********************************************************************************************
04359 
04360 >   BOOL AttrBrushType::IsTimeStamping() 
04361 
04362     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04363     Created:    6/10/99
04364     Inputs:     -
04365     Returns:    TRUE if we are timestamping, or FALSE if not
04366     Purpose:    interface to the BrushAttrValue
04367     SeeAlso:    -
04368 
04369 ********************************************************************************************/
04370 
04371 BOOL AttrBrushType::IsTimeStamping()
04372 {
04373     return m_Value.IsTimeStamping();
04374 }
04375 
04376 
04377 /********************************************************************************************
04378 
04379 >   void AttrBrushType::ClearCachedRect() 
04380 
04381     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04382     Created:    6/10/99
04383     Inputs:     -
04384     Returns:    -
04385     Purpose:    interface to the BrushAttrValue, wipes the cached bounding rect
04386     SeeAlso:    -
04387 
04388 ********************************************************************************************/
04389 
04390 void AttrBrushType::ClearCachedRect()
04391 {
04392     m_Value.SetCachedRect(DocRect(0,0,0,0));
04393 }
04394 
04395 
04396 void AttrBrushType::SetFreeHandTool(FreeHandTool* pTool)
04397 {
04398     m_pFreeTool = pTool;
04399 }
04400 
04401 /********************************************************************************************
04402 
04403 > static void AttrBrushType::RotateBounds(double Angle, DocRect* pBounds)
04404 
04405     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04406     Created:    8/2/2000
04407     Inputs:     Bounds = the bounds to rotate
04408                 Angle  = the angle in degrees by which to rotate it by
04409     Outputs:    Bounds is updated
04410     Returns:    TRUE, unless you try to pass in a dud rect
04411     Purpose:    The bounds are updated to contain the rotated version
04412     SeeAlso:    -
04413 
04414 ********************************************************************************************/
04415 
04416 BOOL AttrBrushType::RotateBounds(double Angle, DocRect* pBounds)
04417 {
04418     ERROR2IF(pBounds == NULL, FALSE, "DocRect is NULL");
04419     if (Angle != 0.0)
04420     {
04421         DocCoord BBCentre = pBounds->Centre();
04422 
04423         DocCoord Coords[4];
04424         Coords[0].x = pBounds->lo.x;    Coords[0].y = pBounds->lo.y;
04425         Coords[1].x = pBounds->hi.x;    Coords[1].y = pBounds->lo.y;
04426         Coords[2].x = pBounds->hi.x;    Coords[2].y = pBounds->hi.y;
04427         Coords[3].x = pBounds->lo.x;    Coords[3].y = pBounds->hi.y;
04428 
04429         Trans2DMatrix Rotate(BBCentre,Angle);
04430         Rotate.Transform(Coords,4);
04431 
04432         pBounds->lo.x = min(min(Coords[0].x,Coords[1].x), min(Coords[2].x,Coords[3].x));
04433         pBounds->hi.x = max(max(Coords[0].x,Coords[1].x), max(Coords[2].x,Coords[3].x));
04434         pBounds->lo.y = min(min(Coords[0].y,Coords[1].y), min(Coords[2].y,Coords[3].y));
04435         pBounds->hi.y = max(max(Coords[0].y,Coords[1].y), max(Coords[2].y,Coords[3].y));
04436     }
04437     return TRUE;
04438 }
04439 
04440 /********************************************************************************************
04441 
04442 >   virtual BOOL AttrBrushType::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
04443 >   virtual BOOL AttrBrushType::WritePreChildrenNative(BaseCamelotFilter *pFilter)
04444 
04445     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04446     Created:    13/12/99
04447 
04448     Inputs:     pFilter - filter to write to
04449 
04450     Returns:    TRUE if the Node has written out a record to the filter
04451 
04452     Purpose:    Writes out a record that represents the node, to either Native or Web
04453                 file format.
04454 
04455                 This function is called before any of the AttrBrushType's children
04456                 are written to the filter.
04457 
04458                 If the AttrBrushType writes out a record successfully to the file,
04459                 it will return TRUE.
04460 
04461                 If the AttrBrushType chooses not to write itself to the filter
04462                 (e.g. because it is not appropriate for this filter), then this
04463                 function will return FALSE.
04464 
04465     Notes:      Simple Brushs (not using fancy bitmap/vector brushes) just
04466                 write out a 4-byte (UINT32) record containing the stroke type.
04467                 Defined stroke types at this time are:
04468                     0 - Simple variable width stroke
04469 
04470     SeeAlso:    Node::WritePreChildrenNative; Node::WritePreChildrenWeb;
04471                 StrokeAttrRecordHandler::HandleRecord
04472 
04473 ********************************************************************************************/
04474 
04475 BOOL AttrBrushType::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
04476 {
04477     return(WritePreChildrenNative(pFilter));
04478 }
04479 
04480 BOOL AttrBrushType::WritePreChildrenNative(BaseCamelotFilter *pFilter)
04481 {
04482     //return TRUE;
04483 
04484     ERROR2IF(pFilter == NULL, FALSE, "Illegal NULL param");
04485     
04486     BOOL ok = TRUE;
04487     PathProcessorBrush *pProcessor = m_Value.GetPathProcessor();
04488     
04489     if (pProcessor != NULL)
04490     {
04491         // first try and get the definition stored in the brush component
04492         BrushHandle Handle = pProcessor->GetBrushDefinitionHandle();
04493         
04494         // also check that the definition exists, as we do not want to save out deactivated brushes
04495         BrushDefinition* pDef = BrushComponent::FindBrushDefinition(Handle);
04496 
04497         if (Handle != BrushHandle_NoBrush && pDef != NULL)
04498         {
04499             // now get the brush component from the document (bit longwinded this but it
04500             // ensures that each brush only gets written once)
04501             Document* pDoc = Document::GetCurrent();
04502             ERROR2IF(pDoc == NULL, FALSE, "Er, wheres the document gone?");
04503             BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
04504             ERROR2IF(pBrushComp == NULL, FALSE, "Couldn't find brush component");
04505             
04506             // finally lets write the definition
04507             ok = pBrushComp->ExportLine(pFilter, Handle);
04508                 
04509             if (ok) ok = pProcessor->WriteNative(pFilter);
04510 
04511             // now write our timestamping and pressure data
04512             if (IsTimeStamping())
04513                 if (ok) ok = m_Value.WriteTimeStampList(pFilter);
04514 
04515             if (ContainsPressureCache())
04516                 if (ok) ok = m_Value.WritePressureData(pFilter);
04517 
04518         }
04519     }
04520     else
04521     {
04522         //ERROR3("Trying to write empty attribute");
04523     //  return FALSE;
04524     }
04525      
04526     return ok;
04527 }
04528 
04529 
04530 
04531 
04532 
04533 
04534 /*------------------------------------------------------------------------------------------
04535 -----------------BRUSH ATTRIBUTE RECORD HANDLER --------------------------------------------
04536 --------------------------------------------------------------------------------------------*/
04537 
04538 
04539 // initialise our static
04540 AttrBrushType* BrushAttrRecordHandler::m_pLastAttribute = NULL;
04541 
04542 
04543 /********************************************************************************************
04544 
04545 >   virtual UINT32 *BrushAttrRecordHandler::GetTagList()
04546 
04547     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04548     Created:    7/1/97
04549 
04550     Returns:    A list of tag values, terminated by CXFRH_TAG_LIST_END
04551 
04552     Purpose:    Provides the record handler system with a list of records handled by this
04553                 handler - all StrokeType attributes:
04554                 
04555     SeeAlso:    BrushTypeAttrRecordHandler::HandleRecord
04556 
04557 ********************************************************************************************/
04558 
04559 UINT32 *BrushAttrRecordHandler::GetTagList()
04560 {
04561     static UINT32 TagList[] =
04562     {
04563         TAG_BRUSHDEFINITION,
04564         TAG_BRUSHATTR,
04565         TAG_BRUSHDATA,
04566         TAG_MOREBRUSHDATA,
04567         TAG_MOREBRUSHATTR,
04568         TAG_EVENMOREBRUSHDATA,
04569         TAG_EVENMOREBRUSHATTR,
04570         TAG_TIMESTAMPBRUSHDATA,
04571         TAG_BRUSHPRESSUREINFO,
04572         TAG_BRUSHATTRPRESSUREINFO,
04573         TAG_BRUSHPRESSUREDATA,
04574         TAG_BRUSHPRESSURESAMPLEDATA,
04575         TAG_BRUSHATTRFILLFLAGS,
04576         TAG_BRUSHTRANSPINFO, 
04577         TAG_BRUSHATTRTRANSPINFO,
04578         CXFRH_TAG_LIST_END
04579     };
04580 
04581     return(TagList);
04582 }
04583 
04584 
04585 
04586 /********************************************************************************************
04587 
04588 >   virtual BOOL BrushAttrRecordHandler::HandleRecord(CXaraFileRecord *pCXaraFileRecord)
04589 
04590     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04591     Created:    21/12/99
04592 
04593     Inputs:     pCXaraFileRecord - The record to handle - may not be NULL
04594     Returns:    TRUE if handled successfuly
04595 
04596     Purpose:    Handles loading of the given AttrBrushType attribute record
04597 
04598 
04599 
04600 ********************************************************************************************/
04601 
04602 BOOL BrushAttrRecordHandler::HandleRecord(CXaraFileRecord *pCXaraFileRecord)
04603 {
04604     ERROR3IF(pCXaraFileRecord == NULL, "pCXaraFileRecord is NULL");
04605 
04606 //  NodeAttribute* pNewNode = NULL;
04607     BOOL RetVal = TRUE;
04608     switch (pCXaraFileRecord->GetTag())
04609     {
04610         case TAG_BRUSHDEFINITION:
04611         {
04612             // get the brush component from the document
04613             Document* pDoc = Document::GetCurrent();
04614             ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
04615             BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
04616             ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
04617             UINT32 ImportHandle = 0;        
04618             BOOL ok = pCXaraFileRecord->ReadUINT32(&ImportHandle);
04619             
04620             if (ok) 
04621                 RetVal =  pBrushComp->StartImportBrush(this, pCXaraFileRecord, ImportHandle);
04622         }
04623         break;
04624         case TAG_BRUSHDATA:
04625             RetVal =  HandleBrushDataRecord(pCXaraFileRecord);
04626             break;
04627         case TAG_BRUSHATTR:
04628             RetVal = HandleBrushAttributeRecord(pCXaraFileRecord);
04629             break;
04630         case TAG_MOREBRUSHDATA:
04631             RetVal =  HandleMoreBrushDataRecord(pCXaraFileRecord);
04632             break;
04633         case TAG_MOREBRUSHATTR:
04634             RetVal =  HandleMoreBrushAttrRecord(pCXaraFileRecord);
04635             break;
04636         case TAG_EVENMOREBRUSHDATA:
04637             RetVal = HandleEvenMoreBrushData(pCXaraFileRecord);
04638             break;
04639         case TAG_EVENMOREBRUSHATTR:
04640             RetVal = HandleEvenMoreBrushAttr(pCXaraFileRecord);
04641             break;
04642         case TAG_TIMESTAMPBRUSHDATA:
04643             RetVal = HandleTimeStampData(pCXaraFileRecord);
04644             break;
04645         case TAG_BRUSHPRESSUREINFO:
04646             RetVal = HandlePressureInfo(pCXaraFileRecord);
04647             break;
04648         case TAG_BRUSHATTRPRESSUREINFO:
04649             RetVal = HandleAttrPressureInfo(pCXaraFileRecord);
04650             break;
04651         case TAG_BRUSHPRESSUREDATA:
04652             RetVal = HandlePressureData(pCXaraFileRecord);
04653             break;
04654         case TAG_BRUSHPRESSURESAMPLEDATA:
04655             RetVal = HandlePressureSampleData(pCXaraFileRecord);
04656             break;
04657         case TAG_BRUSHATTRFILLFLAGS:
04658             RetVal = HandleAttrFillFlags(pCXaraFileRecord);
04659             break;
04660         case TAG_BRUSHTRANSPINFO:
04661             RetVal = HandleTranspInfo(pCXaraFileRecord);
04662             break;
04663         case TAG_BRUSHATTRTRANSPINFO:
04664             RetVal = HandleAttrTranspInfo(pCXaraFileRecord);
04665             break;
04666         default:
04667             ERROR3_PF(("I don't handle records with the tag (%d)\n", pCXaraFileRecord->GetTag()));
04668             break;
04669     }
04670 
04671     return(RetVal);
04672 }
04673 
04674 
04675 /********************************************************************************************
04676 
04677 >    BOOL BrushAttrRecordHandler::HandleBrushAttributeRecord(CXaraFileRecord* pRecord)
04678 
04679     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04680     Created:    21/12/99
04681 
04682     Inputs:     pRecord - the file record holding the data
04683     Returns:    TRUE if brush attribute was successfully read and created, otherwise FALSE
04684     Purpose:    Reads in data which it uses to create a new AttrBrushType node
04685 
04686 ********************************************************************************************/
04687 
04688 BOOL BrushAttrRecordHandler::HandleBrushAttributeRecord(CXaraFileRecord* pRecord)
04689 {
04690     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL");
04691     
04692     // first read in all the data
04693     UINT32 Handle = 0x01000000;
04694     INT32 TempOffsetType = 0;
04695     INT32 TempOffsetValue = 0;
04696     INT32 TempSpacing = 10000;
04697     BYTE Flags;
04698     double TempRotateAngle = 0.0;
04699     double TempScaling = 1.0;
04700     // Import the data from the record
04701     if (!pRecord->ReadUINT32(&Handle) || !pRecord->ReadINT32(&TempSpacing) ||
04702         !pRecord->ReadBYTE(&Flags) || !pRecord->ReadDOUBLE(&TempRotateAngle) 
04703         || !pRecord->ReadINT32(&TempOffsetType) || !pRecord->ReadINT32(&TempOffsetValue)
04704         || !pRecord->ReadDOUBLE(&TempScaling))
04705     {
04706         return(FALSE);
04707     }
04708 
04709     // allocate tge new node
04710     NodeAttribute* pNewNode = new AttrBrushType;
04711     ERROR2IF(pNewNode == NULL, FALSE, "Unable to allocate node attribute");
04712                 
04713     // get the brush component from the document
04714     Document* pDoc = Document::GetCurrent();
04715     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
04716     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
04717     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
04718 
04719     // find the brush definition that this brush uses           
04720     BrushHandle NewHandle = pBrushComp->FindImportedBrush(Handle);  
04721 
04722     // allocate a new path processor
04723     PathProcessorBrush* pNewPathProc = new PathProcessorBrush;
04724     ERROR2IF(pNewPathProc == NULL, FALSE, "Unable to allocate path processor");
04725     // tell it which brush definition to use
04726     pNewPathProc->SetBrushDefinition(NewHandle);
04727 
04728     // transfer all the data
04729     pNewPathProc->SetSpacing(TempSpacing);
04730     PathOffset Offset = (PathOffset)TempOffsetType;
04731     pNewPathProc->SetPathOffsetType(Offset);
04732     pNewPathProc->SetPathOffsetValue(TempOffsetValue);
04733     pNewPathProc->SetRotationAngle(TempRotateAngle);
04734     pNewPathProc->SetBrushScaling(TempScaling);
04735 
04736     BOOL bTile = Flags & TAG_BRUSHTILE_FLAG;
04737     BOOL bRotate = Flags & TAG_BRUSHROTATE_FLAG;
04738     pNewPathProc->SetRotated(bRotate);
04739     pNewPathProc->SetTiling(bTile);
04740 
04741     // now allocate the processor to the AttributeValue
04742     BrushAttrValue* pBrushAttrValue = (BrushAttrValue*)pNewNode->GetAttributeValue();
04743     ERROR2IF(pBrushAttrValue == NULL, FALSE, "Brush attribute value is NULL");
04744     pBrushAttrValue->SetPathProcessor(pNewPathProc);
04745     
04746     // tell the processor who's the boss
04747     pNewPathProc->SetParentAttribute((AttrBrushType*)pNewNode);
04748 
04749     InsertNode(pNewNode);
04750 
04751 
04752     // set the static member, as there may be more data to come
04753     m_pLastAttribute = (AttrBrushType*)pNewNode;
04754 
04755     m_pLastAttribute->GetMaxScalingFromDefinition();
04756 
04757     return TRUE;
04758 
04759 }               
04760 
04761 
04762 /********************************************************************************************
04763 
04764 >    BOOL BrushAttrRecordHandler::HandleBrushAttributeRecord(CXaraFileRecord* pRecord)
04765 
04766     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04767     Created:    21/12/99
04768 
04769     Inputs:     pRecord - the file record holding the data
04770     Returns:    TRUE if all went well, otherwise FALSE
04771     Purpose:    Reads in data and assigns it to the previously created BrushDefinition.
04772 
04773 ********************************************************************************************/
04774 
04775 BOOL BrushAttrRecordHandler::HandleBrushDataRecord(CXaraFileRecord* pRecord)
04776 {
04777     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL");
04778     
04779     // first read in all the data
04780     UINT32 Handle = 0x01000000;
04781     INT32 TempOffsetType = 0;
04782     INT32 TempOffsetValue = 0;
04783     INT32 TempSpacing = 10000;
04784     BYTE Flags;
04785     String_32 TempName;
04786     double TempScaling = 1.0;
04787     double TempRotateAngle = 0.0;
04788     // Import the data from the record
04789     if (!pRecord->ReadUINT32(&Handle) || !pRecord->ReadINT32(&TempSpacing) ||
04790         !pRecord->ReadBYTE(&Flags) || !pRecord->ReadDOUBLE(&TempRotateAngle) 
04791         || !pRecord->ReadINT32(&TempOffsetType) || !pRecord->ReadINT32(&TempOffsetValue) 
04792         || !pRecord->ReadUnicode(&TempName) || !pRecord->ReadDOUBLE(&TempScaling))
04793     {
04794         return(FALSE);
04795     }
04796     
04797     // convert the variables that were not stored as their original type
04798     PathOffset Offset = (PathOffset)TempOffsetType;
04799     BOOL bTile = Flags & TAG_BRUSHTILE_FLAG;
04800     BOOL bRotate = Flags & TAG_BRUSHROTATE_FLAG;
04801 
04802     // If there is a name to be imported, read it as well
04803     //if (!pRecord->ReadUnicode(&TempName))
04804     //  return(FALSE);
04805 
04806     // We remember the imported flags and suchlike, which we will use in EndImportLine.
04807 //  TempName.Left((StringBase *)&m_ImportedName, 31);
04808 
04809     // Now we need to retrieve the previously generated brush definition and assign all
04810     // this lovely data to it. Note that for this to be successful it is vital that
04811     // BrushComponent::StartImportBrush be called prior to this in the import
04812 
04813     // get the brush component from the document
04814     Document* pDoc = Document::GetCurrent();
04815     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
04816     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
04817     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
04818 
04819     // find the brush definition that is currently being imported
04820     BrushDefinition* pBrushDef = pBrushComp->GetImportBrushDefinition();
04821 
04822     if (pBrushDef != NULL)
04823     {
04824         // assign the new data to it
04825         pBrushDef->SetSpacing(TempSpacing);
04826         pBrushDef->SetTiling(bTile);
04827         pBrushDef->SetRotated(bRotate);
04828         pBrushDef->SetRotationAngle(TempRotateAngle);
04829         pBrushDef->SetPathOffsetType(Offset);
04830         pBrushDef->SetPathOffsetValue(TempOffsetValue);
04831         pBrushDef->SetLineName(&TempName);
04832         pBrushDef->SetBrushScaling(1.0);
04833     }
04834 //  else
04835 //      return FALSE;
04836 
04837     
04838     return TRUE; 
04839 }
04840 
04841 
04842 /********************************************************************************************
04843 
04844 >    BOOL BrushAttrRecordHandler::HandleMoreBrushDataRecord(CXaraFileRecord* pRecord)
04845 
04846     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04847     Created:    21/12/99
04848 
04849     Inputs:     pRecord - the file record holding the data
04850     Returns:    TRUE if all went well, otherwise FALSE
04851     Purpose:    Reads in data and assigns it to the previously created BrushDefinition.
04852 
04853 ********************************************************************************************/
04854 
04855 BOOL BrushAttrRecordHandler::HandleMoreBrushDataRecord(CXaraFileRecord* pRecord)
04856 {
04857     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
04858 
04859     // get the variables to read into
04860     double SpacingIncrProp = 1.0;
04861     INT32 SpacingIncrConst  = 0;
04862     INT32 SpacingMaxRand    = 0;
04863     INT32 SpacingRandSeed   = 0;
04864     double ScalingIncr     = 1.0;
04865     INT32 ScalingMaxRand    = 0;
04866     INT32 ScalingRandSeed   = 0;
04867     INT32 Sequence  = SEQ_FORWARD;
04868     INT32 SequenceRandSeed  = 0;
04869     double OffsetIncrProp  = 1.0;
04870     INT32 OffsetIncrConst   = 0;
04871     INT32 OffsetTypeRandSeed = 0;
04872     INT32 OffsetValMaxRand   = 0;
04873     INT32 OffsetValRandSeed  = 0;
04874 
04875     if (!pRecord->ReadDOUBLE(&SpacingIncrProp) || !pRecord->ReadINT32(&SpacingIncrConst) ||
04876         !pRecord->ReadINT32(&SpacingMaxRand) || !pRecord->ReadINT32(&SpacingRandSeed) ||
04877         !pRecord->ReadDOUBLE(&ScalingIncr) || !pRecord->ReadINT32(&ScalingMaxRand) ||
04878         !pRecord->ReadINT32(&ScalingRandSeed) || !pRecord->ReadINT32(&Sequence) ||
04879         !pRecord->ReadINT32(&SequenceRandSeed) || !pRecord->ReadDOUBLE(&OffsetIncrProp) ||
04880         !pRecord->ReadINT32(&OffsetIncrConst) || !pRecord->ReadINT32(&OffsetTypeRandSeed) || 
04881         !pRecord->ReadINT32(&OffsetValMaxRand) || !pRecord->ReadINT32(&OffsetValRandSeed)
04882         )
04883         return FALSE;
04884 
04885     // get the brush component from the document
04886     Document* pDoc = Document::GetCurrent();
04887     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
04888     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
04889     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
04890 
04891     // find the brush definition that is currently being imported
04892     BrushDefinition* pBrushDef = pBrushComp->GetImportBrushDefinition();
04893 
04894     if (pBrushDef != NULL)
04895     {
04896         pBrushDef->SetSpacingIncrProp(SpacingIncrProp);
04897         pBrushDef->SetSpacingIncrConst((UINT32)SpacingIncrConst);
04898         pBrushDef->SetSpacingMaxRand((UINT32)SpacingMaxRand);
04899         pBrushDef->SetSpacingRandSeed((UINT32)SpacingRandSeed);
04900         pBrushDef->SetBrushScalingIncr(ScalingIncr);
04901         pBrushDef->SetScalingMaxRand((UINT32)ScalingMaxRand);
04902         pBrushDef->SetScalingRandSeed((UINT32)ScalingRandSeed);
04903         pBrushDef->SetSequenceType((SequenceType)Sequence);
04904         pBrushDef->SetSequenceSeed(SequenceRandSeed);
04905         pBrushDef->SetPathOffsetIncrProp(OffsetIncrProp);
04906         pBrushDef->SetPathOffsetIncrConst((UINT32)OffsetIncrConst);
04907         pBrushDef->SetOffsetTypeRandSeed((UINT32)OffsetTypeRandSeed);
04908         pBrushDef->SetOffsetValueMaxRand((UINT32)OffsetValMaxRand);
04909         pBrushDef->SetOffsetValueRandSeed((UINT32)OffsetValRandSeed);
04910     }
04911 
04912     return TRUE;
04913 
04914 }
04915 
04916 
04917 /********************************************************************************************
04918 
04919 >    BOOL BrushAttrRecordHandler::HandleMoreBrushAttrRecord(CXaraFileRecord* pRecord)
04920 
04921     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04922     Created:    21/12/99
04923 
04924     Inputs:     pRecord - the file record holding the data
04925     Returns:    TRUE if all went well, otherwise FALSE
04926     Purpose:    reads in the same data as previous fn. but assigns it to the path processor
04927                 of 
04928 
04929 ********************************************************************************************/
04930 
04931 BOOL BrushAttrRecordHandler::HandleMoreBrushAttrRecord(CXaraFileRecord* pRecord)
04932 {
04933     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
04934     // we must have a node to import to 
04935     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");
04936 
04937     // get some variables to read into
04938     double SpacingIncrProp = 1.0;
04939     INT32 SpacingIncrConst  = 0;
04940     INT32 SpacingMaxRand    = 0;
04941     INT32 SpacingRandSeed   = 0;
04942     double ScalingIncr     = 1.0;
04943     INT32 ScalingMaxRand    = 0;
04944     INT32 ScalingRandSeed   = 0;
04945     INT32 Sequence  = SEQ_FORWARD;
04946     INT32 SequenceRandSeed  = 0;
04947     double OffsetIncrProp  = 1.0;
04948     INT32 OffsetIncrConst   = 0;
04949     INT32 OffsetTypeRandSeed = 0;
04950     INT32 OffsetValMaxRand   = 0;
04951     INT32 OffsetValRandSeed  = 0;
04952     INT32 UseLocalFill      = -1;
04953 
04954     if (!pRecord->ReadDOUBLE(&SpacingIncrProp) || !pRecord->ReadINT32(&SpacingIncrConst) ||
04955         !pRecord->ReadINT32(&SpacingMaxRand) || !pRecord->ReadINT32(&SpacingRandSeed) ||
04956         !pRecord->ReadDOUBLE(&ScalingIncr) || !pRecord->ReadINT32(&ScalingMaxRand) ||
04957         !pRecord->ReadINT32(&ScalingRandSeed) || !pRecord->ReadINT32(&Sequence) ||
04958         !pRecord->ReadINT32(&SequenceRandSeed) || !pRecord->ReadDOUBLE(&OffsetIncrProp) || !pRecord->ReadINT32(&OffsetIncrConst) ||
04959         !pRecord->ReadINT32(&OffsetTypeRandSeed) || !pRecord->ReadINT32(&OffsetValMaxRand) ||
04960         !pRecord->ReadINT32(&OffsetValRandSeed) || !pRecord->ReadINT32(&UseLocalFill)
04961         )
04962         return FALSE;
04963 
04964     // now get the path processor belonging to the last attribute
04965     PathProcessorBrush* pPathProc = m_pLastAttribute->GetPathProcessor();
04966     
04967     // if there isn't a path processor thats ok, as it may be default
04968     if (pPathProc == NULL)
04969         return TRUE;
04970     else
04971     {
04972         pPathProc->SetSpacingIncrProp(SpacingIncrProp);
04973         pPathProc->SetSpacingIncrConst((UINT32)SpacingIncrConst);
04974         pPathProc->SetSpacingMaxRand((UINT32)SpacingMaxRand);
04975         pPathProc->SetSpacingRandSeed((UINT32)SpacingRandSeed);
04976         pPathProc->SetBrushScalingIncr(ScalingIncr);
04977         pPathProc->SetScalingMaxRand((UINT32)ScalingMaxRand);
04978         pPathProc->SetScalingRandSeed((UINT32)ScalingRandSeed);
04979         pPathProc->SetSequenceType((SequenceType)Sequence);
04980         pPathProc->SetSequenceSeed(SequenceRandSeed);
04981         pPathProc->SetPathOffsetIncrProp(OffsetIncrProp);
04982         pPathProc->SetPathOffsetIncrConst((UINT32)OffsetIncrConst);
04983         pPathProc->SetOffsetTypeRandSeed((UINT32)OffsetTypeRandSeed);
04984         pPathProc->SetOffsetValueMaxRand((UINT32)OffsetValMaxRand);
04985         pPathProc->SetOffsetValueRandSeed((UINT32)OffsetValRandSeed);
04986         BOOL UseFill = UseLocalFill > 0 ? TRUE : FALSE;
04987         pPathProc->SetUseLocalFillColour(UseFill);
04988 
04989         // gotta set these for the time being
04990         pPathProc->SetRotationMaxRand(0);
04991         pPathProc->SetRotationRandSeed(0);
04992     }
04993 
04994     return TRUE;
04995 }
04996 
04997 
04998 
04999 /********************************************************************************************
05000 
05001 >    BOOL BrushAttrRecordHandler::HandleEvenMoreBrushData(CXaraFileRecord* pRecord)
05002 
05003     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05004     Created:    21/12/99
05005 
05006     Inputs:     pRecord - the file record holding the data
05007     Returns:    TRUE if all went well, otherwise FALSE
05008     Purpose:    Reads in data and assigns it to the previously created BrushDefinition.
05009 
05010 ********************************************************************************************/
05011 
05012 BOOL BrushAttrRecordHandler::HandleEvenMoreBrushData(CXaraFileRecord* pRecord)
05013 {
05014     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05015 
05016     INT32 RotationMaxRand = 0;
05017     INT32 RotationRandSeed = 0;
05018 
05019     if (!pRecord->ReadINT32(&RotationMaxRand) || !pRecord->ReadINT32(&RotationRandSeed)) 
05020         return FALSE;
05021 
05022     // get the brush component from the document
05023     Document* pDoc = Document::GetCurrent();
05024     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
05025     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
05026     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
05027 
05028     // find the brush definition that is currently being imported
05029     BrushDefinition* pBrushDef = pBrushComp->GetImportBrushDefinition();
05030 
05031     if (pBrushDef != NULL)
05032     {
05033         pBrushDef->SetRotationMaxRand((UINT32)RotationMaxRand);
05034         pBrushDef->SetRotationRandSeed((UINT32)RotationRandSeed);
05035     }
05036 
05037     // tell the component we've finished importing
05038     return TRUE; 
05039 }
05040 
05041 
05042 /********************************************************************************************
05043 
05044 >    BOOL BrushAttrRecordHandler::HandleEvenMoreBrushAttr(CXaraFileRecord* pRecord)
05045 
05046     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05047     Created:    21/12/99
05048 
05049     Inputs:     pRecord - the file record holding the data
05050     Returns:    TRUE if all went well, otherwise FALSE
05051     Purpose:    Reads in data and assigns it to the previously created node
05052 
05053 ********************************************************************************************/
05054 
05055 BOOL BrushAttrRecordHandler::HandleEvenMoreBrushAttr(CXaraFileRecord* pRecord)
05056 {
05057     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05058     
05059     // we must have a node to import to 
05060     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");
05061     
05062     INT32 RotationMaxRand = 0;
05063     INT32 RotationRandSeed = 0;
05064     BYTE ScaleFlag        = 0;
05065     if (!pRecord->ReadINT32(&RotationMaxRand) || !pRecord->ReadINT32(&RotationRandSeed)
05066         || !pRecord->ReadBYTE(&ScaleFlag)) 
05067         return FALSE;
05068 
05069 
05070     // now get the path processor belonging to the last attribute
05071     PathProcessorBrush* pPathProc = m_pLastAttribute->GetPathProcessor();
05072     
05073     // if there isn't a path processor thats ok, as it may be default
05074     if (pPathProc == NULL)
05075         return TRUE;
05076 
05077     pPathProc->SetRotationMaxRand((UINT32)RotationMaxRand);
05078     pPathProc->SetRotationRandSeed((UINT32)RotationRandSeed);
05079 
05080     BOOL ScaleToLineWidth = ScaleFlag & TAG_SCALETOWIDTH_FLAG;
05081     pPathProc->SetScaleToLineWidth(ScaleToLineWidth);
05082 
05083 
05084     // set the random hue & sat to zero until we do a tag
05085     /*pPathProc->SetHueMaxRand(0);
05086     pPathProc->SetHueRandSeed(0);
05087     pPathProc->SetSatMaxRand(0);
05088     pPathProc->SetSatRandSeed(0);
05089     pPathProc->SetHueIncrement(1.0);
05090     pPathProc->SetSatIncrement(1.0);
05091     */
05092     return TRUE;
05093 }
05094 
05095 
05096 /********************************************************************************************
05097 
05098 >   BOOL BrushAttrRecordHandler::HandlePressureInfo(CXaraFileRecord* pRecord)
05099 
05100     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05101     Created:    21/12/99
05102 
05103     Inputs:     pRecord - the file record holding the data
05104     Returns:    TRUE if all went well, otherwise FALSE
05105     Purpose:    Reads in data and assigns it to the previously created BrushDefinition.
05106 
05107 ********************************************************************************************/
05108 
05109 BOOL BrushAttrRecordHandler::HandlePressureInfo(CXaraFileRecord* pRecord)
05110 {
05111     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05112     
05113     INT32 ScalingPressure  = 0;
05114     INT32 SpacingPressure  = 0;
05115     INT32 OffsetPressure   = 0;
05116     INT32 RotationPressure = 0;
05117     INT32 HuePressure      = 0;
05118     INT32 SatPressure      = 0;
05119     INT32 TimePressure     = 0;
05120 
05121     if (!pRecord->ReadINT32(&ScalingPressure) || !pRecord->ReadINT32(&SpacingPressure)  ||
05122         !pRecord->ReadINT32(&OffsetPressure) || !pRecord->ReadINT32(&RotationPressure) ||
05123         !pRecord->ReadINT32(&HuePressure) || !pRecord->ReadINT32(&SatPressure) ||
05124         !pRecord->ReadINT32(&TimePressure))
05125     return FALSE;
05126 
05127     // get the brush component from the document
05128     Document* pDoc = Document::GetCurrent();
05129     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
05130     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
05131     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
05132 
05133     // find the brush definition that is currently being imported
05134     BrushDefinition* pBrushDef = pBrushComp->GetImportBrushDefinition();
05135 
05136     // currently we only make use of the scaling pressure value, others to follow when I have
05137     // time to implement them
05138     if (pBrushDef != NULL)
05139     {
05140         pBrushDef->SetScalingMaxPressure((UINT32)ScalingPressure);
05141         pBrushDef->SetRotationMaxPressure((UINT32)RotationPressure);
05142     }
05143 
05144     return TRUE;
05145 }
05146 
05147 
05148 /********************************************************************************************
05149 
05150 >   BOOL BrushAttrRecordHandler::HandleAttrPressureInfo(CXaraFileRecord* pRecord)
05151 
05152     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05153     Created:    21/12/99
05154 
05155     Inputs:     pRecord - the file record holding the data
05156     Returns:    TRUE if all went well, otherwise FALSE
05157     Purpose:    Reads in data and assigns it to the previously created node
05158 
05159 ********************************************************************************************/
05160 
05161 BOOL BrushAttrRecordHandler::HandleAttrPressureInfo(CXaraFileRecord* pRecord)
05162 {
05163     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05164     
05165     // we must have a node to import to 
05166     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");
05167     
05168     INT32 ScalingPressure  = 0;
05169     INT32 SpacingPressure  = 0;
05170     INT32 OffsetPressure   = 0;
05171     INT32 RotationPressure = 0;
05172     INT32 HuePressure      = 0;
05173     INT32 SatPressure      = 0;
05174     INT32 TimePressure     = 0;
05175 
05176     if (!pRecord->ReadINT32(&ScalingPressure) || !pRecord->ReadINT32(&SpacingPressure) ||
05177         !pRecord->ReadINT32(&OffsetPressure) || !pRecord->ReadINT32(&RotationPressure) ||
05178         !pRecord->ReadINT32(&HuePressure) || !pRecord->ReadINT32(&SatPressure) ||
05179         !pRecord->ReadINT32(&TimePressure))
05180     return FALSE;
05181 
05182     // now get the path processor belonging to the last attribute
05183     PathProcessorBrush* pPathProc = m_pLastAttribute->GetPathProcessor();
05184     
05185     // if there isn't a path processor thats ok, as it may be default
05186     if (pPathProc == NULL)
05187         return TRUE;
05188     else
05189     {
05190         pPathProc->SetScalingMaxPressure((UINT32)ScalingPressure);
05191         pPathProc->SetRotationMaxPressure((UINT32)RotationPressure);
05192     }
05193 
05194     return TRUE;
05195 }
05196 
05197 
05198 /********************************************************************************************
05199 
05200 >    BOOL BrushAttrRecordHandler::HandleTimeStampData(CXaraFileRecord* pRecord)
05201 
05202     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05203     Created:    21/12/99
05204 
05205     Inputs:     pRecord - the file record holding the data
05206     Returns:    TRUE if all went well, otherwise FALSE
05207     Purpose:    Reads in timestamp data and assigns it to the last attribute we created
05208 
05209 ********************************************************************************************/
05210 
05211 BOOL BrushAttrRecordHandler::HandlePressureData(CXaraFileRecord* pRecord)
05212 {
05213     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05214     
05215     // we must have a node to import to 
05216     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");
05217     
05218     INT32 NumObjects = 0;
05219     
05220     if (!pRecord->ReadINT32(&NumObjects))
05221         return FALSE;
05222 
05223     // must be some mistake, but ours not to reason why
05224     if (NumObjects <= 0)
05225         return TRUE;
05226 
05227     /*
05228     // otherwise we must make ourselves a list
05229     PressureList* pNewList = new PressureList;
05230     
05231     PressureItem TheItem;
05232     INT32 Pressure;
05233     double Proportion;
05234     INT32 Distance;
05235 
05236     BOOL ok = TRUE;
05237     while ((NumObjects-- > 0) && ok)
05238     {
05239         if (ok) ok = pRecord->ReadINT32(&Pressure);
05240         if (ok) ok = pRecord->ReadDOUBLE(&Proportion);
05241         if (ok) ok = pRecord->ReadINT32(&Distance);
05242         if (ok) 
05243         {
05244             TheItem.m_Pressure = Pressure;
05245             TheItem.m_Proportion = Proportion;
05246             TheItem.m_Distance = Distance;
05247             pNewList->push_back(TheItem);
05248         }
05249     }
05250 
05251     if (pNewList && ok)
05252     {
05253         BrushAttrValue* pVal = (BrushAttrValue*)m_pLastAttribute->GetAttributeValue();
05254         if (pVal)
05255             pVal->SetPressureList(pNewList);
05256         else
05257         {
05258             pNewList->RemoveAll();
05259             delete pNewList;
05260         }
05261         pNewList = NULL;
05262     }
05263     */
05264     return TRUE;
05265 }
05266 
05267 
05268 /********************************************************************************************
05269 
05270 >    BOOL BrushAttrRecordHandler::HandleTimeStampData(CXaraFileRecord* pRecord)
05271 
05272     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05273     Created:    21/12/99
05274 
05275     Inputs:     pRecord - the file record holding the data
05276     Returns:    TRUE if all went well, otherwise FALSE
05277     Purpose:    Reads in timestamp data and assigns it to the last attribute we created
05278 
05279 ********************************************************************************************/
05280 
05281 BOOL BrushAttrRecordHandler::HandleTimeStampData(CXaraFileRecord* pRecord)
05282 {
05283     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05284     
05285     // we must have a node to import to 
05286     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");
05287 
05288     // first find out how many objects we have
05289     INT32 NumObjects = 0;
05290 
05291     if (!pRecord->ReadINT32(&NumObjects))
05292         return FALSE;
05293 
05294     // must be some mistake, but ours not to reason why
05295     if (NumObjects <= 0)
05296         return TRUE;
05297 
05298     // otherwise we must make ourselves a list
05299     TimeStampList* pNewList = new TimeStampList;
05300 
05301     // we may fail to get the list, however we must still read in the data or the next
05302     // record will be really screwed
05303 
05304     DocCoord Point;
05305     double Tangent;
05306     double Proportion;
05307     MILLIPOINT Distance;
05308 
05309     TimeStampBrushPoint TSBP;
05310     BOOL ok = TRUE;
05311     while ((NumObjects-- > 0) && ok)
05312     {
05313         if (ok) ok = pRecord->ReadCoord(&Point);
05314         if (ok) ok = pRecord->ReadDOUBLE(&Tangent);
05315         if (ok) ok = pRecord->ReadDOUBLE(&Proportion);
05316         if (ok) ok = pRecord->ReadINT32(&Distance);
05317         TRACEUSER("Diccon", _T("Read Point %d, %d\n"), Point.x, Point.y);
05318         if (pNewList != NULL && ok)
05319         {
05320             TSBP.m_Distance = Distance;
05321             TSBP.m_Point = Point;
05322             // not quite sure why I have to make this atrocious hack.  It seems that 
05323             // somewhere between being written and being read the millipoint values
05324             // had 576000 added to them.
05325             TSBP.m_Point.x -= 576000;
05326             TSBP.m_Point.y -= 576000;
05327             TSBP.m_Proportion = Proportion;
05328             TSBP.m_Tangent = Tangent;
05329             TSBP.m_Pressure = MAXPRESSURE / 2; //??
05330             pNewList->push_back(TSBP);
05331         }
05332     }
05333 
05334     if (pNewList)
05335     {
05336         BrushAttrValue* pVal = (BrushAttrValue*)m_pLastAttribute->GetAttributeValue();
05337         if (pVal)
05338             pVal->SetTimeStampList(pNewList);
05339         else
05340         {
05341             pNewList->clear();
05342             delete pNewList;
05343         }
05344         pNewList = NULL;
05345     }
05346     return ok;
05347         
05348 }
05349 
05350 
05351 /********************************************************************************************
05352 
05353 >   BOOL BrushAttrRecordHandler::HandleAttrFillFlags(CXaraFileRecord* pRecord)
05354 
05355     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05356     Created:    17/6/2000
05357 
05358     Inputs:     pRecord - the file record holding the data
05359     Returns:    TRUE if all went well, otherwise FALSE
05360     Purpose:    Reads in data, and assigns it to the attribute that we just created
05361 
05362 ********************************************************************************************/
05363 
05364 BOOL BrushAttrRecordHandler::HandleAttrFillFlags(CXaraFileRecord* pRecord)
05365 {
05366     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05367     
05368     // we must have a node to import to 
05369     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");    
05370 
05371     BYTE Flags = 0;
05372     
05373     if (!pRecord->ReadBYTE(&Flags))
05374         return FALSE;
05375 
05376     BOOL bUseLocalFill = Flags & BRUSHFILLFLAG_LOCALFILL;
05377     BOOL bUseLocalTransp = Flags & BRUSHFILLFLAG_LOCALTRANSP;
05378     BOOL bUseNamed = Flags & BRUSHFILLFLAG_NAMEDCOL;
05379     
05380     // we need to get the path processor
05381     PathProcessorBrush* pPPB = m_pLastAttribute->GetPathProcessor();
05382     if (pPPB == NULL)
05383         return FALSE;
05384 
05385     pPPB->SetUseLocalFillColour(bUseLocalFill);
05386     pPPB->SetUseLocalTransp(bUseLocalTransp);
05387     pPPB->SetUseNamedColours(bUseNamed);
05388 
05389     return TRUE;
05390 
05391 }
05392 
05393 
05394 /********************************************************************************************
05395 
05396 >    BOOL BrushAttrRecordHandler::HandleTranspInfo(CXaraFileRecord* pRecord)
05397 
05398     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05399     Created:    21/12/99
05400 
05401     Inputs:     pRecord - the file record holding the data
05402     Returns:    TRUE if all went well, otherwise FALSE
05403     Purpose:    Reads in data pertaining to transparency, and other assorted things
05404 
05405 ********************************************************************************************/
05406 
05407 BOOL BrushAttrRecordHandler::HandleTranspInfo(CXaraFileRecord* pRecord)
05408 {
05409     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05410     
05411     INT32 Transp              = 0;
05412     INT32 TranspPressure   = 0;
05413     double RotIncr        = 0.0;
05414     double ScaleIncr      = 0.0;
05415     INT32 HueMaxRand          = 0;
05416     INT32 HueRandSeed     = 0;
05417     INT32 SatMaxRand       = 0;
05418     INT32 SatRandSeed     = 0;
05419 
05420     if (!pRecord->ReadINT32(&Transp) || !pRecord->ReadINT32(&TranspPressure) ||
05421         !pRecord->ReadDOUBLE(&RotIncr) || !pRecord->ReadDOUBLE(&ScaleIncr) ||
05422         !pRecord->ReadINT32(&HueMaxRand) || !pRecord->ReadINT32(&HueRandSeed) ||
05423         !pRecord->ReadINT32(&SatMaxRand) || !pRecord->ReadINT32(&SatRandSeed))
05424     return FALSE;
05425 
05426     // get the brush component from the document
05427     Document* pDoc = Document::GetCurrent();
05428     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
05429     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
05430     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
05431 
05432     // find the brush definition that is currently being imported
05433     BrushDefinition* pBrushDef = pBrushComp->GetImportBrushDefinition();
05434 
05435     // give the data to the definition
05436     if (pBrushDef != NULL)
05437     {
05438         pBrushDef->SetBrushTransparency(Transp);
05439         pBrushDef->SetTransparencyPressure(UINT32(TranspPressure));
05440         pBrushDef->SetRotationIncrConst(RotIncr);
05441         pBrushDef->SetBrushScalingIncrConst(ScaleIncr);
05442         pBrushDef->SetHueMaxRand(UINT32(HueMaxRand));
05443         pBrushDef->SetHueRandSeed(UINT32(HueRandSeed));
05444         pBrushDef->SetSatMaxRand(UINT32(SatMaxRand));
05445         pBrushDef->SetSatRandSeed(UINT32(SatRandSeed));
05446     }
05447     else
05448         ERROR3("Unable to find brush definition in BrushAttrRecordHandler::HandleTranspInfo");
05449 
05450     // this is the end of this brush import
05451     m_pLastAttribute = NULL;
05452     
05453     return pBrushComp->EndImportBrush(this);
05454 
05455 }
05456 
05457 
05458 /********************************************************************************************
05459 
05460 >    BOOL BrushAttrRecordHandler::HandleAttrTranspInfo(CXaraFileRecord* pRecord)
05461 
05462     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05463     Created:    21/12/99
05464 
05465     Inputs:     pRecord - the file record holding the data
05466     Returns:    TRUE if all went well, otherwise FALSE
05467     Purpose:    Reads in data pertaining to transparency, and other assorted things
05468 
05469 ********************************************************************************************/
05470 
05471 BOOL BrushAttrRecordHandler::HandleAttrTranspInfo(CXaraFileRecord* pRecord)
05472 {
05473     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05474     
05475     // we must have a node to import to 
05476     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");    
05477 
05478     // read in the data
05479     INT32 Transp              = 0;
05480     INT32 TranspPressure   = 0;
05481     double RotIncr        = 0.0;
05482     double ScaleIncr      = 0.0;
05483     INT32 HueMaxRand          = 0;
05484     INT32 HueRandSeed     = 0;
05485     INT32 SatMaxRand       = 0;
05486     INT32 SatRandSeed     = 0;
05487 
05488     if (!pRecord->ReadINT32(&Transp) || !pRecord->ReadINT32(&TranspPressure) ||
05489         !pRecord->ReadDOUBLE(&RotIncr) || !pRecord->ReadDOUBLE(&ScaleIncr) ||
05490         !pRecord->ReadINT32(&HueMaxRand) || !pRecord->ReadINT32(&HueRandSeed) ||
05491         !pRecord->ReadINT32(&SatMaxRand) || !pRecord->ReadINT32(&SatRandSeed))
05492     return FALSE;
05493 
05494     // we need to get the path processor
05495     PathProcessorBrush* pPPB = m_pLastAttribute->GetPathProcessor();
05496 
05497     if (pPPB != NULL)
05498     {
05499         pPPB->SetBrushTransparency(Transp);
05500         pPPB->SetTransparencyPressure(UINT32(TranspPressure));
05501         pPPB->SetRotationIncrConst(RotIncr);
05502         pPPB->SetBrushScalingIncrConst(ScaleIncr);
05503         pPPB->SetHueMaxRand(UINT32(HueMaxRand));
05504         pPPB->SetHueRandSeed(UINT32(HueRandSeed));
05505         pPPB->SetSatMaxRand(UINT32(SatMaxRand));
05506         pPPB->SetSatRandSeed(UINT32(SatRandSeed));
05507     }
05508     else
05509         ERROR3("Unable to find path processor in BrushAttrRecordHandler::HandleAttrTranspInfo");
05510 
05511     return TRUE;
05512 }
05513 
05514 
05515 /********************************************************************************************
05516 
05517 >    BOOL BrushAttrRecordHandler::HandleTimeStampData(CXaraFileRecord* pRecord)
05518 
05519     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05520     Created:    21/12/99
05521 
05522     Inputs:     pRecord - the file record holding the data
05523     Returns:    TRUE if all went well, otherwise FALSE
05524     Purpose:    Reads in timestamp data and assigns it to the last attribute we created
05525 
05526 ********************************************************************************************/
05527 
05528 BOOL BrushAttrRecordHandler::HandlePressureSampleData(CXaraFileRecord* pRecord)
05529 {
05530     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL"); 
05531     
05532     // we must have a node to import to 
05533     ERROR2IF(m_pLastAttribute == NULL, FALSE, "No last attribute to import to");
05534 
05535     // first find out how many objects we have
05536     INT32 NumObjects = 0;
05537 
05538     if (!pRecord->ReadINT32(&NumObjects))
05539         return FALSE;
05540 
05541     // must be some mistake, but ours not to reason why
05542     if (NumObjects <= 0)
05543         return TRUE;
05544 
05545     // make a new pressure sampler
05546     CDistanceSampler* pSampler = new CDistanceSampler;
05547 
05548     if (pSampler == NULL)
05549         return FALSE;
05550 
05551     if (!pSampler->InitialiseData(NumObjects))
05552     {
05553         delete pSampler;
05554         return FALSE;
05555     }
05556     pSampler->SetCollectionSampleRate(1);
05557 
05558     CSampleItem TheItem;
05559     DocCoord    TheCoord;
05560     MILLIPOINT  TheDistance = 0;
05561     INT32       ThePressure = 0;
05562     BOOL ok = TRUE;
05563     BOOL KeepAdding = TRUE;
05564     UINT32 Count = 0;
05565     while (ok && KeepAdding)
05566     {
05567         if (ok) ok = pRecord->ReadINT32(&ThePressure);
05568         if (ok) ok = pRecord->ReadCoord(&TheCoord);
05569         if (ok) ok = pRecord->ReadINT32(&TheDistance);
05570 
05571         TheItem.m_Pressure  = (UINT32)ThePressure;
05572         TheItem.m_Coord     = TheCoord;
05573         TheItem.m_Distance  = TheDistance;
05574         
05575         if (ok) KeepAdding = pSampler->SetNext(TheItem);
05576         Count++;
05577     }
05578 
05579     pSampler->SetDistanceSoFar (TheItem.m_Distance);
05580 
05581     if (ok)
05582         m_pLastAttribute->SetPressureCache(pSampler);
05583     else
05584         delete pSampler;
05585 
05586     return ok;
05587 }
05588 
05589 
05590 
05591 /********************************************************************************************
05592 
05593 >   virtual BOOL BrushAttrRecordHandler::BeginSubtree(UINT32 Tag)
05594 
05595     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05596     Created:    21/12/99
05597 
05598     Inputs:     Tag = tag value of the tag this handler last handled
05599     Returns:    TRUE if this func wants exclusive handling of the tag
05600                 FALSE otherwise
05601     Purpose:    Informs the record handler that a subtree is following a tag of type 'Tag'
05602 
05603                 If you override this func and you do not wish other parts of the system to be informed of the
05604                 subtree start, you should return TRUE
05605 
05606 ********************************************************************************************/
05607 
05608 BOOL BrushAttrRecordHandler::BeginSubtree(UINT32 Tag)
05609 {
05610     // We only want to know about following subtrees when doing stroke definition records.
05611     // If we are doing one, then we grab the subtree so nobody else can faff about with it
05612     if (Tag != TAG_BRUSHDEFINITION)
05613         return(FALSE);
05614 
05615     return(TRUE);
05616 }
05617 
05618 
05619 
05620 /********************************************************************************************
05621 
05622 >   virtual BOOL BrushAttrRecordHandler::EndSubtree(UINT32 Tag)
05623 
05624     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05625     Created:    21/12/99
05626 
05627     Inputs:     Tag = tag value of the tag this handler last handled
05628     Returns:    TRUE if this func wants exclusive handling of the tag
05629                 FALSE otherwise
05630 
05631     Purpose:    Informs the record handler that a subtree that followed a tag of type 'Tag' has ended
05632 
05633                 If you override this func and you do not wish other parts of the system to be
05634                 informed of the subtree end, you should return TRUE
05635 
05636 ********************************************************************************************/
05637 
05638 BOOL BrushAttrRecordHandler::EndSubtree(UINT32 Tag)
05639 {
05640     // We only want to know about following subtrees when doing custom print mark records.
05641     // If we are doing one, then we grab the subtree so nobody else can faff about with it
05642     if (Tag != TAG_BRUSHDEFINITION)
05643         return(FALSE);
05644     
05645     // get the brush component from the document
05646     Document* pDoc = Document::GetCurrent();
05647     ERROR2IF(pDoc == NULL, FALSE, "Wheres the document?");
05648     BrushComponent* pBrushComp = (BrushComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(BrushComponent));
05649     ERROR2IF(pBrushComp == NULL, FALSE, "No brush component");
05650 
05651     return TRUE; //pBrushComp->EndImportBrush(this);
05652     
05653 }
05654 
05655 
05656 
05657 /********************************************************************************************
05658 
05659 >   virtual void BrushAttrRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pRecord,StringBase* pStr)
05660 
05661     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05662     Created:    21/12/99
05663 
05664     Inputs:     pRecord = ptr to a record
05665                 pStr = ptr to string to update
05666 
05667     Returns:    -
05668     Purpose:    Provides descriptions for the brush attribute records.
05669 
05670     Notes:      This function is only present in _DEBUG builds
05671 
05672 ********************************************************************************************/
05673 
05674 #ifdef XAR_TREE_DIALOG
05675 
05676 void BrushAttrRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pRecord, StringBase* pStr)
05677 {
05678     if (pStr == NULL || pRecord == NULL)
05679         return;
05680 
05681     // Call base class first to output the tag and size
05682     CamelotRecordHandler::GetRecordDescriptionText(pRecord, pStr);
05683 
05684 //  UINT32 Tag = pRecord->GetTag();
05685 //  INT32 RecordNumber = pRecord->GetRecordNumber();
05686 
05687 
05688 }
05689 
05690 
05691 
05692 #endif

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