fillattr.cpp

Go to the documentation of this file.
00001 // $Id: fillattr.cpp 1771 2007-06-17 20:14:43Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // This file holds all the AttributeValue and NodeAttribute classes to do with path
00100 // filling attributes.
00101 
00102 /*
00103 */
00104 
00105 #include "camtypes.h"
00106 
00107 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "colormgr.h"
00109 //#include "lineattr.h"
00110 //#include "ink.h"
00111 //#include "rndrgn.h"
00112 //#include "grndrgn.h"
00113 //#include "osrndrgn.h"
00114 //#include "mario.h"
00115 //#include "simon.h"
00116 //#include "tim.h"
00117 //#include "tranform.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 #include "blobs.h"
00120 #include "opgrad.h"
00121 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "toollist.h"
00124 #include "bitmpinf.h"
00125 //#include "filltool.h"
00126 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00127 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 #include "fracfill.h"
00129 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00130 //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00131 #include "oilbitmap.h"
00132 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00133 //#include "will.h"
00134 #include "ndoptmz.h"
00135 #include "attrmap.h"
00136 //#include "camfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00137 #include "cxftags.h"
00138 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00139 #include "rechattr.h"   // Record handling classes for attributes
00140 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00141 #include "cxfcols.h"    // REF_DEFAULTCOLOUR_TRANSPARENT ...
00142 
00143 #include "blendatt.h"
00144 #include "lineattr.h"
00145 
00146 //#include "jason.h"        // For _R(IDS_BLACK)
00147 
00148 #include "nodebmp.h"
00149 #include "nodemold.h"
00150 #include "ophist.h"
00151 
00152 //#include "bfxalu.h"       // For BfxALU::IsGreyscaleBitmap
00153 
00154 //#include "gerry.h"        // for new fill types
00155 #include "fillramp.h"   // for new fill ramps, oh luvely
00156 
00157 #include "bevtrap.h"    // for the calculate intersection stuff
00158 
00159 #include "extender.h"   // for Extender functionality
00160 //#include "ndcchbmp.h" // so we know what a NodeCacheBitmap is.
00161 #include "colcomp.h"    // for ColourListComponent
00162 #include "cutop.h"
00163 #include "effects_stack.h"
00164 
00165 
00166 DECLARE_SOURCE("$Revision: 1771 $");
00167 
00168 //
00169 // NodeAttribute classes
00170 //
00171 CC_IMPLEMENT_DYNAMIC(AttrFillGeometry,              NodeAttribute)
00172 CC_IMPLEMENT_DYNAMIC(AttrTranspFillGeometry,        AttrFillGeometry)
00173 CC_IMPLEMENT_DYNAMIC(AttrFlatFill,                  AttrFillGeometry)
00174 CC_IMPLEMENT_DYNAMIC(AttrLinearFill,                AttrFillGeometry)
00175 CC_IMPLEMENT_DYNAMIC(AttrRadialFill,                AttrFillGeometry)
00176 CC_IMPLEMENT_DYNAMIC(AttrConicalFill,               AttrFillGeometry)
00177 CC_IMPLEMENT_DYNAMIC(AttrSquareFill,                AttrFillGeometry)
00178 CC_IMPLEMENT_DYNAMIC(AttrBitmapFill,                AttrFillGeometry)
00179 CC_IMPLEMENT_DYNAMIC(AttrFractalFill,               AttrBitmapFill)
00180 CC_IMPLEMENT_DYNAMIC(AttrThreeColFill,              AttrFillGeometry)
00181 CC_IMPLEMENT_DYNAMIC(AttrFourColFill,               AttrThreeColFill)
00182 
00183 CC_IMPLEMENT_DYNAMIC(AttrValueChange,               AttrFillGeometry)
00184 CC_IMPLEMENT_DYNCREATE(AttrColourChange,            AttrValueChange)
00185 CC_IMPLEMENT_DYNCREATE(AttrColourDrop,              AttrColourChange)
00186 CC_IMPLEMENT_DYNCREATE(AttrStrokeColourChange,      AttrValueChange)
00187 CC_IMPLEMENT_DYNCREATE(AttrStrokeTranspChange,      AttrValueChange)
00188 CC_IMPLEMENT_DYNCREATE(AttrStrokeTranspTypeChange,  AttrValueChange)
00189 CC_IMPLEMENT_DYNCREATE(AttrTranspChange,            AttrValueChange)
00190 CC_IMPLEMENT_DYNCREATE(AttrTranspTypeChange,        AttrTranspChange)
00191 CC_IMPLEMENT_DYNCREATE(AttrBitmapChange,            AttrValueChange)
00192 CC_IMPLEMENT_DYNCREATE(AttrBitmapTessChange,        AttrBitmapChange)
00193 CC_IMPLEMENT_DYNCREATE(AttrBitmapDpiChange,         AttrBitmapChange)
00194 CC_IMPLEMENT_DYNCREATE(AttrFractalChange,           AttrValueChange)
00195 CC_IMPLEMENT_DYNCREATE(AttrFractalGrainChange,      AttrFractalChange)
00196 CC_IMPLEMENT_DYNCREATE(AttrFractalTileableChange,   AttrFractalChange)
00197 CC_IMPLEMENT_DYNCREATE(AttrNoiseScaleChange,        AttrValueChange)
00198 CC_IMPLEMENT_DYNCREATE(AttrColFillRampChange,       AttrValueChange)
00199 CC_IMPLEMENT_DYNCREATE(AttrTranspFillRampChange,    AttrValueChange)
00200 
00201 CC_IMPLEMENT_DYNCREATE(AttrFlatColourFill,          AttrFlatFill)
00202 CC_IMPLEMENT_DYNCREATE(AttrLinearColourFill,        AttrLinearFill)
00203 CC_IMPLEMENT_DYNCREATE(AttrRadialColourFill,        AttrRadialFill)
00204 CC_IMPLEMENT_DYNCREATE(AttrConicalColourFill,       AttrConicalFill)
00205 CC_IMPLEMENT_DYNCREATE(AttrSquareColourFill,        AttrSquareFill)
00206 CC_IMPLEMENT_DYNCREATE(AttrBitmapColourFill,        AttrBitmapFill)
00207 CC_IMPLEMENT_DYNCREATE(AttrTextureColourFill,       AttrFractalFill)
00208 CC_IMPLEMENT_DYNCREATE(AttrFractalColourFill,       AttrTextureColourFill)
00209 CC_IMPLEMENT_DYNCREATE(AttrNoiseColourFill,         AttrTextureColourFill)
00210 CC_IMPLEMENT_DYNCREATE(AttrThreeColColourFill,      AttrThreeColFill)
00211 CC_IMPLEMENT_DYNCREATE(AttrFourColColourFill,       AttrFourColFill)
00212 
00213 CC_IMPLEMENT_DYNCREATE(AttrFlatTranspFill,          AttrFlatFill)
00214 CC_IMPLEMENT_DYNCREATE(AttrLinearTranspFill,        AttrLinearFill)
00215 CC_IMPLEMENT_DYNCREATE(AttrRadialTranspFill,        AttrRadialFill)
00216 CC_IMPLEMENT_DYNCREATE(AttrConicalTranspFill,       AttrConicalFill)
00217 CC_IMPLEMENT_DYNCREATE(AttrSquareTranspFill,        AttrSquareFill)
00218 CC_IMPLEMENT_DYNCREATE(AttrBitmapTranspFill,        AttrBitmapFill)
00219 CC_IMPLEMENT_DYNCREATE(AttrTextureTranspFill,       AttrFractalFill)
00220 CC_IMPLEMENT_DYNCREATE(AttrFractalTranspFill,       AttrTextureTranspFill)
00221 CC_IMPLEMENT_DYNCREATE(AttrNoiseTranspFill,         AttrTextureTranspFill)
00222 
00223 CC_IMPLEMENT_DYNCREATE(AttrThreeColTranspFill,      AttrThreeColFill)
00224 CC_IMPLEMENT_DYNCREATE(AttrFourColTranspFill,       AttrFourColFill)
00225 
00226 CC_IMPLEMENT_DYNAMIC(AttrCircularColourFill,        AttrRadialColourFill)
00227 CC_IMPLEMENT_DYNAMIC(AttrCircularTranspFill,        AttrRadialTranspFill)
00228 
00229 CC_IMPLEMENT_DYNCREATE(AttrFillMapping,                 NodeAttribute)
00230 CC_IMPLEMENT_DYNCREATE(AttrFillMappingLinear,           AttrFillMapping)
00231 CC_IMPLEMENT_DYNCREATE(AttrFillMappingSin,              AttrFillMapping)
00232 
00233 CC_IMPLEMENT_DYNCREATE(AttrFillEffect,                  NodeAttribute)
00234 CC_IMPLEMENT_DYNCREATE(AttrFillEffectFade,              AttrFillEffect)
00235 CC_IMPLEMENT_DYNCREATE(AttrFillEffectRainbow,           AttrFillEffect)
00236 CC_IMPLEMENT_DYNCREATE(AttrFillEffectAltRainbow,        AttrFillEffect)
00237 
00238 CC_IMPLEMENT_DYNCREATE(AttrTranspFillMapping,           NodeAttribute)
00239 CC_IMPLEMENT_DYNCREATE(AttrTranspFillMappingLinear,     AttrTranspFillMapping)
00240 CC_IMPLEMENT_DYNCREATE(AttrTranspFillMappingSin,        AttrTranspFillMapping)
00241 
00242 CC_IMPLEMENT_DYNCREATE(AttrMould, NodeAttribute)
00243 
00244 // Message sent when Attributes are changed
00245 CC_IMPLEMENT_DYNAMIC(AttrChangedMsg, Msg) 
00246 
00247 CC_IMPLEMENT_MEMDUMP(FillBlobSelectionState, CC_CLASS_MEMDUMP)
00248 
00249 // v2 file format fill record handler
00250 CC_IMPLEMENT_DYNAMIC(FillAttrRecordHandler, CamelotRecordHandler)
00251 
00252 
00253 // Declare smart memory handling in Debug builds
00254 #define new CAM_DEBUG_NEW  
00255 
00256 // Static pointers used when Creating or Editing Fill Attribues
00257 AttrFillGeometry* AttrFillGeometry::EditedFill = NULL;
00258 AttrFillGeometry* AttrFillGeometry::DraggedFill = NULL;
00259 
00260 // Static variables used to stop fill meshes from overwriting one-another
00261 BOOL AttrFillGeometry::DoFillMeshCheck = TRUE;
00262 FillGeometryAttribute* AttrFillGeometry::LastRenderedMesh = NULL;
00263 DocCoord AttrFillGeometry::LastRenderedStartBlob = DocCoord(0,0);
00264 DocCoord AttrFillGeometry::LastRenderedEndBlob = DocCoord(0,0);
00265 DocCoord AttrFillGeometry::LastRenderedEnd2Blob = DocCoord(0,0);
00266 DocCoord AttrFillGeometry::LastRenderedEnd3Blob = DocCoord(0,0);
00267 
00268 BOOL AttrFillGeometry::TranspMeshesVisible = FALSE;
00269 
00270 // The number of selected fill control points
00271 UINT32 AttrFillGeometry::SelectionCount = 0;
00272 
00273 // Some Static variables used for scanning attributes in the Tree.
00274 // See AttrFillGeometry::FindFirstSelectedAttr()
00275 SelectedAttrs AttrFillGeometry::s_SelAttrs;
00276 CCAttrMap AttrFillGeometry::AttribMap;
00277 
00278 FillControl AttrFillGeometry::ControlHit;
00279 AttrFillGeometry* AttrFillGeometry::FillHit;
00280 
00281 List AttrFillGeometry::HitList;
00282 
00283 INT32 AttrFillGeometry::FractalSeed = 63933;
00284 double AttrFillGeometry::FractalGraininess = 5;
00285 double AttrFillGeometry::FractalGravity = 0;
00286 
00287 INT32 AttrFillGeometry::FractalDPI = 96;
00288 INT32 AttrFillGeometry::MaxFractalSize = 256;
00289 BOOL AttrFillGeometry::DoCheckOnFillRampMesh = TRUE;
00290 BOOL AttrFillGeometry::s_bGroupTransparency = TRUE;
00291 
00292 
00294 //
00295 //                              NodeAttribute classes
00296 //
00298 
00299 
00300 
00302 //
00303 //                              AttrFillGeometry
00304 //
00306 
00307 /********************************************************************************************
00308 
00309 >   static BOOL AttrFillGeometry::Init()
00310 
00311     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00312     Created:    21/10/94
00313     Purpose:    Intialise the fill geometry editing operations
00314 
00315 ********************************************************************************************/
00316 
00317 BOOL AttrFillGeometry::Init()
00318 {
00319 #ifdef STANDALONE
00320     BOOL ok = TRUE;
00321 #else
00322     // Initialise our fill Creation and Editing Operations
00323     BOOL ok = ( OpCreateFill::Init() && OpEditFill::Init() );
00324 #endif
00325 
00326 #if !defined(EXCLUDE_FROM_RALPH)
00327     // Declare out 'Bodge' preference that enables or disables the checking for
00328     // duplicate fill mesh rendering
00329     if (Camelot.DeclareSection(_T("DebugFlags"), 1))
00330     {
00331         Camelot.DeclarePref( NULL, _T("DoFillMeshCheck"), 
00332                         &DoFillMeshCheck, FALSE, TRUE );
00333     }
00334 
00335     if (Camelot.DeclareSection(_T("Attributes"), 6))
00336     {
00337         Camelot.DeclarePref(NULL, _T("FractalDPI"),         (UINT32*)&FractalDPI);
00338         Camelot.DeclarePref(NULL, _T("MaxFractalSize"), (UINT32*)&MaxFractalSize);
00339         Camelot.DeclarePref(NULL, _T("FractalSeed"),        (UINT32*)&FractalSeed);
00340         Camelot.DeclarePref(NULL, _T("FractalGraininess"),  &FractalGraininess);
00341         Camelot.DeclarePref(NULL, _T("FractalGravity"),     &FractalGravity);
00342         Camelot.DeclarePref(NULL, _T("GroupTransparency"), &s_bGroupTransparency);
00343     }
00344 #endif
00345 
00346 #ifndef STANDALONE
00347     if (Camelot.DeclareSection( _T("Dragging"), 3))
00348     {
00349         Camelot.DeclarePref(NULL, _T("InteractiveFillEditing"), &OpEditFill::InteractiveDragUpdate);
00350         Camelot.DeclarePref(NULL, _T("ContinuousFillControlUpdate"), &OpEditFill::ContinuousEOR);
00351         Camelot.DeclarePref(NULL, _T("DelayBeforeFillUpdate"), (UINT32*)&OpEditFill::IdleFillDelay);
00352     }
00353 #endif
00354 
00355     return ok;
00356 }
00357 
00358 /********************************************************************************************
00359 
00360     Some Static functions for other people to check for control point hits
00361     or pass clicks to attributes etc.
00362 
00363 ********************************************************************************************/
00364 
00365 /********************************************************************************************
00366 
00367 >   BOOL AttrFillGeometry::CheckAttrClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
00368                                     Spread* pSpread)
00369 
00370     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00371     Created:    14/8/94
00372     Inputs:     PointerPos - The Coords (in DocCoords) of the point where the mouse button
00373                 was clicked
00374                 Click - Describes the type of click that was detected. 
00375                 ClickMods - Indicates which buttons caused the click and which modifers were
00376                 pressed at the same time
00377     Returns:    TRUE if it handled the Click, FALSE otherwise
00378     Purpose:    Check to see if an Attribute wants to do something with a click.
00379     SeeAlso:    AttrFillGeometry::CheckForFillControlHit
00380 
00381 ********************************************************************************************/
00382 
00383 BOOL AttrFillGeometry::CheckAttrClick(DocCoord PointerPos,
00384                                       ClickType Click,
00385                                       ClickModifiers ClickMods,
00386                                       Spread* pSpread)
00387 {
00388 #ifdef STANDALONE
00389     return FALSE;
00390 #else
00391 
00392     if ( !(((Camelot.GetBlobManager())->GetCurrentInterest()).Fill) )
00393         return FALSE;   // Don't bother if fills blobs aren't displayed at the mo.
00394 
00395     // UINT32 SelCount = AttrFillGeometry::SelectionCount;
00396     LastRenderedStartBlob = DocCoord(0,0);
00397     LastRenderedEndBlob = DocCoord(0,0);
00398     LastRenderedEnd2Blob = DocCoord(0,0);
00399     LastRenderedEnd3Blob = DocCoord(0,0);
00400 
00401     if (Click == CLICKTYPE_UP)
00402     {
00403         if (!HitList.IsEmpty())
00404         {
00405             FillHit = NULL;
00406             ControlHit = FILLCONTROL_NULL;
00407             HitList.DeleteAll();    // Make sure the control hit list is empty
00408             return TRUE;
00409         }
00410     }
00411 
00412     if (Click == CLICKTYPE_SINGLE)
00413     {
00414         FillHit = NULL;
00415         ControlHit = FILLCONTROL_NULL;
00416         HitList.DeleteAll();    // Make sure the control hit list is empty
00417 
00418         // Find a fill attribute in the selection
00419         CCRuntimeClass* FillType = IsColourMeshVisible() ? CC_RUNTIME_CLASS(AttrFillGeometry)
00420                                                          : CC_RUNTIME_CLASS(AttrTranspFillGeometry);
00421         
00422         AttrFillGeometry* pAttr = FindFirstSelectedAttr(FillType);
00423     
00424         while (pAttr != NULL)
00425         {
00426             // Ask the Attribute if it wan't to do anything with the click
00427             if ( pAttr->OnClick(PointerPos, Click, ClickMods, pSpread) )
00428             {
00429                 if (FillHit == NULL)
00430                 {
00431                     FillHit = pAttr;
00432                 }
00433 
00434                 BOOL InList = FALSE;
00435 
00436                 // We may have already hit this attribute if the selection is
00437                 // inside a parent and have common attributes, so we need to
00438                 // check and make sure this attribute is NOT in the list
00439                 // already.
00440 
00441                 if (!HitList.IsEmpty())
00442                 {
00443                     ListItem* pItem = HitList.GetHead();
00444 
00445                     while (pItem)
00446                     {
00447                         NodeAttributePtrItem* NodePtr = (NodeAttributePtrItem*)pItem;
00448 
00449                         if (NodePtr->NodeAttribPtr == pAttr)
00450                         {
00451                             // Ignore this one, we've hit it already
00452                             InList = TRUE;
00453                             break;
00454                         }
00455 
00456                         pItem = HitList.GetNext(pItem);
00457                     }
00458                 }
00459 
00460                 if ( !InList &&
00461                      IsMeshSame((FillGeometryAttribute*)FillHit->GetAttributeValue(),
00462                                  (FillGeometryAttribute*)pAttr->GetAttributeValue()) ) 
00463                 {
00464                     NodeAttributePtrItem* NodePtr = new NodeAttributePtrItem;
00465 
00466                     if (NodePtr != NULL)
00467                     {
00468                         // Add the Attr to the Hit list
00469                         NodePtr->NodeAttribPtr = pAttr;
00470                         HitList.AddTail(NodePtr);
00471                     }
00472                 }
00473 
00474             }
00475 
00476             // Move onto the next.
00477             pAttr = FindNextSelectedAttr(FillType);
00478         }                              
00479 
00480         // Check to see if anyone has deselected their control points
00481         // (The click may not have hit anyone at all, but they still may
00482         // have deselected their points).
00483 //      if (!ClickMods.Adjust && HitList.IsEmpty())
00484 //      {
00485             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::COLOURATTCHANGED)); 
00486 //      }
00487 
00488 //      if (!HitList.IsEmpty())
00489 //          return TRUE;
00490     }
00491 
00492     if (Click == CLICKTYPE_DOUBLE)          // check for multi-stage fill blob insertion ....
00493     {
00494         FillHit = NULL;
00495         ControlHit = FILLCONTROL_NULL;
00496         HitList.DeleteAll();    // Make sure the control hit list is empty
00497 
00498         // Find a fill attribute in the selection
00499         CCRuntimeClass* FillType = /*IsColourMeshVisible() ?*/ CC_RUNTIME_CLASS(AttrFillGeometry);
00500                                                          //: CC_RUNTIME_CLASS(AttrTranspFillGeometry);
00501         
00502         // Use our own selected attrs iterator because OnClick uses the legacy global iterator
00503         SelectedAttrs selattrs;
00504         AttrFillGeometry* pAttr = (AttrFillGeometry*)selattrs.FindFirst(FillType);
00505 
00506         BOOL RetVal = FALSE;
00507 
00508         // walk the selection list ....
00509     
00510         while (pAttr != NULL)
00511         {   
00512             // Ask the Attribute if it wan't to do anything with the click
00513             if ( pAttr->OnClick(PointerPos, Click, ClickMods, pSpread) )
00514             {
00515                 // the actual work has been done in the above function call ....
00516                 // BUT we do need to select the new blob ....
00517                 // which by camelots marvelousness only seems to work from within the
00518                 // fill tool ....  (take a look at GradFillTool::OnClick ())
00519                 RetVal = TRUE;
00520             }
00521             
00522             // Move onto the next.
00523             pAttr = (AttrFillGeometry*)selattrs.FindNext(FillType);
00524         }
00525 
00526         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::COLOURATTCHANGED));
00527         return (RetVal);
00528     }
00529 
00530     if (Click == CLICKTYPE_SINGLE && !HitList.IsEmpty())
00531     {
00532         // We hit one or more fills, and are about to drag them ...
00533 
00534         // Is there a Drag Operation already happening ?
00535         if (Operation::GetCurrentDragOp() == NULL)
00536         {
00537             NodeAttributePtrItem* HitFillPtr = 
00538                 (NodeAttributePtrItem*)AttrFillGeometry::HitList.GetHead();
00539 
00540             AttrFillGeometry* HitFill = (AttrFillGeometry*)HitFillPtr->NodeAttribPtr;
00541             
00542             // Need to do a drag on the selected points,
00543             // so we had better start an operation
00544             OpEditFill* pOpEditFill = new OpEditFill;
00545             if (pOpEditFill == NULL)
00546             {
00547                 // Failed to get the memory to do the job
00548                 TRACEUSER( "Mike", _T("The Graduated Fill Edit Blob Operation failed to start\n") );
00549 
00550                 // Inform the user that we are out of memory
00551                 // The error message will be set by new
00552                 InformError();
00553             }
00554             else
00555             {
00556                 // check for a click on a fill ramp control point
00557                 if (ISA_RAMPINDEX(ControlHit))
00558                 {
00559                     // if so, select the point in the fill
00560                     if (HitFill->GetColourRamp())
00561                     {
00562                         HitFill->GetColourRamp()->DeselectAll();
00563                         HitFill->GetColourRamp()->SetSelState(ControlHit, 1);
00564                     }
00565                 }
00566                 
00567                 // Go drag that Control Point !!
00568                 pOpEditFill->DoDrag(PointerPos, pSpread, HitFill, ControlHit);
00569             }
00570         }
00571     
00572         return TRUE;
00573     }
00574 
00575     // Don't claim the click
00576     return FALSE;
00577 #endif
00578 }
00579 
00580 /********************************************************************************************
00581 
00582 >   virtual BOOL AttrFillGeometry::OnClick( DocCoord PointerPos, ClickType Click, 
00583                                             ClickModifiers ClickMods )
00584 
00585     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00586     Created:    22/7/94
00587     Inputs:     PointerPos - The Location of the mouse pointer at the time of the click
00588                 Click - The type of click received (single, double, drag etc)
00589                 ClickMods - The modifiers to the click (eg shift, control etc )
00590     Returns:    BOOL - TRUE if the fill claims the click as its own and FALSE if it is
00591                 not interested in the click
00592     Purpose:    Allows the fill to respond to clicks by selecting its blobs or starting
00593                 drags etc.
00594                 
00595 ********************************************************************************************/
00596 
00597 BOOL AttrFillGeometry::OnClick( DocCoord PointerPos, ClickType Click, 
00598                                 ClickModifiers ClickMods, Spread *pSpread )
00599 {
00600 #ifndef STANDALONE
00601     DocView *pDocView = DocView::GetCurrent();
00602 
00603     // Should always be able to get current view
00604     ERROR3IF(pDocView == NULL, "AttrFillGeometry::OnClick: Could not get current DocView");
00605     if (pDocView==NULL)
00606         return FALSE;
00607 
00608     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill ||
00609         !IsVisible())
00610         return FALSE;
00611 
00612     // Is it just a single click ?
00613     if ( Click == CLICKTYPE_SINGLE )
00614     {
00615         // Did the click hit any of our control points ?
00616         FillControl Hit = CheckForControlHit(PointerPos);
00617         if ( Hit != FILLCONTROL_NULL )
00618         {
00619             // It hit one of our Controls.
00620 
00621             // Was it an Adjust Click ?
00622             if (ClickMods.Adjust && !ClickMods.Constrain)
00623             {
00624                 if (!(ISA_RAMPINDEX (Hit)))             // but not for multi-stage fill blobs!
00625                 {
00626                     DeselectAllBut(Hit);
00627                     // Just toggle the Selection state
00628                     ToggleSelection(Hit);
00629                 }
00630                 else
00631                 {
00632                     SelectBlob(Hit);
00633                     DeselectAllBut(Hit);
00634                 }
00635             }
00636             else
00637             {
00638                 // It was a Select Click, so we need
00639                 // to select this Blob, and deselect
00640                 // all the others
00641                 SelectBlob(Hit);
00642                 DeselectAllBut(Hit);
00643 
00644                 if (ClickMods.Menu)             // was it the right-hand mouse button?
00645                 {
00646                     if (ISA_RAMPINDEX (Hit))    // if so and ramp, then delete the blob ....
00647                     {
00648                         OpDescriptor* pOpDelete = OpDescriptor::FindOpDescriptor (CC_RUNTIME_CLASS (OpDelete));
00649 
00650                         if (pOpDelete)
00651                         {
00652                             pOpDelete->Invoke ();
00653                         }
00654                     }
00655                 }
00656             }
00657 
00658             if (ControlHit == FILLCONTROL_NULL)
00659                 ControlHit = Hit;
00660 
00661             if (Hit != ControlHit)
00662                 return FALSE;
00663 
00664             // Claim the Click, 'cus we did something
00665             return TRUE;
00666         }
00667         else
00668         {
00669             // If it was a select click then we need to
00670             // deselect all out control points
00671             if (!ClickMods.Adjust)
00672             {
00673                 DeselectAll();
00674             }
00675 
00676             // Don't claim the click
00677             return FALSE;   
00678         }
00679     }
00680 
00681     // Is it just a double click ?          // check for insertion of multi-stage fill blob ....
00682     if (Click == CLICKTYPE_DOUBLE)
00683     {
00684         // Did the click hit any of our control points ?
00685         FillControl Hit = CheckForControlHit (PointerPos);
00686 
00687         if (Hit == FILLCONTROL_RAMPPOINT)
00688         {
00689             DocCoord StartPoint = *(GetStartPoint());
00690             DocCoord EndPoint   = *(GetEndPoint());
00691             
00692             // where on the ramp point?
00693             
00694             /*double d =*/ FindRampPoint(PointerPos, StartPoint, EndPoint);
00695             
00696             Spread* pSpread = NULL;
00697             NodeRenderableInk* pNode = NULL;
00698             Pixel32bpp Pix;
00699 
00700             Document* TheDoc = Document::GetCurrent();
00701 PORTNOTE("spread", "Multi-spread warning! Should use the passed in spread pointer?")
00702             pSpread = TheDoc->FindFirstSpread ();
00703 
00704             if (TheDoc != NULL)
00705             {
00706                 // read the colour at that point ....
00708 
00709                 pNode = (NodeRenderableInk *) this->FindParent ();
00710 
00711                 NodeRenderableInk::FindColourForNodeRenderableAtPoint (pSpread, PointerPos, Pix, pNode, this);
00712 
00713                 if (pNode != NULL)
00714                 {
00715                     // convert and apply the colour as a new fill point ....
00716                     
00717                     const double conversion = 1.0/255.0;
00718                             
00719                     FIXED24 rValF24 = Pix.Red * conversion;
00720                     FIXED24 gValF24 = Pix.Green * conversion;
00721                     FIXED24 bValF24 = Pix.Blue * conversion;
00722                     FIXED24 tValF24 = Pix.Alpha * conversion;
00723                             
00724                     ColourRGBT theColourRGBT;
00725                     theColourRGBT.Red = rValF24;
00726                     theColourRGBT.Green = gValF24;
00727                     theColourRGBT.Blue = bValF24;
00728                     theColourRGBT.Transparent = tValF24;
00729                     DocColour* ColourToApply = new DOCCOLOUR_RGBT(&theColourRGBT);
00730 
00731                     if (ColourToApply == NULL)
00732                     {
00733                         return (FALSE);
00734                     }
00735 
00736                     DocRect pSimpleBounds;
00737                     pSimpleBounds = pNode->GetBoundingRect();
00738                             
00739                     AttrColourDrop* dummyDrop = new AttrColourDrop (PointerPos, pSimpleBounds, *ColourToApply);
00740 
00741                     if (dummyDrop == NULL)
00742                     {
00743                         delete (ColourToApply);
00744                         return (FALSE);
00745                     }
00746 
00747                     //AttrFillGeometry::DoColourDropTest(dummyDrop, pNode, this);
00748 
00749                     dummyDrop->SetObjectDroppedOn (pNode);
00750 
00751                     AttributeManager::ApplyAttribToNode(pNode, dummyDrop);
00752 
00753                     delete (ColourToApply);
00754 
00755                     return (TRUE);
00756                 }
00757             }       
00758             return (FALSE);
00759         }
00760         return FALSE;
00761     }
00762 
00763 #endif
00764     return FALSE;
00765 }
00766 
00767 /********************************************************************************************
00768 
00769 >   BOOL AttrFillGeometry::IsFillBeingEdited()
00770 
00771     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00772     Created:    2/11/94
00773     Returns:    TRUE if this fill is currently being edited, FALSE otherwise
00774     Purpose:    Check to see if a fill is being edited, so we can decide whether
00775                 to render the fill mesh or not.
00776 
00777 ********************************************************************************************/
00778 
00779 BOOL AttrFillGeometry::IsFillBeingEdited()
00780 {
00781 #if !defined(EXCLUDE_FROM_RALPH)
00782     if (EditedFill == this)
00783     {
00784         return TRUE;
00785     }
00786 
00787     if (EditedFill != NULL && OpEditFill::CreateFill)
00788     {
00789         return TRUE;
00790     }
00791 
00792     if (EditedFill == NULL || HitList.IsEmpty())
00793     {
00794         return FALSE;
00795     }
00796 
00797     NodeAttributePtrItem* HitFillPtr = (NodeAttributePtrItem*)AttrFillGeometry::HitList.GetHead();
00798 
00799     while (HitFillPtr != NULL)
00800     {
00801         if (HitFillPtr->NodeAttribPtr == this)
00802         {
00803             return TRUE;
00804         }
00805 
00806         HitFillPtr = (NodeAttributePtrItem*)AttrFillGeometry::HitList.GetNext(HitFillPtr);
00807     }
00808 #endif
00809     return FALSE;
00810 }
00811 
00812 /********************************************************************************************
00813 
00814 >   static BOOL AttrFillGeometry::CheckForFillControlHit(DocCoord Pos, UINT32* Status)
00815 
00816     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00817     Created:    14/8/94
00818     Inputs:     Pointer to a Status ID to update if we hit a control point
00819     Purpose:    Check to see if the mouse moves over a fill control point.
00820 
00821 ********************************************************************************************/
00822 
00823 BOOL AttrFillGeometry::CheckForFillControlHit(DocCoord Pos, UINT32* Status)
00824 {
00825 #if !defined(EXCLUDE_FROM_RALPH)
00826     if ( !(((Camelot.GetBlobManager())->GetCurrentInterest()).Fill) )
00827         return FALSE;   // Don't bother if fills blobs aren't displayed at the mo.
00828 
00829     BOOL HitAControl = FALSE;
00830 
00831     // Find the first attribute to test
00832     CCRuntimeClass* FillType = IsColourMeshVisible() ? CC_RUNTIME_CLASS(AttrFillGeometry)
00833                                                      : CC_RUNTIME_CLASS(AttrTranspFillGeometry);
00834 
00835     AttrFillGeometry* pAttr = FindFirstSelectedAttr(FillType);
00836     while (pAttr != NULL)
00837     {
00838         // See if the current pos is over one of this fills controls
00839         FillControl Hit = pAttr->CheckForControlHit(Pos);
00840 
00841         if (Hit != FILLCONTROL_NULL)
00842         {
00843             // We'ew over one of this fills controls ...
00844             // So update the Status according to the controls selection state
00845             // and take into account whether other control are selected
00846 
00847             if ( AttrFillGeometry::SelectionCount == 0)
00848             {
00849                 // No Control points selected
00850                 *Status = _R(IDS_FS_CNTRLPNT_SO);
00851             }
00852 
00853             if ( AttrFillGeometry::SelectionCount == 1)
00854             {
00855                 // Just One Control point selected ....
00856                 if ( pAttr->IsSelected(Hit) )
00857                 {
00858                     if (!ISA_RAMPINDEX(Hit))
00859                     {
00860                         *Status = _R(IDS_FS_CNTRLPNT_DO);   // and it must be this one
00861                     }
00862                     else
00863                     {
00864                         *Status = _R(IDS_FS_CNTRLPNTMS_DO); // and it must be this one (multi-stage)
00865                     }
00866                 }
00867                 else
00868                     *Status = _R(IDS_FS_CNTRLPNT_SM);   // and it's not this one
00869             }
00870 
00871             if ( AttrFillGeometry::SelectionCount >= 2)
00872             {
00873                 // Many Control points selected ...
00874                 if ( pAttr->IsSelected(Hit) )
00875                     *Status = _R(IDS_FS_CNTRLPNT_DM);   // and this is one of them
00876                 else
00877                     *Status = _R(IDS_FS_CNTRLPNT_SM);   // and this isn't on of them
00878             }
00879 
00880             // Signal that we hit something
00881             HitAControl = TRUE;
00882             break;
00883         }
00884         // Move onto the next attr
00885         pAttr = FindNextSelectedAttr(FillType);
00886     }                              
00887 
00888     // Tell the caller whether we hit anything or not
00889     return HitAControl;
00890 #else
00891     return FALSE;
00892 #endif
00893 }
00894 
00895 /********************************************************************************************
00896 
00897 >   BOOL AttrFillGeometry::CheckPreviousFillMesh()
00898 
00899     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00900     Created:    12/8/94
00901     Purpose:    BODGE to stop fill meshes eoring each other out.
00902                 This can be disabled by setting 'DoFillMeshCheck' to '0' in the 'ini' file.
00903 
00904 ********************************************************************************************/
00905 
00906 BOOL AttrFillGeometry::CheckPreviousFillMesh()
00907 {
00908 #if !defined(EXCLUDE_FROM_RALPH)
00909     if (AllowRampRedraw)    // don't want to do this in certian cases!
00910     {
00911         // Don't bother if disabled by 'ini' file preference
00912         if (!DoFillMeshCheck)
00913             return FALSE;
00914 
00915         // Check to see if the Last Rendered Fill Mesh is the same as this one
00916         if (LastRenderedMesh != NULL && IsMeshSame(LastRenderedMesh, (FillGeometryAttribute*)GetAttributeValue()) )
00917         {
00918             // Yep, they're the same
00919             return TRUE;
00920         }
00921         else
00922         {
00923             // Not the same, so update the 'Last Rendered AttrValue' pointer
00924             LastRenderedMesh = (FillGeometryAttribute*)GetAttributeValue();
00925         }
00926         // They're not the same
00927     }
00928 #endif
00929     
00930     return FALSE;
00931 }
00932 
00933 BOOL AttrFillGeometry::IsMeshSame(FillGeometryAttribute* Fill1, FillGeometryAttribute* Fill2)
00934 {
00935 #if !defined(EXCLUDE_FROM_RALPH)
00936     BOOL PointsAreSame = FALSE;
00937 
00938     if (Fill1->GetStartPoint() != NULL && Fill2->GetStartPoint() != NULL)
00939     {
00940         if (*Fill1->GetStartPoint() != *Fill2->GetStartPoint())
00941             return FALSE;
00942 
00943         PointsAreSame = TRUE;
00944     }
00945 
00946     if (Fill1->GetEndPoint() != NULL && Fill2->GetEndPoint() != NULL)
00947     {
00948         if (*Fill1->GetEndPoint() != *Fill2->GetEndPoint())
00949             return FALSE;
00950 
00951         PointsAreSame = TRUE;
00952     }
00953 
00954     if (Fill1->GetEndPoint2() != NULL && Fill2->GetEndPoint2() != NULL)
00955     {
00956         if (*Fill1->GetEndPoint2() != *Fill2->GetEndPoint2())
00957             return FALSE;
00958 
00959         PointsAreSame = TRUE;
00960     }
00961 
00962     return PointsAreSame;
00963 #else
00964     return FALSE;
00965 #endif
00966 }
00967 
00968 UINT32 AttrFillGeometry::FillSelectionCount()
00969 {
00970     return SelectionCount;
00971 }
00972 
00973 void AttrFillGeometry::SetSelectionCount(UINT32 Count)
00974 {
00975     SelectionCount = Count;
00976 }
00977 
00978 void AttrFillGeometry::SetTranspMeshesVisible(BOOL Visible)
00979 {
00980     TranspMeshesVisible = Visible;
00981 }
00982 
00983 BOOL AttrFillGeometry::IsTranspMeshVisible()
00984 {
00985 //  if (FindParent() != NULL && !(FindParent()->IsSelected()))
00986 //      return FALSE;
00987 
00988     return TranspMeshesVisible;
00989 }
00990 
00991 BOOL AttrFillGeometry::IsColourMeshVisible()
00992 {
00993 //  if (FindParent() != NULL && !(FindParent()->IsSelected()))
00994 //      return FALSE;
00995 
00996     return !TranspMeshesVisible;
00997 }
00998 
00999 void AttrFillGeometry::SetLastRenderedBlob(FillControl Control)
01000 {
01001 #if !defined(EXCLUDE_FROM_RALPH)
01002     switch (Control)
01003     {
01004         case FILLCONTROL_STARTPOINT:
01005             if (GetStartPoint() != NULL)
01006                 LastRenderedStartBlob = *GetStartPoint();
01007             break;
01008 
01009         case FILLCONTROL_ENDPOINT:
01010             if (GetEndPoint() != NULL)
01011                 LastRenderedEndBlob = *GetEndPoint();
01012             break;
01013 
01014         case FILLCONTROL_SECONDARYPOINT:
01015         case FILLCONTROL_ENDPOINT2:
01016             if (GetEndPoint2() != NULL)
01017                 LastRenderedEnd2Blob = *GetEndPoint2();
01018             break;
01019 
01020         case FILLCONTROL_ENDPOINT3:
01021             if ((GetStartPoint() != NULL) &&
01022                 (GetEndPoint() != NULL) &&
01023                 (GetEndPoint2() != NULL))
01024             {
01025                 LastRenderedEnd3Blob = *GetEndPoint2() + *GetEndPoint() - *GetStartPoint();
01026             }
01027             break;
01028     }
01029 #endif
01030 }
01031 
01032 BOOL AttrFillGeometry::IsBlobSame(FillControl Control)
01033 {
01034 #if !defined(EXCLUDE_FROM_RALPH)
01035     switch (Control)
01036     {
01037         case FILLCONTROL_STARTPOINT:
01038             if (GetStartPoint() != NULL)
01039                 return (LastRenderedStartBlob == *GetStartPoint());
01040             break;
01041 
01042         case FILLCONTROL_ENDPOINT:
01043             if (GetEndPoint() != NULL)
01044                 return (LastRenderedEndBlob == *GetEndPoint());
01045             break;
01046 
01047         case FILLCONTROL_SECONDARYPOINT:
01048         case FILLCONTROL_ENDPOINT2:
01049             if (GetEndPoint2() != NULL)
01050                 return (LastRenderedEnd2Blob == *GetEndPoint2());
01051             break;
01052 
01053         case FILLCONTROL_ENDPOINT3:
01054             if ((GetStartPoint() != NULL) &&
01055                 (GetEndPoint() != NULL) &&
01056                 (GetEndPoint2() != NULL))
01057             {
01058                 DocCoord EndPoint3 = *GetEndPoint2() + *GetEndPoint() - *GetStartPoint();
01059                 return (LastRenderedEnd3Blob == EndPoint3);
01060             }
01061     }
01062 #endif
01063     return FALSE;   
01064 }
01065 
01066 /********************************************************************************************
01067 
01068 >   double AttrFillGeometry::FindRampPoint(DocCoord &dc, 
01069                     DocCoord &StartPoint, DocCoord &EndPoint)
01070 
01071     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01072     Created:    22/10/99
01073     Inputs:     -
01074     Outputs:    -
01075     Returns:    TRUE if this node requires transparency mode to render properly.
01076     Purpose:    Called 
01077     Errors:     -
01078     SeeAlso:    Node::AttachNode
01079 
01080 ********************************************************************************************/
01081 double AttrFillGeometry::FindRampPoint(DocCoord &dc, DocCoord &StartPoint, DocCoord &EndPoint)
01082 {
01083     DocCoord ClickPos = dc;
01084 
01085     DocRect dr(StartPoint.x, StartPoint.y, StartPoint.x, StartPoint.y);
01086 
01087     if (dr.lo.x > EndPoint.x)
01088     {
01089         dr.lo.x = EndPoint.x;
01090     }
01091             
01092     if (dr.lo.y > EndPoint.y)
01093     {
01094         dr.lo.y = EndPoint.y;
01095     }
01096 
01097     if (dr.hi.x < EndPoint.x)
01098     {
01099             dr.hi.x = EndPoint.x;
01100     }
01101     
01102     if (dr.hi.y < EndPoint.y)
01103     {
01104         dr.hi.y = EndPoint.y;
01105     }
01106 
01107     // get the blob size
01108     double dBlobSize = (double)(Camelot.GetBlobManager())->GetBlobSize();
01109 
01110     if (dr.Width() < (INT32)(dBlobSize * 2))
01111     {
01112         // add half a point to the hit test area
01113         dr.hi.x += (INT32)(dBlobSize * 2);
01114         dr.lo.x -= (INT32)(dBlobSize * 2);
01115     }
01116 
01117     if (dr.Height() < (INT32)(dBlobSize * 2))
01118     {
01119         dr.hi.y += (INT32)(dBlobSize * 2);
01120         dr.lo.y -= (INT32)(dBlobSize * 2);
01121     }
01122     
01123     if (dr.ContainsCoord(ClickPos))
01124     {
01125         // find out if the pointer is on the line (or near it) by
01126         // calculating the perpendicular distance between the
01127         // point and the line
01128         double p = 0;
01129         
01130         double dPosX = ClickPos.x;
01131         double dPosY = ClickPos.y;
01132         
01133         double dX1 = StartPoint.x;
01134         double dY1 = StartPoint.y;
01135         
01136         double dX2 = EndPoint.x;
01137         double dY2 = EndPoint.y;
01138         
01139         double dTestPosY = 0;
01140         double dTestPosX = 0;
01141         
01142         if (fabs(dX2 - dX1) > fabs(dY2 - dY1))
01143         {
01144             if (dX2 != dX1)
01145             {
01146                 p = (dPosX - dX1) / (dX2 - dX1);
01147             
01148                 dTestPosY = ((dY2 - dY1) * p) + dY1;
01149             
01150                 // do the hit test on the line
01151                 if (fabs(dTestPosY - dPosY) < dBlobSize / 2)
01152                 {
01153                     return p;
01154                 }
01155             }
01156         }
01157         else if (dY2 != dY1)
01158         {
01159             p = (dPosY - dY1) / (dY2 - dY1);
01160             
01161             dTestPosX = ((dX2 - dX1) * p) + dX1;
01162             
01163             // do the hit test on the line
01164             if (fabs(dTestPosX - dPosX) < dBlobSize / 2)
01165             {
01166                 return p;           
01167             }
01168         }
01169     }
01170 
01171     return -1;
01172 }
01173 
01174 /********************************************************************************************
01175 
01176 >   virtual BOOL AttrFillGeometry::NeedsTransparency() const
01177 
01178     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01179     Created:    11/5/95
01180     Inputs:     -
01181     Outputs:    -
01182     Returns:    TRUE if this node requires transparency mode to render properly.
01183     Purpose:    Called 
01184     Errors:     -
01185     SeeAlso:    Node::AttachNode
01186 
01187 ********************************************************************************************/
01188 
01189 BOOL AttrFillGeometry::NeedsTransparency() const
01190 {
01191     AttrFillGeometry* pNonConst = (AttrFillGeometry*) this;
01192 
01193     if (!pNonConst->IsAFractalFill() && pNonConst->GetBitmap() != NULL && pNonConst->GetBitmap()->GetBPP() <= 8)
01194     {
01195         INT32 TranspIndex;
01196 
01197         // If the bitmap has a transparency index then we'll need to force transparency on
01198         if (pNonConst->GetBitmap()->GetTransparencyIndex(&TranspIndex))
01199             return TRUE;
01200     }
01201 
01202     return FALSE;
01203 }
01204 
01205 /********************************************************************************************
01206 
01207 >   AttrFillGeometry::AttrFillGeometry()
01208 
01209     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01210     Created:    25/07/94
01211     Purpose:    Default constructor for a Fill Attribute.
01212                 Sets default Selection State and Attribute Bounds.
01213 
01214 ********************************************************************************************/
01215 
01216 AttrFillGeometry::AttrFillGeometry() 
01217 {
01218     // Make all the control points deselected
01219     SelectionState[FILLCONTROL_STARTPOINT] = FALSE;
01220     SelectionState[FILLCONTROL_ENDPOINT] = FALSE;
01221     SelectionState[FILLCONTROL_ENDPOINT2] = FALSE;
01222     SelectionState[FILLCONTROL_ENDPOINT3] = FALSE;
01223     SelectionState[FILLCONTROL_SECONDARYPOINT] = FALSE;
01224 
01225     // Make the attribute bounds empty.
01226     // Attribute bounds are only used for 'Current Attributes' that do not have
01227     // a parent, so they can be scaled when applied to a new object.
01228     AttrBounds = DocRect(0,0,0,0);
01229 
01230     AllowRampRedraw = TRUE;
01231     AllowBoundsRedraw = TRUE;
01232 }
01233 
01234 /********************************************************************************************
01235 
01236 >   AttrFillGeometry::~AttrFillGeometry()
01237 
01238     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01239     Created:    25/07/94
01240     Purpose:    Destroys a Fill.
01241                 Currently this function does nothing.
01242 
01243 ********************************************************************************************/
01244 
01245 AttrFillGeometry::~AttrFillGeometry()
01246 {
01247     LastRenderedMesh = NULL;        // this ptr may be pointing to us!
01248 }
01249 
01250 /********************************************************************************************
01251 
01252 >   INT32 AttrFillGeometry::operator=(const AttrFillGeometry& FillAttrib)
01253 
01254     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01255     Created:    23/8/94
01256     Inputs:     Attrib - the attribute to compare, which must be an AttrFillGeometry
01257     Returns:    Usual semantics for equality.
01258     Purpose:    A virtual comparison operator. See NodeAttribute::operator== for 
01259                 a description of why it's required. 
01260     Errors:     An ERROR3IF failure will occur if Attrib does not have a AttrFlatGeometry 
01261                 runtime class.
01262     SeeAlso:    NodeAttribute::operator==
01263 
01264 ********************************************************************************************/
01265 
01266 INT32 AttrFillGeometry::operator=(AttrFillGeometry& FillAttrib)
01267 {
01268     ERROR3IF(!FillAttrib.IsAFillAttr(), 
01269                 "Trying to assign two objects with different types"); 
01270 
01271     // Copy the Attribute bounds
01272     AttrBounds = FillAttrib.AttrBounds;
01273 
01274     // Copy the selection state
01275     for (INT32 i=0; i < FILLCONTROL_SECONDARYPOINT; i++)
01276     {
01277         SetBlobState(i, FillAttrib.IsSelected(i));
01278     }
01279 
01280     // Copy the Attribute Value.  ie. The Colours and Control Points
01281     *((FillGeometryAttribute*)GetAttributeValue()) = *((FillGeometryAttribute*)FillAttrib.GetAttributeValue());
01282 
01283     // Ensure the control points are valid for this kind of fill
01284     if (GetRuntimeClass() != FillAttrib.GetRuntimeClass())
01285         ValidateAttributeValue();
01286 
01287     return TRUE;
01288 }
01289 
01290 /********************************************************************************************
01291 
01292 >   BOOL AttrFillGeometry::CopyNodeContents( AttrFillGeometry* NodeCopy)
01293 
01294     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01295     Created:    8/8/94
01296     Outputs:    NodeCopy - A copy of this node
01297     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
01298     Errors:     An assertion failure will occur if NodeCopy is NULL
01299     Scope:      protected
01300                                      
01301 ********************************************************************************************/
01302 
01303 BOOL AttrFillGeometry::CopyNodeContents( AttrFillGeometry* NodeCopy)
01304 {
01305     // First call the base class copy function
01306     NodeAttribute::CopyNodeContents( NodeCopy );
01307 
01308     // Copy contents specific to derived class here
01309     NodeCopy->AttrBounds = AttrBounds;
01310 
01311     // Copy the selection state
01312     for (INT32 i=0; i < FILLCONTROL_SECONDARYPOINT; i++)
01313     {
01314         NodeCopy->SetBlobState(i, IsSelected(i));
01315     }
01316 
01317     // and finally, copy the Colours and Control Points
01318     NodeCopy->GetAttributeValue()->SimpleCopy(GetAttributeValue());
01319 
01320     return TRUE;
01321 } 
01322 
01323 
01324 
01325 /***********************************************************************************************
01326 >   void AttrFillGeometry::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01327 
01328     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01329     Created:    18/12/2003
01330     Outputs:    -
01331     Purpose:    Polymorphically copies the contents of this node to another
01332     Errors:     An assertion failure will occur if NodeCopy is NULL
01333     Scope:      protected
01334                                      
01335 ***********************************************************************************************/
01336 
01337 void AttrFillGeometry::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01338 {
01339     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
01340     ENSURE(pNodeCopy->IsKindOf(CC_RUNTIME_CLASS(AttrFillGeometry)), "PolyCopyNodeContents given wrong dest node type");
01341 
01342     if (pNodeCopy->IsKindOf(CC_RUNTIME_CLASS(AttrFillGeometry)))
01343         CopyNodeContents((AttrFillGeometry*)pNodeCopy);
01344 }
01345 
01346 
01347 
01348 /********************************************************************************************
01349 
01350 >   INT32 AttrFillGeometry::operator==(const NodeAttribute& Attrib)
01351 
01352     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01353     Created:    23/8/94
01354     Inputs:     Attrib - the attribute to compare, which must be an AttrFillGeometry
01355     Returns:    Usual semantics for equality.
01356     Purpose:    A virtual comparison operator. See NodeAttribute::operator== for 
01357                 a description of why it's required. 
01358     Errors:     An ERROR3IF failure will occur if Attrib does not have a AttrFlatGeometry 
01359                 runtime class.
01360     SeeAlso:    NodeAttribute::operator==
01361 
01362 ********************************************************************************************/
01363 
01364 INT32 AttrFillGeometry::operator==(const NodeAttribute& Attrib)
01365 {
01366     // First check they are of the same type
01367     if (((NodeAttribute*)&Attrib)->GetAttributeType() != GetAttributeType())
01368         return FALSE;
01369 
01370     // Make a more sensible pointer
01371     AttrFillGeometry* Attr = (AttrFillGeometry*)&Attrib;
01372 
01373     // Are the attributes of the same type and are their value the same ?
01374     return (*((FillGeometryAttribute*)Attr->GetAttributeValue()) == *((FillGeometryAttribute*)GetAttributeValue()) );
01375 }
01376 
01377 /********************************************************************************************
01378     
01379 // Some static functions, which scan the current Selection for Fill Attributes
01380 // returning each one as it finds them.
01381 
01382 ********************************************************************************************/
01383 
01384 /********************************************************************************************
01385 
01386 >   AttrFillGeometry* AttrFillGeometry::FindFirstSelectedAttr(CCRuntimeClass* AttrType)
01387 
01388     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01389     Created:    15/8/94
01390     Returns:    The first AttrFillGeometry it finds in the selection.
01391                 or NULL if they're aren't any.
01392     Purpose:    Scans the selection for fill attributes.
01393     SeeAlso:    AttrFillGeometry::FindNextSelectedAttr
01394 
01395 ********************************************************************************************/
01396 
01397 AttrFillGeometry* AttrFillGeometry::FindFirstSelectedAttr(CCRuntimeClass* AttrType)
01398 {
01399     NodeAttribute* pAttr = s_SelAttrs.FindFirst(AttrType);
01400     if (pAttr && pAttr->IsAFillAttr())
01401         return (AttrFillGeometry*) pAttr;
01402     return NULL;
01403 }
01404 
01405 
01406 /********************************************************************************************
01407 
01408 >   AttrFillGeometry* AttrFillGeometry::FindNextSelectedAttr(CCRuntimeClass* AttrType)
01409 
01410     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01411     Created:    15/8/94
01412     Returns:    The next AttrFillGeometry it finds in the selection.
01413     Purpose:    Scans the selection for fill attributes.
01414     SeeAlso:    AttrFillGeometry::FindFirstSelectedAttr
01415 
01416 ********************************************************************************************/
01417 
01418 AttrFillGeometry* AttrFillGeometry::FindNextSelectedAttr(CCRuntimeClass* AttrType)
01419 {
01420     NodeAttribute* pAttr = s_SelAttrs.FindNext(AttrType);
01421     if (pAttr && pAttr->IsAFillAttr())
01422         return (AttrFillGeometry*) pAttr;
01423     return NULL;
01424 }
01425 
01426 
01427 /********************************************************************************************
01428 
01429 >   NodeAttribute* SelectedAttrs::FindFirst(CCRuntimeClass* AttrType)
01430 
01431     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01432     Created:    20/4/2005
01433     Returns:    The first AttrFillGeometry it finds in the selection.
01434                 or NULL if they're aren't any.
01435     Purpose:    Scans the selection for attributes.
01436                 Replaces AttrFillGeometry::FindFirstSelectedAttr without relying on global
01437                 variables!
01438     SeeAlso:    AttrFillGeometry::FindNextSelectedAttr
01439 
01440 ********************************************************************************************/
01441 
01442 NodeAttribute* SelectedAttrs::FindFirst(CCRuntimeClass* AttrType)
01443 {
01444     // Get the current selection
01445     // and initialise all statics to initial conditions
01446     m_pAttrSelection = Camelot.FindSelection();
01447     m_pLastSelectedAttr = NULL;
01448     m_pSelNode = NULL;
01449 
01450     // If previous use of FindFirst/NextSelectedAttr was stopped before FindNext had reached the
01451     // end, AttrSelectionLevel may still be left lying around...
01452     if (m_pAttrSelectionLevel)
01453     {
01454         delete m_pAttrSelectionLevel;
01455         m_pAttrSelectionLevel = NULL;
01456     }
01457 
01458     m_pAttrSelectionLevel = EffectsStack::GetNewLevelRange(NULL, FALSE);    // Don't escape old controllers, apply attr to base nodes
01459 
01460     if (m_pAttrSelectionLevel)
01461     {
01462         // Find the first Object
01463         m_pSelNode = m_pAttrSelectionLevel->FindFirst();
01464         if (m_pSelNode)
01465         {
01466             // Now find any attributes that are applied to this node.
01467             Node* pAttrNode = m_pSelNode;
01468             if (m_pSelNode->IsAnObject())
01469                 pAttrNode = ((NodeRenderableInk*)m_pSelNode)->GetObjectToApplyTo(AttrType);
01470             ENSURE(pAttrNode->IsAnObject(), "Found unexpected non-ink node in FindFirstSelectedAttr");
01471             m_pLastSelectedAttr = ((NodeRenderableInk*)pAttrNode)->FindAppliedAttribute(AttrType);
01472             if (m_pLastSelectedAttr)
01473                 return (NodeAttribute*)m_pLastSelectedAttr;
01474         }
01475 
01476         // If nothing found on first object or level range is empty
01477         // fall into FindNext so that we don't have to
01478         // duplicate its loop and its tidy up features...
01479         return FindNext(AttrType);
01480     }
01481 
01482     ENSURE(m_pAttrSelectionLevel==NULL, "Possible Range Leak");
01483     m_pAttrSelection = NULL;
01484     m_pSelNode = NULL;
01485     m_pLastSelectedAttr = NULL;
01486     return NULL;
01487 }
01488 
01489 
01490 /********************************************************************************************
01491 
01492 >   NodeAttribute* SelectedAttrs::FindNext(CCRuntimeClass* AttrType)
01493 
01494     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01495     Created:    20/4/2005
01496     Returns:    The next AttrFillGeometry it finds in the selection.
01497     Purpose:    Scans the selection for fill attributes.
01498     SeeAlso:    AttrFillGeometry::FindFirstSelectedAttr
01499 
01500 ********************************************************************************************/
01501 
01502 NodeAttribute* SelectedAttrs::FindNext(CCRuntimeClass* AttrType)
01503 {
01504     // Better make sure nobodys being Silly
01505     ERROR2IF((m_pAttrSelection==NULL), NULL, "AttrSelection NULL in FindNextSelectedAttr");
01506     ERROR2IF((m_pAttrSelectionLevel==NULL), NULL, "AttrSelectionLevel NULL in FindNextSelectedAttr");
01507 
01508     // Loop through the selection range until found another match or end of range
01509     while (m_pSelNode)
01510     {
01511         m_pSelNode = m_pAttrSelectionLevel->FindNext(m_pSelNode);
01512 
01513         if (m_pSelNode)
01514         {
01515             // Now find any attributes that are applied to this node.
01516             Node* pAttrNode = m_pSelNode;
01517             if (m_pSelNode->IsAnObject())
01518                 pAttrNode = ((NodeRenderableInk*)m_pSelNode)->GetObjectToApplyTo(AttrType);
01519             ENSURE(pAttrNode->IsAnObject(), "Found unexpected non-ink node in FindFirstSelectedAttr");
01520             m_pLastSelectedAttr = ((NodeRenderableInk*)pAttrNode)->FindAppliedAttribute(AttrType);
01521             if (m_pLastSelectedAttr)
01522             {
01523                 return (NodeAttribute*)m_pLastSelectedAttr;
01524             }
01525         }
01526     }
01527 
01528     // End of iteration so clear out our statics
01529     if (m_pAttrSelectionLevel)
01530     {
01531         delete m_pAttrSelectionLevel;
01532         m_pAttrSelectionLevel = NULL;
01533     }
01534     m_pAttrSelection = NULL;
01535     m_pSelNode = NULL;
01536     m_pLastSelectedAttr = NULL;
01537 
01538     return NULL;
01539 }
01540 
01541 
01542 /********************************************************************************************
01543 
01544 >   void AttrFillGeometry::RenderFillBlobs()
01545 
01546     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01547     Created:    29/9/94
01548     Purpose:    Force Renders the fill mesh off the screen.
01549 
01550 ********************************************************************************************/
01551 
01552 void AttrFillGeometry::RenderFillBlobs()
01553 {
01554 #if !defined(EXCLUDE_FROM_RALPH)
01555     Node *pNode = this;
01556     while ((pNode != NULL) && !pNode->IsKindOf(CC_RUNTIME_CLASS(Spread)))
01557         pNode = pNode->FindParent();
01558 
01559     if (pNode == NULL)
01560         return;         // We're not really in the tree
01561 
01562     Spread* pSpread = (Spread*)pNode;
01563 
01564     DocRect Bounds = GetBlobBoundingRect();
01565 
01566     // EOR on in all the render regions that are still rendering,
01567     // so that the Blob rendering when the region is finished, 
01568     // will take them off
01569     RenderRegionList* pRegionList = GetApplication()->GetRegionList();
01570     
01571     if (!pRegionList->IsEmpty())
01572     {
01573         RenderRegion* pRegion = (RenderRegion*)pRegionList->GetHead();  
01574         
01575         while (pRegion)
01576         {
01577             // Check the RenderRegion is for the same spread.
01578             if (pRegion->GetRenderSpread() == pSpread &&
01579                 (pRegion->IsInkRenderStarted || pRegion->NeedsOSPaper))
01580             {
01581                 // Render the blobs 'clipped' to this Render Region.
01582                 DocRect ClipRect = pRegion->GetRegionRect();
01583         
01584                 if (ClipRect.IsIntersectedWith(Bounds))
01585                 {
01586                     ClipRect = ClipRect.Intersection(Bounds);
01587                     RenderRegion* pRegion = DocView::RenderOnTop(&ClipRect, pSpread, UnclippedEOR);
01588                     while (pRegion)
01589                     {
01590                         RenderFillBlobs(pRegion);
01591                         LastRenderedMesh = NULL;
01592 
01593                         // Get the Next render region
01594                         pRegion = DocView::GetNextOnTop(&ClipRect);
01595                     }
01596                 }
01597             }
01598 
01599             // Get the Next render region
01600             pRegion = (RenderRegion*)pRegionList->GetNext(pRegion);
01601         }
01602     }
01603 
01604     RenderRegion* pRegion = DocView::RenderOnTop(&Bounds, pSpread, UnclippedEOR);
01605     while (pRegion)
01606     {
01607         RenderFillBlobs(pRegion);
01608         LastRenderedMesh = NULL;
01609 
01610         // Get the Next render region
01611         pRegion = DocView::GetNextOnTop(&Bounds);
01612     }
01613 
01614     // This call was removed by Gerry (2/9/96) as it causes blob problems
01615     // Since we are removing blobs then force all blobs to be deselected
01616 //  DeselectAllNoRedraw();
01617 #endif
01618 }
01619 
01620 /********************************************************************************************
01621     
01622 // Fill Control Point Selection state functions
01623 
01624 ********************************************************************************************/
01625 
01626 /********************************************************************************************
01627 
01628 >   BOOL* AttrFillGeometry::GetSelectionState()
01629 
01630     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01631     Created:    26/7/94
01632     Inputs:     SelState - Array of BOOLs to represent the Selection of Fill Control Points.
01633                 PointCount - The number of control points you are interested in.
01634                              Must be <= NUMCONTROLPOINTS
01635     Purpose:    Get the current Selection state of the Fill Control Points.
01636     SeeAlso:    AttrFillGeometry::IsSelected; AttrFillGeometry::SetSelectionState; 
01637                 AttrFillGeometry::SetBlobState; 
01638                 AttrFillGeometry::CountSelectionControlPoints; 
01639                 AttrFillGeometry::GetSelectionCount; 
01640                 FillControl
01641 
01642 ********************************************************************************************/
01643 
01644 UINT32 AttrFillGeometry::GetSelectionState(BOOL **pOutputState)
01645 {
01646     // check the output pointer
01647     if (pOutputState==NULL)
01648         return 0;
01649 
01650     // assign an output parameter
01651     (*pOutputState=NULL);
01652 
01653     // get the total number if blobs in this fill
01654     UINT32 Count = GetBlobCount();
01655     if (Count==0)
01656         return 0;
01657 
01658     // allocate ourselves an array to hold the data.
01659     BOOL* pArray = (BOOL*)malloc(Count*sizeof(BOOL));
01660     if (pArray==NULL)
01661         return 0;
01662 
01663     // Obtain the selection state of each control point
01664     INT32                   i;
01665     for( i = 0; i<5; i++)
01666     {
01667         pArray[i] = IsSelected(i);
01668     }
01669 
01670     // obtain the selection state of each fill ramp blob
01671     FillRamp *pRamp = GetFillRamp();
01672     if (pRamp)
01673         pRamp->GetSelectionState(&pArray[i]);
01674 
01675     // assign the output
01676     (*pOutputState = pArray);
01677     return Count;
01678 }
01679 
01680 
01681 /********************************************************************************************
01682 
01683 >   UINT32 AttrFillGeometry::GetBlobCount(BOOL IncludeRamps=TRUE)
01684 
01685     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01686     Created:    10/3/97
01687     Inputs:     -
01688     Returns:    the number of blobs in this fill geometry (including colour ramps)
01689     Purpose:    Return the number of editable points in this fill geometry.
01690 
01691 ********************************************************************************************/
01692 
01693 UINT32 AttrFillGeometry::GetBlobCount(BOOL IncludeRamps)
01694 {
01695     UINT32 count=5;
01696     if (IncludeRamps)
01697     {
01698         FillRamp *pRamp = GetFillRamp();
01699         if (pRamp)
01700             count+=pRamp->GetCount();
01701     }
01702     return count;
01703 }
01704 
01705 /*
01706 void AttrFillGeometry::GetSelectionState(BOOL* SelState, INT32 PointCount)
01707 {
01708     if (PointCount > NUMCONTROLPOINTS)
01709         PointCount = NUMCONTROLPOINTS;
01710 
01711     // Obtain the selection state of each control point
01712     for (INT32 i=0; i < PointCount; i++)
01713     {
01714         SelState[i] = IsSelected(i);
01715     }
01716 }
01717 */
01718 
01719 
01720 
01721 /********************************************************************************************
01722 
01723 >   FillRamp* AttrFillGeometry::GetFillRamp() const
01724 
01725     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01726     Created:    10/3/97
01727     Inputs:     -
01728     Returns:    A fill ramp pointer
01729     Purpose:    Return the fill ramp associated with this fill geometry. Currently this
01730                 ramp can be either a colour ramp or a transparency ramp. Other ramps might
01731                 well be added at a later time
01732 
01733 ********************************************************************************************/
01734 
01735 FillRamp* AttrFillGeometry::GetFillRamp()
01736 {
01737     FillRamp*   pRamp = GetColourRamp();
01738     if (!pRamp) pRamp = GetTranspRamp();
01739     return pRamp;
01740 }
01741 
01742 
01743 /********************************************************************************************
01744 
01745 >   DocColour* AttrFillGeometry::GetFirstSelectedColour()
01746 
01747     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01748     Created:    10/3/97
01749     Inputs:     -
01750     Returns:    
01751     Purpose:    Get the colour associated with the first selected endpoint. This function
01752                 tends to be used with GetSelectionCount once you've worked out there's only
01753                 one end point selected. At least I use it mostly that way.
01754 
01755 ********************************************************************************************/
01756 
01757 DocColour* AttrFillGeometry::GetFirstSelectedColour()
01758 {
01759     // Don't bother checking for FILLCONTROL_SECONDARYPOINT as this can never
01760     // be selected.
01761     if (IsSelected(FILLCONTROL_STARTPOINT)) return GetStartColour();
01762     if (IsSelected(FILLCONTROL_ENDPOINT))   return GetEndColour();
01763     if (IsSelected(FILLCONTROL_ENDPOINT2))  return GetEndColour2();
01764     if (IsSelected(FILLCONTROL_ENDPOINT3))  return GetEndColour3();
01765 
01766     // ok is there a colour ramp in this fill? If so check it too.
01767     ColourRamp *pRamp = GetColourRamp();
01768     if (pRamp)
01769         return pRamp->GetFirstSelectedColour();
01770 
01771     // nothing selected here
01772     return NULL;
01773 }
01774 
01775 
01776 /********************************************************************************************
01777 
01778 >   UINT32* AttrFillGeometry::GetFirstSelectedTransp()
01779 
01780     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01781     Created:    10/3/97
01782     Inputs:     -
01783     Returns:    A pointer to the first selected transparency value. (This can be null as
01784                 defined by WillC, so we need to return a pointer rather than the actual
01785                 value.
01786     Purpose:    Get the transparency associated with the first selected endpoint. This function
01787                 tends to be used with GetSelectionCount once you've worked out there's only
01788                 one end point selected. At least I use it mostly that way.
01789 
01790 ********************************************************************************************/
01791 
01792 UINT32* AttrFillGeometry::GetFirstSelectedTransp()
01793 {
01794     if (IsSelected(FILLCONTROL_STARTPOINT)) return GetStartTransp();
01795     if (IsSelected(FILLCONTROL_ENDPOINT))   return GetEndTransp();
01796     if (IsSelected(FILLCONTROL_ENDPOINT2))  return GetEndTransp2();
01797     if (IsSelected(FILLCONTROL_ENDPOINT3))  return GetEndTransp3();
01798 
01799     // ok is there a colour ramp in this fill? If so check it too.
01800     TransparencyRamp *pRamp = GetTranspRamp();
01801     if (pRamp)
01802         return pRamp->GetFirstSelectedTransp();
01803 
01804     // nothing selected here
01805     return NULL;
01806 }
01807 
01808 
01809 
01810 /********************************************************************************************
01811 
01812 >   INT32 AttrFillGeometry::GetFirstSelectedIndex()
01813 
01814     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01815     Created:    10/3/97
01816     Inputs:     -
01817     Returns:    The index of the first selected end blob. [0..n-1]
01818                 -1 if there isn't one
01819     Purpose:    Find the index of the first selected endpoint. If nothing is selected
01820                 -1 will be returned otherwise a number 0..n-1.
01821 
01822 ********************************************************************************************/
01823 
01824 INT32 AttrFillGeometry::GetFirstSelectedIndex()
01825 {
01826     // is there a selected blob internal to the geometry?
01827     for (INT32 i=0; i<FILLCONTROL_SECONDARYPOINT; i++)
01828     {
01829         if (IsSelected(i))
01830             return i;
01831     }
01832 
01833     // note, all fill geometries either contain a colour ramp
01834     // or a transparency ramp, but not both!
01835     FillRamp *pRamp = GetFillRamp();
01836     if (pRamp)
01837         return pRamp->GetSelectedIndex();
01838     
01839     // nothing selected
01840     return -1;
01841 }
01842 
01843 
01844 
01845 
01846 /********************************************************************************************
01847 
01848 >   void AttrFillGeometry::SetSelectionState(BOOL* SelState, INT32 PointCount)
01849 
01850     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01851     Created:    26/7/94
01852     Inputs:     SelState - Array of BOOLs to represent the Selection of Fill Control Points.
01853                 PointCount - The number of control points you want to set.
01854                              Must be <= NUMCONTROLPOINTS
01855     Purpose:    Set the Selection state of the Fill Control Points.
01856     SeeAlso:    AttrFillGeometry::IsSelected; AttrFillGeometry::GetSelectionState; 
01857                 AttrFillGeometry::SetBlobState; 
01858                 AttrFillGeometry::CountSelectionControlPoints; 
01859                 AttrFillGeometry::GetSelectionCount; 
01860                 FillControl
01861 
01862 ********************************************************************************************/
01863 /*
01864 void AttrFillGeometry::SetSelectionState(BOOL* SelState, INT32 PointCount)
01865 {
01866     if (PointCount > NUMCONTROLPOINTS)
01867         PointCount = NUMCONTROLPOINTS;
01868 
01869     // Set the selection state of each control point
01870     for (INT32 i=0; i < PointCount; i++)
01871     {
01872         SetBlobState(i, SelState[i]);
01873     }
01874 }
01875 */
01876 
01877 /********************************************************************************************
01878 
01879 >   BOOL AttrFillGeometry::IsSelected(FillControl Control)
01880 
01881     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01882     Created:    14/8/94
01883     Purpose:    Determines if a Fill Control Point is selected or not.
01884     SeeAlso:    AttrFillGeometry::SetSelectionState; AttrFillGeometry::GetSelectionState; 
01885                 AttrFillGeometry::SetBlobState; 
01886                 AttrFillGeometry::CountSelectionControlPoints; 
01887                 AttrFillGeometry::GetSelectionCount; 
01888                 FillControl
01889 
01890 ********************************************************************************************/
01891 
01892 BOOL AttrFillGeometry::IsSelected(UINT32 Control)
01893 {
01894 #if !defined(EXCLUDE_FROM_RALPH)
01895     
01896     // check for a fill ramp index first.
01897     if (ISA_RAMPINDEX(Control))
01898     {
01899         FillRamp *pRamp = GetFillRamp();
01900         if (pRamp)
01901             return pRamp->IsSelected(Control);
01902     }
01903     
01904     ERROR2IF(Control > NUMCONTROLPOINTS, FALSE, "Invalid control point in IsSelected()");
01905     
01906     // Secondary points can never be selected
01907     if (Control == FILLCONTROL_SECONDARYPOINT)
01908         return FALSE;
01909 
01910     return SelectionState[Control];
01911 #else
01912     return FALSE;
01913 #endif
01914 }
01915 
01916 /********************************************************************************************
01917 
01918 >   UINT32 AttrFillGeometry::CountSelectionControlPoints()
01919 
01920     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01921     Created:    14/8/94
01922     Returns:    UINT32, the number of selected fill control points in the selection.
01923     Purpose:    Get the number of Selected Fill Control Points within the selected objects.
01924     SeeAlso:    AttrFillGeometry::IsSelected; 
01925                 AttrFillGeometry::SetSelectionState; AttrFillGeometry::GetSelectionState; 
01926                 AttrFillGeometry::SetBlobState; 
01927                 AttrFillGeometry::GetSelectionCount; 
01928                 FillControl
01929 
01930 ********************************************************************************************/
01931 
01932 UINT32 AttrFillGeometry::CountSelectionControlPoints()
01933 {
01934     UINT32 Count = 0;
01935 
01936 #if !defined(EXCLUDE_FROM_RALPH)
01937     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill)
01938         return 0;
01939 
01940     CCRuntimeClass* FillType = IsColourMeshVisible() ? CC_RUNTIME_CLASS(AttrFillGeometry)
01941                                                      : CC_RUNTIME_CLASS(AttrTranspFillGeometry);
01942 
01943     // Find the first Fill Attribute in the current Selection
01944     AttrFillGeometry* pAttr = FindFirstSelectedAttr(FillType);
01945 
01946     while (pAttr != NULL)
01947     {
01948         // Count this fill selected control points
01949         // and keep a running total
01950         if (pAttr->IsVisible())
01951             Count += pAttr->GetSelectionCount();
01952 
01953         // Move on to the next Fill
01954         pAttr = FindNextSelectedAttr(FillType);
01955     }
01956 
01957 #endif
01958     // Count = Total number of fill control points
01959     // selected within the current Selection
01960     return Count;
01961 }
01962 
01963 /********************************************************************************************
01964 
01965 >   UINT32 AttrFillGeometry::GetSelectionCount()
01966 
01967     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01968     Created:    14/8/94
01969     Returns:    UINT32, the number of selected control points in this fill.
01970     Purpose:    Get the number of Selected Fill Control Points.
01971     SeeAlso:    AttrFillGeometry::CountSelectionControlPoints;
01972                 AttrFillGeometry::IsSelected; 
01973                 AttrFillGeometry::SetSelectionState; AttrFillGeometry::GetSelectionState; 
01974                 AttrFillGeometry::SetBlobState; 
01975                 FillControl
01976 
01977 ********************************************************************************************/
01978 
01979 UINT32 AttrFillGeometry::GetSelectionCount()
01980 {
01981     UINT32 Count = 0;
01982 #if !defined(EXCLUDE_FROM_RALPH)
01983     // Go though each control point, and increament
01984     // a count if the point is selected.
01985     for (INT32 i=0; i < FILLCONTROL_SECONDARYPOINT; i++)
01986     {
01987         if (IsSelected(i)) Count++;
01988     }
01989 
01990     // add in selected blobs on any colour ramp or transparency ramp
01991     FillRamp *pRamp = GetFillRamp();
01992     if (pRamp)
01993         Count += pRamp->CountSelBlobs();
01994 
01995 #endif
01996     // Number of Selected Fill Control Points
01997     return Count;
01998 }
01999 
02000 /********************************************************************************************
02001 
02002 >   void AttrFillGeometry::SetBlobState(FillControl HitControl, BOOL Selected)
02003 
02004     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02005     Created:    26/07/94
02006     Inputs:     HitControl, the FillControl to set the state of.
02007                 Selected, a BOOL indicating whether to select or deslect this Point.
02008     Purpose:    Sets the selection state of a particular Control Point. 
02009     SeeAlso:    AttrFillGeometry::IsSelected; 
02010                 AttrFillGeometry::SetSelectionState; AttrFillGeometry::GetSelectionState; 
02011                 AttrFillGeometry::CountSelectionControlPoints;
02012                 AttrFillGeometry::GetSelectionCount; 
02013                 FillControl
02014 
02015 ********************************************************************************************/
02016 
02017 void AttrFillGeometry::SetBlobState(FillControl HitControl, BOOL NewState)
02018 {
02019 #if !defined(EXCLUDE_FROM_RALPH)
02020     ChangeBlobState(HitControl, (NewState ? BLOBSTATE_ON : BLOBSTATE_OFF));
02021 #endif
02022 }
02023 
02024 /********************************************************************************************
02025 
02026 >   void AttrFillGeometry::SelectBlob(FillControl HitControl)
02027 
02028     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02029     Created:    26/07/94
02030     Inputs:     HitControl, the FillControl that is to be selected.
02031     Purpose:    Selects a Fill Control Point. 
02032     SeeAlso:    AttrFillGeometry::DeselectBlob;
02033                 AttrFillGeometry::ToggleSelection;
02034                 FillControl;
02035 
02036 ********************************************************************************************/
02037 
02038 void AttrFillGeometry::SelectBlob(FillControl HitControl)
02039 {
02040 #if !defined(EXCLUDE_FROM_RALPH)
02041     ChangeBlobState(HitControl, BLOBSTATE_ON);
02042 #endif
02043 }
02044 
02045 
02046 /********************************************************************************************
02047 
02048 >   void AttrFillGeometry::DeselectBlob(FillControl HitControl)
02049 
02050     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02051     Created:    26/07/94
02052     Inputs:     HitControl, the FillControl that is to be Deselected.
02053     Purpose:    Deselects a particular Fill Control Point. 
02054     SeeAlso:    AttrFillGeometry::SelectBlob;
02055                 AttrFillGeometry::ToggleSelection;
02056                 FillControl;
02057 
02058 ********************************************************************************************/
02059 
02060 void AttrFillGeometry::DeselectBlob(FillControl HitControl)
02061 {
02062 #if !defined(EXCLUDE_FROM_RALPH)
02063     ChangeBlobState(HitControl, BLOBSTATE_OFF);
02064 #endif
02065 }
02066 
02067 /********************************************************************************************
02068 
02069 >   void AttrFillGeometry::ToggleSelection(FillControl HitControl)
02070 
02071     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02072     Created:    26/07/94
02073     Inputs:     HitControl, the FillControl who's state is to be toggled.
02074     Purpose:    Toggle the selection of a Fill Control Point. 
02075     SeeAlso:    AttrFillGeometry::SelectBlob;
02076                 AttrFillGeometry::DeselectBlob;
02077                 FillControl;
02078 
02079 ********************************************************************************************/
02080 
02081 void AttrFillGeometry::ToggleSelection(FillControl HitControl)
02082 {
02083 #if !defined(EXCLUDE_FROM_RALPH)
02084     ChangeBlobState(HitControl, BLOBSTATE_TOGGLE);
02085 #endif
02086 }
02087 
02088 /********************************************************************************************
02089 
02090 >   void AttrFillGeometry::ChangeBlobState(FillControl HitControl, INT32 state)
02091 
02092     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02093     Created:    26/07/94
02094     Inputs:     HitControl, the FillControl that is to be selected.
02095                 state = 0 = deselect blob
02096                         1 = select blob
02097                         2 = toggle blob selection
02098     Purpose:    Sets the state of a fill blob
02099 
02100 ********************************************************************************************/
02101 
02102 void AttrFillGeometry::ChangeBlobState(FillControl HitControl, INT32 state)
02103 {
02104 #if !defined(EXCLUDE_FROM_RALPH)
02105 
02106     // check for a ramp index first - Added by Mike 10/3/97
02107     if (ISA_RAMPINDEX(HitControl))
02108     {
02109         FillRamp *pRamp = GetFillRamp();
02110         if (pRamp)
02111         {
02112             RenderControl(HitControl,FALSE);
02113             pRamp->SetSelState(HitControl,state);
02114             RenderControl(HitControl,state);    
02115             // TODO: NEED TO DO SOMETHING ABOUT - SetLastRenderedBlob(HitControl);
02116             //SetLastRenderedBlob(HitControl);
02117         }
02118         return;
02119     }
02120 
02121     // Can't Select DragPoints
02122     if (HitControl >= FILLCONTROL_DRAGPOINT)
02123         return;
02124 
02125     // Secondary Point selection state is a mirror of End Point selection
02126     if (HitControl == FILLCONTROL_SECONDARYPOINT)
02127         HitControl = FILLCONTROL_ENDPOINT;
02128 
02129     // Save the current state of the blob
02130     BOOL oldstate = SelectionState[HitControl];
02131     BOOL newstate = oldstate;
02132 
02133     // now alter to the new state
02134     switch (state)
02135     {
02136         case BLOBSTATE_OFF: 
02137             newstate = FALSE; 
02138         break;
02139         case BLOBSTATE_ON: 
02140             newstate = TRUE;    
02141         break;
02142         case BLOBSTATE_TOGGLE: 
02143             newstate = !oldstate;
02144         break;
02145     }
02146 
02147     // has the state changed?
02148     if (oldstate != newstate)
02149     {
02150         // Undraw the old blob
02151         RenderControl(HitControl, FALSE);
02152         SelectionState[HitControl] = newstate;
02153         // Redraw the new blob
02154         RenderControl(HitControl, TRUE);
02155         SetLastRenderedBlob(HitControl);
02156     }
02157 #endif
02158 }
02159 
02160 
02161 
02162 /********************************************************************************************
02163 
02164 >   virtual void AttrFillGeometry::CycleSelection(BOOL Reverse)
02165 
02166     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
02167     Created:    24/3/2000
02168     Purpose:    Cycles the selection state of the controls
02169 
02170 ********************************************************************************************/
02171 
02172 void AttrFillGeometry::CycleSelection(BOOL Reverse)
02173 {
02174     // have we got some sort of colour ramp?
02175     FillRamp *pRamp = GetFillRamp();
02176     if (pRamp)
02177     {
02178         // ok, we have a ramp involved, so lets cycle
02179 
02180         BOOL StartPointSelected, EndPointSelected;
02181         FillControl Result, OldSelectedBlob; //NewSelectedBlob;
02182 
02183         if (Reverse)
02184         {
02185             StartPointSelected  = IsSelected (FILLCONTROL_STARTPOINT);
02186             EndPointSelected = IsSelected (FILLCONTROL_ENDPOINT);
02187 
02188             Result = pRamp->RotateSelLeft (StartPointSelected, EndPointSelected, OldSelectedBlob);
02189 
02190             switch (Result)
02191             {
02192                 case FILLCONTROL_STARTPOINT:
02193                     if (OldSelectedBlob != FILLCONTROL_NULL)
02194                     {
02195                         SetBlobState (OldSelectedBlob, TRUE);
02196                         pRamp->SetSelState (OldSelectedBlob, FALSE);
02197                     }
02198                     
02199                     SetBlobState (Result, TRUE);
02200                 break;
02201                 case FILLCONTROL_ENDPOINT:
02202                     ToggleSelection(FILLCONTROL_STARTPOINT);
02203                     SetBlobState (Result, TRUE);
02204                 break;
02205                 default:
02206                     if (ISA_RAMPINDEX (Result))
02207                     {
02208                         if (StartPointSelected) { SetBlobState (FILLCONTROL_STARTPOINT, FALSE); }
02209                         if (EndPointSelected) { SetBlobState (FILLCONTROL_ENDPOINT, FALSE); }
02210 
02211                         if (OldSelectedBlob != FILLCONTROL_NULL)
02212                         {
02213                             SetBlobState (OldSelectedBlob, TRUE);
02214                             pRamp->SetSelState (OldSelectedBlob, FALSE);
02215                         }
02216                         SetBlobState (Result, TRUE);
02217                     }
02218                     
02219                     // do nothing - since handled in RotateSelRight
02220                     return;
02221             }
02222         }
02223         else
02224         {
02225             StartPointSelected  = IsSelected (FILLCONTROL_STARTPOINT);
02226             EndPointSelected = IsSelected (FILLCONTROL_ENDPOINT);
02227 
02228             Result = pRamp->RotateSelRight (StartPointSelected, EndPointSelected, OldSelectedBlob);
02229 
02230             switch (Result)
02231             {
02232                 case FILLCONTROL_STARTPOINT:
02233                     ToggleSelection(FILLCONTROL_ENDPOINT);
02234                     SetBlobState (Result, TRUE);
02235                 break;
02236                 case FILLCONTROL_ENDPOINT:
02237                     if (OldSelectedBlob != FILLCONTROL_NULL)
02238                     {
02239                         SetBlobState (OldSelectedBlob, TRUE);
02240                         pRamp->SetSelState (OldSelectedBlob, FALSE);
02241                     }
02242                     
02243                     SetBlobState (Result, TRUE);
02244                 break;
02245                 default:
02246                     if (ISA_RAMPINDEX (Result))
02247                     {
02248                         if (StartPointSelected) { SetBlobState (FILLCONTROL_STARTPOINT, FALSE); }
02249                         if (EndPointSelected) { SetBlobState (FILLCONTROL_ENDPOINT, FALSE); }
02250 
02251                         if (OldSelectedBlob != FILLCONTROL_NULL)
02252                         {
02253                             SetBlobState (OldSelectedBlob, TRUE);
02254                             pRamp->SetSelState (OldSelectedBlob, FALSE);
02255                         }
02256                         SetBlobState (Result, TRUE);
02257                     }
02258                     
02259                     // do nothing - since handled in RotateSelRight
02260                     return;
02261             }
02262         }       
02263         return;
02264     }
02265     else
02266     {
02267         if (GetSelectionCount() == 1)
02268         {
02269             ToggleSelection(FILLCONTROL_STARTPOINT);
02270             ToggleSelection(FILLCONTROL_ENDPOINT);
02271         }
02272     }
02273 }
02274 
02275 
02276 /********************************************************************************************
02277 
02278 >   void AttrFillGeometry::DeselectAllNoRedraw()
02279 
02280     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02281     Created:    26/07/94
02282     Purpose:    Deselects all of the Fill Control Points for this fill,
02283                 without redawing anything
02284 
02285 ********************************************************************************************/
02286 
02287 void AttrFillGeometry::DeselectAllNoRedraw()
02288 {
02289 #if !defined(EXCLUDE_FROM_RALPH)
02290     // Force all our control points to be deselected
02291     SelectionState[FILLCONTROL_STARTPOINT]      = FALSE;
02292     SelectionState[FILLCONTROL_ENDPOINT]        = FALSE;
02293     SelectionState[FILLCONTROL_ENDPOINT2]       = FALSE;
02294     SelectionState[FILLCONTROL_ENDPOINT3]       = FALSE;
02295     SelectionState[FILLCONTROL_SECONDARYPOINT]  = FALSE;
02296     // And all our colour ramp control points to.
02297     FillRamp *pRamp = GetFillRamp();
02298     if (pRamp)
02299         pRamp->DeselectAll();
02300 #endif
02301 }
02302 
02303 /********************************************************************************************
02304 
02305 >   void AttrFillGeometry::DeselectAll()
02306 
02307     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02308     Created:    26/07/94
02309     Purpose:    Deselects all of the Fill Control Points for this fill. 
02310 
02311 ********************************************************************************************/
02312 
02313 void AttrFillGeometry::DeselectAll()
02314 {
02315 #if !defined(EXCLUDE_FROM_RALPH)
02316     // Force all our control points to be deselected
02317     ChangeBlobState(FILLCONTROL_STARTPOINT,BLOBSTATE_OFF);
02318     ChangeBlobState(FILLCONTROL_ENDPOINT  ,BLOBSTATE_OFF);
02319     ChangeBlobState(FILLCONTROL_ENDPOINT2 ,BLOBSTATE_OFF);
02320     ChangeBlobState(FILLCONTROL_ENDPOINT3 ,BLOBSTATE_OFF);
02321 
02322     // And all our colour/transparency ramp control points to.
02323     FillRamp *pRamp = GetFillRamp();
02324     if (pRamp)
02325     {
02326         UINT32 first,last;
02327         if (pRamp->GetIndexRange(&first,&last))
02328         {
02329             for (UINT32 i=first; i<=last; i++)
02330                 ChangeBlobState(i ,BLOBSTATE_OFF);
02331         }
02332     }
02333 #endif
02334 }
02335 
02336 /********************************************************************************************
02337 
02338 >   void AttrFillGeometry::DeselectAllBut(FillControl HitControl)
02339 
02340     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02341     Created:    26/07/94
02342     Inputs:     HitControl, the FillControl that should NOT be deselected.
02343     Purpose:    Deselects all but one of the Fill Control Points. 
02344 
02345 ********************************************************************************************/
02346 
02347 void AttrFillGeometry::DeselectAllBut(FillControl HitControl)
02348 {
02349 #if !defined(EXCLUDE_FROM_RALPH)
02350     // Secondary Point selection state is a mirror of End Point selection
02351     if (HitControl == FILLCONTROL_SECONDARYPOINT)
02352         HitControl = FILLCONTROL_ENDPOINT;
02353     
02354     for (INT32 i=0; i<FILLCONTROL_SECONDARYPOINT; i++)
02355     {
02356         if ((HitControl!=i) && SelectionState[i])
02357             ChangeBlobState(i,BLOBSTATE_OFF);
02358     }
02359 
02360     // And all our colour/transparency ramp control points to.
02361     FillRamp *pRamp = GetFillRamp();
02362     if (pRamp)
02363     {
02364         UINT32 first,last;
02365         UINT32 hc = (UINT32)HitControl;
02366         if (pRamp->GetIndexRange(&first,&last))
02367         {
02368             for (UINT32 i=first; i<=last; i++)
02369                 if (hc!=i)  
02370                     ChangeBlobState(i ,BLOBSTATE_OFF);
02371         }
02372     }
02373     
02374 #endif
02375 }
02376 
02377 /********************************************************************************************
02378 
02379 >   FillControl AttrFillGeometry::CheckForControlHit(DocCoord &ClickPos)
02380 
02381     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02382     Created:    21/07/94
02383     Inputs:     ClickPos, The DocCoord position to check.
02384     Returns:    A FillControl, indicating the Fill Control Point Hit,
02385                 or FILLCONTROL_NULL, if no points hit.
02386     Purpose:    Check to see if a click was on a Fill Control Point. 
02387     SeeAlso:    FillControl
02388 
02389 ********************************************************************************************/
02390 
02391 FillControl AttrFillGeometry::CheckForControlHit(DocCoord &ClickPos)
02392 {
02393     // Set up a default, that indicates not control points hit
02394     FillControl HitControl = FILLCONTROL_NULL;
02395     DocRect BlobRect;
02396 
02397     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
02398         return FILLCONTROL_NULL;
02399 
02400     // Ok see if we've hit a fill ramp blob.
02401     FillRamp *pRamp = GetFillRamp();
02402     if (pRamp)
02403     {
02404         // have we hit a blob on the fill ramp?
02405         HitControl = pRamp->HitBlob(ATTRVALUE(), ClickPos);
02406         if (!ISA_RAMPINDEX(HitControl))
02407         {
02408             HitControl=FILLCONTROL_NULL;
02409         }
02410         else
02411         {
02412             // if we hit a fill ramp blob, then we need to stop others points from grabbing the drag!
02413             return (HitControl);
02414         }
02415     }
02416 
02417     // otherwise try the geometry points.
02418     if (GetStartPoint() != NULL)
02419     {
02420         // Get the rectangle around the Start Control Point
02421         (Camelot.GetBlobManager())->GetBlobRect(*GetStartPoint(), &BlobRect);
02422         // See if the Click Position is within the rectangle
02423         if ( BlobRect.ContainsCoord(ClickPos) )
02424             HitControl = FILLCONTROL_STARTPOINT;
02425     }
02426 
02427     if (GetEndPoint() != NULL)
02428     {
02429         // Get the rectangle around the end control point
02430         (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint(), &BlobRect);
02431         // See if the Click Position is within the rectangle
02432         if ( BlobRect.ContainsCoord(ClickPos) )
02433             HitControl = FILLCONTROL_ENDPOINT;
02434     }
02435 
02436     if (GetEndPoint2() != NULL)
02437     {
02438         // Get the rectangle around the secondary control point
02439         (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint2(), &BlobRect);
02440         // See if the Click Position is within the rectangle
02441         if ( BlobRect.ContainsCoord(ClickPos) )
02442             HitControl = FILLCONTROL_SECONDARYPOINT;
02443     }
02444 
02445     if (DoCheckOnFillRampMesh)
02446     {
02447         // DMc
02448         if (HitControl == FILLCONTROL_NULL)
02449         {
02450             // check for a hit along the linear fill line
02451             // first, get the line
02452             if (GetStartPoint() != NULL && GetEndPoint() != NULL)
02453             {
02454                 // check the bounding rect first
02455                 DocCoord StartPoint = *(GetStartPoint());
02456                 DocCoord EndPoint   = *(GetEndPoint());
02457 
02458                 double d = FindRampPoint(ClickPos, StartPoint, EndPoint);
02459 
02460                 if ( d > 0 && d < 1.0)
02461                 {
02462                     HitControl = FILLCONTROL_RAMPPOINT;
02463                 }       
02464             }
02465         }
02466     }
02467 
02468     return HitControl;
02469 }
02470 
02471 /********************************************************************************************
02472 
02473 >   void AttrFillGeometry::RenderControl(FillControl Control, BOOL RenderOn)
02474 
02475     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02476     Created:    26/7/94
02477     Inputs:     Control, the FillControl to redraw
02478                 RenderOn = TRUE, if we're putting the control on. FALSE if taking it off.
02479     Purpose:    Redraws the Fill Control blobs when the selection changes.
02480     SeeAlso:    FillControl         
02481 
02482 ********************************************************************************************/
02483 
02484 void AttrFillGeometry::RenderControl(FillControl Control, BOOL RenderOn)
02485 {
02486 #if !defined(EXCLUDE_FROM_RALPH)
02487     DocRect ControlRect;
02488 
02489     // Ignore if we're not in the tree yet
02490     // We may be a tempory clone, or something
02491     NodeRenderable* pParent = (NodeRenderable*)FindParent();
02492     if (pParent == NULL)
02493         return;
02494 
02495     if (IsBlobSame(Control))
02496         return;         // Ignore if same as the last blob rendered
02497 
02498     Spread* pSpread = this->FindParentSpread();
02499 
02500     if (ISA_RAMPINDEX(Control))
02501     {
02502         FillRamp* pRamp = GetFillRamp();
02503         if (pRamp)
02504         {
02505             DocCoord point = pRamp->GetGeometryCoord(ATTRVALUE(), Control);
02506             (Camelot.GetBlobManager())->GetBlobRect(point, &ControlRect, TRUE);
02507             RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
02508         }
02509         return;
02510     }   
02511     
02512     switch (Control)
02513     {
02514         case FILLCONTROL_STARTPOINT:
02515             if (GetStartPoint() != NULL)
02516             {
02517                 // Redraw the Start Point Blob
02518                 (Camelot.GetBlobManager())->GetBlobRect(*GetStartPoint(), &ControlRect);
02519                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
02520             }
02521             break;
02522 
02523         case FILLCONTROL_ENDPOINT:
02524         case FILLCONTROL_SECONDARYPOINT:
02525         {
02526             if (GetEndPoint() != NULL)
02527             {
02528                 // Redraw BOTH End Point Blobs
02529                 (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint(), &ControlRect);
02530                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
02531             }
02532 
02533             if (GetEndPoint2() != NULL)
02534             {
02535                 (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint2(), &ControlRect);
02536                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
02537             }
02538         }
02539         break;
02540     }
02541 #endif
02542 }
02543 
02544 /********************************************************************************************
02545 
02546 >   void AttrFillGeometry::RenderFillControl(BOOL RenderOn, 
02547                                      DocRect* ControlRect, 
02548                                      Spread* pSpread, 
02549                                      NodeRenderable* pParent)
02550     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02551     Created:    13/6/95
02552     Purpose:    Renders a fill control
02553 
02554 ********************************************************************************************/
02555 
02556 void AttrFillGeometry::RenderFillControl(BOOL RenderOn, 
02557                                      DocRect* ControlRect, 
02558                                      Spread* pSpread, 
02559                                      NodeRenderable* pParent)
02560 {
02561 #if !defined(EXCLUDE_FROM_RALPH)
02562     if (!RenderOn)
02563     {
02564         RenderControlIntoPendingRegions(ControlRect, pSpread, pParent);
02565     }
02566 
02567     (Camelot.GetBlobManager())->RenderMyBlobs(ControlRect, pSpread, pParent);
02568     AttrFillGeometry::LastRenderedMesh = NULL;
02569 
02570     if (RenderOn)
02571     {
02572         RenderControlIntoPendingRegions(ControlRect, pSpread, pParent);
02573     }
02574 #endif
02575 }
02576 
02577 /********************************************************************************************
02578 
02579 >   void AttrFillGeometry::RenderControlIntoPendingRegions( DocRect* ControlRect, 
02580                                                             Spread* pSpread, 
02581                                                             NodeRenderable* pParent)
02582     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02583     Created:    13/6/95
02584     Purpose:    Renders the fill control into all pending render regions.
02585 
02586 ********************************************************************************************/
02587 
02588 void AttrFillGeometry::RenderControlIntoPendingRegions( DocRect* ControlRect, 
02589                                                         Spread* pSpread, 
02590                                                         NodeRenderable* pParent)
02591 {
02592 #if !defined(EXCLUDE_FROM_RALPH)
02593     RenderRegionList* pRegionList = GetApplication()->GetRegionList();
02594     
02595     if (!pRegionList->IsEmpty())
02596     {
02597         RenderRegion* pRegion = (RenderRegion*)pRegionList->GetHead();  
02598         
02599         while (pRegion)
02600         {
02601             // Check the RenderRegion is for the same spread.
02602             if (pRegion->GetRenderSpread() == pSpread &&
02603                 (pRegion->IsInkRenderStarted || pRegion->NeedsOSPaper))
02604             {
02605                 // Render the blobs 'clipped' to this Render Region.
02606                 DocRect ClipRect = pRegion->GetRegionRect();
02607         
02608                 if (ClipRect.IsIntersectedWith(*ControlRect))
02609                 {
02610                     ClipRect = ClipRect.Intersection(*ControlRect);
02611                     (Camelot.GetBlobManager())->RenderMyBlobs(&ClipRect, pSpread, pParent);
02612                 }
02613             }
02614 
02615             // Get the Next render region
02616             pRegion = (RenderRegion*)pRegionList->GetNext(pRegion);
02617         }
02618     }
02619 
02620     AttrFillGeometry::LastRenderedMesh = NULL;
02621 #endif
02622 }
02623 
02624 /********************************************************************************************
02625 
02626 >   virtual void AttrFillGeometry::OnControlDrag( DocCoord Pos, FillControl DragControl, 
02627                                                     ClickModifiers ClickMods)
02628     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02629     Created:    2/8/94
02630     Inputs:     Pos - The Location of the mouse pointer at the time of the call
02631                 DragControl - The FillControl that is being dragged.
02632                 ClickMods - The modifiers to the click (eg shift, control etc )
02633     Purpose:    Called when an edit operation is dragging a fill control point.
02634 
02635 ********************************************************************************************/
02636 
02637 void AttrFillGeometry::OnControlDrag( DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
02638 {
02639 #if !defined(EXCLUDE_FROM_RALPH)
02640 
02641 //  Document * pDoc = Document::GetCurrent();
02642 
02643     if (ISA_RAMPINDEX(DragControl))
02644     {
02645         // Aha, we're dragging a point on the fill ramp. We need to do all sorts of
02646         // gubbins here. The point being dragged will need to be snapped to the geometry
02647         // of the fill.
02648         // Algorithm is simply
02649         //   (1) FindClosestPointInGeometrySpace(InCoord, OutParam)
02650         //   (2) pRamp->SetPosition(DragControl, OutParam);
02651     
02652         FillRamp *pRamp = GetFillRamp();
02653         if (pRamp)
02654         {
02655             float t = ATTRVALUE()->GetGeometryParam(Pos);
02656     
02657             FillControl NewDragControl = pRamp->SetPosition(DragControl, t);
02658 
02659             if (NewDragControl != DragControl)
02660             {
02661                 DragControl = NewDragControl;
02662             }
02663     //      pRamp->SortRamp (TRUE);
02664         }
02665         return;
02666     }
02667 
02668     // Is the Control Point Valid ?
02669     ERROR3IF(DragControl > NUMCONTROLPOINTS, "Invalid control point in OnControlDrag()");
02670 
02671     // Which control is being dragged ?
02672     switch (DragControl)
02673     {
02674         case FILLCONTROL_STARTPOINT:
02675 
02676             if (GetStartPoint() != NULL)
02677             {
02678                 // They're dragging the Start Point
02679                 if (ClickMods.Constrain)
02680                 {
02681                     // If the Constrain key is down then constrain the Angle of the
02682                     // point, relative to the other end.
02683                     DocView::ConstrainToAngle(*GetEndPoint(), &Pos);
02684                 }
02685 
02686                 SetStartPoint(&Pos);
02687                 DocCoord temp = MakeLineAtAngle(*GetStartPoint(), *GetEndPoint(), 90);
02688                 SetEndPoint2(&temp);
02689             }
02690             break;
02691 
02692         case FILLCONTROL_ENDPOINT:
02693 
02694             if (GetEndPoint() != NULL)
02695             {
02696                 // They're dragging the End Point
02697                 if (ClickMods.Constrain)
02698                 {
02699                     // If the Constrain key is down then constrain the Angle of the
02700                     // point, relative to the other end.
02701                     DocView::ConstrainToAngle(*GetStartPoint(), &Pos);
02702                 }
02703 
02704                 SetEndPoint(&Pos);
02705                 DocCoord temp = MakeLineAtAngle(*GetStartPoint(), *GetEndPoint(), 90);
02706                 SetEndPoint2(&temp);
02707             }
02708             break;
02709 
02710         case FILLCONTROL_SECONDARYPOINT:
02711 
02712             if (GetEndPoint2() != NULL)
02713             {
02714                 // They're dragging the Secondary Point
02715                 if (ClickMods.Constrain)
02716                 {
02717                     // If the Constrain key is down then constrain the Angle of the
02718                     // point, relative to the other end.
02719                     DocView::ConstrainToAngle(*GetStartPoint(), &Pos);
02720                 }
02721 
02722                 SetEndPoint2(&Pos);
02723             }
02724             break;
02725     }
02726 #endif
02727 }
02728 
02729 void AttrFillGeometry::SetAspectRatio(double Ratio)
02730 {
02731 #if !defined(EXCLUDE_FROM_RALPH)
02732     DocCoord Start  = *GetStartPoint();
02733     DocCoord End    = *GetEndPoint();
02734 
02735     DocCoord End2 = MakeLineAtAngle(Start, 
02736                                     End, 
02737                                     90, 
02738                                     INT32(Start.Distance(End) * Ratio)
02739                                     );
02740 
02741     SetEndPoint2(&End2);
02742 #endif
02743 }
02744 
02745 /********************************************************************************************
02746 
02747 >   void AttrFillGeometry::GetControlPoints(DocCoord* PointArray, INT32 NumControls)    
02748 
02749     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02750     Created:    2/8/94
02751     Inputs:     PointArray, an array of DocCoords to update with control positions
02752                 NumControl, the number of Control points to get.
02753     Outputs:    PointArray is updated with the positions of the Fill Control Points.
02754     Purpose:    Get the positions of fill control points.
02755 
02756 ********************************************************************************************/
02757 
02758 void AttrFillGeometry::GetControlPoints(DocCoord* PointArray, INT32 NumControls)    
02759 {
02760 #if !defined(EXCLUDE_FROM_RALPH)
02761     // Make sure nobodys being silly
02762     if (NumControls > NUMCONTROLPOINTS)
02763         NumControls = NUMCONTROLPOINTS;
02764 
02765     // Make a tempory copy of the points positions
02766     DocCoord Controls[NUMCONTROLPOINTS];
02767     
02768     if (GetStartPoint() != NULL)
02769         Controls[FILLCONTROL_STARTPOINT] = *GetStartPoint();
02770     if (GetEndPoint() != NULL)
02771         Controls[FILLCONTROL_ENDPOINT]   = *GetEndPoint();
02772     if (GetEndPoint2() != NULL)
02773         Controls[FILLCONTROL_SECONDARYPOINT] = *GetEndPoint2();
02774     if (GetEndPoint2() != NULL)
02775         Controls[FILLCONTROL_ENDPOINT2]   = *GetEndPoint2();
02776     if (GetEndPoint3() != NULL)
02777         Controls[FILLCONTROL_ENDPOINT3]   = *GetEndPoint3();
02778 
02779     // Copy the positions into the callers array
02780     for (INT32 i=0; i < NumControls; i++)
02781     {
02782         PointArray[i] = Controls [i];
02783     }
02784 #endif
02785 }
02786 
02787 /********************************************************************************************
02788 
02789 >   void AttrFillGeometry::SetBoundingRect(DocRect &NewBounds)
02790 
02791     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02792     Created:    28/7/94
02793     Returns:    DocRect - The rectangle specifying the new bounds.
02794     Purpose:    Set the Attributes bounding rectangle, which is used for current attributes
02795                 and scaling when applying to new ink nodes.
02796                 This rect is only used for 'Current' Attributes which don't have any parent
02797                 bounds. It allows us to scale current attributes when they are applied.
02798 
02799 ********************************************************************************************/
02800 
02801 void AttrFillGeometry::SetBoundingRect(DocRect &NewBounds)
02802 { 
02803     // Er.. Update the Bounding Rectangle thingy.
02804     // This rect is only used for 'Current' Attributes which don't have any parent bounds
02805     // It allows us to scale current attributes when they are applied.
02806     AttrBounds = NewBounds;
02807 }
02808 
02809 /********************************************************************************************
02810 
02811 >   BOOL AttrFillGeometry::WriteBoundingRect(BaseCamelotFilter* pFilter)
02812 
02813     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02814     Created:    23/03/2004
02815     Returns:    DocRect - The rectangle specifying the new bounds.
02816     Purpose:    Write the Attributes bounding rectangle.
02817 
02818 ********************************************************************************************/
02819 
02820 BOOL AttrFillGeometry::WriteBoundingRect(BaseCamelotFilter* pFilter)
02821 {
02822     BOOL ok = TRUE;
02823 
02824     CamelotFileRecord Rec(pFilter, TAG_CURRENTATTRIBUTEBOUNDS, TAG_CURRENTATTRIBUTEBOUNDS_SIZE);
02825 
02826     ok = Rec.Init();
02827 
02828     if (ok) ok = Rec.WriteCoord(AttrBounds.lo); // write out low corner details
02829     if (ok) ok = Rec.WriteCoord(AttrBounds.hi); // write out high corner details
02830 
02831     // Finally, write the record out to file
02832     // In the process get the record number that this was written out as
02833     INT32 RecordNumber = 0L;
02834     if (ok) RecordNumber = pFilter->Write(&Rec);
02835     
02836     // If we have had a problem at any of the stages then return that to the caller
02837     return (ok && RecordNumber > 0);
02838 }
02839 
02840 /********************************************************************************************
02841 
02842 >   void AttrFillGeometry::TransformSelectedControlPoints( TransformBase& Trans)
02843 
02844     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02845     Created:    23/8/94
02846     Inputs:     Trans - the transform object to apply to this attribute.
02847     Purpose:    Transform a grad fill attribute by moving the selected control points.
02848     SeeAlso:    NodeRenderable::Transform
02849 
02850 ********************************************************************************************/
02851 
02852 void AttrFillGeometry::TransformSelectedControlPoints( TransformBase& Trans, BOOL* isARampBlob /*= NULL*/)
02853 {
02854 #if !defined(EXCLUDE_FROM_RALPH)
02855     if ( Trans.TransFills )
02856     {
02857         ClickModifiers ClickMods; /* = ClickModifiers::GetClickModifiers();*/
02858         ClickMods.Adjust = TRUE;
02859 
02860         if (GetStartPoint() && IsSelected(FILLCONTROL_STARTPOINT))
02861         {
02862             DocCoord Pos = *GetStartPoint();
02863             Trans.Transform( &Pos, 1);
02864 
02865             FillControl Start = FILLCONTROL_STARTPOINT;
02866 
02867             OnControlDrag(Pos, Start, ClickMods);
02868         }
02869 
02870         if (GetEndPoint() && IsSelected(FILLCONTROL_ENDPOINT))
02871         {
02872             DocCoord Pos = *GetEndPoint();
02873             Trans.Transform( &Pos, 1);
02874 
02875             FillControl End = FILLCONTROL_ENDPOINT;
02876 
02877             OnControlDrag(Pos, End, ClickMods);
02878         }
02879 
02880         // CGS:  wo - check the fill ramp as well ....
02881 
02882         TransformSelectedFillRampControlPoints (Trans, ClickMods, isARampBlob);
02883     }
02884 #endif
02885 }
02886 
02887 
02888 
02889 /********************************************************************************************
02890 
02891 >   void AttrFillGeometry::TransformSelectedFillRampControlPoints (TransformBase& Trans, ClickModifiers ClickMods)
02892 
02893     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02894     Created:    26/10/2000
02895     Inputs:     Trans - the transform object to apply to this attribute.
02896                 ClickMods - click modifiers
02897     Purpose:    Transform a grad fill attributes fill ramp by moving the selected control points.
02898     SeeAlso:    AttrFillGeometry::TransformSelectedControlPoints
02899 
02900 ********************************************************************************************/
02901 void AttrFillGeometry::TransformSelectedFillRampControlPoints (TransformBase& Trans, ClickModifiers ClickMods, BOOL* isARampBlob)
02902 {
02903     if (GetFillRamp ())
02904     {
02905         // there is a fill ramp ....
02906 
02907         FillRamp* pRamp = GetFillRamp ();
02908 
02909         // NOTE:  the following code is written with the assumption
02910         // that there is ONLY EVER one blob selected.  If this restriction
02911         // is altered one-day, then the following code will need to be
02912         // revised ....
02913 
02914         if (pRamp->CountSelBlobs () > 0)
02915         {
02916             ERROR3IF (pRamp->CountSelBlobs () > 1, "More than one blob is selected! (extras will be ignored)");
02917 
02918             if (isARampBlob)
02919             {
02920                 *isARampBlob = TRUE;        // cause it is
02921             }
02922 
02923             // get the index of the first ....
02924 
02925             INT32 sel = pRamp->GetSelectedIndex ();
02926 
02927             DocCoord Pos = pRamp->GetGeometryCoord ((FillGeometryAttribute*) GetAttributeValue (), sel);
02928             Trans.Transform( &Pos, 1);
02929 
02930             FillControl control = sel;
02931 
02932             //DisableBoundsRedraw ();
02933             OnControlDrag(Pos, control, ClickMods);
02934             //EnableBoundsRedraw ();
02935         }
02936     }
02937 }
02938 
02939 
02940 
02941 /********************************************************************************************
02942 
02943 >   virtual void AttrFillGeometry::TransformToNewBounds(DocRect& NewBounds) 
02944 
02945     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02946     Created:    26/9/95
02947     Inputs:     The attributes new bounds. Usually the bounds of the object/s that the 
02948                 attribute will be applied to.
02949     Purpose:    Moves and scales the attribute's bounds to fit NewBounds. This function
02950                 is used when applying an attribute which has been stored (eg. as a Current
02951                 attribute) to a new object.
02952 
02953 ********************************************************************************************/
02954 
02955 void AttrFillGeometry::TransformToNewBounds(DocRect& NewBounds)
02956 {
02957 #if !defined(EXCLUDE_FROM_RALPH)
02958     // We are a funny fill thingy, so we better do some transforming
02959     DocRect AttrBounds = GetBoundingRect();
02960 
02961     // If we have valid Node and Attribute Bounds then make a transform
02962     // that is the scale and offset of the two rectangles.
02963     if (!NewBounds.IsEmpty() && !AttrBounds.IsEmpty())
02964     {
02965         // Get the Width and Height of the two rectangles
02966         INT32 NodeWidth  = NewBounds.Width();
02967         INT32 NodeHeight = NewBounds.Height();
02968         INT32 AttrWidth  = AttrBounds.Width();
02969         INT32 AttrHeight = AttrBounds.Height();
02970 
02971         // Find the Centre of each rectangle
02972         NewBounds.Translate(NodeWidth/2, NodeHeight/2);
02973         AttrBounds.Translate(AttrWidth/2, AttrHeight/2);
02974         DocCoord NodeCentre = NewBounds.lo;
02975         DocCoord AttrCentre = AttrBounds.lo;
02976 
02977         // And now make a transform for the attribute
02978         // First move the old attribute position to the origin
02979         Matrix AttrTrans = Matrix(-AttrCentre.x, -AttrCentre.y);
02980 
02981         // Don't scale for bitmap/fractal fills/transparency.
02982         if (!IS_KIND_OF(AttrBitmapFill))
02983         {
02984             // Calculate the difference in size between the two rectangles & scale accordingly.
02985             AttrTrans *= Matrix(FIXED16(double(NodeWidth) / double(AttrWidth)),
02986                                 FIXED16(double(NodeHeight) / double(AttrHeight)));
02987         }
02988 
02989         // And finally move it to the new position
02990         AttrTrans *= Matrix(NodeCentre.x, NodeCentre.y);
02991         Trans2DMatrix Trans = Trans2DMatrix(AttrTrans);
02992 
02993         // Go transform that Attribute !!
02994         Transform(Trans);
02995     }
02996 #endif
02997 }
02998 
02999 
03000 
03001 /********************************************************************************************
03002 
03003 >   BOOL AttrFillGeometry::CopyComponentData(BaseDocument* SrcDoc, BaseDocument* NodesDoc)
03004 
03005     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
03006     Created:    1/9/2000
03007     Inputs:     SrcDoc:   The document from where this node was copied
03008                 NodesDoc: The document where this node lives 
03009     Outputs:    -
03010     Returns:    FALSE if unable to copy data
03011     Purpose:    If the attribute contains any DocColours which are indexed then a copy
03012                 of the indexed colour is made and added to the NodesDoc
03013                 ColourListComponent.
03014     Errors:     -
03015     SeeAlso:    NodeRenderable::CopyComponentData, NodeAttribute::CopyComponentData
03016 
03017     NOTE:       The implementation of this function with NodeAttribute is very poor.
03018                 The code does NOT provide an oppurtunity for the colour ramp to be copied.
03019                 This overidden function fixes this problem, and provides a more robust implementatiom.
03020 
03021 ********************************************************************************************/
03022 
03023 BOOL AttrFillGeometry::CopyComponentData(BaseDocument* SrcDoc, BaseDocument* NodesDoc)
03024 {
03025     // Ask the base class to copy its data
03026     if (!NodeRenderable::CopyComponentData(SrcDoc, NodesDoc))
03027     {
03028         return FALSE; // Failed
03029     }
03030     // Get the colour list component
03031     ColourListComponent *pComponent = 
03032         (ColourListComponent *) NodesDoc->GetDocComponent(CC_RUNTIME_CLASS(ColourListComponent));
03033 
03034     ENSURE (pComponent != NULL, "Could not find ColourListComponent");
03035 
03036     // Copy across all DocColours
03037     
03038     DocColour* pDocCol = GetStartColour ();
03039     if (pDocCol) if (pComponent->CopyColourAcross(pDocCol) == CCCOPY_FAILED) { return (FALSE); }
03040     pDocCol = GetEndColour ();
03041     if (pDocCol) if (pComponent->CopyColourAcross(pDocCol) == CCCOPY_FAILED) { return (FALSE); }        
03042     pDocCol = GetEndColour2 ();
03043     if (pDocCol) if (pComponent->CopyColourAcross(pDocCol) == CCCOPY_FAILED) { return (FALSE); }
03044     pDocCol = GetEndColour3 ();
03045     if (pDocCol) if (pComponent->CopyColourAcross(pDocCol) == CCCOPY_FAILED) { return (FALSE); }
03046 
03047     ColourRamp *pRamp = GetColourRamp();
03048 
03049     if (pRamp)
03050     {
03051         return (pRamp->CopyComponentData (SrcDoc, NodesDoc));
03052     }
03053 
03054     return (TRUE);
03055 }
03056 
03057 /********************************************************************************************
03058 
03059 >   virtual DocRect AttrFillGeometry::GetBlobBoundingRect()
03060 
03061     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03062     Created:    28/7/94
03063     Returns:    DocRect - The rectangle that contains all the attrs selection blobs.
03064     Purpose:    Calculates the bounding rectangle of the attrs blobs.This should always 
03065                 be calculated on the fly as the view scale can change without the attr 
03066                 knowing, giving an incorrect result.
03067 
03068 ********************************************************************************************/
03069 
03070 DocRect AttrFillGeometry::GetBlobBoundingRect()
03071 {
03072 #if !defined(EXCLUDE_FROM_RALPH)
03073     // Optimisation.  If there is currently no interest in Fill Blobs
03074     // and this fill is not being Dragged (Fill blobs are turned off during
03075     // a fill drag), then we needn't bother doing anything. 
03076     if ( (!GetApplication()->GetBlobManager()->GetCurrentInterest(TRUE).Fill || !IsVisible()) && DraggedFill != this )
03077         return DocRect(0,0, 0,0);
03078 
03079     DocCoord StartPoint = DocCoord(0,0);
03080     DocCoord EndPoint = DocCoord(0,0);
03081 
03082     // Get the Start and End Points
03083     if (GetStartPoint() != NULL)
03084         StartPoint = *GetStartPoint();
03085     if (GetEndPoint() != NULL)
03086         EndPoint = *GetEndPoint();
03087 
03088     DocRect StartBlobRect;
03089     DocRect EndBlobRect;
03090     // Make a dummy bounds from just the Start Point
03091     DocRect BoundingRect(StartPoint, StartPoint);
03092 
03093     // Get the Bounding rect of Blobs on each of the ends
03094     (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &StartBlobRect);
03095     (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &EndBlobRect);
03096 
03097     // Now include the Bottom Left and Top Right of each blob in the Bounds.
03098     // We have to do it like this to make sure that the DocRect's coords
03099     // are valid.  ie. The Hi's are Higher than the Lo's.
03100     BoundingRect.IncludePoint(StartBlobRect.lo);
03101     BoundingRect.IncludePoint(StartBlobRect.hi);
03102     BoundingRect.IncludePoint(EndBlobRect.lo);
03103     BoundingRect.IncludePoint(EndBlobRect.hi);
03104 
03105     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint);
03106 
03107     // and return it
03108     return BoundingRect;
03109 #else
03110     return DocRect(0,0, 0,0);
03111 #endif
03112 }
03113 
03114 /********************************************************************************************
03115 
03116 >   AttrFillGeometry::AttributeChanged()
03117 
03118     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03119     Created:    25/07/94
03120     Purpose:    Called by someone who has changed something about us that it thinks
03121                 we should know about.  It used by the Attribute manager to make a
03122                 current attribute validate itself after it has been added to a new
03123                 object.
03124                 This functions just calls 'ValidateAttributeValue'.
03125     SeeAlso:    AttrFillGeometry::ValidateAttributeValue
03126 
03127 ********************************************************************************************/
03128 
03129 void AttrFillGeometry::AttributeChanged()
03130 {
03131     ValidateAttributeValue();
03132 }
03133 
03134 /********************************************************************************************
03135 
03136 >   AttrFillGeometry* AttrFillGeometry::Mutate(AttrFillGeometry* Mutator, BOOL bOptimise = TRUE)
03137 
03138     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03139     Created:    12/8/94
03140     Inputs:     Mutator, The AttrFillGeometry Mutator that will change this fill in some way.
03141     Returns:    A pointer to a new AttrFillGeometry, that is a Mutated version of this Fill. 
03142     Purpose:    Changes a fill in some way.
03143 
03144                 If the Mutator is an 'AttrValueChange' then the fill will attempt to change
03145                 any selected control points to be the colour of the Mutator.  If sucessful
03146                 (ie. points were selected) then it returns a Pointer to a copy of itself
03147                 with the mutators colours. If no points are selected anywhere in either
03148                 this fill or any others in the selection then the Fill will return a pointer 
03149                 to an 'AttrFlatColourFill' with the colours set to the Mutants.
03150 
03151                 If the Mutator is NOT an 'AttrValueChange' then the fill will return a pointer
03152                 to a fill of the same type as the Mutator, but with the fills own control
03153                 points and colours.
03154 
03155     SeeAlso:    AttributeManager::AttributeSelected
03156 
03157 ********************************************************************************************/
03158 
03159 AttrFillGeometry* AttrFillGeometry::Mutate(AttrFillGeometry* Mutator, BOOL bOptimise)
03160 {
03161     AttrFillGeometry* NewFill = NULL;
03162 #if !defined(EXCLUDE_FROM_RALPH)
03163 
03164 //  SelectionCount = CountSelectionControlPoints();
03165 
03166     // Is it a Value Change mutator ?
03167     // and if so does the type match this attribute ?
03168     if ( Mutator->IsAValueChange() &&
03169          Mutator->GetAttributeType() == GetAttributeType() )
03170     {
03171         // We need to change this attribute in some way, depending on the
03172         // mutator.  It knows what it wants to do, so we will ask it to
03173         // mutate 'this', and it will return a mutated copy
03174         NewFill = ((AttrValueChange*)Mutator)->MutateFill(this);
03175         if (NewFill == NULL)
03176             return NULL;
03177     }
03178     else
03179     {
03180         // It must be a 'Geometry change'
03181         // We will change this fill into another different type of fill,
03182         // but retain our control points and colours etc.
03183 
03184         if (IsPerspective() && 
03185            (Mutator->GetRuntimeClass() != GetRuntimeClass()))
03186             return NULL;        // Can't mutate to a different fill when perspectivised
03187 
03188         // Make new fill with the same type as the Mutant
03189         CCRuntimeClass* ObjectType = Mutator->GetRuntimeClass();
03190         NewFill = (AttrFillGeometry*)ObjectType->CreateObject();
03191         if (NewFill == NULL)
03192             return NULL;
03193 
03194         // Copy the Attribute Bounds (used for Current Attributes)
03195         NewFill->AttrBounds = AttrBounds;
03196 
03197         // and copy our Values into it into the new fill
03198         *((FillGeometryAttribute*)NewFill->GetAttributeValue()) = *((FillGeometryAttribute*)this->GetAttributeValue());
03199 
03200         if ((!NewFill->IsABitmapFill() || NewFill->IsAFractalFill()) &&
03201             FindParent() != NULL && FindParent()->IsNodeDocument())
03202         {
03203             // If it's the default Fill attr, then we need to use Blank instead
03204             // of the default fill colour of 'None'
03205             DocColour DefFillCol;
03206             AttributeManager::FindDefaultColour(ColourManager::GetCurrentColourList(),
03207                                                 _R(IDS_BLACKNAME), &DefFillCol);
03208             if (NewFill->IsAFlatFill())
03209                 NewFill->SetStartColour(&DefFillCol);
03210             else
03211                 NewFill->SetEndColour(&DefFillCol);
03212         }
03213 
03214         // Ensure any aspect lock is taken from the mutator
03215         ((FillGeometryAttribute*)NewFill->GetAttributeValue())->
03216             SetAspectLock(((FillGeometryAttribute*)Mutator->GetAttributeValue())->IsAspectLocked());
03217 
03218         // Ensure our profile type is retained (i.e.  NOT taken from the mutator)
03219         ((FillGeometryAttribute*)NewFill->GetAttributeValue())->
03220             SetProfile(((FillGeometryAttribute*)this->GetAttributeValue())->GetProfile());
03221 
03222         // Ensure our transparency type is retained (ie. NOT taken from the mutator)
03223         ((FillGeometryAttribute*)NewFill->GetAttributeValue())->
03224             SetTranspType(((FillGeometryAttribute*)this->GetAttributeValue())->GetTranspType());
03225 
03226         // Check if we're mutating a fractal into a something
03227         if (this->IsAFractalFill() && Mutator->IsAFractalFill())
03228         {
03229             // if so then retain its graininess
03230             ((FillGeometryAttribute*)NewFill->GetAttributeValue())->
03231                 SetGraininess(((FillGeometryAttribute*)this->GetAttributeValue())->GetGraininess());
03232         }
03233 
03234         if (!OpEditFill::CreateFill)
03235         {
03236             if (Mutator->GetBitmap() == NULL && !this->IsAFractalFill())
03237             {
03238                 // No bitmap has been specified in the mutator, 
03239                 // so lets make a default one
03240                 NewFill->CopyBitmap(KernelBitmap::MakeKernelBitmap());
03241             }
03242             else
03243             {
03244                 // Copy the bitmap from the mutator into the new fill
03245                 NewFill->CopyBitmap(Mutator->GetBitmap());
03246             }
03247 
03248             // Get the fractal seed from the Mutator, so we create a new random fractal
03249             ((FillGeometryAttribute*)NewFill->GetAttributeValue())->
03250                 SetSeed(((FillGeometryAttribute*)Mutator->GetAttributeValue())->GetSeed());
03251 
03252             NewFill->RecalcFractal();
03253         }
03254         else
03255         {
03256             NewFill->SetStartPoint(Mutator->GetStartPoint());
03257             NewFill->SetEndPoint(Mutator->GetEndPoint());
03258             NewFill->SetEndPoint2(Mutator->GetEndPoint2());
03259         }
03260 
03261 /*
03262         if (Mutator->GetBitmap() &&
03263             !BfxALU::IsGreyscaleBitmap(Mutator->GetBitmap()))
03264         {
03265             // The new bitmap is not Greyscale, so make sure we
03266             // lose any contone colours
03267             
03268             NewFill->SetStartColour(NULL);
03269             NewFill->SetEndColour(NULL);
03270         }
03271 */
03272 
03273         NewFill->SetBlobState(FILLCONTROL_ENDPOINT, TRUE);
03274 
03275         // Update the mutator's tileable flag, so it can set the
03276         // fill mapping correctly, when the secondary attribute
03277         // is obtained
03278         Mutator->SetTileable(NewFill->GetTileable());
03279     }
03280 
03281     // If the resulting attribute in the tree is the same as the mutator
03282     // Then don't return anything so that the caller knows not to write undo
03283     // info
03284     // BUT: If we're applying an attribute in the knowledge that it will later
03285     // get re-applied many times then we should really apply it, ignoring this
03286     // optimisation
03287     if (NewFill != NULL && *NewFill == *this && bOptimise)
03288     {
03289         // If the mutated fill is the same, then forget about it.
03290         delete NewFill;
03291         return NULL;
03292     }
03293 
03294 #endif
03295     // Return the Mutated Fill
03296     return NewFill;
03297 }
03298 
03299 /********************************************************************************************
03300 
03301 >   AttrFillGeometry* AttrFillGeometry::ChangeColour(AttrValueChange* Mutator)
03302 
03303     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03304     Created:    12/8/94
03305     Inputs:     Mutator, The AttrFillGeometry Mutator that will change this fill in some way.
03306     Returns:    A pointer to a new AttrFillGeometry, that is a Mutated version of this Fill. 
03307     Purpose:    Changes a fill in some way.
03308     SeeAlso:    AttributeManager::AttributeSelected
03309 
03310 ********************************************************************************************/
03311 
03312 AttrFillGeometry* AttrFillGeometry::ChangeColour(AttrValueChange* Mutator)
03313 {
03314     AttrFillGeometry* NewFill = NULL;
03315 
03316 #if !defined(EXCLUDE_FROM_RALPH)
03317     // Make a copy of this Fill and change the copys' control point colours
03318     NewFill = (AttrFillGeometry*)this->SimpleCopy();
03319     if (NewFill == NULL)
03320         return NULL;
03321 
03322     if (Mutator->MutateFill(NewFill))
03323         return NewFill;
03324 
03325     BOOL Changed = NewFill->ChangeControlColour( (AttrColourChange*)Mutator );
03326 
03327     // Did we change any colours ?
03328     if (!Changed)
03329     {
03330         // Only make it a flat fill if there aren't any other fill controls
03331         // selected anywhere else
03332         if (IsVisible() && SelectionCount > 0)
03333             return NewFill;
03334 
03335         // No Control points selected, so make a flat fill instead
03336         delete NewFill;
03337         NewFill = new AttrFlatColourFill;
03338         if (NewFill == NULL)
03339             return NULL;
03340 
03341         // and use the mutants colour
03342         *(FillGeometryAttribute*)(NewFill->GetAttributeValue()) = *(FillGeometryAttribute*)(Mutator->GetAttributeValue());
03343 
03344         if (GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && IsVisible())
03345             RenderFillBlobs();
03346     }
03347 #endif
03348 
03349     // Return the Mutated Fill
03350     return NewFill;
03351 }
03352 
03353 
03354 /********************************************************************************************
03355 
03356 >   AttrFillGeometry* AttrFillGeometry::ChangeTransp(AttrValueChange* Mutator)
03357 
03358     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03359     Created:    12/8/94
03360     Inputs:     Mutator, The AttrFillGeometry Mutator that will change this fill in some way.
03361     Returns:    A pointer to a new AttrFillGeometry, that is a Mutated version of this Fill. 
03362     Purpose:    Changes a fill in some way.
03363     SeeAlso:    AttributeManager::AttributeSelected
03364 
03365 ********************************************************************************************/
03366 
03367 AttrFillGeometry* AttrFillGeometry::ChangeTransp(AttrValueChange* Mutator)
03368 {
03369     AttrFillGeometry* NewFill = NULL;
03370 
03371 #if !defined(EXCLUDE_FROM_RALPH)
03372     // Make a copy of this Fill and change the copys' control point colours
03373     NewFill = (AttrFillGeometry*)this->SimpleCopy();
03374     if (NewFill == NULL)
03375         return NULL;
03376 
03377     if (Mutator->MutateFill(NewFill))
03378         return NewFill;
03379 
03380     BOOL Changed = NewFill->ChangeControlTransp( (AttrTranspChange*)Mutator );
03381 
03382     // Did we change any colours ?
03383     if (!Changed)
03384     {
03385         // Only make it a flat fill if there aren't any other fill controls
03386         // selected anywhere else
03387         if (IsVisible() && SelectionCount > 0)
03388             return NewFill;
03389 
03390         // No Control points selected, so make a flat fill instead
03391         delete NewFill;
03392         NewFill = new AttrFlatTranspFill;
03393         if (NewFill == NULL)
03394             return NULL;
03395 
03396         // and use the mutants colour
03397         *(FillGeometryAttribute*)(NewFill->GetAttributeValue()) = *(FillGeometryAttribute*)(Mutator->GetAttributeValue());
03398 
03399         NewFill->SetTranspType(GetTranspType());
03400 
03401         if (GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && IsVisible())
03402             RenderFillBlobs();
03403     }
03404 #endif
03405 
03406     // Return the Mutated Fill
03407     return NewFill;
03408 }
03409 
03410 /********************************************************************************************
03411 
03412 >   BOOL AttrFillGeometry::ChangeControlColour( AttrColourChange* ColourAttr )
03413 
03414     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03415     Created:    2/9/94
03416     Inputs:     NewColour, the colour that selected control points should change to.
03417     Returns:    TRUE if a control point was selected, and the colour applied.
03418     Purpose:    Applies a colour to selected Fill Control Points.
03419     SeeAlso:    AttrFillGeometry::Mutate
03420 
03421 ********************************************************************************************/
03422 
03423 BOOL AttrFillGeometry::ChangeControlColour( AttrColourChange* ColourAttr )
03424 {
03425 #if !defined(EXCLUDE_FROM_RALPH)
03426     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
03427         return FALSE;
03428 
03429     BOOL ColChanged = FALSE;
03430 
03431     DocColour NewColour = *ColourAttr->GetStartColour();
03432 
03433     // Is the Start Point Selected ?
03434     if (SelectionState[FILLCONTROL_STARTPOINT] /*&& GetStartColour() != NULL*/)
03435     {
03436         // Set the Start Colour
03437         SetStartColour(&NewColour);
03438         ColChanged = TRUE;
03439     }
03440 
03441     // Is the End Point Selected ?
03442     if (SelectionState[FILLCONTROL_ENDPOINT] /*&& GetEndColour() != NULL*/)
03443     {
03444         // Set the End Colour
03445         SetEndColour(&NewColour);
03446         ColChanged = TRUE;
03447     }
03448 
03449     // Is the End Point Selected ?
03450     if (SelectionState[FILLCONTROL_ENDPOINT2] /*&& GetEndColour2() != NULL*/)
03451     {
03452         // Set the End Colour
03453         SetEndColour2(&NewColour);
03454         ColChanged = TRUE;
03455     }
03456 
03457     // Is End Point 3 Selected ?
03458     if (SelectionState[FILLCONTROL_ENDPOINT3] /*&& GetEndColour3() != NULL*/)
03459     {
03460         // Set the Colour
03461         SetEndColour3(&NewColour);
03462         ColChanged = TRUE;
03463     }
03464 
03465     // set any selected colours in the colour ramp?
03466     ColourRamp *pRamp = GetColourRamp();
03467     if (pRamp)
03468     {
03469         // we have a ramp here so set its colours
03470         if (pRamp->SetSelectedColours(&NewColour)>0)
03471             ColChanged=TRUE;
03472     }
03473 
03474     // Tell the caller whether we changed anything or not
03475     return (ColChanged);
03476 #else
03477     return FALSE;
03478 #endif
03479 }
03480 
03481 /********************************************************************************************
03482 
03483 >   BOOL AttrFillGeometry::ChangeControlTransp( AttrTranspChange* TranspAttr )
03484 
03485     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03486     Created:    2/9/94
03487     Inputs:     NewColour, the colour that selected control points should change to.
03488     Returns:    TRUE if a control point was selected, and the colour applied.
03489     Purpose:    Applies a colour to selected Fill Control Points.
03490     SeeAlso:    AttrFillGeometry::Mutate
03491 
03492 ********************************************************************************************/
03493 
03494 BOOL AttrFillGeometry::ChangeControlTransp( AttrTranspChange* TranspAttr )
03495 {
03496 #if !defined(EXCLUDE_FROM_RALPH)
03497     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
03498         return FALSE;
03499 
03500     if (GetStartTransp() == NULL)
03501         return FALSE;
03502 
03503     BOOL TranspChanged = FALSE;
03504 
03505     // Get the required new transparency
03506     UINT32 NewTransp = *TranspAttr->GetStartTransp();
03507 
03508     // Is the Start Point Selected ?
03509     if (SelectionState[FILLCONTROL_STARTPOINT])
03510     {
03511         // Set the Start Transp
03512         SetStartTransp(&NewTransp);
03513         TranspChanged = TRUE;
03514     }
03515 
03516     // Is the End Point Selected ?
03517     if (SelectionState[FILLCONTROL_ENDPOINT])
03518     {
03519         // Set the End Transp
03520         SetEndTransp(&NewTransp);
03521         TranspChanged = TRUE;
03522     }
03523 
03524     // Is the End Point Selected ?
03525     if (SelectionState[FILLCONTROL_ENDPOINT2])
03526     {
03527         // Set the End Transp
03528         SetEndTransp2(&NewTransp);
03529         TranspChanged = TRUE;
03530     }
03531 
03532     // Is the End Point Selected ?
03533     if (SelectionState[FILLCONTROL_ENDPOINT3])
03534     {
03535         // Set the End Transp
03536         SetEndTransp3(&NewTransp);
03537         TranspChanged = TRUE;
03538     }
03539 
03540     // set any selected colours in the colour ramp?
03541     TransparencyRamp *pRamp = GetTranspRamp();
03542     if (pRamp)
03543     {
03544         // we have a ramp here so set its colours
03545         if (pRamp->SetSelectedTransp(NewTransp)>0)
03546             TranspChanged=TRUE;
03547     }
03548 
03549     // Tell the caller whether we changed anything or not
03550     return TranspChanged;
03551 #else
03552     return FALSE;
03553 #endif
03554 }
03555 
03556 
03557 /********************************************************************************************
03558 
03559 >   virtual BOOL AttrFillGeometry::EditColourFillRamp( AttrColFillRampChange *pRampAttr )
03560 
03561     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
03562     Created:    12/3/97
03563     Inputs:     pRampAttr = a pointer to the ramp change attribute
03564     Returns:    TRUE if the change has been made, FALSE if not
03565     Purpose:    Applies a ramp change to this fill. See the class AttrColFillRampChange for
03566                 all the documentation on this
03567 
03568 ********************************************************************************************/
03569 
03570 BOOL AttrFillGeometry::EditColourFillRamp( AttrColFillRampChange *pRampAttr )
03571 {
03572 #if !defined(EXCLUDE_FROM_RALPH)
03573     // ok we've been called to alter the fill ramp in this attribute
03574     // there are three things we can do
03575     if (pRampAttr==NULL)
03576         return FALSE;
03577         
03578     BOOL Changed = FALSE;
03579     ColourRamp *pCRamp;
03580 
03581     switch (pRampAttr->GetAction())
03582     {
03583         case ACT_DONOTHING:
03584             // well lets do nothing then. Aw go on we've gotta do something!
03585             ERROR3("Someone's forgotten to set the edit action of the RampChange attr");
03586             break;
03587 
03588         case ACT_CREATENEWCOL:
03589         {
03590             pCRamp = GetColourRamp();
03591             if (!pCRamp)
03592             {
03593                 FillGeometryAttribute *pAttrValue = ATTRVALUE();
03594                 if (pAttrValue->SupportsFillRamps())
03595                 {
03596                     if (pAttrValue->IS_KIND_OF(GradFillAttribute))
03597                     {
03598                         pCRamp = ((GradFillAttribute*)pAttrValue)->MakeNewColourRamp();
03599                     }
03600                 }
03601             }
03602             
03603             if (pCRamp)
03604             {
03605                 ColRampItem *pItem;
03606                 pItem = pCRamp->AddEntry(pRampAttr->GetPosition(), pRampAttr->GetStartColour());
03607                 Changed=(pItem!=NULL);
03608             }
03609         }
03610         break;
03611 
03612         case ACT_EDITCOLOFITEM:
03613             pCRamp = GetColourRamp();
03614             if (pCRamp)
03615             {
03616                 Changed = pCRamp->SetItemColour(pRampAttr->GetIndex(), pRampAttr->GetStartColour());
03617             }
03618             break;
03619 
03620         case ACT_EDITCOLOFSELECTED:
03621             pCRamp = GetColourRamp();
03622             if (pCRamp)
03623             {
03624                 Changed = (pCRamp->SetSelectedColours(pRampAttr->GetStartColour()))>0;
03625                 Changed=TRUE;
03626             }
03627             break;
03628 
03629         default:
03630             ERROR3("Unknown action found during AttrFillGeometry::EditColFillRamp");
03631             break;
03632     }
03633 
03634     return Changed;
03635 #else
03636     return FALSE;
03637 #endif
03638 }
03639 
03640 
03641 
03642 /********************************************************************************************
03643 
03644 >   BOOL AttrFillGeometry::EditTranspFillRamp( AttrTranspFillRampChange *pRampAttr )
03645 
03646     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
03647     Created:    12/3/97
03648     Inputs:     pRampAttr = a pointer to the ramp change attribute
03649     Returns:    TRUE if the change has been made, FALSE if not
03650     Purpose:    Applies a ramp change to this fill. See the class AttrTranspFillRampChange for
03651                 all the documentation on this
03652 
03653 ********************************************************************************************/
03654 
03655 BOOL AttrFillGeometry::EditTranspFillRamp( AttrTranspFillRampChange *pRampAttr )
03656 {
03657 #if !defined(EXCLUDE_FROM_RALPH)
03658     // ok we've been called to alter the fill ramp in this attribute
03659     // there are three things we can do
03660     if (pRampAttr==NULL)
03661         return FALSE;
03662         
03663     BOOL Changed = FALSE;
03664     TransparencyRamp *pTRamp;
03665 
03666     UINT32 t, *pt = pRampAttr->GetStartTransp();
03667     t = ((pt!=NULL) ? (*pt) : 128);
03668     
03669     switch (pRampAttr->GetAction())
03670     {
03671         case ACT_DONOTHING:
03672             // well lets do nothing then. Aw go on we've gotta do something!
03673             ERROR3("Someone's forgotten to set the edit action of the RampChange attr");
03674             break;
03675 
03676         case ACT_CREATENEWTRANSP:
03677         {
03678             pTRamp = GetTranspRamp();
03679             if (!pTRamp)
03680             {
03681                 FillGeometryAttribute *pAttrValue = ATTRVALUE();
03682                 if (pAttrValue->SupportsFillRamps())
03683                 {
03684                     if (pAttrValue->IS_KIND_OF(GradTranspFillAttribute))
03685                     {
03686                         pTRamp = ((GradTranspFillAttribute*)pAttrValue)->MakeNewTranspRamp();
03687                     }
03688                 }
03689             }
03690             if (pTRamp)
03691             {
03692                 TranspRampItem *pItem;
03693                 pItem = pTRamp->AddEntry(pRampAttr->GetPosition(), t);
03694                 Changed=(pItem!=NULL);
03695             }
03696         }
03697         break;
03698 
03699         case ACT_EDITTRANSPOFITEM:
03700             pTRamp = GetTranspRamp();
03701             if (pTRamp)
03702             {
03703                 Changed = pTRamp->SetItemTransp(pRampAttr->GetIndex(), t);
03704             }
03705             break;
03706 
03707         case ACT_EDITTRANSPOFSELECTED:
03708             pTRamp = GetTranspRamp();
03709             if (pTRamp)
03710             {
03711                 Changed = (pTRamp->SetSelectedTransp(t))>0;
03712             }
03713             break;
03714         
03715         default:
03716             ERROR3("Unknown action found during AttrFillGeometry::EditTranspFillRamp");
03717             break;
03718     }
03719 
03720     return Changed;
03721 #else
03722     return FALSE;
03723 #endif
03724 }
03725 
03726 
03727 /********************************************************************************************
03728 
03729 >   DocColour *AttrFillGeometry::EnumerateColourFields(UINT32 Context)
03730 
03731     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>    (fixed by Chris Snook to make this thing do what it aught to)
03732     Created:    23/8/94 (CGS:  27/4/2001)
03733     Purpose:    See base class.
03734     SeeAlso:    NodeAttribute::EnumerateColourFields
03735 
03736 ********************************************************************************************/
03737 
03738 DocColour *AttrFillGeometry::EnumerateColourFields(UINT32 Context)
03739 {
03740 #if !defined(EXCLUDE_FROM_RALPH)
03741     // Work out which colour to return.
03742 
03743     DocColour * pColour = NULL;
03744             
03745     switch (Context)
03746     {
03747         case 0:
03748             pColour = GetStartColour();
03749         break;
03750 
03751         case 1:
03752             pColour = GetEndColour();
03753         break;
03754 
03755         case 2:
03756             pColour = GetEndColour2();
03757         break;
03758 
03759         case 3:
03760             pColour = GetEndColour3();
03761         break;
03762     }
03763 
03764     if (pColour)
03765     {
03766         // was a valid index - just return the pointer to the colour
03767         return (pColour);
03768     }
03769     else
03770     {
03771         // it was out of range, but we still need to check the fillramp ....
03772 
03773         ColourRamp *pRamp = GetColourRamp();
03774 
03775         INT32 adjuster = 0;     // we need to adjust the offset into the fillramp
03776 
03777         // the following four lines of code always get the correct (zero-based) index ....
03778         if (GetStartColour()) { adjuster++; }
03779         if (GetEndColour())   { adjuster++; }
03780         if (GetEndColour2())  { adjuster++; }
03781         if (GetEndColour3())  { adjuster++; }
03782 
03783         if (pRamp)
03784         {
03785             // nab it from the ramp ....
03786             return (pRamp->EnumerateColourFields(Context-adjuster));
03787         }
03788         // um, drop through and return NULL
03789     }
03790 
03791 #endif
03792     // No more colours.
03793     return NULL;
03794 }
03795 
03796 
03797 
03798 
03799 void AttrFillGeometry::MakePerspective(UndoableOperation* pUndoOp) 
03800 { 
03801     ((FillGeometryAttribute*)GetAttributeValue())->MakePerspective(); 
03802 }
03803 
03804 void AttrFillGeometry::RemovePerspective(UndoableOperation* pUndoOp) 
03805 { 
03806     if (IsPerspective() && pUndoOp != NULL)
03807     {
03808         Node* pParent = FindParent();
03809         if (pParent == NULL)
03810             return;
03811 
03812         AttrFillGeometry* AttribClone;
03813 
03814         ALLOC_WITH_FAIL(AttribClone ,(AttrFillGeometry*)this->SimpleCopy(), pUndoOp)
03815         if (AttribClone == NULL)
03816             return;
03817         
03818         AttribClone->RemovePerspective();
03819 
03820         HideNodeAction* UndoHideNodeAction; 
03821         NodeHidden* pNodeHidden; 
03822         if(!pUndoOp->DoHideNode(this, FALSE, &pNodeHidden,FALSE))
03823             return;                
03824 
03825         AttribClone->AttachNode(pParent, FIRSTCHILD); 
03826 
03827         // Create an action to hide the attribute when we undo 
03828         if ( HideNodeAction::Init(pUndoOp, 
03829                                   pUndoOp->GetUndoActionList(),
03830                                   AttribClone, 
03831                                   TRUE,             // When the attribute gets hidden we
03832                                                     // must include its size 
03833                                  (Action**)(&UndoHideNodeAction))
03834              == AC_FAIL)  
03835         {   
03836             AttribClone->CascadeDelete();       
03837             delete (AttribClone); 
03838             return;  
03839         };
03840     }
03841     else
03842     {
03843         ((FillGeometryAttribute*)GetAttributeValue())->RemovePerspective(); 
03844     }
03845 }
03846 
03847 
03848 
03850 //
03851 //                              AttrValueChange
03852 //
03854 
03855 /********************************************************************************************
03856 
03857 >   AttrValueChange::AttrValueChange()
03858 
03859     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03860     Created:    13/12/94
03861     Purpose:    Constructor for an attribute value change.
03862 
03863 ********************************************************************************************/
03864 
03865 AttrValueChange::AttrValueChange()
03866 {
03867     Colour = TRUE;
03868     Transp = !Colour;
03869 }
03870 
03871 /********************************************************************************************
03872 
03873 >   CCRuntimeClass* AttrValueChange::GetAttributeType()
03874 
03875     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03876     Created:    13/12/94
03877     Returns:    A CC_RUNTIME_CLASS depending on whether this should change colour
03878                 or transparency attribute.
03879     Purpose:    Determines the scope of the value change.
03880 
03881 ********************************************************************************************/
03882 
03883 CCRuntimeClass* AttrValueChange::GetAttributeType()
03884 { 
03885     if (Colour)
03886         return CC_RUNTIME_CLASS(AttrFillGeometry); 
03887     else
03888         return CC_RUNTIME_CLASS(AttrTranspFillGeometry); 
03889 }
03890 
03891 /********************************************************************************************
03892 
03893 >   void AttrValueChange::MutateColourFills(BOOL Change) 
03894 
03895     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03896     Created:    13/12/94
03897     Purpose:    Changes the effect of this value change on colour fills.
03898 
03899 ********************************************************************************************/
03900 
03901 void AttrValueChange::MutateColourFills(BOOL Change) 
03902 { 
03903     Colour = Change;
03904     Transp = !Colour;
03905 }
03906 
03907 /********************************************************************************************
03908 
03909 >   void AttrValueChange::MutateColourFills(BOOL Change) 
03910 
03911     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03912     Created:    13/12/94
03913     Purpose:    Changes the effect of this value change on Transparency fills.
03914 
03915 ********************************************************************************************/
03916 
03917 void AttrValueChange::MutateTranspFills(BOOL Change)
03918 { 
03919     Transp = Change;
03920     Colour = !Transp;
03921 }
03922 
03923 /********************************************************************************************
03924 
03925 >   AttrTranspChange::AttrTranspChange()
03926 
03927     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03928     Created:    13/12/94
03929     Purpose:    Constructor for an attribute value change.
03930 
03931 ********************************************************************************************/
03932 
03933 AttrTranspChange::AttrTranspChange()
03934 {
03935     Transp = TRUE;
03936     Colour = !Transp;
03937 }
03938 
03939 /********************************************************************************************
03940 
03941 >   virtual NodeAttribute* AttrTranspChange::GetOtherAttrToApply(BOOL* IsMutate)
03942 
03943     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03944     Created:    17/8/95
03945     Returns:    The secondary attribute to apply, or NULL if none to apply
03946     Purpose:    Some attributes require a secondary atribute to be changed when they are
03947                 changed.  This routine obtains a pointer to the secondary attribute to
03948                 apply.
03949 
03950 ********************************************************************************************/
03951 
03952 NodeAttribute* AttrTranspChange::GetOtherAttrToApply(BOOL* IsMutate)
03953 {
03954     ERROR3IF(IsMutate == NULL, "NULL flag pointer passed to GetOtherAttrToApply");
03955 
03956     // A transparency change also needs to set the Stroke Transparency
03957 
03958     if (AttrFillGeometry::FillSelectionCount() > 0)
03959         return NULL;    // Only set line transparency if no control
03960                         // points are selected
03961 
03962     NodeAttribute* OtherAttr = new AttrStrokeTranspChange;
03963     if (OtherAttr == NULL)
03964         return NULL;
03965 
03966     UINT32 Transp = *GetStartTransp();
03967 
03968     ((AttrStrokeTranspChange *)OtherAttr)->SetStartTransp(&Transp);
03969 
03970     *IsMutate = TRUE;
03971 
03972     return OtherAttr;
03973 }
03974 
03975 /********************************************************************************************
03976 
03977 >   AttrFillGeometry* AttrColourChange::MutateFill(AttrFillGeometry* FillToMutate) 
03978 
03979     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03980     Created:    13/12/94
03981     Inputs:     The fill that is to be changed.
03982     Purpose:    Changes the colour of a fill.
03983 
03984 ********************************************************************************************/
03985 
03986 AttrFillGeometry* AttrColourChange::MutateFill(AttrFillGeometry* FillToMutate) 
03987 { 
03988 #if !defined(EXCLUDE_FROM_RALPH)
03989     if (FillToMutate->IsVisible() && 
03990         FillToMutate->GetSelectionCount() == 0 &&
03991         SelectionCount > 0)
03992         return NULL;
03993 
03994     // Make a copy of this Fill to change
03995     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
03996     if (NewFill == NULL)
03997         return NULL;
03998 
03999     BOOL Changed = NewFill->ChangeControlColour(this);
04000 
04001     // Did we change any colours ?
04002     if (!Changed)
04003     {
04004         if (NewFill->IsABitmapFill() &&
04005             NewFill->GetSelectionCount() > 0)
04006         {
04007             if (GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && IsVisible())
04008             {
04009                 // We must have failed when trying to set a contone colour,
04010                 // so we'll do nothing
04011 
04012                 delete NewFill;
04013                 return NULL;
04014             }
04015         }
04016 
04017         // No Control points selected, so make a flat fill instead
04018         delete NewFill;
04019 
04020         NewFill = new AttrFlatColourFill;
04021         if (NewFill == NULL)
04022             return NULL;
04023 
04024         // and use the mutants colour
04025         *(FillGeometryAttribute*)(NewFill->GetAttributeValue()) = *(FillGeometryAttribute*)(this->GetAttributeValue());
04026 
04027         if (GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && 
04028             FillToMutate->IsVisible() &&
04029             FillToMutate->FindParent() &&
04030             FillToMutate->FindParent()->IsSelected())
04031         {
04032             FillToMutate->RenderFillBlobs();
04033         }
04034     }
04035     // Return the Mutated Fill
04036     return NewFill;
04037 #else
04038     return NULL;
04039 #endif
04040 }
04041 
04042 /********************************************************************************************
04043 
04044 >   AttrFillGeometry* AttrTranspChange::MutateFill(AttrFillGeometry* FillToMutate) 
04045 
04046     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04047     Created:    13/12/94
04048     Inputs:     The fill that is to be changed.
04049     Purpose:    Changes the colour of a fill.
04050 
04051 ********************************************************************************************/
04052 
04053 AttrFillGeometry* AttrTranspChange::MutateFill(AttrFillGeometry* FillToMutate) 
04054 { 
04055 #if !defined(EXCLUDE_FROM_RALPH)
04056     if (FillToMutate->IsVisible() && 
04057         FillToMutate->GetSelectionCount() == 0 &&
04058         SelectionCount > 0)
04059         return NULL;
04060 
04061     // Make a copy of this Fill to change
04062     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04063     if (NewFill == NULL)
04064         return NULL;
04065 
04066     BOOL Changed = NewFill->ChangeControlTransp(this);
04067 
04068     // Did we change any colours ?
04069     if (!Changed)
04070     {
04071         // No Control points selected, so make a flat fill instead
04072         delete NewFill;
04073 
04074         NewFill = new AttrFlatTranspFill;
04075         if (NewFill == NULL)
04076             return NULL;
04077 
04078         // and use the mutants colour
04079         *(FillGeometryAttribute*)(NewFill->GetAttributeValue()) = *(FillGeometryAttribute*)(this->GetAttributeValue());
04080 
04081         NewFill->SetTranspType(FillToMutate->GetTranspType());
04082 
04083         if (GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && 
04084             FillToMutate->IsVisible() &&
04085             FillToMutate->FindParent() &&
04086             FillToMutate->FindParent()->IsSelected())
04087         {
04088             FillToMutate->RenderFillBlobs();
04089         }
04090     }
04091 
04092     // Return the Mutated Fill
04093     return NewFill;
04094 #else
04095     return NULL;
04096 #endif
04097 }
04098 
04099 /********************************************************************************************
04100 
04101 >   AttrFillGeometry* AttrBitmapChange::MutateFill(AttrFillGeometry* FillToMutate) 
04102 
04103     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04104     Created:    13/12/94
04105     Inputs:     The fill that is to be changed.
04106     Purpose:    Changes the bitmap for a fill.
04107 
04108 ********************************************************************************************/
04109 
04110 AttrFillGeometry* AttrBitmapChange::MutateFill(AttrFillGeometry* FillToMutate) 
04111 { 
04112 #if !defined(EXCLUDE_FROM_RALPH)
04113     // Make a copy of this Fill to change
04114     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04115     if (NewFill == NULL)
04116         return NULL;
04117 
04118 /*
04119     INT32 OldBPP;
04120     
04121     if (NewFill->GetBitmap())
04122         OldBPP = NewFill->GetBitmap()->GetBPP();
04123     else
04124         OldBPP = 24;
04125 
04126     INT32 NewBPP = this->GetBitmap()->GetBPP();
04127 
04128     if (OldBPP <= 8 && NewBPP > 8)
04129     {
04130         // Remove the end point blobs if necessary
04131         FillToMutate->DrawEndBlobs();
04132     }
04133 */
04134 
04135     NewFill->CopyBitmap(GetBitmap());
04136 
04137     return NewFill; 
04138 #else
04139     return NULL;
04140 #endif
04141 }
04142 
04143 /********************************************************************************************
04144 
04145 >   AttrFillGeometry* AttrBitmapTessChange::MutateFill(AttrFillGeometry* FillToMutate) 
04146 
04147     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04148     Created:    13/12/94
04149     Inputs:     The fill that is to be changed.
04150     Purpose:    Changes the bitmap tesselation of a fill.
04151 
04152 ********************************************************************************************/
04153 
04154 AttrFillGeometry* AttrBitmapTessChange::MutateFill(AttrFillGeometry* FillToMutate) 
04155 { 
04156 #if !defined(EXCLUDE_FROM_RALPH)
04157     // Make a copy of this Fill to change
04158     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04159     if (NewFill == NULL)
04160         return NULL;
04161 
04162     NewFill->SetTesselation(GetTesselation());
04163     NewFill->RecalcFractal();
04164 
04165     return NewFill; 
04166 #else
04167     return NULL;
04168 #endif
04169 }
04170 
04171 /********************************************************************************************
04172 
04173 >   AttrFillGeometry* AttrBitmapDpiChange::MutateFill(AttrFillGeometry* FillToMutate) 
04174 
04175     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04176     Created:    13/12/94
04177     Inputs:     The fill that is to be changed.
04178     Purpose:    Changes the bitmap dpi of a fill.
04179 
04180 ********************************************************************************************/
04181 
04182 AttrFillGeometry* AttrBitmapDpiChange::MutateFill(AttrFillGeometry* FillToMutate) 
04183 { 
04184 #if !defined(EXCLUDE_FROM_RALPH)
04185     // Make a copy of this Fill to change
04186     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04187     if (NewFill == NULL)
04188         return NULL;
04189 
04190     NewFill->SetDPI(Dpi);
04191 
04192     return NewFill; 
04193 #else
04194     return NULL;
04195 #endif
04196 }
04197 
04198 /********************************************************************************************
04199 
04200 >   AttrFillGeometry* AttrFractalGrainChange::MutateFill(AttrFillGeometry* FillToMutate) 
04201 
04202     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04203     Created:    13/12/94
04204     Inputs:     The fill that is to be changed.
04205     Purpose:    Changes the fractal graininess of a fill.
04206 
04207 ********************************************************************************************/
04208 
04209 AttrFillGeometry* AttrFractalGrainChange::MutateFill(AttrFillGeometry* FillToMutate) 
04210 { 
04211 #if !defined(EXCLUDE_FROM_RALPH)
04212     // Make a copy of this Fill to change
04213     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04214     if (NewFill == NULL)
04215         return NULL;
04216 
04217     NewFill->SetGraininess(GetGraininess());
04218     NewFill->RecalcFractal();
04219 
04220     return NewFill; 
04221 #else
04222     return NULL;
04223 #endif
04224 }
04225 
04226 /********************************************************************************************
04227 
04228 >   AttrFillGeometry* AttrFractalTileableChange::MutateFill(AttrFillGeometry* FillToMutate) 
04229 
04230     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04231     Created:    13/12/94
04232     Inputs:     The fill that is to be changed.
04233     Purpose:    Changes the Tileable-ness of a fractal fill.
04234 
04235 ********************************************************************************************/
04236 
04237 AttrFillGeometry* AttrFractalTileableChange::MutateFill(AttrFillGeometry* FillToMutate) 
04238 { 
04239 #if !defined(EXCLUDE_FROM_RALPH)
04240     // Make a copy of this Fill to change
04241     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04242     if (NewFill == NULL)
04243         return NULL;
04244 
04245     NewFill->SetTileable(GetTileable());
04246     NewFill->RecalcFractal();
04247 
04248     return NewFill; 
04249 #else
04250     return NULL;
04251 #endif
04252 }
04253 
04254 /********************************************************************************************
04255 
04256 >   AttrFillGeometry* AttrTranspTypeChange::MutateFill(AttrFillGeometry* FillToMutate) 
04257 
04258     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04259     Created:    13/12/94
04260     Inputs:     The fill that is to be changed.
04261     Purpose:    Changes the transparency type of a fill.
04262 
04263 ********************************************************************************************/
04264 
04265 AttrFillGeometry* AttrTranspTypeChange::MutateFill(AttrFillGeometry* FillToMutate) 
04266 { 
04267 #if !defined(EXCLUDE_FROM_RALPH)
04268     // Make a copy of this Fill to change
04269     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04270     if (NewFill == NULL)
04271         return NULL;
04272 
04273     NewFill->SetTranspType(GetTranspType());
04274 
04275     return NewFill; 
04276 #else
04277     return NULL;
04278 #endif
04279 }
04280 
04281 /********************************************************************************************
04282 
04283 >   AttrFillGeometry* AttrNoiseScaleChange::MutateFill(AttrFillGeometry* FillToMutate) 
04284 
04285     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04286     Created:    20/01/97
04287     Inputs:     The fill that is to be changed.
04288     Purpose:    Changes the noise scale of a fill.
04289 
04290 ********************************************************************************************/
04291 
04292 AttrFillGeometry* AttrNoiseScaleChange::MutateFill(AttrFillGeometry* FillToMutate) 
04293 { 
04294 #if !defined(EXCLUDE_FROM_RALPH)
04295     // Make a copy of this Fill to change
04296     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04297     if (NewFill == NULL)
04298         return NULL;
04299 
04300     // get the value from us.
04301     NewFill->SetGraininess(GetGraininess());
04302     NewFill->RecalcFractal();
04303 
04304     return NewFill; 
04305 #else
04306     return NULL;
04307 #endif
04308 }
04309 
04310 /********************************************************************************************
04311 
04312 >   virtual NodeAttribute* AttrTranspTypeChange::GetOtherAttrToApply(BOOL* IsMutate)
04313 
04314     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04315     Created:    17/8/95
04316     Returns:    The secondary attribute to apply, or NULL if none to apply
04317     Purpose:    Some attributes require a secondary atribute to be changed when they are
04318                 changed.  This routine obtains a pointer to the secondary attribute to
04319                 apply.
04320 
04321 ********************************************************************************************/
04322 
04323 NodeAttribute* AttrTranspTypeChange::GetOtherAttrToApply(BOOL* IsMutate)
04324 {
04325 #if !defined(EXCLUDE_FROM_RALPH)
04326     ERROR3IF(IsMutate == NULL, "NULL flag pointer passed to GetOtherAttrToApply");
04327 
04328     // A transparency type change also needs to set the Stroke Transparency type
04329 
04330     NodeAttribute* OtherAttr = new AttrStrokeTranspTypeChange;
04331     if (OtherAttr == NULL)
04332         return NULL;
04333 
04334     UINT32 TranspType = GetTranspType();
04335 
04336     ((AttrStrokeTranspTypeChange *)OtherAttr)->SetTranspType(TranspType);
04337 
04338     *IsMutate = TRUE;
04339 
04340     return OtherAttr;
04341 #else
04342     return NULL;
04343 #endif
04344 }
04345 
04346 /********************************************************************************************
04347 
04348 >   virtual UINT32 AttrValueChange::GetAttrNameID(void)  
04349 
04350     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04351     Created:    13/8/94
04352     Returns:    Attribute description ID
04353     Purpose:    Returns a string resource ID describing the attribute
04354 
04355 ********************************************************************************************/
04356 
04357 UINT32 AttrValueChange::GetAttrNameID(void)  
04358 {
04359     return (_R(IDS_VALUE_CHANGE));
04360 }                                  
04361 
04362 /********************************************************************************************
04363 
04364 >   virtual UINT32 AttrColourChange::GetAttrNameID(void)  
04365 
04366     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04367     Created:    3/01/95
04368     Returns:    Attribute description ID
04369     Purpose:    Returns a string resource ID describing the attribute
04370 
04371 ********************************************************************************************/
04372 
04373 UINT32 AttrColourChange::GetAttrNameID(void)  
04374 {
04375     return (_R(IDS_COLOUR_CHANGE));
04376 }                                  
04377 
04378 /********************************************************************************************
04379 
04380 >   virtual UINT32 AttrBitmapChange::GetAttrNameID(void)  
04381 
04382     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04383     Created:    3/01/95
04384     Returns:    Attribute description ID
04385     Purpose:    Returns a string resource ID describing the attribute
04386 
04387 ********************************************************************************************/
04388 
04389 UINT32 AttrBitmapChange::GetAttrNameID(void)  
04390 {
04391     return (_R(IDS_BITMAP_CHANGE));
04392 }                                  
04393 
04394 /********************************************************************************************
04395 
04396 >   virtual UINT32 AttrBitmapTessChange::GetAttrNameID(void)  
04397 
04398     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04399     Created:    3/01/95
04400     Returns:    Attribute description ID
04401     Purpose:    Returns a string resource ID describing the attribute
04402 
04403 ********************************************************************************************/
04404 
04405 UINT32 AttrBitmapTessChange::GetAttrNameID(void)  
04406 {
04407     return (_R(IDS_BITMAPTESS_CHANGE));
04408 }                                  
04409 
04410 /********************************************************************************************
04411 
04412 >   virtual UINT32 AttrBitmapDpiChange::GetAttrNameID(void)  
04413 
04414     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04415     Created:    3/01/95
04416     Returns:    Attribute description ID
04417     Purpose:    Returns a string resource ID describing the attribute
04418 
04419 ********************************************************************************************/
04420 
04421 UINT32 AttrBitmapDpiChange::GetAttrNameID(void)  
04422 {
04423     return (_R(IDS_BITMAPDPI_CHANGE));
04424 }                                  
04425 
04426 /********************************************************************************************
04427 
04428 >   virtual UINT32 AttrFractalChange::GetAttrNameID(void)  
04429 
04430     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04431     Created:    3/01/95
04432     Returns:    Attribute description ID
04433     Purpose:    Returns a string resource ID describing the attribute
04434 
04435 ********************************************************************************************/
04436 
04437 UINT32 AttrFractalChange::GetAttrNameID(void)  
04438 {
04439     return (_R(IDS_FRACTAL_CHANGE));
04440 }                                  
04441 
04442 /********************************************************************************************
04443 
04444 >   virtual UINT32 AttrFractalGrainChange::GetAttrNameID(void)  
04445 
04446     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04447     Created:    3/01/95
04448     Returns:    Attribute description ID
04449     Purpose:    Returns a string resource ID describing the attribute
04450 
04451 ********************************************************************************************/
04452 
04453 UINT32 AttrFractalGrainChange::GetAttrNameID(void)  
04454 {
04455     return (_R(IDS_FRACTALGRAIN_CHANGE));
04456 }                                  
04457 
04458 /********************************************************************************************
04459 
04460 >   virtual UINT32 AttrFractalTileableChange::GetAttrNameID(void)  
04461 
04462     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04463     Created:    3/01/95
04464     Returns:    Attribute description ID
04465     Purpose:    Returns a string resource ID describing the attribute
04466 
04467 ********************************************************************************************/
04468 
04469 UINT32 AttrFractalTileableChange::GetAttrNameID(void)  
04470 {
04471     return (_R(IDS_FRACTAL_CHANGE));
04472 }                                  
04473 
04474 /********************************************************************************************
04475 
04476 >   virtual UINT32 AttrTranspChange::GetAttrNameID(void)  
04477 
04478     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04479     Created:    3/01/95
04480     Returns:    Attribute description ID
04481     Purpose:    Returns a string resource ID describing the attribute
04482 
04483 ********************************************************************************************/
04484 
04485 UINT32 AttrTranspChange::GetAttrNameID(void)  
04486 {
04487     return (_R(IDS_TRANSP_CHANGE));     //_R(IDS_FLATTRANSPFILL));
04488 }                                  
04489 
04490 /********************************************************************************************
04491 
04492 >   virtual UINT32 AttrTranspTypeChange::GetAttrNameID(void)  
04493 
04494     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04495     Created:    3/01/95
04496     Returns:    Attribute description ID
04497     Purpose:    Returns a string resource ID describing the attribute
04498 
04499 ********************************************************************************************/
04500 
04501 UINT32 AttrTranspTypeChange::GetAttrNameID(void)  
04502 {
04503     return (_R(IDS_TRANSPTYPE_CHANGE));
04504 }
04505 
04506 /********************************************************************************************
04507 
04508 >   virtual UINT32 AttrNoiseScaleChange::GetAttrNameID(void)  
04509 
04510     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04511     Created:    20/01/97
04512     Returns:    Attribute description ID
04513     Purpose:    Returns a string resource ID describing the attribute
04514 
04515 ********************************************************************************************/
04516 
04517 UINT32 AttrNoiseScaleChange::GetAttrNameID(void)  
04518 {
04519     return (_R(IDS_NOISESCALE_CHANGE));
04520 }                                  
04521 
04522 
04523 
04524 
04525 /********************************************************************************************
04526 
04527 >   AttrColFillRampChange::AttrColFillRampChange()
04528 
04529     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04530     Created:    12/03/97
04531     Purpose:    A class to edit colour ramps
04532 
04533 ********************************************************************************************/
04534 
04535 AttrColFillRampChange::AttrColFillRampChange()
04536 {
04537     action   = ACT_DONOTHING;
04538     index    = FILLRAMP_ILLEGALINDEX;
04539     position = 0.0f;
04540 }
04541 
04542 /********************************************************************************************
04543 
04544 >   void InitForColourAdd(DocColour* pColour, float pos);
04545     void InitForTranspAdd(UINT32 t, float pos);
04546     void InitForColourEdit(UINT32 i, DocColour* pColour);
04547     void InitForTranspEdit(UINT32 i, UINT32 t);
04548     void InitForSelEdit(DocColour* pColour);
04549     void InitForSelEdit(UINT32 transparency);
04550 
04551     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04552     Created:    12/03/97
04553     Purpose:    All the init functions to set this AttrColFillRampChange object
04554 
04555 ********************************************************************************************/
04556 
04557 void AttrColFillRampChange::InitForColourAdd(DocColour *pColour, float pos)
04558 {
04559     action   = ACT_CREATENEWCOL;
04560     position = pos;
04561     Value.SetStartColour(pColour);
04562 }
04563 
04564 void AttrColFillRampChange::InitForColourEdit(UINT32 i, DocColour *pColour)
04565 {
04566     action = ACT_EDITCOLOFITEM;
04567     index  = i;
04568     Value.SetStartColour(pColour);
04569 }
04570 
04571 void AttrColFillRampChange::InitForSelEdit(DocColour *pColour)
04572 {
04573     action = ACT_EDITCOLOFSELECTED;
04574     index  = FILLRAMP_ILLEGALINDEX;
04575     Value.SetStartColour(pColour);
04576 }
04577 
04578 
04579 /********************************************************************************************
04580 
04581 >   UINT32 AttrColFillRampChange::GetAttrNameID()
04582 
04583     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04584     Created:    12/03/97
04585     Returns:    Attribute description ID
04586     Purpose:    Returns a string resource ID describing the attribute
04587 
04588 ********************************************************************************************/
04589 
04590 UINT32 AttrColFillRampChange::GetAttrNameID()
04591 {
04592     return (_R(IDS_FILLRAMP_COLOURCHANGE));
04593 }
04594 
04595 
04596 /********************************************************************************************
04597 
04598 >   AttrFillGeometry* AttrColFillRampChange::MutateFill(AttrFillGeometry* FillToMutate) 
04599 
04600     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04601     Created:    12/03/97
04602     Inputs:     FillToMutate = a pointer to a fill attribute to alter.
04603     Returns:    A pointer to a copy which contains the alteration.
04604     Purpose:    Changes the colours in a fill ramp. FillToMutate contains all the info
04605                 necessary to do the edit.
04606 
04607 ********************************************************************************************/
04608 
04609 AttrFillGeometry* AttrColFillRampChange::MutateFill(AttrFillGeometry* FillToMutate) 
04610 { 
04611 #if !defined(EXCLUDE_FROM_RALPH)
04612     if (FillToMutate->IsVisible() && 
04613         FillToMutate->GetSelectionCount() == 0 &&
04614         SelectionCount > 0)
04615         return NULL;
04616 
04617     // Make a copy of this Fill to change
04618     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04619     if (NewFill == NULL)
04620         return NULL;
04621 
04622     // do the actual editing here
04623     BOOL Changed = NewFill->EditColourFillRamp(this);
04624 
04625     // Did we change any colours ?
04626     if (!Changed)
04627     {
04628         delete NewFill;
04629         return NULL;
04630     }
04631     // Return the Mutated Fill
04632     return NewFill;
04633 #else
04634     return NULL;
04635 #endif
04636 }
04637 
04638 /********************************************************************************************
04639 
04640 >   AttrTranspFillRampChange::AttrTranspFillRampChange()
04641 
04642     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04643     Created:    12/03/97
04644     Purpose:    A class to edit colour ramps
04645 
04646 ********************************************************************************************/
04647 
04648 AttrTranspFillRampChange::AttrTranspFillRampChange()
04649 {
04650     action   = ACT_DONOTHING;
04651     index    = FILLRAMP_ILLEGALINDEX;
04652     position = 0.0f;
04653 }
04654 
04655 /********************************************************************************************
04656 
04657 >   void InitForTranspAdd(UINT32 t, float pos);
04658     void InitForTranspEdit(UINT32 i, UINT32 t);
04659     void InitForSelEdit(UINT32 transparency);
04660 
04661     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04662     Created:    12/03/97
04663     Purpose:    All the init functions to set this AttrTranspFillRampChange object
04664 
04665 ********************************************************************************************/
04666 
04667 void AttrTranspFillRampChange::InitForTranspAdd(UINT32 t, float pos)
04668 {
04669     action   = ACT_CREATENEWTRANSP;
04670     position = pos;
04671     Value.SetStartTransp(&t);
04672 }
04673 
04674 void AttrTranspFillRampChange::InitForTranspEdit(UINT32 i, UINT32 t)
04675 {
04676     action = ACT_EDITTRANSPOFITEM;
04677     index  = i;
04678     Value.SetStartTransp(&t);
04679 }
04680 
04681 void AttrTranspFillRampChange::InitForSelEdit(UINT32 t)
04682 {
04683     action = ACT_EDITTRANSPOFSELECTED;
04684     index  = FILLRAMP_ILLEGALINDEX;
04685     Value.SetStartTransp(&t);
04686 }
04687 
04688 /********************************************************************************************
04689 
04690 >   UINT32 AttrTranspFillRampChange::GetAttrNameID()
04691 
04692     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04693     Created:    12/03/97
04694     Returns:    Attribute description ID
04695     Purpose:    Returns a string resource ID describing the attribute
04696 
04697 ********************************************************************************************/
04698 
04699 UINT32 AttrTranspFillRampChange::GetAttrNameID()
04700 {
04701     return (_R(IDS_FILLRAMP_TRANSPCHANGE));
04702 }
04703 
04704 
04705 /********************************************************************************************
04706 
04707 >   AttrFillGeometry* AttrTranspFillRampChange::MutateFill(AttrFillGeometry* FillToMutate) 
04708 
04709     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
04710     Created:    12/03/97
04711     Inputs:     FillToMutate = a pointer to a fill attribute to alter.
04712     Returns:    A pointer to a copy which contains the alteration.
04713     Purpose:    Changes the colours in a fill ramp. FillToMutate contains all the info
04714                 necessary to do the edit.
04715 
04716 ********************************************************************************************/
04717 
04718 AttrFillGeometry* AttrTranspFillRampChange::MutateFill(AttrFillGeometry* FillToMutate) 
04719 { 
04720 #if !defined(EXCLUDE_FROM_RALPH)
04721     if (FillToMutate->IsVisible() && 
04722         FillToMutate->GetSelectionCount() == 0 &&
04723         SelectionCount > 0)
04724         return NULL;
04725 
04726     // Make a copy of this Fill to change
04727     AttrFillGeometry* NewFill = (AttrFillGeometry*)FillToMutate->SimpleCopy();
04728     if (NewFill == NULL)
04729         return NULL;
04730 
04731     // do the actual editing here
04732     BOOL Changed = NewFill->EditTranspFillRamp(this);
04733 
04734     // Did we change any colours ?
04735     if (!Changed)
04736     {
04737         delete NewFill;
04738         return NULL;
04739     }
04740 
04741     // Return the Mutated Fill
04742     return NewFill;
04743 #else
04744     return NULL;
04745 #endif
04746 }
04747 
04748 
04749 /********************************************************************************************
04750 
04751 >   AttrColourDrop::AttrColourDrop(DocCoord &DropPoint, DocRect &ObjectBounds, 
04752                                     DocColour NewColour)
04753     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04754     Created:    7/2/95
04755     Purpose:    Constructor for Colour Drop Attribute
04756 
04757 ********************************************************************************************/
04758 
04759 AttrColourDrop::AttrColourDrop(DocCoord &DropPoint, DocRect &ObjectBounds, 
04760                                 DocColour NewColour)
04761 {
04762 #if !defined(EXCLUDE_FROM_RALPH)
04763     SetDropPoint(DropPoint);
04764     SetObjectBounds(ObjectBounds);
04765     SetStartColour(&NewColour);
04766 
04767     ObjectHit = NULL;
04768     FillHit = NULL;
04769     ControlHit = FILLCONTROL_NULL;
04770 
04771     ObjectIsSelected = FALSE;
04772 #endif
04773 }
04774 
04775 /********************************************************************************************
04776 
04777 >   void AttrColourDrop::SetDropPoint(DocCoord &DropPoint)
04778 
04779     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04780     Created:    7/2/95
04781     Purpose:    Set the drop point for this colour drop
04782 
04783 ********************************************************************************************/
04784 
04785 void AttrColourDrop::SetDropPoint(DocCoord &DropPoint)
04786 {
04787     DropPos = DropPoint;
04788 }
04789 
04790 /********************************************************************************************
04791 
04792 >   void AttrColourDrop::SetObjectBounds(DocRect &ObjectBounds)
04793 
04794     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04795     Created:    7/2/95
04796     Purpose:    Set the object bounds for this colour drop
04797 
04798 ********************************************************************************************/
04799 
04800 void AttrColourDrop::SetObjectBounds(DocRect &ObjectBounds)
04801 {
04802     Bounds = ObjectBounds;
04803 }
04804 
04805 /********************************************************************************************
04806 
04807 >   void AttrColourDrop::SetObjectDroppedOn(NodeRenderableInk* pObject)
04808 
04809     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04810     Created:    7/2/95
04811     Purpose:    Set the object that the colour was dropped on.
04812 
04813 ********************************************************************************************/
04814 
04815 void AttrColourDrop::SetObjectDroppedOn(NodeRenderableInk* pObject)
04816 {
04817 #if !defined(EXCLUDE_FROM_RALPH)
04818     if (pObject)
04819     {
04820         ObjectHit = pObject;
04821         ObjectIsSelected = pObject->IsSelected();
04822     }
04823 #endif
04824 }
04825 
04826 /********************************************************************************************
04827 
04828 >   NodeRenderableInk* AttrColourDrop::GetObjectDroppedOn()
04829 
04830     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04831     Created:    7/2/95
04832     Purpose:    Get the object that the colour was dropped on.
04833 
04834 ********************************************************************************************/
04835 
04836 NodeRenderableInk* AttrColourDrop::GetObjectDroppedOn()
04837 {
04838     return ObjectHit;
04839 }
04840 
04841 /********************************************************************************************
04842 
04843 >   BOOL AttrColourDrop::IsObjectSelected()
04844 
04845     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04846     Created:    7/2/95
04847     Purpose:    Get the selection state of the object that the colour was dropped on.
04848 
04849 ********************************************************************************************/
04850 
04851 BOOL AttrColourDrop::IsObjectSelected()
04852 {
04853     return (ObjectHit && ObjectIsSelected);
04854 }
04855 
04856 /********************************************************************************************
04857 
04858 >   virtual UINT32 AttrColourDrop::GetAttrNameID(void)  
04859 
04860     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04861     Created:    3/01/95
04862     Returns:    Attribute description ID
04863     Purpose:    Returns a string resource ID describing the attribute
04864 
04865 ********************************************************************************************/
04866 
04867 UINT32 AttrColourDrop::GetAttrNameID(void)  
04868 {
04869     return (_R(IDS_COLOUR_CHANGE));
04870 }                                  
04871 
04872 /********************************************************************************************
04873 
04874 >   AttrFillGeometry* AttrColourDrop::MutateFill(AttrFillGeometry* FillToMutate) 
04875 
04876     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04877     Created:    13/12/94
04878     Inputs:     The fill that is to be changed.
04879     Purpose:    Changes the colour of a fill.
04880 
04881 ********************************************************************************************/
04882 
04883 AttrFillGeometry* AttrColourDrop::MutateFill(AttrFillGeometry* FillToMutate) 
04884 { 
04885     return FillToMutate->DoColourDrop(this);    
04886 }
04887 
04888 /********************************************************************************************
04889 
04890 >   AttrFillGeometry* AttrColourDrop::EffectsParentBounds() 
04891 
04892     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
04893     Created:    7/4/2000
04894     Inputs:     -
04895     Purpose:    When creating a new multi-stage fill blob that is outside the shapes
04896                 geometry, we need to invalidate not only the shape; but its bounds as well;
04897                 otherwise we encounter redraw problems.
04898 
04899 ********************************************************************************************/
04900 
04901 BOOL AttrColourDrop::EffectsParentBounds ()
04902 {
04903     return (TRUE);
04904 }
04905 
04906 /********************************************************************************************
04907 
04908 >   FillControl AttrFillGeometry::DoColourDropTest(AttrColourDrop* ColDrop, 
04909                                                     NodeRenderableInk** Object, 
04910                                                     AttrFillGeometry** Fill)
04911     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
04912     Created:    8/2/95
04913     Purpose:    Check to see which colour will be changed if dropped at this point
04914 
04915 ********************************************************************************************/
04916 
04917 FillControl AttrFillGeometry::DoColourDropTest(AttrColourDrop* ColDrop, 
04918                                                 NodeRenderableInk** Object, 
04919                                                 AttrFillGeometry** FillAttr)
04920 {
04921 #if !defined(EXCLUDE_FROM_RALPH)
04922     ERROR2IF(ColDrop == NULL, FILLCONTROL_NULL, "Null ColourDrop passed to DoColourDropTest");
04923 
04924     DocCoord DropPoint = ColDrop->GetDropPoint();
04925 
04926     FillControl ControlHit = FILLCONTROL_NULL;
04927 
04928     if ( (((Camelot.GetBlobManager())->GetCurrentInterest()).Fill) )
04929     {
04930         BOOL HitAControl = FALSE;
04931         HitList.DeleteAll();
04932 
04933         AttrFillGeometry* pAttrFound = NULL;
04934 
04935         // Find the first attribute to test
04936         AttrFillGeometry* pAttr = FindFirstSelectedAttr();
04937         while (pAttr != NULL)
04938         {
04939             // We're only interested in colour fills
04940             if (pAttr->GetAttributeType() == CC_RUNTIME_CLASS(AttrFillGeometry))
04941             {
04942                 // See if the current pos is over one of this fills controls
04943                 FillControl Hit = pAttr->CheckForControlHit(DropPoint);
04944 
04945                 if (Hit != FILLCONTROL_NULL)
04946                 {
04947                     // Signal that we hit something
04948                     HitAControl = TRUE;
04949 
04950                     if (pAttrFound == NULL)
04951                     {
04952                         pAttrFound = pAttr;
04953                         ControlHit = Hit;
04954                     }
04955 
04956                     BOOL InList = FALSE;
04957 
04958                     // We may have already hit this attribute if the selection is
04959                     // inside a parent and have common attributes, so we need to
04960                     // check and make sure this attribute is NOT in the list
04961                     // already.
04962 
04963                     if (!HitList.IsEmpty())
04964                     {
04965                         ListItem* pItem = HitList.GetHead();
04966 
04967                         while (pItem)
04968                         {
04969                             NodeAttributePtrItem* NodePtr = (NodeAttributePtrItem*)pItem;
04970 
04971                             if (NodePtr->NodeAttribPtr == pAttr)
04972                             {
04973                                 // Ignore this one, we've hit it already
04974                                 InList = TRUE;
04975                                 break;
04976                             }
04977 
04978                             pItem = HitList.GetNext(pItem);
04979                         }
04980                     }
04981 
04982                     if (!InList)
04983                     {
04984                         NodeAttributePtrItem* NodePtr = new NodeAttributePtrItem;
04985 
04986                         if (NodePtr != NULL)
04987                         {
04988                             // Add the Attr to the Hit list
04989                             NodePtr->NodeAttribPtr = pAttr;
04990                             HitList.AddTail(NodePtr);
04991                         }
04992                     }
04993                 }
04994             }
04995             
04996             // Move onto the next attr
04997             pAttr = FindNextSelectedAttr();
04998         }                              
04999 
05000         if (HitAControl)
05001         {
05002             // We've hit something !!
05003             if (FillAttr != NULL)
05004                 *FillAttr = pAttrFound;
05005             
05006             if (Object != NULL)
05007                 *Object = (NodeRenderableInk*)pAttrFound->FindParent();
05008 
05009             return ControlHit;
05010         }
05011     }
05012 
05013     if (*Object == NULL)
05014     {
05015         return FILLCONTROL_NULL;
05016     }
05017 
05018     // An object has been specified 
05019     Node* pParent = (Node*)*Object;
05020     ColDrop->SetObjectDroppedOn(*Object);
05021 
05022     DocRect ParentBounds = ((NodeRenderableBounded*)*Object)->GetBoundingRect();
05023 
05024     AttribMap.RemoveAll();
05025     BOOL FoundAttrs = ((NodeRenderableInk*)pParent)->FindAppliedAttributes(&AttribMap);
05026     if (FoundAttrs)
05027     {
05028         void           *pAttr;
05029         if( AttribMap.Lookup( CC_RUNTIME_CLASS(AttrFillGeometry), pAttr ) )
05030         {
05031             // Wahay !! We've got one !!
05032             ControlHit = ((AttrFillGeometry*)pAttr)->TestColourDrop(ColDrop);
05033             return ControlHit;
05034         }
05035     }
05036 #endif
05037     return FILLCONTROL_NULL;
05038 }
05039 
05040 /********************************************************************************************
05041 
05042 >   AttrFillGeometry* AttrFillGeometry::DoColourDrop(AttrColourDrop* ColDrop) 
05043 
05044     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05045     Created:    13/12/94
05046     Inputs:     The fill that is to be changed.
05047     Purpose:    Changes the colour of a fill.
05048 
05049 ********************************************************************************************/
05050 
05051 AttrFillGeometry* AttrFillGeometry::DoColourDrop(AttrColourDrop* ColDrop) 
05052 { 
05053     AttrFillGeometry* NewFill;
05054     DocColour DroppedColour = *ColDrop->GetStartColour();
05055 
05056     // First test to see which colour we should change
05057     FillControl ControlHit = TestColourDrop(ColDrop);
05058 
05059     if (ControlHit == FILLCONTROL_NULL)
05060     {
05061         // No Control points hit, so make a flat fill instead
05062         NewFill = new AttrFlatColourFill;
05063         if (NewFill == NULL)
05064             return NULL;
05065 
05066         // and use the mutants colour
05067         NewFill->SetStartColour(&DroppedColour);
05068 
05069         BOOL InSelection = ColDrop->IsObjectSelected();
05070 
05071         if (InSelection &&
05072             GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && 
05073             IsVisible()
05074             )
05075         {
05076             BOOL UniqueFill = TRUE;
05077 
05078             AttrFillGeometry* pAttr = FindFirstSelectedAttr();
05079             while (pAttr != NULL)
05080             {
05081                 if (pAttr != this && GetAttributeType() == pAttr->GetAttributeType())
05082                 {
05083                     if ( IsMeshSame((FillGeometryAttribute*)GetAttributeValue(),
05084                                     (FillGeometryAttribute*)pAttr->GetAttributeValue()) )
05085                     {
05086                         UniqueFill = FALSE;
05087                         break;
05088                     }
05089                 }
05090 
05091                 // Move onto the next attr
05092                 pAttr = FindNextSelectedAttr();
05093             }
05094 
05095             /*
05096             if (UniqueFill)
05097                 RenderFillBlobs();
05098                 */
05099         }
05100         
05101         return NewFill;
05102     }
05103 
05104     if (FindParent() && FindParent()->IsCompound())
05105     {
05106         if (ColDrop->GetObjectDroppedOn() && 
05107             !(ColDrop->GetObjectDroppedOn()->IsCompound()) && 
05108             ColDrop->IsObjectSelected())
05109         {
05110             // If we are dropping inside a group, then we'll need to remove
05111             // the blobs if this fill is applied to the whole group
05112             // RenderFillBlobs();
05113         }
05114     }
05115 
05116     // Make a copy of this Fill to change
05117     NewFill = (AttrFillGeometry*)this->SimpleCopy();
05118     if (NewFill == NULL)
05119         return NULL;
05120 
05121     if (!NewFill->ChangeControlColour(DroppedColour, ControlHit, ColDrop))
05122     {
05123         delete NewFill;
05124         return NULL;
05125     }
05126 
05127     // Return the Mutated Fill
05128     return NewFill;
05129 }
05130 
05131 /********************************************************************************************
05132 
05133 >   BOOL AttrFillGeometry::ChangeControlColour(DocColour& Col, FillControl Cntrl,
05134                         AttrColourDrop * pColDrop)
05135 
05136     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05137     Created:    8/2/95
05138     Purpose:    Applies a colour to a specific Fill Control Point.
05139 
05140 ********************************************************************************************/
05141 
05142 BOOL AttrFillGeometry::ChangeControlColour(DocColour& Col, FillControl Cntrl,
05143                                            AttrColourDrop * pColDrop)
05144 {
05145 // DMc for drag n drops onto fill ramp control points
05146     if (ISA_RAMPINDEX(Cntrl))
05147     {
05148         // we have a drag and drop onto a ramp control point
05149         if (GetColourRamp())
05150         {
05151             ColourRamp * pRamp = GetColourRamp();
05152 
05153             return pRamp->SetItemColour(Cntrl, &Col);
05154         }
05155 
05156         // treat as a normal ramp point
05157         Cntrl = FILLCONTROL_RAMPPOINT;
05158     }
05159 
05160     switch (Cntrl)
05161     {
05162         case FILLCONTROL_STARTPOINT:
05163             SetStartColour(&Col);
05164             break;
05165 
05166         case FILLCONTROL_ENDPOINT:
05167             SetEndColour(&Col);
05168             break;
05169 
05170         case FILLCONTROL_SECONDARYPOINT:
05171             SetEndColour(&Col);
05172             break;
05173 
05174         case FILLCONTROL_ENDPOINT2:
05175             SetEndColour2(&Col);
05176             break;
05177 
05178         case FILLCONTROL_ENDPOINT3:
05179             SetEndColour3(&Col);
05180             break;
05181         case FILLCONTROL_RAMPPOINT:
05182             if (pColDrop)
05183             {
05184                 CProfileBiasGain DefaultBiasGain;
05185 
05186                 if (!(GetProfile () == DefaultBiasGain))
05187                 {
05188                     // Load and build the question text.
05189                     String_256 QueryString(_R(IDS_ASKMULTIREPLACEPROFILE));
05190                     
05191                     // The only way of bringing up a box with a string in it
05192                     Error::SetError(0, QueryString, 0);
05193                     INT32 DlgResult = InformMessage(0, _R(IDS_YES), _R(IDS_NO));
05194                     Error::ClearError();
05195 
05196                     switch (DlgResult)
05197                     {
05198                         case 1:     // YES
05199                             SetProfile (DefaultBiasGain);       // we MUST revert to
05200                                                                 // the default profile
05201                         break;
05202                         case 2:     // NO
05203                         return (FALSE);         // break out of this stuff!
05204                     }
05205                 }
05206 
05207                 DocCoord DropPoint = pColDrop->GetDropPoint();
05208 
05209                 double dRampPoint = FindRampPoint(DropPoint, *GetStartPoint(),
05210                     *GetEndPoint());
05211 
05212                 // make a new colour ramp (if necessary)
05213                 if (GetColourRamp() == NULL)
05214                 {
05215                     FillGeometryAttribute *pAttrValue = ATTRVALUE();
05216                     if (pAttrValue->SupportsFillRamps())
05217                     {
05218                         if (pAttrValue->IS_KIND_OF(GradFillAttribute))
05219                         {
05220                             ColourRamp * pRamp = ((GradFillAttribute*)pAttrValue)->MakeNewColourRamp();
05221                             pRamp->AddEntry((float)dRampPoint, &Col);
05222                             pRamp->Dump();
05223                         }
05224                     }
05225                 }
05226                 else
05227                 {
05228                     // find out if the drag hit a ramp point
05229                     FillRamp * pRamp = GetColourRamp();
05230 
05231                     ColRampItem * pItem = (ColRampItem *)pRamp->GetHead();
05232 
05233                     while (pItem)
05234                     {
05235                         if (pItem->GetPosition() == dRampPoint)
05236                         {
05237                             // set the colour for the entry
05238                             pItem->SetColour(&Col);
05239                             break;
05240                         }
05241 
05242                         pItem = (ColRampItem *)pRamp->GetNext(pItem);
05243                     }
05244 
05245                     // it hasn't hit a ramp point so add an entry
05246                     if (!pItem)
05247                     {
05248                         GetColourRamp()->AddEntry((float)dRampPoint, &Col);
05249                         GetColourRamp()->Dump();
05250                     }
05251                 }
05252             }
05253             break;      
05254         default:
05255             SetStartColour(&Col);
05256             break;
05257     }
05258 
05259     return TRUE;}
05260 
05261 /********************************************************************************************
05262 
05263 >   BOOL AttrBitmapColourFill::ChangeControlColour(DocColour& Col, FillControl Cntrl)
05264 
05265     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05266     Created:    8/2/95
05267     Purpose:    Applies a colour to a specific Fill Control Point.
05268 
05269 ********************************************************************************************/
05270 
05271 BOOL AttrBitmapColourFill::ChangeControlColour(DocColour& Col, FillControl Cntrl,
05272                                            AttrColourDrop * pColDrop)
05273 {
05274 #if !defined(EXCLUDE_FROM_RALPH)
05275     // Do contone stuff here ....
05276     KernelBitmap* pBitmap = GetBitmap();
05277     KernelBitmap* pGreyBmp = NodeBitmap::CheckGreyscaleBitmap(pBitmap, _R(IDS_MAKEGREY), _R(IDS_DOGREY));
05278 
05279     if (pGreyBmp == NULL)
05280         return FALSE;       // Failed in some way (or the user cancelled)
05281 
05282     return AttrFillGeometry::ChangeControlColour(Col, Cntrl); 
05283 #else
05284     return FALSE;
05285 #endif
05286 }
05287 
05288 /********************************************************************************************
05289 
05290 >   virtual FillControl AttrFillGeometry::TestColourDrop(AttrColourDrop* ColDrop) 
05291 
05292     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05293     Created:    8/2/95
05294     Purpose:    Check to see which colour will be changed if dropped at this point
05295 
05296 ********************************************************************************************/
05297 
05298 FillControl AttrFillGeometry::TestColourDrop(AttrColourDrop* ColDrop) 
05299 { 
05300 #if !defined(EXCLUDE_FROM_RALPH)
05301     // So, where was it dropped (or where will it be dropped)
05302     DocCoord DropPoint = ColDrop->GetDropPoint();
05303 
05304     // Look to see if the DropPoint is over any of the Fill Control Points
05305     return CheckForControlHit(DropPoint);
05306 #else
05307     return FILLCONTROL_NULL;
05308 #endif
05309 }
05310 
05311 /********************************************************************************************
05312 
05313 >   virtual FillControl AttrFlatFill::TestColourDrop(AttrColourDrop* ColDrop) 
05314 
05315     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05316     Created:    8/2/95
05317     Purpose:    Check to see which colour will be changed if dropped at this point
05318 
05319 ********************************************************************************************/
05320 
05321 FillControl AttrFlatFill::TestColourDrop(AttrColourDrop* ColDrop) 
05322 { 
05323     return FILLCONTROL_NULL;
05324 }
05325 
05326 /********************************************************************************************
05327 
05328 >   virtual FillControl AttrLinearFill::TestColourDrop(AttrColourDrop* ColDrop) 
05329 
05330     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05331     Created:    8/2/95
05332     Purpose:    Check to see which colour will be changed if dropped at this point
05333 
05334 ********************************************************************************************/
05335 
05336 FillControl AttrLinearFill::TestColourDrop(AttrColourDrop* ColDrop) 
05337 { 
05338 #if !defined(EXCLUDE_FROM_RALPH)
05339     // So, where was it dropped (or where will it be dropped)
05340     DocCoord DropPoint = ColDrop->GetDropPoint();
05341 
05342     // Look to see if the DropPoint is over any of the Fill Control Points
05343     FillControl ControlHit = CheckForControlHit(DropPoint);
05344     
05345     // If it hit one of our control points, then use that
05346     if (ControlHit != FILLCONTROL_NULL)
05347         return ControlHit;
05348 
05349     // It didn't hit any of our control points, so if the drop is over
05350     // the object then we'll make a guess as to which control point
05351     // the user would like to change, depending on which area of the
05352     // object the pointer is over.
05353 
05354     // First make sure we're actually over an object
05355     NodeRenderableInk* pParentObject = ColDrop->GetObjectDroppedOn();
05356     if (pParentObject == NULL)
05357         return FILLCONTROL_NULL;    // We're not over any object 
05358 
05359     // Make sure this fill type has some Control Points
05360     if (GetStartPoint() == NULL || GetEndPoint() == NULL)
05361         return FILLCONTROL_NULL;
05362 
05363     DocCoord StartPoint = *GetStartPoint();
05364     DocCoord EndPoint   = *GetEndPoint();
05365         
05366     // Find the MidPoint of the line joining the Start and End Points
05367     DocCoord MidPoint = DocCoord(StartPoint.x + (EndPoint.x - StartPoint.x)/2,
05368                                 StartPoint.y + (EndPoint.y - StartPoint.y)/2);
05369 
05370     TRACEUSER( "Mike", _T("DropPoint (before)   = %d,%d\n"),DropPoint.x, DropPoint.y);
05371 
05372     TRACEUSER( "Mike", _T("StartPoint           = %d,%d\n"),StartPoint.x, StartPoint.y);
05373     TRACEUSER( "Mike", _T("MidPoint             = %d,%d\n"),MidPoint.x, MidPoint.y);
05374     TRACEUSER( "Mike", _T("EndPoint             = %d,%d\n"),EndPoint.x, EndPoint.y);
05375 
05376     // Now find the angle of the line relative to the Horizontal
05377     ANGLE LineAngle = CalcLineAngle(MidPoint, EndPoint) - 90;
05378     Matrix Rotate   = Matrix(-LineAngle);
05379 
05380     // Rotate the Drop Point around the MidPoint of the line
05381     DropPoint.translate(-MidPoint.x, -MidPoint.y);
05382     Rotate.transform(&DropPoint);
05383     DropPoint.translate(MidPoint.x, MidPoint.y);
05384 
05385     TRACEUSER( "Mike", _T("DropPoint (after)    = %d,%d\n"),DropPoint.x, DropPoint.y);
05386 
05387     // Now the Coords have be transformed as if the Line was Horizontal,
05388     // so all we need to do is check to see if the Drop Point is to the
05389     // left or right of the MidPoint.
05390 
05391     if (DropPoint.x <= MidPoint.x)
05392         ControlHit = FILLCONTROL_STARTPOINT;        
05393     else
05394         ControlHit = FILLCONTROL_ENDPOINT;      
05395 
05396     return ControlHit;
05397 #else
05398     return FILLCONTROL_NULL;
05399 #endif
05400 }
05401 
05402 /********************************************************************************************
05403 
05404 >   virtual FillControl AttrRadialFill::TestColourDrop(AttrColourDrop* ColDrop) 
05405 
05406     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05407     Created:    8/2/95
05408     Purpose:    Check to see which colour will be changed if dropped at this point
05409 
05410 ********************************************************************************************/
05411 
05412 FillControl AttrRadialFill::TestColourDrop(AttrColourDrop* ColDrop) 
05413 { 
05414 #if !defined(EXCLUDE_FROM_RALPH)
05415     return AttrFillGeometry::TestColourDrop(ColDrop);
05416 
05417     // So, where was it dropped (or where will it be dropped)
05418     DocCoord DropPoint = ColDrop->GetDropPoint();
05419 
05420     // Look to see if the DropPoint is over any of the Fill Control Points
05421     FillControl ControlHit = CheckForControlHit(DropPoint);
05422     
05423     // If it hit one of our control points, then use that
05424     if (ControlHit != FILLCONTROL_NULL)
05425         return ControlHit;
05426 
05427     // It didn't hit any of our control points, so if the drop is over
05428     // the object then we'll make a guess as to which control point
05429     // the user would like to change, depending on which area of the
05430     // object the pointer is over.
05431 
05432     // First make sure we're actually over an object
05433     NodeRenderableInk* pParentObject = ColDrop->GetObjectDroppedOn();
05434     if (pParentObject == NULL)
05435         return FILLCONTROL_NULL;    // We're not over any object 
05436 
05437     // Make sure this fill type has some Control Points
05438     if (GetStartPoint() == NULL || GetEndPoint() == NULL)
05439         return FILLCONTROL_NULL;
05440 
05441     DocCoord StartPoint = *GetStartPoint();
05442     DocCoord EndPoint   = *GetEndPoint();
05443     DocCoord EndPoint2  = *GetEndPoint2();
05444 
05445     double MajRadius = EndPoint.Distance(StartPoint);
05446     double MinRadius = EndPoint2.Distance(StartPoint);
05447 
05448     ANGLE MajAngle  = CalcLineAngle(StartPoint, EndPoint)  + 180;
05449     ANGLE DropAngle = CalcLineAngle(StartPoint, DropPoint) + 180;
05450 
05451     ANGLE Diff = DropAngle - MajAngle;
05452 
05453     if (Diff >= 180)    Diff -= 360;
05454     if (Diff <= -180)   Diff += 360;
05455     
05456     Diff = ABS(Diff);
05457     if (Diff > 90)      Diff = 180 - Diff;
05458 
05459     TRACEUSER( "Mike", _T("MajAngle     = %f\n"),MajAngle.MakeDouble());
05460     TRACEUSER( "Mike", _T("DropAngle    = %f\n"),DropAngle.MakeDouble());
05461     TRACEUSER( "Mike", _T("Diff         = %f\n"),Diff.MakeDouble());
05462 
05463     double Radius = MajRadius + ((MinRadius - MajRadius) * (Diff.MakeDouble()/90));
05464     double Dist   = DropPoint.Distance(StartPoint);
05465 
05466     TRACEUSER( "Mike", _T("Radius       = %f\n"),Radius);
05467     TRACEUSER( "Mike", _T("Dist         = %f\n"),Dist);
05468         
05469     // Is the distance from the centre, more than half the radius ?
05470 
05471     if (Dist <= Radius/2)
05472         ControlHit = FILLCONTROL_STARTPOINT;        
05473     else
05474         ControlHit = FILLCONTROL_ENDPOINT;      
05475 
05476     return ControlHit;
05477 #else
05478     return FILLCONTROL_NULL;
05479 #endif
05480 }
05481 
05482 /********************************************************************************************
05483 
05484 >   virtual FillControl AttrConicalFill::TestColourDrop(AttrColourDrop* ColDrop) 
05485 
05486     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05487     Created:    8/2/95
05488     Purpose:    Check to see which colour will be changed if dropped at this point
05489 
05490 ********************************************************************************************/
05491 
05492 FillControl AttrConicalFill::TestColourDrop(AttrColourDrop* ColDrop) 
05493 { 
05494     // So, where was it dropped (or where will it be dropped)
05495     DocCoord DropPoint = ColDrop->GetDropPoint();
05496 
05497     // Look to see if the DropPoint is over any of the Fill Control Points
05498     FillControl ControlHit = CheckForControlHit(DropPoint);
05499     
05500     // If it hit one of our control points, then use that
05501     if (ControlHit != FILLCONTROL_NULL)
05502         return ControlHit;
05503 
05504     // It didn't hit any of our control points, so if the drop is over
05505     // the object then we'll make a guess as to which control point
05506     // the user would like to change, depending on which area of the
05507     // object the pointer is over.
05508 
05509     // First make sure we're actually over an object
05510     NodeRenderableInk* pParentObject = ColDrop->GetObjectDroppedOn();
05511     if (pParentObject == NULL)
05512         return FILLCONTROL_NULL;    // We're not over any object 
05513 
05514     // Make sure this fill type has some Control Points
05515     if (GetStartPoint() == NULL || GetEndPoint() == NULL)
05516         return FILLCONTROL_NULL;
05517 
05518     DocCoord StartPoint = *GetStartPoint();
05519     DocCoord EndPoint   = *GetEndPoint();
05520 
05521     // Get the angle of lines joining the Start and End points,
05522     // and also the Start and Drop points. (And make them 0 to 360).
05523     ANGLE LineAngle = CalcLineAngle(StartPoint, EndPoint)  + 180;
05524     ANGLE DropAngle = CalcLineAngle(StartPoint, DropPoint) + 180;
05525 
05526     // Get the difference between the two angles
05527     ANGLE Diff = DropAngle - LineAngle;
05528 
05529     // and ensure we always get use the shortest path
05530     if (Diff >= 180)
05531         Diff -= 360;
05532                     
05533     if (Diff <= -180)
05534         Diff += 360;
05535 
05536     TRACEUSER( "Mike", _T("LineAngle    = %f\n"),LineAngle.MakeDouble());
05537     TRACEUSER( "Mike", _T("DropAngle    = %f\n"),DropAngle.MakeDouble());
05538     TRACEUSER( "Mike", _T("Diff         = %f\n"),Diff.MakeDouble());
05539 
05540     // check for a colour drop on the line
05541     double d = FindRampPoint(DropPoint, *GetStartPoint(), *GetEndPoint());
05542 
05543     if (d >= 0 && d <= 1.0)
05544     {
05545         return FILLCONTROL_RAMPPOINT;
05546     }
05547 
05548     // If the difference is greater the +-90, then set the start colour
05549     if (Diff <= 90 && Diff > -90)
05550         ControlHit = FILLCONTROL_ENDPOINT;      
05551     else
05552         ControlHit = FILLCONTROL_STARTPOINT;
05553 
05554     return ControlHit;
05555 }
05556 
05557 
05558 
05559 /********************************************************************************************
05560 
05561 >   virtual FillControl AttrBitmapFill::TestColourDrop(AttrColourDrop* ColDrop) 
05562 
05563     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05564     Created:    8/2/95
05565     Purpose:    Check to see which colour will be changed if dropped at this point
05566 
05567 ********************************************************************************************/
05568 
05569 FillControl AttrBitmapFill::TestColourDrop(AttrColourDrop* ColDrop) 
05570 { 
05571     return AttrFillGeometry::TestColourDrop(ColDrop);
05572 }
05573 
05574 /********************************************************************************************
05575 
05576 >   KernelBitmap *AttrBitmapFill::EnumerateBitmaps(UINT32 Count)
05577 
05578     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05579     Created:    02/17/95
05580     Inputs:     Count - the bitmap to get (see Purpose).
05581     Returns:    The KernelBitmap in use by the node, or NULL if no more are used.
05582     Purpose:    Find out what bitmaps, if any, are used by this node.
05583 
05584                 The base class returns NULL always, so you over-ride this in any node classes
05585                 that use bitmaps.
05586 
05587                 This function supports nodes that use more than one bitmap - you call this
05588                 function repeatedly and keep incrementing the Count parameter that you pass
05589                 in each time by 1.  You should stop calling it when it returns NULL, as this
05590                 indicates that no more bitmaps are used by this node.
05591                 Count should start off as 0 for the first call.  Note that this function
05592                 can (and often will) return NULL for the first call, as many nodes don't
05593                 use bitmaps, obviously.
05594 
05595     SeeAlso:    KernelBitmap
05596 
05597 ********************************************************************************************/
05598 
05599 KernelBitmap *AttrBitmapFill::EnumerateBitmaps(UINT32 Count)
05600 {
05601     if (IsAFractalFill())
05602         return NULL;
05603 
05604     if (Count == 0) 
05605         return GetBitmap();
05606 
05607     return NULL;
05608 }
05609 
05610 
05611 /****************************************************************************
05612 
05613 >   BOOL AttrBitmapFill::ReplaceBitmap(KernelBitmap* pOrigBitmap, KernelBitmap* pNewBitmap)
05614 
05615     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
05616     Created:    07/08/2006
05617 
05618     Inputs:     pOrigBitmap - pointer to a KernelBitmap
05619                 pNewBitmap  - pointer to a KernelBitmap
05620     Returns:    TRUE if ok, FALSE if bother
05621     Purpose:    
05622 
05623 ****************************************************************************/
05624 
05625 BOOL AttrBitmapFill::ReplaceBitmap(KernelBitmap* pOrigBitmap, KernelBitmap* pNewBitmap)
05626 {
05627     if (!IsAFractalFill())
05628     {
05629         if (GetBitmap() == pOrigBitmap)
05630         {
05631             BitmapFillAttribute* pVal = (BitmapFillAttribute*)GetAttributeValue();
05632             if (pVal)
05633                 pVal->GetBitmapRef()->Attach(pNewBitmap);
05634 
05635             return(TRUE);
05636         }
05637     }
05638 
05639     return FALSE;
05640 }
05641 
05642 
05643 /****************************************************************************
05644 
05645 >   double AttrBitmapFill::GetEffectiveBitmapMinDPI(KernelBitmap* pBitmap)
05646 
05647     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
05648     Created:    07/08/2006
05649 
05650     Inputs:     pBitmap     - pointer to a KernelBitmap
05651     Returns:    
05652     Purpose:    Returns the minimum effective dpi this bitmap is used at
05653 
05654 ****************************************************************************/
05655 
05656 double AttrBitmapFill::GetEffectiveBitmapMinDPI(KernelBitmap* pBitmap)
05657 {
05658     if (!IsAFractalFill() && GetBitmap() == pBitmap)
05659     {
05660         // Do we have a valid bitmap ?
05661         OILBitmap *OilBM = pBitmap->ActualBitmap;
05662         if (OilBM != NULL)
05663         {
05664             BitmapInfo Info;
05665             OilBM->GetInfo(&Info);
05666 
05667             // Get the Width of the Bitmap in Pixels
05668             INT32 PixWidth  = Info.PixelWidth;
05669             INT32 PixHeight = Info.PixelHeight;
05670 
05671             DocCoord Start(*GetStartPoint());
05672             DocCoord End(*GetEndPoint());
05673             DocCoord End2(*GetEndPoint2());
05674 
05675             // Get the Width of the Bitmap in Millipoints
05676             INT32 Width  = INT32(Start.Distance(End));
05677             INT32 Height = INT32(Start.Distance(End2));
05678 
05679             // Use doubles so that we can round up as well as down. This improves
05680             // the dpi calculated.
05681             double HDpi = 0;
05682             double VDpi = 0;
05683 
05684             if (Width > 0)
05685                 HDpi = ((double)PixWidth * 72000.0)/(double)Width;
05686 
05687             if (Height > 0)
05688                 VDpi = ((double)PixHeight * 72000.0)/(double)Height;
05689 
05690             // Use the smaller of the two dpi values
05691             if (HDpi < VDpi)
05692                 return(HDpi);
05693             else
05694                 return(VDpi);
05695         }
05696     }
05697 
05698     return(1e9);
05699 }
05700 
05701 
05702 /********************************************************************************************
05703 
05704 >   virtual NodeAttribute* AttrBitmapFill::GetOtherAttrToApply(BOOL* IsMutate)
05705 
05706     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05707     Created:    8/12/99
05708     Returns:    The secondary attribute to apply, or NULL if none to apply
05709     Purpose:    Some attributes require a secondary atribute to be changed when they are
05710                 changed.  This routine obtains a pointer to the secondary attribute to
05711                 apply.
05712 
05713 ********************************************************************************************/
05714 
05715 NodeAttribute* AttrBitmapFill::GetOtherAttrToApply(BOOL* IsMutate)
05716 {
05717     ERROR3IF(IsMutate == NULL, "NULL flag pointer passed to GetOtherAttrToApply");
05718 
05719     // A bitmap fill change also needs to set the mapping to repeating ....
05720 
05721     NodeAttribute* OtherAttr = NULL;
05722     
05723     if (GetAttributeType() == CC_RUNTIME_CLASS(AttrFillGeometry))
05724     {
05725         OtherAttr = new AttrFillMappingLinear;
05726     }
05727     else
05728     {
05729         OtherAttr = new AttrTranspFillMappingLinear;
05730     }
05731 
05732     if (OtherAttr == NULL)
05733     {
05734         return (NULL);
05735     }
05736 
05737     ((AttrFillMappingLinear*) OtherAttr)->SetRepeat(RT_Repeating);
05738 
05739     *IsMutate = FALSE;
05740 
05741     return OtherAttr;
05742 }
05743 
05744 
05745 
05746 
05748 //
05749 //                              AttrFlatFill
05750 //
05752 
05753 /********************************************************************************************
05754 
05755 >   AttrFlatFill::AttrFlatFill()
05756 
05757     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05758     Created:    25/07/94
05759     Purpose:    Constructs a Flat Fill.
05760 
05761 ********************************************************************************************/
05762 
05763 AttrFlatFill::AttrFlatFill() 
05764 {
05765 }
05766 
05767 /********************************************************************************************
05768 
05769 >   virtual DocRect AttrFlatFill::GetBlobBoundingRect()
05770 
05771     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05772     Created:    28/7/94
05773     Returns:    DocRect - The rectangle that contains all the nodes selection blobs.
05774     Purpose:    Calculates the bounding rectangle of the nodes blobs.This should always 
05775                 be calculated on the fly as the view scale can change without the node 
05776                 knowing, giving an incorrect result.
05777 
05778 ********************************************************************************************/
05779 
05780 DocRect AttrFlatFill::GetBlobBoundingRect()
05781 {
05782     // Flat fills have bo bounds
05783     DocRect BoundingRect(0,0,0,0);
05784 
05785     // and return it
05786     return BoundingRect;
05787 }
05788 
05789 /********************************************************************************************
05790 
05791 >   void AttrFlatFill::ValidateAttributeValue()
05792 
05793     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05794     Created:    11/8/94
05795     Purpose:    Makes sure the Coords of the Fill are sensible.
05796 
05797 ********************************************************************************************/
05798 
05799 void AttrFlatFill::ValidateAttributeValue()
05800 {
05801 }
05802 
05804 //
05805 //                              AttrFlatColourFill
05806 //
05808 
05809 /********************************************************************************************
05810 
05811 >   void AttrFlatColourFill::Render( RenderRegion* pRender)
05812 
05813     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05814     Created:    23/8/94
05815     Purpose:    'Renders' a Flat Fill Colour attribute.
05816 
05817 ********************************************************************************************/
05818 
05819 void AttrFlatColourFill::Render(RenderRegion* pRender)
05820 {
05821     pRender->SetFillGeometry(&Value, FALSE);
05822 }
05823 
05824 /********************************************************************************************
05825 
05826 > Node* AttrFlatColourFill::SimpleCopy() 
05827 
05828     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05829     Created:    23/8/94
05830     Returns:    A copy of the node, or NULL if memory runs out 
05831     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
05832                 The function is virtual, and must be defined for all derived classes.  
05833     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
05834                 memory error and the function returns NULL. 
05835     Scope:      protected       
05836 
05837 ********************************************************************************************/
05838      
05839 Node* AttrFlatColourFill::SimpleCopy()
05840 {
05841     AttrFlatColourFill* NodeCopy = new AttrFlatColourFill();
05842     if (NodeCopy == NULL)
05843         return NULL;
05844 
05845     CopyNodeContents(NodeCopy);
05846     
05847     return NodeCopy;
05848 }  
05849 
05850 /********************************************************************************************
05851 
05852 >   virtual UINT32 AttrFlatColourFill::GetAttrNameID(void)  
05853 
05854     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05855     Created:    23/8/94
05856     Returns:    Attribute description ID
05857     Purpose:    Returns a string resource ID describing the attribute
05858 
05859 ********************************************************************************************/
05860 
05861 UINT32 AttrFlatColourFill::GetAttrNameID(void)  
05862 {
05863     return (_R(IDS_FILL_COLOUR));
05864 }                                  
05865 
05866 /********************************************************************************************
05867 
05868 >   void AttrFlatColourFill::GetDebugDetails(StringBase* Str)
05869 
05870     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05871     Created:    20/07/94
05872     Outputs:    Str - the string containing details of the attribute.
05873     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
05874 
05875 ********************************************************************************************/
05876 
05877 void AttrFlatColourFill::GetDebugDetails(StringBase* Str)
05878 {
05879 #ifdef _DEBUG
05880     NodeAttribute::GetDebugDetails( Str );
05881 
05882     String_256 TempStr;
05883 
05884 //  TempStr._MakeMsg( TEXT("\r\nFill") );
05885 //  (*GetStartColour()).GetDebugDetails(&TempStr);
05886 //  (*Str) += TempStr;
05887 
05888 //  TempStr._MakeMsg(TEXT("\r\nStart"));
05889 //  (*GetStartColour()).GetDebugDetails(&TempStr);
05890 //  (*Str) += TempStr;
05891 #endif
05892 }
05893 
05894 
05895 /********************************************************************************************
05896 
05897 >   virtual UINT32 AttrFlatColourFill::GetNodeSize() const
05898 
05899     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
05900     Created:    23/8/94
05901     Returns:    The size of the node in bytes
05902     Purpose:    For finding the size of the node.
05903     SeeAlso:    Node::GetSubtreeSize
05904 
05905 ********************************************************************************************/
05906 
05907 UINT32 AttrFlatColourFill::GetNodeSize() const 
05908 {     
05909     return sizeof(AttrFlatColourFill);
05910 }  
05911 
05912 
05913 
05914 /********************************************************************************************
05915 
05916   > virtual BOOL AttrFlatColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
05917 
05918     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
05919     Created:    30/5/96
05920     Inputs:     pFilter = ptr to the filter
05921     Returns:    TRUE if record is written, FALSE if not
05922     Purpose:    Writes the flat fill record to the filter
05923     SeeAlso:    -
05924 
05925 ********************************************************************************************/
05926 
05927 BOOL AttrFlatColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
05928 {
05929 #ifdef DO_EXPORT
05930     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
05931 
05932     // Must write out the colour first
05933     INT32 ColRef = pFilter->WriteRecord(&Value.Colour);
05934 
05935     // Is the colour reference ok?
05936     BOOL ok = (ColRef != 0);
05937         
05938     if (ok)
05939     {
05940         BOOL ColourRequired = TRUE;
05941         INT32 Tag = TAG_FLATFILL;
05942         INT32 Size = TAG_FLATFILL_SIZE;
05943         switch (ColRef)
05944         {
05945             case REF_DEFAULTCOLOUR_TRANSPARENT:
05946                 Tag = TAG_FLATFILL_NONE;
05947                 Size = TAG_FLATFILL_NONE_SIZE;
05948                 ColourRequired = FALSE;
05949                 break;
05950             case REF_DEFAULTCOLOUR_BLACK:
05951                 Tag = TAG_FLATFILL_BLACK;
05952                 Size = TAG_FLATFILL_BLACK_SIZE;
05953                 ColourRequired = FALSE;
05954                 break;
05955             case REF_DEFAULTCOLOUR_WHITE:
05956                 Tag = TAG_FLATFILL_WHITE;
05957                 Size = TAG_FLATFILL_WHITE_SIZE;
05958                 ColourRequired = FALSE;
05959                 break;
05960         }
05961 
05962         CamelotFileRecord Rec(pFilter,Tag,Size);
05963 
05964         if (ok) ok = Rec.Init();
05965         if (ok && ColourRequired) ok = Rec.WriteReference(ColRef);
05966         if (ok) ok = pFilter->Write(&Rec);
05967     }
05968 
05969     if (!ok)
05970         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
05971 
05972     return ok;
05973 #else
05974     return FALSE;
05975 #endif
05976 }
05977 
05978 //--------------------------------------------------------------
05979 // See AttrFlatColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
05980 //
05981 BOOL AttrFlatColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
05982 {
05983 #ifdef DO_EXPORT
05984     return WritePreChildrenWeb(pFilter);
05985 #else
05986     return FALSE;
05987 #endif
05988 }
05989 
05990 
05991 /********************************************************************************************
05992 
05993   > virtual BOOL AttrFlatColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
05994 
05995     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
05996     Created:    14/9/2000
05997     Inputs:     pFilter = ptr to the filter
05998     Returns:    TRUE if record is written, FALSE if not
05999     Purpose:    Writes out colour definitions for this fill.
06000     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
06001                 Layer::WriteAtomicNodesColourRefs ()
06002 
06003 ********************************************************************************************/
06004 
06005 BOOL AttrFlatColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
06006 {
06007     INT32 ColRef = pFilter->WriteRecord(&Value.Colour);
06008 
06009     // Is the colour reference ok?
06010     
06011     return (ColRef != 0);
06012 }
06013 
06014 //---------------------------------------------------------------------------------------
06015 //---------------------------------------------------------------------------------------
06016 //---------------------------------------------------------------------------------------
06017 
06019 //
06020 //                              AttrFlatTranspFill
06021 //
06023 
06024 /********************************************************************************************
06025 
06026 >   void AttrFlatTranspFill::Render( RenderRegion* pRender)
06027 
06028     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06029     Created:    23/8/94
06030     Purpose:    'Renders' a Flat Fill Colour attribute.
06031 
06032 ********************************************************************************************/
06033 
06034 void AttrFlatTranspFill::Render(RenderRegion* pRender)
06035 {
06036     pRender->SetTranspFillGeometry(&Value, FALSE);
06037 }
06038 
06039 /********************************************************************************************
06040 
06041 > Node* AttrFlatTranspFill::SimpleCopy() 
06042 
06043     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06044     Created:    23/8/94
06045     Returns:    A copy of the node, or NULL if memory runs out 
06046     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
06047                 The function is virtual, and must be defined for all derived classes.  
06048     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
06049                 memory error and the function returns NULL. 
06050     Scope:      protected       
06051 
06052 ********************************************************************************************/
06053      
06054 Node* AttrFlatTranspFill::SimpleCopy()
06055 {
06056     AttrFlatTranspFill* NodeCopy = new AttrFlatTranspFill();
06057     if (NodeCopy == NULL)
06058         return NULL;
06059 
06060     CopyNodeContents(NodeCopy);
06061     
06062     return NodeCopy;
06063 }  
06064 
06065 /********************************************************************************************
06066 
06067 >   virtual UINT32 AttrFlatTranspFill::GetAttrNameID(void)  
06068 
06069     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06070     Created:    23/8/94
06071     Returns:    Attribute description ID
06072     Purpose:    Returns a string resource ID describing the attribute
06073 
06074 ********************************************************************************************/
06075 
06076 UINT32 AttrFlatTranspFill::GetAttrNameID(void)  
06077 {
06078     return (_R(IDS_FILL_COLOUR));
06079 }                                  
06080 
06081 /********************************************************************************************
06082 
06083 >   void AttrFlatTranspFill::GetDebugDetails(StringBase* Str)
06084 
06085     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06086     Created:    20/07/94
06087     Outputs:    Str - the string containing details of the attribute.
06088     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
06089 
06090 ********************************************************************************************/
06091 
06092 void AttrFlatTranspFill::GetDebugDetails(StringBase* Str)
06093 {
06094 #ifdef _DEBUG
06095     NodeAttribute::GetDebugDetails( Str );
06096 
06097     String_256 TempStr;
06098 
06099     TempStr._MakeMsg( TEXT("\r\nFill") );
06100     (*Str) += TempStr;
06101 
06102     TempStr._MakeMsg(TEXT("\r\nStart"));
06103     (*Str) += TempStr;
06104 
06105     TempStr._MakeMsg(TEXT("\r\nFill value = #1%u"), *GetStartTransp() );    
06106     (*Str) += TempStr;
06107 
06108     TempStr._MakeMsg(TEXT("\r\nFill type = #1%u"), GetTranspType() );   
06109     (*Str) += TempStr;
06110 #endif
06111 }
06112 
06113 
06114 /********************************************************************************************
06115 
06116 >   virtual UINT32 AttrFlatTranspFill::GetNodeSize() const
06117 
06118     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06119     Created:    23/8/94
06120     Returns:    The size of the node in bytes
06121     Purpose:    For finding the size of the node.
06122     SeeAlso:    Node::GetSubtreeSize
06123 
06124 ********************************************************************************************/
06125 
06126 UINT32 AttrFlatTranspFill::GetNodeSize() const 
06127 {     
06128     return sizeof(AttrFlatTranspFill);
06129 }  
06130 
06131 
06132 
06133 /********************************************************************************************
06134 
06135   > virtual BOOL AttrFlatTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
06136 
06137     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
06138     Created:    26/6/96
06139     Inputs:     pFilter = ptr to the filter
06140     Returns:    TRUE if record is written, FALSE if not
06141     Purpose:    Writes the flat transparent fill record to the filter
06142     SeeAlso:    -
06143 
06144 ********************************************************************************************/
06145 
06146 BOOL AttrFlatTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
06147 {
06148 #ifdef DO_EXPORT
06149     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
06150     ERROR3IF(Value.Transp     > 255,"Transparency level is too high to be stored as a byte");
06151     ERROR3IF(Value.TranspType > 255,"Transparency type is too high to be stored as a byte");
06152 
06153     BOOL ok = TRUE;
06154 
06155     CamelotFileRecord Rec(pFilter,TAG_FLATTRANSPARENTFILL,TAG_FLATTRANSPARENTFILL_SIZE);
06156 
06157     if (ok) ok = Rec.Init();
06158     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
06159     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
06160     if (ok) ok = pFilter->Write(&Rec);
06161 
06162     if (!ok)
06163         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
06164 
06165     return ok;
06166 #else
06167     return FALSE;
06168 #endif
06169 }
06170 
06171 //--------------------------------------------------------------
06172 // See AttrFlatTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
06173 //
06174 BOOL AttrFlatTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
06175 {
06176 #ifdef DO_EXPORT
06177     return WritePreChildrenWeb(pFilter);
06178 #else
06179     return FALSE;
06180 #endif
06181 }
06182 
06183 
06184 /********************************************************************************************
06185 >   BOOL AttrFlatTranspFill::HasEquivalentDefaultValue(BOOL bAppearance = FALSE)
06186 
06187     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
06188     Created:    11/05/2005
06189     Inputs:     -
06190     Outputs:    -
06191     Returns:    TRUE if this node has a value equivalent to the relevant 
06192                 FALSE otherwise
06193     Purpose:    Determine whether this attribute has the default value or not
06194     Errors:     -
06195     SeeAlso:    -
06196 ********************************************************************************************/
06197 
06198 BOOL AttrFlatTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
06199 {
06200     // Slight bodge - we will assume that the default transparency is fully opaque
06201     return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0));
06202 }
06203 
06204 
06205 
06206 
06208 //
06209 //                              AttrLinearFill
06210 //
06212 
06213 /********************************************************************************************
06214 
06215 >   void AttrLinearFill::Transform( TransformBase& Trans )
06216 
06217     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06218     Created:    23/8/94
06219     Inputs:     Trans - the transform object to apply to this attribute.
06220     Purpose:    Transform a grad fill attribute by moving the start and end points.
06221     SeeAlso:    NodeRenderable::Transform
06222 
06223 ********************************************************************************************/
06224 
06225 void AttrLinearFill::Transform( TransformBase& Trans )
06226 {
06227     if ( Trans.TransFills )
06228     {
06229         Trans.Transform( GetStartPoint(), 1);
06230         Trans.Transform( GetEndPoint(), 1);
06231         Trans.Transform( GetEndPoint2(), 1);
06232 
06233         if (IsPerspective())
06234             Trans.Transform( GetEndPoint3(), 1);
06235     }
06236 }
06237 
06238 /********************************************************************************************
06239 
06240 >   BOOL AttrLinearFill::CanTransform()
06241 
06242     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06243     Created:    23/8/94
06244     Returns:    TRUE => transform this attribute.
06245     Purpose:    Indicate that this attribute can be transformed.
06246     SeeAlso:    NodeRenderable::CanTransform
06247 
06248 ********************************************************************************************/
06249 
06250 BOOL AttrLinearFill::CanTransform()
06251 {
06252     return TRUE;
06253 }
06254 
06255 /********************************************************************************************
06256 
06257 >   FillControl AttrLinearFill::CheckForControlHit(DocCoord &ClickPos)
06258 
06259     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
06260     Created:    21/10/99
06261     Inputs:     ClickPos, The DocCoord position to check.
06262     Returns:    A FillControl, indicating the Fill Control Point Hit,
06263                 or FILLCONTROL_NULL, if no points hit.
06264     Purpose:    Check to see if a click was on a Fill Control Point. 
06265     SeeAlso:    FillControl
06266 
06267 ********************************************************************************************/
06268 
06269 FillControl AttrLinearFill::CheckForControlHit(DocCoord &ClickPos)
06270 {
06271     return AttrFillGeometry::CheckForControlHit(ClickPos);
06272     
06273 }
06274 
06275 /********************************************************************************************
06276 
06277 >   AttrFillGeometry* AttrLinearFill::DoColourDrop(AttrColourDrop* ColDrop) 
06278 
06279     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
06280     Created:    13/12/94
06281     Inputs:     The fill that is to be changed.
06282     Purpose:    Changes the colour of a fill + does the colour ramps too
06283 
06284 ********************************************************************************************/
06285 
06286 AttrFillGeometry* AttrLinearFill::DoColourDrop(AttrColourDrop* ColDrop) 
06287 { 
06288     return AttrFillGeometry::DoColourDrop(ColDrop);
06289 }
06290 
06291 /********************************************************************************************
06292 
06293 >   BOOL AttrLinearFill::ChangeControlColour(DocColour& Col, FillControl Cntrl,
06294                         AttrColourDrop * pColDrop)
06295 
06296     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
06297     Created:    8/2/95
06298     Purpose:    Applies a colour to a specific Fill Control Point.
06299 
06300 ********************************************************************************************/
06301 
06302 BOOL AttrLinearFill::ChangeControlColour(DocColour& Col, FillControl Cntrl,
06303                                            AttrColourDrop * pColDrop)
06304 {
06305     return AttrFillGeometry::ChangeControlColour(Col, Cntrl, pColDrop);
06306     
06307 }
06308 
06309 
06310 
06311 
06312 /********************************************************************************************
06313 
06314 >   void AttrLinearFill::RenderFillMesh(RenderRegion* pRender, 
06315                                     DocCoord* ControlPoints, BOOL* SelState,
06316                                     INT32 NumControlPoints)
06317     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06318     Created:    24/7/94
06319     Inputs:     pRender - The region to render the blobs to.
06320                 ControlPoints - The positions of all the control points
06321                 SelState - The selection state of the control points
06322                 NumControlPoints - The Number of control points.
06323     Purpose:    Renders the grad fills mesh during a drag op.
06324                 Don't call this, call RenderFillBlobs().
06325     SeeAlso:    AttrLinearFill::RenderFillBlobs
06326 
06327 ********************************************************************************************/
06328 
06329 void AttrLinearFill::RenderFillMesh(RenderRegion* pRender, 
06330                                     DocCoord* ControlPoints, BOOL* SelState,
06331                                     INT32 NumControlPoints)
06332 {
06333 #if !defined(EXCLUDE_FROM_RALPH)
06334     if (AllowRampRedraw == FALSE)
06335     {
06336         FillRamp *pRamp = GetFillRamp();
06337         if (pRamp)
06338         {
06339             pRamp->RenderSelectedBlob (ATTRVALUE(), pRender);
06340         }
06341         
06342         return;
06343     }
06344     
06345     DocCoord Start = ControlPoints[FILLCONTROL_STARTPOINT];
06346     DocCoord End   = ControlPoints[FILLCONTROL_ENDPOINT];
06347 
06348     if (Start == End)
06349         return;
06350 
06351     if (SelState == NULL)
06352     {
06353         // If no selection state passed in, then assume
06354         // all the points are deselected
06355         BOOL Selected[NUMCONTROLPOINTS];
06356         for (INT32 i=0; i< NumControlPoints; i++)
06357         {
06358             Selected[i] = FALSE;
06359         }
06360         SelState = Selected;
06361     }
06362 
06363     // Remember what attributes were here before
06364     pRender->SaveContext();
06365 
06366     // Get the current blob size in Doc Units
06367     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
06368 
06369     // Calculate the Arrow on the End of the Line
06370     Path ArrowPath;
06371     ArrowPath.Initialise();
06372     DocCoord LineEnd;
06373     MakeMeshArrow(&ArrowPath, Start, End, &LineEnd);
06374     // This will have also calculated a point for us to draw
06375     // the line to, so we don't try and draw though the arrow head.
06376 
06377     // Set the line colours etc as we need them
06378     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
06379     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
06380 
06381     // First Draw a Line from the Start Point to the End point,
06382     // minus a bit to allow for the Arrow head on the end.
06383     pRender->SetLineWidth(BlobSize/4);
06384     pRender->DrawLine(Start, LineEnd);
06385 
06386     // Render an Arrow at the end of the line
06387     pRender->SetLineWidth(0);
06388     pRender->SetLineColour(COLOUR_NONE);
06389     pRender->DrawPath(&ArrowPath);
06390 
06391     // Now Render the blobs on the path
06392 
06393     // Draw a blob at the start point
06394     if (SelState[FILLCONTROL_STARTPOINT])
06395     {
06396         // Draw Selected Blob
06397 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
06398         pRender->SetLineColour(COLOUR_NONE);
06399         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
06400         pRender->DrawBlob(Start, BT_SELECTED);
06401     }
06402     else
06403     {
06404         // Draw Unselected Blob
06405 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
06406         pRender->SetLineColour(COLOUR_NONE);
06407         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
06408         pRender->DrawBlob(Start, BT_UNSELECTED);
06409     }
06410 
06411     // Draw a blob at the end point
06412     if (SelState[FILLCONTROL_ENDPOINT])
06413     {
06414         // Draw Selected Blob
06415         pRender->SetLineColour(COLOUR_SELECTEDBLOB);
06416         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
06417         pRender->DrawBlob(End, BT_SELECTED);
06418     }
06419     else
06420     {
06421         // Draw Unselected Blob
06422 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
06423         pRender->SetLineColour(COLOUR_NONE);
06424         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
06425         pRender->DrawBlob(End, BT_UNSELECTED);
06426     }
06427 
06428     // now render any ramp blobs
06429     FillRamp *pRamp = GetFillRamp();
06430     if (pRamp)
06431     {
06432         pRamp->RenderRampBlobs(ATTRVALUE(), pRender, NULL);
06433     }
06434 
06435     // Put all the old attributes back
06436     pRender->RestoreContext();
06437 #endif
06438 }
06439 
06440 
06441 /********************************************************************************************
06442 
06443 >   void AttrFillGeometry::DrawEndBlobs()
06444 
06445     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06446     Created:    25/1/95
06447     Purpose:    Draws the blobs on the ends of the fill arrows.
06448 
06449 ********************************************************************************************/
06450 
06451 void AttrFillGeometry::DrawEndBlobs()
06452 {
06453 }
06454 
06455 /********************************************************************************************
06456 
06457 >   void AttrLinearColourFill::RenderFillBlobs(RenderRegion* pRender)
06458 
06459     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06460     Created:    8/8/94
06461     Inputs:     pRender - The region to render the blobs to.
06462     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
06463 
06464 ********************************************************************************************/
06465 
06466 void AttrLinearColourFill::RenderFillBlobs(RenderRegion* pRender)
06467 {
06468 #if !defined(EXCLUDE_FROM_RALPH)
06469     if (!IsVisible())
06470         return;     // We're in Fill Transparency Mode
06471 
06472     // Don't bother if this fill is being edited as a copy of it
06473     // we be rendered thoughout the drag op
06474     if (IsFillBeingEdited())
06475         return;
06476 
06477     // Ignore this if the mesh is the same as the last one rendered.
06478     if (CheckPreviousFillMesh())
06479         return;
06480 
06481     DocCoord ControlPoints[2];
06482     ControlPoints[0] = (*GetStartPoint());
06483     ControlPoints[1] = (*GetEndPoint());
06484 
06485     // Render a nice pretty Fill Mesh thingy
06486     RenderFillMesh(pRender, ControlPoints, SelectionState, 2);
06487 
06488     // This call was removed by Gerry (2/9/96) as it causes blob problems
06489     // If we are removing blobs then force all blobs to be deselected
06490 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
06491 //      DeselectAllNoRedraw();
06492 #endif
06493 }
06494 
06495 /********************************************************************************************
06496 
06497 >   void AttrLinearTranspFill::RenderFillBlobs(RenderRegion* pRender)
06498 
06499     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06500     Created:    8/8/94
06501     Inputs:     pRender - The region to render the blobs to.
06502     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
06503 
06504 ********************************************************************************************/
06505 
06506 void AttrLinearTranspFill::RenderFillBlobs(RenderRegion* pRender)
06507 {
06508 #if !defined(EXCLUDE_FROM_RALPH)
06509     if (!IsVisible())
06510         return;     // We're Not in Fill Transparency Mode
06511 
06512     // Don't bother if this fill is being edited as a copy of it
06513     // we be rendered thoughout the drag op
06514     if (IsFillBeingEdited())
06515         return;
06516 
06517     // Ignore this if the mesh is the same as the last one rendered.
06518     if (CheckPreviousFillMesh())
06519         return;
06520 
06521     DocCoord ControlPoints[2];
06522     ControlPoints[0] = (*GetStartPoint());
06523     ControlPoints[1] = (*GetEndPoint());
06524 
06525     // Render a nice pretty Fill Mesh thingy
06526     RenderFillMesh(pRender, ControlPoints, SelectionState, 2);
06527 
06528     // This call was removed by Gerry (2/9/96) as it causes blob problems
06529     // If we are removing blobs then force all blobs to be deselected
06530 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
06531 //      DeselectAllNoRedraw();
06532 #endif
06533 }
06534 
06535 /********************************************************************************************
06536 
06537 >   void AttrLinearFill::ValidateAttributeValue()
06538 
06539     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06540     Created:    11/8/94
06541     Purpose:    Makes sure the Coords of the Fill are sensible.
06542 
06543 ********************************************************************************************/
06544 
06545 void AttrLinearFill::ValidateAttributeValue()
06546 {
06547 #if !defined(EXCLUDE_FROM_RALPH)
06548     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0))
06549         return;
06550 
06551     // Make some defaults
06552     DocRect AttrBounds = DocRect(0,0,0,0);
06553 
06554     INT32 Width  = DEFAULT_FILLWIDTH;
06555     INT32 Height = DEFAULT_FILLHEIGHT;
06556 
06557     // Are we an Orphan ?
06558     if (FindParent() != NULL)
06559     {
06560         // Nope, so we can use Daddies Bounding Box
06561         SelRange* Selected = GetApplication()->FindSelection();
06562                  
06563         if (Selected == NULL || Selected->Count() <= 1)
06564             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
06565         else
06566             AttrBounds = Selected->GetBoundingRect();
06567 
06568         Width  = AttrBounds.Width();
06569         Height = AttrBounds.Height();
06570     }
06571 
06572     // If the StartPoint is 'NULL' then make all points sensible
06573     if ((*GetStartPoint()) == DocCoord(0,0))
06574     {
06575         // Start in the middle
06576         DocCoord temp = CentreOf(AttrBounds); 
06577         SetStartPoint(&temp);
06578 
06579         // End on the Middle Right
06580         temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
06581         SetEndPoint(&temp);
06582     }
06583 
06584     // If the EndPoint is 'NULL' then make end points sensible
06585     if ((*GetEndPoint()) == DocCoord(0,0))
06586     {
06587         DocCoord temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
06588         SetEndPoint(&temp);
06589     }
06590 
06591     if ((*GetEndPoint2()) == DocCoord(0,0))
06592     {
06593         DocCoord temp = MakeLineAtAngle(*GetStartPoint(), *GetEndPoint(), 90);
06594         SetEndPoint2(&temp);
06595     }
06596 #endif
06597 }
06598 
06600 //
06601 //                              AttrLinearColourFill
06602 //
06604 
06605 /********************************************************************************************
06606 
06607     void AttrLinearColourFill::Render( RenderRegion* pRender)
06608 
06609     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06610     Created:    23/8/94
06611     Purpose:    'Renders' a Linear Fill Colour attribute.
06612 
06613 ********************************************************************************************/
06614 
06615 void AttrLinearColourFill::Render(RenderRegion* pRender)
06616 {
06617     pRender->SetFillGeometry(&Value, FALSE);
06618 }
06619 
06620 /********************************************************************************************
06621 
06622 > Node* AttrLinearColourFill::SimpleCopy() 
06623 
06624     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06625     Created:    23/8/94
06626     Returns:    A copy of the node, or NULL if memory runs out 
06627     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
06628                 The function is virtual, and must be defined for all derived classes.  
06629     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
06630                 memory error and the function returns NULL. 
06631     Scope:      protected       
06632 
06633 ********************************************************************************************/
06634      
06635 Node* AttrLinearColourFill::SimpleCopy()
06636 {
06637     AttrLinearColourFill* NodeCopy = new AttrLinearColourFill();
06638     if (NodeCopy == NULL)
06639         return NULL;
06640 
06641     CopyNodeContents(NodeCopy);
06642     
06643     return NodeCopy;
06644 }  
06645 
06646 /********************************************************************************************
06647 
06648 >   virtual UINT32 AttrLinearColourFill::GetAttrNameID(void)  
06649 
06650     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06651     Created:    23/8/94
06652     Returns:    Attribute description ID
06653     Purpose:    Returns a string resource ID describing the attribute
06654 
06655 ********************************************************************************************/
06656 
06657 UINT32 AttrLinearColourFill::GetAttrNameID(void)  
06658 {
06659     return (_R(IDS_LINEARGRADFILL)); 
06660 }                                  
06661 
06662 /********************************************************************************************
06663 
06664 >   void AttrLinearColourFill::GetDebugDetails(StringBase* Str)
06665 
06666     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06667     Created:    20/07/94
06668     Outputs:    Str - the string containing details of the attribute.
06669     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
06670 
06671 ********************************************************************************************/
06672 
06673 void AttrLinearColourFill::GetDebugDetails(StringBase* Str)
06674 {
06675 #ifdef _DEBUG
06676     NodeAttribute::GetDebugDetails( Str );
06677 
06678     String_256 TempStr;
06679 
06680     TempStr._MakeMsg( TEXT("\r\nLinear Graduated Fill:\r\n"));
06681     (*Str) += TempStr;
06682 
06683 //  TempStr._MakeMsg(TEXT("\r\nStart"));
06684 //  (*GetStartColour()).GetDebugDetails(&TempStr);
06685 //  (*Str) += TempStr;
06686 
06687 //  TempStr._MakeMsg(TEXT("\r\nEnd"));
06688 //  (*GetEndColour()).GetDebugDetails(&TempStr);
06689 //  (*Str) += TempStr;
06690 
06691     TempStr._MakeMsg(TEXT("\r\nStart point =(#1%ld, #2%ld)"), 
06692                      (*GetStartPoint()).x, (*GetStartPoint()).y);
06693     (*Str) += TempStr;
06694 
06695     TempStr._MakeMsg(TEXT("\r\nEnd point =(#1%ld, #2%ld), "), 
06696                      (*GetEndPoint()).x, (*GetEndPoint()).y);
06697     (*Str) += TempStr;
06698 
06699     for (INT32 i=0; i<5; i++)
06700     {
06701         TempStr._MakeMsg(TEXT("\r\nControl #1%ld = #2%ld"),
06702                          i, SelectionState[i]);
06703         (*Str) += TempStr;
06704     }
06705 #endif
06706 }
06707 
06708 
06709 /********************************************************************************************
06710 
06711 >   virtual UINT32 AttrLinearColourFill::GetNodeSize() const
06712 
06713     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06714     Created:    23/8/94
06715     Returns:    The size of the node in bytes
06716     Purpose:    For finding the size of the node.
06717     SeeAlso:    Node::GetSubtreeSize
06718 
06719 ********************************************************************************************/
06720 
06721 UINT32 AttrLinearColourFill::GetNodeSize() const 
06722 {     
06723     return sizeof(AttrLinearColourFill);
06724 }  
06725 
06726 
06727 
06728 /********************************************************************************************
06729 
06730   > virtual BOOL AttrLinearColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
06731 
06732     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
06733     Created:    25/6/96
06734     Inputs:     pFilter = ptr to the filter
06735     Returns:    TRUE if record is written, FALSE if not
06736     Purpose:    Writes the linear fill record to the filter
06737     SeeAlso:    -
06738 
06739 ********************************************************************************************/
06740 
06741 BOOL AttrLinearColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
06742 {
06743 #ifdef DO_EXPORT
06744     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
06745 
06746     // Must write out the colours first
06747     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
06748     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
06749 
06750     // am I a multistage fill ??
06751     BOOL bMultistage = FALSE;
06752 
06753     ColourRamp * pRamp = GetColourRamp();
06754     INT32 * pRampColRefs = NULL;
06755     double * pPositions = NULL;
06756     ColRampItem * pItem = NULL;
06757     UINT32 NumRampItems = 0;
06758 
06759     if (pRamp)
06760     {
06761         // write out all the colour references
06762         if (pRamp->GetCount() > 0)
06763         {
06764             bMultistage = TRUE;
06765             NumRampItems = pRamp->GetCount();
06766 
06767             pRampColRefs = new INT32[NumRampItems];
06768             pPositions   = new double[NumRampItems];
06769 
06770             pItem = (ColRampItem *)pRamp->GetHead();
06771 
06772             for (UINT32 i = 0 ; i < NumRampItems; i++)
06773             {
06774                 if (pItem)
06775                 {
06776                     pPositions[i]   = pItem->GetPosition();
06777                     DocColour tempcolour = pItem->GetColour();
06778                     pRampColRefs[i] = pFilter->WriteRecord(&tempcolour);
06779                 }
06780 
06781                 pItem = (ColRampItem *)pRamp->GetNext(pItem);
06782             }
06783         }
06784     }
06785 
06786     // Are the colour references ok?
06787     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
06788 
06789     // If the linear fill points are not perpendicular then we must write
06790     // a new 3-point linear fill record...
06791     BOOL b3PointLinear = (!AreLinesPerpendicular(GetStartPoint(), GetEndPoint(), GetEndPoint2()));
06792 
06793     if (ok)
06794     {
06795         if (!bMultistage)
06796         {
06797             INT32 tag = TAG_LINEARFILL;
06798             UINT32 size = TAG_LINEARFILL_SIZE;
06799             if (b3PointLinear)
06800             {
06801                 tag = TAG_LINEARFILL3POINT;
06802                 size = TAG_LINEARFILL3POINT_SIZE;
06803             }
06804 
06805             CamelotFileRecord Rec(pFilter, tag, size);
06806             
06807             if (ok) ok = Rec.Init();
06808             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
06809             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
06810             if (ok && b3PointLinear) ok = Rec.WriteCoord(Value.EndPoint2);
06811             if (ok) ok = Rec.WriteReference(StartColRef);
06812             if (ok) ok = Rec.WriteReference(EndColRef);
06813             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
06814             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
06815             if (ok) ok = pFilter->Write(&Rec);
06816         }
06817         else
06818         {
06819             INT32 tag = TAG_LINEARFILLMULTISTAGE;
06820             INT32 size = TAG_LINEARFILLMULTISTAGE_SIZE;
06821             if (b3PointLinear)
06822             {
06823                 tag = TAG_LINEARFILLMULTISTAGE3POINT;
06824                 size = TAG_LINEARFILLMULTISTAGE3POINT_SIZE;
06825             }
06826 
06827             CamelotFileRecord Rec(pFilter, tag, size);
06828             
06829             if (ok) ok = Rec.Init();
06830             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
06831             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
06832             if (ok && b3PointLinear) ok = Rec.WriteCoord(Value.EndPoint2);
06833             if (ok) ok = Rec.WriteReference(StartColRef);
06834             if (ok) ok = Rec.WriteReference(EndColRef);
06835 
06836             // now, write out all the colour ramp items
06837             if (ok) ok = Rec.WriteUINT32(NumRampItems);
06838 
06839             for (UINT32 i = 0 ; i < NumRampItems; i++)
06840             {
06841                 if (ok) ok = Rec.WriteDOUBLE(pPositions[i]);
06842                 if (ok) ok = Rec.WriteReference(pRampColRefs[i]);
06843             }
06844 
06845             if (ok) ok = pFilter->Write(&Rec);
06846         }
06847     }
06848 
06849     if (pRampColRefs)
06850         delete [] pRampColRefs;
06851 
06852     if (pPositions)
06853         delete [] pPositions;
06854 
06855     if (!ok)
06856         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
06857 
06858     return ok;
06859 #else
06860     return FALSE;
06861 #endif
06862 }
06863 
06864 //--------------------------------------------------------------
06865 // See AttrDashPatternAttrLinearColourFillWritePreChildrenWeb(BaseCamelotFilter* pFilter)
06866 //
06867 BOOL AttrLinearColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
06868 {
06869 #ifdef DO_EXPORT
06870     return WritePreChildrenWeb(pFilter);
06871 #else
06872     return FALSE;
06873 #endif
06874 }
06875 
06876 
06877 /********************************************************************************************
06878 
06879   > virtual BOOL AttrLinearColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
06880 
06881     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
06882     Created:    14/9/2000
06883     Inputs:     pFilter = ptr to the filter
06884     Returns:    TRUE if record is written, FALSE if not
06885     Purpose:    Writes out colour definitions for this fill.
06886     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
06887                 Layer::WriteAtomicNodesColourRefs ()
06888 
06889 ********************************************************************************************/
06890 
06891 BOOL AttrLinearColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
06892 {
06893     // Must write out the colours first
06894     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
06895     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
06896 
06897     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
06898 
06899     if (ok)
06900     {
06901         ColourRamp * pRamp = GetColourRamp();
06902         if (pRamp)
06903         if (pRamp->GetCount() > 0)
06904         {
06905             ok = pRamp->WriteColourDefinitions (pFilter);
06906         }
06907     }
06908     
06909     return (ok);
06910 }
06911 
06913 //
06914 //                              AttrLinearTranspFill
06915 //
06917 
06918 /********************************************************************************************
06919 
06920 >   void AttrLinearTranspFill::Render( RenderRegion* pRender)
06921 
06922     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06923     Created:    23/8/94
06924     Purpose:    'Renders' a Linear Fill Colour attribute.
06925 
06926 ********************************************************************************************/
06927 
06928 void AttrLinearTranspFill::Render(RenderRegion* pRender)
06929 {
06930     pRender->SetTranspFillGeometry(&Value, FALSE);
06931 }
06932 
06933 /********************************************************************************************
06934 
06935 > Node* AttrLinearTranspFill::SimpleCopy() 
06936 
06937     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06938     Created:    23/8/94
06939     Returns:    A copy of the node, or NULL if memory runs out 
06940     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
06941                 The function is virtual, and must be defined for all derived classes.  
06942     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
06943                 memory error and the function returns NULL. 
06944     Scope:      protected       
06945 
06946 ********************************************************************************************/
06947      
06948 Node* AttrLinearTranspFill::SimpleCopy()
06949 {
06950     AttrLinearTranspFill* NodeCopy = new AttrLinearTranspFill();
06951     if (NodeCopy == NULL)
06952         return NULL;
06953 
06954     CopyNodeContents(NodeCopy);
06955     
06956     return NodeCopy;
06957 }  
06958 
06959 /********************************************************************************************
06960 
06961 >   virtual UINT32 AttrLinearTranspFill::GetAttrNameID(void)  
06962 
06963     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06964     Created:    23/8/94
06965     Returns:    Attribute description ID
06966     Purpose:    Returns a string resource ID describing the attribute
06967 
06968 ********************************************************************************************/
06969 
06970 UINT32 AttrLinearTranspFill::GetAttrNameID(void)  
06971 {
06972     return (_R(IDS_LINEARTRANSPFILL)); 
06973 }                                  
06974 
06975 /********************************************************************************************
06976 
06977 >   void AttrLinearTranspFill::GetDebugDetails(StringBase* Str)
06978 
06979     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
06980     Created:    20/07/94
06981     Outputs:    Str - the string containing details of the attribute.
06982     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
06983 
06984 ********************************************************************************************/
06985 
06986 void AttrLinearTranspFill::GetDebugDetails(StringBase* Str)
06987 {
06988 #ifdef _DEBUG
06989     NodeAttribute::GetDebugDetails( Str );
06990 
06991     String_256 TempStr;
06992 
06993     TempStr._MakeMsg( TEXT("\r\nLinear Graduated Transp:\r\n"));
06994     (*Str) += TempStr;
06995 
06996     TempStr._MakeMsg(TEXT("\r\nStart = #1%u"), *GetStartTransp() );
06997     (*Str) += TempStr;
06998 
06999     TempStr._MakeMsg(TEXT("\r\nEnd = #1%u"), *GetEndTransp() );
07000     (*Str) += TempStr;
07001 
07002     TempStr._MakeMsg(TEXT("\r\nStart point =(#1%ld, #2%ld)"), 
07003                      (*GetStartPoint()).x, (*GetStartPoint()).y);
07004     (*Str) += TempStr;
07005 
07006     TempStr._MakeMsg(TEXT("\r\nEnd point =(#1%ld, #2%ld), "), 
07007                      (*GetEndPoint()).x, (*GetEndPoint()).y);
07008     (*Str) += TempStr;
07009 #endif
07010 }
07011 
07012 
07013 /********************************************************************************************
07014 
07015 >   virtual UINT32 AttrLinearTranspFill::GetNodeSize() const
07016 
07017     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07018     Created:    23/8/94
07019     Returns:    The size of the node in bytes
07020     Purpose:    For finding the size of the node.
07021     SeeAlso:    Node::GetSubtreeSize
07022 
07023 ********************************************************************************************/
07024 
07025 UINT32 AttrLinearTranspFill::GetNodeSize() const 
07026 {     
07027     return sizeof(AttrLinearTranspFill);
07028 }  
07029 
07030 
07031 
07032 /********************************************************************************************
07033 
07034   > virtual BOOL AttrLinearTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
07035 
07036     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
07037     Created:    26/6/96
07038     Inputs:     pFilter = ptr to the filter
07039     Returns:    TRUE if record is written, FALSE if not
07040     Purpose:    Writes the linear transparent fill record to the filter
07041     SeeAlso:    -
07042 
07043 ********************************************************************************************/
07044 
07045 BOOL AttrLinearTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
07046 {
07047 #ifdef DO_EXPORT
07048     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
07049     ERROR3IF(Value.Transp     > 255,"Start transparency level is too high to be stored as a byte");
07050     ERROR3IF(Value.EndTransp  > 255,"End transparency level is too high to be stored as a byte");
07051     ERROR3IF(Value.TranspType > 255,"Transparency type is too high to be stored as a byte");
07052 
07053     BOOL ok = TRUE;
07054 
07055     // If the linear fill points are not perpendicular then we must write
07056     // a new 3-point linear fill record...
07057     BOOL b3PointLinear = (!AreLinesPerpendicular(GetStartPoint(), GetEndPoint(), GetEndPoint2()));
07058 
07059     INT32 tag = TAG_LINEARTRANSPARENTFILL;
07060     UINT32 size = TAG_LINEARTRANSPARENTFILL_SIZE;
07061     if (b3PointLinear)
07062     {
07063         tag = TAG_LINEARTRANSPARENTFILL3POINT;
07064         size = TAG_LINEARTRANSPARENTFILL3POINT_SIZE;
07065     }
07066 
07067     CamelotFileRecord Rec(pFilter, tag, size);
07068 
07069     if (ok) ok = Rec.Init();
07070     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
07071     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
07072     if (ok && b3PointLinear) ok = Rec.WriteCoord(Value.EndPoint2);
07073     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
07074     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));
07075     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
07076     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
07077     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
07078     if (ok) ok = pFilter->Write(&Rec);
07079 
07080     if (!ok)
07081         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
07082 
07083     return ok;
07084 #else
07085     return FALSE;
07086 #endif
07087 }
07088 
07089 //--------------------------------------------------------------
07090 // See AttrDashPatternAttrLinearTranspFillWritePreChildrenWeb(BaseCamelotFilter* pFilter)
07091 //
07092 BOOL AttrLinearTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
07093 {
07094 #ifdef DO_EXPORT
07095     return WritePreChildrenWeb(pFilter);
07096 #else
07097     return FALSE;
07098 #endif
07099 }
07100 
07101 
07102 /********************************************************************************************
07103 >   BOOL AttrLinearTranspFill::HasEquivalentDefaultValue(BOOL bAppearance = FALSE)
07104 
07105     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
07106     Created:    11/05/2005
07107     Inputs:     -
07108     Outputs:    -
07109     Returns:    TRUE if this node has a value equivalent to the relevant 
07110                 FALSE otherwise
07111     Purpose:    Determine whether this attribute has the default value or not
07112     Errors:     -
07113     SeeAlso:    -
07114 ********************************************************************************************/
07115 
07116 BOOL AttrLinearTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
07117 {
07118     // Slight bodge - we will assume that the default transparency is fully opaque
07119     if (bAppearance)
07120         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0));
07121     else
07122         return FALSE;
07123 }
07124 
07125 
07126 
07127 
07129 //
07130 //                              AttrRadialFill
07131 //
07133 
07134 /********************************************************************************************
07135 
07136 >   void AttrRadialFill::Transform( TransformBase& Trans )
07137 
07138     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07139     Created:    23/8/94
07140     Inputs:     Trans - the transform object to apply to this attribute.
07141     Purpose:    Transform a grad fill attribute by moving the start and end points.
07142     SeeAlso:    NodeRenderable::Transform
07143 
07144 ********************************************************************************************/
07145 
07146 void AttrRadialFill::Transform( TransformBase& Trans )
07147 {
07148     if ( Trans.TransFills )
07149     {
07150         Trans.Transform( GetStartPoint(), 1);
07151         Trans.Transform( GetEndPoint(), 1);
07152         Trans.Transform( GetEndPoint2(), 1);
07153         
07154         if (IsPerspective())
07155             Trans.Transform( GetEndPoint3(), 1);
07156 
07157         // Ensure the transformed Points are sensible
07158         if (IsCircular() &&
07159             (!AreLinesPerpendicular(GetStartPoint(), GetEndPoint(), GetEndPoint2()) ||
07160             ( ABS( (*GetStartPoint()).Distance(*GetEndPoint()) 
07161                                 - (*GetStartPoint()).Distance(*GetEndPoint2()) ) ) > 5 ))
07162         {
07163             // Oh dear we're not circular any more !!
07164             MakeElliptical();
07165         }
07166     }
07167 }
07168 
07169 /********************************************************************************************
07170 
07171 >   BOOL AttrRadialFill::CanTransform()
07172 
07173     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07174     Created:    23/8/94
07175     Returns:    TRUE => transform this attribute.
07176     Purpose:    Indicate that this attribute can be transformed.
07177     SeeAlso:    NodeRenderable::CanTransform
07178 
07179 ********************************************************************************************/
07180 
07181 BOOL AttrRadialFill::CanTransform()
07182 {
07183     return TRUE;
07184 }
07185 
07186 
07187 /*********************************************************************************************
07188 
07189 >    virtual BOOL AttrRadialFill::NeedsToRenderAtEachBrushStroke()
07190 
07191      Author:    Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07192      Created:   29/11/99
07193      Inputs:    -
07194      Outputs:   -
07195      Returns:   TRUE if this attribute should be rendered at every step of a brush stroke
07196      Purpose:   So that don't have to keep re-rendering attributes whilst drawing a brush, this
07197                 identifies whether or not the attribute need to be rendered at each step, 
07198                 e.g. radial fills.
07199      Errors:    
07200      See Also;  Brush code (ndbrshmk.cpp)
07201 
07202 **********************************************************************************************/
07203        
07204 BOOL AttrRadialFill::NeedsToRenderAtEachBrushStroke() const
07205 {
07206     return TRUE;
07207 }
07208 
07209 /********************************************************************************************
07210 
07211 >   virtual void AttrRadialFill::OnControlDrag( DocCoord Pos, FillControl DragControl, 
07212                                                     ClickModifiers ClickMods)
07213     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07214     Created:    2/8/94
07215     Inputs:     Pos - The Location of the mouse pointer at the time of the call
07216                 DragControl - The FillControl that is being dragged.
07217                 ClickMods - The modifiers to the click (eg shift, control etc )
07218     Purpose:    Called when an edit operation is dragging a control point.
07219 
07220 ********************************************************************************************/
07221 
07222 void AttrRadialFill::OnControlDrag( DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
07223 {
07224 #if !defined(EXCLUDE_FROM_RALPH)
07225     // Get the current Control Positions
07226     DocCoord StartPoint = *GetStartPoint();
07227     DocCoord EndPoint = *GetEndPoint();
07228     DocCoord EndPoint2 = *GetEndPoint2();
07229 
07230     INT32 dx, dy;
07231 
07232     // Which control point is being dragged ?
07233     switch (DragControl)
07234     {
07235         case FILLCONTROL_STARTPOINT:
07236         
07237             // Someone is dragging the Centre of the Fill
07238             dx = StartPoint.x - Pos.x;
07239             dy = StartPoint.y - Pos.y;
07240             // Move the other points relative
07241             EndPoint.translate(-dx, -dy);
07242             EndPoint2.translate(-dx, -dy);
07243 
07244             SetEndPoint(&EndPoint);
07245             SetEndPoint2(&EndPoint2);
07246             SetStartPoint(&Pos);
07247             break;
07248 
07249         case FILLCONTROL_ENDPOINT:
07250             
07251             // Someone is dragging the first End Point
07252             
07253             // Constrain the angle if necessary
07254             if (ClickMods.Constrain)
07255                 DocView::ConstrainToAngle(StartPoint, &Pos);
07256 
07257             // The Aspect ratio can be locked either by it being circular
07258             // or by the Shift key      
07259             if (IsCircular() || ClickMods.Adjust)
07260             {
07261                 double OldLen = StartPoint.Distance(EndPoint);
07262                 double NewLen = StartPoint.Distance(Pos);
07263                 double Ratio = 1.0;
07264 
07265                 if (OldLen == 0)
07266                     Ratio = 0;
07267                 else
07268                     Ratio = NewLen/OldLen;
07269 
07270                 // Calculate the new end point based on the aspect ratio
07271                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, 90, INT32(StartPoint.Distance(EndPoint2) * Ratio));
07272                 SetEndPoint2(&temp);
07273             }
07274             else
07275             {
07276                 // Aspect ratio is not locked, so maintain the old line length
07277                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, 90, INT32(StartPoint.Distance(EndPoint2)));
07278                 SetEndPoint2(&temp);
07279             }
07280 
07281             SetEndPoint(&Pos);
07282             break;
07283 
07284         case FILLCONTROL_SECONDARYPOINT:
07285 
07286             // Someone is dragging the second End Point
07287             
07288             // Constrain the angle if necessary
07289             if (ClickMods.Constrain)
07290                 DocView::ConstrainToAngle(StartPoint, &Pos);
07291 
07292             // The Aspect ratio can be locked either by it being circular
07293             // or by the Shift key      
07294             if (IsCircular() || ClickMods.Adjust)
07295             {
07296                 double OldLen = StartPoint.Distance(EndPoint2);
07297                 double NewLen = StartPoint.Distance(Pos);
07298                 double Ratio = 1.0;
07299 
07300                 if (OldLen == 0)
07301                     Ratio = 0;
07302                 else
07303                     Ratio = NewLen/OldLen;
07304 
07305                 // Calculate the new end point based on the aspect ratio
07306                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, -90, INT32(StartPoint.Distance(EndPoint) * Ratio));
07307                 SetEndPoint(&temp);
07308             }
07309             else
07310             {
07311                 // Aspect ratio is not locked, so maintain the old line length
07312                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, -90, INT32(StartPoint.Distance(EndPoint)));
07313                 SetEndPoint(&temp);
07314             }
07315 
07316             SetEndPoint2(&Pos);
07317             break;
07318         default:
07319             // check for dragging a ramp point
07320             if (ISA_RAMPINDEX(DragControl))
07321             {
07322                 AttrFillGeometry::OnControlDrag( Pos, DragControl, ClickMods);
07323             }
07324             break;
07325     }
07326 #endif
07327 }
07328 
07329 /********************************************************************************************
07330 
07331 >   void AttrRadialFill::ValidateAttributeValue()
07332 
07333     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07334     Created:    11/8/94
07335     Purpose:    Makes sure the Coords of the Fill are sensible.
07336 
07337 ********************************************************************************************/
07338 
07339 void AttrRadialFill::ValidateAttributeValue()
07340 {
07341 #if !defined(EXCLUDE_FROM_RALPH)
07342     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0))
07343     {
07344         // If the EndPoint2 is 'NULL' then make it sensible
07345         if (*GetEndPoint2() == DocCoord(0,0))
07346         {
07347             DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90);
07348             SetEndPoint2(&temp);
07349             return;
07350         }
07351         
07352 //      if (IsElliptical())
07353 //      {
07354 //          SetEndPoint2(&MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90, 
07355 //                              INT32((*GetStartPoint()).Distance((*GetEndPoint2())))));
07356 //      }
07357 //      else
07358         if (IsCircular())
07359         {
07360             // This must be a Circle, so make sure EndPoint2 is on the same
07361             // radius as the other endpoint
07362             DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90);
07363             SetEndPoint2(&temp);
07364         }
07365 
07366         return;
07367     }
07368 
07369     // Make up some sensible defaults
07370     DocRect AttrBounds = DocRect(0,0,0,0);
07371 
07372     INT32 Width  = DEFAULT_FILLWIDTH;
07373     INT32 Height = DEFAULT_FILLHEIGHT;
07374 
07375     // Are we an Orphan ?
07376     if (FindParent() != NULL)
07377     {
07378         // Nope, so we can use Daddies Bounding Box
07379         SelRange* Selected = GetApplication()->FindSelection();
07380                  
07381         if (Selected == NULL || Selected->Count() <= 1)
07382             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
07383         else
07384             AttrBounds = Selected->GetBoundingRect();
07385 
07386         Width  = AttrBounds.Width();
07387         Height = AttrBounds.Height();
07388     }
07389 
07390     // If the StartPoint is 'NULL' then make all points sensible
07391     if ((*GetStartPoint()) == DocCoord(0,0))
07392     {
07393         // Start in the centre of the bounds
07394         DocCoord temp = CentreOf(AttrBounds);
07395         SetStartPoint(&temp);
07396         // and set End Points to Middle Right, and Middle Top
07397         temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
07398         SetEndPoint(&temp);
07399         temp = DocCoord((*GetStartPoint()).x, (*GetStartPoint()).y + (Height/2));
07400         SetEndPoint2(&temp);
07401     }
07402 
07403     // If the EndPoint is 'NULL' then make end points sensible
07404     if ((*GetEndPoint()) == DocCoord(0,0))
07405     {
07406         DocCoord temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
07407         SetEndPoint(&temp);
07408         temp = DocCoord((*GetStartPoint()).x, (*GetStartPoint()).y + (Height/2));
07409         SetEndPoint2(&temp);
07410     }
07411 
07412     if ((*GetEndPoint2()) == DocCoord(0,0))
07413     {
07414         DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90, Height/2);
07415         SetEndPoint2(&temp);
07416     }
07417 
07418     if (IsCircular())
07419     {
07420         DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()));
07421         SetEndPoint2(&temp);
07422     }
07423 #endif
07424 }
07425 
07426 /********************************************************************************************
07427 
07428 >   virtual DocRect AttrRadialFill::GetBlobBoundingRect()
07429 
07430     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07431     Created:    28/7/94
07432     Returns:    DocRect - The rectangle that contains all the nodes selection blobs.
07433     Purpose:    Calculates the bounding rectangle of the attrs blobs.This should always 
07434                 be calculated on the fly as the view scale can change without the attr 
07435                 knowing, giving an incorrect result.
07436 
07437 ********************************************************************************************/
07438 
07439 DocRect AttrRadialFill::GetBlobBoundingRect()
07440 {
07441 #if !defined(EXCLUDE_FROM_RALPH)
07442     // Optimisation.  If there is currently no interest in Fill Blobs
07443     // and this fill is not being Dragged (Fill blobs are turned off during
07444     // a fill drag), then we needn't bother doing anything. 
07445     if ( (!GetApplication()->GetBlobManager()->GetCurrentInterest(TRUE).Fill || !IsVisible()) && DraggedFill != this )
07446         return DocRect(0,0, 0,0);
07447 
07448     // Get the Start and End Points
07449     DocCoord StartPoint = *GetStartPoint();
07450     DocCoord EndPoint   = *GetEndPoint();
07451     DocCoord EndPoint2  = *GetEndPoint2();
07452 
07453     // Make a dummy bounds from just the Start Point
07454     DocRect BoundingRect(StartPoint, StartPoint);
07455 
07456     if (DraggedFill == this)
07457     {
07458         // This fill is being dragged, so we have to include the Ellipse bounding
07459         // rect as well
07460         DocRect StartBlobRect;
07461         DocRect EndBlobRect;
07462         
07463         DocRect DragRect = GetMeshEllipseBounds(StartPoint, EndPoint, EndPoint2);
07464 
07465         // Get the Bounding rect of Blobs on each of the ends
07466         (Camelot.GetBlobManager())->GetBlobRect(DragRect.lo, &StartBlobRect);
07467         (Camelot.GetBlobManager())->GetBlobRect(DragRect.hi, &EndBlobRect);
07468 
07469         // Now include the Bottom Left and Top Right of each blob in the Bounds.
07470         // We have to do it like this to make sure that the DocRect's coords
07471         // are valid.  ie. The Hi's are Higher than the Lo's.
07472         BoundingRect.IncludePoint(StartBlobRect.lo);
07473         BoundingRect.IncludePoint(StartBlobRect.hi);
07474         BoundingRect.IncludePoint(EndBlobRect.lo);
07475         BoundingRect.IncludePoint(EndBlobRect.hi);
07476     }
07477     else
07478     {
07479         // We're not being dragged, so just calc the bounds of the Start and End Blobs
07480         DocRect StartBlobRect;
07481         DocRect EndBlobRect;
07482         DocRect End2BlobRect;
07483 
07484         // Get the Bounding rect of the Fill Line, including the Blobs on the ends
07485         (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &StartBlobRect);
07486         (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &EndBlobRect);
07487         (Camelot.GetBlobManager())->GetBlobRect(EndPoint2, &End2BlobRect);
07488 
07489         // Now include the Bottom Left and Top Right of each blob in the Bounds.
07490         // We have to do it like this to make sure that the DocRect's coords
07491         // are valid.  ie. The Hi's are Higher than the Lo's.
07492         BoundingRect.IncludePoint(StartBlobRect.lo);
07493         BoundingRect.IncludePoint(StartBlobRect.hi);
07494         BoundingRect.IncludePoint(EndBlobRect.lo);
07495         BoundingRect.IncludePoint(EndBlobRect.hi);
07496         BoundingRect.IncludePoint(End2BlobRect.lo);
07497         BoundingRect.IncludePoint(End2BlobRect.hi);
07498     }
07499 
07500     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint);
07501     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint2);
07502 
07503     // and return it
07504     return BoundingRect;
07505 #else
07506     return DocRect(0,0, 0,0);
07507 #endif
07508 }
07509 
07510 /********************************************************************************************
07511 
07512 >   FillControl AttrRadialFill::CheckForControlHit(DocCoord &ClickPos)
07513 
07514     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07515     Created:    21/07/94
07516     Inputs:     ClickPos, The DocCoord position to check.
07517     Returns:    A FillControl, indicating the Fill Control Point Hit,
07518                 or FILLCONTROL_NULL, if no points hit.
07519     Purpose:    Check to see if a click was on a Fill Control Point. 
07520     SeeAlso:    FillControl
07521 
07522 ********************************************************************************************/
07523 
07524 FillControl AttrRadialFill::CheckForControlHit(DocCoord &ClickPos)
07525 {
07526 #if !defined(EXCLUDE_FROM_RALPH)
07527     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
07528         return FILLCONTROL_NULL;
07529 
07530     return AttrFillGeometry::CheckForControlHit(ClickPos);
07531 
07532     // Set up a default, that indicates not control points hit
07533     FillControl HitControl = FILLCONTROL_NULL;
07534     DocRect BlobRect;
07535 
07536     // Get the current control positions
07537     DocCoord CentrePoint  = *GetStartPoint();
07538     DocCoord EndColBlob   = *GetEndPoint();
07539     DocCoord End2ColBlob  = *GetEndPoint2();
07540 
07541     // Get the rectangle around the Centre Control Point
07542     (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &BlobRect);
07543     // See if the Click Position is within the rectangle
07544     if ( BlobRect.ContainsCoord(ClickPos) )
07545         HitControl = FILLCONTROL_STARTPOINT;
07546 
07547     // Get the rectangle around the End Control Point
07548     (Camelot.GetBlobManager())->GetBlobRect(EndColBlob, &BlobRect);
07549     // See if the Click Position is within the rectangle
07550     if ( BlobRect.ContainsCoord(ClickPos) )
07551         HitControl = FILLCONTROL_ENDPOINT;
07552 
07553     if (IsElliptical())
07554     {
07555         // Only elliptical fills have a second end point
07556         
07557         // Get the rectangle around the Senond End Control Point
07558         (Camelot.GetBlobManager())->GetBlobRect(End2ColBlob, &BlobRect);
07559         // See if the Click Position is within the rectangle
07560         if ( BlobRect.ContainsCoord(ClickPos) )
07561             HitControl = FILLCONTROL_SECONDARYPOINT;
07562     }
07563 
07564     return HitControl;
07565 #else
07566     return FILLCONTROL_NULL;
07567 #endif
07568 }
07569 
07570 /********************************************************************************************
07571 
07572 >   void AttrRadialFill::RenderFillMesh(RenderRegion* pRender, 
07573                                     DocCoord* ControlPoints, BOOL* SelState,
07574                                     INT32 NumControlPoints)
07575     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07576     Created:    24/7/94
07577     Inputs:     pRender - The region to render the blobs to.
07578                 ControlPoints - The positions of all the control points
07579                 SelState - The selection state of the control points
07580                 NumControlPoints - The Number of control points.
07581     Purpose:    Renders the grad fills mesh during a drag op.
07582                 Don't call this, call RenderFillBlobs().
07583     SeeAlso:    AttrRadialFill::RenderFillBlobs
07584 
07585 ********************************************************************************************/
07586 
07587 void AttrRadialFill::RenderFillMesh(RenderRegion* pRender, 
07588                                     DocCoord* ControlPoints, BOOL* SelState,
07589                                     INT32 NumControlPoints)
07590 {
07591 #if !defined(EXCLUDE_FROM_RALPH)
07592     if (AllowRampRedraw == FALSE)
07593     {
07594         FillRamp *pRamp = GetFillRamp();
07595         if (pRamp)
07596         {
07597             pRamp->RenderSelectedBlob (ATTRVALUE(), pRender);
07598         }
07599         
07600         return;
07601     }
07602     
07603     DocCoord Start = ControlPoints[FILLCONTROL_STARTPOINT];
07604     DocCoord End   = ControlPoints[FILLCONTROL_ENDPOINT];
07605 
07606     if (Start == End)
07607         return;
07608 
07609     if (SelState == NULL)
07610     {
07611         // If no selection state passed in, then assume
07612         // all the points are deselected
07613         BOOL Selected[NUMCONTROLPOINTS];
07614         for (INT32 i=0; i< NumControlPoints; i++)
07615         {
07616             Selected[i] = FALSE;
07617         }
07618         SelState = Selected;
07619     }
07620 
07621     DocCoord End2  = ControlPoints[FILLCONTROL_SECONDARYPOINT];
07622 
07623     // Remember what attributes were here before
07624     pRender->SaveContext();
07625 
07626     // Get the current blob size in Doc Units
07627     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
07628 
07629     // Calculate the Arrow on the End of the Line
07630     Path ArrowPath;
07631     ArrowPath.Initialise();
07632     DocCoord LineEnd;
07633     MakeMeshArrow(&ArrowPath, Start, End, &LineEnd);
07634     // This will have also calculated a point for us to draw
07635     // the line to, so we don't try and draw though the arrow head.
07636 
07637     Path ArrowPath2;
07638     DocCoord LineEnd2;
07639 
07640     if (IsElliptical())
07641     {
07642         // Calculate the Arrow on the End of the Line2
07643         ArrowPath2.Initialise();
07644         MakeMeshArrow(&ArrowPath2, Start, End2, &LineEnd2);
07645     }
07646 
07647     // Set the line colours etc as we need them
07648     pRender->SetLineWidth(0);
07649     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
07650     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
07651 
07652     // First Draw the Line
07653     pRender->SetLineWidth(BlobSize/4);
07654     pRender->DrawLine(Start, LineEnd);
07655 
07656     // Draw the secondary line if needed
07657     if (IsElliptical())
07658         pRender->DrawLine(Start, LineEnd2);
07659 
07660     // Render an Arrow at the end of the line
07661     pRender->SetLineWidth(0);
07662     pRender->SetLineColour(COLOUR_NONE);
07663     pRender->DrawPath(&ArrowPath);
07664 
07665     // Render arrow on the end of line2 if its there
07666     if (IsElliptical())
07667         pRender->DrawPath(&ArrowPath2);
07668 
07669     if (DraggedFill == this)
07670     {
07671         if (AllowBoundsRedraw)
07672         {
07673             // This fill is being dragged, so draw an Ellipse to show the
07674             // shape of the fill
07675             pRender->SetLineColour(COLOUR_SELECTEDBLOB);
07676             pRender->SetFillColour(COLOUR_NONE);
07677         
07678             Path EllipsePath;
07679             EllipsePath.Initialise();
07680             // Make an Elliptical path
07681             MakeMeshEllipse(&EllipsePath, Start, End, End2);
07682 
07683             pRender->DrawPath(&EllipsePath);
07684         }
07685     }
07686 
07687     // Now Render the blobs on the path
07688 
07689     // Draw a blob at the start point
07690     if (SelState[FILLCONTROL_STARTPOINT])
07691     {
07692         // Draw Selected Blob
07693 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
07694         pRender->SetLineColour(COLOUR_NONE);
07695         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
07696         pRender->DrawBlob(Start, BT_SELECTED);
07697     }
07698     else
07699     {
07700         // Draw Unselected Blob
07701 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
07702         pRender->SetLineColour(COLOUR_NONE);
07703         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
07704         pRender->DrawBlob(Start, BT_UNSELECTED);
07705     }
07706 
07707     // Draw a blob at the end point
07708     if (SelState[FILLCONTROL_ENDPOINT])
07709     {
07710         // Draw Selected Blob
07711 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
07712         pRender->SetLineColour(COLOUR_NONE);
07713         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
07714         pRender->DrawBlob(End, BT_SELECTED);
07715         if (IsElliptical())
07716             pRender->DrawBlob(End2,BT_SELECTED);
07717     }
07718     else
07719     {
07720         // Draw Unselected Blob
07721 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
07722         pRender->SetLineColour(COLOUR_NONE);
07723         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
07724         pRender->DrawBlob(End, BT_UNSELECTED);
07725         if (IsElliptical())
07726             pRender->DrawBlob(End2,BT_UNSELECTED);
07727     }
07728 
07729     // now render any ramp blobs
07730     FillRamp *pRamp = GetFillRamp();
07731     if (pRamp)
07732         pRamp->RenderRampBlobs(ATTRVALUE(), pRender, NULL);
07733 
07734     // Put all the old attributes back
07735     pRender->RestoreContext();
07736 #endif
07737 }
07738 
07739 /********************************************************************************************
07740 
07741 >   void AttrRadialColourFill::RenderFillBlobs(RenderRegion* pRender)
07742 
07743     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
07744     Created:    24/6/94
07745     Inputs:     pRender - The region to render the blobs to.
07746     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
07747 
07748 ********************************************************************************************/
07749 
07750 void AttrRadialColourFill::RenderFillBlobs(RenderRegion* pRender)
07751 {
07752 #if !defined(EXCLUDE_FROM_RALPH)
07753     if (!IsVisible())
07754         return;     // We're in Fill Transparency Mode
07755 
07756     // Don't bother if this fill is being edited as a copy of it
07757     // we be rendered thoughout the drag op
07758     if (IsFillBeingEdited())
07759         return;
07760 
07761     // Ignore this if the mesh is the same as the last one rendered.
07762     if (CheckPreviousFillMesh())
07763         return;
07764 
07765     DocCoord ControlPoints[5];
07766     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
07767     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
07768     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
07769 
07770     // Render a nice pretty Fill Mesh thingy
07771     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
07772 
07773     // This call was removed by Gerry (2/9/96) as it causes blob problems
07774     // If we are removing blobs then force all blobs to be deselected
07775 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
07776 //      DeselectAllNoRedraw();
07777 #endif
07778 }
07779 
07780 /********************************************************************************************
07781 
07782 >   void AttrRadialTranspFill::RenderFillBlobs(RenderRegion* pRender)
07783 
07784     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
07785     Created:    24/6/94
07786     Inputs:     pRender - The region to render the blobs to.
07787     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
07788 
07789 ********************************************************************************************/
07790 
07791 void AttrRadialTranspFill::RenderFillBlobs(RenderRegion* pRender)
07792 {
07793 #if !defined(EXCLUDE_FROM_RALPH)
07794     if (!IsVisible())
07795         return;     // We're Not in Fill Transparency Mode
07796 
07797     // Don't bother if this fill is being edited as a copy of it
07798     // we be rendered thoughout the drag op
07799     if (IsFillBeingEdited())
07800         return;
07801 
07802     // Ignore this if the mesh is the same as the last one rendered.
07803     if (CheckPreviousFillMesh())
07804         return;
07805 
07806     DocCoord ControlPoints[5];
07807     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
07808     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
07809     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
07810 
07811     // Render a nice pretty Fill Mesh thingy
07812     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
07813 
07814     // This call was removed by Gerry (2/9/96) as it causes blob problems
07815     // If we are removing blobs then force all blobs to be deselected
07816 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
07817 //      DeselectAllNoRedraw();
07818 #endif
07819 }
07820 
07821 /********************************************************************************************
07822 
07823 >   void AttrRadialFill::MakeCircular()
07824 
07825     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07826     Created:    12/8/94
07827     Purpose:    Makes this fill into a circular one.
07828     SeeAlso:    AttrRadialFill::MakeElliptical;
07829                 AttrRadialFill::IsElliptical;
07830                 AttrRadialFill::IsCircular
07831 
07832 ********************************************************************************************/
07833 
07834 void AttrRadialFill::MakeCircular()
07835 {
07836     ((FillGeometryAttribute*)GetAttributeValue())->SetAspectLock(TRUE);
07837 }
07838 
07839 /********************************************************************************************
07840 
07841 >   void AttrRadialFill::MakeElliptical()
07842 
07843     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07844     Created:    12/8/94
07845     Purpose:    Makes this fill into an elliptical one.
07846     SeeAlso:    AttrRadialFill::MakeCircular;
07847                 AttrRadialFill::IsElliptical;
07848                 AttrRadialFill::IsCircular
07849 
07850 ********************************************************************************************/
07851 
07852 void AttrRadialFill::MakeElliptical()
07853 {
07854     ((FillGeometryAttribute*)GetAttributeValue())->SetAspectLock(FALSE);
07855 }
07856 
07858 //
07859 //                              AttrRadialColourFill
07860 //
07862 
07863 /********************************************************************************************
07864 
07865 >   void AttrRadialColourFill::Render( RenderRegion* pRender)
07866 
07867     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07868     Created:    23/8/94
07869     Purpose:    'Renders' a Radial Fill Colour attribute.
07870 
07871 ********************************************************************************************/
07872 
07873 void AttrRadialColourFill::Render(RenderRegion* pRender)
07874 {
07875     pRender->SetFillGeometry(&Value, FALSE);
07876 }
07877 
07878 /********************************************************************************************
07879 
07880 > Node* AttrRadialColourFill::SimpleCopy() 
07881 
07882     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07883     Created:    23/8/94
07884     Returns:    A copy of the node, or NULL if memory runs out 
07885     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
07886                 The function is virtual, and must be defined for all derived classes.  
07887     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
07888                 memory error and the function returns NULL. 
07889     Scope:      protected       
07890 
07891 ********************************************************************************************/
07892      
07893 Node* AttrRadialColourFill::SimpleCopy()
07894 {
07895     AttrRadialColourFill* NodeCopy = new AttrRadialColourFill();
07896     if (NodeCopy == NULL)
07897         return NULL;
07898 
07899     CopyNodeContents(NodeCopy);
07900     
07901     return NodeCopy;
07902 }  
07903 
07904 /********************************************************************************************
07905 
07906 >   virtual UINT32 AttrRadialColourFill::GetAttrNameID(void)  
07907 
07908     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07909     Created:    23/8/94
07910     Returns:    Attribute description ID
07911     Purpose:    Returns a string resource ID describing the attribute
07912 
07913 ********************************************************************************************/
07914 
07915 UINT32 AttrRadialColourFill::GetAttrNameID(void)  
07916 {
07917     if (IsElliptical ())
07918     {
07919         return (_R(IDS_ELLIPITICALGRADFILL));
07920     }
07921     else
07922     {
07923         return (_R(IDS_CIRCULARGRADFILL));
07924     }
07925 }                                  
07926 
07927 
07928 
07929 /********************************************************************************************
07930 
07931 >   void AttrRadialColourFill::GetDebugDetails(StringBase* Str)
07932 
07933     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07934     Created:    20/07/94
07935     Outputs:    Str - the string containing details of the attribute.
07936     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
07937 
07938 ********************************************************************************************/
07939 
07940 void AttrRadialColourFill::GetDebugDetails(StringBase* Str)
07941 {
07942 #ifdef _DEBUG
07943     NodeAttribute::GetDebugDetails( Str );
07944 
07945     String_256 TempStr;
07946 
07947     TempStr._MakeMsg( TEXT("\r\nRadial Graduated Fill:\r\n"));
07948     (*Str) += TempStr;
07949 
07950 //  TempStr._MakeMsg(TEXT("\r\nStart"));
07951 //  (*GetStartColour()).GetDebugDetails(&TempStr);
07952 //  (*Str) += TempStr;
07953 
07954 //  TempStr._MakeMsg(TEXT("\r\nEnd"));
07955 //  (*GetEndColour()).GetDebugDetails(&TempStr);
07956 //  (*Str) += TempStr;
07957 
07958     TempStr._MakeMsg(TEXT("\r\nStart point =(#1%ld, #2%ld)"), 
07959                      (*GetStartPoint()).x, (*GetStartPoint()).y);
07960     (*Str) += TempStr;
07961 
07962     TempStr._MakeMsg(TEXT("\r\nEnd point =(#1%ld, #2%ld), "), 
07963                      (*GetEndPoint()).x, (*GetEndPoint()).y);
07964     (*Str) += TempStr;
07965 
07966     TempStr._MakeMsg(TEXT("\r\nEnd point2 = (#1%ld, #2%ld) "), 
07967                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
07968     (*Str) += TempStr;
07969 #endif
07970 }
07971 
07972 /********************************************************************************************
07973 
07974 >   virtual UINT32 AttrRadialColourFill::GetNodeSize() const
07975 
07976     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
07977     Created:    23/8/94
07978     Returns:    The size of the node in bytes
07979     Purpose:    For finding the size of the node.
07980     SeeAlso:    Node::GetSubtreeSize
07981 
07982 ********************************************************************************************/
07983 
07984 UINT32 AttrRadialColourFill::GetNodeSize() const 
07985 {     
07986     return sizeof(AttrRadialColourFill);
07987 }  
07988 
07989 
07990 
07991 /********************************************************************************************
07992 
07993   > virtual BOOL AttrRadialColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
07994 
07995     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
07996     Created:    26/6/96
07997     Inputs:     pFilter = ptr to the filter
07998     Returns:    TRUE if record is written, FALSE if not
07999     Purpose:    Writes the radial fill record to the filter
08000     SeeAlso:    -
08001 
08002 ********************************************************************************************/
08003 
08004 BOOL AttrRadialColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
08005 {
08006 #ifdef DO_EXPORT
08007     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
08008 
08009     UINT32 Tag = TAG_CIRCULARFILL;
08010     INT32 TagSize = TAG_CIRCULARFILL_SIZE;
08011 
08012     if (IsElliptical())
08013     {
08014         Tag     = TAG_ELLIPTICALFILL;
08015         TagSize = TAG_ELLIPTICALFILL_SIZE;
08016     }
08017 
08018     // Must write out the colours first
08019     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
08020     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
08021 
08022     // am I a multistage fill ??
08023     BOOL bMultistage = FALSE;
08024 
08025     // write out the colours for the ramp
08026     ColourRamp * pRamp = GetColourRamp();
08027     INT32 * pRampColRefs = NULL;
08028     double * pPositions = NULL;
08029     ColRampItem * pItem = NULL;
08030     UINT32 NumRampItems = 0;
08031 
08032     if (pRamp)
08033     {
08034         // write out all the colour references
08035         if (pRamp->GetCount() > 0)
08036         {
08037             bMultistage = TRUE;
08038             NumRampItems = pRamp->GetCount();
08039 
08040             pRampColRefs = new INT32[NumRampItems];
08041             pPositions   = new double[NumRampItems];
08042 
08043             pItem = (ColRampItem *)pRamp->GetHead();
08044 
08045             for (UINT32 i = 0 ; i < NumRampItems; i++)
08046             {
08047                 if (pItem)
08048                 {
08049                     pPositions[i]   = pItem->GetPosition();
08050                     DocColour tempcolour = pItem->GetColour();
08051                     pRampColRefs[i] = pFilter->WriteRecord(&tempcolour);
08052                 }
08053 
08054                 pItem = (ColRampItem *)pRamp->GetNext(pItem);
08055             }
08056         }
08057     }
08058 
08059     // Are the colour references ok?
08060     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
08061         
08062     if (!bMultistage)
08063     {
08064         if (ok)
08065         {
08066             CamelotFileRecord Rec(pFilter,Tag,TagSize);
08067             
08068             if (ok) ok = Rec.Init();
08069             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
08070             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
08071             
08072             if (ok && IsElliptical())                       // Write out extra control point in the ellipse case
08073                 ok = Rec.WriteCoord(Value.EndPoint2);
08074             
08075             if (ok) ok = Rec.WriteReference(StartColRef);
08076             if (ok) ok = Rec.WriteReference(EndColRef);
08077 
08078             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
08079             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
08080 
08081             if (ok) ok = pFilter->Write(&Rec);
08082         }
08083     }
08084     else
08085     {
08086         if (IsElliptical())
08087         {
08088             Tag = TAG_ELLIPTICALFILLMULTISTAGE;
08089             TagSize = TAG_ELLIPTICALFILLMULTISTAGE_SIZE;
08090         }
08091         else
08092         {
08093             Tag = TAG_CIRCULARFILLMULTISTAGE;
08094             TagSize = TAG_CIRCULARFILLMULTISTAGE_SIZE;
08095         }
08096 
08097         if (ok)
08098         {
08099             CamelotFileRecord Rec(pFilter,Tag,TagSize);
08100             
08101             if (ok) ok = Rec.Init();
08102             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
08103             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
08104 
08105             if (ok && IsElliptical())                       // Write out extra control point in the ellipse case
08106                 ok = Rec.WriteCoord(Value.EndPoint2);
08107 
08108             if (ok) ok = Rec.WriteReference(StartColRef);
08109             if (ok) ok = Rec.WriteReference(EndColRef);
08110 
08111             // now, write out all the colour ramp items
08112             if (ok) ok = Rec.WriteUINT32(NumRampItems);
08113 
08114             for (UINT32 i = 0 ; i < NumRampItems; i++)
08115             {
08116                 if (ok) ok = Rec.WriteDOUBLE(pPositions[i]);
08117                 if (ok) ok = Rec.WriteReference(pRampColRefs[i]);
08118             }
08119 
08120             if (ok) ok = pFilter->Write(&Rec);
08121         }
08122     }
08123 
08124     if (pRampColRefs)
08125         delete [] pRampColRefs;
08126 
08127     if (pPositions)
08128         delete [] pPositions;
08129 
08130 
08131     if (!ok)
08132         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
08133 
08134     return ok;
08135 #else
08136     return FALSE;
08137 #endif
08138 }
08139 
08140 //--------------------------------------------------------------
08141 // See AttrRadialColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
08142 //
08143 BOOL AttrRadialColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
08144 {
08145 #ifdef DO_EXPORT
08146     return WritePreChildrenWeb(pFilter);
08147 #else
08148     return FALSE;
08149 #endif
08150 }
08151 
08152 
08153 /********************************************************************************************
08154 
08155   > virtual BOOL AttrRadialColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
08156 
08157     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
08158     Created:    14/9/2000
08159     Inputs:     pFilter = ptr to the filter
08160     Returns:    TRUE if record is written, FALSE if not
08161     Purpose:    Writes out colour definitions for this fill.
08162     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
08163                 Layer::WriteAtomicNodesColourRefs ()
08164 
08165 ********************************************************************************************/
08166 
08167 BOOL AttrRadialColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
08168 {
08169     // Must write out the colours first
08170     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
08171     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
08172 
08173     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
08174 
08175     if (ok)
08176     {
08177         ColourRamp * pRamp = GetColourRamp();
08178         if (pRamp)
08179         if (pRamp->GetCount() > 0)
08180         {
08181             ok = pRamp->WriteColourDefinitions (pFilter);
08182         }
08183     }
08184     
08185     return (ok);
08186 }
08187 
08189 //
08190 //                              AttrRadialTranspFill
08191 //
08193 
08194 /********************************************************************************************
08195 
08196 >   void AttrRadialTranspFill::Render( RenderRegion* pRender)
08197 
08198     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08199     Created:    23/8/94
08200     Purpose:    'Renders' a Radial Fill Colour attribute.
08201 
08202 ********************************************************************************************/
08203 
08204 void AttrRadialTranspFill::Render(RenderRegion* pRender)
08205 {
08206     pRender->SetTranspFillGeometry(&Value, FALSE);
08207 }
08208 
08209 /********************************************************************************************
08210 
08211 > Node* AttrRadialTranspFill::SimpleCopy() 
08212 
08213     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08214     Created:    23/8/94
08215     Returns:    A copy of the node, or NULL if memory runs out 
08216     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
08217                 The function is virtual, and must be defined for all derived classes.  
08218     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
08219                 memory error and the function returns NULL. 
08220     Scope:      protected       
08221 
08222 ********************************************************************************************/
08223      
08224 Node* AttrRadialTranspFill::SimpleCopy()
08225 {
08226     AttrRadialTranspFill* NodeCopy = new AttrRadialTranspFill();
08227     if (NodeCopy == NULL)
08228         return NULL;
08229 
08230     CopyNodeContents(NodeCopy);
08231     
08232     return NodeCopy;
08233 }  
08234 
08235 /********************************************************************************************
08236 
08237 >   virtual UINT32 AttrRadialTranspFill::GetAttrNameID(void)  
08238 
08239     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08240     Created:    23/8/94
08241     Returns:    Attribute description ID
08242     Purpose:    Returns a string resource ID describing the attribute
08243 
08244 ********************************************************************************************/
08245 
08246 UINT32 AttrRadialTranspFill::GetAttrNameID(void)  
08247 {
08248     if (!IsATranspFill ())
08249     {
08250         if (IsElliptical ())
08251         {
08252             return (_R(IDS_LINEARGRADFILL)); 
08253         }
08254         else
08255         {
08256             return (_R(IDS_CIRCULARGRADFILL));
08257         }
08258     }
08259     else
08260     {
08261         if (IsElliptical ())
08262         {
08263             return (_R(IDS_ELLIPITICALTRANSPFILL)); 
08264         }
08265         else
08266         {
08267             return (_R(IDS_CIRCULARTRANSPFILL));
08268         }
08269     }
08270 }                                  
08271 
08272 /********************************************************************************************
08273 
08274 >   void AttrRadialTranspFill::GetDebugDetails(StringBase* Str)
08275 
08276     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08277     Created:    20/07/94
08278     Outputs:    Str - the string containing details of the attribute.
08279     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
08280 
08281 ********************************************************************************************/
08282 
08283 void AttrRadialTranspFill::GetDebugDetails(StringBase* Str)
08284 {
08285 #ifdef _DEBUG
08286     NodeAttribute::GetDebugDetails( Str );
08287 
08288     String_256 TempStr;
08289 
08290     TempStr._MakeMsg( TEXT("\r\nRadial Graduated Fill:\r\n"));
08291     (*Str) += TempStr;
08292 
08293     TempStr._MakeMsg(TEXT("\r\nStart"));
08294     (*Str) += TempStr;
08295 
08296     TempStr._MakeMsg(TEXT("\r\nEnd"));
08297     (*Str) += TempStr;
08298 
08299     TempStr._MakeMsg(TEXT("\r\nStart point =(#1%ld, #2%ld)"), 
08300                      (*GetStartPoint()).x, (*GetStartPoint()).y);
08301     (*Str) += TempStr;
08302 
08303     TempStr._MakeMsg(TEXT("\r\nEnd point =(#1%ld, #2%ld), "), 
08304                      (*GetEndPoint()).x, (*GetEndPoint()).y);
08305     (*Str) += TempStr;
08306 
08307     TempStr._MakeMsg(TEXT("\r\nEnd point2 = (#1%ld, #2%ld) "), 
08308                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
08309     (*Str) += TempStr;
08310 #endif
08311 }
08312 
08313 /********************************************************************************************
08314 
08315 >   virtual UINT32 AttrRadialTranspFill::GetNodeSize() const
08316 
08317     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08318     Created:    23/8/94
08319     Returns:    The size of the node in bytes
08320     Purpose:    For finding the size of the node.
08321     SeeAlso:    Node::GetSubtreeSize
08322 
08323 ********************************************************************************************/
08324 
08325 UINT32 AttrRadialTranspFill::GetNodeSize() const 
08326 {     
08327     return sizeof(AttrRadialTranspFill);
08328 }  
08329 
08330 
08331 /*********************************************************************************************
08332 
08333 >    virtual BOOL AttrRadialTranspFill::NeedsToRenderAtEachBrushStroke()
08334 
08335      Author:    Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
08336      Created:   29/11/99
08337      Inputs:    -
08338      Outputs:   -
08339      Returns:   TRUE if this attribute should be rendered at every step of a brush stroke
08340      Purpose:   So that don't have to keep re-rendering attributes whilst drawing a brush, this
08341                 identifies whether or not the attribute need to be rendered at each step, 
08342                 e.g. radial fills.
08343      Errors:    
08344      See Also;  Brush code (ndbrshmk.cpp)
08345 
08346 **********************************************************************************************/
08347        
08348 BOOL AttrRadialTranspFill::NeedsToRenderAtEachBrushStroke() const
08349 {
08350     return TRUE;
08351 }
08352 
08353 /********************************************************************************************
08354 
08355   > virtual BOOL AttrRadialTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
08356 
08357     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
08358     Created:    26/6/96
08359     Inputs:     pFilter = ptr to the filter
08360     Returns:    TRUE if record is written, FALSE if not
08361     Purpose:    Writes the radial transparent fill record to the filter
08362     SeeAlso:    -
08363 
08364 ********************************************************************************************/
08365 
08366 BOOL AttrRadialTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
08367 {
08368 #ifdef DO_EXPORT
08369     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
08370     ERROR3IF(Value.Transp     > 255,"Start transparency level is too high to be stored as a byte");
08371     ERROR3IF(Value.EndTransp  > 255,"End transparency level is too high to be stored as a byte");
08372     ERROR3IF(Value.TranspType > 255,"Transparency type is too high to be stored as a byte");
08373 
08374     BOOL ok = TRUE;
08375 
08376     UINT32 Tag = TAG_CIRCULARTRANSPARENTFILL, TagSize = TAG_CIRCULARTRANSPARENTFILL_SIZE;
08377 
08378     if (IsElliptical())
08379     {
08380         Tag     = TAG_ELLIPTICALTRANSPARENTFILL;
08381         TagSize = TAG_ELLIPTICALTRANSPARENTFILL_SIZE;
08382     }
08383 
08384     CamelotFileRecord Rec(pFilter,Tag,TagSize);
08385 
08386     if (ok) ok = Rec.Init();
08387     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
08388     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
08389 
08390     if (ok && IsElliptical())
08391         if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
08392 
08393     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
08394     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));
08395     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
08396     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
08397     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
08398     if (ok) ok = pFilter->Write(&Rec);
08399 
08400     if (!ok)
08401         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
08402 
08403     return ok;
08404 #else
08405     return FALSE;
08406 #endif
08407 }
08408 
08409 /********************************************************************************************
08410 >   BOOL AttrRadialTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
08411 
08412     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
08413     Created:    11/05/2005
08414     Inputs:     -
08415     Outputs:    -
08416     Returns:    TRUE if this node has a value equivalent to the relevant 
08417                 FALSE otherwise
08418     Purpose:    Determine whether this attribute has the default value or not
08419     Errors:     -
08420     SeeAlso:    -
08421 ********************************************************************************************/
08422 
08423 BOOL AttrRadialTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
08424 {
08425     // Slight bodge - we will assume that the default transparency is fully opaque
08426     if (bAppearance)
08427         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0));
08428     else
08429         return FALSE;
08430 }
08431 
08432 
08433 
08434 
08435 //--------------------------------------------------------------
08436 // See AttrDashPatternAttrRadialTranspFillWritePreChildrenWeb(BaseCamelotFilter* pFilter)
08437 //
08438 BOOL AttrRadialTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
08439 {
08440 #ifdef DO_EXPORT
08441     return WritePreChildrenWeb(pFilter);
08442 #else
08443     return FALSE;
08444 #endif
08445 }
08446 
08447 
08449 //
08450 //                              AttrConicalFill
08451 //
08453 
08454 /********************************************************************************************
08455 
08456 >   void AttrConicalFill::Transform( TransformBase& Trans )
08457 
08458     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08459     Created:    23/8/94
08460     Inputs:     Trans - the transform object to apply to this attribute.
08461     Purpose:    Transform a grad fill attribute by moving the start and end points.
08462     SeeAlso:    NodeRenderable::Transform
08463 
08464 ********************************************************************************************/
08465 
08466 void AttrConicalFill::Transform( TransformBase& Trans )
08467 {
08468     if ( Trans.TransFills )
08469     {
08470         Trans.Transform( GetStartPoint(), 1);
08471         Trans.Transform( GetEndPoint(), 1);
08472 
08473 //      ValidateAttributeValue();
08474     }
08475 }
08476 
08477 /********************************************************************************************
08478 
08479 >   void AttrConicalFill::TransformSelectedControlPoints( TransformBase& Trans)
08480 
08481     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08482     Created:    23/8/94
08483     Inputs:     Trans - the transform object to apply to this attribute.
08484     Purpose:    Transform a grad fill attribute by moving the selected control points.
08485     SeeAlso:    NodeRenderable::Transform
08486 
08487 ********************************************************************************************/
08488 
08489 void AttrConicalFill::TransformSelectedControlPoints( TransformBase& Trans, BOOL* isARampBlob /*= NULL*/)
08490 {
08491 #if !defined(EXCLUDE_FROM_RALPH)
08492     if ( Trans.TransFills )
08493     {
08494         ClickModifiers ClickMods; /* = ClickModifiers::GetClickModifiers();*/
08495         ClickMods.Adjust = TRUE;
08496 
08497         if (GetStartPoint() && IsSelected(FILLCONTROL_STARTPOINT))
08498         {
08499             DocCoord Pos = *GetStartPoint();
08500             Trans.Transform( &Pos, 1);
08501 
08502             FillControl Pt = FILLCONTROL_DRAGPOINT;
08503             
08504             OnControlDrag(Pos, Pt, ClickMods);
08505         }
08506 
08507         if (GetEndPoint() && IsSelected(FILLCONTROL_ENDPOINT))
08508         {
08509             DocCoord Pos = *GetEndPoint();
08510             Trans.Transform( &Pos, 1);
08511 
08512             FillControl End = FILLCONTROL_ENDPOINT;
08513 
08514             OnControlDrag(Pos, End, ClickMods);
08515         }
08516 
08517         // CGS - wo, lets check the fill ramp as well ....
08518 
08519         TransformSelectedFillRampControlPoints (Trans, ClickMods, isARampBlob);
08520     }
08521 #endif
08522 }
08523 
08524 /********************************************************************************************
08525 
08526 >   BOOL AttrConicalFill::CanTransform()
08527 
08528     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08529     Created:    23/8/94
08530     Returns:    TRUE => transform this attribute.
08531     Purpose:    Indicate that this attribute can be transformed.
08532     SeeAlso:    NodeRenderable::CanTransform
08533 
08534 ********************************************************************************************/
08535 
08536 BOOL AttrConicalFill::CanTransform()
08537 {
08538     return TRUE;
08539 }
08540 
08541 
08542 /********************************************************************************************
08543 
08544 >   FillControl AttrConicalFill::CheckForControlHit(DocCoord &ClickPos)
08545 
08546     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08547     Created:    21/07/94
08548     Inputs:     ClickPos, The DocCoord position to check.
08549     Returns:    A FillControl, indicating the Fill Control Point Hit,
08550                 or FILLCONTROL_NULL, if no points hit.
08551     Purpose:    Check to see if a click was on a Fill Control Point. 
08552     SeeAlso:    FillControl
08553 
08554 ********************************************************************************************/
08555 
08556 FillControl AttrConicalFill::CheckForControlHit(DocCoord &ClickPos)
08557 {
08558 #if !defined(EXCLUDE_FROM_RALPH)
08559     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
08560         return FILLCONTROL_NULL;
08561 
08562     // Set up a default, that indicates not control points hit
08563     FillControl HitControl = FILLCONTROL_NULL;
08564     DocRect BlobRect;
08565 
08566     // Get the current control positions
08567     DocCoord CentrePoint  = *GetStartPoint();
08568     DocCoord EndColBlob   = *GetEndPoint();
08569     DocCoord StartColBlob = MakeLineAtAngle(CentrePoint, EndColBlob, 180);
08570 
08571     // Get the rectangle around the Centre Control Point
08572     (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &BlobRect);
08573     // See if the Click Position is within the rectangle
08574     if ( BlobRect.ContainsCoord(ClickPos) )
08575         HitControl = FILLCONTROL_DRAGPOINT;
08576 
08577     // Get the rectangle around the Start Colour Control Point
08578     (Camelot.GetBlobManager())->GetBlobRect(StartColBlob, &BlobRect);
08579     // See if the Click Position is within the rectangle
08580     if ( BlobRect.ContainsCoord(ClickPos) )
08581         HitControl = FILLCONTROL_STARTPOINT;
08582 
08583     // Get the rectangle around the End Colour Control Point
08584     (Camelot.GetBlobManager())->GetBlobRect(EndColBlob, &BlobRect);
08585     // See if the Click Position is within the rectangle
08586     if ( BlobRect.ContainsCoord(ClickPos) )
08587         HitControl = FILLCONTROL_ENDPOINT;
08588 
08589     // check the fill ramp blobs
08590     if (HitControl == FILLCONTROL_NULL)
08591     {
08592         // do we have a fill ramp ?
08593         if (GetColourRamp())
08594         {
08595 //          ColourRamp * pRamp = GetColourRamp();
08596 
08597             // check for a hit
08598             return AttrFillGeometry::CheckForControlHit(ClickPos);
08599         }
08600         else
08601         {
08602             // check the position on the fill ramp
08603             double d = FindRampPoint(ClickPos, *GetStartPoint(), *GetEndPoint());
08604 
08605             if (d > 0 && d < 1)
08606             {
08607                 return FILLCONTROL_RAMPPOINT;
08608             }
08609         }           
08610     }
08611 
08612     return HitControl;
08613 #else
08614     return FILLCONTROL_NULL;
08615 #endif
08616 }
08617 
08618 /********************************************************************************************
08619 
08620 >   AttrFillGeometry* AttrConicalFill::DoColourDrop(AttrColourDrop*)
08621 
08622     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
08623     Created:    27/10/99
08624     Purpose:    Does colour drop onto conical fills
08625 
08626 ********************************************************************************************/
08627 AttrFillGeometry* AttrConicalFill::DoColourDrop(AttrColourDrop* ColDrop)
08628 {
08629     AttrFillGeometry* NewFill;
08630     DocColour DroppedColour = *ColDrop->GetStartColour();
08631 
08632     // First test to see which colour we should change
08633     FillControl ControlHit = TestColourDrop(ColDrop);
08634 
08635     if (ControlHit == FILLCONTROL_NULL)
08636     {
08637         // No Control points hit, so make a flat fill instead
08638         NewFill = new AttrFlatColourFill;
08639         if (NewFill == NULL)
08640             return NULL;
08641 
08642         // and use the mutants colour
08643         NewFill->SetStartColour(&DroppedColour);
08644 
08645         BOOL InSelection = ColDrop->IsObjectSelected();
08646 
08647         if (InSelection &&
08648             GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && 
08649             IsVisible()
08650             )
08651         {
08652             BOOL UniqueFill = TRUE;
08653 
08654             AttrFillGeometry* pAttr = FindFirstSelectedAttr();
08655             while (pAttr != NULL)
08656             {
08657                 if (pAttr != this && GetAttributeType() == pAttr->GetAttributeType())
08658                 {
08659                     if ( IsMeshSame((FillGeometryAttribute*)GetAttributeValue(),
08660                                     (FillGeometryAttribute*)pAttr->GetAttributeValue()) )
08661                     {
08662                         UniqueFill = FALSE;
08663                         break;
08664                     }
08665                 }
08666 
08667                 // Move onto the next attr
08668                 pAttr = FindNextSelectedAttr();
08669             }
08670 
08671             /*
08672             if (UniqueFill)
08673                 RenderFillBlobs();
08674                 */
08675         }
08676         
08677         return NewFill;
08678     }
08679 
08680     if (FindParent() && FindParent()->IsCompound())
08681     {
08682         if (ColDrop->GetObjectDroppedOn() && 
08683             !(ColDrop->GetObjectDroppedOn()->IsCompound()) && 
08684             ColDrop->IsObjectSelected())
08685         {
08686             // If we are dropping inside a group, then we'll need to remove
08687             // the blobs if this fill is applied to the whole group
08688             // RenderFillBlobs();
08689         }
08690     }
08691 
08692     // Make a copy of this Fill to change
08693     NewFill = (AttrFillGeometry*)this->SimpleCopy();
08694     if (NewFill == NULL)
08695         return NULL;
08696 
08697     if (!NewFill->ChangeControlColour(DroppedColour, ControlHit, ColDrop))
08698     {
08699         delete NewFill;
08700         return NULL;
08701     }
08702 
08703     // invalidate the region in the document & render the fill blobs
08704     Document * pDoc = Document::GetCurrent();
08705 
08706     if (pDoc)
08707         pDoc->ForceRedraw(FindParentSpread(), GetBlobBoundingRect(), FALSE, this->FindParent());
08708 
08709     // Return the Mutated Fill
08710     return NewFill;
08711 }
08712 
08713 
08714 
08715 
08716 /********************************************************************************************
08717 
08718 >   void AttrConicalFill::RenderControl(FillControl Control, BOOL RenderOn)
08719 
08720     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08721     Created:    26/7/94
08722     Inputs:     Control, the FillControl to redraw
08723     Purpose:    Redraws the Fill Control blobs when the selection changes.
08724     SeeAlso:    FillControl         
08725 
08726 ********************************************************************************************/
08727 
08728 void AttrConicalFill::RenderControl(FillControl Control, BOOL RenderOn)
08729 {
08730 #if !defined(EXCLUDE_FROM_RALPH)
08731     DocRect ControlRect;
08732 
08733     // Ignore if we're not in the tree yet
08734     // We may be a tempory clone, or something
08735     NodeRenderable* pParent = (NodeRenderable*)FindParent();
08736 
08737     if (pParent == NULL)
08738         return;
08739 
08740     if (IsBlobSame(Control))
08741         return;         // Ignore if same as the last blob rendered
08742 
08743     Spread* pSpread = this->FindParentSpread();
08744 
08745     DocCoord StartPoint = *GetStartPoint();
08746     DocCoord EndPoint   = *GetEndPoint();
08747     DocCoord EndPoint2  = 
08748         MakeLineAtAngle(StartPoint, EndPoint, 180);
08749 
08750     switch (Control)
08751     {
08752         case FILLCONTROL_DRAGPOINT:
08753             // Redraw the Centre Point Blob
08754             (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &ControlRect);
08755             break;
08756 
08757         case FILLCONTROL_STARTPOINT:
08758             // Redraw the Start Colour Blob
08759             (Camelot.GetBlobManager())->GetBlobRect(EndPoint2, &ControlRect);
08760             break;
08761 
08762         case FILLCONTROL_ENDPOINT:
08763             // Redraw the End Colour Blob
08764             (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &ControlRect);
08765             break;
08766     }
08767 
08768     if (ISA_RAMPINDEX(Control))
08769     {
08770         FillRamp* pRamp = GetFillRamp();
08771         if (pRamp)
08772         {
08773             DocCoord point = pRamp->GetGeometryCoord(ATTRVALUE(), Control);
08774             (Camelot.GetBlobManager())->GetBlobRect(point, &ControlRect, TRUE);
08775         }
08776     }   
08777 
08778     // Redraw the rectangle we calculated above
08779     RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
08780 #endif
08781 }
08782 
08783 /********************************************************************************************
08784 
08785 >   virtual void AttrConicalFill::OnControlDrag( DocCoord Pos, FillControl DragControl, 
08786                                                     ClickModifiers ClickMods)
08787     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08788     Created:    2/8/94
08789     Inputs:     Pos - The Location of the mouse pointer at the time of the call
08790                 DragControl - The FillControl that is being dragged.
08791                 ClickMods - The modifiers to the click (eg shift, control etc )
08792     Purpose:    Called when an edit operation is dragging a fill control point.
08793 
08794 ********************************************************************************************/
08795 
08796 void AttrConicalFill::OnControlDrag( DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
08797 {
08798     // Get the current Control Point Positions
08799     DocCoord StartPoint = *GetStartPoint();
08800     DocCoord EndPoint = *GetEndPoint();
08801 
08802     INT32 dx, dy;
08803 
08804     switch (DragControl)
08805     {
08806         case FILLCONTROL_DRAGPOINT:
08807             // They're dragging the Centre Point
08808             dx = StartPoint.x - Pos.x;
08809             dy = StartPoint.y - Pos.y;
08810             // Move the other points relative
08811             EndPoint.translate(-dx, -dy);
08812             SetEndPoint(&EndPoint);
08813             SetStartPoint(&Pos);
08814             break;
08815 
08816         case FILLCONTROL_STARTPOINT:
08817 
08818             // If the Constrain key is down then constrain the Angle of the
08819             // point, relative to the centre.
08820             if (ClickMods.Constrain)
08821                 DocView::ConstrainToAngle(StartPoint, &Pos);
08822 
08823             {
08824                 DocCoord coord( MakeLineAtAngle( StartPoint, Pos, 180 ) );
08825                 SetEndPoint( &coord );
08826             }
08827             break;
08828 
08829         case FILLCONTROL_ENDPOINT:
08830 
08831             // If the Constrain key is down then constrain the Angle of the
08832             // point, relative to the centre.
08833             if (ClickMods.Constrain)
08834                 DocView::ConstrainToAngle(StartPoint, &Pos);
08835 
08836             SetEndPoint(&Pos);
08837             break;
08838         default:
08839             // is the hit point a ramp point ?
08840             if (ISA_RAMPINDEX(DragControl))
08841             {
08842                 FillRamp *pRamp = GetFillRamp();
08843                 
08844                 if (pRamp)
08845                 {
08846                     float t = (float)FindRampPoint(Pos, *GetStartPoint(), *GetEndPoint());
08847 
08848                     if (t > 0 && t < 1.0)
08849                     {   
08850                         FillControl NewDragControl = pRamp->SetPosition(DragControl, t);
08851 
08852                         if (NewDragControl != DragControl)
08853                         {
08854                             DragControl = NewDragControl;
08855                         }
08856 
08857                         Document * pDoc = Document::GetCurrent();
08858                         
08859                         if (pDoc)
08860                         {
08861                             Spread * pSpread = (Spread *)FindParent(CC_RUNTIME_CLASS(Spread));
08862                             
08863                             if (pSpread)
08864                             {
08865                                 if (AllowRampRedraw)
08866                                 {
08867                                     pDoc->ForceRedraw(pSpread, GetBlobBoundingRect(), FALSE, this->FindParent());
08868                                 }
08869                             }
08870                             else
08871                             {
08872                                 pSpread = Document::GetSelectedSpread();
08873                                 
08874                                 if (pSpread)
08875                                 {
08876                                     if (AllowRampRedraw)
08877                                     {
08878                                         pDoc->ForceRedraw(pSpread, GetBlobBoundingRect(), FALSE, this->FindParent());
08879                                     }
08880                                     
08881                                 }
08882                             }
08883                         }
08884                         
08885                     }
08886                 }
08887             }
08888             break;
08889     }
08890 }
08891 
08892 /********************************************************************************************
08893 
08894 >   double AttrConicalFill::FindRampPoint(DocCoord &dc, DocCoord &StartPoint, DocCoord &EndPoint);
08895 
08896     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
08897     Created:    26/10/99
08898     Returns:    -
08899     Purpose:    Gives the value (0 - 1) of the given dc - bearing in mind the start point is
08900                 the centre of the conical fill and end point is the start point on the conical
08901                 curve
08902 
08903 ********************************************************************************************/
08904 
08905 
08906 double AttrConicalFill::FindRampPoint(DocCoord &dc, DocCoord &StartPoint, DocCoord &EndPoint)
08907 {
08908     //get the dot product
08909     DocCoord Centre((StartPoint.x + EndPoint.x) / 2, (StartPoint.y + EndPoint.y) / 2);
08910 
08911     double dStartX = StartPoint.x;
08912     double dStartY = StartPoint.y;
08913 
08914     double dEndX = EndPoint.x;
08915     double dEndY = EndPoint.y;
08916 
08917     double dVecX = dEndX - dStartX;
08918     double dVecY = dEndY - dStartY;
08919 
08920     // calculate the distance between the point and the centre point
08921     double ddX = dc.x - StartPoint.x;
08922     double ddY = dc.y - StartPoint.y;
08923 
08924     double DistToPoint = sqrt((ddX * ddX) + (ddY * ddY));
08925     
08926     // normalise the vector
08927 
08928     double DistToEndPoint = sqrt((dVecX * dVecX) + (dVecY * dVecY));
08929 
08930     double dRMod = 1/DistToEndPoint;
08931     dVecX *= dRMod;
08932     dVecY *= dRMod;
08933 
08934     double dToPointX = ((double)dc.x) - dStartX;
08935     double dToPointY = ((double)dc.y) - dStartY;
08936 
08937     dRMod = 1/sqrt((dToPointX * dToPointX) + (dToPointY * dToPointY));
08938 
08939     dToPointX *= dRMod;
08940     dToPointY *= dRMod;
08941 
08942     double dot = (dToPointX * dVecX) + (dToPointY * dVecY);
08943 
08944     // do the 90 degree dot product as well since we need to know
08945     // whether the point is over the blob itself, or over its mirror
08946     // image
08947     double dot90 = (-dToPointY * dVecX) + (dToPointX * dVecY);
08948 
08949     if (dot > 1.0)
08950         dot = 1.0;
08951 
08952     if (dot < -1.0)
08953         dot = -1.0;
08954 
08955     // get the angle
08956     double Angle = acos(dot) * 180.0 / 3.142;
08957 
08958     double Retn = (180.0 - Angle) / 180.0;
08959 
08960     double dBlobSize = (double)(Camelot.GetBlobManager())->GetBlobSize();
08961 
08962     // is the point in range ?
08963     if (fabs(DistToPoint - DistToEndPoint) < dBlobSize && dot90 < 0)
08964     {
08965         return Retn;
08966     }
08967 
08968     return -1;
08969 }
08970 
08971 /********************************************************************************************
08972 
08973 >   void AttrConicalFill::ValidateAttributeValue()
08974 
08975     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
08976     Created:    11/8/94
08977     Returns:    -
08978     Purpose:    Makes sure the Coords of the Fill are sensible.
08979 
08980 ********************************************************************************************/
08981 
08982 void AttrConicalFill::ValidateAttributeValue()
08983 {
08984 #if !defined(EXCLUDE_FROM_RALPH)
08985     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0))
08986         return;
08987 
08988     // Make some defaults
08989     DocRect AttrBounds = DocRect(0,0,0,0);
08990 
08991     INT32 Width  = DEFAULT_FILLWIDTH;
08992     INT32 Height = DEFAULT_FILLHEIGHT;
08993 
08994     // Are we an Orphan ?
08995     if (FindParent() != NULL)
08996     {
08997         // Nope, so we can use Daddies Bounding Box
08998         SelRange* Selected = GetApplication()->FindSelection();
08999                  
09000         if (Selected == NULL || Selected->Count() <= 1)
09001             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
09002         else
09003             AttrBounds = Selected->GetBoundingRect();
09004 
09005         Width  = AttrBounds.Width();
09006         Height = AttrBounds.Height();
09007     }
09008 
09009     // If the StartPoint is 'NULL' then make all points sensible
09010     if ((*GetStartPoint()) == DocCoord(0,0))
09011     {
09012         // Start in the middle
09013         DocCoord temp = CentreOf(AttrBounds);
09014         SetStartPoint(&temp);
09015 
09016         // End on the Middle Right
09017         temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
09018         SetEndPoint(&temp);
09019     }
09020 
09021     // If the EndPoint is 'NULL' then make end points sensible
09022     if ((*GetEndPoint()) == DocCoord(0,0))
09023     {
09024         DocCoord temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
09025         SetEndPoint(&temp);
09026     }
09027 #endif
09028 }
09029 
09030 /********************************************************************************************
09031 
09032 >   virtual DocRect AttrConicalFill::GetBlobBoundingRect()
09033 
09034     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09035     Created:    28/7/94
09036     Returns:    DocRect - The rectangle that contains all the attrs selection blobs.
09037     Purpose:    Calculates the bounding rectangle of the attrs blobs.This should always 
09038                 be calculated on the fly as the view scale can change without the attr 
09039                 knowing, giving an incorrect result.
09040 
09041 ********************************************************************************************/
09042 
09043 DocRect AttrConicalFill::GetBlobBoundingRect()
09044 {
09045 #if !defined(EXCLUDE_FROM_RALPH)
09046     // Optimisation.  If there is currently no interest in Fill Blobs
09047     // and this fill is not being Dragged (Fill blobs are turned off during
09048     // a fill drag), then we needn't bother doing anything. 
09049     if ( (!GetApplication()->GetBlobManager()->GetCurrentInterest(TRUE).Fill || !IsVisible()) && DraggedFill != this )
09050         return DocRect(0,0, 0,0);
09051 
09052     // Get the Start and End Points
09053     DocCoord StartPoint = *GetStartPoint();
09054     DocCoord EndPoint   = *GetEndPoint();
09055     DocCoord EndPoint2  = MakeLineAtAngle(StartPoint, EndPoint, 180);
09056 
09057     DocRect StartBlobRect;
09058     DocRect EndBlobRect;
09059     // Get the bounds of the funny semi-circle mesh thingy
09060     DocRect BoundingRect = GetMeshEllipseBounds(StartPoint, EndPoint);
09061 
09062     // Get the Bounding rect of the Fill Line, including the Blobs on the ends
09063     (Camelot.GetBlobManager())->GetBlobRect(BoundingRect.lo, &StartBlobRect);
09064     (Camelot.GetBlobManager())->GetBlobRect(BoundingRect.hi, &EndBlobRect);
09065 
09066     // Now include the Bottom Left and Top Right of each blob in the Bounds.
09067     // We have to do it like this to make sure that the DocRect's coords
09068     // are valid.  ie. The Hi's are Higher than the Lo's.
09069     BoundingRect.IncludePoint(StartBlobRect.lo);
09070     BoundingRect.IncludePoint(StartBlobRect.hi);
09071     BoundingRect.IncludePoint(EndBlobRect.lo);
09072     BoundingRect.IncludePoint(EndBlobRect.hi);
09073 
09074     DocCoord Temp  = MakeLineAtAngle(EndPoint, StartPoint, -90);
09075     IncludeArrowHead(&BoundingRect, Temp, EndPoint);
09076 
09077     // and return it
09078     return BoundingRect;
09079 #else
09080     return DocRect(0,0, 0,0);
09081 #endif
09082 }
09083 
09084 /********************************************************************************************
09085 
09086 >   void AttrConicalFill::RenderFillMesh(RenderRegion* pRender, 
09087                                     DocCoord* ControlPoints, BOOL* SelState,
09088                                     INT32 NumControlPoints)
09089     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09090     Created:    24/7/94
09091     Inputs:     pRender - The region to render the blobs to.
09092                 ControlPoints - The positions of all the control points
09093                 SelState - The selection state of the control points
09094                 NumControlPoints - The Number of control points.
09095     Purpose:    Renders the grad fills mesh during a drag op.
09096                 Don't call this, call RenderFillBlobs().
09097     SeeAlso:    AttrConicalFill::RenderFillBlobs
09098 
09099 ********************************************************************************************/
09100 
09101 void AttrConicalFill::RenderFillMesh(RenderRegion* pRender, 
09102                                     DocCoord* ControlPoints, BOOL* SelState,
09103                                     INT32 NumControlPoints)
09104 {
09105 #if !defined(EXCLUDE_FROM_RALPH)
09106     if (AllowRampRedraw == FALSE)
09107     {
09108         FillRamp *pRamp = GetFillRamp();
09109         if (pRamp)
09110         {
09111             pRamp->RenderSelectedBlob (ATTRVALUE(), pRender);
09112         }
09113         
09114         return;
09115     }
09116     
09117     DocCoord Start = ControlPoints[FILLCONTROL_STARTPOINT];
09118     DocCoord End   = ControlPoints[FILLCONTROL_ENDPOINT];
09119 
09120     if (Start == End)
09121         return;
09122 
09123     if (SelState == NULL)
09124     {
09125         // If no selection state passed in, then assume
09126         // all the points are deselected
09127         BOOL Selected[NUMCONTROLPOINTS];
09128         for (INT32 i=0; i< NumControlPoints; i++)
09129         {
09130             Selected[i] = FALSE;
09131         }
09132         SelState = Selected;
09133     }
09134 
09135     DocCoord End2  = MakeLineAtAngle(Start, End, 180);
09136 
09137     // Remember what attributes were here before
09138     pRender->SaveContext();
09139 
09140     // Get the current blob size in Doc Units
09141     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
09142 
09143     // Calculate the Arrow on the End of the Line
09144     Path ArrowPath;
09145     ArrowPath.Initialise();
09146     DocCoord LineEnd;
09147     DocCoord Temp  = MakeLineAtAngle(End, Start, -90);
09148     MakeMeshArrow(&ArrowPath, Temp, End, &LineEnd);
09149     // This will have also calculated a point for us to draw
09150     // the line to, so we don't try and draw though the arrow head.
09151 
09152     Path EllipsePath;
09153     EllipsePath.Initialise();
09154     MakeMeshSemiCircle(&EllipsePath, Start, End, LineEnd);
09155 
09156     // Set the line colours etc as we need them
09157     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
09158     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
09159 
09160     // First Draw the Line
09161     pRender->SetFillColour(COLOUR_NONE);
09162 
09163     if (DraggedFill == this)
09164     {
09165         if (AllowBoundsRedraw)
09166         {
09167             // If we are being dragged, then draw some lines to show the
09168             // fill angle
09169             pRender->DrawLine(Start, End);
09170             pRender->DrawLine(Start, End2);
09171         }
09172     }
09173 
09174     // Render a Circle
09175     pRender->SetLineWidth(BlobSize/4);
09176     pRender->DrawPath(&EllipsePath);
09177 
09178     // Render an Arrow at the end of the line
09179     pRender->SetLineWidth(0);
09180     pRender->SetLineColour(COLOUR_NONE);
09181     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
09182     pRender->DrawPath(&ArrowPath);
09183 
09184     // Now Render the blobs on the path
09185 //  pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
09186     pRender->SetLineColour(COLOUR_NONE);
09187     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
09188     pRender->DrawBlob(Start, BT_UNSELECTED);
09189 
09190     // Draw a blob at the start point
09191     if (SelState[FILLCONTROL_ENDPOINT])
09192     {
09193         // Draw Selected Blob
09194 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
09195         pRender->SetLineColour(COLOUR_NONE);
09196         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
09197         pRender->DrawBlob(End, BT_SELECTED);
09198     }
09199     else
09200     {
09201         // Draw Unselected Blob
09202 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
09203         pRender->SetLineColour(COLOUR_NONE);
09204         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
09205         pRender->DrawBlob(End, BT_UNSELECTED);
09206     }
09207 
09208     // Draw a blob at the end point
09209     if (SelState[FILLCONTROL_STARTPOINT])
09210     {
09211         // Draw Selected Blob
09212 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
09213         pRender->SetLineColour(COLOUR_NONE);
09214         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
09215         pRender->DrawBlob(End2, BT_SELECTED);
09216     }
09217     else
09218     {
09219         // Draw Unselected Blob
09220 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
09221         pRender->SetLineColour(COLOUR_NONE);
09222         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
09223         pRender->DrawBlob(End2, BT_UNSELECTED);
09224     }
09225 
09226     // now render any ramp blobs
09227     FillRamp *pRamp = GetFillRamp();
09228     if (pRamp)
09229         pRamp->RenderRampBlobs(ATTRVALUE(), pRender, NULL);
09230 
09231     // Put all the old attributes back
09232     pRender->RestoreContext();
09233 #endif
09234 }
09235 
09236 /********************************************************************************************
09237 
09238 >   void AttrConicalColourFill::RenderFillBlobs(RenderRegion* pRender)
09239 
09240     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
09241     Created:    24/6/94
09242     Inputs:     pRender - The region to render the blobs to.
09243     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
09244 
09245 ********************************************************************************************/
09246 
09247 void AttrConicalColourFill::RenderFillBlobs(RenderRegion* pRender)
09248 {
09249 #if !defined(EXCLUDE_FROM_RALPH)
09250     if (!IsVisible())
09251         return;     // We're in Fill Transparency Mode
09252 
09253     // Don't bother if this fill is being edited as a copy of it
09254     // we be rendered thoughout the drag op
09255     if (IsFillBeingEdited())
09256         return;
09257 
09258     // Ignore this if the mesh is the same as the last one rendered.
09259     if (CheckPreviousFillMesh())
09260         return;
09261 
09262     DocCoord ControlPoints[2];
09263     ControlPoints[0] = (*GetStartPoint());
09264     ControlPoints[1] = (*GetEndPoint());
09265 
09266     // Render a nice pretty Fill Mesh thingy
09267     RenderFillMesh(pRender, ControlPoints, SelectionState, 2);
09268 
09269     // This call was removed by Gerry (2/9/96) as it causes blob problems
09270     // If we are removing blobs then force all blobs to be deselected
09271 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
09272 //      DeselectAllNoRedraw();
09273 #endif
09274 }
09275 
09276 /********************************************************************************************
09277 
09278 >   void AttrConicalTranspFill::RenderFillBlobs(RenderRegion* pRender)
09279 
09280     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
09281     Created:    24/6/94
09282     Inputs:     pRender - The region to render the blobs to.
09283     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
09284 
09285 ********************************************************************************************/
09286 
09287 void AttrConicalTranspFill::RenderFillBlobs(RenderRegion* pRender)
09288 {
09289 #if !defined(EXCLUDE_FROM_RALPH)
09290     if (!IsVisible())
09291         return;     // We're Not in Fill Transparency Mode
09292 
09293     // Don't bother if this fill is being edited as a copy of it
09294     // we be rendered thoughout the drag op
09295     if (IsFillBeingEdited())
09296         return;
09297 
09298     // Ignore this if the mesh is the same as the last one rendered.
09299     if (CheckPreviousFillMesh())
09300         return;
09301 
09302     DocCoord ControlPoints[2];
09303     ControlPoints[0] = (*GetStartPoint());
09304     ControlPoints[1] = (*GetEndPoint());
09305 
09306     // Render a nice pretty Fill Mesh thingy
09307     RenderFillMesh(pRender, ControlPoints, SelectionState, 2);
09308 
09309     // This call was removed by Gerry (2/9/96) as it causes blob problems
09310     // If we are removing blobs then force all blobs to be deselected
09311 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
09312 //      DeselectAllNoRedraw();
09313 #endif
09314 }
09315 
09317 //
09318 //                              AttrConicalColourFill
09319 //
09321 
09322 /********************************************************************************************
09323 
09324 >   void AttrConicalColourFill::Render( RenderRegion* pRender)
09325 
09326     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09327     Created:    23/8/94
09328     Purpose:    'Renders' a Conical Fill Colour attribute.
09329 
09330 ********************************************************************************************/
09331 
09332 void AttrConicalColourFill::Render(RenderRegion* pRender)
09333 {
09334     pRender->SetFillGeometry(&Value, FALSE);
09335 }
09336 
09337 /********************************************************************************************
09338 
09339 > Node* AttrConicalColourFill::SimpleCopy() 
09340 
09341     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09342     Created:    23/8/94
09343     Returns:    A copy of the node, or NULL if memory runs out 
09344     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
09345                 The function is virtual, and must be defined for all derived classes.  
09346     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
09347                 memory error and the function returns NULL. 
09348     Scope:      protected       
09349 
09350 ********************************************************************************************/
09351      
09352 Node* AttrConicalColourFill::SimpleCopy()
09353 {
09354     AttrConicalColourFill* NodeCopy = new AttrConicalColourFill();
09355     if (NodeCopy == NULL)
09356         return NULL;
09357 
09358     CopyNodeContents(NodeCopy);
09359     
09360     return NodeCopy;
09361 }  
09362 
09363 /********************************************************************************************
09364 
09365 >   virtual UINT32 AttrConicalColourFill::GetAttrNameID(void)  
09366 
09367     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09368     Created:    23/8/94
09369     Returns:    Attribute description ID
09370     Purpose:    Returns a string resource ID describing the attribute
09371 
09372 ********************************************************************************************/
09373 
09374 UINT32 AttrConicalColourFill::GetAttrNameID(void)  
09375 {
09376     return (_R(IDS_CONICALGRADFILL)); 
09377 }                                  
09378 
09379 /********************************************************************************************
09380 
09381 >   void AttrConicalColourFill::GetDebugDetails(StringBase* Str)
09382 
09383     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09384     Created:    20/07/94
09385     Outputs:    Str - the string containing details of the attribute.
09386     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
09387 
09388 ********************************************************************************************/
09389 
09390 void AttrConicalColourFill::GetDebugDetails(StringBase* Str)
09391 {
09392 #ifdef _DEBUG
09393     NodeAttribute::GetDebugDetails( Str );
09394 
09395     String_256 TempStr;
09396 
09397     TempStr._MakeMsg( TEXT("\r\nConical Graduated Fill:\r\n"));
09398     (*Str) += TempStr;
09399 
09400 //  TempStr._MakeMsg(TEXT("\r\nStart"));
09401 //  (*GetStartColour()).GetDebugDetails(&TempStr);
09402 //  (*Str) += TempStr;
09403 
09404 //  TempStr._MakeMsg(TEXT("\r\nEnd"));
09405 //  (*GetEndColour()).GetDebugDetails(&TempStr);
09406 //  (*Str) += TempStr;
09407 
09408     TempStr._MakeMsg(TEXT("\r\nStart point =(#1%ld, #2%ld)"), 
09409                      (*GetStartPoint()).x, (*GetStartPoint()).y);
09410     (*Str) += TempStr;
09411 
09412     TempStr._MakeMsg(TEXT("\r\nEnd point =(#1%ld, #2%ld), "), 
09413                      (*GetEndPoint()).x, (*GetEndPoint()).y);
09414     (*Str) += TempStr;
09415 #endif
09416 }
09417 
09418 /********************************************************************************************
09419 
09420 >   virtual UINT32 AttrConicalColourFill::GetNodeSize() const
09421 
09422     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09423     Created:    23/8/94
09424     Returns:    The size of the node in bytes
09425     Purpose:    For finding the size of the node.
09426     SeeAlso:    Node::GetSubtreeSize
09427 
09428 ********************************************************************************************/
09429 
09430 UINT32 AttrConicalColourFill::GetNodeSize() const 
09431 {     
09432     return sizeof(AttrConicalColourFill);
09433 }  
09434 
09435 
09436 
09437 /********************************************************************************************
09438 
09439   > virtual BOOL AttrConicalColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
09440 
09441     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
09442     Created:    26/6/96
09443     Inputs:     pFilter = ptr to the filter
09444     Returns:    TRUE if record is written, FALSE if not
09445     Purpose:    Writes the conical fill record to the filter
09446     SeeAlso:    -
09447 
09448 ********************************************************************************************/
09449 
09450 BOOL AttrConicalColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
09451 {
09452 #ifdef DO_EXPORT
09453     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
09454 
09455     // Must write out the colours first
09456     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
09457     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
09458 
09459     // am I a multistage fill ??
09460     BOOL bMultistage = FALSE;
09461 
09462     ColourRamp * pRamp = GetColourRamp();
09463     INT32 * pRampColRefs = NULL;
09464     double * pPositions = NULL;
09465     ColRampItem * pItem = NULL;
09466     UINT32 NumRampItems = 0;
09467 
09468     if (pRamp)
09469     {
09470         // write out all the colour references
09471         if (pRamp->GetCount() > 0)
09472         {
09473             bMultistage = TRUE;
09474             NumRampItems = pRamp->GetCount();
09475 
09476             pRampColRefs = new INT32[NumRampItems];
09477             pPositions   = new double[NumRampItems];
09478 
09479             pItem = (ColRampItem *)pRamp->GetHead();
09480 
09481             for (UINT32 i = 0 ; i < NumRampItems; i++)
09482             {
09483                 if (pItem)
09484                 {
09485                     pPositions[i]   = pItem->GetPosition();
09486                     DocColour tempcolour = pItem->GetColour();
09487                     pRampColRefs[i] = pFilter->WriteRecord(&tempcolour);
09488                 }
09489 
09490                 pItem = (ColRampItem *)pRamp->GetNext(pItem);
09491             }
09492         }
09493     }
09494 
09495     // Are the colour references ok?
09496     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
09497         
09498     if (ok)
09499     {
09500         if (!bMultistage)
09501         {
09502             CamelotFileRecord Rec(pFilter,TAG_CONICALFILL,TAG_CONICALFILL_SIZE);
09503 
09504             if (ok) ok = Rec.Init();
09505             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
09506             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
09507             if (ok) ok = Rec.WriteReference(StartColRef);
09508             if (ok) ok = Rec.WriteReference(EndColRef);
09509             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
09510             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
09511             if (ok) ok = pFilter->Write(&Rec);
09512         }
09513         else
09514         {
09515             CamelotFileRecord Rec(pFilter,TAG_CONICALFILLMULTISTAGE,
09516                 TAG_CONICALFILLMULTISTAGE_SIZE);
09517 
09518             if (ok) ok = Rec.Init();
09519             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
09520             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
09521             if (ok) ok = Rec.WriteReference(StartColRef);
09522             if (ok) ok = Rec.WriteReference(EndColRef);
09523 
09524             // now, write out all the colour ramp items
09525             if (ok) ok = Rec.WriteUINT32(NumRampItems);
09526 
09527             for (UINT32 i = 0 ; i < NumRampItems; i++)
09528             {
09529                 if (ok) ok = Rec.WriteDOUBLE(pPositions[i]);
09530                 if (ok) ok = Rec.WriteReference(pRampColRefs[i]);
09531             }
09532 
09533             if (ok) ok = pFilter->Write(&Rec);
09534         }
09535     }
09536 
09537     if (pPositions)
09538         delete [] pPositions;
09539 
09540     if (pRampColRefs)
09541         delete [] pRampColRefs;
09542 
09543     if (!ok)
09544         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
09545 
09546     return ok;
09547 #else
09548     return FALSE;
09549 #endif
09550 }
09551 
09552 //--------------------------------------------------------------
09553 // See AttrConicalColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
09554 //
09555 BOOL AttrConicalColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
09556 {
09557 #ifdef DO_EXPORT
09558     return WritePreChildrenWeb(pFilter);
09559 #else
09560     return FALSE;
09561 #endif
09562 }
09563 
09564 
09565 /********************************************************************************************
09566 
09567   > virtual BOOL AttrConicalColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
09568 
09569     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
09570     Created:    14/9/2000
09571     Inputs:     pFilter = ptr to the filter
09572     Returns:    TRUE if record is written, FALSE if not
09573     Purpose:    Writes out colour definitions for this fill.
09574     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
09575                 Layer::WriteAtomicNodesColourRefs ()
09576 
09577 ********************************************************************************************/
09578 
09579 BOOL AttrConicalColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
09580 {
09581     // Must write out the colours first
09582     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
09583     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
09584 
09585     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
09586 
09587     if (ok)
09588     {
09589         ColourRamp * pRamp = GetColourRamp();
09590         if (pRamp)
09591         if (pRamp->GetCount() > 0)
09592         {
09593             ok = pRamp->WriteColourDefinitions (pFilter);
09594         }
09595     }
09596     
09597     return (ok);
09598 }
09599 
09601 //
09602 //                              AttrConicalTranspFill
09603 //
09605 
09606 /********************************************************************************************
09607 
09608 >   void AttrConicalTranspFill::Render( RenderRegion* pRender)
09609 
09610     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09611     Created:    23/8/94
09612     Purpose:    'Renders' a Conical Fill Colour attribute.
09613 
09614 ********************************************************************************************/
09615 
09616 void AttrConicalTranspFill::Render(RenderRegion* pRender)
09617 {
09618     pRender->SetTranspFillGeometry(&Value, FALSE);
09619 }
09620 
09621 /********************************************************************************************
09622 
09623 > Node* AttrConicalTranspFill::SimpleCopy() 
09624 
09625     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09626     Created:    23/8/94
09627     Returns:    A copy of the node, or NULL if memory runs out 
09628     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
09629                 The function is virtual, and must be defined for all derived classes.  
09630     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
09631                 memory error and the function returns NULL. 
09632     Scope:      protected       
09633 
09634 ********************************************************************************************/
09635      
09636 Node* AttrConicalTranspFill::SimpleCopy()
09637 {
09638     AttrConicalTranspFill* NodeCopy = new AttrConicalTranspFill();
09639     if (NodeCopy == NULL)
09640         return NULL;
09641 
09642     CopyNodeContents(NodeCopy);
09643     
09644     return NodeCopy;
09645 }  
09646 
09647 /********************************************************************************************
09648 
09649 >   virtual UINT32 AttrConicalTranspFill::GetAttrNameID(void)  
09650 
09651     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09652     Created:    23/8/94
09653     Returns:    Attribute description ID
09654     Purpose:    Returns a string resource ID describing the attribute
09655 
09656 ********************************************************************************************/
09657 
09658 UINT32 AttrConicalTranspFill::GetAttrNameID(void)  
09659 {
09660     return (_R(IDS_CONICALTRANSPFILL)); 
09661 }                                  
09662 
09663 /********************************************************************************************
09664 
09665 >   void AttrConicalTranspFill::GetDebugDetails(StringBase* Str)
09666 
09667     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09668     Created:    20/07/94
09669     Outputs:    Str - the string containing details of the attribute.
09670     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
09671 
09672 ********************************************************************************************/
09673 
09674 void AttrConicalTranspFill::GetDebugDetails(StringBase* Str)
09675 {
09676 #ifdef _DEBUG
09677     NodeAttribute::GetDebugDetails( Str );
09678 
09679     String_256 TempStr;
09680 
09681     TempStr._MakeMsg( TEXT("\r\nConical Graduated Fill:\r\n"));
09682     (*Str) += TempStr;
09683 
09684     TempStr._MakeMsg(TEXT("\r\nStart"));
09685     (*Str) += TempStr;
09686 
09687     TempStr._MakeMsg(TEXT("\r\nEnd"));
09688     (*Str) += TempStr;
09689 
09690     TempStr._MakeMsg(TEXT("\r\nStart point =(#1%ld, #2%ld)"), 
09691                      (*GetStartPoint()).x, (*GetStartPoint()).y);
09692     (*Str) += TempStr;
09693 
09694     TempStr._MakeMsg(TEXT("\r\nEnd point =(#1%ld, #2%ld), "), 
09695                      (*GetEndPoint()).x, (*GetEndPoint()).y);
09696     (*Str) += TempStr;
09697 #endif
09698 }
09699 
09700 /********************************************************************************************
09701 
09702 >   virtual UINT32 AttrConicalTranspFill::GetNodeSize() const
09703 
09704     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
09705     Created:    23/8/94
09706     Returns:    The size of the node in bytes
09707     Purpose:    For finding the size of the node.
09708     SeeAlso:    Node::GetSubtreeSize
09709 
09710 ********************************************************************************************/
09711 
09712 UINT32 AttrConicalTranspFill::GetNodeSize() const 
09713 {     
09714     return sizeof(AttrConicalTranspFill);
09715 }  
09716 
09717 
09718 
09719 
09720 /********************************************************************************************
09721 
09722   > virtual BOOL AttrConicalTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
09723 
09724     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
09725     Created:    26/6/96
09726     Inputs:     pFilter = ptr to the filter
09727     Returns:    TRUE if record is written, FALSE if not
09728     Purpose:    Writes the conical transparent fill record to the filter
09729     SeeAlso:    -
09730 
09731 ********************************************************************************************/
09732 
09733 BOOL AttrConicalTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
09734 {
09735 #ifdef DO_EXPORT
09736     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
09737     ERROR3IF(Value.Transp     > 255,"Start transparency level is too high to be stored as a byte");
09738     ERROR3IF(Value.EndTransp  > 255,"End transparency level is too high to be stored as a byte");
09739     ERROR3IF(Value.TranspType > 255,"Transparency type is too high to be stored as a byte");
09740 
09741     BOOL ok = TRUE;
09742 
09743     CamelotFileRecord Rec(pFilter,TAG_CONICALTRANSPARENTFILL,TAG_CONICALTRANSPARENTFILL_SIZE);
09744 
09745     if (ok) ok = Rec.Init();
09746     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
09747     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
09748     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
09749     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));
09750     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
09751     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
09752     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
09753     if (ok) ok = pFilter->Write(&Rec);
09754 
09755     if (!ok)
09756         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
09757 
09758     return ok;
09759 #else
09760     return FALSE;
09761 #endif
09762 }
09763 
09764 //--------------------------------------------------------------
09765 // See AttrConicalTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
09766 //
09767 BOOL AttrConicalTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
09768 {
09769 #ifdef DO_EXPORT
09770     return WritePreChildrenWeb(pFilter);
09771 #else
09772     return FALSE;
09773 #endif
09774 }
09775 
09776 
09777 
09778 /********************************************************************************************
09779 >   BOOL AttrConicalTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
09780 
09781     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
09782     Created:    11/05/2005
09783     Inputs:     -
09784     Outputs:    -
09785     Returns:    TRUE if this node has a value equivalent to the relevant 
09786                 FALSE otherwise
09787     Purpose:    Determine whether this attribute has the default value or not
09788     Errors:     -
09789     SeeAlso:    -
09790 ********************************************************************************************/
09791 
09792 BOOL AttrConicalTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
09793 {
09794     // Slight bodge - we will assume that the default transparency is fully opaque
09795     if (bAppearance)
09796         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0));
09797     else
09798         return FALSE;
09799 }
09800 
09801 
09802 
09803 
09805 //
09806 //                              AttrSquareFill
09807 //
09809 
09810 /********************************************************************************************
09811 
09812 >   virtual FillControl AttrSquareFill::TestColourDrop(AttrColourDrop* ColDrop) 
09813 
09814     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
09815     Created:    9/8/96
09816     Inputs:     ColDrop - pointer to the 
09817     Purpose:    Check to see which colour will be changed if dropped at this point
09818 
09819 ********************************************************************************************/
09820 
09821 FillControl AttrSquareFill::TestColourDrop(AttrColourDrop* ColDrop) 
09822 { 
09823 #if !defined(EXCLUDE_FROM_RALPH)
09824     // So, where was it dropped (or where will it be dropped)
09825     DocCoord DropPoint = ColDrop->GetDropPoint();
09826 
09827     // Look to see if the DropPoint is over any of the Fill Control Points
09828     FillControl ControlHit = CheckForControlHit(DropPoint);
09829     
09830     // If it hit one of our control points, then use that
09831     if (ControlHit != FILLCONTROL_NULL)
09832         return ControlHit;
09833 
09834     // It didn't hit any of our control points, so if the drop is over
09835     // the object then we'll make a guess as to which control point
09836     // the user would like to change, depending on which area of the
09837     // object the pointer is over.
09838 
09839     // First make sure we're actually over an object
09840     NodeRenderableInk* pParentObject = ColDrop->GetObjectDroppedOn();
09841     if (pParentObject == NULL)
09842         return FILLCONTROL_NULL;    // We're not over any object 
09843 
09844     // Make sure this fill type has some Control Points
09845     if (GetStartPoint() == NULL || GetEndPoint() == NULL || GetEndPoint2() == NULL)
09846         return FILLCONTROL_NULL;
09847 
09848     // This next bit effectively transforms the drop point into the parallelogram coord space
09849     // t & u specify the coords (i.e. EndPoint is t = 1 and u = 0 and EndPoint2 is t = 0 and u = 1
09850     // If the absolute value of either coord is less than 0.5 then we are closer to the start point
09851     
09852     DocCoord StartPoint = *GetStartPoint();
09853     DocCoord EndPoint   = *GetEndPoint();
09854     DocCoord EndPoint2  = *GetEndPoint2();
09855 
09856     DocCoord P = EndPoint - StartPoint;
09857     DocCoord Q = EndPoint2 - StartPoint;
09858     DocCoord N = DropPoint - StartPoint;
09859 
09860     double px = P.x;
09861     double py = P.y;
09862     double qx = Q.x;
09863     double qy = Q.y;
09864     double nx = N.x;
09865     double ny = N.y;
09866         
09867     double den = (px * qy) - (py * qx);
09868 
09869     // Default to end point
09870     ControlHit = FILLCONTROL_ENDPOINT;
09871 
09872     // Guard against divide by zero
09873     // If this is zero it indicates that the fill is collapsed in some way
09874     // We always hit the end point because that is what is displayed
09875 
09876     if (den != 0.0)
09877     {
09878         // Calculate u
09879         double u = ((px * ny) - (py * nx)) / den;
09880 
09881         // If this is smaller than 0.5 then we need to calculate t
09882         if (fabs(u) < 0.5)
09883         {
09884             double t = 1.0;
09885 
09886             if (px != 0.0)
09887                 t = (nx - (u * qx)) / px;
09888             else
09889                 t = (ny - (u * qy)) / py;
09890 
09891             if (fabs(t) < 0.5)
09892                 ControlHit = FILLCONTROL_STARTPOINT;
09893         }
09894     }
09895 
09896     return ControlHit;
09897 
09898 #else
09899     return FILLCONTROL_NULL;
09900 #endif
09901 }
09902 
09903 
09904 
09905 /********************************************************************************************
09906 
09907 >   void AttrSquareFill::Transform( TransformBase& Trans )
09908 
09909     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
09910     Created:    9/8/96
09911     Inputs:     Trans - the transform object to apply to this attribute.
09912     Purpose:    Transform a grad fill attribute by moving the start and end points.
09913     SeeAlso:    Copied from AttrLinearFill
09914 
09915 ********************************************************************************************/
09916 
09917 void AttrSquareFill::Transform( TransformBase& Trans )
09918 {
09919     if ( Trans.TransFills )
09920     {
09921         Trans.Transform( GetStartPoint(), 1);
09922         Trans.Transform( GetEndPoint(), 1);
09923         Trans.Transform( GetEndPoint2(), 1);
09924 
09925         if (IsPerspective())
09926             Trans.Transform( GetEndPoint3(), 1);
09927     }
09928 }
09929 
09930 
09931 
09932 /********************************************************************************************
09933 
09934 >   BOOL AttrSquareFill::CanTransform()
09935 
09936     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
09937     Created:    9/8/96
09938     Returns:    TRUE => transform this attribute.
09939     Purpose:    Indicate that this attribute can be transformed.
09940     SeeAlso:    Copied from AttrLinearFill
09941 
09942 ********************************************************************************************/
09943 
09944 BOOL AttrSquareFill::CanTransform()
09945 {
09946     return TRUE;
09947 }
09948 
09949 
09950 
09951 /********************************************************************************************
09952 
09953 >   void AttrSquareFill::RenderFillMesh(RenderRegion* pRender, 
09954                                     DocCoord* ControlPoints, BOOL* SelState,
09955                                     INT32 NumControlPoints)
09956     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
09957     Created:    9/8/96
09958     Inputs:     pRender - The region to render the blobs to.
09959                 ControlPoints - The positions of all the control points
09960                 SelState - The selection state of the control points
09961                 NumControlPoints - The Number of control points.
09962     Purpose:    Renders the grad fills mesh during a drag op.
09963                 Don't call this, call RenderFillBlobs().
09964     SeeAlso:    AttrSquareFill::RenderFillBlobs
09965 
09966 ********************************************************************************************/
09967 
09968 void AttrSquareFill::RenderFillMesh(RenderRegion* pRender, 
09969                                     DocCoord* ControlPoints, BOOL* SelState,
09970                                     INT32 NumControlPoints)
09971 {
09972 #if !defined(EXCLUDE_FROM_RALPH)
09973     if (AllowRampRedraw == FALSE)
09974     {
09975         FillRamp *pRamp = GetFillRamp();
09976         if (pRamp)
09977         {
09978             pRamp->RenderSelectedBlob (ATTRVALUE(), pRender);
09979         }
09980         
09981         return;
09982     }
09983     
09984     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
09985     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
09986 
09987     if (StartPoint == EndPoint)
09988         return;
09989 
09990     if (SelState == NULL)
09991     {
09992         // If no selection state passed in, then assume
09993         // all the points are deselected
09994         BOOL Selected[NUMCONTROLPOINTS];
09995         for (INT32 i=0; i< NumControlPoints; i++)
09996         {
09997             Selected[i] = FALSE;
09998         }
09999         SelState = Selected;
10000     }
10001 
10002     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_SECONDARYPOINT];
10003 
10004     // Remember what attributes were here before
10005     pRender->SaveContext();
10006 
10007     // Get the current blob size in Doc Units
10008     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
10009 
10010     // Calculate the Arrow on the End of the Line
10011     Path ArrowPath;
10012     ArrowPath.Initialise();
10013     DocCoord LineEnd;
10014     MakeMeshArrow(&ArrowPath, StartPoint, EndPoint, &LineEnd);
10015 
10016     // Calculate the Arrow on the End of the Line2
10017     Path ArrowPath2;
10018     ArrowPath2.Initialise();
10019     DocCoord LineEnd2;
10020     MakeMeshArrow(&ArrowPath2, StartPoint, EndPoint2, &LineEnd2);
10021 
10022     // Set the line colours etc as we need them
10023     pRender->SetLineWidth(0);
10024     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
10025     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
10026 
10027     // First Draw the Line
10028     pRender->SetLineWidth(BlobSize/4);
10029     pRender->DrawLine(StartPoint, LineEnd);
10030 
10031     // Draw the secondary line
10032     pRender->DrawLine(StartPoint, LineEnd2);
10033 
10034     // Render an Arrow at the end of the line
10035     pRender->SetLineWidth(0);
10036     pRender->SetLineColour(COLOUR_NONE);
10037     pRender->DrawPath(&ArrowPath);
10038 
10039     // and on the end of the secondary line
10040     pRender->DrawPath(&ArrowPath2);
10041 
10042     if (DraggedFill == this)
10043     {
10044         if (AllowBoundsRedraw)
10045         {
10046             // If we are being dragged then draw a Parallelgram to
10047             // show the shape of the bitmap
10048             pRender->SetLineColour(COLOUR_SELECTEDBLOB);
10049             pRender->SetFillColour(COLOUR_NONE);
10050         
10051             Path ParaPath;
10052             ParaPath.Initialise();
10053             MakeMeshParallelagram(&ParaPath, StartPoint, EndPoint, EndPoint2);
10054 
10055             // Draw the parallelagram
10056             pRender->DrawPath(&ParaPath);
10057         }
10058     }
10059 
10060     // Now Render the blobs on the path
10061     // Set the line colour to none
10062     pRender->SetLineColour(COLOUR_NONE);
10063 
10064     // Draw a blob at the start point
10065     if (SelState[FILLCONTROL_STARTPOINT])
10066     {
10067         // Draw Selected Blob
10068         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
10069         pRender->DrawBlob(StartPoint, BT_SELECTED);
10070     }
10071     else
10072     {
10073         // Draw Unselected Blob
10074         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
10075         pRender->DrawBlob(StartPoint, BT_UNSELECTED);
10076     }
10077 
10078     // Draw the blobs at the end points
10079     if (SelState[FILLCONTROL_ENDPOINT])
10080     {
10081         // Draw Selected Blobs
10082         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
10083         pRender->DrawBlob(EndPoint, BT_SELECTED);
10084         pRender->DrawBlob(EndPoint2,BT_SELECTED);
10085     }
10086     else
10087     {
10088         // Draw Unselected Blobs
10089         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
10090         pRender->DrawBlob(EndPoint, BT_UNSELECTED);
10091         pRender->DrawBlob(EndPoint2,BT_UNSELECTED);
10092     }
10093 
10094     // now render any ramp blobs
10095     FillRamp *pRamp = GetFillRamp();
10096     if (pRamp)
10097         pRamp->RenderRampBlobs(ATTRVALUE(), pRender, NULL);
10098 
10099     // Put all the old attributes back
10100     pRender->RestoreContext();
10101 #endif
10102 }
10103 
10104 
10105 
10106 /********************************************************************************************
10107 
10108 >   virtual void AttrSquareFill::OnControlDrag(DocCoord Pos, FillControl DragControl, 
10109                                                     ClickModifiers ClickMods)
10110     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10111     Created:    9/8/96
10112     Inputs:     Pos - The Location of the mouse pointer at the time of the call
10113                 DragControl - The FillControl that is being dragged.
10114                 ClickMods - The modifiers to the click (eg shift, control etc )
10115     Purpose:    Called when an edit operation is dragging a control point.
10116 
10117 ********************************************************************************************/
10118 
10119 void AttrSquareFill::OnControlDrag(DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
10120 {
10121 #if !defined(EXCLUDE_FROM_RALPH)
10122     // Get the current Control Positions
10123     DocCoord StartPoint = *GetStartPoint();
10124     DocCoord EndPoint = *GetEndPoint();
10125     DocCoord EndPoint2 = *GetEndPoint2();
10126 
10127     INT32 dx, dy;
10128 
10129     // Which control point is being dragged ?
10130     switch (DragControl)
10131     {
10132         case FILLCONTROL_STARTPOINT:
10133         
10134             // Someone is dragging the Centre of the Fill
10135             dx = StartPoint.x - Pos.x;
10136             dy = StartPoint.y - Pos.y;
10137             // Move the other points relative
10138             EndPoint.translate(-dx, -dy);
10139             EndPoint2.translate(-dx, -dy);
10140 
10141             SetEndPoint(&EndPoint);
10142             SetEndPoint2(&EndPoint2);
10143             SetStartPoint(&Pos);
10144             break;
10145 
10146         case FILLCONTROL_ENDPOINT:
10147             
10148             // Someone is dragging the first End Point
10149             
10150             // Constrain the angle if necessary
10151             if (ClickMods.Constrain)
10152                 DocView::ConstrainToAngle(StartPoint, &Pos);
10153 
10154             // The Aspect ratio can be locked either by it being circular
10155             // or by the Shift key      
10156             if (ClickMods.Adjust)
10157             {
10158                 double OldLen = StartPoint.Distance(EndPoint);
10159                 double NewLen = StartPoint.Distance(Pos);
10160                 double Ratio = 1.0;
10161 
10162                 if (OldLen == 0)
10163                     Ratio = 0;
10164                 else
10165                     Ratio = NewLen/OldLen;
10166 
10167                 // Calculate the new end point based on the aspect ratio
10168                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, 90, INT32(StartPoint.Distance(EndPoint2) * Ratio));
10169                 SetEndPoint2(&temp);
10170             }
10171 
10172             SetEndPoint(&Pos);
10173             break;
10174 
10175         case FILLCONTROL_SECONDARYPOINT:
10176 
10177             // Someone is dragging the second End Point
10178             
10179             // Constrain the angle if necessary
10180             if (ClickMods.Constrain)
10181                 DocView::ConstrainToAngle(StartPoint, &Pos);
10182 
10183             // The Aspect ratio can be locked either by it being circular
10184             // or by the Shift key      
10185             if (ClickMods.Adjust)
10186             {
10187                 double OldLen = StartPoint.Distance(EndPoint2);
10188                 double NewLen = StartPoint.Distance(Pos);
10189                 double Ratio = 1.0;
10190 
10191                 if (OldLen == 0)
10192                     Ratio = 0;
10193                 else
10194                     Ratio = NewLen/OldLen;
10195 
10196                 // Calculate the new end point based on the aspect ratio
10197                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, -90, INT32(StartPoint.Distance(EndPoint) * Ratio));
10198                 SetEndPoint(&temp);
10199             }
10200 
10201             SetEndPoint2(&Pos);
10202             break;
10203 
10204             default:
10205             // check for dragging a ramp point
10206             if (ISA_RAMPINDEX(DragControl))
10207             {
10208                 AttrFillGeometry::OnControlDrag( Pos, DragControl, ClickMods);
10209             }
10210             break;
10211     }
10212 #endif
10213 }
10214 
10215 
10216 
10217 /********************************************************************************************
10218 
10219 >   virtual DocRect AttrSquareFill::GetBlobBoundingRect()
10220 
10221     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10222     Created:    9/8/96
10223     Returns:    DocRect - The rectangle that contains all the nodes selection blobs.
10224     Purpose:    Calculates the bounding rectangle of the attrs blobs.This should always 
10225                 be calculated on the fly as the view scale can change without the attr 
10226                 knowing, giving an incorrect result.
10227 
10228 ********************************************************************************************/
10229 
10230 DocRect AttrSquareFill::GetBlobBoundingRect()
10231 {
10232 #if !defined(EXCLUDE_FROM_RALPH)
10233     // Optimisation.  If there is currently no interest in Fill Blobs
10234     // and this fill is not being Dragged (Fill blobs are turned off during
10235     // a fill drag), then we needn't bother doing anything. 
10236     if ( (!GetApplication()->GetBlobManager()->GetCurrentInterest(TRUE).Fill || !IsVisible()) && DraggedFill != this )
10237         return DocRect(0,0, 0,0);
10238 
10239     // Get the Start and End Points
10240     DocCoord StartPoint = *GetStartPoint();
10241     DocCoord EndPoint   = *GetEndPoint();
10242     DocCoord EndPoint2  = *GetEndPoint2();
10243 
10244     // Make a dummy bounds from just the Start Point
10245     DocRect BoundingRect(StartPoint, StartPoint);
10246 
10247     if (DraggedFill == this)
10248     {
10249         // This fill is being dragged, so we have to include the Parallelagram 
10250         // bounding rect as well
10251         DocRect StartBlobRect;
10252         DocRect EndBlobRect;
10253         DocRect DragRect = GetParallelagramBounds(StartPoint, EndPoint, EndPoint2);
10254 
10255         // Get the Bounding rect of Blobs on each of the ends
10256         (Camelot.GetBlobManager())->GetBlobRect(DragRect.lo, &StartBlobRect);
10257         (Camelot.GetBlobManager())->GetBlobRect(DragRect.hi, &EndBlobRect);
10258 
10259         // Now include the Bottom Left and Top Right of each blob in the Bounds.
10260         // We have to do it like this to make sure that the DocRect's coords
10261         // are valid.  ie. The Hi's are Higher than the Lo's.
10262         BoundingRect.IncludePoint(StartBlobRect.lo);
10263         BoundingRect.IncludePoint(StartBlobRect.hi);
10264         BoundingRect.IncludePoint(EndBlobRect.lo);
10265         BoundingRect.IncludePoint(EndBlobRect.hi);
10266     }
10267     else
10268     {
10269         // We're not being dragged, so just calc the bounds of the Start and End Blobs
10270         DocRect StartBlobRect;
10271         DocRect EndBlobRect;
10272         DocRect End2BlobRect;
10273 
10274         // Get the Bounding rect of the Fill Line, including the Blobs on the ends
10275         (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &StartBlobRect);
10276         (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &EndBlobRect);
10277         (Camelot.GetBlobManager())->GetBlobRect(EndPoint2, &End2BlobRect);
10278 
10279         // Now include the Bottom Left and Top Right of each blob in the Bounds.
10280         // We have to do it like this to make sure that the DocRect's coords
10281         // are valid.  ie. The Hi's are Higher than the Lo's.
10282         BoundingRect.IncludePoint(StartBlobRect.lo);
10283         BoundingRect.IncludePoint(StartBlobRect.hi);
10284         BoundingRect.IncludePoint(EndBlobRect.lo);
10285         BoundingRect.IncludePoint(EndBlobRect.hi);
10286         BoundingRect.IncludePoint(End2BlobRect.lo);
10287         BoundingRect.IncludePoint(End2BlobRect.hi);
10288     }
10289 
10290     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint);
10291     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint2);
10292 
10293     // and return it
10294     return BoundingRect;
10295 #else
10296     return DocRect(0,0,0,0);
10297 #endif
10298 }
10299 
10300 
10301 
10302 /********************************************************************************************
10303 
10304 >   void AttrSquareFill::ValidateAttributeValue()
10305 
10306     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10307     Created:    9/8/96
10308     Purpose:    Makes sure the Coords of the Fill are sensible.
10309 
10310 ********************************************************************************************/
10311 
10312 void AttrSquareFill::ValidateAttributeValue()
10313 {
10314 #if !defined(EXCLUDE_FROM_RALPH)
10315     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0))
10316     {
10317         // If the EndPoint2 is 'NULL' then make it sensible
10318         if (*GetEndPoint2() == DocCoord(0,0))
10319         {
10320             DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90);
10321             SetEndPoint2(&temp);
10322         }
10323         
10324         return;
10325     }
10326 
10327     // Make up some sensible defaults
10328     DocRect AttrBounds = DocRect(0,0,0,0);
10329 
10330     INT32 Width  = DEFAULT_FILLWIDTH;
10331     INT32 Height = DEFAULT_FILLHEIGHT;
10332 
10333     // Are we an Orphan ?
10334     if (FindParent() != NULL)
10335     {
10336         // Nope, so we can use Daddies Bounding Box
10337         SelRange* Selected = GetApplication()->FindSelection();
10338                  
10339         if (Selected == NULL || Selected->Count() <= 1)
10340             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
10341         else
10342             AttrBounds = Selected->GetBoundingRect();
10343 
10344         Width  = AttrBounds.Width();
10345         Height = AttrBounds.Height();
10346     }
10347 
10348     // If the StartPoint is 'NULL' then make all points sensible
10349     if ((*GetStartPoint()) == DocCoord(0,0))
10350     {
10351         // Start in the centre of the bounds
10352         DocCoord temp = CentreOf(AttrBounds);
10353         SetStartPoint(&temp);
10354 
10355         // and set End Points to Middle Right, and Middle Top
10356         temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
10357         SetEndPoint(&temp);
10358         temp = DocCoord((*GetStartPoint()).x, (*GetStartPoint()).y + (Height/2));
10359         SetEndPoint2(&temp);
10360     }
10361 
10362     // If the EndPoint is 'NULL' then make end points sensible
10363     if ((*GetEndPoint()) == DocCoord(0,0))
10364     {
10365         DocCoord temp = DocCoord((*GetStartPoint()).x + (Width/2), (*GetStartPoint()).y);
10366         SetEndPoint(&temp);
10367         temp = DocCoord((*GetStartPoint()).x, (*GetStartPoint()).y + (Height/2));
10368         SetEndPoint2(&temp);
10369     }
10370 
10371     if ((*GetEndPoint2()) == DocCoord(0,0))
10372     {
10373         DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90, Height/2);
10374         SetEndPoint2(&temp);
10375     }
10376 #endif
10377 }
10378 
10379 
10380 
10382 //
10383 //                              AttrSquareColourFill
10384 //
10386 
10387 /********************************************************************************************
10388 
10389 >   void AttrSquareColourFill::Render( RenderRegion* pRender)
10390 
10391     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10392     Created:    9/8/96
10393     Purpose:    'Renders' a Square Fill Colour attribute.
10394 
10395 ********************************************************************************************/
10396 
10397 void AttrSquareColourFill::Render(RenderRegion* pRender)
10398 {
10399     pRender->SetFillGeometry(&Value, FALSE);
10400 }
10401 
10402 
10403 
10404 /********************************************************************************************
10405 
10406 > Node* AttrSquareColourFill::SimpleCopy() 
10407 
10408     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10409     Created:    9/8/96
10410     Returns:    A copy of the node, or NULL if memory runs out 
10411     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
10412                 The function is virtual, and must be defined for all derived classes.  
10413     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
10414                 memory error and the function returns NULL. 
10415     Scope:      protected       
10416 
10417 ********************************************************************************************/
10418      
10419 Node* AttrSquareColourFill::SimpleCopy()
10420 {
10421     AttrSquareColourFill* NodeCopy = new AttrSquareColourFill();
10422     if (NodeCopy == NULL)
10423         return NULL;
10424 
10425     CopyNodeContents(NodeCopy);
10426     
10427     return NodeCopy;
10428 }  
10429 
10430 
10431 
10432 /********************************************************************************************
10433 
10434 >   void AttrSquareColourFill::RenderFillBlobs(RenderRegion* pRender)
10435 
10436     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10437     Created:    9/8/96
10438     Inputs:     pRender - The region to render the blobs to.
10439     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
10440 
10441 ********************************************************************************************/
10442 
10443 void AttrSquareColourFill::RenderFillBlobs(RenderRegion* pRender)
10444 {
10445 #if !defined(EXCLUDE_FROM_RALPH)
10446     if (!IsVisible())
10447         return;     // We're in Fill Transparency Mode
10448 
10449     // Don't bother if this fill is being edited as a copy of it
10450     // we be rendered thoughout the drag op
10451     if (IsFillBeingEdited())
10452         return;
10453 
10454     // Ignore this if the mesh is the same as the last one rendered.
10455     if (CheckPreviousFillMesh())
10456         return;
10457 
10458     DocCoord ControlPoints[5];
10459     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
10460     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
10461     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
10462 
10463     // Render a nice pretty Fill Mesh thingy
10464     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
10465 
10466     // This call was removed by Gerry (2/9/96) as it causes blob problems
10467     // If we are removing blobs then force all blobs to be deselected
10468 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
10469 //      DeselectAllNoRedraw();
10470 #endif
10471 }
10472 
10473 
10474 
10475 /********************************************************************************************
10476 
10477 >   virtual UINT32 AttrSquareColourFill::GetAttrNameID(void)  
10478 
10479     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10480     Created:    9/8/96
10481     Returns:    Attribute description ID
10482     Purpose:    Returns a string resource ID describing the attribute
10483 
10484 ********************************************************************************************/
10485 
10486 UINT32 AttrSquareColourFill::GetAttrNameID(void)  
10487 {
10488     return (_R(IDS_SQUAREGRADFILL)); 
10489 }                                  
10490 
10491 
10492 
10493 /********************************************************************************************
10494 
10495 >   void AttrSquareColourFill::GetDebugDetails(StringBase* Str)
10496 
10497     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10498     Created:    9/8/96
10499     Outputs:    Str - the string containing details of the attribute.
10500     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
10501 
10502 ********************************************************************************************/
10503 
10504 void AttrSquareColourFill::GetDebugDetails(StringBase* Str)
10505 {
10506 #ifdef _DEBUG
10507     NodeAttribute::GetDebugDetails( Str );
10508 
10509     String_256 TempStr;
10510 
10511     TempStr._MakeMsg( TEXT("\r\nDiamond Graduated Fill:\r\n"));
10512     (*Str) += TempStr;
10513 
10514 //  TempStr._MakeMsg(TEXT("\r\nStart"));
10515 //  (*GetStartColour()).GetDebugDetails(&TempStr);
10516 //  (*Str) += TempStr;
10517 
10518 //  TempStr._MakeMsg(TEXT("\r\nEnd"));
10519 //  (*GetEndColour()).GetDebugDetails(&TempStr);
10520 //  (*Str) += TempStr;
10521 
10522     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
10523                      (*GetStartPoint()).x, (*GetStartPoint()).y);
10524     (*Str) += TempStr;
10525 
10526     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
10527                      (*GetEndPoint()).x, (*GetEndPoint()).y);
10528     (*Str) += TempStr;
10529 
10530     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
10531                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
10532     (*Str) += TempStr;
10533 #endif
10534 }
10535 
10536 
10537 
10538 /********************************************************************************************
10539 
10540 >   virtual UINT32 AttrSquareColourFill::GetNodeSize() const
10541 
10542     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10543     Created:    9/8/96
10544     Returns:    The size of the node in bytes
10545     Purpose:    For finding the size of the node.
10546     SeeAlso:    Node::GetSubtreeSize
10547 
10548 ********************************************************************************************/
10549 
10550 UINT32 AttrSquareColourFill::GetNodeSize() const 
10551 {     
10552     return sizeof(AttrSquareColourFill);
10553 }  
10554 
10555 
10556 
10557 /********************************************************************************************
10558 
10559   > virtual BOOL AttrSquareColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
10560 
10561     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10562     Created:    9/8/96
10563     Inputs:     pFilter = ptr to the filter
10564     Returns:    TRUE if record is written, FALSE if not
10565     Purpose:    Writes the Square fill record to the filter
10566     SeeAlso:    -
10567 
10568 ********************************************************************************************/
10569 
10570 BOOL AttrSquareColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
10571 {
10572 #ifdef DO_EXPORT
10573     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
10574 
10575     // Must write out the colours first
10576     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
10577     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
10578 
10579     // am I a multistage fill ??
10580     BOOL bMultistage = FALSE;
10581 
10582     ColourRamp * pRamp = GetColourRamp();
10583     INT32 * pRampColRefs = NULL;
10584     double * pPositions = NULL;
10585     ColRampItem * pItem = NULL;
10586     UINT32 NumRampItems = 0;
10587 
10588     if (pRamp)
10589     {
10590         // write out all the colour references
10591         if (pRamp->GetCount() > 0)
10592         {
10593             bMultistage = TRUE;
10594             NumRampItems = pRamp->GetCount();
10595 
10596             pRampColRefs = new INT32[NumRampItems];
10597             pPositions   = new double[NumRampItems];
10598 
10599             pItem = (ColRampItem *)pRamp->GetHead();
10600 
10601             for (UINT32 i = 0 ; i < NumRampItems; i++)
10602             {
10603                 if (pItem)
10604                 {
10605                     pPositions[i]   = pItem->GetPosition();
10606                     DocColour tempcolour = pItem->GetColour();
10607                     pRampColRefs[i] = pFilter->WriteRecord(&tempcolour);
10608                 }
10609 
10610                 pItem = (ColRampItem *)pRamp->GetNext(pItem);
10611             }
10612         }
10613     }
10614 
10615     // Are the colour references ok?
10616     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
10617         
10618     if (ok)
10619     {
10620         if (!bMultistage)
10621         {
10622             CamelotFileRecord Rec(pFilter,TAG_SQUAREFILL,TAG_SQUAREFILL_SIZE);
10623 
10624             if (ok) ok = Rec.Init();
10625             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
10626             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
10627             if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
10628             if (ok) ok = Rec.WriteReference(StartColRef);
10629             if (ok) ok = Rec.WriteReference(EndColRef);
10630             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
10631             if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
10632             if (ok) ok = pFilter->Write(&Rec);
10633         }
10634         else
10635         {
10636             CamelotFileRecord Rec(pFilter,TAG_SQUAREFILLMULTISTAGE,
10637                 TAG_SQUAREFILLMULTISTAGE_SIZE);
10638 
10639             if (ok) ok = Rec.Init();
10640             if (ok) ok = Rec.WriteCoord(Value.StartPoint);
10641             if (ok) ok = Rec.WriteCoord(Value.EndPoint);
10642             if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
10643             if (ok) ok = Rec.WriteReference(StartColRef);
10644             if (ok) ok = Rec.WriteReference(EndColRef);
10645 
10646             // now, write out all the colour ramp items
10647             if (ok) ok = Rec.WriteUINT32(NumRampItems);
10648 
10649             for (UINT32 i = 0 ; i < NumRampItems; i++)
10650             {
10651                 if (ok) ok = Rec.WriteDOUBLE(pPositions[i]);
10652                 if (ok) ok = Rec.WriteReference(pRampColRefs[i]);
10653             }
10654 
10655             if (ok) ok = pFilter->Write(&Rec);
10656         }
10657     }
10658 
10659     if (pPositions)
10660         delete [] pPositions;
10661 
10662     if (pRampColRefs)
10663         delete [] pRampColRefs;
10664 
10665     if (!ok)
10666         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
10667 
10668     return ok;
10669 #else
10670     return FALSE;
10671 #endif
10672 }
10673 
10674 
10675 
10676 /********************************************************************************************
10677 
10678   > virtual BOOL AttrSquareColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
10679 
10680     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10681     Created:    9/8/96
10682     Inputs:     pFilter - ptr to the filter
10683     Returns:    TRUE if record is written, FALSE if not
10684     Purpose:    Writes the Square fill record to the filter
10685     SeeAlso:    -
10686 
10687 ********************************************************************************************/
10688 
10689 BOOL AttrSquareColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
10690 {
10691 #ifdef DO_EXPORT
10692     return WritePreChildrenWeb(pFilter);
10693 #else
10694     return FALSE;
10695 #endif
10696 }
10697 
10698 
10699 /********************************************************************************************
10700 
10701   > virtual BOOL AttrSquareColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
10702 
10703     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
10704     Created:    14/9/2000
10705     Inputs:     pFilter = ptr to the filter
10706     Returns:    TRUE if record is written, FALSE if not
10707     Purpose:    Writes out colour definitions for this fill.
10708     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
10709                 Layer::WriteAtomicNodesColourRefs ()
10710 
10711 ********************************************************************************************/
10712 
10713 BOOL AttrSquareColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
10714 {
10715     // Must write out the colours first
10716     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
10717     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
10718 
10719     BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
10720 
10721     if (ok)
10722     {
10723         ColourRamp * pRamp = GetColourRamp();
10724         if (pRamp)
10725         if (pRamp->GetCount() > 0)
10726         {
10727             ok = pRamp->WriteColourDefinitions (pFilter);
10728         }
10729     }
10730     
10731     return (ok);
10732 }
10733 
10735 //
10736 //                              AttrSquareTranspFill
10737 //
10739 
10740 /********************************************************************************************
10741 
10742 >   void AttrSquareTranspFill::Render( RenderRegion* pRender)
10743 
10744     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10745     Created:    9/8/96
10746     Purpose:    'Renders' a Square Fill Colour attribute.
10747 
10748 ********************************************************************************************/
10749 
10750 void AttrSquareTranspFill::Render(RenderRegion* pRender)
10751 {
10752     pRender->SetTranspFillGeometry(&Value, FALSE);
10753 }
10754 
10755 
10756 
10757 /********************************************************************************************
10758 >   virtual BOOL AttrSquareTranspFill::NeedsTransparency() const
10759 
10760     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10761     Created:    9/8/96
10762     Inputs:     -
10763     Outputs:    -
10764     Returns:    TRUE if this node requires transparency mode to render properly.
10765     Purpose:    Called to determine whether transparency is needed to render properly.
10766     Errors:     -
10767 
10768 ********************************************************************************************/
10769 
10770 BOOL AttrSquareTranspFill::NeedsTransparency() const
10771 {
10772     AttrSquareTranspFill* pNonConst = (AttrSquareTranspFill*) this;
10773     return (    pNonConst->GetTranspType()      != TT_Mix ||
10774                 *(pNonConst->GetStartTransp())  != 0 ||
10775                 *(pNonConst->GetEndTransp())    != 0 );
10776 }
10777 
10778 
10779 
10780 /********************************************************************************************
10781 
10782 > Node* AttrSquareTranspFill::SimpleCopy() 
10783 
10784     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10785     Created:    9/8/96
10786     Returns:    A copy of the node, or NULL if memory runs out 
10787     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
10788                 The function is virtual, and must be defined for all derived classes.  
10789     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
10790                 memory error and the function returns NULL. 
10791     Scope:      protected       
10792 
10793 ********************************************************************************************/
10794      
10795 Node* AttrSquareTranspFill::SimpleCopy()
10796 {
10797     AttrSquareTranspFill* NodeCopy = new AttrSquareTranspFill();
10798     if (NodeCopy == NULL)
10799         return NULL;
10800 
10801     CopyNodeContents(NodeCopy);
10802     
10803     return NodeCopy;
10804 }  
10805 
10806 
10807 
10808 /********************************************************************************************
10809 
10810 >   void AttrSquareTranspFill::RenderFillBlobs(RenderRegion* pRender)
10811 
10812     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10813     Created:    9/8/96
10814     Inputs:     pRender - The region to render the blobs to.
10815     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
10816 
10817 ********************************************************************************************/
10818 
10819 void AttrSquareTranspFill::RenderFillBlobs(RenderRegion* pRender)
10820 {
10821 #if !defined(EXCLUDE_FROM_RALPH)
10822     if (!IsVisible())
10823         return;     // We're in Fill Transparency Mode
10824 
10825     // Don't bother if this fill is being edited as a copy of it
10826     // we be rendered thoughout the drag op
10827     if (IsFillBeingEdited())
10828         return;
10829 
10830     // Ignore this if the mesh is the same as the last one rendered.
10831     if (CheckPreviousFillMesh())
10832         return;
10833 
10834     DocCoord ControlPoints[5];
10835     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
10836     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
10837     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
10838 
10839     // Render a nice pretty Fill Mesh thingy
10840     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
10841 
10842     // This call was removed by Gerry (2/9/96) as it causes blob problems
10843     // If we are removing blobs then force all blobs to be deselected
10844 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
10845 //      DeselectAllNoRedraw();
10846 #endif
10847 }
10848 
10849 
10850 
10851 /********************************************************************************************
10852 
10853 >   virtual UINT32 AttrSquareTranspFill::GetAttrNameID(void)  
10854 
10855     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10856     Created:    9/8/96
10857     Returns:    Attribute description ID
10858     Purpose:    Returns a string resource ID describing the attribute
10859 
10860 ********************************************************************************************/
10861 
10862 UINT32 AttrSquareTranspFill::GetAttrNameID(void)  
10863 {
10864     return (_R(IDS_SQUARETRANSPFILL));
10865 }                                  
10866 
10867 
10868 
10869 /********************************************************************************************
10870 
10871 >   void AttrSquareTranspFill::GetDebugDetails(StringBase* Str)
10872 
10873     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10874     Created:    9/8/96
10875     Outputs:    Str - the string containing details of the attribute.
10876     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
10877 
10878 ********************************************************************************************/
10879 
10880 void AttrSquareTranspFill::GetDebugDetails(StringBase* Str)
10881 {
10882 #ifdef _DEBUG
10883     NodeAttribute::GetDebugDetails( Str );
10884 
10885     String_256 TempStr;
10886 
10887     TempStr._MakeMsg( TEXT("\r\nSquare Graduated Fill:\r\n"));
10888     (*Str) += TempStr;
10889 
10890     TempStr._MakeMsg(TEXT("\r\nStart"));
10891     (*Str) += TempStr;
10892 
10893     TempStr._MakeMsg(TEXT("\r\nEnd"));
10894     (*Str) += TempStr;
10895 
10896     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
10897                      (*GetStartPoint()).x, (*GetStartPoint()).y);
10898     (*Str) += TempStr;
10899 
10900     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
10901                      (*GetEndPoint()).x, (*GetEndPoint()).y);
10902     (*Str) += TempStr;
10903 
10904     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
10905                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
10906     (*Str) += TempStr;
10907 #endif
10908 }
10909 
10910 
10911 
10912 /********************************************************************************************
10913 
10914 >   virtual UINT32 AttrSquareTranspFill::GetNodeSize() const
10915 
10916     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10917     Created:    9/8/96
10918     Returns:    The size of the node in bytes
10919     Purpose:    For finding the size of the node.
10920     SeeAlso:    Node::GetSubtreeSize
10921 
10922 ********************************************************************************************/
10923 
10924 UINT32 AttrSquareTranspFill::GetNodeSize() const 
10925 {     
10926     return sizeof(AttrSquareTranspFill);
10927 }  
10928 
10929 
10930 
10931 /********************************************************************************************
10932 
10933   > virtual BOOL AttrSquareTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
10934 
10935     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10936     Created:    9/8/96
10937     Inputs:     pFilter - ptr to the filter
10938     Returns:    TRUE if record is written, FALSE if not
10939     Purpose:    Writes the Square transparent fill record to the filter
10940     SeeAlso:    -
10941 
10942 ********************************************************************************************/
10943 
10944 BOOL AttrSquareTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
10945 {
10946 #ifdef DO_EXPORT
10947     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
10948     ERROR3IF(Value.Transp     > 255,"Start transparency level is too high to be stored as a byte");
10949     ERROR3IF(Value.EndTransp  > 255,"End transparency level is too high to be stored as a byte");
10950     ERROR3IF(Value.TranspType > 255,"Transparency type is too high to be stored as a byte");
10951 
10952     BOOL ok = TRUE;
10953 
10954     CamelotFileRecord Rec(pFilter,TAG_SQUARETRANSPARENTFILL,TAG_SQUARETRANSPARENTFILL_SIZE);
10955 
10956     if (ok) ok = Rec.Init();
10957     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
10958     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
10959     if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
10960     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
10961     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));
10962     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
10963     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
10964     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
10965     if (ok) ok = pFilter->Write(&Rec);
10966 
10967     if (!ok)
10968         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
10969 
10970     return ok;
10971 #else
10972     return FALSE;
10973 #endif
10974 }
10975 
10976 
10977 
10978 /********************************************************************************************
10979 
10980   > virtual BOOL AttrSquareTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
10981 
10982     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
10983     Created:    9/8/96
10984     Inputs:     pFilter - ptr to the filter
10985     Returns:    TRUE if record is written, FALSE if not
10986     Purpose:    Writes the Square transparent fill record to the filter
10987     SeeAlso:    -
10988 
10989 ********************************************************************************************/
10990 
10991 BOOL AttrSquareTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
10992 {
10993 #ifdef DO_EXPORT
10994     return WritePreChildrenWeb(pFilter);
10995 #else
10996     return FALSE;
10997 #endif
10998 }
10999 
11000 
11001 
11002 
11003 
11004 /********************************************************************************************
11005 >   BOOL AttrSquareTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
11006 
11007     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
11008     Created:    11/05/2005
11009     Inputs:     -
11010     Outputs:    -
11011     Returns:    TRUE if this node has a value equivalent to the relevant 
11012                 FALSE otherwise
11013     Purpose:    Determine whether this attribute has the default value or not
11014     Errors:     -
11015     SeeAlso:    -
11016 ********************************************************************************************/
11017 
11018 BOOL AttrSquareTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
11019 {
11020     // Slight bodge - we will assume that the default transparency is fully opaque
11021     if (bAppearance)
11022         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0));
11023     else
11024         return FALSE;
11025 }
11026 
11027 
11028 
11029 
11031 //
11032 //                              AttrThreeColFill
11033 //
11035 
11036 
11037 /********************************************************************************************
11038 
11039 >   void AttrThreeColFill::TransformSelectedControlPoints( TransformBase& Trans)
11040 
11041     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11042     Created:    28/8/96
11043     Inputs:     Trans - the transform object to apply to this attribute.
11044     Purpose:    Transform a grad fill attribute by moving the selected control points.
11045     SeeAlso:    NodeRenderable::Transform
11046 
11047 ********************************************************************************************/
11048 
11049 void AttrThreeColFill::TransformSelectedControlPoints( TransformBase& Trans, BOOL* isARampBlob /*= NULL*/)
11050 {
11051 #if !defined(EXCLUDE_FROM_RALPH)
11052     if ( Trans.TransFills )
11053     {
11054         ClickModifiers ClickMods;
11055         ClickMods.Adjust = FALSE;       // Force adjust off
11056 
11057         // If the start point is selected then move the whole mesh
11058         if (IsSelected(FILLCONTROL_STARTPOINT))
11059         {
11060             DocCoord Pos = *GetStartPoint();
11061             Trans.Transform( &Pos, 1);
11062 
11063             FillControl Start = FILLCONTROL_STARTPOINT;
11064 
11065             OnControlDrag(Pos, Start, ClickMods);
11066         }
11067         else
11068         {
11069             // Otherwise move the fill points
11070             if (IsSelected(FILLCONTROL_ENDPOINT))
11071             {
11072                 DocCoord Pos = *GetEndPoint();
11073                 Trans.Transform( &Pos, 1);
11074 
11075                 FillControl End = FILLCONTROL_ENDPOINT;
11076 
11077                 OnControlDrag(Pos, End, ClickMods);
11078             }
11079 
11080             if (IsSelected(FILLCONTROL_ENDPOINT2))
11081             {
11082                 DocCoord Pos = *GetEndPoint2();
11083                 Trans.Transform( &Pos, 1);
11084 
11085                 FillControl End2 = FILLCONTROL_ENDPOINT2;
11086 
11087                 OnControlDrag(Pos, End2, ClickMods);
11088             }
11089         }
11090     }
11091 #endif
11092 }
11093 
11094 
11095 /********************************************************************************************
11096 
11097 >   virtual FillControl AttrThreeColFill::TestColourDrop(AttrColourDrop* ColDrop) 
11098 
11099     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11100     Created:    9/8/96
11101     Inputs:     ColDrop - pointer to the 
11102     Purpose:    Check to see which colour will be changed if dropped at this point
11103 
11104 ********************************************************************************************/
11105 
11106 FillControl AttrThreeColFill::TestColourDrop(AttrColourDrop* ColDrop) 
11107 { 
11108 #if !defined(EXCLUDE_FROM_RALPH)
11109     // So, where was it dropped (or where will it be dropped)
11110     DocCoord DropPoint = ColDrop->GetDropPoint();
11111 
11112     // Look to see if the DropPoint is over any of the Fill Control Points
11113     FillControl ControlHit = CheckForControlHit(DropPoint);
11114     
11115     // If it hit one of our control points, then use that
11116     if (ControlHit != FILLCONTROL_NULL)
11117         return ControlHit;
11118 
11119     // It didn't hit any of our control points, so if the drop is over
11120     // the object then we'll make a guess as to which control point
11121     // the user would like to change, depending on which area of the
11122     // object the pointer is over.
11123 
11124     // First make sure we're actually over an object
11125     NodeRenderableInk* pParentObject = ColDrop->GetObjectDroppedOn();
11126     if (pParentObject == NULL)
11127         return FILLCONTROL_NULL;    // We're not over any object 
11128 
11129     // Make sure this fill type has some Control Points
11130     if (GetStartPoint() == NULL || GetEndPoint() == NULL || GetEndPoint2() == NULL)
11131         return FILLCONTROL_NULL;
11132 
11133     DocCoord StartPoint = *GetStartPoint();
11134     DocCoord EndPoint   = *GetEndPoint();
11135     DocCoord EndPoint2  = *GetEndPoint2();
11136 
11137     double StartDist = DropPoint.Distance(StartPoint);
11138     double EndDist = DropPoint.Distance(EndPoint);
11139     double End2Dist = DropPoint.Distance(EndPoint2);
11140     
11141     // FInd which point is closest
11142     
11143     if (StartDist < End2Dist)
11144     {
11145         if (StartDist < EndDist)
11146             ControlHit = FILLCONTROL_STARTPOINT;
11147         else
11148             ControlHit = FILLCONTROL_ENDPOINT;
11149     }
11150     else
11151     {
11152         if (EndDist < End2Dist)
11153             ControlHit = FILLCONTROL_ENDPOINT;
11154         else
11155             ControlHit = FILLCONTROL_ENDPOINT2;
11156     }
11157 
11158     return ControlHit;
11159 #else
11160     return FILLCONTROL_NULL;
11161 #endif
11162 }
11163 
11164 
11165 
11166 /********************************************************************************************
11167 
11168 >   void AttrThreeColFill::Transform( TransformBase& Trans )
11169 
11170     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11171     Created:    9/8/96
11172     Inputs:     Trans - the transform object to apply to this attribute.
11173     Purpose:    Transform a grad fill attribute by moving the start and end points.
11174     SeeAlso:    Copied from AttrLinearFill
11175 
11176 ********************************************************************************************/
11177 
11178 void AttrThreeColFill::Transform( TransformBase& Trans )
11179 {
11180     if ( Trans.TransFills )
11181     {
11182         Trans.Transform( GetStartPoint(), 1);
11183         Trans.Transform( GetEndPoint(), 1);
11184         Trans.Transform( GetEndPoint2(), 1);
11185 
11186         if (IsPerspective())
11187             Trans.Transform( GetEndPoint3(), 1);
11188     }
11189 }
11190 
11191 
11192 
11193 /********************************************************************************************
11194 
11195 >   BOOL AttrThreeColFill::CanTransform()
11196 
11197     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11198     Created:    9/8/96
11199     Returns:    TRUE => transform this attribute.
11200     Purpose:    Indicate that this attribute can be transformed.
11201     SeeAlso:    Copied from AttrLinearFill
11202 
11203 ********************************************************************************************/
11204 
11205 BOOL AttrThreeColFill::CanTransform()
11206 {
11207     return TRUE;
11208 }
11209 
11210 
11211 
11212 /********************************************************************************************
11213 
11214 >   void AttrThreeColFill::RenderFillMesh(RenderRegion* pRender, 
11215                                     DocCoord* ControlPoints, BOOL* SelState,
11216                                     INT32 NumControlPoints)
11217     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11218     Created:    9/8/96
11219     Inputs:     pRender - The region to render the blobs to.
11220                 ControlPoints - The positions of all the control points
11221                 SelState - The selection state of the control points
11222                 NumControlPoints - The Number of control points.
11223     Purpose:    Renders the grad fills mesh during a drag op.
11224                 Don't call this, call RenderFillBlobs().
11225     SeeAlso:    AttrThreeColFill::RenderFillBlobs
11226 
11227 ********************************************************************************************/
11228 
11229 void AttrThreeColFill::RenderFillMesh(RenderRegion* pRender, 
11230                                     DocCoord* ControlPoints, BOOL* SelState,
11231                                     INT32 NumControlPoints)
11232 {
11233 #if !defined(EXCLUDE_FROM_RALPH)
11234     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
11235     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
11236     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_ENDPOINT2];
11237 
11238     if (StartPoint == EndPoint)
11239         return;
11240 
11241     if (SelState == NULL)
11242     {
11243         // If no selection state passed in, then assume
11244         // all the points are deselected
11245         BOOL Selected[NUMCONTROLPOINTS];
11246         for (INT32 i=0; i< NumControlPoints; i++)
11247         {
11248             Selected[i] = FALSE;
11249         }
11250         SelState = Selected;
11251     }
11252 
11253     // Remember what attributes were here before
11254     pRender->SaveContext();
11255 
11256     // Get the current blob size in Doc Units
11257     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
11258 
11259     // Calculate the Arrow on the End of the Line
11260     Path ArrowPath;
11261     ArrowPath.Initialise();
11262     DocCoord LineEnd;
11263     MakeMeshArrow(&ArrowPath, StartPoint, EndPoint, &LineEnd);
11264 
11265     // Calculate the Arrow on the End of the Line2
11266     Path ArrowPath2;
11267     ArrowPath2.Initialise();
11268     DocCoord LineEnd2;
11269     MakeMeshArrow(&ArrowPath2, StartPoint, EndPoint2, &LineEnd2);
11270 
11271     // Set the line colours etc as we need them
11272     pRender->SetLineWidth(0);
11273     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
11274     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
11275 
11276     // First Draw the Line
11277     pRender->SetLineWidth(BlobSize/4);
11278     pRender->DrawLine(StartPoint, LineEnd);
11279 
11280     // Draw the secondary line
11281     pRender->DrawLine(StartPoint, LineEnd2);
11282 
11283     // Render an Arrow at the end of the line
11284     pRender->SetLineWidth(0);
11285     pRender->SetLineColour(COLOUR_NONE);
11286     pRender->DrawPath(&ArrowPath);
11287 
11288     // and on the end of the secondary line
11289     pRender->DrawPath(&ArrowPath2);
11290 
11291     if (DraggedFill == this)
11292     {
11293         // If we are being dragged then draw a line accros the end of the triangle
11294         pRender->SetLineColour(COLOUR_SELECTEDBLOB);
11295         pRender->SetFillColour(COLOUR_NONE);
11296         pRender->DrawLine(EndPoint, EndPoint2);
11297     }
11298 
11299     // Now Render the blobs on the path
11300     // Set the line colour to none
11301     pRender->SetLineColour(COLOUR_NONE);
11302 
11303     // Draw a blob at the start point
11304     if (SelState[FILLCONTROL_STARTPOINT])
11305     {
11306         // Draw Selected Blob
11307         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
11308         pRender->DrawBlob(StartPoint, BT_SELECTED);
11309     }
11310     else
11311     {
11312         // Draw Unselected Blob
11313         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
11314         pRender->DrawBlob(StartPoint, BT_UNSELECTED);
11315     }
11316 
11317     // Draw the blobs at the end points
11318     if (SelState[FILLCONTROL_ENDPOINT])
11319     {
11320         // Draw Selected Blobs
11321         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
11322         pRender->DrawBlob(EndPoint, BT_SELECTED);
11323     }
11324     else
11325     {
11326         // Draw Unselected Blobs
11327         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
11328         pRender->DrawBlob(EndPoint, BT_UNSELECTED);
11329     }
11330 
11331     // Draw the blobs at the second end point
11332     if (SelState[FILLCONTROL_ENDPOINT2])
11333     {
11334         // Draw Selected Blobs
11335         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
11336         pRender->DrawBlob(EndPoint2,BT_SELECTED);
11337     }
11338     else
11339     {
11340         // Draw Unselected Blobs
11341         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
11342         pRender->DrawBlob(EndPoint2,BT_UNSELECTED);
11343     }
11344 
11345     // Put all the old attributes back
11346     pRender->RestoreContext();
11347 #endif
11348 }
11349 
11350 
11351 
11352 /********************************************************************************************
11353 
11354 >   virtual void AttrThreeColFill::OnControlDrag(DocCoord Pos, FillControl DragControl, 
11355                                                     ClickModifiers ClickMods)
11356     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11357     Created:    9/8/96
11358     Inputs:     Pos - The Location of the mouse pointer at the time of the call
11359                 DragControl - The FillControl that is being dragged.
11360                 ClickMods - The modifiers to the click (eg shift, control etc )
11361     Purpose:    Called when an edit operation is dragging a control point.
11362 
11363 ********************************************************************************************/
11364 
11365 void AttrThreeColFill::OnControlDrag(DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
11366 {
11367 #if !defined(EXCLUDE_FROM_RALPH)
11368     // Get the current Control Positions
11369     DocCoord StartPoint = *GetStartPoint();
11370     DocCoord EndPoint = *GetEndPoint();
11371     DocCoord EndPoint2 = *GetEndPoint2();
11372 
11373     INT32 dx, dy;
11374 
11375     // Which control point is being dragged ?
11376     switch (DragControl)
11377     {
11378         case FILLCONTROL_STARTPOINT:
11379         
11380             // Someone is dragging the Centre of the Fill
11381             dx = StartPoint.x - Pos.x;
11382             dy = StartPoint.y - Pos.y;
11383             // Move the other points relative
11384             EndPoint.translate(-dx, -dy);
11385             EndPoint2.translate(-dx, -dy);
11386 
11387             SetEndPoint(&EndPoint);
11388             SetEndPoint2(&EndPoint2);
11389             SetStartPoint(&Pos);
11390             break;
11391 
11392         case FILLCONTROL_ENDPOINT:
11393             
11394             // Someone is dragging the first End Point
11395             
11396             // Constrain the angle if necessary
11397             if (ClickMods.Constrain)
11398                 DocView::ConstrainToAngle(StartPoint, &Pos);
11399 
11400             // The mesh can be locked as an equilateral triangle by the Shift key
11401             if (ClickMods.Adjust)
11402             {
11403                 double OldLen = StartPoint.Distance(EndPoint);
11404                 double NewLen = StartPoint.Distance(Pos);
11405                 double Ratio = 1.0;
11406 
11407                 if (OldLen == 0)
11408                     Ratio = 0;
11409                 else
11410                     Ratio = NewLen/OldLen;
11411 
11412                 // Calculate the new end point
11413                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, 60, INT32(StartPoint.Distance(EndPoint2) * Ratio));
11414                 SetEndPoint2(&temp);
11415             }
11416 
11417             SetEndPoint(&Pos);
11418             break;
11419 
11420         case FILLCONTROL_ENDPOINT2:
11421 
11422             // Someone is dragging the second End Point
11423             
11424             // Constrain the angle if necessary
11425             if (ClickMods.Constrain)
11426                 DocView::ConstrainToAngle(StartPoint, &Pos);
11427 
11428             // The mesh can be locked as an equilateral triangle by the Shift key
11429             if (ClickMods.Adjust)
11430             {
11431                 double OldLen = StartPoint.Distance(EndPoint2);
11432                 double NewLen = StartPoint.Distance(Pos);
11433                 double Ratio = 1.0;
11434 
11435                 if (OldLen == 0)
11436                     Ratio = 0;
11437                 else
11438                     Ratio = NewLen/OldLen;
11439 
11440                 // Calculate the new end point
11441                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, -60, INT32(StartPoint.Distance(EndPoint) * Ratio));
11442                 SetEndPoint(&temp);
11443             }
11444 
11445             SetEndPoint2(&Pos);
11446             break;
11447     }
11448 #endif
11449 }
11450 
11451 
11452 
11453 /********************************************************************************************
11454 
11455 >   virtual DocRect AttrThreeColFill::GetBlobBoundingRect()
11456 
11457     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11458     Created:    9/8/96
11459     Returns:    DocRect - The rectangle that contains all the nodes selection blobs.
11460     Purpose:    Calculates the bounding rectangle of the attrs blobs.This should always 
11461                 be calculated on the fly as the view scale can change without the attr 
11462                 knowing, giving an incorrect result.
11463 
11464 ********************************************************************************************/
11465 
11466 DocRect AttrThreeColFill::GetBlobBoundingRect()
11467 {
11468 #if !defined(EXCLUDE_FROM_RALPH)
11469     // Optimisation.  If there is currently no interest in Fill Blobs
11470     // and this fill is not being Dragged (Fill blobs are turned off during
11471     // a fill drag), then we needn't bother doing anything. 
11472     if ( (!GetApplication()->GetBlobManager()->GetCurrentInterest(TRUE).Fill || !IsVisible()) && DraggedFill != this )
11473         return DocRect(0,0, 0,0);
11474 
11475     // Get the Start and End Points
11476     DocCoord StartPoint = *GetStartPoint();
11477     DocCoord EndPoint = *GetEndPoint();
11478     DocCoord EndPoint2 = *GetEndPoint2();
11479 
11480     // Make a dummy bounds from just the Start Point
11481     DocRect BoundingRect(StartPoint, StartPoint);
11482 
11483     // We're not being dragged, so just calc the bounds of the Start and End Blobs
11484     DocRect BlobRect;
11485 
11486     // Get the Bounding rect of the Blob and include the Bottom Left and
11487     // Top Right of each blob in the Bounds.
11488     // We have to do it like this to make sure that the DocRect's coords
11489     // are valid.  ie. The Hi's are Higher than the Lo's.
11490     (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &BlobRect);
11491     BoundingRect.IncludePoint(BlobRect.lo);
11492     BoundingRect.IncludePoint(BlobRect.hi);
11493 
11494     (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &BlobRect);
11495     BoundingRect.IncludePoint(BlobRect.lo);
11496     BoundingRect.IncludePoint(BlobRect.hi);
11497 
11498     (Camelot.GetBlobManager())->GetBlobRect(EndPoint2, &BlobRect);
11499     BoundingRect.IncludePoint(BlobRect.lo);
11500     BoundingRect.IncludePoint(BlobRect.hi);
11501 
11502     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint);
11503     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint2);
11504 
11505     // and return it
11506     return BoundingRect;
11507 #else
11508     return DocRect(0,0,0,0);
11509 #endif
11510 }
11511 
11512 
11513 /********************************************************************************************
11514 
11515 >   virtual void AttrThreeColFill::RenderControl(FillControl Control, BOOL RenderOn)
11516 
11517     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11518     Created:    14/08/96
11519     Inputs:     Control, the control to render
11520                 RenderOn, TRUE if rendering blob on FALSE if off
11521     Purpose:    Renders a specified control
11522     SeeAlso:    FillControl
11523 
11524 ********************************************************************************************/
11525 
11526 void AttrThreeColFill::RenderControl(FillControl Control, BOOL RenderOn)
11527 {
11528 #if !defined(EXCLUDE_FROM_RALPH)
11529     DocRect ControlRect;
11530 
11531     // Ignore if we're not in the tree yet
11532     // We may be a tempory clone, or something
11533     NodeRenderable* pParent = (NodeRenderable*)FindParent();
11534 
11535     if (pParent == NULL)
11536         return;
11537 
11538     if (IsBlobSame(Control))
11539         return;         // Ignore if same as the last blob rendered
11540 
11541     Spread* pSpread = this->FindParentSpread();
11542 
11543     switch (Control)
11544     {
11545         case FILLCONTROL_STARTPOINT:
11546             if (GetStartPoint() != NULL)
11547             {
11548                 // Redraw the Start Point Blob
11549                 (Camelot.GetBlobManager())->GetBlobRect(*GetStartPoint(), &ControlRect);
11550                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
11551             }
11552             break;
11553 
11554         case FILLCONTROL_ENDPOINT:
11555             if (GetEndPoint() != NULL)
11556             {
11557                 // Redraw BOTH End Point Blobs
11558                 (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint(), &ControlRect);
11559                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
11560             }
11561             break;
11562 
11563         case FILLCONTROL_ENDPOINT2:
11564             if (GetEndPoint2() != NULL)
11565             {
11566                 (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint2(), &ControlRect);
11567                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
11568             }
11569             break;
11570     }
11571 #endif
11572 }
11573 
11574     
11575 /********************************************************************************************
11576 
11577 >   virtual void AttrThreeColFill::CycleSelection(BOOL Reverse)
11578 
11579     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11580     Created:    14/08/96
11581     Purpose:    Cycles the selection state of the controls
11582 
11583 ********************************************************************************************/
11584 
11585 void AttrThreeColFill::CycleSelection(BOOL Reverse)
11586 {
11587     if (GetSelectionCount() == 1)
11588     {
11589         if (SelectionState[FILLCONTROL_STARTPOINT])
11590         {
11591             DeselectAll();
11592             if (Reverse)
11593                 SelectBlob(FILLCONTROL_ENDPOINT2);
11594             else
11595                 SelectBlob(FILLCONTROL_ENDPOINT);
11596         }
11597         else if (SelectionState[FILLCONTROL_ENDPOINT])
11598         {
11599             DeselectAll();
11600             if (Reverse)
11601                 SelectBlob(FILLCONTROL_STARTPOINT);
11602             else
11603                 SelectBlob(FILLCONTROL_ENDPOINT2);
11604         }
11605         else if (SelectionState[FILLCONTROL_ENDPOINT2])
11606         {
11607             DeselectAll();
11608             if (Reverse)
11609                 SelectBlob(FILLCONTROL_ENDPOINT);
11610             else
11611                 SelectBlob(FILLCONTROL_STARTPOINT);
11612         }
11613     }
11614 }
11615 
11616 
11617 /********************************************************************************************
11618 
11619 >   FillControl AttrThreeColFill::CheckForControlHit(DocCoord &ClickPos)
11620 
11621     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11622     Created:    14/08/96
11623     Inputs:     ClickPos, The DocCoord position to check.
11624     Returns:    A FillControl, indicating the Fill Control Point Hit,
11625                 or FILLCONTROL_NULL, if no points hit.
11626     Purpose:    Check to see if a click was on a Fill Control Point. 
11627     SeeAlso:    FillControl
11628 
11629 ********************************************************************************************/
11630 
11631 FillControl AttrThreeColFill::CheckForControlHit(DocCoord &ClickPos)
11632 {
11633     // Set up a default, that indicates not control points hit
11634     FillControl HitControl = FILLCONTROL_NULL;
11635 #if !defined(EXCLUDE_FROM_RALPH)
11636     DocRect BlobRect;
11637 
11638     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
11639         return FILLCONTROL_NULL;
11640 
11641 
11642     // Get the rectangle around the Start Control Point
11643     (Camelot.GetBlobManager())->GetBlobRect(*GetStartPoint(), &BlobRect);
11644     // See if the Click Position is within the rectangle
11645     if ( BlobRect.ContainsCoord(ClickPos) )
11646         HitControl = FILLCONTROL_STARTPOINT;
11647 
11648     // Get the rectangle around the End Control Point
11649     (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint(), &BlobRect);
11650     // See if the Click Position is within the rectangle
11651     if ( BlobRect.ContainsCoord(ClickPos) )
11652         HitControl = FILLCONTROL_ENDPOINT;
11653 
11654     // Get the rectangle around the Secondary Control Point
11655     (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint2(), &BlobRect);
11656     // See if the Click Position is within the rectangle
11657     if ( BlobRect.ContainsCoord(ClickPos) )
11658         HitControl = FILLCONTROL_ENDPOINT2;
11659 #endif
11660     return HitControl;
11661 }
11662 
11663 
11664 
11665 
11666 /********************************************************************************************
11667 
11668 >   void AttrThreeColFill::ValidateAttributeValue()
11669 
11670     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11671     Created:    9/8/96
11672     Purpose:    Makes sure the Coords of the Fill are sensible.
11673 
11674 ********************************************************************************************/
11675 
11676 void AttrThreeColFill::ValidateAttributeValue()
11677 {
11678 #if !defined(EXCLUDE_FROM_RALPH)
11679     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0))
11680     {
11681         // If the EndPoint2 is 'NULL' then make it sensible
11682         if (*GetEndPoint2() == DocCoord(0,0))
11683         {
11684             DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90);
11685             SetEndPoint2(&temp);
11686         }
11687         
11688         return;
11689     }
11690 
11691     // Make up some sensible defaults
11692     DocRect AttrBounds = DocRect(0,0,0,0);
11693 
11694     INT32 Width  = DEFAULT_FILLWIDTH;
11695     INT32 Height = DEFAULT_FILLHEIGHT;
11696 
11697     // Are we an Orphan ?
11698     if (FindParent() != NULL)
11699     {
11700         // Nope, so we can use Daddies Bounding Box
11701         SelRange* Selected = GetApplication()->FindSelection();
11702                  
11703         if (Selected == NULL || Selected->Count() <= 1)
11704             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
11705         else
11706             AttrBounds = Selected->GetBoundingRect();
11707 
11708         Width  = AttrBounds.Width();
11709         Height = AttrBounds.Height();
11710     }
11711 
11712     // If the StartPoint is 'NULL' then make all points sensible
11713     if ((*GetStartPoint()) == DocCoord(0,0))
11714     {
11715         // Start in the centre of the bounds
11716         SetStartPoint(&AttrBounds.lo);
11717 
11718         // and set End Points to Middle Right, and Middle Top
11719         DocCoord temp = DocCoord(AttrBounds.hi.x, AttrBounds.lo.y);
11720         SetEndPoint(&temp);
11721         temp = DocCoord(AttrBounds.lo.x, AttrBounds.hi.y);
11722         SetEndPoint2(&temp);
11723     }
11724 
11725     // If the EndPoint is 'NULL' then make it sensible
11726     if ((*GetEndPoint()) == DocCoord(0,0))
11727     {
11728         DocCoord temp = DocCoord(AttrBounds.hi.x, AttrBounds.lo.y);
11729         SetEndPoint(&temp);
11730     }
11731 
11732     if ((*GetEndPoint2()) == DocCoord(0,0))
11733     {
11734         DocCoord temp = DocCoord(AttrBounds.lo.x, AttrBounds.hi.y);
11735         SetEndPoint2(&temp);
11736     }
11737 #endif
11738 }
11739 
11740 
11741 
11743 //
11744 //                              AttrThreeColColourFill
11745 //
11747 
11748 /********************************************************************************************
11749 
11750 >   void AttrThreeColColourFill::Render( RenderRegion* pRender)
11751 
11752     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11753     Created:    9/8/96
11754     Purpose:    'Renders' a ThreeCol Fill Colour attribute.
11755 
11756 ********************************************************************************************/
11757 
11758 void AttrThreeColColourFill::Render(RenderRegion* pRender)
11759 {
11760     pRender->SetFillGeometry(&Value, FALSE);
11761 }
11762 
11763 
11764 
11765 /********************************************************************************************
11766 
11767 > Node* AttrThreeColColourFill::SimpleCopy() 
11768 
11769     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11770     Created:    9/8/96
11771     Returns:    A copy of the node, or NULL if memory runs out 
11772     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
11773                 The function is virtual, and must be defined for all derived classes.  
11774     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
11775                 memory error and the function returns NULL. 
11776     Scope:      protected       
11777 
11778 ********************************************************************************************/
11779      
11780 Node* AttrThreeColColourFill::SimpleCopy()
11781 {
11782     AttrThreeColColourFill* NodeCopy = new AttrThreeColColourFill();
11783     if (NodeCopy == NULL)
11784         return NULL;
11785 
11786     CopyNodeContents(NodeCopy);
11787     
11788     return NodeCopy;
11789 }  
11790 
11791 
11792 
11793 /********************************************************************************************
11794 
11795 >   void AttrThreeColColourFill::RenderFillBlobs(RenderRegion* pRender)
11796 
11797     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11798     Created:    9/8/96
11799     Inputs:     pRender - The region to render the blobs to.
11800     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
11801 
11802 ********************************************************************************************/
11803 
11804 void AttrThreeColColourFill::RenderFillBlobs(RenderRegion* pRender)
11805 {
11806 #if !defined(EXCLUDE_FROM_RALPH)
11807     if (!IsVisible())
11808         return;     // We're in Fill Transparency Mode
11809 
11810     // Don't bother if this fill is being edited as a copy of it
11811     // we be rendered thoughout the drag op
11812     if (IsFillBeingEdited())
11813         return;
11814 
11815     // Ignore this if the mesh is the same as the last one rendered.
11816     if (CheckPreviousFillMesh())
11817         return;
11818 
11819     DocCoord ControlPoints[3];
11820     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
11821     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
11822     ControlPoints[FILLCONTROL_ENDPOINT2] = (*GetEndPoint2());
11823 
11824     // Render a nice pretty Fill Mesh thingy
11825     RenderFillMesh(pRender, ControlPoints, SelectionState, 3);
11826 
11827     // This call was removed by Gerry (2/9/96) as it causes blob problems
11828     // If we are removing blobs then force all blobs to be deselected
11829 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
11830 //      DeselectAllNoRedraw();
11831 #endif
11832 }
11833 
11834 
11835 
11836 /********************************************************************************************
11837 
11838 >   virtual UINT32 AttrThreeColColourFill::GetAttrNameID(void)  
11839 
11840     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11841     Created:    9/8/96
11842     Returns:    Attribute description ID
11843     Purpose:    Returns a string resource ID describing the attribute
11844 
11845 ********************************************************************************************/
11846 
11847 UINT32 AttrThreeColColourFill::GetAttrNameID(void)  
11848 {
11849     return (_R(IDS_THREECOLGRADFILL)); 
11850 }                                  
11851 
11852 
11853 
11854 /********************************************************************************************
11855 
11856 >   void AttrThreeColColourFill::GetDebugDetails(StringBase* Str)
11857 
11858     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11859     Created:    9/8/96
11860     Outputs:    Str - the string containing details of the attribute.
11861     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
11862 
11863 ********************************************************************************************/
11864 
11865 void AttrThreeColColourFill::GetDebugDetails(StringBase* Str)
11866 {
11867 #ifdef _DEBUG
11868     NodeAttribute::GetDebugDetails( Str );
11869 
11870     String_256 TempStr;
11871 
11872     TempStr._MakeMsg( TEXT("\r\nDiamond Graduated Fill:\r\n"));
11873     (*Str) += TempStr;
11874 
11875 //  TempStr._MakeMsg(TEXT("\r\nStart"));
11876 //  (*GetStartColour()).GetDebugDetails(&TempStr);
11877 //  (*Str) += TempStr;
11878 
11879 //  TempStr._MakeMsg(TEXT("\r\nEnd"));
11880 //  (*GetEndColour()).GetDebugDetails(&TempStr);
11881 //  (*Str) += TempStr;
11882 
11883     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
11884                      (*GetStartPoint()).x, (*GetStartPoint()).y);
11885     (*Str) += TempStr;
11886 
11887     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
11888                      (*GetEndPoint()).x, (*GetEndPoint()).y);
11889     (*Str) += TempStr;
11890 
11891     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
11892                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
11893     (*Str) += TempStr;
11894 #endif
11895 }
11896 
11897 
11898 
11899 /********************************************************************************************
11900 
11901 >   virtual UINT32 AttrThreeColColourFill::GetNodeSize() const
11902 
11903     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11904     Created:    9/8/96
11905     Returns:    The size of the node in bytes
11906     Purpose:    For finding the size of the node.
11907     SeeAlso:    Node::GetSubtreeSize
11908 
11909 ********************************************************************************************/
11910 
11911 UINT32 AttrThreeColColourFill::GetNodeSize() const 
11912 {     
11913     return sizeof(AttrThreeColColourFill);
11914 }  
11915 
11916 
11917 
11918 /********************************************************************************************
11919 
11920   > virtual BOOL AttrThreeColColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
11921 
11922     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11923     Created:    9/8/96
11924     Inputs:     pFilter = ptr to the filter
11925     Returns:    TRUE if record is written, FALSE if not
11926     Purpose:    Writes the ThreeCol fill record to the filter
11927     SeeAlso:    -
11928 
11929 ********************************************************************************************/
11930 
11931 BOOL AttrThreeColColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
11932 {
11933 #ifdef DO_EXPORT
11934     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
11935 
11936     // Must write out the colours first
11937     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
11938     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
11939     INT32 EndCol2Ref     = pFilter->WriteRecord(&Value.EndColour2);
11940 
11941     // Are the colour references ok?
11942     BOOL ok = ((StartColRef != 0) && (EndColRef != 0) && (EndCol2Ref != 0));
11943         
11944     if (ok)
11945     {
11946         CamelotFileRecord Rec(pFilter,TAG_THREECOLFILL,TAG_THREECOLFILL_SIZE);
11947 
11948         if (ok) ok = Rec.Init();
11949         if (ok) ok = Rec.WriteCoord(Value.StartPoint);
11950         if (ok) ok = Rec.WriteCoord(Value.EndPoint);
11951         if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
11952         if (ok) ok = Rec.WriteReference(StartColRef);
11953         if (ok) ok = Rec.WriteReference(EndColRef);
11954         if (ok) ok = Rec.WriteReference(EndCol2Ref);
11955         if (ok) ok = pFilter->Write(&Rec);
11956     }
11957 
11958     if (!ok)
11959         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
11960 
11961     return ok;
11962 #else
11963     return FALSE;
11964 #endif
11965 }
11966 
11967 
11968 
11969 /********************************************************************************************
11970 
11971   > virtual BOOL AttrThreeColColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
11972 
11973     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11974     Created:    9/8/96
11975     Inputs:     pFilter - ptr to the filter
11976     Returns:    TRUE if record is written, FALSE if not
11977     Purpose:    Writes the ThreeCol fill record to the filter
11978     SeeAlso:    -
11979 
11980 ********************************************************************************************/
11981 
11982 BOOL AttrThreeColColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
11983 {
11984 #ifdef DO_EXPORT
11985     return WritePreChildrenWeb(pFilter);
11986 #else
11987     return FALSE;
11988 #endif
11989 }
11990 
11991 
11992 /********************************************************************************************
11993 
11994   > virtual BOOL AttrThreeColColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
11995 
11996     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
11997     Created:    14/9/2000
11998     Inputs:     pFilter = ptr to the filter
11999     Returns:    TRUE if record is written, FALSE if not
12000     Purpose:    Writes out colour definitions for this fill.
12001     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
12002                 Layer::WriteAtomicNodesColourRefs ()
12003 
12004 ********************************************************************************************/
12005 
12006 BOOL AttrThreeColColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
12007 {
12008     // Must write out the colours first
12009     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
12010     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
12011     INT32 EndCol2Ref     = pFilter->WriteRecord(&Value.EndColour2);
12012 
12013     // Are the colour references ok?
12014     BOOL ok = ((StartColRef != 0) && (EndColRef != 0) && (EndCol2Ref != 0));
12015     
12016     return (ok);
12017 }
12018 
12020 //
12021 //                              AttrThreeColTranspFill
12022 //
12024 
12025 /********************************************************************************************
12026 
12027 >   void AttrThreeColTranspFill::Render( RenderRegion* pRender)
12028 
12029     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12030     Created:    9/8/96
12031     Purpose:    'Renders' a ThreeCol Fill Colour attribute.
12032 
12033 ********************************************************************************************/
12034 
12035 void AttrThreeColTranspFill::Render(RenderRegion* pRender)
12036 {
12037     pRender->SetTranspFillGeometry(&Value, FALSE);
12038 }
12039 
12040 
12041 
12042 /********************************************************************************************
12043 >   virtual BOOL AttrThreeColTranspFill::NeedsTransparency() const
12044 
12045     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12046     Created:    9/8/96
12047     Inputs:     -
12048     Outputs:    -
12049     Returns:    TRUE if this node requires transparency mode to render properly.
12050     Purpose:    Called to determine whether transparency is needed to render properly.
12051     Errors:     -
12052 
12053 ********************************************************************************************/
12054 
12055 BOOL AttrThreeColTranspFill::NeedsTransparency() const
12056 {
12057     AttrThreeColTranspFill* pNonConst = (AttrThreeColTranspFill*) this;
12058     return (    pNonConst->GetTranspType()      != TT_Mix ||
12059                 *(pNonConst->GetStartTransp())  != 0 ||
12060                 *(pNonConst->GetEndTransp())    != 0 ||
12061                 *(pNonConst->GetEndTransp2())   != 0 );
12062 }
12063 
12064 
12065 
12066 /********************************************************************************************
12067 
12068 > Node* AttrThreeColTranspFill::SimpleCopy() 
12069 
12070     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12071     Created:    9/8/96
12072     Returns:    A copy of the node, or NULL if memory runs out 
12073     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
12074                 The function is virtual, and must be defined for all derived classes.  
12075     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
12076                 memory error and the function returns NULL. 
12077     Scope:      protected       
12078 
12079 ********************************************************************************************/
12080      
12081 Node* AttrThreeColTranspFill::SimpleCopy()
12082 {
12083     AttrThreeColTranspFill* NodeCopy = new AttrThreeColTranspFill();
12084     if (NodeCopy == NULL)
12085         return NULL;
12086 
12087     CopyNodeContents(NodeCopy);
12088     
12089     return NodeCopy;
12090 }  
12091 
12092 
12093 
12094 /********************************************************************************************
12095 
12096 >   void AttrThreeColTranspFill::RenderFillBlobs(RenderRegion* pRender)
12097 
12098     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12099     Created:    9/8/96
12100     Inputs:     pRender - The region to render the blobs to.
12101     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
12102 
12103 ********************************************************************************************/
12104 
12105 void AttrThreeColTranspFill::RenderFillBlobs(RenderRegion* pRender)
12106 {
12107 #if !defined(EXCLUDE_FROM_RALPH)
12108     if (!IsVisible())
12109         return;     // We're in Fill Transparency Mode
12110 
12111     // Don't bother if this fill is being edited as a copy of it
12112     // we be rendered thoughout the drag op
12113     if (IsFillBeingEdited())
12114         return;
12115 
12116     // Ignore this if the mesh is the same as the last one rendered.
12117     if (CheckPreviousFillMesh())
12118         return;
12119 
12120     DocCoord ControlPoints[3];
12121     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
12122     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
12123     ControlPoints[FILLCONTROL_ENDPOINT2] = (*GetEndPoint2());
12124 
12125     // Render a nice pretty Fill Mesh thingy
12126     RenderFillMesh(pRender, ControlPoints, SelectionState, 3);
12127 
12128     // This call was removed by Gerry (2/9/96) as it causes blob problems
12129     // If we are removing blobs then force all blobs to be deselected
12130 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
12131 //      DeselectAllNoRedraw();
12132 #endif
12133 }
12134 
12135 
12136 
12137 /********************************************************************************************
12138 
12139 >   virtual UINT32 AttrThreeColTranspFill::GetAttrNameID(void)  
12140 
12141     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12142     Created:    9/8/96
12143     Returns:    Attribute description ID
12144     Purpose:    Returns a string resource ID describing the attribute
12145 
12146 ********************************************************************************************/
12147 
12148 UINT32 AttrThreeColTranspFill::GetAttrNameID(void)  
12149 {
12150     return (_R(IDS_THREECOLTRANSPFILL)); 
12151 }                                  
12152 
12153 
12154 
12155 /********************************************************************************************
12156 
12157 >   void AttrThreeColTranspFill::GetDebugDetails(StringBase* Str)
12158 
12159     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12160     Created:    9/8/96
12161     Outputs:    Str - the string containing details of the attribute.
12162     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
12163 
12164 ********************************************************************************************/
12165 
12166 void AttrThreeColTranspFill::GetDebugDetails(StringBase* Str)
12167 {
12168 #ifdef _DEBUG
12169     NodeAttribute::GetDebugDetails( Str );
12170 
12171     String_256 TempStr;
12172 
12173     TempStr._MakeMsg( TEXT("\r\nThreeCol Graduated Fill:\r\n"));
12174     (*Str) += TempStr;
12175 
12176     TempStr._MakeMsg(TEXT("\r\nStart"));
12177     (*Str) += TempStr;
12178 
12179     TempStr._MakeMsg(TEXT("\r\nEnd"));
12180     (*Str) += TempStr;
12181 
12182     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
12183                      (*GetStartPoint()).x, (*GetStartPoint()).y);
12184     (*Str) += TempStr;
12185 
12186     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
12187                      (*GetEndPoint()).x, (*GetEndPoint()).y);
12188     (*Str) += TempStr;
12189 
12190     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
12191                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
12192     (*Str) += TempStr;
12193 #endif
12194 }
12195 
12196 
12197 
12198 /********************************************************************************************
12199 
12200 >   virtual UINT32 AttrThreeColTranspFill::GetNodeSize() const
12201 
12202     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12203     Created:    9/8/96
12204     Returns:    The size of the node in bytes
12205     Purpose:    For finding the size of the node.
12206     SeeAlso:    Node::GetSubtreeSize
12207 
12208 ********************************************************************************************/
12209 
12210 UINT32 AttrThreeColTranspFill::GetNodeSize() const 
12211 {     
12212     return sizeof(AttrThreeColTranspFill);
12213 }  
12214 
12215 
12216 
12217 /********************************************************************************************
12218 
12219   > virtual BOOL AttrThreeColTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
12220 
12221     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12222     Created:    9/8/96
12223     Inputs:     pFilter - ptr to the filter
12224     Returns:    TRUE if record is written, FALSE if not
12225     Purpose:    Writes the ThreeCol transparent fill record to the filter
12226     SeeAlso:    -
12227 
12228 ********************************************************************************************/
12229 
12230 BOOL AttrThreeColTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
12231 {
12232 #ifdef DO_EXPORT
12233     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
12234     ERROR3IF(Value.Transp     > 255,"Start transparency level is too high to be stored as a byte");
12235     ERROR3IF(Value.EndTransp  > 255,"End transparency level is too high to be stored as a byte");
12236     ERROR3IF(Value.EndTransp2 > 255,"End transparency2 level is too high to be stored as a byte");
12237     ERROR3IF(Value.TranspType > 255,"Transparency type is too high to be stored as a byte");
12238 
12239     BOOL ok = TRUE;
12240 
12241     CamelotFileRecord Rec(pFilter,TAG_THREECOLTRANSPARENTFILL,TAG_THREECOLTRANSPARENTFILL_SIZE);
12242 
12243     if (ok) ok = Rec.Init();
12244     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
12245     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
12246     if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
12247     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
12248     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));
12249     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp2));
12250     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
12251     if (ok) ok = pFilter->Write(&Rec);
12252 
12253     if (!ok)
12254         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
12255 
12256     return ok;
12257 #else
12258     return FALSE;
12259 #endif
12260 }
12261 
12262 
12263 
12264 /********************************************************************************************
12265 
12266   > virtual BOOL AttrThreeColTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
12267 
12268     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12269     Created:    9/8/96
12270     Inputs:     pFilter - ptr to the filter
12271     Returns:    TRUE if record is written, FALSE if not
12272     Purpose:    Writes the ThreeCol transparent fill record to the filter
12273     SeeAlso:    -
12274 
12275 ********************************************************************************************/
12276 
12277 BOOL AttrThreeColTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
12278 {
12279 #ifdef DO_EXPORT
12280     return WritePreChildrenWeb(pFilter);
12281 #else
12282     return FALSE;
12283 #endif
12284 }
12285 
12286 
12287 
12288 
12289 /********************************************************************************************
12290 >   BOOL AttrThreeColTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
12291 
12292     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
12293     Created:    11/05/2005
12294     Inputs:     -
12295     Outputs:    -
12296     Returns:    TRUE if this node has a value equivalent to the relevant 
12297                 FALSE otherwise
12298     Purpose:    Determine whether this attribute has the default value or not
12299     Errors:     -
12300     SeeAlso:    -
12301 ********************************************************************************************/
12302 
12303 BOOL AttrThreeColTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
12304 {
12305     // Slight bodge - we will assume that the default transparency is fully opaque
12306     if (bAppearance)
12307         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0 && Value.EndTransp2==0));
12308     else
12309         return FALSE;
12310 }
12311 
12312 
12313 
12314 
12316 //
12317 //                              AttrFourColFill
12318 //
12320 
12321 
12322 /********************************************************************************************
12323 
12324 >   void AttrFourColFill::TransformSelectedControlPoints( TransformBase& Trans)
12325 
12326     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12327     Created:    28/8/96
12328     Inputs:     Trans - the transform object to apply to this attribute.
12329     Purpose:    Transform a grad fill attribute by moving the selected control points.
12330     SeeAlso:    NodeRenderable::Transform
12331 
12332 ********************************************************************************************/
12333 
12334 void AttrFourColFill::TransformSelectedControlPoints( TransformBase& Trans, BOOL* isARampBlob /*= NULL*/)
12335 {
12336 #if !defined(EXCLUDE_FROM_RALPH)
12337     TRACE( _T("TransformSelected\n"));
12338     
12339     if ( Trans.TransFills )
12340     {
12341         ClickModifiers ClickMods;
12342         ClickMods.Adjust = FALSE;       // Force adjust off
12343 
12344         // If the start point is selected then just move the fill
12345         if (IsSelected(FILLCONTROL_STARTPOINT))
12346         {
12347             DocCoord Pos = *GetStartPoint();
12348             Trans.Transform( &Pos, 1);
12349 
12350             FillControl Start = FILLCONTROL_STARTPOINT;
12351 
12352             OnControlDrag(Pos, Start, ClickMods);
12353         }
12354         else
12355         {
12356             if (IsSelected(FILLCONTROL_ENDPOINT3))
12357             {
12358                 DocCoord Pos = *GetEndPoint2() + *GetEndPoint() - *GetStartPoint();
12359                 Trans.Transform( &Pos, 1);
12360 
12361                 FillControl End3 = FILLCONTROL_ENDPOINT3;
12362 
12363                 OnControlDrag(Pos, End3, ClickMods);
12364             }
12365             else
12366             {
12367                 if (IsSelected(FILLCONTROL_ENDPOINT))
12368                 {
12369                     DocCoord Pos = *GetEndPoint();
12370                     Trans.Transform( &Pos, 1);
12371 
12372                     FillControl End = FILLCONTROL_ENDPOINT;
12373 
12374                     OnControlDrag(Pos, End, ClickMods);
12375                 }
12376 
12377                 if (IsSelected(FILLCONTROL_ENDPOINT2))
12378                 {
12379                     DocCoord Pos = *GetEndPoint2();
12380                     Trans.Transform( &Pos, 1);
12381 
12382                     FillControl End2 = FILLCONTROL_ENDPOINT2;
12383 
12384                     OnControlDrag(Pos, End2, ClickMods);
12385                 }
12386             }   
12387         }
12388     }
12389 #endif
12390 }
12391 
12392 
12393 /********************************************************************************************
12394 
12395 >   virtual FillControl AttrFourColFill::TestColourDrop(AttrColourDrop* ColDrop) 
12396 
12397     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12398     Created:    9/8/96
12399     Inputs:     ColDrop - pointer to the 
12400     Purpose:    Check to see which colour will be changed if dropped at this point
12401 
12402 ********************************************************************************************/
12403 
12404 FillControl AttrFourColFill::TestColourDrop(AttrColourDrop* ColDrop) 
12405 { 
12406 #if !defined(EXCLUDE_FROM_RALPH)
12407     // So, where was it dropped (or where will it be dropped)
12408     DocCoord DropPoint = ColDrop->GetDropPoint();
12409 
12410     // Look to see if the DropPoint is over any of the Fill Control Points
12411     FillControl ControlHit = CheckForControlHit(DropPoint);
12412     
12413     // If it hit one of our control points, then use that
12414     if (ControlHit != FILLCONTROL_NULL)
12415         return ControlHit;
12416 
12417     // It didn't hit any of our control points, so if the drop is over
12418     // the object then we'll make a guess as to which control point
12419     // the user would like to change, depending on which area of the
12420     // object the pointer is over.
12421 
12422     // First make sure we're actually over an object
12423     NodeRenderableInk* pParentObject = ColDrop->GetObjectDroppedOn();
12424     if (pParentObject == NULL)
12425         return FILLCONTROL_NULL;    // We're not over any object 
12426 
12427     // Make sure this fill type has some Control Points
12428     if (GetStartPoint() == NULL || GetEndPoint() == NULL || GetEndPoint2() == NULL)
12429         return FILLCONTROL_NULL;
12430 
12431     DocCoord StartPoint = *GetStartPoint();
12432     DocCoord EndPoint   = *GetEndPoint();
12433     DocCoord EndPoint2  = *GetEndPoint2();
12434     DocCoord EndPoint3 = EndPoint2 + EndPoint - StartPoint;
12435 
12436     double StartDist = DropPoint.Distance(StartPoint);
12437     double EndDist = DropPoint.Distance(EndPoint);
12438     double End2Dist = DropPoint.Distance(EndPoint2);
12439     double End3Dist = DropPoint.Distance(EndPoint3);
12440     
12441     // FInd which point is closest
12442     
12443     if (StartDist < End3Dist)
12444     {
12445         // Start is smallest so far
12446         if (StartDist < End2Dist)
12447         {
12448             // Start is still smallest
12449             if (StartDist < EndDist)
12450                 ControlHit = FILLCONTROL_STARTPOINT;
12451             else
12452                 ControlHit = FILLCONTROL_ENDPOINT;
12453         }
12454         else
12455         {
12456             // End2 is smallest so far
12457             if (EndDist < End2Dist)
12458                 ControlHit = FILLCONTROL_ENDPOINT;
12459             else
12460                 ControlHit = FILLCONTROL_ENDPOINT2;
12461         }
12462     }
12463     else
12464     {
12465         // End3 is smallest so far
12466         if (End3Dist < End2Dist)
12467         {
12468             // End3 is still smallest
12469             if (End3Dist < EndDist)
12470                 ControlHit = FILLCONTROL_ENDPOINT3;
12471             else
12472                 ControlHit = FILLCONTROL_ENDPOINT;
12473         }
12474         else
12475         {
12476             // End2 is smallest so far
12477             if (End2Dist < EndDist)
12478                 ControlHit = FILLCONTROL_ENDPOINT2;
12479             else
12480                 ControlHit = FILLCONTROL_ENDPOINT;
12481         }
12482     }
12483 
12484     return ControlHit;
12485 #else
12486     return FILLCONTROL_NULL;
12487 #endif
12488 }
12489 
12490 
12491 
12492 /********************************************************************************************
12493 
12494 >   void AttrFourColFill::Transform( TransformBase& Trans )
12495 
12496     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12497     Created:    9/8/96
12498     Inputs:     Trans - the transform object to apply to this attribute.
12499     Purpose:    Transform a grad fill attribute by moving the start and end points.
12500     SeeAlso:    Copied from AttrLinearFill
12501 
12502 ********************************************************************************************/
12503 
12504 void AttrFourColFill::Transform( TransformBase& Trans )
12505 {
12506     if ( Trans.TransFills )
12507     {
12508         Trans.Transform( GetStartPoint(), 1);
12509         Trans.Transform( GetEndPoint(), 1);
12510         Trans.Transform( GetEndPoint2(), 1);
12511 
12512         if (IsPerspective())
12513             Trans.Transform( GetEndPoint3(), 1);
12514     }
12515 }
12516 
12517 
12518 
12519 /********************************************************************************************
12520 
12521 >   BOOL AttrFourColFill::CanTransform()
12522 
12523     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12524     Created:    9/8/96
12525     Returns:    TRUE => transform this attribute.
12526     Purpose:    Indicate that this attribute can be transformed.
12527     SeeAlso:    Copied from AttrLinearFill
12528 
12529 ********************************************************************************************/
12530 
12531 BOOL AttrFourColFill::CanTransform()
12532 {
12533     return TRUE;
12534 }
12535 
12536 
12537 
12538 /********************************************************************************************
12539 
12540 >   void AttrFourColFill::RenderFillMesh(RenderRegion* pRender, 
12541                                     DocCoord* ControlPoints, BOOL* SelState,
12542                                     INT32 NumControlPoints)
12543     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12544     Created:    9/8/96
12545     Inputs:     pRender - The region to render the blobs to.
12546                 ControlPoints - The positions of all the control points
12547                 SelState - The selection state of the control points
12548                 NumControlPoints - The Number of control points.
12549     Purpose:    Renders the grad fills mesh during a drag op.
12550                 Don't call this, call RenderFillBlobs().
12551     SeeAlso:    AttrFourColFill::RenderFillBlobs
12552 
12553 ********************************************************************************************/
12554 
12555 void AttrFourColFill::RenderFillMesh(RenderRegion* pRender, 
12556                                     DocCoord* ControlPoints, BOOL* SelState,
12557                                     INT32 NumControlPoints)
12558 {
12559 #if !defined(EXCLUDE_FROM_RALPH)
12560     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
12561     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
12562     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_ENDPOINT2];
12563 
12564     if (StartPoint == EndPoint)
12565         return;
12566 
12567     if (SelState == NULL)
12568     {
12569         // If no selection state passed in, then assume
12570         // all the points are deselected
12571         BOOL Selected[NUMCONTROLPOINTS];
12572         for (INT32 i = 0; i <= FILLCONTROL_ENDPOINT3; i++)
12573         {
12574             Selected[i] = FALSE;
12575         }
12576         SelState = Selected;
12577     }
12578 
12579     DocCoord EndPoint3 = EndPoint2 + EndPoint - StartPoint;
12580 
12581     // Remember what attributes were here before
12582     pRender->SaveContext();
12583 
12584     // Get the current blob size in Doc Units
12585     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
12586 
12587     // Calculate the Arrow on the End of the Line
12588     Path ArrowPath;
12589     ArrowPath.Initialise();
12590     DocCoord LineEnd;
12591     MakeMeshArrow(&ArrowPath, StartPoint, EndPoint, &LineEnd);
12592 
12593     // Calculate the Arrow on the End of the Line2
12594     Path ArrowPath2;
12595     ArrowPath2.Initialise();
12596     DocCoord LineEnd2;
12597     MakeMeshArrow(&ArrowPath2, StartPoint, EndPoint2, &LineEnd2);
12598 
12599     // Set the line colours etc as we need them
12600     pRender->SetLineWidth(0);
12601     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
12602     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
12603 
12604     // First Draw the Line
12605     pRender->SetLineWidth(BlobSize/4);
12606     pRender->DrawLine(StartPoint, LineEnd);
12607 
12608     // Draw the secondary line
12609     pRender->DrawLine(StartPoint, LineEnd2);
12610 
12611         // Draw a line from EndPoint to EndPoint3
12612     pRender->DrawLine(EndPoint, EndPoint3);
12613 
12614     // Draw a line from EndPoint2 to EndPoint3
12615     pRender->DrawLine(EndPoint2, EndPoint3);
12616 
12617     // Render an Arrow at the end of the line
12618     pRender->SetLineWidth(0);
12619     pRender->SetLineColour(COLOUR_NONE);
12620     pRender->DrawPath(&ArrowPath);
12621 
12622     // and on the end of the secondary line
12623     pRender->DrawPath(&ArrowPath2);
12624     
12625     // Now Render the blobs on the path
12626     // Set the line colour to none
12627     pRender->SetLineColour(COLOUR_NONE);
12628 
12629     // Draw a blob at the start point
12630     if (SelState[FILLCONTROL_STARTPOINT])
12631     {
12632         // Draw Selected Blob
12633         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
12634         pRender->DrawBlob(StartPoint, BT_SELECTED);
12635     }
12636     else
12637     {
12638         // Draw Unselected Blob
12639         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
12640         pRender->DrawBlob(StartPoint, BT_UNSELECTED);
12641     }
12642 
12643     // Draw the blobs at the end points
12644     if (SelState[FILLCONTROL_ENDPOINT])
12645     {
12646         // Draw Selected Blobs
12647         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
12648         pRender->DrawBlob(EndPoint, BT_SELECTED);
12649     }
12650     else
12651     {
12652         // Draw Unselected Blobs
12653         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
12654         pRender->DrawBlob(EndPoint, BT_UNSELECTED);
12655     }
12656 
12657     // Draw the blobs at the end points
12658     if (SelState[FILLCONTROL_ENDPOINT2])
12659     {
12660         // Draw Selected Blobs
12661         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
12662         pRender->DrawBlob(EndPoint2,BT_SELECTED);
12663     }
12664     else
12665     {
12666         // Draw Unselected Blobs
12667         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
12668         pRender->DrawBlob(EndPoint2,BT_UNSELECTED);
12669     }
12670 
12671     // Draw the blobs at the end points
12672     if (SelState[FILLCONTROL_ENDPOINT3])
12673     {
12674         // Draw Selected Blobs
12675         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
12676         pRender->DrawBlob(EndPoint3,BT_SELECTED);
12677     }
12678     else
12679     {
12680         // Draw Unselected Blobs
12681         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
12682         pRender->DrawBlob(EndPoint3,BT_UNSELECTED);
12683     }
12684 
12685     // Put all the old attributes back
12686     pRender->RestoreContext();
12687 #endif
12688 }
12689 
12690 
12691 
12692 /********************************************************************************************
12693 
12694 >   virtual void AttrFourColFill::OnControlDrag(DocCoord Pos, FillControl DragControl, 
12695                                                     ClickModifiers ClickMods)
12696     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12697     Created:    9/8/96
12698     Inputs:     Pos - The Location of the mouse pointer at the time of the call
12699                 DragControl - The FillControl that is being dragged.
12700                 ClickMods - The modifiers to the click (eg shift, control etc )
12701     Purpose:    Called when an edit operation is dragging a control point.
12702 
12703 ********************************************************************************************/
12704 
12705 void AttrFourColFill::OnControlDrag(DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
12706 {
12707 #if !defined(EXCLUDE_FROM_RALPH)
12708     // Get the current Control Positions
12709     DocCoord StartPoint = *GetStartPoint();
12710     DocCoord EndPoint = *GetEndPoint();
12711     DocCoord EndPoint2 = *GetEndPoint2();
12712 
12713     INT32 dx, dy;
12714 
12715     // Which control point is being dragged ?
12716     switch (DragControl)
12717     {
12718         case FILLCONTROL_STARTPOINT:
12719         
12720             // Someone is dragging the Centre of the Fill
12721             dx = StartPoint.x - Pos.x;
12722             dy = StartPoint.y - Pos.y;
12723             // Move the other points relative
12724             EndPoint.translate(-dx, -dy);
12725             EndPoint2.translate(-dx, -dy);
12726 
12727             SetEndPoint(&EndPoint);
12728             SetEndPoint2(&EndPoint2);
12729             SetStartPoint(&Pos);
12730             break;
12731 
12732         case FILLCONTROL_ENDPOINT:
12733             
12734             // Someone is dragging the first End Point
12735             
12736             // Constrain the angle if necessary
12737             if (ClickMods.Constrain)
12738                 DocView::ConstrainToAngle(StartPoint, &Pos);
12739 
12740             // The Aspect ratio can be locked either by it being circular
12741             // or by the Shift key      
12742             if (ClickMods.Adjust)
12743             {
12744                 double OldLen = StartPoint.Distance(EndPoint);
12745                 double NewLen = StartPoint.Distance(Pos);
12746                 double Ratio = 1.0;
12747 
12748                 if (OldLen == 0)
12749                     Ratio = 0;
12750                 else
12751                     Ratio = NewLen/OldLen;
12752 
12753                 // Calculate the new end point based on the aspect ratio
12754                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, 90, INT32(StartPoint.Distance(EndPoint2) * Ratio));
12755                 SetEndPoint2(&temp);
12756             }
12757 
12758             SetEndPoint(&Pos);
12759             break;
12760 
12761         case FILLCONTROL_ENDPOINT2:
12762 
12763             // Someone is dragging the second End Point
12764             
12765             // Constrain the angle if necessary
12766             if (ClickMods.Constrain)
12767                 DocView::ConstrainToAngle(StartPoint, &Pos);
12768 
12769             // The Aspect ratio can be locked either by it being circular
12770             // or by the Shift key      
12771             if (ClickMods.Adjust)
12772             {
12773                 double OldLen = StartPoint.Distance(EndPoint2);
12774                 double NewLen = StartPoint.Distance(Pos);
12775                 double Ratio = 1.0;
12776 
12777                 if (OldLen == 0)
12778                     Ratio = 0;
12779                 else
12780                     Ratio = NewLen/OldLen;
12781 
12782                 // Calculate the new end point based on the aspect ratio
12783                 DocCoord temp = MakeLineAtAngle(StartPoint, Pos, -90, INT32(StartPoint.Distance(EndPoint) * Ratio));
12784                 SetEndPoint(&temp);
12785             }
12786 
12787             SetEndPoint2(&Pos);
12788             break;
12789 
12790         case FILLCONTROL_ENDPOINT3:
12791             DocCoord P = EndPoint - StartPoint;
12792             DocCoord Q = EndPoint2 - StartPoint;
12793             DocCoord N = Pos - StartPoint;
12794             DocCoord NewEndPoint = EndPoint;
12795             DocCoord NewEndPoint2 = EndPoint2;
12796 
12797             // If shift is down or both endpoints are the same
12798                         
12799             if ((Pos.Distance(StartPoint) > 512) &&
12800                 (Pos.Distance(EndPoint) > 512) &&
12801                 (Pos.Distance(EndPoint2) > 512) )
12802             {
12803                 if (ClickMods.Adjust || (P == Q))
12804                 {
12805                     NewEndPoint = DocCoord(Pos.x, StartPoint.y);
12806                     NewEndPoint2 = DocCoord(StartPoint.x, Pos.y);
12807                 }
12808                 else
12809                 {
12810                     // We are now going to move the two endpoints such that the gradient
12811                     // of all the edges remains constant
12812                     
12813                     double px = P.x;
12814                     double py = P.y;
12815                     double qx = Q.x;
12816                     double qy = Q.y;
12817                     double nx = N.x;
12818                     double ny = N.y;
12819                     
12820                     double den = (px * qy) - (py * qx);
12821 
12822                     ERROR3IF(floor(den) != den, "Non integer denominator");
12823 
12824                     if (den != 0.0)
12825                     {
12826                         double u = ((px * ny) - (py * nx)) / den;
12827 
12828                         NewEndPoint.x = Pos.x - (INT32) (u * qx);
12829                         NewEndPoint.y = Pos.y - (INT32) (u * qy);
12830                         NewEndPoint2.x = StartPoint.x + (INT32) (u * qx);
12831                         NewEndPoint2.y = StartPoint.y + (INT32) (u * qy);
12832                     }
12833                     else
12834                     {
12835                         NewEndPoint = DocCoord(Pos.x, StartPoint.y);
12836                         NewEndPoint2 = DocCoord(StartPoint.x, Pos.y);
12837                     }
12838                 }
12839 
12840                 // Don't let the points get too close
12841                 if ((StartPoint.Distance(NewEndPoint) > 512) &&
12842                     (StartPoint.Distance(NewEndPoint2) > 512) )
12843                 {
12844                     SetEndPoint(&NewEndPoint);
12845                     SetEndPoint2(&NewEndPoint2);
12846                 }
12847             }
12848             
12849             break;
12850     }
12851 #endif
12852 }
12853 
12854 
12855 
12856 /********************************************************************************************
12857 
12858 >   virtual DocRect AttrFourColFill::GetBlobBoundingRect()
12859 
12860     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12861     Created:    9/8/96
12862     Returns:    DocRect - The rectangle that contains all the nodes selection blobs.
12863     Purpose:    Calculates the bounding rectangle of the attrs blobs.This should always 
12864                 be calculated on the fly as the view scale can change without the attr 
12865                 knowing, giving an incorrect result.
12866 
12867 ********************************************************************************************/
12868 
12869 DocRect AttrFourColFill::GetBlobBoundingRect()
12870 {
12871 #if !defined(EXCLUDE_FROM_RALPH)
12872     // Optimisation.  If there is currently no interest in Fill Blobs
12873     // and this fill is not being Dragged (Fill blobs are turned off during
12874     // a fill drag), then we needn't bother doing anything. 
12875     if ( (!GetApplication()->GetBlobManager()->GetCurrentInterest(TRUE).Fill || !IsVisible()) && DraggedFill != this )
12876         return DocRect(0,0, 0,0);
12877 
12878     // Get the control points
12879     DocCoord StartPoint = *GetStartPoint();
12880     DocCoord EndPoint = *GetEndPoint();
12881     DocCoord EndPoint2 = *GetEndPoint2();
12882     DocCoord EndPoint3 = EndPoint2 + EndPoint - StartPoint;
12883 
12884     // Make a dummy bounds from just the Start Point
12885     DocRect BoundingRect(StartPoint, StartPoint);
12886 
12887     // We're not being dragged, so just calc the bounds of the Start and End Blobs
12888     DocRect BlobRect;
12889 
12890     // Get the Bounding rect of the Blob and include the Bottom Left and
12891     // Top Right of each blob in the Bounds.
12892     // We have to do it like this to make sure that the DocRect's coords
12893     // are valid.  ie. The Hi's are Higher than the Lo's.
12894     (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &BlobRect);
12895     BoundingRect.IncludePoint(BlobRect.lo);
12896     BoundingRect.IncludePoint(BlobRect.hi);
12897 
12898     (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &BlobRect);
12899     BoundingRect.IncludePoint(BlobRect.lo);
12900     BoundingRect.IncludePoint(BlobRect.hi);
12901 
12902     (Camelot.GetBlobManager())->GetBlobRect(EndPoint2, &BlobRect);
12903     BoundingRect.IncludePoint(BlobRect.lo);
12904     BoundingRect.IncludePoint(BlobRect.hi);
12905 
12906     (Camelot.GetBlobManager())->GetBlobRect(EndPoint3, &BlobRect);
12907     BoundingRect.IncludePoint(BlobRect.lo);
12908     BoundingRect.IncludePoint(BlobRect.hi);
12909 
12910     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint);
12911     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint2);
12912 
12913     // and return it
12914     return BoundingRect;
12915 #else
12916     return DocRect(0,0,0,0);
12917 #endif
12918 }
12919 
12920 
12921 /********************************************************************************************
12922 
12923 >   virtual void AttrFourColFill::RenderControl(FillControl Control, BOOL RenderOn)
12924 
12925     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12926     Created:    14/08/96
12927     Inputs:     Control, the control to render
12928                 RenderOn, TRUE if rendering blob on FALSE if off
12929     Purpose:    Renders a specified control
12930     SeeAlso:    FillControl
12931 
12932 ********************************************************************************************/
12933 
12934 void AttrFourColFill::RenderControl(FillControl Control, BOOL RenderOn)
12935 {
12936 #if !defined(EXCLUDE_FROM_RALPH)
12937     DocRect ControlRect;
12938 
12939     // Ignore if we're not in the tree yet
12940     // We may be a tempory clone, or something
12941     NodeRenderable* pParent = (NodeRenderable*)FindParent();
12942 
12943     if (pParent == NULL)
12944         return;
12945 
12946     if (IsBlobSame(Control))
12947         return;         // Ignore if same as the last blob rendered
12948 
12949     Spread* pSpread = this->FindParentSpread();
12950 
12951     switch (Control)
12952     {
12953         case FILLCONTROL_STARTPOINT:
12954             // Redraw the Start Point Blob
12955             (Camelot.GetBlobManager())->GetBlobRect(*GetStartPoint(), &ControlRect);
12956             RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
12957             break;
12958 
12959         case FILLCONTROL_ENDPOINT:
12960             (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint(), &ControlRect);
12961             RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
12962             break;
12963 
12964         case FILLCONTROL_ENDPOINT2:
12965             (Camelot.GetBlobManager())->GetBlobRect(*GetEndPoint2(), &ControlRect);
12966             RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
12967             break;
12968 
12969         case FILLCONTROL_ENDPOINT3:
12970             DocCoord EndPoint3 = *GetEndPoint2() + *GetEndPoint() - *GetStartPoint();
12971             (Camelot.GetBlobManager())->GetBlobRect(EndPoint3, &ControlRect);
12972             RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
12973             break;
12974     }
12975 #endif
12976 }
12977 
12978     
12979 /********************************************************************************************
12980 
12981 >   virtual void AttrFourColFill::CycleSelection(BOOL Reverse)
12982 
12983     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
12984     Created:    14/08/96
12985     Purpose:    Cycles the selection state of the controls
12986     SeeAlso:    FillControl
12987 
12988 ********************************************************************************************/
12989 
12990 void AttrFourColFill::CycleSelection(BOOL Reverse)
12991 {
12992     if (GetSelectionCount() == 1)
12993     {
12994         if (SelectionState[FILLCONTROL_STARTPOINT])
12995         {
12996             DeselectAll();
12997             if (Reverse)
12998                 SelectBlob(FILLCONTROL_ENDPOINT3);
12999             else
13000                 SelectBlob(FILLCONTROL_ENDPOINT);
13001         }
13002         else if (SelectionState[FILLCONTROL_ENDPOINT])
13003         {
13004             DeselectAll();
13005             if (Reverse)
13006                 SelectBlob(FILLCONTROL_STARTPOINT);
13007             else
13008                 SelectBlob(FILLCONTROL_ENDPOINT2);
13009         }
13010         else if (SelectionState[FILLCONTROL_ENDPOINT2])
13011         {
13012             DeselectAll();
13013             if (Reverse)
13014                 SelectBlob(FILLCONTROL_ENDPOINT);
13015             else
13016                 SelectBlob(FILLCONTROL_ENDPOINT3);
13017         }
13018         else if (SelectionState[FILLCONTROL_ENDPOINT3])
13019         {
13020             DeselectAll();
13021             if (Reverse)
13022                 SelectBlob(FILLCONTROL_ENDPOINT2);
13023             else
13024                 SelectBlob(FILLCONTROL_STARTPOINT);
13025         }
13026     }
13027 }
13028 
13029 
13030 /********************************************************************************************
13031 
13032 >   FillControl AttrFourColFill::CheckForControlHit(DocCoord &ClickPos)
13033 
13034     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13035     Created:    14/08/96
13036     Inputs:     ClickPos, The DocCoord position to check.
13037     Returns:    A FillControl, indicating the Fill Control Point Hit,
13038                 or FILLCONTROL_NULL, if no points hit.
13039     Purpose:    Check to see if a click was on a Fill Control Point. 
13040     SeeAlso:    FillControl
13041 
13042 ********************************************************************************************/
13043 
13044 FillControl AttrFourColFill::CheckForControlHit(DocCoord &ClickPos)
13045 {
13046     // Set up a default, that indicates not control points hit
13047     FillControl HitControl = FILLCONTROL_NULL;
13048 #if !defined(EXCLUDE_FROM_RALPH)
13049     DocRect BlobRect;
13050 
13051     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
13052         return FILLCONTROL_NULL;
13053 
13054     // Get the control points
13055     DocCoord StartPoint = *GetStartPoint();
13056     DocCoord EndPoint = *GetEndPoint();
13057     DocCoord EndPoint2 = *GetEndPoint2();
13058     DocCoord EndPoint3 = EndPoint2 + EndPoint - StartPoint;
13059 
13060     // Get the rectangle around the Start Control Point
13061     (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &BlobRect);
13062     // See if the Click Position is within the rectangle
13063     if ( BlobRect.ContainsCoord(ClickPos) )
13064         HitControl = FILLCONTROL_STARTPOINT;
13065 
13066     // Get the rectangle around the End Control Point
13067     (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &BlobRect);
13068     // See if the Click Position is within the rectangle
13069     if ( BlobRect.ContainsCoord(ClickPos) )
13070         HitControl = FILLCONTROL_ENDPOINT;
13071 
13072     // Get the rectangle around the Secondary Control Point
13073     (Camelot.GetBlobManager())->GetBlobRect(EndPoint2, &BlobRect);
13074     // See if the Click Position is within the rectangle
13075     if ( BlobRect.ContainsCoord(ClickPos) )
13076         HitControl = FILLCONTROL_ENDPOINT2;
13077 
13078     // Get the rectangle around the Secondary Control Point
13079     (Camelot.GetBlobManager())->GetBlobRect(EndPoint3, &BlobRect);
13080     // See if the Click Position is within the rectangle
13081     if ( BlobRect.ContainsCoord(ClickPos) )
13082         HitControl = FILLCONTROL_ENDPOINT3;
13083 #endif
13084     return HitControl;
13085 }
13086 
13087 
13088 /********************************************************************************************
13089 
13090 >   void AttrFourColFill::ValidateAttributeValue()
13091 
13092     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13093     Created:    9/8/96
13094     Purpose:    Makes sure the Coords of the Fill are sensible.
13095 
13096 ********************************************************************************************/
13097 
13098 void AttrFourColFill::ValidateAttributeValue()
13099 {
13100 #if !defined(EXCLUDE_FROM_RALPH)
13101     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0))
13102     {
13103         // If the EndPoint2 is 'NULL' then make it sensible
13104         if (*GetEndPoint2() == DocCoord(0,0))
13105         {
13106             DocCoord temp = MakeLineAtAngle((*GetStartPoint()), (*GetEndPoint()), 90);
13107             SetEndPoint2(&temp);
13108         }
13109         
13110         return;
13111     }
13112 
13113     // Make up some sensible defaults
13114     DocRect AttrBounds = DocRect(0,0,0,0);
13115 
13116     INT32 Width  = DEFAULT_FILLWIDTH;
13117     INT32 Height = DEFAULT_FILLHEIGHT;
13118 
13119     // Are we an Orphan ?
13120     if (FindParent() != NULL)
13121     {
13122         // Nope, so we can use Daddies Bounding Box
13123         SelRange* Selected = GetApplication()->FindSelection();
13124                  
13125         if (Selected == NULL || Selected->Count() <= 1)
13126             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
13127         else
13128             AttrBounds = Selected->GetBoundingRect();
13129 
13130         Width  = AttrBounds.Width();
13131         Height = AttrBounds.Height();
13132     }
13133 
13134     // If the StartPoint is 'NULL' then make all points sensible
13135     if ((*GetStartPoint()) == DocCoord(0,0))
13136     {
13137         // Start in the centre of the bounds
13138         SetStartPoint(&AttrBounds.lo);
13139 
13140         // and set End Points to Middle Right, and Middle Top
13141         DocCoord temp = DocCoord(AttrBounds.hi.x, AttrBounds.lo.y);
13142         SetEndPoint(&temp);
13143         temp = DocCoord(AttrBounds.lo.x, AttrBounds.hi.y);
13144         SetEndPoint2(&temp);
13145     }
13146 
13147     // If EndPoint is 'NULL' then make it sensible
13148     if ((*GetEndPoint()) == DocCoord(0,0))
13149     {
13150         DocCoord temp = DocCoord(AttrBounds.hi.x, AttrBounds.lo.y);
13151         SetEndPoint(&temp);
13152     }
13153 
13154     // If EndPoint2 is 'NULL' then make it sensible
13155     if ((*GetEndPoint2()) == DocCoord(0,0))
13156     {
13157         DocCoord temp = DocCoord(AttrBounds.lo.x, AttrBounds.hi.y);
13158         SetEndPoint2(&temp);
13159     }
13160 #endif
13161 }
13162 
13163 
13164 
13166 //
13167 //                              AttrFourColColourFill
13168 //
13170 
13171 /********************************************************************************************
13172 
13173 >   void AttrFourColColourFill::Render( RenderRegion* pRender)
13174 
13175     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13176     Created:    9/8/96
13177     Purpose:    'Renders' a FourCol Fill Colour attribute.
13178 
13179 ********************************************************************************************/
13180 
13181 void AttrFourColColourFill::Render(RenderRegion* pRender)
13182 {
13183     pRender->SetFillGeometry(&Value, FALSE);
13184 }
13185 
13186 
13187 
13188 /********************************************************************************************
13189 
13190 > Node* AttrFourColColourFill::SimpleCopy() 
13191 
13192     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13193     Created:    9/8/96
13194     Returns:    A copy of the node, or NULL if memory runs out 
13195     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
13196                 The function is virtual, and must be defined for all derived classes.  
13197     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
13198                 memory error and the function returns NULL. 
13199     Scope:      protected       
13200 
13201 ********************************************************************************************/
13202      
13203 Node* AttrFourColColourFill::SimpleCopy()
13204 {
13205     AttrFourColColourFill* NodeCopy = new AttrFourColColourFill();
13206     if (NodeCopy == NULL)
13207         return NULL;
13208 
13209     CopyNodeContents(NodeCopy);
13210     
13211     return NodeCopy;
13212 }  
13213 
13214 
13215 
13216 /********************************************************************************************
13217 
13218 >   void AttrFourColColourFill::RenderFillBlobs(RenderRegion* pRender)
13219 
13220     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13221     Created:    9/8/96
13222     Inputs:     pRender - The region to render the blobs to.
13223     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
13224 
13225 ********************************************************************************************/
13226 
13227 void AttrFourColColourFill::RenderFillBlobs(RenderRegion* pRender)
13228 {
13229 #if !defined(EXCLUDE_FROM_RALPH)
13230     if (!IsVisible())
13231         return;     // We're in Fill Transparency Mode
13232 
13233     // Don't bother if this fill is being edited as a copy of it
13234     // we be rendered thoughout the drag op
13235     if (IsFillBeingEdited())
13236         return;
13237 
13238     // Ignore this if the mesh is the same as the last one rendered.
13239     if (CheckPreviousFillMesh())
13240         return;
13241 
13242     // Get the control points
13243     DocCoord StartPoint = *GetStartPoint();
13244     DocCoord EndPoint = *GetEndPoint();
13245     DocCoord EndPoint2 = *GetEndPoint2();
13246     DocCoord EndPoint3 = EndPoint2 + EndPoint - StartPoint;
13247 
13248     DocCoord ControlPoints[4];
13249     ControlPoints[FILLCONTROL_STARTPOINT] = StartPoint;
13250     ControlPoints[FILLCONTROL_ENDPOINT] = EndPoint;
13251     ControlPoints[FILLCONTROL_ENDPOINT2] = EndPoint2;
13252     ControlPoints[FILLCONTROL_ENDPOINT3] = EndPoint3;
13253 
13254     // Render a nice pretty Fill Mesh thingy
13255     RenderFillMesh(pRender, ControlPoints, SelectionState, 4);
13256 
13257     // This call was removed by Gerry (2/9/96) as it causes blob problems
13258     // If we are removing blobs then force all blobs to be deselected
13259 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
13260 //      DeselectAllNoRedraw();
13261 #endif
13262 }
13263 
13264 
13265 
13266 /********************************************************************************************
13267 
13268 >   virtual UINT32 AttrFourColColourFill::GetAttrNameID(void)  
13269 
13270     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13271     Created:    9/8/96
13272     Returns:    Attribute description ID
13273     Purpose:    Returns a string resource ID describing the attribute
13274 
13275 ********************************************************************************************/
13276 
13277 UINT32 AttrFourColColourFill::GetAttrNameID(void)  
13278 {
13279     return (_R(IDS_FOURCOLGRADFILL)); 
13280 }                                  
13281 
13282 
13283 
13284 /********************************************************************************************
13285 
13286 >   void AttrFourColColourFill::GetDebugDetails(StringBase* Str)
13287 
13288     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13289     Created:    9/8/96
13290     Outputs:    Str - the string containing details of the attribute.
13291     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
13292 
13293 ********************************************************************************************/
13294 
13295 void AttrFourColColourFill::GetDebugDetails(StringBase* Str)
13296 {
13297 #ifdef _DEBUG
13298     NodeAttribute::GetDebugDetails( Str );
13299 
13300     String_256 TempStr;
13301 
13302     TempStr._MakeMsg( TEXT("\r\nFour colour graduated fill:\r\n"));
13303     (*Str) += TempStr;
13304 
13305 //  TempStr._MakeMsg(TEXT("\r\nStart"));
13306 //  (*GetStartColour()).GetDebugDetails(&TempStr);
13307 //  (*Str) += TempStr;
13308 
13309 //  TempStr._MakeMsg(TEXT("\r\nEnd"));
13310 //  (*GetEndColour()).GetDebugDetails(&TempStr);
13311 //  (*Str) += TempStr;
13312 
13313 //  TempStr._MakeMsg(TEXT("\r\nEnd2"));
13314 //  (*GetEndColour2()).GetDebugDetails(&TempStr);
13315 //  (*Str) += TempStr;
13316 
13317 //  TempStr._MakeMsg(TEXT("\r\nEnd3"));
13318 //  (*GetEndColour3()).GetDebugDetails(&TempStr);
13319 //  (*Str) += TempStr;
13320 
13321     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
13322                      (*GetStartPoint()).x, (*GetStartPoint()).y);
13323     (*Str) += TempStr;
13324 
13325     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
13326                      (*GetEndPoint()).x, (*GetEndPoint()).y);
13327     (*Str) += TempStr;
13328 
13329     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
13330                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
13331     (*Str) += TempStr;
13332 #endif
13333 }
13334 
13335 
13336 
13337 /********************************************************************************************
13338 
13339 >   virtual UINT32 AttrFourColColourFill::GetNodeSize() const
13340 
13341     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13342     Created:    9/8/96
13343     Returns:    The size of the node in bytes
13344     Purpose:    For finding the size of the node.
13345     SeeAlso:    Node::GetSubtreeSize
13346 
13347 ********************************************************************************************/
13348 
13349 UINT32 AttrFourColColourFill::GetNodeSize() const 
13350 {     
13351     return sizeof(AttrFourColColourFill);
13352 }  
13353 
13354 
13355 
13356 /********************************************************************************************
13357 
13358   > virtual BOOL AttrFourColColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
13359 
13360     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13361     Created:    9/8/96
13362     Inputs:     pFilter = ptr to the filter
13363     Returns:    TRUE if record is written, FALSE if not
13364     Purpose:    Writes the FourCol fill record to the filter
13365     SeeAlso:    -
13366 
13367 ********************************************************************************************/
13368 
13369 BOOL AttrFourColColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
13370 {
13371 #ifdef DO_EXPORT
13372     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
13373 
13374     // Must write out the colours first
13375     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
13376     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
13377     INT32 EndCol2Ref     = pFilter->WriteRecord(&Value.EndColour2);
13378     INT32 EndCol3Ref     = pFilter->WriteRecord(&Value.EndColour3);
13379 
13380     // Are the colour references ok?
13381     BOOL ok = ((StartColRef != 0) && (EndColRef != 0) && (EndCol2Ref != 0) && (EndCol3Ref != 0));
13382         
13383     if (ok)
13384     {
13385         CamelotFileRecord Rec(pFilter,TAG_FOURCOLFILL,TAG_FOURCOLFILL_SIZE);
13386 
13387         if (ok) ok = Rec.Init();
13388         if (ok) ok = Rec.WriteCoord(Value.StartPoint);
13389         if (ok) ok = Rec.WriteCoord(Value.EndPoint);
13390         if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
13391         if (ok) ok = Rec.WriteReference(StartColRef);
13392         if (ok) ok = Rec.WriteReference(EndColRef);
13393         if (ok) ok = Rec.WriteReference(EndCol2Ref);
13394         if (ok) ok = Rec.WriteReference(EndCol3Ref);
13395         if (ok) ok = pFilter->Write(&Rec);
13396     }
13397 
13398     if (!ok)
13399         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
13400 
13401     return ok;
13402 #else
13403     return FALSE;
13404 #endif
13405 }
13406 
13407 
13408 
13409 /********************************************************************************************
13410 
13411   > virtual BOOL AttrFourColColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
13412 
13413     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13414     Created:    9/8/96
13415     Inputs:     pFilter - ptr to the filter
13416     Returns:    TRUE if record is written, FALSE if not
13417     Purpose:    Writes the FourCol fill record to the filter
13418     SeeAlso:    -
13419 
13420 ********************************************************************************************/
13421 
13422 BOOL AttrFourColColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
13423 {
13424 #ifdef DO_EXPORT
13425     return WritePreChildrenWeb(pFilter);
13426 #else
13427     return FALSE;
13428 #endif
13429 }
13430 
13431 
13432 /********************************************************************************************
13433 
13434   > virtual BOOL AttrFourColColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
13435 
13436     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
13437     Created:    14/9/2000
13438     Inputs:     pFilter = ptr to the filter
13439     Returns:    TRUE if record is written, FALSE if not
13440     Purpose:    Writes out colour definitions for this fill.
13441     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
13442                 Layer::WriteAtomicNodesColourRefs ()
13443 
13444 ********************************************************************************************/
13445 
13446 BOOL AttrFourColColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
13447 {
13448     // Must write out the colours first
13449     INT32 StartColRef = pFilter->WriteRecord(&Value.Colour);
13450     INT32 EndColRef  = pFilter->WriteRecord(&Value.EndColour);
13451     INT32 EndCol2Ref     = pFilter->WriteRecord(&Value.EndColour2);
13452     INT32 EndCol3Ref     = pFilter->WriteRecord(&Value.EndColour3);
13453 
13454     // Are the colour references ok?
13455     BOOL ok = ((StartColRef != 0) && (EndColRef != 0) && (EndCol2Ref != 0) && (EndCol3Ref != 0));
13456     
13457     return (ok);
13458 }
13459 
13461 //
13462 //                              AttrFourColTranspFill
13463 //
13465 
13466 /********************************************************************************************
13467 
13468 >   void AttrFourColTranspFill::Render( RenderRegion* pRender)
13469 
13470     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13471     Created:    9/8/96
13472     Purpose:    'Renders' a FourCol Fill Colour attribute.
13473 
13474 ********************************************************************************************/
13475 
13476 void AttrFourColTranspFill::Render(RenderRegion* pRender)
13477 {
13478     pRender->SetTranspFillGeometry(&Value, FALSE);
13479 }
13480 
13481 
13482 
13483 /********************************************************************************************
13484 >   virtual BOOL AttrFourColTranspFill::NeedsTransparency() const
13485 
13486     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13487     Created:    9/8/96
13488     Inputs:     -
13489     Outputs:    -
13490     Returns:    TRUE if this node requires transparency mode to render properly.
13491     Purpose:    Called to determine whether transparency is needed to render properly.
13492     Errors:     -
13493 
13494 ********************************************************************************************/
13495 
13496 BOOL AttrFourColTranspFill::NeedsTransparency() const
13497 {
13498     AttrFourColTranspFill* pNonConst = (AttrFourColTranspFill*) this;
13499     return (    pNonConst->GetTranspType()      != TT_Mix || 
13500                 *(pNonConst->GetStartTransp())  != 0 ||
13501                 *(pNonConst->GetEndTransp())    != 0 ||
13502                 *(pNonConst->GetEndTransp2())   != 0 ||
13503                 *(pNonConst->GetEndTransp3())   != 0 );
13504 }
13505 
13506 
13507 
13508 /********************************************************************************************
13509 
13510 > Node* AttrFourColTranspFill::SimpleCopy() 
13511 
13512     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13513     Created:    9/8/96
13514     Returns:    A copy of the node, or NULL if memory runs out 
13515     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
13516                 The function is virtual, and must be defined for all derived classes.  
13517     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
13518                 memory error and the function returns NULL. 
13519     Scope:      protected       
13520 
13521 ********************************************************************************************/
13522      
13523 Node* AttrFourColTranspFill::SimpleCopy()
13524 {
13525     AttrFourColTranspFill* NodeCopy = new AttrFourColTranspFill();
13526     if (NodeCopy == NULL)
13527         return NULL;
13528 
13529     CopyNodeContents(NodeCopy);
13530     
13531     return NodeCopy;
13532 }  
13533 
13534 
13535 
13536 /********************************************************************************************
13537 
13538 >   void AttrFourColTranspFill::RenderFillBlobs(RenderRegion* pRender)
13539 
13540     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13541     Created:    9/8/96
13542     Inputs:     pRender - The region to render the blobs to.
13543     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
13544 
13545 ********************************************************************************************/
13546 
13547 void AttrFourColTranspFill::RenderFillBlobs(RenderRegion* pRender)
13548 {
13549 #if !defined(EXCLUDE_FROM_RALPH)
13550     if (!IsVisible())
13551         return;     // We're in Fill Transparency Mode
13552 
13553     // Don't bother if this fill is being edited as a copy of it
13554     // we be rendered thoughout the drag op
13555     if (IsFillBeingEdited())
13556         return;
13557 
13558     // Ignore this if the mesh is the same as the last one rendered.
13559     if (CheckPreviousFillMesh())
13560         return;
13561 
13562     // Get the control points
13563     DocCoord StartPoint = *GetStartPoint();
13564     DocCoord EndPoint = *GetEndPoint();
13565     DocCoord EndPoint2 = *GetEndPoint2();
13566     DocCoord EndPoint3 = EndPoint2 + EndPoint - StartPoint;
13567 
13568     DocCoord ControlPoints[4];
13569     ControlPoints[FILLCONTROL_STARTPOINT] = StartPoint;
13570     ControlPoints[FILLCONTROL_ENDPOINT] = EndPoint;
13571     ControlPoints[FILLCONTROL_ENDPOINT2] = EndPoint2;
13572     ControlPoints[FILLCONTROL_ENDPOINT3] = EndPoint3;
13573 
13574     // Render a nice pretty Fill Mesh thingy
13575     RenderFillMesh(pRender, ControlPoints, SelectionState, 4);
13576 
13577     // This call was removed by Gerry (2/9/96) as it causes blob problems
13578     // If we are removing blobs then force all blobs to be deselected
13579 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
13580 //      DeselectAllNoRedraw();
13581 #endif
13582 }
13583 
13584 
13585 
13586 /********************************************************************************************
13587 
13588 >   virtual UINT32 AttrFourColTranspFill::GetAttrNameID(void)  
13589 
13590     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13591     Created:    9/8/96
13592     Returns:    Attribute description ID
13593     Purpose:    Returns a string resource ID describing the attribute
13594 
13595 ********************************************************************************************/
13596 
13597 UINT32 AttrFourColTranspFill::GetAttrNameID(void)  
13598 {
13599     return (_R(IDS_FOURCOLTRANSPFILL)); 
13600 }                                  
13601 
13602 
13603 
13604 /********************************************************************************************
13605 
13606 >   void AttrFourColTranspFill::GetDebugDetails(StringBase* Str)
13607 
13608     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13609     Created:    9/8/96
13610     Outputs:    Str - the string containing details of the attribute.
13611     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
13612 
13613 ********************************************************************************************/
13614 
13615 void AttrFourColTranspFill::GetDebugDetails(StringBase* Str)
13616 {
13617 #ifdef _DEBUG
13618     NodeAttribute::GetDebugDetails( Str );
13619 
13620     String_256 TempStr;
13621 
13622     TempStr._MakeMsg( TEXT("\r\nFourCol Graduated Fill:\r\n"));
13623     (*Str) += TempStr;
13624 
13625     TempStr._MakeMsg(TEXT("\r\nStart"));
13626     (*Str) += TempStr;
13627 
13628     TempStr._MakeMsg(TEXT("\r\nEnd"));
13629     (*Str) += TempStr;
13630 
13631     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
13632                      (*GetStartPoint()).x, (*GetStartPoint()).y);
13633     (*Str) += TempStr;
13634 
13635     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
13636                      (*GetEndPoint()).x, (*GetEndPoint()).y);
13637     (*Str) += TempStr;
13638 
13639     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
13640                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
13641     (*Str) += TempStr;
13642 #endif
13643 }
13644 
13645 
13646 
13647 /********************************************************************************************
13648 
13649 >   virtual UINT32 AttrFourColTranspFill::GetNodeSize() const
13650 
13651     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13652     Created:    9/8/96
13653     Returns:    The size of the node in bytes
13654     Purpose:    For finding the size of the node.
13655     SeeAlso:    Node::GetSubtreeSize
13656 
13657 ********************************************************************************************/
13658 
13659 UINT32 AttrFourColTranspFill::GetNodeSize() const 
13660 {     
13661     return sizeof(AttrFourColTranspFill);
13662 }  
13663 
13664 
13665 
13666 /********************************************************************************************
13667 
13668   > virtual BOOL AttrFourColTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
13669 
13670     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13671     Created:    9/8/96
13672     Inputs:     pFilter - ptr to the filter
13673     Returns:    TRUE if record is written, FALSE if not
13674     Purpose:    Writes the FourCol transparent fill record to the filter
13675     SeeAlso:    -
13676 
13677 ********************************************************************************************/
13678 
13679 BOOL AttrFourColTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
13680 {
13681 #ifdef DO_EXPORT
13682     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
13683     ERROR3IF(Value.Transp     > 255,"Start transparency level is too high to be stored as a byte");
13684     ERROR3IF(Value.EndTransp  > 255,"End transparency level is too high to be stored as a byte");
13685     ERROR3IF(Value.EndTransp2 > 255,"End transparency2 level is too high to be stored as a byte");
13686     ERROR3IF(Value.EndTransp3 > 255,"End transparency3 level is too high to be stored as a byte");
13687     ERROR3IF(Value.TranspType > 255,"Transparency type is too high to be stored as a byte");
13688 
13689     BOOL ok = TRUE;
13690 
13691     CamelotFileRecord Rec(pFilter,TAG_FOURCOLTRANSPARENTFILL,TAG_FOURCOLTRANSPARENTFILL_SIZE);
13692 
13693     if (ok) ok = Rec.Init();
13694     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
13695     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
13696     if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
13697     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
13698     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));
13699     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp2));
13700     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp3));
13701     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
13702     if (ok) ok = pFilter->Write(&Rec);
13703 
13704     if (!ok)
13705         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
13706 
13707     return ok;
13708 #else
13709     return FALSE;
13710 #endif
13711 }
13712 
13713 
13714 
13715 /********************************************************************************************
13716 
13717   > virtual BOOL AttrFourColTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
13718 
13719     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
13720     Created:    9/8/96
13721     Inputs:     pFilter - ptr to the filter
13722     Returns:    TRUE if record is written, FALSE if not
13723     Purpose:    Writes the FourCol transparent fill record to the filter
13724     SeeAlso:    -
13725 
13726 ********************************************************************************************/
13727 
13728 BOOL AttrFourColTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
13729 {
13730 #ifdef DO_EXPORT
13731     return WritePreChildrenWeb(pFilter);
13732 #else
13733     return FALSE;
13734 #endif
13735 }
13736 
13737 
13738 
13739 
13740 /********************************************************************************************
13741 >   BOOL AttrFourColTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
13742 
13743     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
13744     Created:    11/05/2005
13745     Inputs:     -
13746     Outputs:    -
13747     Returns:    TRUE if this node has a value equivalent to the relevant 
13748                 FALSE otherwise
13749     Purpose:    Determine whether this attribute has the default value or not
13750     Errors:     -
13751     SeeAlso:    -
13752 ********************************************************************************************/
13753 
13754 BOOL AttrFourColTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
13755 {
13756     // Slight bodge - we will assume that the default transparency is fully opaque
13757     if (bAppearance)
13758         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0 && Value.EndTransp2==0 && Value.EndTransp3==0));
13759     else
13760         return FALSE;
13761 }
13762 
13763 
13764 
13765 
13767 //
13768 //                              AttrBitmapFill
13769 //
13771 
13772 /***********************************************************************************************
13773 
13774 >    virtual BOOL AttrBitmapFill::HidingNode()
13775 
13776      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
13777      Created:   11/1/94
13778      Returns:   TRUE if all was ok. FALSE if an error occured.
13779      Purpose:   This virtual function is called whenever the node is hidden.
13780                 It allows the node do things like 'optimise' itself to use less memory or
13781                 send a message to let others know it is being hidden etc.
13782 
13783                 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION.
13784 
13785 ***********************************************************************************************/
13786 
13787 BOOL AttrBitmapFill::HidingNode()
13788 {
13789     // Call the base class first
13790     if (!AttrFillGeometry::HidingNode())
13791         return FALSE;
13792 
13793     GetBitmapRef()->RemoveFromTree();
13794 
13795     return TRUE;
13796 }
13797 
13798 /***********************************************************************************************
13799 
13800 >    virtual BOOL AttrBitmapFill::ShowingNode()
13801 
13802      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
13803      Created:   11/1/94
13804      Returns:   TRUE if all was ok. FALSE if an error occured (eg Out of memory).
13805      Purpose:   This virtual function is called whenever the node is re-shown after being 
13806                 Hidden.
13807                 It allows the node to reconstruct itself if it was optimised or
13808                 send a message to let others know it is back etc.
13809 
13810                 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION.
13811 
13812 ***********************************************************************************************/
13813 
13814 BOOL AttrBitmapFill::ShowingNode()
13815 {
13816     // Call the base class first
13817     if (!AttrFillGeometry::ShowingNode())
13818         return FALSE;
13819 
13820     GetBitmapRef()->AddtoTree();
13821 
13822     return TRUE;
13823 }
13824 
13825 /********************************************************************************************
13826 
13827 >   BOOL AttrBitmapFill::SetDPI(UINT32 NewDpi)
13828 
13829     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
13830     Created:    11/11/94
13831     Inputs:     NewDpi - the new Dpi for this bitmap fill.
13832     Purpose:    Changes the Dpi of this bitmap by scaling the fill control points.
13833 
13834 ********************************************************************************************/
13835 /*
13836 BOOL AttrBitmapFill::SetDPI(UINT32 NewDpi)
13837 {
13838     if (NewDpi == 0)
13839         return FALSE;
13840 
13841     if (GetBitmap() == NULL)
13842         return FALSE;
13843 
13844     OILBitmap *OilBM = GetBitmap()->ActualBitmap;
13845 
13846     if (IsAFractalFill())
13847     {
13848         ((FillGeometryAttribute*)GetAttributeValue())->SetDPI(NewDpi);
13849     }
13850 
13851     if (OilBM == NULL)
13852         return FALSE;
13853 
13854     BitmapInfo Info;
13855     OilBM->GetInfo(&Info);
13856 
13857     INT32 PixWidth  = Info.PixelWidth;
13858     INT32 PixHeight = Info.PixelHeight;
13859 
13860     DocCoord Start = *GetStartPoint();
13861     DocCoord End   = *GetEndPoint();
13862     DocCoord End2  = *GetEndPoint2();
13863 
13864     INT32 Width  = INT32(Start.Distance(End));
13865     INT32 Height = INT32(Start.Distance(End2));
13866 
13867     INT32 HDpi = (PixWidth*72000)/Width;
13868     INT32 VDpi = (PixHeight*72000)/Height;
13869 
13870     INT32 OldDpi = HDpi;
13871     if (VDpi < OldDpi)
13872         OldDpi = VDpi;
13873 
13874     TRACEUSER( "Mike", _T("Bitmap Dpi is currently %d\n"),OldDpi);
13875     TRACEUSER( "Mike", _T("Setting Bitmap Dpi to %d\n"),NewDpi);
13876 
13877     FIXED16 Ratio   = FIXED16(double(OldDpi)/double(NewDpi));
13878     Matrix Scale    = Matrix(Ratio, Ratio);
13879 
13880     GetBitmapVirtualPoints(Start, End, End2,
13881                             &Start, &End, &End2);
13882 
13883     DocCoord Centre = Start;
13884 
13885     Start.translate(-Centre.x, -Centre.y);  
13886     Scale.transform(&Start);
13887     Start.translate(Centre.x, Centre.y);    
13888 
13889     End.translate(-Centre.x, -Centre.y);    
13890     Scale.transform(&End);
13891     End.translate(Centre.x, Centre.y);  
13892 
13893     End2.translate(-Centre.x, -Centre.y);   
13894     Scale.transform(&End2);
13895     End2.translate(Centre.x, Centre.y); 
13896 
13897     GetBitmapRealPoints(Start, End, End2,
13898                         &Start, &End, &End2);
13899 
13900     SetStartPoint(&Start);
13901     SetEndPoint(&End);
13902     SetEndPoint2(&End2);
13903 
13904     return TRUE;
13905 }
13906 */
13907 
13908 /********************************************************************************************
13909 
13910 >   void AttrBitmapFill::Transform( TransformBase& Trans )
13911 
13912     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
13913     Created:    23/8/94
13914     Inputs:     Trans - the transform object to apply to this attribute.
13915     Purpose:    Transform a grad fill attribute by moving the start and end points.
13916     SeeAlso:    NodeRenderable::Transform
13917 
13918 ********************************************************************************************/
13919 
13920 void AttrBitmapFill::Transform( TransformBase& Trans )
13921 {
13922     if ( Trans.TransFills )
13923     {
13924         Trans.Transform( GetStartPoint(), 1);
13925         Trans.Transform( GetEndPoint(), 1);
13926         Trans.Transform( GetEndPoint2(), 1);
13927         Trans.Transform( GetEndPoint3(), 1);
13928 
13929 //      ValidateAttributeValue();
13930     }
13931 }
13932 
13933 /********************************************************************************************
13934 
13935 >   void AttrBitmapFill::TransformSelectedControlPoints( TransformBase& Trans)
13936 
13937     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
13938     Created:    23/8/94
13939     Inputs:     Trans - the transform object to apply to this attribute.
13940     Purpose:    Transform a grad fill attribute by moving the selected control points.
13941     SeeAlso:    NodeRenderable::Transform
13942 
13943 ********************************************************************************************/
13944 
13945 void AttrBitmapFill::TransformSelectedControlPoints( TransformBase& Trans, BOOL* isARampBlob /*= NULL*/)
13946 {
13947 #if !defined(EXCLUDE_FROM_RALPH)
13948     if ( Trans.TransFills )
13949     {
13950         ClickModifiers ClickMods; /* = ClickModifiers::GetClickModifiers();*/
13951         ClickMods.Adjust = TRUE;
13952 
13953         DocCoord StartPoint  = *GetStartPoint();
13954         DocCoord EndPoint    = *GetEndPoint();
13955         DocCoord EndPoint2   = *GetEndPoint2();
13956 
13957         DocCoord CentrePoint;
13958         DocCoord Drag2Blob;
13959         DocCoord Drag3Blob;
13960 
13961         GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
13962                                 &CentrePoint, &Drag2Blob, &Drag3Blob);
13963 
13964         if (GetStartPoint() && IsSelected(FILLCONTROL_STARTPOINT))
13965         {
13966             Trans.Transform( &CentrePoint, 1);
13967 
13968             FillControl Start = FILLCONTROL_STARTPOINT;
13969             
13970             OnControlDrag(CentrePoint, Start, ClickMods);
13971         }
13972 
13973         if (GetEndPoint() && IsSelected(FILLCONTROL_ENDPOINT))
13974         {
13975             Trans.Transform( &Drag2Blob, 1);
13976 
13977             FillControl End = FILLCONTROL_ENDPOINT;
13978 
13979             OnControlDrag(Drag2Blob, End, ClickMods);
13980         }
13981     }
13982 #endif
13983 }
13984 
13985 /********************************************************************************************
13986 
13987 >   BOOL AttrBitmapFill::CanTransform()
13988 
13989     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
13990     Created:    23/8/94
13991     Returns:    TRUE => transform this attribute.
13992     Purpose:    Indicate that this attribute can be transformed.
13993     SeeAlso:    NodeRenderable::CanTransform
13994 
13995 ********************************************************************************************/
13996 
13997 BOOL AttrBitmapFill::CanTransform()
13998 {
13999     return TRUE;
14000 }
14001 
14002 /********************************************************************************************
14003 
14004 >   BOOL AttrBitmapFill::CopyNodeContents( AttrBitmapFill* NodeCopy)
14005 
14006     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14007     Created:    23/8/94
14008     Outputs:    A copy of this node
14009     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
14010     Errors:     An assertion failure will occur if NodeCopy is NULL
14011     Scope:      protected
14012                                      
14013 ********************************************************************************************/
14014 
14015 BOOL AttrBitmapFill::CopyNodeContents( AttrBitmapFill* NodeCopy)
14016 {
14017     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrBitmapFill::CopyNodeContents!");
14018 
14019     AttrFillGeometry::CopyNodeContents( NodeCopy );
14020 
14021     // Copy contents specific to derived class here
14022     return TRUE;
14023 } 
14024 
14025 
14026 
14027 /********************************************************************************************
14028 
14029 >   FillControl AttrBitmapFill::CheckForControlHit(DocCoord &ClickPos)
14030 
14031     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14032     Created:    21/07/94
14033     Inputs:     ClickPos, The DocCoord position to check.
14034     Returns:    A FillControl, indicating the Fill Control Point Hit,
14035                 or FILLCONTROL_NULL, if no points hit.
14036     Purpose:    Check to see if a click was on a Fill Control Point. 
14037     SeeAlso:    FillControl
14038 
14039 ********************************************************************************************/
14040 
14041 FillControl AttrBitmapFill::CheckForControlHit(DocCoord &ClickPos)
14042 {
14043 #if !defined(EXCLUDE_FROM_RALPH)
14044     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
14045         return FILLCONTROL_NULL;
14046 
14047     // Set up a default, that indicates not control points hit
14048     FillControl HitControl = FILLCONTROL_NULL;
14049     DocRect BlobRect;
14050 
14051     DocCoord StartPoint  = *GetStartPoint();
14052     DocCoord EndPoint    = *GetEndPoint();
14053     DocCoord EndPoint2   = *GetEndPoint2();
14054 
14055     // Bodge Alert !!
14056     
14057     // Bitmap fills have a complicated control point system.
14058     // The actual control points needed for rendering are the Bottom Left,
14059     // Top Left, and Bottom Right points of the bitmap.  But on screen the 
14060     // points seen and moved are the Centre, Middle Right, and Middle Top.
14061     // So we need to convert the click points into vitual points before
14062     // we do the hit test.
14063 
14064     DocCoord CentrePoint;
14065     DocCoord Drag2Blob;
14066     DocCoord Drag3Blob;
14067 
14068     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
14069                             &CentrePoint, &Drag2Blob, &Drag3Blob);
14070 
14071     // Get the rectangle around the Centre Control Point
14072     (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &BlobRect);
14073     // See if the Click Position is within the rectangle
14074     if ( BlobRect.ContainsCoord(ClickPos) )
14075         HitControl = FILLCONTROL_STARTPOINT;
14076 
14077     // Get the rectangle around the First End Point
14078     (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &BlobRect);
14079     // See if the Click Position is within the rectangle
14080     if ( BlobRect.ContainsCoord(ClickPos) )
14081         HitControl = FILLCONTROL_ENDPOINT;
14082 
14083     // Get the rectangle around the Second End Point
14084     (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &BlobRect);
14085     // See if the Click Position is within the rectangle
14086     if ( BlobRect.ContainsCoord(ClickPos) )
14087         HitControl = FILLCONTROL_SECONDARYPOINT;
14088 
14089     return HitControl;
14090 #else
14091     return FILLCONTROL_NULL;
14092 #endif
14093 }
14094 
14095 /********************************************************************************************
14096 
14097 >   virtual void AttrBitmapFill::OnControlDrag( DocCoord Pos, FillControl DragControl, 
14098                                                     ClickModifiers ClickMods)
14099     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14100     Created:    2/8/94
14101     Inputs:     Pos - The Location of the mouse pointer at the time of the call
14102                 DragControl - The FillControl that is being dragged.
14103                 ClickMods - The modifiers to the click (eg shift, control etc )
14104     Purpose:    Called when an edit operation is dragging a fill control point.
14105 
14106 ********************************************************************************************/
14107 
14108 void AttrBitmapFill::OnControlDrag( DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
14109 {
14110 #if !defined(EXCLUDE_FROM_RALPH)
14111     // Get the current Control Point Positions
14112     DocCoord StartPoint = *GetStartPoint();
14113     DocCoord EndPoint = *GetEndPoint();
14114     DocCoord EndPoint2 = *GetEndPoint2();
14115 
14116     DocCoord CentrePoint;
14117     DocCoord Drag2Blob;
14118     DocCoord Drag3Blob;
14119 
14120     // Bodge Alert !!
14121     
14122     // Bitmap fills have a complicated control point system.
14123     // The actual control points needed for rendering are the Bottom Left,
14124     // Top Left, and Bottom Right points of the bitmap.  But on screen the 
14125     // points seen and moved are the Centre, Middle Right, and Middle Top.
14126     // So we need to convert the click points into vitual points before
14127     // we start dragging them about.
14128 
14129     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
14130                             &CentrePoint, &Drag2Blob, &Drag3Blob);
14131 
14132     INT32 dx, dy;
14133 
14134     // Which control is being dragged ?
14135     switch (DragControl)
14136     {
14137         case FILLCONTROL_STARTPOINT:
14138 
14139             // They're dragging the Centre Point
14140             dx = CentrePoint.x - Pos.x;
14141             dy = CentrePoint.y - Pos.y;
14142             // Move the other points relative
14143             Drag2Blob.translate(-dx, -dy);
14144             Drag3Blob.translate(-dx, -dy);
14145             CentrePoint = Pos;
14146             break;
14147 
14148         case FILLCONTROL_ENDPOINT:
14149 
14150             // If the Constrain key is down then constrain the Angle of the
14151             // point, relative to the centre position.
14152             if (ClickMods.Constrain)
14153                 DocView::ConstrainToAngle(CentrePoint, &Pos);
14154 
14155             if (ClickMods.Adjust)
14156             {
14157                 // Shift is pressed, so lock the aspect ratio of the bitmap mesh
14158                 double OldLen = CentrePoint.Distance(Drag2Blob);
14159                 double NewLen = CentrePoint.Distance(Pos);
14160                 double Ratio = 1.0;
14161 
14162                 if (OldLen == 0)
14163                     Ratio = 0;
14164                 else
14165                     Ratio = NewLen/OldLen;
14166 
14167                 // Calculate the new point based on the aspect ratio
14168                 Drag3Blob = 
14169                         MakeLineAtAngle(CentrePoint, Pos, 90, INT32(CentrePoint.Distance(Drag3Blob) * Ratio));
14170             }
14171 
14172             Drag2Blob   = Pos;
14173             break;
14174 
14175         case FILLCONTROL_SECONDARYPOINT:
14176 
14177             // If the Constrain key is down then constrain the Angle of the
14178             // point, relative to the centre position.
14179             if (ClickMods.Constrain)
14180                 DocView::ConstrainToAngle(CentrePoint, &Pos);
14181 
14182             if (ClickMods.Adjust)
14183             {
14184                 // Shift is pressed, so lock the aspect ratio of the bitmap mesh
14185                 double OldLen = CentrePoint.Distance(Drag3Blob);
14186                 double NewLen = CentrePoint.Distance(Pos);
14187                 double Ratio = 1.0;
14188 
14189                 if (OldLen == 0)
14190                     Ratio = 0;
14191                 else
14192                     Ratio = NewLen/OldLen;
14193 
14194                 // Calculate the new point based on the aspect ratio
14195                 Drag2Blob = 
14196                         MakeLineAtAngle(CentrePoint, Pos, -90, INT32(CentrePoint.Distance(Drag2Blob) * Ratio));
14197             }
14198 
14199             Drag3Blob  = Pos;
14200             break;
14201     }
14202 
14203     // Now we have to convert the Virtual Coords back into real
14204     // bitmap control points.
14205     TRACEUSER( "Mike", _T("Centre at %d,%d\n"), CentrePoint.x, CentrePoint.y);
14206 
14207     GetBitmapRealPoints(CentrePoint, Drag2Blob, Drag3Blob,
14208                             &StartPoint, &EndPoint, &EndPoint2);
14209 
14210     // Store the new points back in the Fill
14211     SetStartPoint(&StartPoint);
14212     SetEndPoint(&EndPoint);
14213     SetEndPoint2(&EndPoint2);
14214 #endif
14215 }
14216 
14217 void AttrBitmapFill::SetAspectRatio(double Ratio)
14218 {
14219 #if !defined(EXCLUDE_FROM_RALPH)
14220     // Get the current Control Point Positions
14221     DocCoord StartPoint = *GetStartPoint();
14222     DocCoord EndPoint = *GetEndPoint();
14223     DocCoord EndPoint2 = *GetEndPoint2();
14224 
14225     DocCoord CentrePoint;
14226     DocCoord Drag2Blob;
14227     DocCoord Drag3Blob;
14228 
14229     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
14230                             &CentrePoint, &Drag2Blob, &Drag3Blob);
14231 
14232     Drag3Blob = MakeLineAtAngle(CentrePoint, 
14233                                 Drag2Blob, 
14234                                 90, 
14235                                 INT32(CentrePoint.Distance(Drag2Blob) * Ratio)
14236                                 );
14237 
14238     GetBitmapRealPoints(CentrePoint, Drag2Blob, Drag3Blob,
14239                             &StartPoint, &EndPoint, &EndPoint2);
14240 
14241     // Store the new points back in the Fill
14242     SetStartPoint(&StartPoint);
14243     SetEndPoint(&EndPoint);
14244     SetEndPoint2(&EndPoint2);
14245 #endif
14246 }
14247 
14248 /********************************************************************************************
14249 
14250 >   void AttrBitmapFill::ValidateAttributeValue()
14251 
14252     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14253     Created:    11/8/94
14254     Purpose:    Makes sure the Coords of the Fill are sensible. Defaults to natural size
14255                 of the bitmap
14256 
14257 ********************************************************************************************/
14258 
14259 void AttrBitmapFill::ValidateAttributeValue()
14260 {
14261 #if !defined(EXCLUDE_FROM_RALPH)
14262     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0) &&
14263         (*GetEndPoint2()) != DocCoord(0,0))
14264         return;
14265 
14266     // Make some defaults
14267     DocRect AttrBounds = DocRect(0,0,0,0);
14268 
14269     INT32 Width  = DEFAULT_FILLWIDTH;
14270     INT32 Height = DEFAULT_FILLHEIGHT;
14271 
14272     // Are we an Orphan ?
14273     if (FindParent() != NULL)
14274     {
14275         // Nope, so we can use Daddies Bounding Box
14276         SelRange* Selected = GetApplication()->FindSelection();
14277                  
14278         if (Selected == NULL || Selected->Count() <= 1)
14279             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
14280         else
14281             AttrBounds = Selected->GetBoundingRect();
14282 
14283         Width  = AttrBounds.Width();
14284         Height = AttrBounds.Height();
14285     }
14286 
14287     BitmapInfo Info;
14288     BOOL GotBitmap = FALSE;
14289 
14290     // if possible we base our default size on the bitmaps preferred size
14291     KernelBitmap* KerBmp = ((FillGeometryAttribute*)GetAttributeValue())->GetBitmap();
14292     
14293     if (KerBmp && KerBmp->ActualBitmap)
14294         GotBitmap = KerBmp->ActualBitmap->GetInfo( &Info );
14295 
14296     // Use the recommended Width and Height if possible
14297     INT32 BitmapWidth  = (GotBitmap ? Info.RecommendedWidth  : Width );
14298     INT32 BitmapHeight = (GotBitmap ? Info.RecommendedHeight : Height );
14299 
14300     // Find the middle of the Attributes Bounds
14301     DocCoord Centre = CentreOf(AttrBounds);
14302 
14303     // Get the current control positions
14304     DocCoord StartPoint = *GetStartPoint();
14305     DocCoord EndPoint = *GetEndPoint();
14306     DocCoord EndPoint2 = *GetEndPoint2();
14307 
14308     // If the StartPoint is 'NULL' then make all points sensible
14309     if (StartPoint == DocCoord(0,0))
14310     {
14311         // Start in the middle
14312         StartPoint = DocCoord(Centre.x - BitmapWidth/2, Centre.y - BitmapHeight/2);
14313         // End on the Middle Right
14314         EndPoint = DocCoord(StartPoint.x + BitmapWidth, StartPoint.y);
14315         // and Middle Top
14316         EndPoint2 = DocCoord(StartPoint.x, StartPoint.y + BitmapHeight);
14317     }
14318 
14319     // If the EndPoint is 'NULL' then make end points sensible
14320     if (EndPoint == DocCoord(0,0))
14321     {
14322         EndPoint = DocCoord(StartPoint.x + BitmapWidth, StartPoint.y);
14323         EndPoint2 = DocCoord(StartPoint.x, StartPoint.y + BitmapHeight);
14324     }
14325 
14326     // If the EndPoint2 is 'NULL' then make it sensible
14327     if (EndPoint2 == DocCoord(0,0))
14328     {
14329         EndPoint2 = DocCoord(StartPoint.x, StartPoint.y + BitmapHeight);
14330     }
14331 
14332     // Store the validated positions back
14333     SetStartPoint(&StartPoint);
14334     SetEndPoint(&EndPoint);
14335     SetEndPoint2(&EndPoint2);
14336 #endif
14337 }
14338 
14339 /********************************************************************************************
14340 
14341 >   void AttrBitmapFill::RenderFillMesh(RenderRegion* pRender, 
14342                                     DocCoord* ControlPoints, BOOL* SelState,
14343                                     INT32 NumControlPoints)
14344     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14345     Created:    24/7/94
14346     Inputs:     pRender - The region to render the blobs to.
14347                 ControlPoints - The positions of all the control points
14348                 SelState - The selection state of the control points
14349                 NumControlPoints - The Number of control points.
14350     Purpose:    Renders the grad fills mesh during a drag op.
14351                 Don't call this, call RenderFillBlobs().
14352     SeeAlso:    AttrBitmapFill::RenderFillBlobs
14353 
14354 ********************************************************************************************/
14355 
14356 void AttrBitmapFill::RenderFillMesh(RenderRegion* pRender, 
14357                                     DocCoord* ControlPoints, BOOL* SelState,
14358                                     INT32 NumControlPoints)
14359 {
14360 #if !defined(EXCLUDE_FROM_RALPH)
14361     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
14362     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
14363 
14364     if (StartPoint == EndPoint)
14365         return;
14366 
14367     if (SelState == NULL)
14368     {
14369         // If no selection state passed in, then assume
14370         // all the points are deselected
14371         BOOL Selected[NUMCONTROLPOINTS];
14372         for (INT32 i=0; i< NumControlPoints; i++)
14373         {
14374             Selected[i] = FALSE;
14375         }
14376         SelState = Selected;
14377     }
14378 
14379     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_SECONDARYPOINT];
14380 
14381     DocCoord Start;
14382     DocCoord End;
14383     DocCoord End2; 
14384 
14385     // Work out the Virtual positions of the Bitmap Controls
14386     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
14387                             &Start, &End, &End2);
14388 
14389     // Remember what attributes were here before
14390     pRender->SaveContext();
14391 
14392     // Get the current blob size in Doc Units
14393     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
14394 
14395     // Calculate the Arrow on the End of the Line
14396     Path ArrowPath;
14397     ArrowPath.Initialise();
14398     DocCoord LineEnd;
14399     MakeMeshArrow(&ArrowPath, Start, End, &LineEnd);
14400 
14401     // Calculate the Arrow on the End of the Line2
14402     Path ArrowPath2;
14403     ArrowPath2.Initialise();
14404     DocCoord LineEnd2;
14405     MakeMeshArrow(&ArrowPath2, Start, End2, &LineEnd2);
14406 
14407     // Set the line colours etc as we need them
14408     pRender->SetLineWidth(0);
14409     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
14410     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
14411 
14412     // First Draw the Line
14413     pRender->SetLineWidth(BlobSize/4);
14414     pRender->DrawLine(Start, LineEnd);
14415 
14416     // Draw the secondary line
14417     pRender->DrawLine(Start, LineEnd2);
14418 
14419     // Render an Arrow at the end of the line
14420     pRender->SetLineWidth(0);
14421     pRender->SetLineColour(COLOUR_NONE);
14422     pRender->DrawPath(&ArrowPath);
14423 
14424     // and on the end of the secondary line
14425     pRender->DrawPath(&ArrowPath2);
14426 
14427     if (DraggedFill == this)
14428     {
14429         // If we are being dragged then draw a Parallelgram to
14430         // show the shape of the bitmap
14431         pRender->SetLineColour(COLOUR_SELECTEDBLOB);
14432         pRender->SetFillColour(COLOUR_NONE);
14433     
14434         Path ParaPath;
14435         ParaPath.Initialise();
14436         MakeMeshParallelagram(&ParaPath, Start, End, End2);
14437 
14438         // Draw the parallelagram
14439         pRender->DrawPath(&ParaPath);
14440     }
14441 
14442     // Put all the old attributes back
14443     pRender->RestoreContext();
14444 #endif
14445 }
14446 
14447 /********************************************************************************************
14448 
14449 >   virtual DocRect AttrBitmapFill::GetBlobBoundingRect()
14450 
14451     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14452     Created:    10/8/94
14453     Returns:    DocRect - The rectangle that contains all the nodes selection blobs.
14454     Purpose:    Calculates the bounding rectangle of the attrs blobs.This should always 
14455                 be calculated on the fly as the view scale can change without the attr 
14456                 knowing, giving an incorrect result.
14457 
14458 ********************************************************************************************/
14459 
14460 DocRect AttrBitmapFill::GetBlobBoundingRect()
14461 {
14462 #if !defined(EXCLUDE_FROM_RALPH)
14463     // Optimisation.  If there is currently no interest in Fill Blobs
14464     // and this fill is not being Dragged (Fill blobs are turned off during
14465     // a fill drag), then we needn't bother doing anything. 
14466     if ( (!GetApplication()->GetBlobManager()->GetCurrentInterest(TRUE).Fill || !IsVisible()) && DraggedFill != this )
14467         return DocRect(0,0, 0,0);
14468 
14469     // Get the Start and End Points
14470     DocCoord StartPoint = *GetStartPoint();
14471     DocCoord EndPoint   = *GetEndPoint();
14472     DocCoord EndPoint2  = *GetEndPoint2();
14473 
14474     // Work out the Virtual Coords
14475     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
14476                             &StartPoint, &EndPoint, &EndPoint2);
14477 
14478     // Make a dummy bounds from just the Start Point
14479     DocRect BoundingRect(StartPoint, StartPoint);
14480 
14481     if (DraggedFill == this)
14482     {
14483         // This fill is being dragged, so we have to include the Parallelagram 
14484         // bounding rect as well
14485         DocRect StartBlobRect;
14486         DocRect EndBlobRect;
14487         DocRect DragRect = GetParallelagramBounds(StartPoint, EndPoint, EndPoint2);
14488 
14489         // Get the Bounding rect of Blobs on each of the ends
14490         (Camelot.GetBlobManager())->GetBlobRect(DragRect.lo, &StartBlobRect);
14491         (Camelot.GetBlobManager())->GetBlobRect(DragRect.hi, &EndBlobRect);
14492 
14493         // Now include the Bottom Left and Top Right of each blob in the Bounds.
14494         // We have to do it like this to make sure that the DocRect's coords
14495         // are valid.  ie. The Hi's are Higher than the Lo's.
14496         BoundingRect.IncludePoint(StartBlobRect.lo);
14497         BoundingRect.IncludePoint(StartBlobRect.hi);
14498         BoundingRect.IncludePoint(EndBlobRect.lo);
14499         BoundingRect.IncludePoint(EndBlobRect.hi);
14500     }
14501     else
14502     {
14503         // We're not being dragged, so just calc the bounds of the Start and End Blobs
14504         DocRect StartBlobRect;
14505         DocRect EndBlobRect;
14506         DocRect End2BlobRect;
14507 
14508         // Get the Bounding rect of the Fill Line, including the Blobs on the ends
14509         (Camelot.GetBlobManager())->GetBlobRect(StartPoint, &StartBlobRect);
14510         (Camelot.GetBlobManager())->GetBlobRect(EndPoint, &EndBlobRect);
14511         (Camelot.GetBlobManager())->GetBlobRect(EndPoint2, &End2BlobRect);
14512 
14513         // Now include the Bottom Left and Top Right of each blob in the Bounds.
14514         // We have to do it like this to make sure that the DocRect's coords
14515         // are valid.  ie. The Hi's are Higher than the Lo's.
14516         BoundingRect.IncludePoint(StartBlobRect.lo);
14517         BoundingRect.IncludePoint(StartBlobRect.hi);
14518         BoundingRect.IncludePoint(EndBlobRect.lo);
14519         BoundingRect.IncludePoint(EndBlobRect.hi);
14520         BoundingRect.IncludePoint(End2BlobRect.lo);
14521         BoundingRect.IncludePoint(End2BlobRect.hi);
14522     }
14523 
14524     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint);
14525     IncludeArrowHead(&BoundingRect, StartPoint, EndPoint2);
14526 
14527     // and return it
14528     return BoundingRect;
14529 #else
14530     return DocRect(0,0,0,0);
14531 #endif
14532 }
14533 
14534 /********************************************************************************************
14535 
14536 >   void AttrBitmapFill::DrawEndBlobs()
14537 
14538     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14539     Created:    25/1/95
14540     Purpose:    Draws the blobs on the ends of the fill arrows.
14541 
14542 ********************************************************************************************/
14543 
14544 void AttrBitmapFill::DrawEndBlobs()
14545 {
14546 #if !defined(EXCLUDE_FROM_RALPH)
14547     Node *pNode = this;
14548     while ((pNode != NULL) && !pNode->IsKindOf(CC_RUNTIME_CLASS(Spread)))
14549         pNode = pNode->FindParent();
14550 
14551     if (pNode == NULL)
14552         return;         // We're not really in the tree
14553 
14554     Spread* pSpread = (Spread*)pNode;
14555 
14556     DocRect Bounds = GetBlobBoundingRect();
14557 
14558     DocCoord Start = *GetStartPoint();
14559     DocCoord End   = *GetEndPoint();
14560     DocCoord End2  = *GetEndPoint2();
14561 
14562     GetBitmapVirtualPoints(Start, End, End2,
14563                             &Start, &End, &End2);
14564 
14565     RenderRegion* pRender = DocView::RenderOnTop(&Bounds, pSpread, UnclippedEOR);
14566     while (pRender)
14567     {
14568         // Draw a blob at the start point
14569         if (IsSelected(FILLCONTROL_STARTPOINT))
14570         {
14571             // Draw Selected Blob
14572 //          pRender->SetLineColour(COLOUR_SELECTEDBLOB);
14573             pRender->SetLineColour(COLOUR_NONE);
14574             pRender->SetFillColour(COLOUR_SELECTEDBLOB);
14575             pRender->DrawBlob(Start, BT_SELECTED);
14576         }
14577         else
14578         {
14579             // Draw Unselected Blob
14580 //          pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
14581             pRender->SetLineColour(COLOUR_NONE);
14582             pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
14583             pRender->DrawBlob(Start, BT_UNSELECTED);
14584         }
14585 
14586         // Draw a blob at the end point
14587         if (IsSelected(FILLCONTROL_ENDPOINT))
14588         {
14589             // Draw Selected Blob
14590 //          pRender->SetLineColour(COLOUR_SELECTEDBLOB);
14591             pRender->SetLineColour(COLOUR_NONE);
14592             pRender->SetFillColour(COLOUR_SELECTEDBLOB);
14593             pRender->DrawBlob(End, BT_SELECTED);
14594             pRender->DrawBlob(End2, BT_SELECTED);
14595         }
14596         else
14597         {
14598             // Draw Unselected Blob
14599 //          pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
14600             pRender->SetLineColour(COLOUR_NONE);
14601             pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
14602             pRender->DrawBlob(End, BT_UNSELECTED);
14603             pRender->DrawBlob(End2, BT_UNSELECTED);
14604         }
14605 
14606         // Get the Next render region
14607         pRender = DocView::GetNextOnTop(&Bounds);
14608     }
14609 
14610     // Bodge to stop fill meshes EOR each other out.
14611     AttrFillGeometry::LastRenderedMesh = NULL;
14612 #endif
14613 }
14614 
14615 
14616 //===========================================================================================
14617 //
14618 //  Karim MacDonald 08/12/1999
14619 //  Extending Bits
14620 //
14621 //===========================================================================================
14622 
14623 /********************************************************************************************
14624 
14625 >   DocRect AttrBitmapFill::ValidateExtend(const ExtendParams& ExtParams)
14626 
14627     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
14628     Created:    08/12/1999
14629     Inputs:     ExtParams       description parameters for the extension.
14630     Outputs:    
14631     Returns:    TRUE    if this bitmap fill may be reversible extended.
14632                 FALSE   otherwise.
14633     Purpose:    Determine whether applying an extend to this Node is a reversible process.
14634     Errors:     
14635     See also:   class Extender; IsTypeExtendible(); Extend()
14636 
14637 ********************************************************************************************/
14638 DocRect AttrBitmapFill::ValidateExtend(const ExtendParams& ExtParams)
14639 {
14640     // a bitmap fill is treated a bit like text - it should maintain its aspect ratio and
14641     // translate as a whole. therefore, we only validate its extend reference-centre.
14642     // it also has no children to test.
14643     DocCoord doccArray[1] = { FindExtendCentre() };
14644     return Extender::ValidateControlPoints(1, doccArray, ExtParams);
14645 //  return DocRect(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX);
14646 }
14647 
14648 
14649 
14650 /********************************************************************************************
14651 
14652 >   void AttrBitmapFill::Extend(const ExtendParams& ExtParams)
14653 
14654     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
14655     Created:    08/12/1999
14656     Inputs:     ExtParams       description parameters for the extension.
14657     Outputs:    This fill node may have its dimensions altered by the extension.
14658     Returns:    
14659     Purpose:    Perform an extend operation on this fill node.
14660     Errors:     
14661     See also:   class Extender; IsTypeExtendible(); Extend()
14662 
14663 ********************************************************************************************/
14664 void AttrBitmapFill::Extend(const ExtendParams& ExtParams)
14665 {
14666     // a bitmap fill's behaviour depends upon what it is applied to:
14667     //  non-path    with    EXTEND  ::  do nothing - its parent will transform it correctly.
14668     //  path node   with    EXTEND  ::  translate itself; remember that its parent has moved
14669     //                                  its centre by ExtParams.doccOffset already.
14670     //  any node    with    STRETCH ::  we need to unstretch ourself...
14671     // it is assumed here, though this may not always be true, that the fill's parent node
14672     // is the node to which it is applied.
14673     Node* pParent = FindParent();
14674     if (pParent != NULL)
14675         if (pParent->IsNodePath() || pParent->IsCompound())
14676             TransformTranslateObject(ExtParams);
14677 
14678     // if we are asked to stretch, we must first undo any stretch which was done to us by the
14679     // node we are applied to. then we must translate ourself, so that we maintain our place,
14680     // relative to the centre of the button.
14681 
14682 
14683     // we do all of this because this is what would be expected for a texture on a button.
14684     // the texture should _not_ stretch if the button stretches, but _should_ move around
14685     // with the button.
14686     // if the button stretches and moves, we arbitrarily decided that the fill should remain
14687     // in the same position relative to the scale-reference coord of the button - see
14688     // definition of ExtendParams for details.
14689     ExtendParams eps = ExtParams;
14690     eps.xscale = 1 / eps.xscale;                    //
14691     eps.yscale = 1 / eps.yscale;                    //  ie, 'undo the stretch, but leave
14692     eps.doccScaleStart = ExtParams.doccScaleEnd;    //      us where the stretch put us."
14693     eps.doccScaleEnd = ExtParams.doccScaleEnd;      //
14694     TransformStretchObject(eps);
14695 }
14696 
14697 
14698 
14699 /********************************************************************************************
14700 
14701 >   virtual void AttrBitmapFill::TransformTranslateObject(const ExtendParams& ExtParams)
14702 
14703     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
14704     Created:    09/12/1999
14705     Inputs:     ExtParams       description of how this bitmap fill should translate.
14706     Outputs:    This fill may be translated, depending on the flags held within ExtParams.
14707     Purpose:    Translate this bitmap fill, according to the offsets and flags defined in ExtParams,
14708                 and a reference centre, defined by NodeRenderable::FindExtendCentre().
14709                 This function does nothing unless ExtParams uses X_EXTEND or Y_EXTEND.
14710 
14711                 This function is identical to NodeRenderable::TransformObject, except that
14712                 in all cases except when our parent is a group, it will have already applied
14713                 ExtParams' doccOffset to us, so we can usually omit this step.
14714 
14715     See also:   The Extender class; FindExtendCentre().
14716 
14717 ********************************************************************************************/
14718 void AttrBitmapFill::TransformTranslateObject(const ExtendParams& ExtParams)
14719 {
14720     DocCoord doccCentre = FindExtendCentre();
14721 
14722     // x-extension - we move the whole Node; behaviour determined by its centre.
14723     if (ExtParams.fExtendFlags & X_EXTEND)
14724     {
14725         // if our parent is a group, then it won't have applied any offset parameter to us,
14726         // so we need to do this ourself.
14727         Node* pParent = FindParent();
14728         if (pParent != NULL && pParent->IsCompound())
14729         {
14730             Trans2DMatrix baseXoffset(ExtParams.doccOffset.x, 0);
14731             Transform(baseXoffset);
14732         }
14733 
14734         // we only move anything if we're outside a buffer-zone around the centre
14735         // (necessary as objects can be misaligned by a millipoint or two).
14736         if (doccCentre.x > ExtParams.doccEndCentre.x + ExtParams.xincExtendBuffer)
14737         {
14738             Trans2DMatrix translateX(ExtParams.xinc, 0);
14739             Transform(translateX);
14740         }
14741         else if (doccCentre.x < ExtParams.doccEndCentre.x - ExtParams.xdecExtendBuffer)
14742         {
14743             Trans2DMatrix translateX(-ExtParams.xdec, 0);
14744             Transform(translateX);
14745         }
14746     }
14747 
14748     // y-extension - we move the whole Node; behaviour determined by its centre.
14749     if (ExtParams.fExtendFlags & Y_EXTEND)
14750     {
14751         // if our parent is a group, then it won't have applied any offset parameter to us,
14752         // so we need to do this ourself.
14753         Node* pParent = FindParent();
14754         if (pParent != NULL && pParent->IsCompound())
14755         {
14756             Trans2DMatrix baseYoffset(0, ExtParams.doccOffset.y);
14757             Transform(baseYoffset);
14758         }
14759 
14760         // only extend if we're outside the centre's buffer-zone.
14761         if (doccCentre.y > ExtParams.doccEndCentre.y + ExtParams.yincExtendBuffer)
14762         {
14763             Trans2DMatrix translateY(0, ExtParams.yinc);
14764             Transform(translateY);
14765         }
14766         else if (doccCentre.y < ExtParams.doccEndCentre.y - ExtParams.ydecExtendBuffer)
14767         {
14768             Trans2DMatrix translateY(0, -ExtParams.ydec);
14769             Transform(translateY);
14770         }
14771     }
14772 }
14773 
14774 
14775 
14777 //
14778 //                              AttrBitmapColourFill
14779 //
14781 
14782 /********************************************************************************************
14783 
14784 >   void AttrBitmapColourFill::Render( RenderRegion* pRender)
14785 
14786     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14787     Created:    23/8/94
14788     Purpose:    'Renders' a Bitmap Fill Colour attribute.
14789 
14790 ********************************************************************************************/
14791 
14792 void AttrBitmapColourFill::Render(RenderRegion* pRender)
14793 {
14794     pRender->SetFillGeometry(&Value, FALSE);
14795 }
14796 
14797 /********************************************************************************************
14798 
14799 > Node* AttrBitmapColourFill::SimpleCopy() 
14800 
14801     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14802     Created:    23/8/94
14803     Returns:    A copy of the node, or NULL if memory runs out 
14804     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
14805                 The function is virtual, and must be defined for all derived classes.  
14806     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
14807                 memory error and the function returns NULL. 
14808     Scope:      protected       
14809 
14810 ********************************************************************************************/
14811      
14812 Node* AttrBitmapColourFill::SimpleCopy()
14813 {
14814     AttrBitmapColourFill* NodeCopy = new AttrBitmapColourFill();
14815     if (NodeCopy == NULL)
14816         return NULL;
14817 
14818     CopyNodeContents(NodeCopy);
14819     
14820     return NodeCopy;
14821 }  
14822 
14823 /********************************************************************************************
14824 
14825 >   virtual UINT32 AttrBitmapColourFill::GetAttrNameID(void)  
14826 
14827     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14828     Created:    23/8/94
14829     Returns:    Attribute description ID
14830     Purpose:    Returns a string resource ID describing the attribute
14831 
14832 ********************************************************************************************/
14833 
14834 UINT32 AttrBitmapColourFill::GetAttrNameID(void)  
14835 {
14836     return (_R(IDS_BITMAPFILL)); 
14837 }                                  
14838 
14839 /********************************************************************************************
14840 
14841 >   void AttrBitmapColourFill::GetDebugDetails(StringBase* Str)
14842 
14843     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14844     Created:    20/07/94
14845     Outputs:    Str - the string containing details of the attribute.
14846     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
14847 
14848 ********************************************************************************************/
14849 
14850 void AttrBitmapColourFill::GetDebugDetails(StringBase* Str)
14851 {
14852 #ifdef _DEBUG
14853     NodeAttribute::GetDebugDetails( Str );
14854 
14855     String_256 TempStr;
14856 
14857     TempStr._MakeMsg( TEXT("\r\nBitmap Fill:\r\n"));
14858     (*Str) += TempStr;
14859 
14860     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
14861                      (*GetStartPoint()).x, (*GetStartPoint()).y);
14862     (*Str) += TempStr;
14863 
14864     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
14865                      (*GetEndPoint()).x, (*GetEndPoint()).y);
14866     (*Str) += TempStr;
14867 
14868     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
14869                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
14870     (*Str) += TempStr;
14871 
14872     BitmapInfo Info;
14873     KernelBitmap* KerBmp = ((BitmapFillAttribute*)GetAttributeValue())->GetBitmap();
14874 
14875     if (KerBmp && KerBmp->ActualBitmap && KerBmp->ActualBitmap->GetInfo( &Info ) )
14876     {
14877         TempStr._MakeMsg( _T("\r\nBits = (#1%ux#2%ux#3%u) "), Info.PixelWidth,
14878                                         Info.PixelHeight,
14879                                         Info.PixelDepth
14880                         );
14881         (*Str) += TempStr;
14882     }
14883 #endif
14884 }
14885 
14886 /********************************************************************************************
14887 
14888 >   virtual UINT32 AttrBitmapColourFill::GetNodeSize() const
14889 
14890     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14891     Created:    23/8/94
14892     Returns:    The size of the node in bytes
14893     Purpose:    For finding the size of the node.
14894     SeeAlso:    Node::GetSubtreeSize
14895 
14896 ********************************************************************************************/
14897 
14898 UINT32 AttrBitmapColourFill::GetNodeSize() const 
14899 {     
14900     return sizeof(AttrBitmapColourFill);
14901 }  
14902 
14903 /********************************************************************************************
14904 
14905 >   void AttrBitmapColourFill::RenderFillBlobs(RenderRegion* pRender)
14906 
14907     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
14908     Created:    24/6/94
14909     Inputs:     pRender - The region to render the blobs to.
14910     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
14911 
14912 ********************************************************************************************/
14913 
14914 void AttrBitmapColourFill::RenderFillBlobs(RenderRegion* pRender)
14915 {
14916 #if !defined(EXCLUDE_FROM_RALPH)
14917     if (!IsVisible())
14918         return;     // We're in Fill Transparency Mode
14919 
14920     // Don't bother if this fill is being edited as a copy of it
14921     // we be rendered thoughout the drag op
14922     if (IsFillBeingEdited())
14923         return;
14924 
14925     // Ignore this if the mesh is the same as the last one rendered.
14926     if (CheckPreviousFillMesh())
14927         return;
14928 
14929     DocCoord ControlPoints[5];
14930     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
14931     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
14932     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
14933 
14934 /*
14935     TRACEUSER( "Mike", _T("Start=%d,%d; End=%d,%d; End2=%d,%d\n"),ControlPoints[0].x, ControlPoints[0].y,
14936                                                              ControlPoints[1].x, ControlPoints[1].y,
14937                                                              ControlPoints[2].x, ControlPoints[2].y);
14938 
14939     DocRect ClipRect = pRender->GetClipRect();
14940 
14941     if (DraggedFill == NULL)
14942     {
14943         DocColour RandCol = DocColour(ColourValue(rand()>>7), ColourValue(rand()>>7), ColourValue(rand()>>7));
14944 
14945         pRender->SetFillColour(RandCol);
14946         pRender->SetLineColour(COLOUR_NONE);
14947         pRender->DrawRect(&ClipRect);
14948     }
14949 
14950     TRACEUSER( "Mike", _T("ClipRect=%d,%d, %d,%d\n"),ClipRect.lox,ClipRect.loy,ClipRect.hix,ClipRect.hiy);
14951 */
14952 
14953     // Render a nice pretty Fill Mesh thingy
14954     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
14955 
14956     // This call was removed by Gerry (2/9/96) as it causes blob problems
14957     // If we are removing blobs then force all blobs to be deselected
14958 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
14959 //      DeselectAllNoRedraw();
14960 #endif
14961 }
14962 
14963 /********************************************************************************************
14964 
14965 >   void AttrBitmapColourFill::RenderFillMesh(  RenderRegion* pRender, 
14966                                                 DocCoord* ControlPoints, BOOL* SelState,
14967                                                 INT32 NumControlPoints)
14968     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
14969     Created:    24/7/94
14970     Inputs:     pRender - The region to render the blobs to.
14971                 ControlPoints - The positions of all the control points
14972                 SelState - The selection state of the control points
14973                 NumControlPoints - The Number of control points.
14974     Purpose:    Renders the grad fills mesh during a drag op.
14975                 Don't call this, call RenderFillBlobs().
14976     SeeAlso:    AttrBitmapFill::RenderFillBlobs
14977 
14978 ********************************************************************************************/
14979 
14980 void AttrBitmapColourFill::RenderFillMesh(  RenderRegion* pRender, 
14981                                             DocCoord* ControlPoints, BOOL* SelState,
14982                                             INT32 NumControlPoints)
14983 {
14984 #if !defined(EXCLUDE_FROM_RALPH)
14985     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
14986     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
14987 
14988     if (StartPoint == EndPoint)
14989         return;
14990 
14991     if (SelState == NULL)
14992     {
14993         // If no selection state passed in, then assume
14994         // all the points are deselected
14995         BOOL Selected[NUMCONTROLPOINTS];
14996         for (INT32 i=0; i< NumControlPoints; i++)
14997         {
14998             Selected[i] = FALSE;
14999         }
15000         SelState = Selected;
15001     }
15002 
15003     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_SECONDARYPOINT];
15004 
15005     DocCoord Start;
15006     DocCoord End;
15007     DocCoord End2; 
15008 
15009     // Work out the Virtual positions of the Bitmap Controls
15010     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
15011                             &Start, &End, &End2);
15012 
15013     // Remember what attributes were here before
15014     pRender->SaveContext();
15015 
15016     // Get the current blob size in Doc Units
15017     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
15018 
15019     // Calculate the Arrow on the End of the Line
15020     Path ArrowPath;
15021     ArrowPath.Initialise();
15022     DocCoord LineEnd;
15023     MakeMeshArrow(&ArrowPath, Start, End, &LineEnd);
15024 
15025     // Calculate the Arrow on the End of the Line2
15026     Path ArrowPath2;
15027     ArrowPath2.Initialise();
15028     DocCoord LineEnd2;
15029     MakeMeshArrow(&ArrowPath2, Start, End2, &LineEnd2);
15030 
15031     // Set the line colours etc as we need them
15032     pRender->SetLineWidth(0);
15033     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
15034     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
15035 
15036     // First Draw the Line
15037     pRender->SetLineWidth(BlobSize/4);
15038     pRender->DrawLine(Start, LineEnd);
15039 
15040     // Draw the secondary line
15041     pRender->DrawLine(Start, LineEnd2);
15042 
15043     // Render an Arrow at the end of the line
15044     pRender->SetLineWidth(0);
15045     pRender->SetLineColour(COLOUR_NONE);
15046     pRender->DrawPath(&ArrowPath);
15047 
15048     // and on the end of the secondary line
15049     pRender->DrawPath(&ArrowPath2);
15050 
15051     if (DraggedFill == this)
15052     {
15053         // If we are being dragged then draw a Parallelgram to
15054         // show the shape of the bitmap
15055         pRender->SetLineColour(COLOUR_SELECTEDBLOB);
15056         pRender->SetFillColour(COLOUR_NONE);
15057     
15058         Path ParaPath;
15059         ParaPath.Initialise();
15060         MakeMeshParallelagram(&ParaPath, Start, End, End2);
15061 
15062         // Draw the parallelagram
15063         pRender->DrawPath(&ParaPath);
15064     }
15065 
15066     // Now Render the blobs on the path
15067 //  if (GetBitmap()->GetBPP() <= 8)
15068 //  {
15069         // Draw a blob at the start point
15070         if (SelState[FILLCONTROL_STARTPOINT])
15071         {
15072             // Draw Selected Blob
15073 //          pRender->SetLineColour(COLOUR_SELECTEDBLOB);
15074             pRender->SetLineColour(COLOUR_NONE);
15075             pRender->SetFillColour(COLOUR_SELECTEDBLOB);
15076             pRender->DrawBlob(Start, BT_SELECTED);
15077         }
15078         else
15079         {
15080             // Draw Unselected Blob
15081 //          pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
15082             pRender->SetLineColour(COLOUR_NONE);
15083             pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
15084             pRender->DrawBlob(Start, BT_UNSELECTED);
15085         }
15086 
15087         // Draw a blob at the end point
15088         if (SelState[FILLCONTROL_ENDPOINT])
15089         {
15090             // Draw Selected Blob
15091 //          pRender->SetLineColour(COLOUR_SELECTEDBLOB);
15092             pRender->SetLineColour(COLOUR_NONE);
15093             pRender->SetFillColour(COLOUR_SELECTEDBLOB);
15094             pRender->DrawBlob(End, BT_SELECTED);
15095             pRender->DrawBlob(End2,BT_SELECTED);
15096         }
15097         else
15098         {
15099             // Draw Unselected Blob
15100 //          pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
15101             pRender->SetLineColour(COLOUR_NONE);
15102             pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
15103             pRender->DrawBlob(End, BT_UNSELECTED);
15104             pRender->DrawBlob(End2,BT_UNSELECTED);
15105         }
15106 //  }
15107 
15108     // Put all the old attributes back
15109     pRender->RestoreContext();
15110 #endif
15111 }
15112 
15113 /********************************************************************************************
15114 
15115 >   void AttrBitmapColourFill::RenderControl(FillControl Control, BOOL RenderOn)
15116 
15117     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15118     Created:    26/7/94
15119     Inputs:     Control, the FillControl to redraw
15120     Purpose:    Redraws the Fill Control blobs when the selection changes.
15121     SeeAlso:    FillControl         
15122 
15123 ********************************************************************************************/
15124 
15125 void AttrBitmapColourFill::RenderControl(FillControl Control, BOOL RenderOn)
15126 {
15127 #if !defined(EXCLUDE_FROM_RALPH)
15128     DocRect ControlRect;
15129 
15130     // Ignore if we're not in the tree yet
15131     // We may be a tempory clone, or something
15132     NodeRenderable* pParent = (NodeRenderable*)FindParent();
15133 
15134     if (pParent == NULL)
15135         return;
15136 
15137     if (IsBlobSame(Control))
15138         return;         // Ignore if same as the last blob rendered
15139 
15140     Spread* pSpread = this->FindParentSpread();
15141 
15142     DocCoord StartPoint = *GetStartPoint();
15143     DocCoord EndPoint = *GetEndPoint();
15144     DocCoord EndPoint2 = *GetEndPoint2();
15145 
15146     DocCoord CentrePoint;
15147     DocCoord Drag2Blob;
15148     DocCoord Drag3Blob;
15149 
15150     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
15151                             &CentrePoint, &Drag2Blob, &Drag3Blob);
15152 
15153     switch (Control)
15154     {
15155         case FILLCONTROL_STARTPOINT:
15156 
15157             if (GetStartPoint() != NULL)
15158             {
15159                 // Redraw the Start Point Blob
15160                 (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &ControlRect);
15161                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15162             }
15163             break;
15164 
15165         case FILLCONTROL_ENDPOINT:
15166 
15167             if (GetEndPoint() != NULL)
15168             {
15169                 // Redraw BOTH End Point Blobs
15170                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
15171                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15172             }
15173 
15174             if (GetEndPoint2() != NULL)
15175             {
15176                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
15177                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15178             }
15179             break;
15180 
15181         case FILLCONTROL_SECONDARYPOINT:
15182 
15183             if (GetEndPoint2() != NULL)
15184             {
15185                 // Redraw BOTH End Point Blobs
15186                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
15187                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15188             }
15189 
15190             if (GetEndPoint2() != NULL)
15191             {
15192                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
15193                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15194             }
15195             break;
15196     }
15197 #endif
15198 }
15199 
15200 /********************************************************************************************
15201 
15202 >   BOOL AttrBitmapColourFill::ChangeControlColour(AttrColourChange* NewCol)
15203 
15204     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15205     Created:    27/6/95
15206     Inputs:     -
15207     Purpose:    Alter the colour of a selected fill handle
15208     SeeAlso:    -
15209 
15210 ********************************************************************************************/
15211 
15212 BOOL AttrBitmapColourFill::ChangeControlColour(AttrColourChange* NewCol)
15213 { 
15214 #if !defined(EXCLUDE_FROM_RALPH)
15215     // Do contone stuff here ....
15216     if (SelectionState[FILLCONTROL_STARTPOINT] ||
15217         SelectionState[FILLCONTROL_ENDPOINT])
15218     {
15219         if (GetApplication()->GetBlobManager()->GetCurrentInterest().Fill && IsVisible())
15220         {
15221             KernelBitmap* pBitmap = GetBitmap();
15222             KernelBitmap* pGreyBmp = NodeBitmap::CheckGreyscaleBitmap(pBitmap, _R(IDS_MAKEGREY), _R(IDS_DOGREY));
15223 
15224             if (pGreyBmp == NULL)
15225                 return FALSE;   // Failed in some way (or the user cancelled)
15226         }
15227     }
15228 
15229     return AttrFillGeometry::ChangeControlColour(NewCol); 
15230 #else
15231     return FALSE;
15232 #endif
15233 }
15234 
15235 
15236 
15237 /********************************************************************************************
15238 
15239   > virtual BOOL AttrBitmapColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
15240 
15241     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
15242     Created:    26/6/96
15243     Inputs:     pFilter = ptr to the filter
15244     Returns:    TRUE if record is written, FALSE if not
15245     Purpose:    Writes the bitmap fill record to the filter
15246     SeeAlso:    -
15247 
15248 ********************************************************************************************/
15249 
15250 BOOL AttrBitmapColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
15251 {
15252 #ifdef DO_EXPORT
15253     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
15254 
15255     BOOL ok = TRUE;
15256 
15257     // Find the kernel bmp
15258     KernelBitmap *pBmp = Value.GetBitmap();
15259     ERROR2IF(pBmp == NULL,FALSE,"CXaraFileNodeBitmap::WriteNodeBitmap pBmp is NULL");
15260 
15261     // Must write out the bitmap first
15262     INT32 BitmapRecordRef = pFilter->WriteRecord(pBmp);
15263     ERROR2IF(BitmapRecordRef == 0,FALSE,"CXaraFileNodeBitmap::WriteNodeBitmap BitmapRecordRef is 0");
15264 
15265     UINT32 Tag     = TAG_BITMAPFILL;
15266     UINT32 TagSize = TAG_BITMAPFILL_SIZE;
15267 
15268     // Contone?
15269     DocColour* pStartCol= Value.GetStartColour();
15270     DocColour* pEndCol  = Value.GetEndColour();
15271     INT32 StartColRef=0;
15272     INT32 EndColRef=0;
15273 
15274     if (pStartCol != NULL && pEndCol != NULL)
15275     {
15276         // It's a contone bmp if it has both a start & an end colour.
15277         StartColRef = pFilter->WriteRecord(pStartCol);
15278         EndColRef   = pFilter->WriteRecord(pEndCol);
15279 
15280         Tag     = TAG_CONTONEBITMAPFILL;
15281         TagSize = TAG_CONTONEBITMAPFILL_SIZE;
15282 
15283         // Are the colour refs ok?
15284         ok = (StartColRef != 0) && (EndColRef != 0);
15285     }
15286 
15287     // Is the bmp reference ok?
15288     if (ok) ok = (BitmapRecordRef != 0);
15289         
15290     CamelotFileRecord Rec(pFilter,Tag,TagSize);
15291 
15292     if (ok) ok = Rec.Init();
15293     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
15294     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
15295     if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
15296 
15297     if (Tag == TAG_CONTONEBITMAPFILL)
15298     {
15299         if (ok) ok = Rec.WriteReference(StartColRef);
15300         if (ok) ok = Rec.WriteReference(EndColRef);
15301     }
15302 
15303     if (ok) ok = Rec.WriteReference(BitmapRecordRef);
15304     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
15305     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
15306     if (ok) ok = pFilter->Write(&Rec);
15307 
15308     if (!ok)
15309         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
15310 
15311     return ok;
15312 #else
15313     return FALSE;
15314 #endif
15315 }
15316 
15317 //--------------------------------------------------------------
15318 // See AttrBitmapColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
15319 //
15320 BOOL AttrBitmapColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
15321 {
15322 #ifdef DO_EXPORT
15323     return WritePreChildrenWeb(pFilter);
15324 #else
15325     return FALSE;
15326 #endif
15327 }
15328 
15329 
15330 /********************************************************************************************
15331 
15332   > virtual BOOL AttrBitmapColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
15333 
15334     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
15335     Created:    14/9/2000
15336     Inputs:     pFilter = ptr to the filter
15337     Returns:    TRUE if record is written, FALSE if not
15338     Purpose:    Writes out colour definitions for this fill.
15339     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
15340                 Layer::WriteAtomicNodesColourRefs ()
15341 
15342 ********************************************************************************************/
15343 
15344 BOOL AttrBitmapColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
15345 {
15346     // Contone?
15347     DocColour* pStartCol= Value.GetStartColour();
15348     DocColour* pEndCol  = Value.GetEndColour();
15349     INT32 StartColRef, EndColRef;
15350 
15351     if (pStartCol != NULL && pEndCol != NULL)
15352     {
15353         // It's a contone bmp if it has both a start & an end colour.
15354         StartColRef = pFilter->WriteRecord(pStartCol);
15355         EndColRef   = pFilter->WriteRecord(pEndCol);
15356 
15357         // Are the colour references ok?
15358         BOOL ok = ((StartColRef != 0) && (EndColRef != 0));
15359 
15360         return (ok);
15361     }
15362     
15363     return (TRUE);
15364 }
15365 
15366 
15368 //
15369 //                              AttrBitmapTranspFill
15370 //
15372 
15373 /********************************************************************************************
15374 
15375 >   void AttrBitmapTranspFill::Render( RenderRegion* pRender)
15376 
15377     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15378     Created:    23/8/94
15379     Purpose:    'Renders' a Bitmap Fill Transp attribute.
15380 
15381 ********************************************************************************************/
15382 
15383 void AttrBitmapTranspFill::Render(RenderRegion* pRender)
15384 {
15385     pRender->SetTranspFillGeometry(&Value, FALSE);
15386 }
15387 
15388 /********************************************************************************************
15389 
15390 > Node* AttrBitmapTranspFill::SimpleCopy() 
15391 
15392     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15393     Created:    23/8/94
15394     Returns:    A copy of the node, or NULL if memory runs out 
15395     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
15396                 The function is virtual, and must be defined for all derived classes.  
15397     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
15398                 memory error and the function returns NULL. 
15399     Scope:      protected       
15400 
15401 ********************************************************************************************/
15402      
15403 Node* AttrBitmapTranspFill::SimpleCopy()
15404 {
15405     AttrBitmapTranspFill* NodeCopy = new AttrBitmapTranspFill();
15406     if (NodeCopy == NULL)
15407         return NULL;
15408 
15409     CopyNodeContents(NodeCopy);
15410     
15411     return NodeCopy;
15412 }  
15413 
15414 /********************************************************************************************
15415 
15416 >   virtual UINT32 AttrBitmapTranspFill::GetAttrNameID(void)  
15417 
15418     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15419     Created:    23/8/94
15420     Returns:    Attribute description ID
15421     Purpose:    Returns a string resource ID describing the attribute
15422 
15423 ********************************************************************************************/
15424 
15425 UINT32 AttrBitmapTranspFill::GetAttrNameID(void)  
15426 {
15427     return (_R(IDS_BITMAPTRANSPFILL)); 
15428 }                                  
15429 
15430 /********************************************************************************************
15431 
15432 >   void AttrBitmapTranspFill::GetDebugDetails(StringBase* Str)
15433 
15434     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15435     Created:    20/07/94
15436     Outputs:    Str - the string containing details of the attribute.
15437     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
15438 
15439 ********************************************************************************************/
15440 
15441 void AttrBitmapTranspFill::GetDebugDetails(StringBase* Str)
15442 {
15443 #ifdef _DEBUG
15444     NodeAttribute::GetDebugDetails( Str );
15445 
15446     String_256 TempStr;
15447 
15448     TempStr._MakeMsg( TEXT("\r\nBitmap Fill:\r\n"));
15449     (*Str) += TempStr;
15450 
15451     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
15452                      (*GetStartPoint()).x, (*GetStartPoint()).y);
15453     (*Str) += TempStr;
15454 
15455     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
15456                      (*GetEndPoint()).x, (*GetEndPoint()).y);
15457     (*Str) += TempStr;
15458 
15459     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
15460                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
15461     (*Str) += TempStr;
15462 
15463     BitmapInfo Info;
15464     KernelBitmap* KerBmp = ((BitmapTranspFillAttribute*)GetAttributeValue())->GetBitmap();
15465 
15466     if (KerBmp && KerBmp->ActualBitmap && KerBmp->ActualBitmap->GetInfo( &Info ) )
15467     {
15468         TempStr._MakeMsg( _T("\r\nBits = (#1%ux#2%ux#3%u) "), Info.PixelWidth,
15469                                         Info.PixelHeight,
15470                                         Info.PixelDepth
15471                         );
15472         (*Str) += TempStr;
15473     }
15474 #endif
15475 }
15476 
15477 /********************************************************************************************
15478 
15479 >   virtual UINT32 AttrBitmapTranspFill::GetNodeSize() const
15480 
15481     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15482     Created:    23/8/94
15483     Returns:    The size of the node in bytes
15484     Purpose:    For finding the size of the node.
15485     SeeAlso:    Node::GetSubtreeSize
15486 
15487 ********************************************************************************************/
15488 
15489 UINT32 AttrBitmapTranspFill::GetNodeSize() const 
15490 {     
15491     return sizeof(AttrBitmapTranspFill);
15492 }  
15493 
15494 /********************************************************************************************
15495 
15496 >   void AttrBitmapTranspFill::RenderFillBlobs(RenderRegion* pRender)
15497 
15498     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15499     Created:    13/9/94
15500     Inputs:     pRender - The region to render the blobs to.
15501     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
15502 
15503 ********************************************************************************************/
15504 
15505 void AttrBitmapTranspFill::RenderFillBlobs(RenderRegion* pRender)
15506 {
15507 #if !defined(EXCLUDE_FROM_RALPH)
15508     if (!IsVisible())
15509         return;     // We're Not in Fill Transparency Mode
15510 
15511     // Don't bother if this fill is being edited as a copy of it
15512     // we be rendered thoughout the drag op
15513     if (IsFillBeingEdited())
15514         return;
15515 
15516     // Ignore this if the mesh is the same as the last one rendered.
15517     if (CheckPreviousFillMesh())
15518         return;
15519 
15520     DocCoord ControlPoints[5];
15521     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
15522     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
15523     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
15524 
15525     // Render a nice pretty Fill Mesh thingy
15526     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
15527 
15528     // This call was removed by Gerry (2/9/96) as it causes blob problems
15529     // If we are removing blobs then force all blobs to be deselected
15530 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
15531 //      DeselectAllNoRedraw();
15532 #endif
15533 }
15534 
15535 void AttrBitmapTranspFill::RenderFillMesh(  RenderRegion* pRender, 
15536                                             DocCoord* ControlPoints, BOOL* SelState,
15537                                             INT32 NumControlPoints)
15538 {
15539 #if !defined(EXCLUDE_FROM_RALPH)
15540     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
15541     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
15542 
15543     if (StartPoint == EndPoint)
15544         return;
15545 
15546     if (SelState == NULL)
15547     {
15548         // If no selection state passed in, then assume
15549         // all the points are deselected
15550         BOOL Selected[NUMCONTROLPOINTS];
15551         for (INT32 i=0; i< NumControlPoints; i++)
15552         {
15553             Selected[i] = FALSE;
15554         }
15555         SelState = Selected;
15556     }
15557 
15558     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_SECONDARYPOINT];
15559 
15560     DocCoord Start;
15561     DocCoord End;
15562     DocCoord End2; 
15563 
15564     // Work out the Virtual positions of the Bitmap Controls
15565     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
15566                             &Start, &End, &End2);
15567 
15568     // Remember what attributes were here before
15569     pRender->SaveContext();
15570 
15571     // Get the current blob size in Doc Units
15572     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
15573 
15574     // Calculate the Arrow on the End of the Line
15575     Path ArrowPath;
15576     ArrowPath.Initialise();
15577     DocCoord LineEnd;
15578     MakeMeshArrow(&ArrowPath, Start, End, &LineEnd);
15579 
15580     // Calculate the Arrow on the End of the Line2
15581     Path ArrowPath2;
15582     ArrowPath2.Initialise();
15583     DocCoord LineEnd2;
15584     MakeMeshArrow(&ArrowPath2, Start, End2, &LineEnd2);
15585 
15586     // Set the line colours etc as we need them
15587     pRender->SetLineWidth(0);
15588     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
15589     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
15590 
15591     // First Draw the Line
15592     pRender->SetLineWidth(BlobSize/4);
15593     pRender->DrawLine(Start, LineEnd);
15594 
15595     // Draw the secondary line
15596     pRender->DrawLine(Start, LineEnd2);
15597 
15598     // Render an Arrow at the end of the line
15599     pRender->SetLineWidth(0);
15600     pRender->SetLineColour(COLOUR_NONE);
15601     pRender->DrawPath(&ArrowPath);
15602 
15603     // and on the end of the secondary line
15604     pRender->DrawPath(&ArrowPath2);
15605 
15606     if (DraggedFill == this)
15607     {
15608         // If we are being dragged then draw a Parallelgram to
15609         // show the shape of the bitmap
15610         pRender->SetLineColour(COLOUR_SELECTEDBLOB);
15611         pRender->SetFillColour(COLOUR_NONE);
15612     
15613         Path ParaPath;
15614         ParaPath.Initialise();
15615         MakeMeshParallelagram(&ParaPath, Start, End, End2);
15616 
15617         // Draw the parallelagram
15618         pRender->DrawPath(&ParaPath);
15619     }
15620 
15621     // Now Render the blobs on the path
15622 
15623     // Draw a blob at the start point
15624     if (SelState[FILLCONTROL_STARTPOINT])
15625     {
15626         // Draw Selected Blob
15627 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
15628         pRender->SetLineColour(COLOUR_NONE);
15629         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
15630         pRender->DrawBlob(Start, BT_SELECTED);
15631     }
15632     else
15633     {
15634         // Draw Unselected Blob
15635 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
15636         pRender->SetLineColour(COLOUR_NONE);
15637         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
15638         pRender->DrawBlob(Start, BT_UNSELECTED);
15639     }
15640 
15641     // Draw a blob at the end point
15642     if (SelState[FILLCONTROL_ENDPOINT])
15643     {
15644         // Draw Selected Blob
15645 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
15646         pRender->SetLineColour(COLOUR_NONE);
15647         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
15648         pRender->DrawBlob(End, BT_SELECTED);
15649         pRender->DrawBlob(End2,BT_SELECTED);
15650     }
15651     else
15652     {
15653         // Draw Unselected Blob
15654 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
15655         pRender->SetLineColour(COLOUR_NONE);
15656         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
15657         pRender->DrawBlob(End, BT_UNSELECTED);
15658         pRender->DrawBlob(End2,BT_UNSELECTED);
15659     }
15660 
15661     // Put all the old attributes back
15662     pRender->RestoreContext();
15663 #endif
15664 }
15665 
15666 void AttrBitmapTranspFill::RenderControl(FillControl Control, BOOL RenderOn)
15667 {
15668 #if !defined(EXCLUDE_FROM_RALPH)
15669     DocRect ControlRect;
15670 
15671     // Ignore if we're not in the tree yet
15672     // We may be a tempory clone, or something
15673     NodeRenderable* pParent = (NodeRenderable*)FindParent();
15674 
15675     if (pParent == NULL)
15676         return;
15677 
15678     if (IsBlobSame(Control))
15679         return;         // Ignore if same as the last blob rendered
15680 
15681     Spread* pSpread = this->FindParentSpread();
15682 
15683     DocCoord StartPoint = *GetStartPoint();
15684     DocCoord EndPoint = *GetEndPoint();
15685     DocCoord EndPoint2 = *GetEndPoint2();
15686 
15687     DocCoord CentrePoint;
15688     DocCoord Drag2Blob;
15689     DocCoord Drag3Blob;
15690 
15691     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
15692                             &CentrePoint, &Drag2Blob, &Drag3Blob);
15693 
15694     switch (Control)
15695     {
15696         case FILLCONTROL_STARTPOINT:
15697 
15698             if (GetStartPoint() != NULL)
15699             {
15700                 // Redraw the Start Point Blob
15701                 (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &ControlRect);
15702                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15703             }
15704             break;
15705 
15706         case FILLCONTROL_ENDPOINT:
15707 
15708             if (GetEndPoint() != NULL)
15709             {
15710                 // Redraw BOTH End Point Blobs
15711                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
15712                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15713             }
15714 
15715             if (GetEndPoint2() != NULL)
15716             {
15717                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
15718                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15719             }
15720             break;
15721 
15722         case FILLCONTROL_SECONDARYPOINT:
15723 
15724             if (GetEndPoint2() != NULL)
15725             {
15726                 // Redraw BOTH End Point Blobs
15727                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
15728                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15729             }
15730 
15731             if (GetEndPoint2() != NULL)
15732             {
15733                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
15734                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
15735             }
15736             break;
15737     }
15738 #endif
15739 }
15740 
15741 
15742 /********************************************************************************************
15743 
15744   > virtual BOOL AttrBitmapTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
15745 
15746     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
15747     Created:    26/6/96
15748     Inputs:     pFilter = ptr to the filter
15749     Returns:    TRUE if record is written, FALSE if not
15750     Purpose:    Writes the bitmap transparent fill record to the filter
15751     SeeAlso:    -
15752 
15753 ********************************************************************************************/
15754 
15755 BOOL AttrBitmapTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
15756 {
15757 #ifdef DO_EXPORT
15758     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
15759 
15760     BOOL ok = TRUE;
15761 
15762     // Find the kernel bmp
15763     KernelBitmap *pBmp = Value.GetBitmap();
15764     ERROR2IF(pBmp == NULL,FALSE,"CXaraFileNodeBitmap::WriteNodeBitmap pBmp is NULL");
15765 
15766     // Must write out the bitmap first
15767     INT32 BitmapRecordRef = pFilter->WriteRecord(pBmp);
15768     ERROR2IF(BitmapRecordRef == 0,FALSE,"CXaraFileNodeBitmap::WriteNodeBitmap BitmapRecordRef is 0");
15769 
15770     // Is the bmp reference ok?
15771     if (ok) ok = (BitmapRecordRef != 0);
15772         
15773     CamelotFileRecord Rec(pFilter,TAG_BITMAPTRANSPARENTFILL,TAG_BITMAPTRANSPARENTFILL_SIZE);
15774 
15775     if (ok) ok = Rec.Init();
15776     if (ok) ok = Rec.WriteCoord(Value.StartPoint);
15777     if (ok) ok = Rec.WriteCoord(Value.EndPoint);
15778     if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
15779     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));
15780     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));
15781     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));
15782     if (ok) ok = Rec.WriteReference(BitmapRecordRef);
15783     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
15784     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
15785     if (ok) ok = pFilter->Write(&Rec);
15786 
15787     if (!ok)
15788         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
15789 
15790     return ok;
15791 #else
15792     return FALSE;
15793 #endif
15794 }
15795 
15796 //--------------------------------------------------------------
15797 // See AttrBitmapTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
15798 //
15799 BOOL AttrBitmapTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
15800 {
15801 #ifdef DO_EXPORT
15802     return WritePreChildrenWeb(pFilter);
15803 #else
15804     return FALSE;
15805 #endif
15806 }
15807 
15808 
15809 
15810 
15811 /********************************************************************************************
15812 >   BOOL AttrBitmapTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
15813 
15814     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
15815     Created:    11/05/2005
15816     Inputs:     -
15817     Outputs:    -
15818     Returns:    TRUE if this node has a value equivalent to the relevant 
15819                 FALSE otherwise
15820     Purpose:    Determine whether this attribute has the default value or not
15821     Errors:     -
15822     SeeAlso:    -
15823 ********************************************************************************************/
15824 
15825 BOOL AttrBitmapTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
15826 {
15827     // Slight bodge - we will assume that the default transparency is fully opaque
15828     if (bAppearance)
15829         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0));
15830     else
15831         return FALSE;
15832 }
15833 
15834 
15835 
15836 
15838 //
15839 //                              AttrFractalFill
15840 //
15842 
15843 /********************************************************************************************
15844 
15845 >   void AttrFractalFill::Transform( TransformBase& Trans )
15846 
15847     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15848     Created:    23/8/94
15849     Inputs:     Trans - the transform object to apply to this attribute.
15850     Purpose:    Transform a grad fill attribute by moving the start and end points.
15851     SeeAlso:    NodeRenderable::Transform
15852 
15853 ********************************************************************************************/
15854 
15855 void AttrFractalFill::Transform( TransformBase& Trans )
15856 {
15857     if ( Trans.TransFills )
15858     {
15859         Trans.Transform( GetStartPoint(), 1);
15860         Trans.Transform( GetEndPoint(), 1);
15861         Trans.Transform( GetEndPoint2(), 1);
15862         Trans.Transform( GetEndPoint3(), 1);
15863 
15864         // Ensure the transformed Points are sensible
15865 //      ValidateAttributeValue();
15866         SetFractalDPI(GetDPI());
15867     }
15868 }
15869 
15870 /********************************************************************************************
15871 
15872 >   BOOL AttrFractalFill::CanTransform()
15873 
15874     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15875     Created:    23/8/94
15876     Returns:    TRUE => transform this attribute.
15877     Purpose:    Indicate that this attribute can be transformed.
15878     SeeAlso:    NodeRenderable::CanTransform
15879 
15880 ********************************************************************************************/
15881 
15882 BOOL AttrFractalFill::CanTransform()
15883 {
15884     return TRUE;
15885 }
15886 
15887 /********************************************************************************************
15888 
15889 >   BOOL AttrFractalFill::CopyNodeContents( AttrFractalFill* NodeCopy)
15890 
15891     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15892     Created:    23/8/94
15893     Outputs:    A copy of this node
15894     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
15895     Errors:     An assertion failure will occur if NodeCopy is NULL
15896     Scope:      protected
15897                                      
15898 ********************************************************************************************/
15899 
15900 BOOL AttrFractalFill::CopyNodeContents( AttrFractalFill* NodeCopy)
15901 {
15902     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrFractalFill::CopyNodeContents!");
15903 
15904     AttrFillGeometry::CopyNodeContents( NodeCopy );
15905 
15906     // Copy contents specific to derived class here
15907     return TRUE;
15908 } 
15909 
15910 /***********************************************************************************************
15911 
15912 >    virtual BOOL AttrFractalFill::HidingNode()
15913 
15914      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15915      Created:   9/11/94
15916      Returns:   TRUE if all was ok. FALSE if an error occured.
15917      Purpose:   This virtual function is called whenever the node is hidden.
15918                 It allows the node do things like 'optimise' itself to use less memory or
15919                 send a message to let others know it is being hidden etc.
15920 
15921                 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION.
15922 
15923 ***********************************************************************************************/
15924 
15925 BOOL AttrFractalFill::HidingNode()
15926 {
15927     // Call the base class first
15928     if (!AttrFillGeometry::HidingNode())
15929         return FALSE;
15930 
15931     ((FillGeometryAttribute*)GetAttributeValue())->DetachBitmap();
15932 
15933     return TRUE;
15934 }
15935 
15936 /***********************************************************************************************
15937 
15938 >    virtual BOOL AttrFractalFill::ShowingNode()
15939 
15940      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15941      Created:   9/11/94
15942      Returns:   TRUE if all was ok. FALSE if an error occured (eg Out of memory).
15943      Purpose:   This virtual function is called whenever the node is re-shown after being 
15944                 Hidden.
15945                 It allows the node to reconstruct itself if it was optimised or
15946                 send a message to let others know it is back etc.
15947 
15948                 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION.
15949 
15950 ***********************************************************************************************/
15951 
15952 BOOL AttrFractalFill::ShowingNode()
15953 {
15954     // Call the base class first
15955     if (!AttrFillGeometry::ShowingNode())
15956         return FALSE;
15957 
15958     RecalcFractal();
15959 
15960     return TRUE;
15961 }
15962 
15963 /********************************************************************************************
15964 
15965 >   void AttrFractalFill::ValidateAttributeValue()
15966 
15967     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
15968     Created:    11/8/94
15969     Purpose:    Makes sure the Coords of the Fill are sensible. Defaults to natural size
15970                 of the bitmap
15971 
15972 ********************************************************************************************/
15973 
15974 void AttrFractalFill::ValidateAttributeValue()
15975 {
15976 #if !defined(EXCLUDE_FROM_RALPH)
15977     if ((*GetStartPoint()) != DocCoord(0,0) && (*GetEndPoint()) != DocCoord(0,0) &&
15978         (*GetEndPoint2()) != DocCoord(0,0))
15979         return;
15980 
15981     // Make some defaults
15982     DocRect AttrBounds = DocRect(0,0,0,0);
15983 
15984     INT32 Width  = DEFAULT_FILLWIDTH;
15985     INT32 Height = DEFAULT_FILLHEIGHT;
15986 
15987     // Are we an Orphan ?
15988     if (FindParent() != NULL)
15989     {
15990         // Nope, so we can use Daddies Bounding Box
15991         SelRange* Selected = GetApplication()->FindSelection();
15992                  
15993         if (Selected == NULL || Selected->Count() <= 1)
15994             AttrBounds = ((NodeRenderableBounded*)FindParent())->GetBoundingRect(TRUE);
15995         else
15996             AttrBounds = Selected->GetBoundingRect();
15997 
15998         Width  = AttrBounds.Width();
15999         Height = Width;
16000     }
16001 
16002     // Find the middle of the Attributes Bounds
16003     DocCoord Centre = CentreOf(AttrBounds);
16004 
16005     // Get the current control positions
16006     DocCoord StartPoint = *GetStartPoint();
16007     DocCoord EndPoint = *GetEndPoint();
16008     DocCoord EndPoint2 = *GetEndPoint2();
16009 
16010     BOOL recalc = FALSE;
16011 
16012     // If the StartPoint is 'NULL' then make all points sensible
16013     if (StartPoint == DocCoord(0,0))
16014     {
16015         // Start in the middle
16016         StartPoint = DocCoord(Centre.x - Width/2, Centre.y - Height/2);
16017         // End on the Middle Right
16018         EndPoint = DocCoord(StartPoint.x + Width, StartPoint.y);
16019         // and Middle Top
16020         EndPoint2 = DocCoord(StartPoint.x, StartPoint.y + Height);
16021 
16022         recalc = TRUE;
16023     }
16024 
16025     // If the EndPoint is 'NULL' then make end points sensible
16026     if (EndPoint == DocCoord(0,0))
16027     {
16028         EndPoint = DocCoord(StartPoint.x + Width, StartPoint.y);
16029         EndPoint2 = DocCoord(StartPoint.x, StartPoint.y + Height);
16030 
16031         recalc = TRUE;
16032     }
16033 
16034     // If the EndPoint2 is 'NULL' then make it sensible
16035     if (EndPoint2 == DocCoord(0,0))
16036     {
16037         EndPoint2 = DocCoord(StartPoint.x, StartPoint.y + Height);
16038 
16039         recalc = TRUE;
16040     }
16041 
16042     // Store the validated positions back
16043     SetStartPoint(&StartPoint);
16044     SetEndPoint(&EndPoint);
16045     SetEndPoint2(&EndPoint2);
16046 
16047     if (recalc)
16048         ((FillGeometryAttribute*)GetAttributeValue())->RecalcFractal();
16049 #endif
16050 }
16051 
16052 /********************************************************************************************
16053 
16054 >   virtual NodeAttribute* AttrFractalFill::GetOtherAttrToApply(BOOL* IsMutate)
16055 
16056     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16057     Created:    17/8/95
16058     Returns:    The secondary attribute to apply, or NULL if none to apply
16059     Purpose:    Some attributes require a secondary atribute to be changed when they are
16060                 changed.  This routine obtains a pointer to the secondary attribute to
16061                 apply.
16062 
16063 ********************************************************************************************/
16064 
16065 NodeAttribute* AttrFractalFill::GetOtherAttrToApply(BOOL* IsMutate)
16066 {
16067 #if !defined(EXCLUDE_FROM_RALPH)
16068     ERROR3IF(IsMutate == NULL, "NULL flag pointer passed to GetOtherAttrToApply");
16069 
16070     // A Fractal fill change also needs to set the Fill Mapping
16071 
16072     NodeAttribute* OtherAttr = NULL;
16073 
16074     BOOL Tileable = GetTileable();
16075 
16076     if (GetAttributeType() == CC_RUNTIME_CLASS(AttrFillGeometry))
16077     {
16078         OtherAttr = new AttrFillMappingLinear;
16079     }
16080     else
16081     {
16082         OtherAttr = new AttrTranspFillMappingLinear;
16083     }
16084 
16085     if (OtherAttr == NULL)
16086         return NULL;
16087 
16088     if (Tileable)
16089         ((AttrFillMappingLinear*)OtherAttr)->SetRepeat(RT_Repeating);
16090     else
16091         ((AttrFillMappingLinear*)OtherAttr)->SetRepeat(RT_RepeatInverted);
16092 
16093     *IsMutate = FALSE;
16094 
16095     return OtherAttr;
16096 #else
16097     return NULL;
16098 #endif
16099 }
16100 
16101 void AttrFractalFill::SetAspectRatio(double Ratio)
16102 {
16103 #if !defined(EXCLUDE_FROM_RALPH)
16104     // Get the current Control Point Positions
16105     DocCoord StartPoint = *GetStartPoint();
16106     DocCoord EndPoint = *GetEndPoint();
16107     DocCoord EndPoint2 = *GetEndPoint2();
16108 
16109     DocCoord CentrePoint;
16110     DocCoord Drag2Blob;
16111     DocCoord Drag3Blob;
16112 
16113     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
16114                             &CentrePoint, &Drag2Blob, &Drag3Blob);
16115 
16116     Drag3Blob = MakeLineAtAngle(CentrePoint, 
16117                                 Drag2Blob, 
16118                                 90, 
16119                                 INT32(CentrePoint.Distance(Drag2Blob) * Ratio)
16120                                 );
16121 
16122     GetBitmapRealPoints(CentrePoint, Drag2Blob, Drag3Blob,
16123                             &StartPoint, &EndPoint, &EndPoint2);
16124 
16125     // Store the new points back in the Fill
16126     SetStartPoint(&StartPoint);
16127     SetEndPoint(&EndPoint);
16128     SetEndPoint2(&EndPoint2);
16129 #endif
16130 }
16131 
16132 
16133 
16135 //
16136 //                              AttrTextureColourFill
16137 //
16139 
16140 /********************************************************************************************
16141 
16142 >   AttrTextureColourFill::AttrTextureColourFill()
16143 
16144     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
16145     Created:    16/9/94
16146     Purpose:    Constructor for a texture fill.
16147 
16148 ********************************************************************************************/
16149 
16150 AttrTextureColourFill::AttrTextureColourFill()
16151 {
16152 }
16153 
16154 /********************************************************************************************
16155 
16156 >   AttrTextureColourFill::~AttrTextureColourFill()
16157 
16158     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
16159     Created:    16/9/94
16160     Purpose:    Destructor for a texture fill.
16161 
16162 ********************************************************************************************/
16163 
16164 AttrTextureColourFill::~AttrTextureColourFill()
16165 {
16166 }
16167 
16168 
16169 
16170 /********************************************************************************************
16171 
16172 > Node* AttrTextureColourFill::SimpleCopy() 
16173 
16174     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16175     Created:    23/8/94
16176     Returns:    A copy of the node, or NULL if memory runs out 
16177     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
16178                 The function is virtual, and must be defined for all derived classes.  
16179     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
16180                 memory error and the function returns NULL. 
16181     Scope:      protected       
16182 
16183 ********************************************************************************************/
16184      
16185 Node* AttrTextureColourFill::SimpleCopy()
16186 {
16187     TRACEUSER( "Mike", _T("AttrTextureColourFill::SimpleCopy() called. This should NOT happen."));
16188 
16189     AttrTextureColourFill* NodeCopy = new AttrTextureColourFill();
16190     if (NodeCopy == NULL)
16191         return NULL;
16192 
16193     CopyNodeContents(NodeCopy);
16194     
16195     return NodeCopy;
16196 }  
16197 
16198 
16199 /********************************************************************************************
16200 
16201 >   virtual UINT32 AttrTextureColourFill::GetAttrNameID(void)  
16202 
16203     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16204     Created:    23/8/94
16205     Returns:    Attribute description ID
16206     Purpose:    Returns a string resource ID describing the attribute
16207 
16208 ********************************************************************************************/
16209 
16210 UINT32 AttrTextureColourFill::GetAttrNameID (void)
16211 {   
16212     return (_R(IDS_BITMAPFILL));
16213 }
16214 
16215 // I can't be bothered to enter any comments for these ....
16216 
16217 UINT32 AttrFractalColourFill::GetAttrNameID (void)
16218 {
16219     return (_R(IDS_FRACTALCLOUDSGRADFILL));
16220 }
16221 
16222 UINT32 AttrNoiseColourFill::GetAttrNameID (void)
16223 {
16224     return (_R(IDS_FRACTALPLASMAGRADFILL));
16225 }
16226 
16227 
16228 
16229 /********************************************************************************************
16230 
16231 >   void AttrTextureColourFill::GetDebugDetails(StringBase* Str)
16232 
16233     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
16234     Created:    20/07/94
16235     Outputs:    Str - the string containing details of the attribute.
16236     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
16237 
16238 ********************************************************************************************/
16239 
16240 void AttrTextureColourFill::GetDebugDetails(StringBase* Str)
16241 {
16242 #ifdef _DEBUG
16243     NodeAttribute::GetDebugDetails( Str );
16244 
16245     String_256 TempStr;
16246 
16247     TempStr._MakeMsg( TEXT("\r\nTexture Fill:\r\n"));
16248     (*Str) += TempStr;
16249 
16250 //  TempStr._MakeMsg(TEXT("\r\nStart"));
16251 //  (*GetStartColour()).GetDebugDetails(&TempStr);
16252 //  (*Str) += TempStr;
16253 
16254 //  TempStr._MakeMsg(TEXT("\r\nEnd"));
16255 //  (*GetEndColour()).GetDebugDetails(&TempStr);
16256 //  (*Str) += TempStr;
16257 
16258     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
16259                      (*GetStartPoint()).x, (*GetStartPoint()).y);
16260     (*Str) += TempStr;
16261 
16262     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
16263                      (*GetEndPoint()).x, (*GetEndPoint()).y);
16264     (*Str) += TempStr;
16265 
16266     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) \n"), 
16267                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
16268     (*Str) += TempStr;
16269 
16270 #endif
16271 }
16272 
16273 
16274 /********************************************************************************************
16275 
16276 >   void AttrTextureColourFill::Render( RenderRegion* pRender)
16277 
16278     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16279     Created:    23/8/94
16280     Purpose:    'Renders' a Fractal Fill colour attribute.
16281 
16282 ********************************************************************************************/
16283 
16284 void AttrTextureColourFill::Render(RenderRegion* pRender)
16285 {
16286     if (GetBitmap() == NULL || GetBitmap()->ActualBitmap == NULL)
16287     {
16288         if (!RecalcFractal())
16289             return;
16290     }
16291 
16292     pRender->SetFillGeometry((ColourFillAttribute*)GetAttributeValue(), FALSE);
16293 }
16294 
16295 
16296 
16297 /********************************************************************************************
16298 
16299 >   void AttrTextureColourFill::RenderFillBlobs(RenderRegion* pRender)
16300 
16301     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16302     Created:    13/9/94
16303     Inputs:     pRender - The region to render the blobs to.
16304     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
16305 
16306 ********************************************************************************************/
16307 
16308 void AttrTextureColourFill::RenderFillBlobs(RenderRegion* pRender)
16309 {
16310 #if !defined(EXCLUDE_FROM_RALPH)
16311     if (!IsVisible())
16312         return;     // We're Not in Fill Transparency Mode
16313 
16314     // Don't bother if this fill is being edited as a copy of it
16315     // we be rendered thoughout the drag op
16316     if (IsFillBeingEdited())
16317         return;
16318 
16319     // Ignore this if the mesh is the same as the last one rendered.
16320     if (CheckPreviousFillMesh())
16321         return;
16322 
16323     DocCoord ControlPoints[5];
16324     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
16325     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
16326     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
16327 
16328     // Render a nice pretty Fill Mesh thingy
16329     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
16330 
16331     // This call was removed by Gerry (2/9/96) as it causes blob problems
16332     // If we are removing blobs then force all blobs to be deselected
16333 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
16334 //      DeselectAllNoRedraw();
16335 #endif
16336 }
16337 
16338 
16339 
16340 /********************************************************************************************
16341 
16342 >   FillControl AttrTextureColourFill::CheckForControlHit(DocCoord &ClickPos)
16343 
16344     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16345     Created:    21/07/94
16346     Inputs:     ClickPos, The DocCoord position to check.
16347     Returns:    A FillControl, indicating the Fill Control Point Hit,
16348                 or FILLCONTROL_NULL, if no points hit.
16349     Purpose:    Check to see if a click was on a Fill Control Point. 
16350     SeeAlso:    FillControl
16351 
16352 ********************************************************************************************/
16353 
16354 FillControl AttrTextureColourFill::CheckForControlHit(DocCoord &ClickPos)
16355 {
16356 #if !defined(EXCLUDE_FROM_RALPH)
16357     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
16358         return FILLCONTROL_NULL;
16359 
16360     // Set up a default, that indicates not control points hit
16361     FillControl HitControl = FILLCONTROL_NULL;
16362     DocRect BlobRect;
16363 
16364     DocCoord StartPoint  = *GetStartPoint();
16365     DocCoord EndPoint    = *GetEndPoint();
16366     DocCoord EndPoint2   = *GetEndPoint2();
16367 
16368     // Bodge Alert !!
16369     
16370     // Bitmap fills have a complicated control point system.
16371     // The actual control points needed for rendering are the Bottom Left,
16372     // Top Left, and Bottom Right points of the bitmap.  But on screen the 
16373     // points seen and moved are the Centre, Middle Right, and Middle Top.
16374     // So we need to convert the click points into vitual points before
16375     // we do the hit test.
16376 
16377     DocCoord CentrePoint;
16378     DocCoord Drag2Blob;
16379     DocCoord Drag3Blob;
16380 
16381     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
16382                             &CentrePoint, &Drag2Blob, &Drag3Blob);
16383 
16384     // Get the rectangle around the Centre Control Point
16385     (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &BlobRect);
16386     // See if the Click Position is within the rectangle
16387     if ( BlobRect.ContainsCoord(ClickPos) )
16388         HitControl = FILLCONTROL_STARTPOINT;
16389 
16390     // Get the rectangle around the First End Point
16391     (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &BlobRect);
16392     // See if the Click Position is within the rectangle
16393     if ( BlobRect.ContainsCoord(ClickPos) )
16394         HitControl = FILLCONTROL_ENDPOINT;
16395 
16396     // Get the rectangle around the Second End Point
16397     (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &BlobRect);
16398     // See if the Click Position is within the rectangle
16399     if ( BlobRect.ContainsCoord(ClickPos) )
16400         HitControl = FILLCONTROL_SECONDARYPOINT;
16401 
16402     return HitControl;
16403 #else
16404     return FILLCONTROL_NULL;
16405 #endif
16406 }
16407 
16408 
16409 /********************************************************************************************
16410 
16411 >   virtual void AttrTextureColourFill::OnControlDrag( DocCoord Pos, FillControl DragControl, 
16412                                                     ClickModifiers ClickMods)
16413     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16414     Created:    2/8/94
16415     Inputs:     Pos - The Location of the mouse pointer at the time of the call
16416                 DragControl - The FillControl that is being dragged.
16417                 ClickMods - The modifiers to the click (eg shift, control etc )
16418     Purpose:    Called when an edit operation is dragging a fill control point.
16419 
16420 ********************************************************************************************/
16421 
16422 void AttrTextureColourFill::OnControlDrag( DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
16423 {
16424 #if !defined(EXCLUDE_FROM_RALPH)
16425     // Get the current Control Point Positions
16426     DocCoord StartPoint = *GetStartPoint();
16427     DocCoord EndPoint = *GetEndPoint();
16428     DocCoord EndPoint2 = *GetEndPoint2();
16429 
16430     DocCoord CentrePoint;
16431     DocCoord Drag2Blob;
16432     DocCoord Drag3Blob;
16433 
16434     // Bodge Alert !!
16435     
16436     // Bitmap fills have a complicated control point system.
16437     // The actual control points needed for rendering are the Bottom Left,
16438     // Top Left, and Bottom Right points of the bitmap.  But on screen the 
16439     // points seen and moved are the Centre, Middle Right, and Middle Top.
16440     // So we need to convert the click points into vitual points before
16441     // we start dragging them about.
16442 
16443     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
16444                             &CentrePoint, &Drag2Blob, &Drag3Blob);
16445 
16446     INT32 dx, dy;
16447 
16448     // Which control is being dragged ?
16449     switch (DragControl)
16450     {
16451         case FILLCONTROL_STARTPOINT:
16452 
16453             // They're dragging the Centre Point
16454             dx = CentrePoint.x - Pos.x;
16455             dy = CentrePoint.y - Pos.y;
16456             // Move the other points relative
16457             Drag2Blob.translate(-dx, -dy);
16458             Drag3Blob.translate(-dx, -dy);
16459             CentrePoint = Pos;
16460             break;
16461 
16462         case FILLCONTROL_ENDPOINT:
16463 
16464             // If the Constrain key is down then constrain the Angle of the
16465             // point, relative to the centre position.
16466             if (ClickMods.Constrain)
16467                 DocView::ConstrainToAngle(CentrePoint, &Pos);
16468 
16469             if (ClickMods.Adjust)
16470             {
16471                 // Shift is pressed, so lock the aspect ratio of the bitmap mesh
16472                 double OldLen = CentrePoint.Distance(Drag2Blob);
16473                 double NewLen = CentrePoint.Distance(Pos);
16474                 double Ratio = 1.0;
16475 
16476                 if (OldLen == 0)
16477                     Ratio = 0;
16478                 else
16479                     Ratio = NewLen/OldLen;
16480 
16481                 // Calculate the new point based on the aspect ratio
16482                 Drag3Blob = 
16483                         MakeLineAtAngle(CentrePoint, Pos, 90, INT32(CentrePoint.Distance(Drag3Blob) * Ratio));
16484             }
16485 
16486             Drag2Blob   = Pos;
16487             break;
16488 
16489         case FILLCONTROL_SECONDARYPOINT:
16490 
16491             // If the Constrain key is down then constrain the Angle of the
16492             // point, relative to the centre position.
16493             if (ClickMods.Constrain)
16494                 DocView::ConstrainToAngle(CentrePoint, &Pos);
16495 
16496             if (ClickMods.Adjust)
16497             {
16498                 // Shift is pressed, so lock the aspect ratio of the bitmap mesh
16499                 double OldLen = CentrePoint.Distance(Drag3Blob);
16500                 double NewLen = CentrePoint.Distance(Pos);
16501                 double Ratio = 1.0;
16502 
16503                 if (OldLen == 0)
16504                     Ratio = 0;
16505                 else
16506                     Ratio = NewLen/OldLen;
16507 
16508                 // Calculate the new point based on the aspect ratio
16509                 Drag2Blob = 
16510                         MakeLineAtAngle(CentrePoint, Pos, -90, INT32(CentrePoint.Distance(Drag2Blob) * Ratio));
16511             }
16512 
16513             Drag3Blob  = Pos;
16514             break;
16515     }
16516 
16517     // Now we have to convert the Vitual Coords back into real
16518     // bitmap control points.
16519 
16520     GetBitmapRealPoints(CentrePoint, Drag2Blob, Drag3Blob,
16521                             &StartPoint, &EndPoint, &EndPoint2);
16522 
16523     // Store the new points back in the Fill
16524     SetStartPoint(&StartPoint);
16525     SetEndPoint(&EndPoint);
16526     SetEndPoint2(&EndPoint2);
16527 #endif
16528 }
16529 
16530 
16531 /********************************************************************************************
16532 
16533 >   void AttrTextureColourFill::RenderControl(FillControl Control, BOOL RenderOn)
16534 
16535     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16536     Created:    26/7/94
16537     Inputs:     Control, the FillControl to redraw
16538     Purpose:    Redraws the Fill Control blobs when the selection changes.
16539     SeeAlso:    FillControl         
16540 
16541 ********************************************************************************************/
16542 
16543 void AttrTextureColourFill::RenderControl(FillControl Control, BOOL RenderOn)
16544 {
16545 #if !defined(EXCLUDE_FROM_RALPH)
16546     DocRect ControlRect;
16547 
16548     // Ignore if we're not in the tree yet
16549     // We may be a tempory clone, or something
16550     NodeRenderable* pParent = (NodeRenderable*)FindParent();
16551 
16552     if (pParent == NULL)
16553         return;
16554 
16555     if (IsBlobSame(Control))
16556         return;         // Ignore if same as the last blob rendered
16557 
16558     Spread* pSpread = this->FindParentSpread();
16559 
16560     DocCoord StartPoint = *GetStartPoint();
16561     DocCoord EndPoint = *GetEndPoint();
16562     DocCoord EndPoint2 = *GetEndPoint2();
16563 
16564     DocCoord CentrePoint;
16565     DocCoord Drag2Blob;
16566     DocCoord Drag3Blob;
16567 
16568     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
16569                             &CentrePoint, &Drag2Blob, &Drag3Blob);
16570 
16571     switch (Control)
16572     {
16573         case FILLCONTROL_STARTPOINT:
16574 
16575             if (GetStartPoint() != NULL)
16576             {
16577                 // Redraw the Start Point Blob
16578                 (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &ControlRect);
16579                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
16580             }
16581             break;
16582 
16583         case FILLCONTROL_ENDPOINT:
16584 
16585             if (GetEndPoint() != NULL)
16586             {
16587                 // Redraw BOTH End Point Blobs
16588                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
16589                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
16590             }
16591 
16592             if (GetEndPoint2() != NULL)
16593             {
16594                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
16595                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
16596             }
16597             break;
16598 
16599         case FILLCONTROL_SECONDARYPOINT:
16600 
16601             if (GetEndPoint2() != NULL)
16602             {
16603                 // Redraw BOTH End Point Blobs
16604                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
16605                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
16606             }
16607 
16608             if (GetEndPoint2() != NULL)
16609             {
16610                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
16611                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
16612             }
16613             break;
16614     }
16615 #endif
16616 }
16617 
16618 
16619 
16620 /********************************************************************************************
16621 
16622 >   void AttrTextureColourFill::RenderFillMesh(RenderRegion* pRender, 
16623                                     DocCoord* ControlPoints, BOOL* SelState,
16624                                     INT32 NumControlPoints)
16625     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16626     Created:    24/7/94
16627     Inputs:     pRender - The region to render the blobs to.
16628                 ControlPoints - The positions of all the control points
16629                 SelState - The selection state of the control points
16630                 NumControlPoints - The Number of control points.
16631     Purpose:    Renders the grad fills mesh during a drag op.
16632                 Don't call this, call RenderFillBlobs().
16633     SeeAlso:    AttrBitmapFill::RenderFillBlobs
16634 
16635 ********************************************************************************************/
16636 
16637 void AttrTextureColourFill::RenderFillMesh(RenderRegion* pRender, 
16638                                             DocCoord* ControlPoints, BOOL* SelState,
16639                                             INT32 NumControlPoints)
16640 {
16641 #if !defined(EXCLUDE_FROM_RALPH)
16642     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
16643     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
16644 
16645     if (StartPoint == EndPoint)
16646         return;
16647 
16648     if (SelState == NULL)
16649     {
16650         // If no selection state passed in, then assume
16651         // all the points are deselected
16652         BOOL Selected[NUMCONTROLPOINTS];
16653         for (INT32 i=0; i< NumControlPoints; i++)
16654         {
16655             Selected[i] = FALSE;
16656         }
16657         SelState = Selected;
16658     }
16659 
16660     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_SECONDARYPOINT];
16661 
16662     DocCoord Start;
16663     DocCoord End;
16664     DocCoord End2; 
16665 
16666     // Work out the Virtual positions of the Bitmap Controls
16667     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
16668                             &Start, &End, &End2);
16669 
16670     // Remember what attributes were here before
16671     pRender->SaveContext();
16672 
16673     // Get the current blob size in Doc Units
16674     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
16675 
16676     // Calculate the Arrow on the End of the Line
16677     Path ArrowPath;
16678     ArrowPath.Initialise();
16679     DocCoord LineEnd;
16680     MakeMeshArrow(&ArrowPath, Start, End, &LineEnd);
16681 
16682     // Calculate the Arrow on the End of the Line2
16683     Path ArrowPath2;
16684     ArrowPath2.Initialise();
16685     DocCoord LineEnd2;
16686     MakeMeshArrow(&ArrowPath2, Start, End2, &LineEnd2);
16687 
16688     // Set the line colours etc as we need them
16689     pRender->SetLineWidth(0);
16690     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
16691     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
16692 
16693     // First Draw the Line
16694     pRender->SetLineWidth(BlobSize/4);
16695     pRender->DrawLine(Start, LineEnd);
16696 
16697     // Draw the secondary line
16698     pRender->DrawLine(Start, LineEnd2);
16699 
16700     // Render an Arrow at the end of the line
16701     pRender->SetLineWidth(0);
16702     pRender->SetLineColour(COLOUR_NONE);
16703     pRender->DrawPath(&ArrowPath);
16704 
16705     // and on the end of the secondary line
16706     pRender->DrawPath(&ArrowPath2);
16707 
16708     if (DraggedFill == this)
16709     {
16710         // If we are being dragged then draw a Parallelgram to
16711         // show the shape of the bitmap
16712         pRender->SetLineColour(COLOUR_SELECTEDBLOB);
16713         pRender->SetFillColour(COLOUR_NONE);
16714     
16715         Path ParaPath;
16716         ParaPath.Initialise();
16717         MakeMeshParallelagram(&ParaPath, Start, End, End2);
16718 
16719         // Draw the parallelagram
16720         pRender->DrawPath(&ParaPath);
16721     }
16722 
16723     // Now Render the blobs on the path
16724 
16725     // Draw a blob at the start point
16726     if (SelState[FILLCONTROL_STARTPOINT])
16727     {
16728         // Draw Selected Blob
16729 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
16730         pRender->SetLineColour(COLOUR_NONE);
16731         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
16732         pRender->DrawBlob(Start, BT_SELECTED);
16733     }
16734     else
16735     {
16736         // Draw Unselected Blob
16737 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
16738         pRender->SetLineColour(COLOUR_NONE);
16739         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
16740         pRender->DrawBlob(Start, BT_UNSELECTED);
16741     }
16742 
16743     // Draw a blob at the end point
16744     if (SelState[FILLCONTROL_ENDPOINT])
16745     {
16746         // Draw Selected Blob
16747 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
16748         pRender->SetLineColour(COLOUR_NONE);
16749         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
16750         pRender->DrawBlob(End, BT_SELECTED);
16751         pRender->DrawBlob(End2,BT_SELECTED);
16752     }
16753     else
16754     {
16755         // Draw Unselected Blob
16756 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
16757         pRender->SetLineColour(COLOUR_NONE);
16758         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
16759         pRender->DrawBlob(End, BT_UNSELECTED);
16760         pRender->DrawBlob(End2,BT_UNSELECTED);
16761     }
16762 
16763     // Put all the old attributes back
16764     pRender->RestoreContext();
16765 #endif
16766 }
16767 
16768 
16769 
16770 
16771 
16772 
16773 
16774 
16775 
16776 
16777 
16778 
16779 
16780 
16781 
16782 
16783 
16785 //
16786 //                              AttrFractalColourFill
16787 //
16789 
16790 
16791 /********************************************************************************************
16792 
16793 >   AttrFractalColourFill::AttrFractalColourFill()
16794 
16795     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16796     Created:    16/9/94
16797     Purpose:    Constructor for a fractal fill.
16798 
16799 ********************************************************************************************/
16800 
16801 AttrFractalColourFill::AttrFractalColourFill()
16802 {
16803     SetFractalDPI(AttrFillGeometry::FractalDPI);
16804 }
16805 
16806 /********************************************************************************************
16807 
16808 >   AttrFractalColourFill::~AttrFractalColourFill()
16809 
16810     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16811     Created:    16/9/94
16812     Purpose:    Destructor for a fractal fill.
16813 
16814 ********************************************************************************************/
16815 
16816 AttrFractalColourFill::~AttrFractalColourFill()
16817 {
16818 }
16819 
16820 
16821 
16822 /********************************************************************************************
16823 
16824 >   void AttrFractalColourFill::GetDebugDetails(StringBase* Str)
16825 
16826     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16827     Created:    20/07/94
16828     Outputs:    Str - the string containing details of the attribute.
16829     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
16830 
16831 ********************************************************************************************/
16832 
16833 void AttrFractalColourFill::GetDebugDetails(StringBase* Str)
16834 {
16835 #ifdef _DEBUG
16836     AttrTextureColourFill::GetDebugDetails( Str );
16837 
16838     String_256 TempStr;
16839 
16840     TempStr._MakeMsg( TEXT("\r\nFractal Fill:\r\n"));
16841     (*Str) += TempStr;
16842 
16843     INT32 Seed          = ((FractalFillAttribute*)GetAttributeValue())->Seed;
16844 //  double Gravity      = ((FractalFillAttribute*)GetAttributeValue())->Gravity.MakeDouble();
16845 //  double Graininess   = ((FractalFillAttribute*)GetAttributeValue())->Graininess.MakeDouble();
16846 //  double Squash       = ((FractalFillAttribute*)GetAttributeValue())->Squash.MakeDouble();
16847 
16848     TempStr._MakeMsg(TEXT("\r\n\nSeed = #1%ld "), 
16849                      (Seed));
16850     (*Str) += TempStr;
16851 #endif
16852 }
16853 
16854 
16855 /********************************************************************************************
16856 
16857 >   virtual UINT32 AttrFractalColourFill::GetNodeSize() const
16858 
16859     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16860     Created:    23/8/94
16861     Returns:    The size of the node in bytes
16862     Purpose:    For finding the size of the node.
16863     SeeAlso:    Node::GetSubtreeSize
16864 
16865 ********************************************************************************************/
16866 
16867 UINT32 AttrFractalColourFill::GetNodeSize() const 
16868 {     
16869     return sizeof(AttrFractalColourFill);
16870 }  
16871 
16872 
16873 /********************************************************************************************
16874 
16875 >   Node* AttrFractalColourFill::SimpleCopy() 
16876 
16877     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
16878     Created:    23/8/94
16879     Returns:    A copy of the node, or NULL if memory runs out 
16880     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
16881                 The function is virtual, and must be defined for all derived classes.  
16882     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
16883                 memory error and the function returns NULL. 
16884     Scope:      protected       
16885 
16886 ********************************************************************************************/
16887      
16888 Node* AttrFractalColourFill::SimpleCopy()
16889 {
16890     AttrFractalColourFill* NodeCopy = new AttrFractalColourFill();
16891     if (NodeCopy == NULL)
16892         return NULL;
16893 
16894     CopyNodeContents(NodeCopy);
16895     
16896     return NodeCopy;
16897 }  
16898 
16899 
16900 /********************************************************************************************
16901 
16902   > virtual BOOL AttrFractalColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
16903 
16904     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
16905     Created:    26/6/96
16906     Inputs:     pFilter = ptr to the filter
16907     Returns:    TRUE if record is written, FALSE if not
16908     Purpose:    Writes the fractal fill record to the filter
16909     SeeAlso:    -
16910 
16911 ********************************************************************************************/
16912 
16913 BOOL AttrFractalColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
16914 {
16915 #ifdef DO_EXPORT
16916     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
16917 
16918     BOOL ok = TRUE;
16919 
16920     // Make sure the start & end colours are written out first.
16921     INT32 StartColRef = pFilter->WriteRecord(Value.GetStartColour());
16922     INT32 EndColRef   = pFilter->WriteRecord(Value.GetEndColour());
16923 
16924     // Are the colour refs ok?
16925     ok = (StartColRef != 0) && (EndColRef != 0);
16926 
16927     if (ok)
16928     {
16929         CamelotFileRecord Rec(pFilter,TAG_FRACTALFILL,TAG_FRACTALFILL_SIZE);
16930 
16931         if (ok) ok = Rec.Init();
16932         if (ok) ok = Rec.WriteCoord(Value.StartPoint);
16933         if (ok) ok = Rec.WriteCoord(Value.EndPoint);
16934         if (ok) ok = Rec.WriteCoord(Value.EndPoint2);
16935         if (ok) ok = Rec.WriteReference(StartColRef);
16936         if (ok) ok = Rec.WriteReference(EndColRef);
16937 
16938         if (ok) ok = Rec.WriteINT32(Value.Seed);
16939         if (ok) ok = Rec.WriteFIXED16(Value.Graininess);
16940         if (ok) ok = Rec.WriteFIXED16(Value.Gravity);
16941         if (ok) ok = Rec.WriteFIXED16(Value.Squash);
16942         if (ok) ok = Rec.WriteINT32(Value.Dpi);
16943         if (ok) ok = Rec.WriteBYTE(Value.Tileable);
16944         if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
16945         if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
16946 
16947         if (ok) ok = pFilter->Write(&Rec);
16948     }
16949 
16950     if (!ok)
16951         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
16952 
16953     return ok;
16954 #else
16955     return FALSE;
16956 #endif
16957 }
16958 
16959 //--------------------------------------------------------------
16960 // See AttrFractalColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
16961 //
16962 BOOL AttrFractalColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
16963 {
16964 #ifdef DO_EXPORT
16965     return WritePreChildrenWeb(pFilter);
16966 #else
16967     return FALSE;
16968 #endif
16969 }
16970 
16971 
16972 /********************************************************************************************
16973 
16974   > virtual BOOL AttrFractalColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
16975 
16976     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
16977     Created:    14/9/2000
16978     Inputs:     pFilter = ptr to the filter
16979     Returns:    TRUE if record is written, FALSE if not
16980     Purpose:    Writes out colour definitions for this fill.
16981     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
16982                 Layer::WriteAtomicNodesColourRefs ()
16983 
16984 ********************************************************************************************/
16985 
16986 BOOL AttrFractalColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
16987 {
16988     // Make sure the start & end colours are written out first.
16989     INT32 StartColRef = pFilter->WriteRecord(Value.GetStartColour());
16990     INT32 EndColRef   = pFilter->WriteRecord(Value.GetEndColour());
16991 
16992     // Are the colour refs ok?
16993     BOOL ok = (StartColRef != 0) && (EndColRef != 0);
16994     
16995     return (ok);
16996 }
16997 
16998 
16999 
17000 
17001 
17002 
17003 
17004 
17006 //
17007 //                              AttrNoiseColourFill
17008 //
17010 
17011 /********************************************************************************************
17012 
17013 >   AttrNoiseColourFill::AttrNoiseColourFill()
17014 
17015     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
17016     Created:    16/01/97
17017     Purpose:    Constructor for a texture fill.
17018 
17019 ********************************************************************************************/
17020 
17021 AttrNoiseColourFill::AttrNoiseColourFill()
17022 {
17023 }
17024 
17025 /********************************************************************************************
17026 
17027 >   AttrNoiseColourFill::~AttrNoiseColourFill()
17028 
17029     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
17030     Created:    16/01/97
17031     Purpose:    Destructor for a texture fill.
17032 
17033 ********************************************************************************************/
17034 
17035 AttrNoiseColourFill::~AttrNoiseColourFill()
17036 {
17037 }
17038 
17039 
17040 /********************************************************************************************
17041 
17042 >   void AttrNoiseColourFill::GetDebugDetails(StringBase* Str)
17043 
17044     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
17045     Created:    16/01/97
17046     Outputs:    Str - the string containing details of the attribute.
17047     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
17048 
17049 ********************************************************************************************/
17050 
17051 void AttrNoiseColourFill::GetDebugDetails(StringBase* Str)
17052 {
17053 #ifdef _DEBUG
17054     AttrTextureColourFill::GetDebugDetails( Str );
17055 
17056     String_256 TempStr;
17057 
17058     TempStr._MakeMsg( TEXT("\r\nNoise Fill:\r\n"));
17059     (*Str) += TempStr;
17060 
17061     double Scale = ((NoiseFillAttribute*)GetAttributeValue())->GetGraininess().MakeDouble();
17062 
17063     TempStr._MakeMsg(TEXT("\r\n\nScale = #1%f "), 
17064                      (Scale));
17065     (*Str) += TempStr;
17066 #endif
17067 }
17068 
17069 /********************************************************************************************
17070 
17071 >   virtual UINT32 AttrNoiseColourFill::GetNodeSize() const
17072 
17073     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
17074     Created:    16/01/97
17075     Returns:    The size of the node in bytes
17076     Purpose:    For finding the size of the node.
17077     SeeAlso:    Node::GetSubtreeSize
17078 
17079 ********************************************************************************************/
17080 
17081 UINT32 AttrNoiseColourFill::GetNodeSize() const 
17082 {     
17083     return sizeof(AttrNoiseColourFill);
17084 }  
17085 
17086 
17087 /********************************************************************************************
17088 
17089 >   Node* AttrNoiseColourFill::SimpleCopy() 
17090 
17091     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
17092     Created:    16/01/97
17093     Returns:    A copy of the node, or NULL if memory runs out 
17094     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
17095                 The function is virtual, and must be defined for all derived classes.  
17096     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
17097                 memory error and the function returns NULL. 
17098     Scope:      protected       
17099 
17100 ********************************************************************************************/
17101      
17102 Node* AttrNoiseColourFill::SimpleCopy()
17103 {
17104     AttrNoiseColourFill* NodeCopy = new AttrNoiseColourFill();
17105     if (NodeCopy == NULL)
17106         return NULL;
17107 
17108     CopyNodeContents(NodeCopy);
17109     
17110     return NodeCopy;
17111 }  
17112 
17113 
17114 /********************************************************************************************
17115 
17116   > virtual BOOL AttrNoiseColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
17117 
17118     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
17119     Created:    26/6/96
17120     Inputs:     pFilter = ptr to the filter
17121     Returns:    TRUE if record is written, FALSE if not
17122     Purpose:    Writes the fractal fill record to the filter
17123     SeeAlso:    -
17124 
17125 ********************************************************************************************/
17126 
17127 BOOL AttrNoiseColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
17128 {
17129 #ifdef DO_EXPORT
17130     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
17131 
17132     BOOL ok = TRUE;
17133 
17134     // Make sure the start & end colours are written out first.
17135     INT32 StartColRef = pFilter->WriteRecord(Value.GetStartColour());
17136     INT32 EndColRef   = pFilter->WriteRecord(Value.GetEndColour());
17137 
17138     // Are the colour refs ok?
17139     ok = (StartColRef != 0) && (EndColRef != 0);
17140 
17141     if (ok)
17142     {
17143         CamelotFileRecord Rec(pFilter,TAG_NOISEFILL,TAG_NOISEFILL_SIZE);
17144 
17145         if (ok) ok = Rec.Init();
17146         if (ok) ok = Rec.WriteCoord(Value.StartPoint);          // INT32,INT32  4,4
17147         if (ok) ok = Rec.WriteCoord(Value.EndPoint);            //              4,4
17148         if (ok) ok = Rec.WriteCoord(Value.EndPoint2);           //              4,4
17149         if (ok) ok = Rec.WriteReference(StartColRef);           //              4
17150         if (ok) ok = Rec.WriteReference(EndColRef);             //              4
17151         if (ok) ok = Rec.WriteFIXED16(Value.GetGraininess());   //              4
17152         if (ok) ok = Rec.WriteINT32(Value.GetSeed());           //              4
17153         if (ok) ok = Rec.WriteINT32(Value.GetFractalDPI());     //              4
17154         if (ok) ok = Rec.WriteBYTE(Value.GetTileable());        //              1       = 45
17155         if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());
17156         if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());
17157 
17158         if (ok) ok = pFilter->Write(&Rec);
17159     }
17160 
17161     if (!ok)
17162         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
17163 
17164     return ok;
17165 #else
17166     return FALSE;
17167 #endif
17168 }
17169 
17170 //--------------------------------------------------------------
17171 // See AttrNoiseColourFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
17172 //
17173 BOOL AttrNoiseColourFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
17174 {
17175 #ifdef DO_EXPORT
17176     return WritePreChildrenWeb(pFilter);
17177 #else
17178     return FALSE;
17179 #endif
17180 }
17181 
17182 
17183 
17184 /********************************************************************************************
17185 
17186   > virtual BOOL AttrNoiseColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
17187 
17188     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
17189     Created:    14/9/2000
17190     Inputs:     pFilter = ptr to the filter
17191     Returns:    TRUE if record is written, FALSE if not
17192     Purpose:    Writes out colour definitions for this fill.
17193     SeeAlso:    BaseCamelotFilter::WriteRemainingAtomicTagDefinitions ()
17194                 Layer::WriteAtomicNodesColourRefs ()
17195 
17196 ********************************************************************************************/
17197 
17198 BOOL AttrNoiseColourFill::WriteColourDefinitions (BaseCamelotFilter* pFilter)
17199 {
17200     // Make sure the start & end colours are written out first.
17201     INT32 StartColRef = pFilter->WriteRecord(Value.GetStartColour());
17202     INT32 EndColRef   = pFilter->WriteRecord(Value.GetEndColour());
17203 
17204     // Are the colour refs ok?
17205     BOOL ok = (StartColRef != 0) && (EndColRef != 0);
17206     
17207     return (ok);
17208 }
17209 
17210 
17211 
17213 //
17214 //                              AttrTextureTranspFill
17215 //
17217 
17218 /********************************************************************************************
17219 
17220 >   AttrTextureTranspFill::AttrTextureTranspFill()
17221 
17222     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17223     Created:    16/9/94
17224     Purpose:    Constructor for a fractal fill.
17225 
17226 ********************************************************************************************/
17227 
17228 AttrTextureTranspFill::AttrTextureTranspFill()
17229 {
17230 }
17231 
17232 /********************************************************************************************
17233 
17234 >   AttrTextureTranspFill::~AttrTextureTranspFill()
17235 
17236     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17237     Created:    16/9/94
17238     Purpose:    Destructor for a fractal fill.
17239 
17240 ********************************************************************************************/
17241 
17242 AttrTextureTranspFill::~AttrTextureTranspFill()
17243 {
17244 }
17245 
17246 /********************************************************************************************
17247 
17248 >   virtual BOOL AttrTextureTranspFill::NeedsTransparency() const
17249 
17250     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
17251     Created:    6/1/95
17252     Inputs:     -
17253     Outputs:    -
17254     Returns:    TRUE if this node requires transparency mode to render properly.
17255     Purpose:    Called 
17256     Errors:     -
17257     SeeAlso:    Node::AttachNode
17258 
17259 ********************************************************************************************/
17260 
17261 BOOL AttrTextureTranspFill::NeedsTransparency() const
17262 {
17263     return TRUE;
17264 }
17265 
17266 /********************************************************************************************
17267 
17268 > Node* AttrTextureTranspFill::SimpleCopy() 
17269 
17270     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17271     Created:    23/8/94
17272     Returns:    A copy of the node, or NULL if memory runs out 
17273     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
17274                 The function is virtual, and must be defined for all derived classes.  
17275     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
17276                 memory error and the function returns NULL. 
17277     Scope:      protected       
17278 
17279 ********************************************************************************************/
17280      
17281 Node* AttrTextureTranspFill::SimpleCopy()
17282 {
17283     AttrTextureTranspFill* NodeCopy = new AttrTextureTranspFill();
17284     if (NodeCopy == NULL)
17285         return NULL;
17286 
17287     CopyNodeContents(NodeCopy);
17288     
17289     return NodeCopy;
17290 }  
17291 
17292 /********************************************************************************************
17293 
17294 >   virtual UINT32 AttrTextureTranspFill::GetAttrNameID(void)  
17295 
17296     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17297     Created:    23/8/94
17298     Returns:    Attribute description ID
17299     Purpose:    Returns a string resource ID describing the attribute
17300 
17301 ********************************************************************************************/
17302 
17303 UINT32 AttrTextureTranspFill::GetAttrNameID(void)  
17304 {
17305     
17306     return (_R(IDS_BITMAPTRANSPFILL));
17307 }
17308 
17309 UINT32 AttrFractalTranspFill::GetAttrNameID(void)  
17310 {   
17311     return (_R(IDS_FRACTALCLOUDSTRANSPFILL));
17312 }
17313 
17314 UINT32 AttrNoiseTranspFill::GetAttrNameID(void)  
17315 {   
17316     return (_R(IDS_FRACTALPLASMATRANSPFILL));
17317 }
17318 
17319 /********************************************************************************************
17320 
17321 >   void AttrTextureTranspFill::GetDebugDetails(StringBase* Str)
17322 
17323     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17324     Created:    20/07/94
17325     Outputs:    Str - the string containing details of the attribute.
17326     Purpose:    Output details of this attribute to the Camelot debug tree dialog.
17327 
17328 ********************************************************************************************/
17329 
17330 void AttrTextureTranspFill::GetDebugDetails(StringBase* Str)
17331 {
17332 #ifdef _DEBUG
17333     NodeAttribute::GetDebugDetails( Str );
17334 
17335     String_256 TempStr;
17336 
17337     TempStr._MakeMsg( TEXT("\r\nTexture transparency:\r\n"));
17338     (*Str) += TempStr;
17339 
17340     TempStr._MakeMsg(TEXT("\r\nStart = (#1%ld, #2%ld)"), 
17341                      (*GetStartPoint()).x, (*GetStartPoint()).y);
17342     (*Str) += TempStr;
17343 
17344     TempStr._MakeMsg(TEXT("\r\nEnd = (#1%ld, #2%ld) "), 
17345                      (*GetEndPoint()).x, (*GetEndPoint()).y);
17346     (*Str) += TempStr;
17347 
17348     TempStr._MakeMsg(TEXT("\r\n3rd = (#1%ld, #2%ld) "), 
17349                      (*GetEndPoint2()).x, (*GetEndPoint2()).y);
17350     (*Str) += TempStr;
17351 #endif
17352 }
17353 
17354 
17355 
17356 /********************************************************************************************
17357 
17358 >   void AttrTextureTranspFill::Render( RenderRegion* pRender)
17359 
17360     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17361     Created:    23/8/94
17362     Purpose:    'Renders' a Fractal Fill Transp attribute.
17363 
17364 ********************************************************************************************/
17365 
17366 void AttrTextureTranspFill::Render(RenderRegion* pRender)
17367 {
17368     if (GetBitmap() == NULL || GetBitmap()->ActualBitmap == NULL)
17369     {
17370         if (!RecalcFractal())
17371             return;
17372     }
17373 
17374     pRender->SetTranspFillGeometry((TranspFillAttribute*)GetAttributeValue(), FALSE);
17375 }
17376 
17377 
17378 /********************************************************************************************
17379 
17380 >   void AttrTextureTranspFill::RenderFillBlobs(RenderRegion* pRender)
17381 
17382     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17383     Created:    13/9/94
17384     Inputs:     pRender - The region to render the blobs to.
17385     Purpose:    Renders the grad fills arrow blob when requested to by its selected parent.
17386 
17387 ********************************************************************************************/
17388 
17389 void AttrTextureTranspFill::RenderFillBlobs(RenderRegion* pRender)
17390 {
17391 #if !defined(EXCLUDE_FROM_RALPH)
17392     if (!IsVisible())
17393         return;     // We're Not in Fill Transparency Mode
17394 
17395     // Don't bother if this fill is being edited as a copy of it
17396     // we be rendered thoughout the drag op
17397     if (IsFillBeingEdited())
17398         return;
17399 
17400     // Ignore this if the mesh is the same as the last one rendered.
17401     if (CheckPreviousFillMesh())
17402         return;
17403 
17404     DocCoord ControlPoints[5];
17405     ControlPoints[FILLCONTROL_STARTPOINT] = (*GetStartPoint());
17406     ControlPoints[FILLCONTROL_ENDPOINT] = (*GetEndPoint());
17407     ControlPoints[FILLCONTROL_SECONDARYPOINT] = (*GetEndPoint2());
17408 
17409     // Render a nice pretty Fill Mesh thingy
17410     RenderFillMesh(pRender, ControlPoints, SelectionState, 5);
17411 
17412     // This call was removed by Gerry (2/9/96) as it causes blob problems
17413     // If we are removing blobs then force all blobs to be deselected
17414 //  if ((Camelot.GetBlobManager())->IsRemovingBlobs())
17415 //      DeselectAllNoRedraw();
17416 #endif
17417 }
17418 
17419 
17420 
17421 
17422 
17423 /********************************************************************************************
17424 
17425 >   FillControl AttrTextureTranspFill::CheckForControlHit(DocCoord &ClickPos)
17426 
17427     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17428     Created:    21/07/94
17429     Inputs:     ClickPos, The DocCoord position to check.
17430     Returns:    A FillControl, indicating the Fill Control Point Hit,
17431                 or FILLCONTROL_NULL, if no points hit.
17432     Purpose:    Check to see if a click was on a Fill Control Point. 
17433     SeeAlso:    FillControl
17434 
17435 ********************************************************************************************/
17436 
17437 FillControl AttrTextureTranspFill::CheckForControlHit(DocCoord &ClickPos)
17438 {
17439 #if !defined(EXCLUDE_FROM_RALPH)
17440     if (!GetApplication()->GetBlobManager()->GetCurrentInterest().Fill || !IsVisible())
17441         return FILLCONTROL_NULL;
17442 
17443     // Set up a default, that indicates not control points hit
17444     FillControl HitControl = FILLCONTROL_NULL;
17445     DocRect BlobRect;
17446 
17447     DocCoord StartPoint  = *GetStartPoint();
17448     DocCoord EndPoint    = *GetEndPoint();
17449     DocCoord EndPoint2   = *GetEndPoint2();
17450 
17451     // Bodge Alert !!
17452     
17453     // Bitmap fills have a complicated control point system.
17454     // The actual control points needed for rendering are the Bottom Left,
17455     // Top Left, and Bottom Right points of the bitmap.  But on screen the 
17456     // points seen and moved are the Centre, Middle Right, and Middle Top.
17457     // So we need to convert the click points into vitual points before
17458     // we do the hit test.
17459 
17460     DocCoord CentrePoint;
17461     DocCoord Drag2Blob;
17462     DocCoord Drag3Blob;
17463 
17464     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
17465                             &CentrePoint, &Drag2Blob, &Drag3Blob);
17466 
17467     // Get the rectangle around the Centre Control Point
17468     (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &BlobRect);
17469     // See if the Click Position is within the rectangle
17470     if ( BlobRect.ContainsCoord(ClickPos) )
17471         HitControl = FILLCONTROL_STARTPOINT;
17472 
17473     // Get the rectangle around the First End Point
17474     (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &BlobRect);
17475     // See if the Click Position is within the rectangle
17476     if ( BlobRect.ContainsCoord(ClickPos) )
17477         HitControl = FILLCONTROL_ENDPOINT;
17478 
17479     // Get the rectangle around the Second End Point
17480     (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &BlobRect);
17481     // See if the Click Position is within the rectangle
17482     if ( BlobRect.ContainsCoord(ClickPos) )
17483         HitControl = FILLCONTROL_SECONDARYPOINT;
17484 
17485     return HitControl;
17486 #else
17487     return FILLCONTROL_NULL;
17488 #endif
17489 }
17490 
17491 
17492 
17493 /********************************************************************************************
17494 
17495 >   virtual void AttrTextureTranspFill::OnControlDrag( DocCoord Pos, FillControl DragControl, 
17496                                                     ClickModifiers ClickMods)
17497     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17498     Created:    2/8/94
17499     Inputs:     Pos - The Location of the mouse pointer at the time of the call
17500                 DragControl - The FillControl that is being dragged.
17501                 ClickMods - The modifiers to the click (eg shift, control etc )
17502     Purpose:    Called when an edit operation is dragging a fill control point.
17503 
17504 ********************************************************************************************/
17505 
17506 void AttrTextureTranspFill::OnControlDrag( DocCoord Pos, FillControl& DragControl, ClickModifiers ClickMods)
17507 {
17508 #if !defined(EXCLUDE_FROM_RALPH)
17509     // Get the current Control Point Positions
17510     DocCoord StartPoint = *GetStartPoint();
17511     DocCoord EndPoint = *GetEndPoint();
17512     DocCoord EndPoint2 = *GetEndPoint2();
17513 
17514     DocCoord CentrePoint;
17515     DocCoord Drag2Blob;
17516     DocCoord Drag3Blob;
17517 
17518     // Bodge Alert !!
17519     
17520     // Bitmap fills have a complicated control point system.
17521     // The actual control points needed for rendering are the Bottom Left,
17522     // Top Left, and Bottom Right points of the bitmap.  But on screen the 
17523     // points seen and moved are the Centre, Middle Right, and Middle Top.
17524     // So we need to convert the click points into vitual points before
17525     // we start dragging them about.
17526 
17527     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
17528                             &CentrePoint, &Drag2Blob, &Drag3Blob);
17529 
17530     INT32 dx, dy;
17531 
17532     // Which control is being dragged ?
17533     switch (DragControl)
17534     {
17535         case FILLCONTROL_STARTPOINT:
17536 
17537             // They're dragging the Centre Point
17538             dx = CentrePoint.x - Pos.x;
17539             dy = CentrePoint.y - Pos.y;
17540             // Move the other points relative
17541             Drag2Blob.translate(-dx, -dy);
17542             Drag3Blob.translate(-dx, -dy);
17543             CentrePoint = Pos;
17544             break;
17545 
17546         case FILLCONTROL_ENDPOINT:
17547 
17548             // If the Constrain key is down then constrain the Angle of the
17549             // point, relative to the centre position.
17550             if (ClickMods.Constrain)
17551                 DocView::ConstrainToAngle(CentrePoint, &Pos);
17552 
17553             if (ClickMods.Adjust)
17554             {
17555                 // Shift is pressed, so lock the aspect ratio of the bitmap mesh
17556                 double OldLen = CentrePoint.Distance(Drag2Blob);
17557                 double NewLen = CentrePoint.Distance(Pos);
17558                 double Ratio = 1.0;
17559 
17560                 if (OldLen == 0)
17561                     Ratio = 0;
17562                 else
17563                     Ratio = NewLen/OldLen;
17564 
17565                 // Calculate the new point based on the aspect ratio
17566                 Drag3Blob = 
17567                         MakeLineAtAngle(CentrePoint, Pos, 90, INT32(CentrePoint.Distance(Drag3Blob) * Ratio));
17568             }
17569 
17570             Drag2Blob   = Pos;
17571             break;
17572 
17573         case FILLCONTROL_SECONDARYPOINT:
17574 
17575             // If the Constrain key is down then constrain the Angle of the
17576             // point, relative to the centre position.
17577             if (ClickMods.Constrain)
17578                 DocView::ConstrainToAngle(CentrePoint, &Pos);
17579 
17580             if (ClickMods.Adjust)
17581             {
17582                 // Shift is pressed, so lock the aspect ratio of the bitmap mesh
17583                 double OldLen = CentrePoint.Distance(Drag3Blob);
17584                 double NewLen = CentrePoint.Distance(Pos);
17585                 double Ratio = 1.0;
17586 
17587                 if (OldLen == 0)
17588                     Ratio = 0;
17589                 else
17590                     Ratio = NewLen/OldLen;
17591 
17592                 // Calculate the new point based on the aspect ratio
17593                 Drag2Blob = 
17594                         MakeLineAtAngle(CentrePoint, Pos, -90, INT32(CentrePoint.Distance(Drag2Blob) * Ratio));
17595             }
17596 
17597             Drag3Blob  = Pos;
17598             break;
17599     }
17600 
17601     // Now we have to convert the Vitual Coords back into real
17602     // bitmap control points.
17603 
17604     GetBitmapRealPoints(CentrePoint, Drag2Blob, Drag3Blob,
17605                             &StartPoint, &EndPoint, &EndPoint2);
17606 
17607     // Store the new points back in the Fill
17608     SetStartPoint(&StartPoint);
17609     SetEndPoint(&EndPoint);
17610     SetEndPoint2(&EndPoint2);
17611 #endif
17612 }
17613 
17614 /********************************************************************************************
17615 
17616 >   void AttrTextureColourFill::RenderControl(FillControl Control, BOOL RenderOn)
17617 
17618     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17619     Created:    26/7/94
17620     Inputs:     Control, the FillControl to redraw
17621     Purpose:    Redraws the Fill Control blobs when the selection changes.
17622     SeeAlso:    FillControl         
17623 
17624 ********************************************************************************************/
17625 
17626 void AttrTextureTranspFill::RenderControl(FillControl Control, BOOL RenderOn)
17627 {
17628 #if !defined(EXCLUDE_FROM_RALPH)
17629     DocRect ControlRect;
17630 
17631     // Ignore if we're not in the tree yet
17632     // We may be a tempory clone, or something
17633     NodeRenderable* pParent = (NodeRenderable*)FindParent();
17634 
17635     if (pParent == NULL)
17636         return;
17637 
17638     if (IsBlobSame(Control))
17639         return;         // Ignore if same as the last blob rendered
17640 
17641     Spread* pSpread = this->FindParentSpread();
17642 
17643     DocCoord StartPoint = *GetStartPoint();
17644     DocCoord EndPoint = *GetEndPoint();
17645     DocCoord EndPoint2 = *GetEndPoint2();
17646 
17647     DocCoord CentrePoint;
17648     DocCoord Drag2Blob;
17649     DocCoord Drag3Blob;
17650 
17651     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
17652                             &CentrePoint, &Drag2Blob, &Drag3Blob);
17653 
17654     switch (Control)
17655     {
17656         case FILLCONTROL_STARTPOINT:
17657 
17658             if (GetStartPoint() != NULL)
17659             {
17660                 // Redraw the Start Point Blob
17661                 (Camelot.GetBlobManager())->GetBlobRect(CentrePoint, &ControlRect);
17662                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
17663             }
17664             break;
17665 
17666         case FILLCONTROL_ENDPOINT:
17667 
17668             if (GetEndPoint() != NULL)
17669             {
17670                 // Redraw BOTH End Point Blobs
17671                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
17672                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
17673             }
17674 
17675             if (GetEndPoint2() != NULL)
17676             {
17677                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
17678                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
17679             }
17680             break;
17681 
17682         case FILLCONTROL_SECONDARYPOINT:
17683 
17684             if (GetEndPoint2() != NULL)
17685             {
17686                 // Redraw BOTH End Point Blobs
17687                 (Camelot.GetBlobManager())->GetBlobRect(Drag2Blob, &ControlRect);
17688                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
17689             }
17690 
17691             if (GetEndPoint2() != NULL)
17692             {
17693                 (Camelot.GetBlobManager())->GetBlobRect(Drag3Blob, &ControlRect);
17694                 RenderFillControl(RenderOn, &ControlRect, pSpread, pParent);
17695             }
17696             break;
17697     }
17698 #endif
17699 }
17700 
17701 
17702 
17703 /********************************************************************************************
17704 
17705 >   void AttrTextureTranspFill::RenderFillMesh(RenderRegion* pRender, 
17706                                     DocCoord* ControlPoints, BOOL* SelState,
17707                                     INT32 NumControlPoints)
17708     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17709     Created:    24/7/94
17710     Inputs:     pRender - The region to render the blobs to.
17711                 ControlPoints - The positions of all the control points
17712                 SelState - The selection state of the control points
17713                 NumControlPoints - The Number of control points.
17714     Purpose:    Renders the grad fills mesh during a drag op.
17715                 Don't call this, call RenderFillBlobs().
17716     SeeAlso:    AttrBitmapFill::RenderFillBlobs
17717 
17718 ********************************************************************************************/
17719 
17720 void AttrTextureTranspFill::RenderFillMesh(RenderRegion* pRender, 
17721                                             DocCoord* ControlPoints, BOOL* SelState,
17722                                             INT32 NumControlPoints)
17723 {
17724 #if !defined(EXCLUDE_FROM_RALPH)
17725     DocCoord StartPoint = ControlPoints[FILLCONTROL_STARTPOINT];
17726     DocCoord EndPoint   = ControlPoints[FILLCONTROL_ENDPOINT];
17727 
17728     if (StartPoint == EndPoint)
17729         return;
17730 
17731     if (SelState == NULL)
17732     {
17733         // If no selection state passed in, then assume
17734         // all the points are deselected
17735         BOOL Selected[NUMCONTROLPOINTS];
17736         for (INT32 i=0; i< NumControlPoints; i++)
17737         {
17738             Selected[i] = FALSE;
17739         }
17740         SelState = Selected;
17741     }
17742 
17743     DocCoord EndPoint2  = ControlPoints[FILLCONTROL_SECONDARYPOINT];
17744 
17745     DocCoord Start;
17746     DocCoord End;
17747     DocCoord End2; 
17748 
17749     // Work out the Virtual positions of the Bitmap Controls
17750     GetBitmapVirtualPoints(StartPoint, EndPoint, EndPoint2,
17751                             &Start, &End, &End2);
17752 
17753     // Remember what attributes were here before
17754     pRender->SaveContext();
17755 
17756     // Get the current blob size in Doc Units
17757     INT32 BlobSize = (Camelot.GetBlobManager())->GetBlobSize();
17758 
17759     // Calculate the Arrow on the End of the Line
17760     Path ArrowPath;
17761     ArrowPath.Initialise();
17762     DocCoord LineEnd;
17763     MakeMeshArrow(&ArrowPath, Start, End, &LineEnd);
17764 
17765     // Calculate the Arrow on the End of the Line2
17766     Path ArrowPath2;
17767     ArrowPath2.Initialise();
17768     DocCoord LineEnd2;
17769     MakeMeshArrow(&ArrowPath2, Start, End2, &LineEnd2);
17770 
17771     // Set the line colours etc as we need them
17772     pRender->SetLineWidth(0);
17773     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
17774     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
17775 
17776     // First Draw the Line
17777     pRender->SetLineWidth(BlobSize/4);
17778     pRender->DrawLine(Start, LineEnd);
17779 
17780     // Draw the secondary line
17781     pRender->DrawLine(Start, LineEnd2);
17782 
17783     // Render an Arrow at the end of the line
17784     pRender->SetLineWidth(0);
17785     pRender->SetLineColour(COLOUR_NONE);
17786     pRender->DrawPath(&ArrowPath);
17787 
17788     // and on the end of the secondary line
17789     pRender->DrawPath(&ArrowPath2);
17790 
17791     if (DraggedFill == this)
17792     {
17793         // If we are being dragged then draw a Parallelgram to
17794         // show the shape of the bitmap
17795         pRender->SetLineColour(COLOUR_SELECTEDBLOB);
17796         pRender->SetFillColour(COLOUR_NONE);
17797     
17798         Path ParaPath;
17799         ParaPath.Initialise();
17800         MakeMeshParallelagram(&ParaPath, Start, End, End2);
17801 
17802         // Draw the parallelagram
17803         pRender->DrawPath(&ParaPath);
17804     }
17805 
17806     // Now Render the blobs on the path
17807 
17808     // Draw a blob at the start point
17809     if (SelState[FILLCONTROL_STARTPOINT])
17810     {
17811         // Draw Selected Blob
17812 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
17813         pRender->SetLineColour(COLOUR_NONE);
17814         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
17815         pRender->DrawBlob(Start, BT_SELECTED);
17816     }
17817     else
17818     {
17819         // Draw Unselected Blob
17820 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
17821         pRender->SetLineColour(COLOUR_NONE);
17822         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
17823         pRender->DrawBlob(Start, BT_UNSELECTED);
17824     }
17825 
17826     // Draw a blob at the end point
17827     if (SelState[FILLCONTROL_ENDPOINT])
17828     {
17829         // Draw Selected Blob
17830 //      pRender->SetLineColour(COLOUR_SELECTEDBLOB);
17831         pRender->SetLineColour(COLOUR_NONE);
17832         pRender->SetFillColour(COLOUR_SELECTEDBLOB);
17833         pRender->DrawBlob(End, BT_SELECTED);
17834         pRender->DrawBlob(End2,BT_SELECTED);
17835     }
17836     else
17837     {
17838         // Draw Unselected Blob
17839 //      pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
17840         pRender->SetLineColour(COLOUR_NONE);
17841         pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
17842         pRender->DrawBlob(End, BT_UNSELECTED);
17843         pRender->DrawBlob(End2,BT_UNSELECTED);
17844     }
17845 
17846     // Put all the old attributes back
17847     pRender->RestoreContext();
17848 #endif
17849 }
17850 
17851 
17852 
17854 //
17855 //                              AttrFractalTranspFill
17856 //
17858 
17859 /********************************************************************************************
17860 
17861 >   AttrFractalTranspFill::AttrFractalTranspFill()
17862 
17863     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17864     Created:    16/9/94
17865     Purpose:    Constructor for a transparency fill.
17866 
17867 ********************************************************************************************/
17868 
17869 AttrFractalTranspFill::AttrFractalTranspFill()
17870 {
17871     SetFractalDPI(AttrFillGeometry::FractalDPI);
17872 }
17873 
17874 /********************************************************************************************
17875 
17876 >   AttrFractalColourFill::~AttrFractalColourFill()
17877 
17878     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17879     Created:    16/9/94
17880     Purpose:    Destructor for a transparency fill.
17881 
17882 ********************************************************************************************/
17883 
17884 AttrFractalTranspFill::~AttrFractalTranspFill()
17885 {
17886 }
17887 
17888 /********************************************************************************************
17889 
17890 >   virtual UINT32 AttrFractalTranspFill::GetNodeSize() const
17891 
17892     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17893     Created:    23/8/94
17894     Returns:    The size of the node in bytes
17895     Purpose:    For finding the size of the node.
17896     SeeAlso:    Node::GetSubtreeSize
17897 
17898 ********************************************************************************************/
17899 
17900 UINT32 AttrFractalTranspFill::GetNodeSize() const 
17901 {     
17902     return sizeof(AttrFractalTranspFill);
17903 }  
17904 
17905 /********************************************************************************************
17906 
17907 > Node* AttrFractalTranspFill::SimpleCopy() 
17908 
17909     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
17910     Created:    23/8/94
17911     Returns:    A copy of the node, or NULL if memory runs out 
17912     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
17913                 The function is virtual, and must be defined for all derived classes.  
17914     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
17915                 memory error and the function returns NULL. 
17916     Scope:      protected       
17917 
17918 ********************************************************************************************/
17919      
17920 Node* AttrFractalTranspFill::SimpleCopy()
17921 {
17922     AttrFractalTranspFill* NodeCopy = new AttrFractalTranspFill();
17923     if (NodeCopy == NULL)
17924         return NULL;
17925 
17926     CopyNodeContents(NodeCopy);
17927     
17928     return NodeCopy;
17929 }  
17930 
17931 /********************************************************************************************
17932 
17933   > virtual BOOL AttrFractalTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
17934 
17935     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
17936     Created:    26/6/96
17937     Inputs:     pFilter = ptr to the filter
17938     Returns:    TRUE if record is written, FALSE if not
17939     Purpose:    Writes the fractal transparent fill record to the filter
17940     SeeAlso:    -
17941 
17942 ********************************************************************************************/
17943 
17944 BOOL AttrFractalTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
17945 {
17946 #ifdef DO_EXPORT
17947     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
17948 
17949     BOOL ok = TRUE;
17950 
17951     CamelotFileRecord Rec(pFilter,TAG_FRACTALTRANSPARENTFILL,TAG_FRACTALTRANSPARENTFILL_SIZE);
17952 
17953     if (ok) ok = Rec.Init();
17954     if (ok) ok = Rec.WriteCoord(Value.StartPoint);          // INT32,INT32  4,4
17955     if (ok) ok = Rec.WriteCoord(Value.EndPoint);            //            4,4
17956     if (ok) ok = Rec.WriteCoord(Value.EndPoint2);           //            4,4
17957 
17958     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));         //              1
17959     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));      //              1
17960     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));     //              1
17961 
17962     if (ok) ok = Rec.WriteINT32(Value.Seed);                    //              4
17963     if (ok) ok = Rec.WriteFIXED16(Value.Graininess);        //              4
17964     if (ok) ok = Rec.WriteFIXED16(Value.Gravity);           //              4
17965     if (ok) ok = Rec.WriteFIXED16(Value.Squash);            //              4
17966     if (ok) ok = Rec.WriteINT32(Value.Dpi);                 //              4
17967     if (ok) ok = Rec.WriteBYTE(Value.Tileable);             //              1   = 48
17968     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());       // 8
17969     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());       // 8
17970 
17971     if (ok) ok = pFilter->Write(&Rec);
17972 
17973     if (!ok)
17974         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
17975 
17976     return ok;
17977 #else
17978     return FALSE;
17979 #endif
17980 }
17981 
17982 //--------------------------------------------------------------
17983 // See AttrFractalTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
17984 //
17985 BOOL AttrFractalTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
17986 {
17987 #ifdef DO_EXPORT
17988     return WritePreChildrenWeb(pFilter);
17989 #else
17990     return FALSE;
17991 #endif
17992 }
17993 
17994 
17995 /********************************************************************************************
17996 >   BOOL AttrFractalTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
17997 
17998     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
17999     Created:    11/05/2005
18000     Inputs:     -
18001     Outputs:    -
18002     Returns:    TRUE if this node has a value equivalent to the relevant 
18003                 FALSE otherwise
18004     Purpose:    Determine whether this attribute has the default value or not
18005     Errors:     -
18006     SeeAlso:    -
18007 ********************************************************************************************/
18008 
18009 BOOL AttrFractalTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
18010 {
18011     // Slight bodge - we will assume that the default transparency is fully opaque
18012     if (bAppearance)
18013         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0));
18014     else
18015         return FALSE;
18016 }
18017 
18018 
18019 
18020 
18022 //
18023 //                              AttrNoiseTranspFill
18024 //
18026 
18027 /********************************************************************************************
18028 
18029 >   AttrNoiseTranspFill::AttrNoiseTranspFill()
18030 
18031     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18032     Created:    16/9/94
18033     Purpose:    Constructor for a transparency fill.
18034 
18035 ********************************************************************************************/
18036 
18037 AttrNoiseTranspFill::AttrNoiseTranspFill()
18038 {
18039     SetFractalDPI(AttrFillGeometry::FractalDPI);
18040 }
18041 
18042 /********************************************************************************************
18043 
18044 >   AttrFractalColourFill::~AttrFractalColourFill()
18045 
18046     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18047     Created:    16/9/94
18048     Purpose:    Destructor for a transparency fill.
18049 
18050 ********************************************************************************************/
18051 
18052 AttrNoiseTranspFill::~AttrNoiseTranspFill()
18053 {
18054 }
18055 
18056 /********************************************************************************************
18057 
18058 >   virtual UINT32 AttrNoiseTranspFill::GetNodeSize() const
18059 
18060     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18061     Created:    23/8/94
18062     Returns:    The size of the node in bytes
18063     Purpose:    For finding the size of the node.
18064     SeeAlso:    Node::GetSubtreeSize
18065 
18066 ********************************************************************************************/
18067 
18068 UINT32 AttrNoiseTranspFill::GetNodeSize() const 
18069 {     
18070     return sizeof(AttrNoiseTranspFill);
18071 }  
18072 
18073 /********************************************************************************************
18074 
18075 > Node* AttrNoiseTranspFill::SimpleCopy() 
18076 
18077     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18078     Created:    23/8/94
18079     Returns:    A copy of the node, or NULL if memory runs out 
18080     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
18081                 The function is virtual, and must be defined for all derived classes.  
18082     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
18083                 memory error and the function returns NULL. 
18084     Scope:      protected       
18085 
18086 ********************************************************************************************/
18087      
18088 Node* AttrNoiseTranspFill::SimpleCopy()
18089 {
18090     AttrNoiseTranspFill* NodeCopy = new AttrNoiseTranspFill();
18091     if (NodeCopy == NULL)
18092         return NULL;
18093 
18094     CopyNodeContents(NodeCopy);
18095     
18096     return NodeCopy;
18097 }  
18098 
18099 /********************************************************************************************
18100 
18101   > virtual BOOL AttrNoiseTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18102 
18103     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
18104     Created:    26/6/96
18105     Inputs:     pFilter = ptr to the filter
18106     Returns:    TRUE if record is written, FALSE if not
18107     Purpose:    Writes the fractal transparent fill record to the filter
18108     SeeAlso:    -
18109 
18110 ********************************************************************************************/
18111 
18112 BOOL AttrNoiseTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18113 {
18114 #ifdef DO_EXPORT
18115     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
18116 
18117     BOOL ok = TRUE;
18118 
18119     CamelotFileRecord Rec(pFilter,TAG_NOISETRANSPARENTFILL,TAG_NOISETRANSPARENTFILL_SIZE);
18120 
18121     if (ok) ok = Rec.Init();
18122     if (ok) ok = Rec.WriteCoord(Value.StartPoint);              // INT32, INT32 = 4,4
18123     if (ok) ok = Rec.WriteCoord(Value.EndPoint);                //              4,4
18124     if (ok) ok = Rec.WriteCoord(Value.EndPoint2);               //              4,4
18125 
18126     if (ok) ok = Rec.WriteBYTE(BYTE(Value.Transp));             //              1
18127     if (ok) ok = Rec.WriteBYTE(BYTE(Value.EndTransp));          //              1
18128     if (ok) ok = Rec.WriteBYTE(BYTE(Value.TranspType));         //              1
18129 
18130     if (ok) ok = Rec.WriteFIXED16(Value.GetGraininess());       //              4
18131     if (ok) ok = Rec.WriteINT32(Value.GetSeed());               //              4
18132     if (ok) ok = Rec.WriteINT32(Value.GetFractalDPI());         //              4
18133     if (ok) ok = Rec.WriteBYTE(Value.GetTileable());            //              1       = 40
18134     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetBias ());       // 8
18135     if (ok) ok = Rec.WriteDOUBLE ((double) GetProfile ().GetGain ());       // 8
18136 
18137     if (ok) ok = pFilter->Write(&Rec);
18138 
18139     if (!ok)
18140         pFilter->GotError(_R(IDE_FILE_WRITE_ERROR));
18141 
18142     return ok;
18143 #else
18144     return FALSE;
18145 #endif
18146 }
18147 
18148 //--------------------------------------------------------------
18149 // See AttrNoiseTranspFill::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18150 //
18151 BOOL AttrNoiseTranspFill::WritePreChildrenNative(BaseCamelotFilter* pFilter)
18152 {
18153 #ifdef DO_EXPORT
18154     return WritePreChildrenWeb(pFilter);
18155 #else
18156     return FALSE;
18157 #endif
18158 }
18159 
18160 
18161 
18162 
18163 /********************************************************************************************
18164 >   BOOL AttrNoiseTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
18165 
18166     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
18167     Created:    11/05/2005
18168     Inputs:     -
18169     Outputs:    -
18170     Returns:    TRUE if this node has a value equivalent to the relevant 
18171                 FALSE otherwise
18172     Purpose:    Determine whether this attribute has the default value or not
18173     Errors:     -
18174     SeeAlso:    -
18175 ********************************************************************************************/
18176 
18177 BOOL AttrNoiseTranspFill::HasEquivalentDefaultValue(BOOL bAppearance)
18178 {
18179     // Slight bodge - we will assume that the default transparency is fully opaque
18180     if (bAppearance)
18181         return (Value.TranspType==TT_NoTranspType || (Value.TranspType==TT_Mix && Value.Transp == 0 && Value.EndTransp==0));
18182     else
18183         return FALSE;
18184 }
18185 
18186 
18187 
18188 
18190 //
18191 //                              AttrFillMapping
18192 //
18194 
18195 /********************************************************************************************
18196 
18197 >   INT32 AttrFillMapping::operator==(const NodeAttribute& Attrib)
18198 
18199     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18200     Created:    23/8/94
18201     Inputs:     Attrib - the attribute to compare, which must be an AttrFillMappingLinear 
18202     Returns:    Usual semantics for equality.
18203     Purpose:    A virtual comparison operator. See NodeAttribute::operator== for 
18204                 a description of why it's required. 
18205     Errors:     An ERROR3IF failure will occur if Attrib does not have a AttrFillMappingLinear 
18206                 runtime class.
18207     SeeAlso:    NodeAttribute::operator==
18208 
18209 ********************************************************************************************/
18210 
18211 INT32 AttrFillMapping::operator==(const NodeAttribute& Attrib)
18212 {
18213     ERROR3IF(!Attrib.IsKindOf(CC_RUNTIME_CLASS(AttrFillMapping)), 
18214                 "Trying to compare two objects with different types"); 
18215 
18216     return (GetRepeat() == ((AttrFillMapping*)&Attrib)->GetRepeat());
18217 }
18218 
18219 /********************************************************************************************
18220 
18221 >   virtual NodeAttribute* AttrFillMapping::GetOtherAttrToApply(BOOL* IsMutate)
18222 
18223     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18224     Created:    17/8/95
18225     Returns:    The secondary attribute to apply, or NULL if none to apply
18226     Purpose:    Some attributes require a secondary atribute to be changed when they are
18227                 changed.  This routine obtains a pointer to the secondary attribute to
18228                 apply.
18229 
18230 ********************************************************************************************/
18231 
18232 NodeAttribute* AttrFillMapping::GetOtherAttrToApply(BOOL* IsMutate)
18233 {
18234 #if !defined(EXCLUDE_FROM_RALPH)
18235     ERROR3IF(IsMutate == NULL, "NULL flag pointer passed to GetOtherAttrToApply");
18236 
18237     // If the fill mapping is changing, then we must make sure that
18238     // any fractal tileable flags are updated
18239     
18240     NodeAttribute* OtherAttr = new AttrFractalTileableChange;
18241     if (OtherAttr == NULL)
18242         return NULL;
18243 
18244     ((AttrValueChange*)OtherAttr)->MutateColourFills(TRUE);
18245 
18246     INT32 Repeat = GetRepeat();
18247     BOOL Tile;
18248 
18249     switch (Repeat)
18250     {
18251         case RT_Simple:
18252             Tile = FALSE;
18253             break;
18254 
18255         case RT_Repeating:
18256             Tile = TRUE;
18257             break;
18258 
18259         case RT_RepeatInverted:
18260             Tile = FALSE;
18261             break;
18262 
18263         default:
18264             Tile = TRUE;
18265             break;
18266     }
18267 
18268     ((AttrValueChange*)OtherAttr)->SetTileable(Tile);
18269 
18270     *IsMutate = TRUE;
18271 
18272     return OtherAttr;
18273 #else
18274     return NULL;
18275 #endif
18276 }
18277 
18278 //Mark Howitt, 7/10/97. Display Repeat Value info in the camelot debug tree
18279 #ifdef _DEBUG
18280 void AttrFillMapping::GetDebugDetails(StringBase* Str)
18281 {
18282     NodeAttribute::GetDebugDetails(Str);
18283     (*Str) += TEXT("\r\nRepeating Value = ");
18284     switch(GetRepeat())
18285     {
18286         case 0 :
18287             (*Str) += TEXT("Flat.");
18288             break;
18289         case 1 :
18290             (*Str) += TEXT("Simple.");
18291             break;
18292         case 2 :
18293             (*Str) += TEXT("Repeating.");
18294             break;
18295         case 3 :
18296             (*Str) += TEXT("InvRepeating.");
18297             break;
18298         case 4 :
18299             (*Str) += TEXT("Repeating Extra.");
18300             break;
18301         default :
18302             (*Str) += TEXT("Not Reconized!");
18303             break;
18304     }
18305     (*Str) += TEXT("\r\n");
18306 }
18307 #endif
18308 //
18309 
18310 /********************************************************************************************
18311 
18312 >   void AttrFillMappingLinear::Render( RenderRegion* pRender)
18313 
18314     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18315     Created:    23/8/94
18316     Purpose:    'Renders' a linear graduation fill mapping attribute.
18317 
18318 ********************************************************************************************/
18319 
18320 void AttrFillMappingLinear::Render( RenderRegion* pRender)
18321 {
18322     pRender->SetFillMapping(&Value, FALSE);
18323 }
18324 
18325 
18326 /********************************************************************************************
18327 
18328 > Node* AttrFillMappingLinear::SimpleCopy() 
18329 
18330     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18331     Created:    23/8/94
18332     Returns:    A copy of the node, or NULL if memory runs out 
18333     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
18334                 The function is virtual, and must be defined for all derived classes.  
18335     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
18336                 memory error and the function returns NULL. 
18337     Scope:      protected       
18338 
18339 ********************************************************************************************/
18340      
18341 Node* AttrFillMappingLinear::SimpleCopy()
18342 {
18343     AttrFillMappingLinear* NodeCopy = new AttrFillMappingLinear;
18344     if (NodeCopy == NULL)
18345         return NULL;
18346 
18347     CopyNodeContents(NodeCopy);
18348     
18349     return NodeCopy;
18350 }  
18351 
18352 /********************************************************************************************
18353 
18354 >   virtual UINT32 AttrFillMappingLinear::GetAttrNameID(void)  
18355 
18356     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18357     Created:    23/8/94
18358     Returns:    Attribute description ID
18359     Purpose:    Returns a string resource ID describing the attribute
18360 
18361 ********************************************************************************************/
18362 
18363 UINT32 AttrFillMappingLinear::GetAttrNameID(void)  
18364 {
18365     return (_R(IDS_FILLMAPPINGLINEAR)); 
18366 }                                  
18367 
18368 
18369 /********************************************************************************************
18370 
18371 >   BOOL AttrFillMappingLinear::CopyNodeContents(AttrFillMappingLinear* NodeCopy)
18372 
18373     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18374     Created:    23/8/94
18375     Inputs:     NodeCopy - the node to copy.
18376     Outputs:    A copy of this node
18377     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
18378     Errors:     An assertion failure will occur if NodeCopy is NULL
18379     Scope:      protected
18380                                      
18381 ********************************************************************************************/
18382 
18383 BOOL AttrFillMappingLinear::CopyNodeContents(AttrFillMappingLinear* NodeCopy)
18384 {
18385     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrFillMappingLinear::CopyNodeContents!");
18386 
18387     NodeAttribute::CopyNodeContents(NodeCopy);
18388 
18389     // Copy contents specific to derived class here
18390     NodeCopy->Value.SimpleCopy(&Value);
18391     return TRUE;
18392 } 
18393 
18394 
18395 /***********************************************************************************************
18396 >   void AttrFillMappingLinear::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18397 
18398     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
18399     Created:    18/12/2003
18400     Outputs:    -
18401     Purpose:    Polymorphically copies the contents of this node to another
18402     Errors:     An assertion failure will occur if NodeCopy is NULL
18403     Scope:      protected
18404                                      
18405 ***********************************************************************************************/
18406 
18407 void AttrFillMappingLinear::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18408 {
18409     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
18410     ENSURE(IS_A(pNodeCopy, AttrFillMappingLinear), "PolyCopyNodeContents given wrong dest node type");
18411 
18412     if (IS_A(pNodeCopy, AttrFillMappingLinear))
18413         CopyNodeContents((AttrFillMappingLinear*)pNodeCopy);
18414 }
18415 
18416 
18417 
18418 /********************************************************************************************
18419 
18420 >   virtual UINT32 AttrFillMappingLinear::GetNodeSize() const
18421 
18422     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18423     Created:    23/8/94
18424     Returns:    The size of the node in bytes
18425     Purpose:    For finding the size of the node 
18426     SeeAlso:    Node::GetSubtreeSize
18427 
18428 ********************************************************************************************/
18429 
18430 UINT32 AttrFillMappingLinear::GetNodeSize() const 
18431 {     
18432     return (sizeof(AttrFillMappingLinear)); 
18433 }  
18434 
18435 
18436 
18437 
18438 /********************************************************************************************
18439 
18440   > virtual BOOL AttrFillMappingLinear::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18441 
18442     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
18443     Created:    30/5/96
18444     Inputs:     pFilter = ptr to the filter
18445     Returns:    TRUE if record is written, FALSE if not
18446     Purpose:    Writes the linear fill mapping record to the filter
18447     SeeAlso:    -
18448 
18449 ********************************************************************************************/
18450 
18451 BOOL AttrFillMappingLinear::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18452 {
18453 #ifdef DO_EXPORT
18454     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
18455 
18456     UINT32 Tag = TAG_UNDEFINED, TagSize = 1;
18457     switch (Value.Repeat)
18458     {
18459         case 0 :
18460         case 1 :    Tag     = TAG_FILL_NONREPEATING;
18461                     TagSize = TAG_FILL_NONREPEATING_SIZE;
18462                     break;
18463         case 2 :    Tag     = TAG_FILL_REPEATING;
18464                     TagSize = TAG_FILL_REPEATING_SIZE;
18465                     break;
18466         case 3 :    Tag     = TAG_FILL_REPEATINGINVERTED;
18467                     TagSize = TAG_FILL_REPEATINGINVERTED_SIZE;
18468                     break;
18469 //Mark Howitt. 8/10/97. Make repeating grad fills a special case
18470 #ifdef NEW_FEATURES
18471         case 4 :    Tag     = TAG_FILL_REPEATING_EXTRA;
18472                     TagSize = TAG_FILL_REPEATING_EXTRA_SIZE;
18473                     break;
18474 #endif
18475         default:
18476             ERROR3("Unknown repeat type in this fill mapping attr");
18477             return FALSE;
18478             break;
18479     }
18480 
18481     CamelotFileRecord Rec(pFilter,Tag,TagSize);
18482     return pFilter->Write(&Rec);
18483 #else
18484     return FALSE;
18485 #endif
18486 }
18487 
18488 //--------------------------------------------------------------
18489 // See AttrFillMappingLinear::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18490 //
18491 BOOL AttrFillMappingLinear::WritePreChildrenNative(BaseCamelotFilter* pFilter)
18492 {
18493 #ifdef DO_EXPORT
18494     return WritePreChildrenWeb(pFilter);
18495 #else
18496     return FALSE;
18497 #endif
18498 }
18499 
18500 
18501 /********************************************************************************************
18502 
18503 >   void AttrFillMappingSin::Render( RenderRegion* pRender)
18504 
18505     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18506     Created:    23/8/94
18507     Purpose:    'Renders' a sinusoidal graduation fill mapping attribute.
18508 
18509 ********************************************************************************************/
18510 
18511 void AttrFillMappingSin::Render( RenderRegion* pRender)
18512 {
18513     pRender->SetFillMapping(&Value, FALSE);
18514 }
18515 
18516 /********************************************************************************************
18517 
18518 > Node* AttrFillMappingSin::SimpleCopy() 
18519 
18520     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18521     Created:    23/8/94
18522     Returns:    A copy of the node, or NULL if memory runs out 
18523     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
18524                 The function is virtual, and must be defined for all derived classes.  
18525     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
18526                 memory error and the function returns NULL. 
18527     Scope:      protected       
18528 
18529 ********************************************************************************************/
18530      
18531 Node* AttrFillMappingSin::SimpleCopy()
18532 {
18533     AttrFillMappingSin* NodeCopy = new AttrFillMappingSin();
18534     if (NodeCopy == NULL)
18535         return NULL;
18536 
18537     CopyNodeContents(NodeCopy);
18538     
18539     return NodeCopy;
18540 }  
18541 
18542 /********************************************************************************************
18543 
18544 >   virtual UINT32 AttrFillMappingSin::GetAttrNameID(void)  
18545 
18546     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18547     Created:    23/8/94
18548     Returns:    Attribute description ID
18549     Purpose:    Returns a string resource ID describing the attribute
18550 
18551 ********************************************************************************************/
18552 
18553 UINT32 AttrFillMappingSin::GetAttrNameID(void)  
18554 {
18555     return (_R(IDS_FILLMAPPINGSIN)); 
18556 }                                  
18557 
18558 
18559 /********************************************************************************************
18560 
18561 >   BOOL AttrFillMappingSin::CopyNodeContents(AttrFillMappingSin* NodeCopy)
18562 
18563     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18564     Created:    23/8/94
18565     Inputs:     NodeCopy - the node to copy.
18566     Outputs:    A copy of this node
18567     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
18568     Errors:     An assertion failure will occur if NodeCopy is NULL
18569     Scope:      protected
18570                                      
18571 ********************************************************************************************/
18572 
18573 BOOL AttrFillMappingSin::CopyNodeContents(AttrFillMappingSin* NodeCopy)
18574 {
18575     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrFillMappingSin::CopyNodeContents!");
18576 
18577     NodeAttribute::CopyNodeContents(NodeCopy);
18578 
18579     // Copy contents specific to derived class here
18580     NodeCopy->Value.SimpleCopy(&Value);
18581     return TRUE;
18582 } 
18583 
18584 
18585 /***********************************************************************************************
18586 >   void AttrFillMappingSin::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18587 
18588     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
18589     Created:    18/12/2003
18590     Outputs:    -
18591     Purpose:    Polymorphically copies the contents of this node to another
18592     Errors:     An assertion failure will occur if NodeCopy is NULL
18593     Scope:      protected
18594                                      
18595 ***********************************************************************************************/
18596 
18597 void AttrFillMappingSin::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18598 {
18599     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
18600     ENSURE(IS_A(pNodeCopy, AttrFillMappingSin), "PolyCopyNodeContents given wrong dest node type");
18601 
18602     if (IS_A(pNodeCopy, AttrFillMappingSin))
18603         CopyNodeContents((AttrFillMappingSin*)pNodeCopy);
18604 }
18605 
18606 
18607 
18608 /********************************************************************************************
18609 
18610 >   virtual UINT32 AttrFillMappingSin::GetNodeSize() const
18611 
18612     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18613     Created:    23/8/94
18614     Returns:    The size of the node in bytes
18615     Purpose:    For finding the size of the node 
18616     SeeAlso:    Node::GetSubtreeSize
18617 
18618 ********************************************************************************************/
18619 
18620 UINT32 AttrFillMappingSin::GetNodeSize() const 
18621 {     
18622     return (sizeof(AttrFillMappingSin)); 
18623 }  
18624 
18625 
18626 /********************************************************************************************
18627 
18628   > virtual BOOL AttrFillMappingSin::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18629 
18630     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
18631     Created:    30/5/96
18632     Inputs:     pFilter = ptr to the filter
18633     Returns:    TRUE if record is written, FALSE if not
18634     Purpose:    Writes the sine fill mappine record to the filter
18635     SeeAlso:    -
18636 
18637 ********************************************************************************************/
18638 
18639 BOOL AttrFillMappingSin::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18640 {
18641 #ifdef DO_EXPORT
18642     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
18643 
18644     ERROR3("v2 file format does not support this attribute");
18645     return FALSE;
18646 #else
18647     return FALSE;
18648 #endif
18649 }
18650 
18651 //--------------------------------------------------------------
18652 // See AttrFillMappingSin::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18653 //
18654 BOOL AttrFillMappingSin::WritePreChildrenNative(BaseCamelotFilter* pFilter)
18655 {
18656 #ifdef DO_EXPORT
18657     return WritePreChildrenWeb(pFilter);
18658 #else
18659     return FALSE;
18660 #endif
18661 }
18662 
18663 /********************************************************************************************
18664 
18665 >   INT32 AttrFillEffect::operator==(const NodeAttribute& Attrib)
18666 
18667     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18668     Created:    23/8/94
18669     Inputs:     Attrib  - the attribute to compare, which must be an AttrFillEffectFade 
18670     Returns:    Usual semantics for equality.
18671     Purpose:    A virtual comparison operator. See NodeAttribute::operator== for 
18672                 a description of why it's required. 
18673     Errors:     An ERROR3IF failure will occur if Attrib does not have a AttrFillEffectFade 
18674                 runtime class.
18675     SeeAlso:    NodeAttribute::operator==
18676 
18677 ********************************************************************************************/
18678 
18679 INT32 AttrFillEffect::operator==(const NodeAttribute& Attrib)
18680 {
18681     // Always equal
18682     return TRUE;
18683 }
18684 
18685 /********************************************************************************************
18686 
18687 >   void AttrFillEffectFade::Render( RenderRegion* pRender)
18688 
18689     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18690     Created:    23/8/94
18691     Purpose:    'Renders' a RGB fade fill effect attribute.
18692 
18693 ********************************************************************************************/
18694 
18695 void AttrFillEffectFade::Render( RenderRegion* pRender)
18696 {
18697     pRender->SetFillEffect(&Value, FALSE);
18698 }
18699 
18700 
18701 /********************************************************************************************
18702 
18703 > Node* AttrFillEffectFade::SimpleCopy() 
18704 
18705     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18706     Created:    23/8/94
18707     Returns:    A copy of the node, or NULL if memory runs out 
18708     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
18709                 The function is virtual, and must be defined for all derived classes.  
18710     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
18711                 memory error and the function returns NULL. 
18712     Scope:      protected       
18713 
18714 ********************************************************************************************/
18715      
18716 Node* AttrFillEffectFade::SimpleCopy()
18717 {
18718     AttrFillEffectFade* NodeCopy = new AttrFillEffectFade();
18719     if (NodeCopy == NULL)
18720         return NULL;
18721 
18722     CopyNodeContents(NodeCopy);
18723     
18724     return NodeCopy;
18725 }  
18726 
18727 /********************************************************************************************
18728 
18729 >   virtual UINT32 AttrFillEffectFade::GetAttrNameID(void)  
18730 
18731     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18732     Created:    23/8/94
18733     Returns:    Attribute description ID
18734     Purpose:    Returns a string resource ID describing the attribute
18735 
18736 ********************************************************************************************/
18737 
18738 UINT32 AttrFillEffectFade::GetAttrNameID(void)  
18739 {
18740     return (_R(IDS_FILLEFFECTFADE)); 
18741 }                                  
18742 
18743 
18744 /********************************************************************************************
18745 
18746 >   BOOL AttrFillEffectFade::CopyNodeContents(AttrFillEffectFade* NodeCopy)
18747 
18748     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18749     Created:    23/8/94
18750     Inputs:     NodeCopy - the node to copy.
18751     Outputs:    A copy of this node
18752     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
18753     Errors:     An assertion failure will occur if NodeCopy is NULL
18754     Scope:      protected
18755                                      
18756 ********************************************************************************************/
18757 
18758 BOOL AttrFillEffectFade::CopyNodeContents(AttrFillEffectFade* NodeCopy)
18759 {
18760     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrFillEffectFade::CopyNodeContents!");
18761 
18762     NodeAttribute::CopyNodeContents(NodeCopy);
18763 
18764     // Copy contents specific to derived class here
18765     NodeCopy->Value.SimpleCopy(&Value);
18766     return TRUE;
18767 } 
18768 
18769 
18770 /***********************************************************************************************
18771 >   void AttrFillEffectFade::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18772 
18773     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
18774     Created:    18/12/2003
18775     Outputs:    -
18776     Purpose:    Polymorphically copies the contents of this node to another
18777     Errors:     An assertion failure will occur if NodeCopy is NULL
18778     Scope:      protected
18779                                      
18780 ***********************************************************************************************/
18781 
18782 void AttrFillEffectFade::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18783 {
18784     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
18785     ENSURE(IS_A(pNodeCopy, AttrFillEffectFade), "PolyCopyNodeContents given wrong dest node type");
18786 
18787     if (IS_A(pNodeCopy, AttrFillEffectFade))
18788         CopyNodeContents((AttrFillEffectFade*)pNodeCopy);
18789 }
18790 
18791 
18792 
18793 /********************************************************************************************
18794 
18795 >   virtual UINT32 AttrFillEffectFade::GetNodeSize() const
18796 
18797     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18798     Created:    23/8/94
18799     Returns:    The size of the node in bytes
18800     Purpose:    For finding the size of the node 
18801     SeeAlso:    Node::GetSubtreeSize
18802 
18803 ********************************************************************************************/
18804 
18805 UINT32 AttrFillEffectFade::GetNodeSize() const 
18806 {     
18807     return (sizeof(AttrFillEffectFade)); 
18808 }  
18809 
18810 
18811 /********************************************************************************************
18812 
18813   > virtual BOOL AttrFillEffectFade::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18814 
18815     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
18816     Created:    30/5/96
18817     Inputs:     pFilter = ptr to the filter
18818     Returns:    TRUE if record is written, FALSE if not
18819     Purpose:    Writes the fade fill effect record to the filter
18820     SeeAlso:    -
18821 
18822 ********************************************************************************************/
18823 
18824 BOOL AttrFillEffectFade::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18825 {
18826 #ifdef DO_EXPORT
18827     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
18828 
18829     CamelotFileRecord Rec(pFilter,TAG_FILLEFFECT_FADE,TAG_FILLEFFECT_FADE_SIZE);
18830     return pFilter->Write(&Rec);
18831 #else
18832     return FALSE;
18833 #endif
18834 }
18835 
18836 //--------------------------------------------------------------
18837 // See AttrFillEffectFade::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18838 //
18839 BOOL AttrFillEffectFade::WritePreChildrenNative(BaseCamelotFilter* pFilter)
18840 {
18841 #ifdef DO_EXPORT
18842     return WritePreChildrenWeb(pFilter);
18843 #else
18844     return FALSE;
18845 #endif
18846 }
18847 
18848 /********************************************************************************************
18849 
18850 >   void AttrFillEffectRainbow::Render( RenderRegion* pRender)
18851 
18852     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18853     Created:    23/8/94
18854     Purpose:    'Renders' a rainbow fill effect attribute.
18855 
18856 ********************************************************************************************/
18857 
18858 void AttrFillEffectRainbow::Render( RenderRegion* pRender)
18859 {
18860     pRender->SetFillEffect(&Value, FALSE);
18861 }
18862 
18863 /********************************************************************************************
18864 
18865 > Node* AttrFillEffectRainbow::SimpleCopy() 
18866 
18867     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18868     Created:    23/8/94
18869     Returns:    A copy of the node, or NULL if memory runs out 
18870     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
18871                 The function is virtual, and must be defined for all derived classes.  
18872     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
18873                 memory error and the function returns NULL. 
18874     Scope:      protected       
18875 
18876 ********************************************************************************************/
18877      
18878 Node* AttrFillEffectRainbow::SimpleCopy()
18879 {
18880     AttrFillEffectRainbow* NodeCopy = new AttrFillEffectRainbow();
18881     if (NodeCopy == NULL)
18882         return NULL;
18883 
18884     CopyNodeContents(NodeCopy);
18885     
18886     return NodeCopy;
18887 }  
18888 
18889 /********************************************************************************************
18890 
18891 >   virtual UINT32 AttrFillEffectRainbow::GetAttrNameID(void)  
18892 
18893     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18894     Created:    23/8/94
18895     Returns:    Attribute description ID
18896     Purpose:    Returns a string resource ID describing the attribute
18897 
18898 ********************************************************************************************/
18899 
18900 UINT32 AttrFillEffectRainbow::GetAttrNameID(void)  
18901 {
18902     return (_R(IDS_FILLEFFECTRAINBOW)); 
18903 }                                  
18904 
18905 
18906 /********************************************************************************************
18907 
18908 >   BOOL AttrFillEffectRainbow::CopyNodeContents(AttrFillEffectRainbow* NodeCopy)
18909 
18910     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18911     Created:    23/8/94
18912     Inputs:     NodeCopy - the node to copy.
18913     Outputs:    A copy of this node
18914     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
18915     Errors:     An assertion failure will occur if NodeCopy is NULL
18916     Scope:      protected
18917                                      
18918 ********************************************************************************************/
18919 
18920 BOOL AttrFillEffectRainbow::CopyNodeContents(AttrFillEffectRainbow* NodeCopy)
18921 {
18922     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrFillEffectRainbow::CopyNodeContents!");
18923 
18924     NodeAttribute::CopyNodeContents(NodeCopy);
18925 
18926     // Copy contents specific to derived class here
18927     NodeCopy->Value.SimpleCopy(&Value);
18928     return TRUE;
18929 } 
18930 
18931 
18932 /***********************************************************************************************
18933 >   void AttrFillEffectRainbow::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18934 
18935     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
18936     Created:    18/12/2003
18937     Outputs:    -
18938     Purpose:    Polymorphically copies the contents of this node to another
18939     Errors:     An assertion failure will occur if NodeCopy is NULL
18940     Scope:      protected
18941                                      
18942 ***********************************************************************************************/
18943 
18944 void AttrFillEffectRainbow::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
18945 {
18946     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
18947     ENSURE(IS_A(pNodeCopy, AttrFillEffectRainbow), "PolyCopyNodeContents given wrong dest node type");
18948 
18949     if (IS_A(pNodeCopy, AttrFillEffectRainbow))
18950         CopyNodeContents((AttrFillEffectRainbow*)pNodeCopy);
18951 }
18952 
18953 
18954 
18955 /********************************************************************************************
18956 
18957 >   virtual UINT32 AttrFillEffectRainbow::GetNodeSize() const
18958 
18959     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
18960     Created:    23/8/94
18961     Returns:    The size of the node in bytes
18962     Purpose:    For finding the size of the node 
18963     SeeAlso:    Node::GetSubtreeSize
18964 
18965 ********************************************************************************************/
18966 
18967 UINT32 AttrFillEffectRainbow::GetNodeSize() const 
18968 {     
18969     return (sizeof(AttrFillEffectRainbow)); 
18970 }  
18971 
18972 
18973 
18974 /********************************************************************************************
18975 
18976   > virtual BOOL AttrFillEffectRainbow::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18977 
18978     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
18979     Created:    30/5/96
18980     Inputs:     pFilter = ptr to the filter
18981     Returns:    TRUE if record is written, FALSE if not
18982     Purpose:    Writes the rainbow fill effect record to the filter
18983     SeeAlso:    -
18984 
18985 ********************************************************************************************/
18986 
18987 BOOL AttrFillEffectRainbow::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
18988 {
18989 #ifdef DO_EXPORT
18990     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
18991 
18992     CamelotFileRecord Rec(pFilter,TAG_FILLEFFECT_RAINBOW,TAG_FILLEFFECT_RAINBOW_SIZE);
18993     return pFilter->Write(&Rec);
18994 #else
18995     return FALSE;
18996 #endif
18997 }
18998 
18999 //--------------------------------------------------------------
19000 // See AttrFillEffectRainbow::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19001 //
19002 BOOL AttrFillEffectRainbow::WritePreChildrenNative(BaseCamelotFilter* pFilter)
19003 {
19004 #ifdef DO_EXPORT
19005     return WritePreChildrenWeb(pFilter);
19006 #else
19007     return FALSE;
19008 #endif
19009 }
19010 
19011 /********************************************************************************************
19012 
19013 >   void AttrFillEffectAltRainbow::Render( RenderRegion* pRender)
19014 
19015     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19016     Created:    23/8/94
19017     Purpose:    'Renders' an alternate rainbow fill effect attribute.
19018 
19019 ********************************************************************************************/
19020 
19021 void AttrFillEffectAltRainbow::Render( RenderRegion* pRender)
19022 {
19023     pRender->SetFillEffect(&Value, FALSE);
19024 }
19025 
19026 /********************************************************************************************
19027 
19028 > Node* AttrFillEffectAltRainbow::SimpleCopy() 
19029 
19030     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19031     Created:    23/8/94
19032     Returns:    A copy of the node, or NULL if memory runs out 
19033     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
19034                 The function is virtual, and must be defined for all derived classes.  
19035     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
19036                 memory error and the function returns NULL. 
19037     Scope:      protected       
19038 
19039 ********************************************************************************************/
19040      
19041 Node* AttrFillEffectAltRainbow::SimpleCopy()
19042 {
19043     AttrFillEffectAltRainbow* NodeCopy = new AttrFillEffectAltRainbow();
19044     if (NodeCopy == NULL)
19045         return NULL;
19046 
19047     CopyNodeContents(NodeCopy);
19048     
19049     return NodeCopy;
19050 }  
19051 
19052 /********************************************************************************************
19053 
19054 >   virtual UINT32 AttrFillEffectAltRainbow::GetAttrNameID(void)  
19055 
19056     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19057     Created:    23/8/94
19058     Returns:    Attribute description ID
19059     Purpose:    Returns a string resource ID describing the attribute
19060 
19061 ********************************************************************************************/
19062 
19063 UINT32 AttrFillEffectAltRainbow::GetAttrNameID(void)  
19064 {
19065     return (_R(IDS_FILLEFFECTALTRAINBOW)); 
19066 }                                  
19067 
19068 
19069 /********************************************************************************************
19070 
19071 >   BOOL AttrFillEffectAltRainbow::CopyNodeContents(AttrFillEffectAltRainbow* NodeCopy)
19072 
19073     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19074     Created:    23/8/94
19075     Inputs:     NodeCopy - the node to copy.
19076     Outputs:    A copy of this node
19077     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
19078     Errors:     An assertion failure will occur if NodeCopy is NULL
19079     Scope:      protected
19080                                      
19081 ********************************************************************************************/
19082 
19083 BOOL AttrFillEffectAltRainbow::CopyNodeContents(AttrFillEffectAltRainbow* NodeCopy)
19084 {
19085     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrFillEffectAltRainbow::CopyNodeContents!");
19086 
19087     NodeAttribute::CopyNodeContents(NodeCopy);
19088 
19089     // Copy contents specific to derived class here
19090     NodeCopy->Value.SimpleCopy(&Value);
19091     return TRUE;
19092 } 
19093 
19094 
19095 /***********************************************************************************************
19096 >   void AttrFillEffectAltRainbow::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19097 
19098     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
19099     Created:    18/12/2003
19100     Outputs:    -
19101     Purpose:    Polymorphically copies the contents of this node to another
19102     Errors:     An assertion failure will occur if NodeCopy is NULL
19103     Scope:      protected
19104                                      
19105 ***********************************************************************************************/
19106 
19107 void AttrFillEffectAltRainbow::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19108 {
19109     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
19110     ENSURE(IS_A(pNodeCopy, AttrFillEffectAltRainbow), "PolyCopyNodeContents given wrong dest node type");
19111 
19112     if (IS_A(pNodeCopy, AttrFillEffectAltRainbow))
19113         CopyNodeContents((AttrFillEffectAltRainbow*)pNodeCopy);
19114 }
19115 
19116 
19117 
19118 /********************************************************************************************
19119 
19120 >   virtual UINT32 AttrFillEffectAltRainbow::GetNodeSize() const
19121 
19122     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19123     Created:    23/8/94
19124     Returns:    The size of the node in bytes
19125     Purpose:    For finding the size of the node 
19126     SeeAlso:    Node::GetSubtreeSize
19127 
19128 ********************************************************************************************/
19129 
19130 UINT32 AttrFillEffectAltRainbow::GetNodeSize() const 
19131 {     
19132     return (sizeof(AttrFillEffectAltRainbow)); 
19133 }  
19134 
19135 
19136 
19137 /********************************************************************************************
19138 
19139   > virtual BOOL AttrFillEffectAltRainbow::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19140 
19141     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
19142     Created:    30/5/96
19143     Inputs:     pFilter = ptr to the filter
19144     Returns:    TRUE if record is written, FALSE if not
19145     Purpose:    Writes the alt rainbow fill effect record to the filter
19146     SeeAlso:    -
19147 
19148 ********************************************************************************************/
19149 
19150 BOOL AttrFillEffectAltRainbow::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19151 {
19152 #ifdef DO_EXPORT
19153     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
19154 
19155     CamelotFileRecord Rec(pFilter,TAG_FILLEFFECT_ALTRAINBOW,TAG_FILLEFFECT_ALTRAINBOW_SIZE);
19156     return pFilter->Write(&Rec);
19157 #else
19158     return FALSE;
19159 #endif
19160 }
19161 
19162 //--------------------------------------------------------------
19163 // See AttrFillEffectAltRainbow::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19164 //
19165 BOOL AttrFillEffectAltRainbow::WritePreChildrenNative(BaseCamelotFilter* pFilter)
19166 {
19167 #ifdef DO_EXPORT
19168     return WritePreChildrenWeb(pFilter);
19169 #else
19170     return FALSE;
19171 #endif
19172 }
19173 
19174 /********************************************************************************************
19175 
19176 >   INT32 AttrTranspFillMapping::operator==(const NodeAttribute& Attrib)
19177 
19178     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19179     Created:    23/8/94
19180     Inputs:     Attrib - the attribute to compare, which must be an AttrTranspFillMappingLinear 
19181     Returns:    Usual semantics for equality.
19182     Purpose:    A virtual comparison operator. See NodeAttribute::operator== for 
19183                 a description of why it's required. 
19184     Errors:     An ERROR3IF failure will occur if Attrib does not have a AttrTranspFillMappingLinear 
19185                 runtime class.
19186     SeeAlso:    NodeAttribute::operator==
19187 
19188 ********************************************************************************************/
19189 
19190 INT32 AttrTranspFillMapping::operator==(const NodeAttribute& Attrib)
19191 {
19192     ERROR3IF(!Attrib.IsKindOf(CC_RUNTIME_CLASS(AttrTranspFillMapping)), 
19193                 "Trying to compare two objects with different types"); 
19194 
19195     return (GetRepeat() == ((AttrTranspFillMapping*)&Attrib)->GetRepeat());
19196 }
19197 
19198 /********************************************************************************************
19199 
19200 >   virtual NodeAttribute* AttrTranspFillMapping::GetOtherAttrToApply(BOOL* IsMutate)
19201 
19202     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19203     Created:    17/8/95
19204     Returns:    The secondary attribute to apply, or NULL if none to apply
19205     Purpose:    Some attributes require a secondary atribute to be changed when they are
19206                 changed.  This routine obtains a pointer to the secondary attribute to
19207                 apply.
19208 
19209 ********************************************************************************************/
19210 
19211 NodeAttribute* AttrTranspFillMapping::GetOtherAttrToApply(BOOL* IsMutate)
19212 {
19213 #if !defined(EXCLUDE_FROM_RALPH)
19214     ERROR3IF(IsMutate == NULL, "NULL flag pointer passed to GetOtherAttrToApply");
19215 
19216     // If the fill mapping is changing, then we must make sure that
19217     // any fractal tileable flags are updated
19218     
19219     NodeAttribute* OtherAttr = new AttrFractalTileableChange;
19220     if (OtherAttr == NULL)
19221         return NULL;
19222 
19223     ((AttrValueChange*)OtherAttr)->MutateTranspFills(TRUE);
19224 
19225     INT32 Repeat = GetRepeat();
19226     BOOL Tile;
19227 
19228     switch (Repeat)
19229     {
19230         case RT_Simple:
19231             Tile = FALSE;
19232             break;
19233 
19234         case RT_Repeating:
19235             Tile = TRUE;
19236             break;
19237 
19238         case RT_RepeatInverted:
19239             Tile = FALSE;
19240             break;
19241 
19242         default:
19243             Tile = TRUE;
19244             break;
19245     }
19246 
19247     ((AttrValueChange*)OtherAttr)->SetTileable(Tile);
19248 
19249     *IsMutate = TRUE;
19250 
19251     return OtherAttr;
19252 #else
19253     return NULL;
19254 #endif
19255 }
19256 
19257 /********************************************************************************************
19258 
19259 >   void AttrTranspFillMappingLinear::Render( RenderRegion* pRender)
19260 
19261     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19262     Created:    23/8/94
19263     Purpose:    'Renders' a linear graduation FillTransp mapping attribute.
19264 
19265 ********************************************************************************************/
19266 
19267 void AttrTranspFillMappingLinear::Render( RenderRegion* pRender)
19268 {
19269     pRender->SetTranspFillMapping(&Value, FALSE);
19270 }
19271 
19272 
19273 /********************************************************************************************
19274 
19275 > Node* AttrTranspFillMappingLinear::SimpleCopy() 
19276 
19277     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19278     Created:    23/8/94
19279     Returns:    A copy of the node, or NULL if memory runs out 
19280     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
19281                 The function is virtual, and must be defined for all derived classes.  
19282     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
19283                 memory error and the function returns NULL. 
19284     Scope:      protected       
19285 
19286 ********************************************************************************************/
19287      
19288 Node* AttrTranspFillMappingLinear::SimpleCopy()
19289 {
19290     AttrTranspFillMappingLinear* NodeCopy = new AttrTranspFillMappingLinear;
19291     if (NodeCopy == NULL)
19292         return NULL;
19293 
19294     CopyNodeContents(NodeCopy);
19295     
19296     return NodeCopy;
19297 }  
19298 
19299 /********************************************************************************************
19300 
19301 >   virtual UINT32 AttrTranspFillMappingLinear::GetAttrNameID(void)  
19302 
19303     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19304     Created:    23/8/94
19305     Returns:    Attribute description ID
19306     Purpose:    Returns a string resource ID describing the attribute
19307 
19308 ********************************************************************************************/
19309 
19310 UINT32 AttrTranspFillMappingLinear::GetAttrNameID(void)  
19311 {
19312     return (_R(IDS_FILLMAPPINGLINEAR)); 
19313 }                                  
19314 
19315 
19316 /********************************************************************************************
19317 
19318 >   BOOL AttrTranspFillMappingLinear::CopyNodeContents(AttrTranspFillMappingLinear* NodeCopy)
19319 
19320     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19321     Created:    23/8/94
19322     Inputs:     NodeCopy - the node to copy.
19323     Outputs:    A copy of this node
19324     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
19325     Errors:     An assertion failure will occur if NodeCopy is NULL
19326     Scope:      protected
19327                                      
19328 ********************************************************************************************/
19329 
19330 BOOL AttrTranspFillMappingLinear::CopyNodeContents(AttrTranspFillMappingLinear* NodeCopy)
19331 {
19332     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrTranspFillMappingLinear::CopyNodeContents!");
19333 
19334     NodeAttribute::CopyNodeContents(NodeCopy);
19335 
19336     // Copy contents specific to derived class here
19337     NodeCopy->Value.SimpleCopy(&Value);
19338     return TRUE;
19339 } 
19340 
19341 
19342 /***********************************************************************************************
19343 >   void AttrTranspFillMappingLinear::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19344 
19345     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
19346     Created:    18/12/2003
19347     Outputs:    -
19348     Purpose:    Polymorphically copies the contents of this node to another
19349     Errors:     An assertion failure will occur if NodeCopy is NULL
19350     Scope:      protected
19351                                      
19352 ***********************************************************************************************/
19353 
19354 void AttrTranspFillMappingLinear::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19355 {
19356     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
19357     ENSURE(IS_A(pNodeCopy, AttrTranspFillMappingLinear), "PolyCopyNodeContents given wrong dest node type");
19358 
19359     if (IS_A(pNodeCopy, AttrTranspFillMappingLinear))
19360         CopyNodeContents((AttrTranspFillMappingLinear*)pNodeCopy);
19361 }
19362 
19363 
19364 
19365 /********************************************************************************************
19366 
19367 >   virtual UINT32 AttrTranspFillMappingLinear::GetNodeSize() const
19368 
19369     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19370     Created:    23/8/94
19371     Returns:    The size of the node in bytes
19372     Purpose:    For finding the size of the node 
19373     SeeAlso:    Node::GetSubtreeSize
19374 
19375 ********************************************************************************************/
19376 
19377 UINT32 AttrTranspFillMappingLinear::GetNodeSize() const 
19378 {     
19379     return (sizeof(AttrTranspFillMappingLinear)); 
19380 }  
19381 
19382 
19383 
19384 /********************************************************************************************
19385 
19386   > virtual BOOL AttrTranspFillMappingLinear::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19387 
19388     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
19389     Created:    30/5/96
19390     Inputs:     pFilter = ptr to the filter
19391     Returns:    TRUE if record is written, FALSE if not
19392     Purpose:    Writes the linear fill mapping record to the filter
19393     SeeAlso:    -
19394 
19395 ********************************************************************************************/
19396 
19397 BOOL AttrTranspFillMappingLinear::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19398 {
19399 #ifdef DO_EXPORT
19400     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
19401 
19402     UINT32 Tag = TAG_UNDEFINED, TagSize = 1;
19403     switch (Value.Repeat)
19404     {
19405         case 0 :
19406         case 1 :    Tag     = TAG_TRANSPARENTFILL_NONREPEATING;
19407                     TagSize = TAG_TRANSPARENTFILL_NONREPEATING_SIZE;
19408                     break;
19409         case 2 :    Tag     = TAG_TRANSPARENTFILL_REPEATING;
19410                     TagSize = TAG_TRANSPARENTFILL_REPEATING_SIZE;
19411                     break;
19412         case 3 :    Tag     = TAG_TRANSPARENTFILL_REPEATINGINVERTED;
19413                     TagSize = TAG_TRANSPARENTFILL_REPEATINGINVERTED_SIZE;
19414                     break;
19415     //Mark Howitt. 8/10/97. (well actually Chris Snook - 8/12/99); cause we need to do it here
19416     //as well - Make repeating grad fills a special case
19417 #ifdef NEW_FEATURES
19418         case 4 :    Tag     = TAG_TRANSPARENTFILL_REPEATING_EXTRA;
19419                     TagSize = TAG_TRANSPARENTFILL_REPEATING_EXTRA_SIZE;
19420                     break;
19421 #endif
19422 
19423         default:
19424             ERROR3("Unknown repeat type in this fill mapping attr");
19425             return FALSE;
19426             break;
19427     }
19428 
19429     CamelotFileRecord Rec(pFilter,Tag,TagSize);
19430     return pFilter->Write(&Rec);
19431 #else
19432     return FALSE;
19433 #endif
19434 }
19435 
19436 //--------------------------------------------------------------
19437 // See AttrTranspFillMappingLinear::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19438 //
19439 BOOL AttrTranspFillMappingLinear::WritePreChildrenNative(BaseCamelotFilter* pFilter)
19440 {
19441 #ifdef DO_EXPORT
19442     return WritePreChildrenWeb(pFilter);
19443 #else
19444     return FALSE;
19445 #endif
19446 }
19447 
19448 
19449 /********************************************************************************************
19450 >   BOOL AttrTranspFillMappingLinear::HasEquivalentDefaultValue(BOOL bAppearance = FALSE)
19451 
19452     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
19453     Created:    28/09/2005
19454     Inputs:     -
19455     Outputs:    -
19456     Returns:    TRUE if this node has a value equivalent to the relevant 
19457                 FALSE otherwise
19458     Purpose:    Determine whether this attribute has the default value or not
19459     Errors:     -
19460     SeeAlso:    -
19461 ********************************************************************************************/
19462 
19463 BOOL AttrTranspFillMappingLinear::HasEquivalentDefaultValue(BOOL bAppearance)
19464 {
19465     return (Value.Repeat==2);
19466 }
19467 
19468 
19469 
19470 
19471 /********************************************************************************************
19472 
19473 >   void AttrTranspFillMappingSin::Render( RenderRegion* pRender)
19474 
19475     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19476     Created:    23/8/94
19477     Purpose:    'Renders' a sinusoidal graduation FillTransp mapping attribute.
19478 
19479 ********************************************************************************************/
19480 
19481 void AttrTranspFillMappingSin::Render( RenderRegion* pRender)
19482 {
19483     pRender->SetTranspFillMapping(&Value, FALSE);
19484 }
19485 
19486 /********************************************************************************************
19487 
19488 > Node* AttrTranspFillMappingSin::SimpleCopy() 
19489 
19490     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19491     Created:    23/8/94
19492     Returns:    A copy of the node, or NULL if memory runs out 
19493     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
19494                 The function is virtual, and must be defined for all derived classes.  
19495     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
19496                 memory error and the function returns NULL. 
19497     Scope:      protected       
19498 
19499 ********************************************************************************************/
19500      
19501 Node* AttrTranspFillMappingSin::SimpleCopy()
19502 {
19503     AttrTranspFillMappingSin* NodeCopy = new AttrTranspFillMappingSin();
19504     if (NodeCopy == NULL)
19505         return NULL;
19506 
19507     CopyNodeContents(NodeCopy);
19508     
19509     return NodeCopy;
19510 }  
19511 
19512 /********************************************************************************************
19513 
19514 >   virtual UINT32 AttrTranspFillMappingSin::GetAttrNameID(void)  
19515 
19516     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19517     Created:    23/8/94
19518     Returns:    Attribute description ID
19519     Purpose:    Returns a string resource ID describing the attribute
19520 
19521 ********************************************************************************************/
19522 
19523 UINT32 AttrTranspFillMappingSin::GetAttrNameID(void)  
19524 {
19525     return (_R(IDS_FILLMAPPINGSIN)); 
19526 }                                  
19527 
19528 
19529 /********************************************************************************************
19530 
19531 >   BOOL AttrTranspFillMappingSin::CopyNodeContents(AttrTranspFillMappingSin* NodeCopy)
19532 
19533     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19534     Created:    23/8/94
19535     Inputs:     NodeCopy - the node to copy.
19536     Outputs:    A copy of this node
19537     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
19538     Errors:     An assertion failure will occur if NodeCopy is NULL
19539     Scope:      protected
19540                                      
19541 ********************************************************************************************/
19542 
19543 BOOL AttrTranspFillMappingSin::CopyNodeContents(AttrTranspFillMappingSin* NodeCopy)
19544 {
19545     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrTranspFillMappingSin::CopyNodeContents!");
19546 
19547     NodeAttribute::CopyNodeContents(NodeCopy);
19548 
19549     // Copy contents specific to derived class here
19550     NodeCopy->Value.SimpleCopy(&Value);
19551     return TRUE;
19552 } 
19553 
19554 
19555 /***********************************************************************************************
19556 >   void AttrTranspFillMappingSin::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19557 
19558     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
19559     Created:    18/12/2003
19560     Outputs:    -
19561     Purpose:    Polymorphically copies the contents of this node to another
19562     Errors:     An assertion failure will occur if NodeCopy is NULL
19563     Scope:      protected
19564                                      
19565 ***********************************************************************************************/
19566 
19567 void AttrTranspFillMappingSin::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19568 {
19569     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
19570     ENSURE(IS_A(pNodeCopy, AttrTranspFillMappingSin), "PolyCopyNodeContents given wrong dest node type");
19571 
19572     if (IS_A(pNodeCopy, AttrTranspFillMappingSin))
19573         CopyNodeContents((AttrTranspFillMappingSin*)pNodeCopy);
19574 }
19575 
19576 
19577 
19578 /********************************************************************************************
19579 
19580 >   virtual UINT32 AttrTranspFillMappingSin::GetNodeSize() const
19581 
19582     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19583     Created:    23/8/94
19584     Returns:    The size of the node in bytes
19585     Purpose:    For finding the size of the node 
19586     SeeAlso:    Node::GetSubtreeSize
19587 
19588 ********************************************************************************************/
19589 
19590 UINT32 AttrTranspFillMappingSin::GetNodeSize() const 
19591 {     
19592     return (sizeof(AttrTranspFillMappingSin)); 
19593 }  
19594 
19595 
19596 
19597 
19598 
19599 
19600 /********************************************************************************************
19601 
19602   > virtual BOOL AttrTranspFillMappingSin::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19603 
19604     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
19605     Created:    30/5/96
19606     Inputs:     pFilter = ptr to the filter
19607     Returns:    TRUE if record is written, FALSE if not
19608     Purpose:    Writes the transparent sine fill mapping record to the filter
19609     SeeAlso:    -
19610 
19611 ********************************************************************************************/
19612 
19613 BOOL AttrTranspFillMappingSin::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19614 {
19615 #ifdef DO_EXPORT
19616     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
19617 
19618     ERROR3("v2 file format does not support this attribute");
19619     return FALSE;
19620 #else
19621     return FALSE;
19622 #endif
19623 }
19624 
19625 //--------------------------------------------------------------
19626 // See AttrTranspFillMappingSin::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
19627 //
19628 BOOL AttrTranspFillMappingSin::WritePreChildrenNative(BaseCamelotFilter* pFilter)
19629 {
19630 #ifdef DO_EXPORT
19631     return WritePreChildrenWeb(pFilter);
19632 #else
19633     return FALSE;
19634 #endif
19635 }
19636 
19637 
19638 /********************************************************************************************
19639 
19640 >   AttrMould::AttrMould(NodeMould* pMould, MouldGeometry* pMouldShape)
19641 
19642     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19643     Created:    03/02/94
19644     Inputs:     pMould - the Mould to associate with this attribute
19645     Purpose:    Constructor for Mould attribute.
19646 
19647 ********************************************************************************************/
19648 
19649 AttrMould::AttrMould(NodeMould* pMould, MouldGeometry* pMouldShape)
19650 {
19651     SetParentMould(pMould);
19652     SetMouldShape(pMouldShape);
19653 }
19654 
19655 /********************************************************************************************
19656 
19657 >   INT32 AttrMould::operator==(const NodeAttribute& Attrib)
19658 
19659     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19660     Created:    23/8/94
19661     Inputs:     Attrib - the attribute to compare, which must be an AttrMouldLinear 
19662     Returns:    Usual semantics for equality.
19663     Purpose:    A virtual comparison operator. See NodeAttribute::operator== for 
19664                 a description of why it's required. 
19665     Errors:     An ERROR3IF failure will occur if Attrib does not have a AttrMouldLinear 
19666                 runtime class.
19667     SeeAlso:    NodeAttribute::operator==
19668 
19669 ********************************************************************************************/
19670 
19671 INT32 AttrMould::operator==(const NodeAttribute& Attrib)
19672 {
19673     ERROR3IF(!Attrib.IsKindOf(CC_RUNTIME_CLASS(AttrMould)), 
19674                 "Trying to compare two objects with different types"); 
19675 
19676     return (GetParentMould() == ((AttrMould*)&Attrib)->GetParentMould());
19677 }
19678 
19679 /********************************************************************************************
19680 
19681 >   void AttrMould::Render( RenderRegion* pRender)
19682 
19683     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19684     Created:    23/8/94
19685     Purpose:    'Renders' a Mould attribute.
19686 
19687 ********************************************************************************************/
19688 
19689 void AttrMould::Render( RenderRegion* pRender)
19690 {
19691 //  pRender->SetMould(&Value, FALSE);
19692 }
19693 
19694 /********************************************************************************************
19695 
19696 > Node* AttrMould::SimpleCopy() 
19697 
19698     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19699     Created:    23/8/94
19700     Returns:    A copy of the node, or NULL if memory runs out 
19701     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
19702                 The function is virtual, and must be defined for all derived classes.  
19703     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of 
19704                 memory error and the function returns NULL. 
19705     Scope:      protected       
19706 
19707 ********************************************************************************************/
19708      
19709 Node* AttrMould::SimpleCopy()
19710 {
19711     AttrMould* NodeCopy = new AttrMould;
19712     if (NodeCopy == NULL)
19713         return NULL;
19714 
19715     CopyNodeContents(NodeCopy);
19716     
19717     return NodeCopy;
19718 }  
19719 
19720 /********************************************************************************************
19721 
19722 >   virtual UINT32 AttrMould::GetAttrNameID(void)  
19723 
19724     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19725     Created:    23/8/94
19726     Returns:    Attribute description ID
19727     Purpose:    Returns a string resource ID describing the attribute
19728 
19729 ********************************************************************************************/
19730 
19731 UINT32 AttrMould::GetAttrNameID(void)  
19732 {
19733     return (_R(IDS_ATTRMOULD)); 
19734 }                                  
19735 
19736 /********************************************************************************************
19737 
19738 >   BOOL AttrMould::CopyNodeContents(AttrMould* NodeCopy)
19739 
19740     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19741     Created:    23/8/94
19742     Inputs:     NodeCopy - the node to copy.
19743     Outputs:    A copy of this node
19744     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
19745     Errors:     An assertion failure will occur if NodeCopy is NULL
19746     Scope:      protected
19747                                      
19748 ********************************************************************************************/
19749 
19750 BOOL AttrMould::CopyNodeContents(AttrMould* NodeCopy)
19751 {
19752     ERROR2IF(NodeCopy == NULL, FALSE, "NULL pointer in AttrMould::CopyNodeContents!");
19753 
19754     NodeAttribute::CopyNodeContents(NodeCopy);
19755 
19756     // Copy contents specific to derived class here
19757     NodeCopy->Value.SimpleCopy(&Value);
19758     return TRUE;
19759 } 
19760 
19761 /***********************************************************************************************
19762 >   void AttrMould::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19763 
19764     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
19765     Created:    18/12/2003
19766     Outputs:    -
19767     Purpose:    Polymorphically copies the contents of this node to another
19768     Errors:     An assertion failure will occur if NodeCopy is NULL
19769     Scope:      protected
19770                                      
19771 ***********************************************************************************************/
19772 
19773 void AttrMould::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
19774 {
19775     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
19776     ENSURE(IS_A(pNodeCopy, AttrMould), "PolyCopyNodeContents given wrong dest node type");
19777 
19778     if (IS_A(pNodeCopy, AttrMould))
19779         CopyNodeContents((AttrMould*)pNodeCopy);
19780 }
19781 
19782 
19783 
19784 /********************************************************************************************
19785 
19786 >   virtual UINT32 AttrMould::GetNodeSize() const
19787 
19788     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
19789     Created:    23/8/94
19790     Returns:    The size of the node in bytes
19791     Purpose:    For finding the size of the node 
19792     SeeAlso:    Node::GetSubtreeSize
19793 
19794 ********************************************************************************************/
19795 
19796 UINT32 AttrMould::GetNodeSize() const 
19797 {     
19798     return (sizeof(AttrMould)); 
19799 }  
19800 
19801 
19802 
19803 
19804 /********************************************************************************************
19805 
19806             Blending Bits
19807 
19808 ********************************************************************************************/
19809 
19810 BOOL AttrFillGeometry::Blend(BlendAttrParam* pBlendParam)
19811 {
19812     // Check entry param isn't NULL
19813     ERROR3IF(pBlendParam == NULL,"NULL entry param");
19814     if (pBlendParam == NULL) return FALSE;
19815 
19816     // Get the Value member to blend to the Value member of the other NodeAttribute.
19817     // If it succeeds, ask the blended Value to make a NodeAttribute out of itself.
19818 
19819     if (GetAttributeValue()->Blend(pBlendParam))
19820     {
19821         // Get the blended attr val. After this call, the ptr is our reponsibility
19822         // so we have to delete it if it's no longer needed
19823         AttributeValue* pBlendedAttrVal = pBlendParam->GetBlendedAttrVal();
19824 
19825         if (pBlendedAttrVal != NULL)
19826         {
19827             // We have a blended attr val, so ask it to make a NodeAttribute out of itself
19828             // and set the pBlendParam's blended NodeAttribute ptr to it
19829             NodeAttribute* pBlendedAttr = pBlendedAttrVal->MakeNode();
19830             pBlendParam->SetBlendedAttr(pBlendedAttr);
19831 
19832             if (pBlendedAttr != NULL)
19833             {
19834                 // We were able to make a blended NodeAttribute
19835                 // so delete the blended attr val, and return TRUE
19836                 delete pBlendedAttrVal;
19837                 return TRUE;
19838             }
19839             else
19840             {
19841                 // Couldn't make a blended NodeAttribute, so give the blended attr val back
19842                 // and return FALSE
19843                 pBlendParam->SetBlendedAttrVal(pBlendedAttrVal);
19844                 return FALSE;
19845             }
19846         }
19847     }
19848 
19849     return FALSE;
19850 }
19851 
19852 
19853 
19854 //===========================================================================================
19855 //
19856 //  Karim MacDonald 08/12/1999
19857 //  Extending Bits
19858 //
19859 //===========================================================================================
19860 
19861 /********************************************************************************************
19862 
19863 >   DocRect AttrFillGeometry::ValidateExtend(const ExtendParams& ExtParams)
19864 
19865     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
19866     Created:    03/12/1999
19867     Inputs:     ExtParams       description parameters for the extension.
19868     Outputs:    
19869     Returns:    TRUE    if this fill is unextendible (it is not graduated), or if it may be
19870                         reversible extended.
19871                 FALSE   otherwise.
19872     Purpose:    Determine whether applying an extend to this Node is a reversible process.
19873     Errors:     
19874     See also:   class Extender; IsTypeExtendible(); Extend()
19875 
19876 ********************************************************************************************/
19877 DocRect AttrFillGeometry::ValidateExtend(const ExtendParams& ExtParams)
19878 {
19879     // quit immediately with all-clear if we are not a graduated fill.
19880     if (!IsAGradFill())
19881         return DocRect(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX);
19882 
19883     // construct an array of the fill's handles.
19884     INT32 i = 0;
19885     DocCoord doccHandles[3];
19886     DocCoord* pDocc = GetStartPoint();
19887     if (pDocc != NULL)
19888         doccHandles[i ++] = *pDocc;
19889 
19890     pDocc = GetEndPoint();
19891     if (pDocc != NULL)
19892         doccHandles[i ++] = *pDocc;
19893 
19894     pDocc = GetEndPoint2();
19895     if (pDocc != NULL)
19896         doccHandles[i ++] = *pDocc;
19897 
19898     // validate our array of fill handles.
19899     // don't bother checking children - attributes don't have any.
19900     INT32 numPoints = GetNumberOfControlPoints();
19901     return Extender::ValidateControlPoints(numPoints, doccHandles, ExtParams);
19902 }
19903 
19904 
19905 
19906 /********************************************************************************************
19907 
19908 >   void AttrFillGeometry::Extend(const ExtendParams& ExtParams)
19909 
19910     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
19911     Created:    03/12/1999
19912     Inputs:     ExtParams       description parameters for the extension.
19913     Outputs:    This fill node may have its dimensions altered by the extension.
19914     Returns:    
19915     Purpose:    Perform an extend operation on this fill node.
19916     Errors:     
19917     See also:   class Extender; IsTypeExtendible(); Extend()
19918 
19919 ********************************************************************************************/
19920 void AttrFillGeometry::Extend(const ExtendParams& ExtParams)
19921 {
19922     // quit immediately if we are not a graduated fill.
19923     if (!IsAGradFill())
19924         return;
19925 
19926     // we only need to do the extend operation, as whatever we're applied to
19927     // takes care of translating/stretching us.
19928     Node* pParent = FindParent();
19929     if (pParent != NULL)
19930         if (pParent->IsNodePath() || pParent->IsCompound())
19931             TransformTranslateObject(ExtParams);
19932 }
19933 
19934 
19935 
19936 /********************************************************************************************
19937 
19938 >   virtual void AttrFillGeometry::TransformTranslateObject(const ExtendParams& ExtParams)
19939 
19940     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
19941     Created:    01/12/1999
19942     Inputs:     ExtParams       description of how this path should extend.
19943     Outputs:    This path's control points may be extended, depending on ExtParams' flags.
19944     Purpose:    Do an extend (as opposed to stretch) operation on this fill, using ExtParams
19945                 as the source of the extend data, together with the extend-centre of this
19946                 path, defined in NodeRenderable::FindExtendCentre() and overridden here also.
19947 
19948                 Because whatever we're applied to has already translated us by ExtParams'
19949                 doccOffset parameter, we usually skip that particular step in the process,
19950                 with the exception of our parent being a group, in which case it won't have
19951                 applied any transformation directly to us.
19952 
19953                 This function does nothing unless ExtParams uses X_EXTEND or Y_EXTEND.
19954     See also:   The Extender class; FindExtendCentre().
19955 
19956 ********************************************************************************************/
19957 void AttrFillGeometry::TransformTranslateObject(const ExtendParams& ExtParams)
19958 {
19959     // construct an array of the fill's handles.
19960     INT32 pointIndex = 0;
19961     DocCoord* doccpHandles[3];
19962     DocCoord* pDocc = GetStartPoint();
19963     if (pDocc != NULL)
19964         doccpHandles[pointIndex ++] = pDocc;
19965 
19966     pDocc = GetEndPoint();
19967     if (pDocc != NULL)
19968         doccpHandles[pointIndex ++] = pDocc;
19969 
19970     pDocc = GetEndPoint2();
19971     if (pDocc != NULL)
19972         doccpHandles[pointIndex ++] = pDocc;
19973 
19974     INT32 numPoints = GetNumberOfControlPoints();
19975 
19976     // x-extension behaviour.
19977     if (ExtParams.fExtendFlags & X_EXTEND)
19978     {
19979         // if our parent is a group, then it won't have applied any offset parameter to us,
19980         // so we need to do this ourself.
19981         Node* pParent = FindParent();
19982         if (pParent != NULL && pParent->IsCompound())
19983         {
19984             Trans2DMatrix baseXoffset(ExtParams.doccOffset.x, 0);
19985             Transform(baseXoffset);
19986         }
19987 
19988         for (INT32 i = 0; i < numPoints; i ++)
19989         {
19990             if (doccpHandles[i]->x > ExtParams.doccEndCentre.x + ExtParams.xincExtendBuffer)
19991                 doccpHandles[i]->x += ExtParams.xinc;
19992             else if (doccpHandles[i]->x < ExtParams.doccEndCentre.x - ExtParams.xdecExtendBuffer)
19993                 doccpHandles[i]->x -= ExtParams.xdec;
19994         }
19995     }
19996 
19997     // y-extension behaviour.
19998     if (ExtParams.fExtendFlags & Y_EXTEND)
19999     {
20000         // if our parent is a group, then it won't have applied any offset parameter to us,
20001         // so we need to do this ourself.
20002         Node* pParent = FindParent();
20003         if (pParent != NULL && pParent->IsCompound())
20004         {
20005             Trans2DMatrix baseYoffset(0, ExtParams.doccOffset.y);
20006             Transform(baseYoffset);
20007         }
20008 
20009         for (INT32 i = 0; i < numPoints; i ++)
20010         {
20011             if (doccpHandles[i]->y > ExtParams.doccEndCentre.y + ExtParams.yincExtendBuffer)
20012                 doccpHandles[i]->y += ExtParams.yinc;
20013             else if (doccpHandles[i]->y < ExtParams.doccEndCentre.y - ExtParams.ydecExtendBuffer)
20014                 doccpHandles[i]->y -= ExtParams.ydec;
20015         }
20016     }
20017 
20018     // doing this should cause the fourth fill point to be reset to a sensible value.
20019     SetEndPoint3(NULL);
20020 }
20021 
20022 
20023 
20024 /********************************************************************************************
20025 
20026 >   void AttrLinearFill::TransformTranslateObject(const ExtendParams& ExtParams)
20027 
20028     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
20029     Created:    14/11/2000
20030 
20031     Purpose:    Override of AttrFillGeometry::TransformTranslateObject().
20032                 See that method for more info.
20033 
20034     See also:   AttrFillGeometry::TransformTranslateObject()
20035 
20036 ********************************************************************************************/
20037 void AttrLinearFill::TransformTranslateObject(const ExtendParams& ExtParams)
20038 {
20039     // call our base class to do the major extending stuff.
20040     AttrFillGeometry::TransformTranslateObject(ExtParams);
20041 
20042     // ok, after the extend, our third control point is a bit skew-wiff,
20043     // so we need to wack it back in line - done by this (deceptively) simple call.
20044     SetEndPoint2(NULL);
20045 }
20046 
20047 
20048 
20049 /********************************************************************************************
20050 
20051 >   void AttrRadialFill::TransformTranslateObject(const ExtendParams& ExtParams)
20052 
20053     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
20054     Created:    14/11/2000
20055 
20056     Purpose:    Override of AttrFillGeometry::TransformTranslateObject().
20057                 See that method for more info.
20058 
20059     See also:   AttrFillGeometry::TransformTranslateObject()
20060 
20061 ********************************************************************************************/
20062 void AttrRadialFill::TransformTranslateObject(const ExtendParams& ExtParams)
20063 {
20064     // call our base class to do the major extending stuff.
20065     AttrFillGeometry::TransformTranslateObject(ExtParams);
20066 
20067     // if we're a circle, then the extend has left our third control point
20068     // hanging in the air, so we need to pull it back down to earth...
20069     if (IsCircular())
20070     {
20071         DocCoord Start  = *GetStartPoint();
20072         DocCoord End1   = *GetEndPoint();
20073         DocCoord End2   = MakeLineAtAngle(Start, End1, 90, (INT32)Start.Distance(End1));
20074         SetEndPoint2(&End2);
20075     }
20076 }
20077 
20078 
20079 
20080 /*
20081     Transparency mode-change stuff.
20082 */
20083 
20084 /********************************************************************************************
20085 >   virtual BOOL AttrFlatTranspFill::NeedsTransparency() const
20086 
20087     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
20088     Created:    6/1/95
20089     Inputs:     -
20090     Outputs:    -
20091     Returns:    TRUE if this node requires transparency mode to render properly.
20092     Purpose:    Called 
20093     Errors:     -
20094     SeeAlso:    Node::AttachNode
20095 ********************************************************************************************/
20096 
20097 BOOL AttrFlatTranspFill::NeedsTransparency() const
20098 {
20099     AttrFlatTranspFill* pNonConst = (AttrFlatTranspFill*) this;
20100     return pNonConst->GetTranspType() != TT_Mix || *(pNonConst->GetStartTransp()) != 0;
20101 }
20102 
20103 
20104 
20105 /********************************************************************************************
20106 >   virtual BOOL AttrLinearTranspFill::NeedsTransparency() const
20107 
20108     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
20109     Created:    6/1/95
20110     Inputs:     -
20111     Outputs:    -
20112     Returns:    TRUE if this node requires transparency mode to render properly.
20113     Purpose:    Called 
20114     Errors:     -
20115     SeeAlso:    Node::AttachNode
20116 ********************************************************************************************/
20117 
20118 BOOL AttrLinearTranspFill::NeedsTransparency() const
20119 {
20120     AttrLinearTranspFill* pNonConst = (AttrLinearTranspFill*) this;
20121     return (    pNonConst->GetTranspType()      != TT_Mix ||
20122                 *(pNonConst->GetStartTransp())  != 0 ||
20123                 *(pNonConst->GetEndTransp())    != 0 );
20124 }
20125 
20126 
20127 
20128 /********************************************************************************************
20129 >   virtual BOOL AttrRadialTranspFill::NeedsTransparency() const
20130 
20131     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
20132     Created:    6/1/95
20133     Inputs:     -
20134     Outputs:    -
20135     Returns:    TRUE if this node requires transparency mode to render properly.
20136     Purpose:    Called 
20137     Errors:     -
20138     SeeAlso:    Node::AttachNode
20139 ********************************************************************************************/
20140 
20141 BOOL AttrRadialTranspFill::NeedsTransparency() const
20142 {
20143     AttrRadialTranspFill* pNonConst = (AttrRadialTranspFill*) this;
20144     return (    pNonConst->GetTranspType()      != TT_Mix ||
20145                 *(pNonConst->GetStartTransp())  != 0 ||
20146                 *(pNonConst->GetEndTransp())    != 0 );
20147 }
20148 
20149 
20150 
20151 /********************************************************************************************
20152 >   virtual BOOL AttrConicalTranspFill::NeedsTransparency() const
20153 
20154     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
20155     Created:    6/1/95
20156     Inputs:     -
20157     Outputs:    -
20158     Returns:    TRUE if this node requires transparency mode to render properly.
20159     Purpose:    Called 
20160     Errors:     -
20161     SeeAlso:    Node::AttachNode
20162 ********************************************************************************************/
20163 
20164 BOOL AttrConicalTranspFill::NeedsTransparency() const
20165 {
20166     AttrConicalTranspFill* pNonConst = (AttrConicalTranspFill*) this;
20167     return (    pNonConst->GetTranspType()      != TT_Mix ||
20168                 *(pNonConst->GetStartTransp())  != 0 ||
20169                 *(pNonConst->GetEndTransp())    != 0 );
20170 }
20171 
20172 
20173 
20174 /********************************************************************************************
20175 >   virtual BOOL AttrBitmapTranspFill::NeedsTransparency() const
20176 
20177     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
20178     Created:    6/1/95
20179     Inputs:     -
20180     Outputs:    -
20181     Returns:    TRUE if this node requires transparency mode to render properly.
20182     Purpose:    Called 
20183     Errors:     -
20184     SeeAlso:    Node::AttachNode
20185 ********************************************************************************************/
20186 
20187 BOOL AttrBitmapTranspFill::NeedsTransparency() const
20188 {
20189     return TRUE;
20190 }
20191 
20192 
20193 
20194 /********************************************************************************************
20195 
20196     FillAttrBlobState::FillAttrBlobState()
20197 
20198     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
20199     Created:    13/3/96
20200     Purpose:    Constructor
20201 
20202 ********************************************************************************************/
20203 
20204 FillAttrBlobState::FillAttrBlobState()
20205 {
20206     count=0;
20207     pFillAttr=NULL;
20208     SelectionState=NULL;
20209 }
20210 
20211 /********************************************************************************************
20212 
20213     FillAttrBlobState::~FillAttrBlobState()
20214 
20215     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
20216     Created:    13/3/96
20217     Purpose:    Destruct this object. If the state pointer is not null delete it.
20218 
20219 ********************************************************************************************/
20220 
20221 FillAttrBlobState::~FillAttrBlobState()
20222 {
20223     if (SelectionState!=NULL)
20224     {
20225         free(SelectionState);
20226         SelectionState=NULL;
20227     }
20228 }
20229 
20230 
20231 /********************************************************************************************
20232 
20233 >   BOOL FillAttrBlobState::operator==(FillAttrBlobState& BlobState)
20234 
20235     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
20236     Created:    13/3/96
20237     Returns:    TRUE if the blobs states are the same
20238     Purpose:    Compares two blob states to see if they are the same
20239 
20240 ********************************************************************************************/
20241 
20242 BOOL FillAttrBlobState::operator==(FillAttrBlobState& BlobState)
20243 {
20244     if (pFillAttr != BlobState.pFillAttr)
20245         return FALSE;
20246 
20247     if (count != BlobState.count)
20248         return FALSE;
20249 
20250     if (pFillAttr != NULL)
20251     {
20252         if (SelectionState==NULL || BlobState.SelectionState==NULL)
20253             return FALSE;
20254 
20255         for (UINT32 i=0; i<count; i++)
20256         {
20257             if (SelectionState[i] != BlobState.SelectionState[i])
20258                 return FALSE;
20259         }
20260     }
20261     
20262     return TRUE;
20263 }
20264 
20265 /********************************************************************************************
20266 
20267 >   FillBlobSelectionState::FillBlobSelectionState()
20268 
20269     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
20270     Created:    13/3/96
20271     Purpose:    Constructor for the blob selection state record class
20272 
20273 ********************************************************************************************/
20274 
20275 FillBlobSelectionState::FillBlobSelectionState()
20276 {
20277     BlobCount = 0;
20278     FillType = NULL;
20279 }
20280 
20281 /********************************************************************************************
20282 
20283 >   FillBlobSelectionState::~FillBlobSelectionState()
20284 
20285     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
20286     Created:    13/3/96
20287     Purpose:    Constructor for the blob selection state record class.
20288                 Deletes all the blob selection states in the list.
20289 
20290 ********************************************************************************************/
20291 
20292 FillBlobSelectionState::~FillBlobSelectionState()
20293 {
20294     BlobStateList.DeleteAll();
20295 }
20296 
20297 /********************************************************************************************
20298 
20299 >   BOOL FillBlobSelectionState::Record()
20300 
20301     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
20302     Created:    13/3/96
20303     Returns:    TRUE if all ok
20304     Purpose:    Makes a record of the current fill blob selection state so it can be
20305                 compared at some later date.
20306 
20307 ********************************************************************************************/
20308 
20309 BOOL FillBlobSelectionState::Record()
20310 {
20311 #if !defined(EXCLUDE_FROM_RALPH)
20312     BlobStateList.DeleteAll();
20313     FillType = NULL;
20314 
20315     if (GetApplication()->GetBlobManager()->GetCurrentInterest().Fill)
20316     {
20317         FillType = AttrFillGeometry::IsColourMeshVisible() ? CC_RUNTIME_CLASS(AttrFillGeometry)
20318                                                            : CC_RUNTIME_CLASS(AttrTranspFillGeometry);
20319 
20320         // Find the first Fill Attribute in the current Selection
20321         AttrFillGeometry* pAttr = AttrFillGeometry::FindFirstSelectedAttr(FillType);
20322 
20323         while (pAttr != NULL)
20324         {
20325             // Count this fill selected control points
20326             // and keep a running total
20327             if (pAttr->IsVisible())
20328             {
20329                 if (pAttr->GetSelectionCount() > 0)
20330                 {
20331                     FillAttrBlobState* pBlobState = new FillAttrBlobState();
20332                     if (pBlobState != NULL)
20333                     {
20334                         pBlobState->pFillAttr = pAttr;
20335                         pBlobState->count = pAttr->GetSelectionState(&(pBlobState->SelectionState));
20336                         BlobStateList.AddTail(pBlobState);
20337                     }
20338                 }
20339             }
20340 
20341             // Move on to the next Fill
20342             pAttr = AttrFillGeometry::FindNextSelectedAttr(FillType);
20343         }
20344     }
20345 #endif
20346     return TRUE;
20347 }
20348 
20349 /********************************************************************************************
20350 
20351 >   BOOL FillBlobSelectionState::operator==(FillBlobSelectionState& SelState)
20352 
20353     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
20354     Created:    13/3/96
20355     Returns:    TRUE if the blobs states are the same
20356     Purpose:    Compares two blob states to see if they are the same
20357 
20358 ********************************************************************************************/
20359 
20360 BOOL FillBlobSelectionState::operator==(FillBlobSelectionState& SelState)
20361 {
20362 #if !defined(EXCLUDE_FROM_RALPH)
20363     // Were the same type of fills visible ?
20364     if (FillType != SelState.FillType)
20365         return FALSE;
20366 
20367     // Were the same number of blobs selected ?
20368     if (BlobCount != SelState.BlobCount)
20369         return FALSE;
20370 
20371     // Were the same fills selected ?
20372     if (BlobStateList.GetCount() != SelState.BlobStateList.GetCount())
20373         return FALSE;
20374 
20375     // So are they *really* identical ?
20376     if (BlobStateList.GetCount() > 0)
20377     {
20378         FillAttrBlobState* pBlobState = (FillAttrBlobState*)BlobStateList.GetHead();
20379         FillAttrBlobState* pOtherBlobState = (FillAttrBlobState*)SelState.BlobStateList.GetHead();
20380 
20381         while (pBlobState != NULL && pOtherBlobState != NULL)
20382         {
20383             if ( !(*pBlobState == *pOtherBlobState) )
20384                 return FALSE;
20385 
20386             pBlobState = (FillAttrBlobState*)BlobStateList.GetNext(pBlobState);
20387             pOtherBlobState = (FillAttrBlobState*)SelState.BlobStateList.GetNext(pOtherBlobState);
20388         }
20389     }
20390 #endif
20391     return TRUE;
20392 }
20393 
20394 //---------------------------------------------------------------------------------------
20395 //---------------------------------------------------------------------------------------
20396 //---------------------------------------------------------------------------------------
20397 
20398 
20399 /********************************************************************************************
20400 
20401 >   virtual UINT32* FillAttrRecordHandler::GetTagList()
20402 
20403     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
20404     Created:    29/5/96
20405     Inputs:     -
20406     Returns:    Ptr to a list of tag values, terminated by CXFRH_TAG_LIST_END
20407     Purpose:    Provides the record handler system with a list of records handled by this
20408                 handler
20409     SeeAlso:    -
20410 
20411 ********************************************************************************************/
20412 
20413 UINT32* FillAttrRecordHandler::GetTagList()
20414 {
20415     static UINT32 TagList[] = { TAG_FLATFILL,
20416                                 TAG_FLATFILL_NONE,
20417                                 TAG_FLATFILL_BLACK,
20418                                 TAG_FLATFILL_WHITE,
20419                                 TAG_LINEARFILL,
20420                                 TAG_LINEARFILL3POINT,
20421                                 TAG_ELLIPTICALFILL,
20422                                 TAG_CIRCULARFILL,
20423                                 TAG_CONICALFILL,
20424                                 TAG_SQUAREFILL,
20425                                 TAG_THREECOLFILL,
20426                                 TAG_FOURCOLFILL,
20427                                 TAG_BITMAPFILL,
20428                                 TAG_CONTONEBITMAPFILL,
20429                                 TAG_FRACTALFILL,
20430                                 TAG_NOISEFILL,
20431 
20432                                 TAG_FLATTRANSPARENTFILL,
20433                                 TAG_LINEARTRANSPARENTFILL,
20434                                 TAG_LINEARTRANSPARENTFILL3POINT,
20435                                 TAG_ELLIPTICALTRANSPARENTFILL,
20436                                 TAG_CIRCULARTRANSPARENTFILL,
20437                                 TAG_CONICALTRANSPARENTFILL,
20438                                 TAG_SQUARETRANSPARENTFILL,
20439                                 TAG_THREECOLTRANSPARENTFILL,
20440                                 TAG_FOURCOLTRANSPARENTFILL,
20441                                 TAG_BITMAPTRANSPARENTFILL,
20442                                 TAG_FRACTALTRANSPARENTFILL,
20443                                 TAG_NOISETRANSPARENTFILL,
20444 
20445                                 TAG_FILL_REPEATING,
20446                                 TAG_FILL_NONREPEATING,
20447                                 TAG_FILL_REPEATINGINVERTED,
20448 //Mark Howitt, 8/10/97. Include repeating grad fills
20449 #ifdef NEW_FEATURES
20450                                 TAG_FILL_REPEATING_EXTRA,
20451                                 TAG_TRANSPARENTFILL_REPEATING_EXTRA,    // Chris Snook (8/12/99)
20452 #endif
20453                                 TAG_TRANSPARENTFILL_REPEATING,
20454                                 TAG_TRANSPARENTFILL_NONREPEATING,
20455                                 TAG_TRANSPARENTFILL_REPEATINGINVERTED,
20456 
20457                                 TAG_FILLEFFECT_ALTRAINBOW,
20458                                 TAG_FILLEFFECT_RAINBOW,
20459                                 TAG_FILLEFFECT_FADE,
20460                                 TAG_LINEARFILLMULTISTAGE,
20461                                 TAG_LINEARFILLMULTISTAGE3POINT,
20462                                 TAG_CIRCULARFILLMULTISTAGE,
20463                                 TAG_ELLIPTICALFILLMULTISTAGE,
20464                                 TAG_CONICALFILLMULTISTAGE,
20465                                 TAG_SQUAREFILLMULTISTAGE,
20466 
20467                                 CXFRH_TAG_LIST_END};
20468 
20469     return (UINT32*)&TagList;
20470 }
20471 
20472 /********************************************************************************************
20473 
20474 >   virtual BOOL FillAttrRecordHandler::HandleRecord(CXaraFileRecord* pCXaraFileRecord)
20475 
20476     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
20477     Created:    29/5/96
20478     Inputs:     pCXaraFileRecord = ptr to record to handle
20479     Returns:    TRUE if handled successfuly
20480                 FALSE otherwise
20481     Purpose:    Handles the given record.
20482     SeeAlso:    -
20483 
20484 ********************************************************************************************/
20485 
20486 BOOL FillAttrRecordHandler::HandleRecord(CXaraFileRecord* pCXaraFileRecord)
20487 {
20488     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
20489 
20490     BOOL ok = TRUE;
20491 
20492     switch (pCXaraFileRecord->GetTag())
20493     {
20494         case TAG_FLATFILL:
20495         case TAG_FLATFILL_NONE:
20496         case TAG_FLATFILL_BLACK:
20497         case TAG_FLATFILL_WHITE:            ok = HandleFlatFillRecord(pCXaraFileRecord);                    break;
20498         
20499         case TAG_LINEARFILL3POINT:
20500         case TAG_LINEARFILL:                ok = HandleLinearFillRecord(pCXaraFileRecord);                  break;
20501         case TAG_LINEARFILLMULTISTAGE3POINT:
20502         case TAG_LINEARFILLMULTISTAGE:      ok = HandleMultiStageLinearFillRecord(pCXaraFileRecord);        break;
20503         case TAG_ELLIPTICALFILL:        
20504         case TAG_CIRCULARFILL:              ok = HandleEllipticalFillRecord(pCXaraFileRecord);              break;
20505         case TAG_ELLIPTICALFILLMULTISTAGE:
20506         case TAG_CIRCULARFILLMULTISTAGE:    ok = HandleMultiStageCircularFillRecord(pCXaraFileRecord);      break;
20507         case TAG_CONICALFILL:               ok = HandleConicalFillRecord(pCXaraFileRecord);                 break;
20508         case TAG_CONICALFILLMULTISTAGE:     ok = HandleMultiStageConicalFillRecord(pCXaraFileRecord);       break;
20509         case TAG_SQUAREFILL:                ok = HandleSquareFillRecord(pCXaraFileRecord);                  break;
20510         case TAG_SQUAREFILLMULTISTAGE:      ok = HandleMultiStageSquareFillRecord(pCXaraFileRecord);        break;
20511         case TAG_THREECOLFILL:              ok = HandleThreeColFillRecord(pCXaraFileRecord);                break;
20512         case TAG_FOURCOLFILL:               ok = HandleFourColFillRecord(pCXaraFileRecord);                 break;
20513         case TAG_BITMAPFILL:            
20514         case TAG_CONTONEBITMAPFILL:         ok = HandleBitmapFillRecord(pCXaraFileRecord);                  break;
20515         case TAG_FRACTALFILL:               ok = HandleFractalFillRecord(pCXaraFileRecord);                 break;
20516         case TAG_NOISEFILL:                 ok = HandleNoiseFillRecord(pCXaraFileRecord);                   break;
20517 
20518         case TAG_FLATTRANSPARENTFILL:       ok = HandleFlatTransparentFillRecord(pCXaraFileRecord);         break;
20519         case TAG_LINEARTRANSPARENTFILL3POINT:
20520         case TAG_LINEARTRANSPARENTFILL:     ok = HandleLinearTransparentFillRecord(pCXaraFileRecord);       break;
20521         case TAG_ELLIPTICALTRANSPARENTFILL:
20522         case TAG_CIRCULARTRANSPARENTFILL:   ok = HandleEllipticalTransparentFillRecord(pCXaraFileRecord);   break;
20523         case TAG_CONICALTRANSPARENTFILL:    ok = HandleConicalTransparentFillRecord(pCXaraFileRecord);      break;
20524         case TAG_SQUARETRANSPARENTFILL:     ok = HandleSquareTransparentFillRecord(pCXaraFileRecord);       break;
20525         case TAG_THREECOLTRANSPARENTFILL:   ok = HandleThreeColTransparentFillRecord(pCXaraFileRecord);     break;
20526         case TAG_FOURCOLTRANSPARENTFILL:    ok = HandleFourColTransparentFillRecord(pCXaraFileRecord);      break;
20527 
20528         case TAG_BITMAPTRANSPARENTFILL:     ok = HandleBitmapTransparentFillRecord(pCXaraFileRecord);       break;
20529         case TAG_FRACTALTRANSPARENTFILL:    ok = HandleFractalTransparentFillRecord(pCXaraFileRecord);      break;
20530         case TAG_NOISETRANSPARENTFILL:      ok = HandleNoiseTransparentFillRecord(pCXaraFileRecord);        break;
20531 
20532         case TAG_FILL_REPEATING:
20533 //Mark Howitt, 7/10/97. using new fill modes
20534 #ifdef NEW_FEATURES
20535         case TAG_FILL_REPEATING_EXTRA:
20536 #endif
20537         case TAG_FILL_NONREPEATING:
20538         case TAG_FILL_REPEATINGINVERTED:            ok = HandleFillRepeatRecord(pCXaraFileRecord);              break;
20539 //Chris Snook, 8/12/99. using new fill modes
20540 #ifdef NEW_FEATURES     
20541         case TAG_TRANSPARENTFILL_REPEATING_EXTRA:
20542 #endif
20543         case TAG_TRANSPARENTFILL_REPEATING:
20544         case TAG_TRANSPARENTFILL_NONREPEATING:
20545         case TAG_TRANSPARENTFILL_REPEATINGINVERTED: ok = HandleTransparentFillRepeatRecord(pCXaraFileRecord);   break;
20546 
20547         case TAG_FILLEFFECT_ALTRAINBOW:
20548         case TAG_FILLEFFECT_RAINBOW: 
20549         case TAG_FILLEFFECT_FADE:       ok = HandleFillEffectRecord(pCXaraFileRecord);  break;
20550 
20551         default:
20552             ok = FALSE;
20553             ERROR3_PF(("I don't handle records with the tag (%d)\n",pCXaraFileRecord->GetTag()));
20554             break;
20555     }
20556 
20557     return ok;
20558 }
20559 
20560 
20561 /********************************************************************************************
20562 
20563 >   BOOL FillAttrRecordHandler::HandleFlatFillRecord(CXaraFileRecord* pCXaraFileRecord)
20564 
20565     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
20566     Created:    30/5/96
20567     Inputs:     pCXaraFileRecord = ptr to record to handle
20568     Returns:    TRUE if handled successfuly
20569                 FALSE otherwise
20570     Purpose:    Handles the given record.
20571                 The record has to be a flat fill record
20572     SeeAlso:    -
20573 
20574 ********************************************************************************************/
20575 
20576 BOOL FillAttrRecordHandler::HandleFlatFillRecord(CXaraFileRecord* pCXaraFileRecord)
20577 {
20578     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
20579 
20580     INT32 ColourRef;
20581     INT32 Tag = pCXaraFileRecord->GetTag();
20582     BOOL ok = TRUE;
20583     // If it is the plain flat fill record then read the colour
20584     // If it is one of the flat fill default colour records then this is not required
20585     switch (Tag)
20586     {
20587         case TAG_FLATFILL:
20588             ok = pCXaraFileRecord->ReadINT32(&ColourRef);
20589             break;
20590         case TAG_FLATFILL_NONE:
20591             ColourRef = REF_DEFAULTCOLOUR_TRANSPARENT;
20592             break;
20593         case TAG_FLATFILL_BLACK:
20594             ColourRef = REF_DEFAULTCOLOUR_BLACK;
20595             break;
20596         case TAG_FLATFILL_WHITE:
20597             ColourRef = REF_DEFAULTCOLOUR_WHITE;
20598             break;
20599         default:
20600             ERROR2(FALSE,"I don't handle this tag type");
20601     }
20602 
20603     if (ok)
20604     {
20605         AttrFlatColourFill* pAttr = new AttrFlatColourFill;
20606         if (pAttr != NULL)
20607         {
20608             FlatFillAttribute* pValue = (FlatFillAttribute*)pAttr->GetAttributeValue();
20609 
20610             if (pValue != NULL)
20611             {
20612                 if (ok) ok = GetDocColour(ColourRef,&(pValue->Colour));
20613                 if (ok) ok = InsertNode(pAttr);
20614             }
20615             else
20616                 ok = FALSE;
20617         }
20618         else
20619             ok = FALSE;
20620     }
20621 
20622     return ok;
20623 }
20624 
20625 /********************************************************************************************
20626 
20627 >   BOOL FillAttrRecordHandler::HandleLinearFillRecord(CXaraFileRecord* pCXaraFileRecord)
20628 
20629     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
20630     Created:    25/6/96
20631     Inputs:     pCXaraFileRecord = ptr to record to handle
20632     Returns:    TRUE if handled successfuly
20633                 FALSE otherwise
20634     Purpose:    Handles the given record.
20635                 The record has to be a linear fill record
20636     SeeAlso:    -
20637 
20638 ********************************************************************************************/
20639 
20640 BOOL FillAttrRecordHandler::HandleLinearFillRecord(CXaraFileRecord* pCXaraFileRecord)
20641 {
20642     UINT32 tag = pCXaraFileRecord->GetTag();
20643     ERROR2IF(pCXaraFileRecord == NULL, FALSE, "pCXaraFileRecord is NULL");
20644     ERROR2IF(tag!=TAG_LINEARFILL && tag!=TAG_LINEARFILL3POINT, FALSE, "I don't handle this tag type");
20645 
20646     BOOL ok = TRUE;
20647     BOOL b3PointLinear = (tag==TAG_LINEARFILL3POINT);
20648 
20649     DocCoord StartPoint, EndPoint, EndPoint2;
20650     INT32 StartColourRef,EndColourRef;
20651     double Bias = 0, Gain = 0;
20652     double* ptrBias = &Bias, *ptrGain = &Gain;
20653 
20654     // Read in the linear fill data
20655     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
20656     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
20657     if (ok && b3PointLinear) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
20658     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
20659     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
20660     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
20661     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
20662 
20663     CProfileBiasGain Profile;
20664 
20665     if ((ptrBias != NULL) && (ptrGain != NULL))
20666     {
20667         Profile.SetBias((AFp) Bias);
20668         Profile.SetGain((AFp) Gain);
20669     }
20670 
20671     if (ok)
20672     {
20673         AttrLinearColourFill* pAttr = new AttrLinearColourFill;
20674         if (pAttr != NULL)
20675         {
20676             // Get a ptr to the attr value object
20677             LinearFillAttribute* pValue = (LinearFillAttribute*)pAttr->GetAttributeValue();
20678 
20679             if (pValue != NULL)
20680             {
20681                 // Store the start and end points
20682                 pValue->SetStartPoint(&StartPoint);
20683                 pValue->SetEndPoint(&EndPoint);
20684                 if (b3PointLinear)
20685                     pValue->SetEndPoint2(&EndPoint2);
20686                 else
20687                     pValue->SetEndPoint2(NULL);
20688                 
20689                 // Store the profile
20690                 pValue->SetProfile (Profile);
20691 
20692                 // Convert the colour references into doc colours, and insert the attr into the tree
20693                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
20694                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
20695                 if (ok) ok = InsertNode(pAttr);
20696             }
20697             else
20698                 ok = FALSE;
20699         }
20700         else
20701             ok = FALSE;
20702     }
20703 
20704     return ok;
20705 }
20706 
20707 /********************************************************************************************
20708 
20709 >   BOOL FillAttrRecordHandler::HandleMultiStageLinearFillRecord(
20710                     CXaraFileRecord* pCXaraFileRecord)
20711 
20712     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
20713     Created:    24/10/99
20714     Inputs:     pCXaraFileRecord = ptr to record to handle
20715     Returns:    TRUE if handled successfuly
20716                 FALSE otherwise
20717     Purpose:    Handles the given record.
20718                 The record has to be a multi stage linear fill record
20719     SeeAlso:    -
20720 
20721 ********************************************************************************************/
20722 
20723 BOOL FillAttrRecordHandler::HandleMultiStageLinearFillRecord(CXaraFileRecord* pCXaraFileRecord)
20724 {
20725     UINT32 tag = pCXaraFileRecord->GetTag();
20726     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
20727     ERROR2IF(tag!=TAG_LINEARFILLMULTISTAGE && tag!=TAG_LINEARFILLMULTISTAGE3POINT, FALSE, "I don't handle this tag type");
20728 
20729     BOOL ok = TRUE;
20730     BOOL b3PointLinear = (tag==TAG_LINEARFILLMULTISTAGE3POINT);
20731 
20732     DocCoord StartPoint, EndPoint, EndPoint2;
20733     INT32 StartColourRef,EndColourRef;
20734 
20735     // Read in the linear fill data
20736     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
20737     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
20738     if (ok && b3PointLinear) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
20739     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
20740     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
20741 
20742     // now, read all the multi stage records
20743     INT32 * pColRecs = NULL;
20744     UINT32 NumRecords = 0;
20745 
20746     if (ok) ok = pCXaraFileRecord->ReadUINT32(&NumRecords);
20747 
20748     pColRecs = new INT32[NumRecords];
20749 
20750     double *pPositions = new double[NumRecords];
20751 
20752     UINT32              i;
20753     for( i = 0 ; i < NumRecords; i++)
20754     {
20755         if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&(pPositions[i]));
20756         if (ok) ok = pCXaraFileRecord->ReadINT32(&(pColRecs[i]));
20757     }
20758 
20759     DocColour Colour;
20760 
20761     if (ok)
20762     {
20763         AttrLinearColourFill* pAttr = new AttrLinearColourFill;
20764         if (pAttr != NULL)
20765         {
20766             // Get a ptr to the attr value object
20767             LinearFillAttribute* pValue = (LinearFillAttribute*)pAttr->GetAttributeValue();
20768 
20769             if (pValue != NULL)
20770             {
20771                 // Store the start and end points
20772                 pValue->SetStartPoint(&StartPoint);
20773                 pValue->SetEndPoint(&EndPoint);
20774                 if (b3PointLinear)
20775                     pValue->SetEndPoint2(&EndPoint2);
20776                 else
20777                     pValue->SetEndPoint2(NULL);
20778 
20779                 // Convert the colour references into doc colours, and insert the attr into the tree
20780                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
20781                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
20782 
20783                 // create the colour ramp
20784                 ColourRamp * pRamp = pValue->MakeNewColourRamp();           
20785 
20786                 for (i = 0 ; i < NumRecords; i++)
20787                 {
20788                     // add a new ramp item
20789                     if (ok) ok = GetDocColour(pColRecs[i], &Colour);
20790                     
20791                     if (ok) pRamp->AddEntry((float)pPositions[i], &Colour);
20792                 }               
20793 
20794                 if (ok) ok = InsertNode(pAttr);
20795             }
20796             else
20797                 ok = FALSE;
20798         }
20799         else
20800             ok = FALSE;
20801     }
20802 
20803     if (pPositions)
20804         delete [] pPositions;
20805 
20806     if (pColRecs)
20807         delete [] pColRecs;
20808 
20809     return ok;
20810 }
20811 
20812 
20813 /********************************************************************************************
20814 
20815 >   BOOL FillAttrRecordHandler::HandleEllipticalFillRecord(CXaraFileRecord* pCXaraFileRecord)
20816 
20817     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
20818     Created:    25/6/96
20819     Inputs:     pCXaraFileRecord = ptr to record to handle
20820     Returns:    TRUE if handled successfuly
20821                 FALSE otherwise
20822     Purpose:    Handles the given record.
20823                 The record has to be a elliptical or circular fill record
20824     SeeAlso:    -
20825 
20826 ********************************************************************************************/
20827 
20828 BOOL FillAttrRecordHandler::HandleEllipticalFillRecord(CXaraFileRecord* pCXaraFileRecord)
20829 {
20830     UINT32 Tag = pCXaraFileRecord->GetTag();
20831 
20832     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
20833     ERROR2IF(Tag != TAG_ELLIPTICALFILL && Tag != TAG_CIRCULARFILL,FALSE,"I don't handle this tag type");
20834 
20835     BOOL ok = TRUE;
20836 
20837     DocCoord StartPoint, EndPoint, EndPoint2;
20838     INT32 StartColourRef,EndColourRef;
20839     double Bias = 0, Gain = 0;
20840     double* ptrBias = &Bias, *ptrGain = &Gain;
20841 
20842     // Read in the elliptical/circular fill data
20843     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
20844     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
20845 
20846     if (ok && Tag == TAG_ELLIPTICALFILL)                // Ellipses have an extra control point
20847         ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
20848 
20849     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
20850     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
20851     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
20852     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
20853 
20854     CProfileBiasGain Profile;
20855 
20856     if ((ptrBias != NULL) && (ptrGain != NULL))
20857     {
20858         Profile.SetBias((AFp) Bias);
20859         Profile.SetGain((AFp) Gain);
20860     }
20861 
20862     if (ok)
20863     {
20864         AttrRadialColourFill* pAttr = new AttrRadialColourFill;
20865         if (pAttr != NULL)
20866         {
20867             // Get a ptr to the attr value object
20868             RadialFillAttribute* pValue = (RadialFillAttribute*)pAttr->GetAttributeValue();
20869 
20870             if (pValue != NULL)
20871             {
20872                 // Store the start and end points
20873                 pValue->SetStartPoint(&StartPoint);
20874                 pValue->SetEndPoint(&EndPoint);
20875 
20876                 if (Tag == TAG_ELLIPTICALFILL)
20877                 {
20878                     pValue->SetEndPoint2(&EndPoint2);
20879                     pValue->MakeElliptical();
20880                 }
20881                 else
20882                     pValue->MakeCircular();
20883 
20884                 // Store the profile
20885                 pValue->SetProfile (Profile);
20886 
20887                 // Convert the colour references into doc colours, and insert the attr into the tree
20888                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
20889                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
20890                 if (ok) ok = InsertNode(pAttr);
20891             }
20892             else
20893                 ok = FALSE;
20894         }
20895         else
20896             ok = FALSE;
20897     }
20898 
20899     return ok;
20900 }
20901 
20902 /********************************************************************************************
20903 
20904 >   BOOL FillAttrRecordHandler::HandleMultiStageCircularFillRecord(
20905             CXaraFileRecord* pCXaraFileRecord)
20906 
20907     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
20908     Created:    24/10/99
20909     Inputs:     pCXaraFileRecord = ptr to record to handle
20910     Returns:    TRUE if handled successfuly
20911                 FALSE otherwise
20912     Purpose:    Handles the given record.
20913                 The record has to be a multistage circular fill
20914     SeeAlso:    -
20915 
20916 ********************************************************************************************/
20917 
20918 BOOL FillAttrRecordHandler::HandleMultiStageCircularFillRecord(
20919             CXaraFileRecord* pCXaraFileRecord)
20920 {
20921     UINT32 Tag = pCXaraFileRecord->GetTag();
20922 
20923     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
20924     ERROR2IF(Tag != TAG_CIRCULARFILLMULTISTAGE &&
20925         Tag != TAG_ELLIPTICALFILLMULTISTAGE,FALSE,"I don't handle this tag type");
20926 
20927     BOOL ok = TRUE;
20928 
20929     DocCoord StartPoint, EndPoint, EndPoint2;
20930     INT32 StartColourRef,EndColourRef;
20931 
20932     // Read in the elliptical/circular fill data
20933     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
20934     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
20935 
20936     if (ok && Tag == TAG_ELLIPTICALFILLMULTISTAGE)  // Ellipses have an extra control point
20937         ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
20938 
20939     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
20940     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
20941 
20942     // now, read all the multi stage records
20943     INT32 * pColRecs = NULL;
20944     UINT32 NumRecords = 0;
20945 
20946     if (ok) ok = pCXaraFileRecord->ReadUINT32(&NumRecords);
20947 
20948     pColRecs = new INT32[NumRecords];
20949 
20950     double *pPositions = new double[NumRecords];
20951 
20952     for (UINT32 i = 0 ; i < NumRecords; i++)
20953     {
20954         if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&(pPositions[i]));
20955         if (ok) ok = pCXaraFileRecord->ReadINT32(&(pColRecs[i]));
20956     }
20957 
20958     DocColour Colour;
20959 
20960     if (ok)
20961     {
20962         AttrRadialColourFill* pAttr = new AttrRadialColourFill;
20963         if (pAttr != NULL)
20964         {
20965             // Get a ptr to the attr value object
20966             RadialFillAttribute* pValue = (RadialFillAttribute*)pAttr->GetAttributeValue();
20967 
20968             if (pValue != NULL)
20969             {
20970                 // Store the start and end points
20971                 pValue->SetStartPoint(&StartPoint);
20972                 pValue->SetEndPoint(&EndPoint);
20973 
20974                 if (Tag == TAG_ELLIPTICALFILLMULTISTAGE)
20975                 {
20976                     pValue->SetEndPoint2(&EndPoint2);
20977                     pValue->MakeElliptical();
20978                 }
20979                 else                        
20980                     pValue->MakeCircular();
20981 
20982                 // Convert the colour references into doc colours, and insert the attr into the tree
20983                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
20984                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
20985 
20986                 // create the colour ramp
20987                 ColourRamp * pRamp = pValue->MakeNewColourRamp();           
20988 
20989                 for (UINT32 i = 0 ; i < NumRecords; i++)
20990                 {
20991                     // add a new ramp item
20992                     if (ok) ok = GetDocColour(pColRecs[i], &Colour);
20993                     
20994                     if (ok) pRamp->AddEntry((float)pPositions[i], &Colour);
20995                 }               
20996 
20997                 if (ok) ok = InsertNode(pAttr);
20998             }
20999             else
21000                 ok = FALSE;
21001         }
21002         else
21003             ok = FALSE;
21004     }
21005 
21006     delete [] pPositions;
21007     delete [] pColRecs;
21008 
21009     return ok;
21010 }
21011 
21012 /********************************************************************************************
21013 
21014 >   BOOL FillAttrRecordHandler::HandleConicalFillRecord(CXaraFileRecord* pCXaraFileRecord)
21015 
21016     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
21017     Created:    25/6/96
21018     Inputs:     pCXaraFileRecord = ptr to record to handle
21019     Returns:    TRUE if handled successfuly
21020                 FALSE otherwise
21021     Purpose:    Handles the given record.
21022                 The record has to be a conical fill record
21023     SeeAlso:    -
21024 
21025 ********************************************************************************************/
21026 
21027 BOOL FillAttrRecordHandler::HandleConicalFillRecord(CXaraFileRecord* pCXaraFileRecord)
21028 {
21029     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21030     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_CONICALFILL,FALSE,"I don't handle this tag type");
21031 
21032     BOOL ok = TRUE;
21033 
21034     DocCoord StartPoint, EndPoint;
21035     INT32 StartColourRef,EndColourRef;
21036     double Bias = 0, Gain = 0;
21037     double* ptrBias = &Bias, *ptrGain = &Gain;
21038 
21039     // Read in the conical fill data
21040     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21041     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21042     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
21043     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
21044     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21045     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21046 
21047     CProfileBiasGain Profile;
21048 
21049     if ((ptrBias != NULL) && (ptrGain != NULL))
21050     {
21051         Profile.SetBias((AFp) Bias);
21052         Profile.SetGain((AFp) Gain);
21053     }
21054 
21055     if (ok)
21056     {
21057         AttrConicalColourFill* pAttr = new AttrConicalColourFill;
21058         if (pAttr != NULL)
21059         {
21060             // Get a ptr to the attr value object
21061             ConicalFillAttribute* pValue = (ConicalFillAttribute*)pAttr->GetAttributeValue();
21062 
21063             if (pValue != NULL)
21064             {
21065                 // Store the start and end points
21066                 pValue->SetStartPoint(&StartPoint);
21067                 pValue->SetEndPoint(&EndPoint);
21068                 pValue->SetEndPoint2(NULL);
21069 
21070                 // Store the profile
21071                 pValue->SetProfile (Profile);
21072 
21073                 // Convert the colour references into doc colours, and insert the attr into the tree
21074                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
21075                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
21076                 if (ok) ok = InsertNode(pAttr);
21077             }
21078             else
21079                 ok = FALSE;
21080         }
21081         else
21082             ok = FALSE;
21083     }
21084 
21085     return ok;
21086 }
21087 
21088 /********************************************************************************************
21089 
21090 >   BOOL FillAttrRecordHandler::HandleMultiStageConicalFillRecord(
21091                 CXaraFileRecord* pCXaraFileRecord)
21092 
21093     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
21094     Created:    29/10/99
21095     Inputs:     pCXaraFileRecord = ptr to record to handle
21096     Returns:    TRUE if handled successfuly
21097                 FALSE otherwise
21098     Purpose:    Handles the given record.
21099                 The record has to be a multi stage conical fill record
21100     SeeAlso:    -
21101 
21102 ********************************************************************************************/
21103 
21104 BOOL FillAttrRecordHandler::HandleMultiStageConicalFillRecord(CXaraFileRecord* pCXaraFileRecord)
21105 {
21106     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21107     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_CONICALFILLMULTISTAGE,FALSE,"I don't handle this tag type");
21108 
21109     BOOL ok = TRUE;
21110 
21111     DocCoord StartPoint, EndPoint;
21112     INT32 StartColourRef,EndColourRef;
21113 
21114     // Read in the conical fill data
21115     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21116     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21117     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
21118     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
21119 
21120         // now, read all the multi stage records
21121     INT32 * pColRecs = NULL;
21122     UINT32 NumRecords = 0;
21123 
21124     if (ok) ok = pCXaraFileRecord->ReadUINT32(&NumRecords);
21125 
21126     pColRecs = new INT32[NumRecords];
21127 
21128     double *pPositions = new double[NumRecords];
21129 
21130     UINT32              i;
21131     for( i = 0 ; i < NumRecords; i++)
21132     {
21133         if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&(pPositions[i]));
21134         if (ok) ok = pCXaraFileRecord->ReadINT32(&(pColRecs[i]));
21135     }
21136 
21137     DocColour Colour;
21138 
21139     if (ok)
21140     {
21141         AttrConicalColourFill* pAttr = new AttrConicalColourFill;
21142         if (pAttr != NULL)
21143         {
21144             // Get a ptr to the attr value object
21145             ConicalFillAttribute* pValue = (ConicalFillAttribute*)pAttr->GetAttributeValue();
21146 
21147             if (pValue != NULL)
21148             {
21149                 // Store the start and end points
21150                 pValue->SetStartPoint(&StartPoint);
21151                 pValue->SetEndPoint(&EndPoint);
21152                 pValue->SetEndPoint2(NULL);
21153 
21154                 // Convert the colour references into doc colours, and insert the attr into the tree
21155                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
21156                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
21157 
21158                 // create the colour ramp
21159                 ColourRamp * pRamp = pValue->MakeNewColourRamp();           
21160 
21161                 for (i = 0 ; i < NumRecords; i++)
21162                 {
21163                     // add a new ramp item
21164                     if (ok) ok = GetDocColour(pColRecs[i], &Colour);
21165                     
21166                     if (ok) pRamp->AddEntry((float)pPositions[i], &Colour);
21167                 }               
21168 
21169                 if (ok) ok = InsertNode(pAttr);
21170             }
21171             else
21172                 ok = FALSE;
21173         }
21174         else
21175             ok = FALSE;
21176     }
21177 
21178     if (pPositions)
21179         delete [] pPositions;
21180 
21181     if (pColRecs)
21182         delete [] pColRecs;
21183 
21184     return ok;
21185 }
21186 
21187 
21188 /********************************************************************************************
21189 
21190 >   BOOL FillAttrRecordHandler::HandleSquareFillRecord(CXaraFileRecord* pCXaraFileRecord)
21191 
21192     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
21193     Created:    9/8/96
21194     Inputs:     pCXaraFileRecord = ptr to record to handle
21195     Returns:    TRUE if handled successfuly
21196                 FALSE otherwise
21197     Purpose:    Handles the given record.
21198                 The record has to be a square fill record
21199     SeeAlso:    -
21200 
21201 ********************************************************************************************/
21202 
21203 BOOL FillAttrRecordHandler::HandleSquareFillRecord(CXaraFileRecord* pCXaraFileRecord)
21204 {
21205     UINT32 Tag = pCXaraFileRecord->GetTag();
21206 
21207     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21208     ERROR2IF(Tag != TAG_SQUAREFILL,FALSE,"I don't handle this tag type");
21209 
21210     BOOL ok = TRUE;
21211 
21212     DocCoord StartPoint, EndPoint, EndPoint2;
21213     INT32 StartColourRef,EndColourRef;
21214     double Bias = 0, Gain = 0;
21215     double* ptrBias = &Bias, *ptrGain = &Gain;
21216 
21217     // Read in the elliptical/circular fill data
21218     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21219     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21220     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21221 
21222     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
21223     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
21224     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21225     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21226 
21227     CProfileBiasGain Profile;
21228 
21229     if ((ptrBias != NULL) && (ptrGain != NULL))
21230     {
21231         Profile.SetBias((AFp) Bias);
21232         Profile.SetGain((AFp) Gain);
21233     }
21234 
21235     if (ok)
21236     {
21237         AttrSquareColourFill* pAttr = new AttrSquareColourFill;
21238         if (pAttr != NULL)
21239         {
21240             // Get a ptr to the attr value object
21241             SquareFillAttribute* pValue = (SquareFillAttribute*)pAttr->GetAttributeValue();
21242 
21243             if (pValue != NULL)
21244             {
21245                 // Store the start and end points
21246                 pValue->SetStartPoint(&StartPoint);
21247                 pValue->SetEndPoint(&EndPoint);
21248                 pValue->SetEndPoint2(&EndPoint2);
21249 
21250                 // Store the profile
21251                 pValue->SetProfile (Profile);
21252 
21253                 // Convert the colour references into doc colours, and insert the attr into the tree
21254                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
21255                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
21256                 if (ok) ok = InsertNode(pAttr);
21257             }
21258             else
21259                 ok = FALSE;
21260         }
21261         else
21262             ok = FALSE;
21263     }
21264 
21265     return ok;
21266 }
21267 
21268 /********************************************************************************************
21269 
21270 >   BOOL FillAttrRecordHandler::HandleMultiStageSquareFillRecord(CXaraFileRecord* pCXaraFileRecord)
21271 
21272     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
21273     Created:    23/3/2000
21274     Inputs:     pCXaraFileRecord = ptr to record to handle
21275     Returns:    TRUE if handled successfuly
21276                 FALSE otherwise
21277     Purpose:    Handles the given record.
21278                 The record has to be a multi-stage square fill record
21279     SeeAlso:    -
21280 
21281 ********************************************************************************************/
21282 
21283 BOOL FillAttrRecordHandler::HandleMultiStageSquareFillRecord(CXaraFileRecord* pCXaraFileRecord)
21284 {
21285     UINT32 Tag = pCXaraFileRecord->GetTag();
21286 
21287     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21288     ERROR2IF(Tag != TAG_SQUAREFILLMULTISTAGE,FALSE,"I don't handle this tag type");
21289 
21290     BOOL ok = TRUE;
21291 
21292     DocCoord StartPoint, EndPoint, EndPoint2;
21293     INT32 StartColourRef,EndColourRef;
21294 //  double Bias = 0, Gain = 0;
21295 //  double* ptrBias = &Bias, *ptrGain = &Gain;
21296 
21297     // Read in the elliptical/circular fill data
21298     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21299     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21300     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21301 
21302     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
21303     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
21304 //  if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21305 //  if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21306     
21307     // now, read all the multi stage records
21308     INT32 * pColRecs = NULL;
21309     UINT32 NumRecords = 0;
21310 
21311     if (ok) ok = pCXaraFileRecord->ReadUINT32(&NumRecords);
21312 
21313     pColRecs = new INT32[NumRecords];
21314 
21315     double *pPositions = new double[NumRecords];
21316 
21317     UINT32              i;
21318     for( i = 0 ; i < NumRecords; i++)
21319     {
21320         if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&(pPositions[i]));
21321         if (ok) ok = pCXaraFileRecord->ReadINT32(&(pColRecs[i]));
21322     }
21323 
21324     DocColour Colour;
21325 
21326     if (ok)
21327     {
21328         AttrSquareColourFill* pAttr = new AttrSquareColourFill;
21329         if (pAttr != NULL)
21330         {
21331             // Get a ptr to the attr value object
21332             SquareFillAttribute* pValue = (SquareFillAttribute*)pAttr->GetAttributeValue();
21333 
21334             if (pValue != NULL)
21335             {
21336                 // Store the start and end points
21337                 pValue->SetStartPoint(&StartPoint);
21338                 pValue->SetEndPoint(&EndPoint);
21339                 pValue->SetEndPoint2(&EndPoint2);
21340 
21341                 // Convert the colour references into doc colours, and insert the attr into the tree
21342                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
21343                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
21344 
21345                 // create the colour ramp
21346                 ColourRamp * pRamp = pValue->MakeNewColourRamp();           
21347 
21348                 for (i = 0 ; i < NumRecords; i++)
21349                 {
21350                     // add a new ramp item
21351                     if (ok) ok = GetDocColour(pColRecs[i], &Colour);
21352                     
21353                     if (ok) pRamp->AddEntry((float)pPositions[i], &Colour);
21354                 }               
21355 
21356                 if (ok) ok = InsertNode(pAttr);
21357             }
21358             else
21359                 ok = FALSE;
21360         }
21361         else
21362             ok = FALSE;
21363     }
21364 
21365     if (pPositions)
21366         delete [] pPositions;
21367 
21368     if (pColRecs)
21369         delete [] pColRecs;
21370 
21371     return ok;
21372 }
21373 
21374 /********************************************************************************************
21375 
21376 >   BOOL FillAttrRecordHandler::HandleThreeColFillRecord(CXaraFileRecord* pCXaraFileRecord)
21377 
21378     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
21379     Created:    9/8/96
21380     Inputs:     pCXaraFileRecord = ptr to record to handle
21381     Returns:    TRUE if handled successfuly
21382                 FALSE otherwise
21383     Purpose:    Handles the given record.
21384                 The record has to be a ThreeCol fill record
21385     SeeAlso:    -
21386 
21387 ********************************************************************************************/
21388 
21389 BOOL FillAttrRecordHandler::HandleThreeColFillRecord(CXaraFileRecord* pCXaraFileRecord)
21390 {
21391     UINT32 Tag = pCXaraFileRecord->GetTag();
21392 
21393     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21394     ERROR2IF(Tag != TAG_THREECOLFILL,FALSE,"I don't handle this tag type");
21395 
21396     BOOL ok = TRUE;
21397 
21398     DocCoord StartPoint;
21399     DocCoord EndPoint;
21400     DocCoord EndPoint2;
21401     INT32 StartColourRef;
21402     INT32 EndColourRef;
21403     INT32 EndColour2Ref;
21404 
21405     // Read in the elliptical/circular fill data
21406     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21407     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21408     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21409 
21410     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
21411     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
21412     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColour2Ref);
21413 
21414     if (ok)
21415     {
21416         AttrThreeColColourFill* pAttr = new AttrThreeColColourFill;
21417         if (pAttr != NULL)
21418         {
21419             // Get a ptr to the attr value object
21420             ThreeColFillAttribute* pValue = (ThreeColFillAttribute*)pAttr->GetAttributeValue();
21421 
21422             if (pValue != NULL)
21423             {
21424                 // Store the start and end points
21425                 pValue->SetStartPoint(&StartPoint);
21426                 pValue->SetEndPoint(&EndPoint);
21427                 pValue->SetEndPoint2(&EndPoint2);
21428 
21429                 // Convert the colour references into doc colours, and insert the attr into the tree
21430                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
21431                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
21432                 if (ok) ok = GetDocColour(EndColour2Ref,&(pValue->EndColour2));
21433                 if (ok) ok = InsertNode(pAttr);
21434             }
21435             else
21436                 ok = FALSE;
21437         }
21438         else
21439             ok = FALSE;
21440     }
21441 
21442     return ok;
21443 }
21444 
21445 /********************************************************************************************
21446 
21447 >   BOOL FillAttrRecordHandler::HandleFourColFillRecord(CXaraFileRecord* pCXaraFileRecord)
21448 
21449     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
21450     Created:    9/8/96
21451     Inputs:     pCXaraFileRecord = ptr to record to handle
21452     Returns:    TRUE if handled successfuly
21453                 FALSE otherwise
21454     Purpose:    Handles the given record.
21455                 The record has to be a FourCol fill record
21456     SeeAlso:    -
21457 
21458 ********************************************************************************************/
21459 
21460 BOOL FillAttrRecordHandler::HandleFourColFillRecord(CXaraFileRecord* pCXaraFileRecord)
21461 {
21462     UINT32 Tag = pCXaraFileRecord->GetTag();
21463 
21464     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21465     ERROR2IF(Tag != TAG_FOURCOLFILL,FALSE,"I don't handle this tag type");
21466 
21467     BOOL ok = TRUE;
21468 
21469     DocCoord StartPoint;
21470     DocCoord EndPoint;
21471     DocCoord EndPoint2;
21472     INT32 StartColourRef;
21473     INT32 EndColourRef;
21474     INT32 EndColour2Ref;
21475     INT32 EndColour3Ref;
21476 
21477     // Read in the elliptical/circular fill data
21478     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21479     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21480     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21481 
21482     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColourRef);
21483     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColourRef);
21484     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColour2Ref);
21485     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColour3Ref);
21486 
21487     if (ok)
21488     {
21489         AttrFourColColourFill* pAttr = new AttrFourColColourFill;
21490         if (pAttr != NULL)
21491         {
21492             // Get a ptr to the attr value object
21493             FourColFillAttribute* pValue = (FourColFillAttribute*)pAttr->GetAttributeValue();
21494 
21495             if (pValue != NULL)
21496             {
21497                 // Store the start and end points
21498                 pValue->SetStartPoint(&StartPoint);
21499                 pValue->SetEndPoint(&EndPoint);
21500                 pValue->SetEndPoint2(&EndPoint2);
21501 
21502                 // Convert the colour references into doc colours, and insert the attr into the tree
21503                 if (ok) ok = GetDocColour(StartColourRef,&(pValue->Colour));
21504                 if (ok) ok = GetDocColour(EndColourRef,&(pValue->EndColour));
21505                 if (ok) ok = GetDocColour(EndColour2Ref,&(pValue->EndColour2));
21506                 if (ok) ok = GetDocColour(EndColour3Ref,&(pValue->EndColour3));
21507                 if (ok) ok = InsertNode(pAttr);
21508             }
21509             else
21510                 ok = FALSE;
21511         }
21512         else
21513             ok = FALSE;
21514     }
21515 
21516     return ok;
21517 }
21518 
21519 /********************************************************************************************
21520 
21521 >   BOOL FillAttrRecordHandler::HandleBitmapFillRecord(CXaraFileRecord* pCXaraFileRecord)
21522 
21523     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
21524     Created:    25/6/96
21525     Inputs:     pCXaraFileRecord = ptr to record to handle
21526     Returns:    TRUE if handled successfuly
21527                 FALSE otherwise
21528     Purpose:    Handles the given record.
21529                 The record has to be a bitmap or contone bitmap fill record
21530     SeeAlso:    -
21531 
21532 ********************************************************************************************/
21533 
21534 BOOL FillAttrRecordHandler::HandleBitmapFillRecord(CXaraFileRecord* pCXaraFileRecord)
21535 {
21536     UINT32 Tag = pCXaraFileRecord->GetTag();
21537 
21538     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21539     ERROR2IF(Tag != TAG_BITMAPFILL && Tag != TAG_CONTONEBITMAPFILL,FALSE,"I don't handle this tag type");
21540 
21541     BOOL ok = TRUE;
21542 
21543     DocCoord StartPoint, EndPoint, EndPoint2;
21544     INT32 BitmapRef,StartColRef,EndColRef;
21545     double Bias = 0, Gain = 0;
21546     double* ptrBias = &Bias, *ptrGain = &Gain;
21547 
21548     // Read in the bitmap fill data
21549     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21550     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21551     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21552 
21553     if (Tag == TAG_CONTONEBITMAPFILL)
21554     {
21555         if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColRef);
21556         if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColRef);
21557     }
21558 
21559     if (ok) ok = pCXaraFileRecord->ReadINT32(&BitmapRef);
21560     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21561     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21562 
21563     CProfileBiasGain Profile;
21564 
21565     if ((ptrBias != NULL) && (ptrGain != NULL))
21566     {
21567         Profile.SetBias((AFp) Bias);
21568         Profile.SetGain((AFp) Gain);
21569     }
21570 
21571     if (ok)
21572     {
21573         AttrBitmapColourFill* pAttr = new AttrBitmapColourFill;
21574         if (pAttr != NULL)
21575         {
21576             // Get a ptr to the attr value object
21577             BitmapFillAttribute* pValue = (BitmapFillAttribute*)pAttr->GetAttributeValue();
21578 
21579             if (pValue != NULL)
21580             {
21581                 // Store the start and end points
21582                 pValue->SetStartPoint(&StartPoint);
21583                 pValue->SetEndPoint(&EndPoint);
21584                 pValue->SetEndPoint2(&EndPoint2);
21585 
21586                 if (Tag == TAG_CONTONEBITMAPFILL)
21587                 {
21588                     DocColour StartCol,EndCol;
21589 
21590                     // Convert the colour references into doc colours
21591                     if (ok) ok = GetDocColour(StartColRef,&StartCol);
21592                     if (ok) ok = GetDocColour(EndColRef,&EndCol);
21593 
21594                     if (ok)
21595                     {
21596                         pValue->SetStartColour(&StartCol);
21597                         pValue->SetEndColour(&EndCol);
21598                     }
21599                 }
21600 
21601                 // Store the profile
21602                 pValue->SetProfile (Profile);
21603 
21604                 // Convert the bmp reference into a kernel bmp, and insert the attr into the tree
21605                 KernelBitmap * pBitmap = NULL;
21606                 pBitmap = GetReadBitmapReference(BitmapRef);
21607 
21608                 ok = (pBitmap != NULL);
21609                 if (ok) ok = pValue->AttachBitmap(pBitmap);
21610                 if (ok) ok = InsertNode(pAttr);
21611             }
21612             else
21613                 ok = FALSE;
21614         }
21615         else
21616             ok = FALSE;
21617     }
21618 
21619     return ok;
21620 }
21621 
21622 /********************************************************************************************
21623 
21624 >   BOOL FillAttrRecordHandler::HandleFractalFillRecord(CXaraFileRecord* pCXaraFileRecord)
21625 
21626     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
21627     Created:    25/6/96
21628     Inputs:     pCXaraFileRecord = ptr to record to handle
21629     Returns:    TRUE if handled successfuly
21630                 FALSE otherwise
21631     Purpose:    Handles the given record.
21632                 The record must be a fractal fill record
21633     SeeAlso:    -
21634 
21635 ********************************************************************************************/
21636 
21637 BOOL FillAttrRecordHandler::HandleFractalFillRecord(CXaraFileRecord* pCXaraFileRecord)
21638 {
21639     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21640     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_FRACTALFILL,FALSE,"I don't handle this tag type");
21641 
21642     BOOL ok = TRUE;
21643 
21644     DocCoord StartPoint, EndPoint, EndPoint2;
21645     INT32 StartColRef,EndColRef, Seed, DPI;
21646     FIXED16 Graininess, Gravity, Squash;
21647     BYTE Tileable;
21648     double Bias = 0, Gain = 0;
21649     double* ptrBias = &Bias, *ptrGain = &Gain;
21650 
21651     // Read in the fractal fill data
21652     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21653     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21654     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21655     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColRef);
21656     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColRef);
21657 
21658     if (ok) ok = pCXaraFileRecord->ReadINT32(&Seed);
21659     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Graininess);
21660     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Gravity);
21661     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Squash);
21662     if (ok) ok = pCXaraFileRecord->ReadINT32(&DPI);
21663     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Tileable);
21664     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21665     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21666 
21667     CProfileBiasGain Profile;
21668 
21669     if ((ptrBias != NULL) && (ptrGain != NULL))
21670     {
21671         Profile.SetBias((AFp) Bias);
21672         Profile.SetGain((AFp) Gain);
21673     }
21674 
21675     if (ok)
21676     {
21677         AttrFractalColourFill* pAttr = new AttrFractalColourFill;
21678         if (pAttr != NULL)
21679         {
21680             // Get a ptr to the attr value object
21681             FractalFillAttribute* pValue = (FractalFillAttribute*)pAttr->GetAttributeValue();
21682 
21683             if (pValue != NULL)
21684             {
21685                 // Store the start and end points
21686                 pValue->SetStartPoint(&StartPoint);
21687                 pValue->SetEndPoint(&EndPoint);
21688                 pValue->SetEndPoint2(&EndPoint2);
21689                                        
21690                 // Store the fractal data
21691                 pValue->SetSeed(Seed);
21692                 pValue->SetGraininess(Graininess);
21693                 pValue->SetGravity(Gravity);
21694                 pValue->SetSquash(Squash);
21695                 pValue->SetFractalDPI(DPI);
21696                 pValue->SetTileable(Tileable);
21697 
21698                 DocColour StartCol,EndCol;
21699 
21700                 // Convert the colour references into doc colours
21701                 if (ok) ok = GetDocColour(StartColRef,&StartCol);
21702                 if (ok) ok = GetDocColour(EndColRef,&EndCol);
21703                 if (ok)
21704                 {
21705                     pValue->SetStartColour(&StartCol);
21706                     pValue->SetEndColour(&EndCol);
21707                 }
21708 
21709                 // Store the profile
21710                 pValue->SetProfile (Profile);
21711 
21712                 // Recreate the fractal, and insert the attr into the tree
21713                 if (ok) ok = pValue->RecalcFractal();
21714                 if (ok) ok = InsertNode(pAttr);
21715             }
21716             else
21717                 ok = FALSE;
21718         }
21719         else
21720             ok = FALSE;
21721     }
21722 
21723     return ok;
21724 }
21725 
21726 
21727 /********************************************************************************************
21728 
21729 >   BOOL FillAttrRecordHandler::HandleNoiseFillRecord(CXaraFileRecord* pCXaraFileRecord)
21730 
21731     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
21732     Created:    24/1/97
21733     Inputs:     pCXaraFileRecord = ptr to record to handle
21734     Returns:    TRUE if handled successfuly
21735                 FALSE otherwise
21736     Purpose:    Handles the given record.
21737                 The record must be a noise fill record
21738     SeeAlso:    -
21739 
21740 ********************************************************************************************/
21741 
21742 BOOL FillAttrRecordHandler::HandleNoiseFillRecord(CXaraFileRecord* pCXaraFileRecord)
21743 {
21744     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21745     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_NOISEFILL,FALSE,"I don't handle this tag type");
21746 
21747     BOOL ok = TRUE;
21748 
21749     DocCoord StartPoint, EndPoint, EndPoint2;
21750     INT32 StartColRef,EndColRef, DPI;
21751     FIXED16 Grain;
21752     INT32 Seed;
21753     BYTE Tileable;
21754     double Bias = 0, Gain = 0;
21755     double* ptrBias = &Bias, *ptrGain = &Gain;
21756 
21757     // Read in the fractal fill data
21758     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21759     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21760     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21761     if (ok) ok = pCXaraFileRecord->ReadINT32(&StartColRef);
21762     if (ok) ok = pCXaraFileRecord->ReadINT32(&EndColRef);
21763     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Grain);
21764     if (ok) ok = pCXaraFileRecord->ReadINT32(&Seed);
21765     if (ok) ok = pCXaraFileRecord->ReadINT32(&DPI);
21766     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Tileable);
21767     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21768     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21769 
21770     CProfileBiasGain Profile;
21771 
21772     if ((ptrBias != NULL) && (ptrGain != NULL))
21773     {
21774         Profile.SetBias((AFp) Bias);
21775         Profile.SetGain((AFp) Gain);
21776     }
21777 
21778     if (ok)
21779     {
21780         AttrNoiseColourFill* pAttr = new AttrNoiseColourFill;
21781         if (pAttr != NULL)
21782         {
21783             // Get a ptr to the attr value object
21784             NoiseFillAttribute* pValue = (NoiseFillAttribute*)pAttr->GetAttributeValue();
21785 
21786             if (pValue != NULL)
21787             {
21788                 // Store the start and end points
21789                 pValue->SetStartPoint(&StartPoint);
21790                 pValue->SetEndPoint(&EndPoint);
21791                 pValue->SetEndPoint2(&EndPoint2);
21792                                        
21793                 // Store the noise data
21794                 pValue->SetGraininess(Grain);
21795                 pValue->SetSeed(Seed);
21796                 pValue->SetFractalDPI(DPI);
21797                 pValue->SetTileable(Tileable);
21798 
21799                 DocColour StartCol,EndCol;
21800 
21801                 // Convert the colour references into doc colours
21802                 if (ok) ok = GetDocColour(StartColRef,&StartCol);
21803                 if (ok) ok = GetDocColour(EndColRef,&EndCol);
21804                 if (ok)
21805                 {
21806                     pValue->SetStartColour(&StartCol);
21807                     pValue->SetEndColour(&EndCol);
21808                 }
21809 
21810                 // Store the profile
21811                 pValue->SetProfile (Profile);
21812 
21813                 // Recreate the fractal, and insert the attr into the tree
21814                 if (ok) ok = pValue->RecalcFractal();
21815                 if (ok) ok = InsertNode(pAttr);
21816             }
21817             else
21818                 ok = FALSE;
21819         }
21820         else
21821             ok = FALSE;
21822     }
21823 
21824     return ok;
21825 }
21826 
21827 //----------------------------------------------------------------------------------
21828 //----------------------------------------------------------------------------------
21829 //----------------------------------------------------------------------------------
21830 
21831 /********************************************************************************************
21832 
21833 >   BOOL FillAttrRecordHandler::HandleFlatTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
21834 
21835     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
21836     Created:    26/6/96
21837     Inputs:     pCXaraFileRecord = ptr to record to handle
21838     Returns:    TRUE if handled successfuly
21839                 FALSE otherwise
21840     Purpose:    Handles the given record.
21841                 The record has to be a flat transparent fill record
21842     SeeAlso:    -
21843 
21844 ********************************************************************************************/
21845 
21846 BOOL FillAttrRecordHandler::HandleFlatTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
21847 {
21848     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21849     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_FLATTRANSPARENTFILL,FALSE,"I don't handle this tag type");
21850 
21851     BOOL ok = TRUE;
21852 
21853     BYTE Transp,TranspType;
21854 
21855     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
21856     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
21857 
21858     if (ok)
21859     {
21860         AttrFlatTranspFill* pAttr = new AttrFlatTranspFill;
21861         if (pAttr != NULL)
21862         {
21863             FlatTranspFillAttribute* pValue = (FlatTranspFillAttribute*)pAttr->GetAttributeValue();
21864 
21865             if (pValue != NULL)
21866             {
21867                 pValue->Transp      = UINT32(Transp);
21868                 pValue->TranspType  = UINT32(TranspType);
21869                 ok = InsertNode(pAttr);
21870             }
21871             else
21872                 ok = FALSE;
21873         }
21874         else
21875             ok = FALSE;
21876     }
21877 
21878     return ok;
21879 }
21880 
21881 /********************************************************************************************
21882 
21883 >   BOOL FillAttrRecordHandler::HandleLinearTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
21884 
21885     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
21886     Created:    26/6/96
21887     Inputs:     pCXaraFileRecord = ptr to record to handle
21888     Returns:    TRUE if handled successfuly
21889                 FALSE otherwise
21890     Purpose:    Handles the given record.
21891                 The record has to be a Linear transparent fill record
21892     SeeAlso:    -
21893 
21894 ********************************************************************************************/
21895 
21896 BOOL FillAttrRecordHandler::HandleLinearTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
21897 {
21898     UINT32 tag = pCXaraFileRecord->GetTag();
21899     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21900     ERROR2IF(tag!=TAG_LINEARTRANSPARENTFILL && tag!=TAG_LINEARTRANSPARENTFILL3POINT, FALSE, "I don't handle this tag type");
21901 
21902     BOOL ok = TRUE;
21903     BOOL b3PointLinear = (tag==TAG_LINEARTRANSPARENTFILL3POINT);
21904 
21905     DocCoord StartPoint, EndPoint, EndPoint2;
21906     BYTE Transp,EndTransp,TranspType;
21907     double Bias = 0, Gain = 0;
21908     double* ptrBias = &Bias, *ptrGain = &Gain;
21909 
21910     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21911     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21912     if (ok && b3PointLinear) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21913     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
21914     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
21915     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
21916     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21917     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21918 
21919     CProfileBiasGain Profile;
21920 
21921     if ((ptrBias != NULL) && (ptrGain != NULL))
21922     {
21923         Profile.SetBias((AFp) Bias);
21924         Profile.SetGain((AFp) Gain);
21925     }
21926 
21927     if (ok)
21928     {
21929         AttrLinearTranspFill* pAttr = new AttrLinearTranspFill;
21930         if (pAttr != NULL)
21931         {
21932             LinearTranspFillAttribute* pValue = (LinearTranspFillAttribute*)pAttr->GetAttributeValue();
21933 
21934             if (pValue != NULL)
21935             {
21936                 pValue->SetStartPoint(&StartPoint);
21937                 pValue->SetEndPoint(&EndPoint);
21938                 if (b3PointLinear)
21939                     pValue->SetEndPoint2(&EndPoint2);
21940                 else
21941                     pValue->SetEndPoint2(NULL);
21942                 pValue->Transp      = UINT32(Transp);
21943                 pValue->EndTransp   = UINT32(EndTransp);
21944                 pValue->TranspType  = UINT32(TranspType);
21945                 pValue->SetProfile (Profile);
21946                 ok = InsertNode(pAttr);
21947             }
21948             else
21949                 ok = FALSE;
21950         }
21951         else
21952             ok = FALSE;
21953     }
21954 
21955     return ok;
21956 }
21957 
21958 /********************************************************************************************
21959 
21960 >   BOOL FillAttrRecordHandler::HandleEllipticalTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
21961 
21962     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
21963     Created:    26/6/96
21964     Inputs:     pCXaraFileRecord = ptr to record to handle
21965     Returns:    TRUE if handled successfuly
21966                 FALSE otherwise
21967     Purpose:    Handles the given record.
21968                 The record has to be an Elliptical or circular transparent fill record
21969     SeeAlso:    -
21970 
21971 ********************************************************************************************/
21972 
21973 BOOL FillAttrRecordHandler::HandleEllipticalTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
21974 {
21975     UINT32 Tag = pCXaraFileRecord->GetTag();
21976 
21977     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
21978     ERROR2IF(Tag != TAG_ELLIPTICALTRANSPARENTFILL && Tag != TAG_CIRCULARTRANSPARENTFILL,FALSE,"I don't handle this tag type");
21979 
21980     BOOL ok = TRUE;
21981 
21982     DocCoord StartPoint, EndPoint, EndPoint2;
21983     BYTE Transp,EndTransp,TranspType;
21984     double Bias = 0, Gain = 0;
21985     double* ptrBias = &Bias, *ptrGain = &Gain;
21986 
21987     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
21988     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
21989 
21990     if (ok && Tag == TAG_ELLIPTICALTRANSPARENTFILL)
21991         ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
21992 
21993     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
21994     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
21995     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
21996     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
21997     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
21998 
21999     CProfileBiasGain Profile;
22000 
22001     if ((ptrBias != NULL) && (ptrGain != NULL))
22002     {
22003         Profile.SetBias((AFp) Bias);
22004         Profile.SetGain((AFp) Gain);
22005     }
22006 
22007     if (ok)
22008     {
22009         AttrRadialTranspFill* pAttr = new AttrRadialTranspFill;
22010         if (pAttr != NULL)
22011         {
22012             RadialTranspFillAttribute* pValue = (RadialTranspFillAttribute*)pAttr->GetAttributeValue();
22013 
22014             if (pValue != NULL)
22015             {
22016                 pValue->SetStartPoint(&StartPoint);
22017                 pValue->SetEndPoint(&EndPoint);
22018 
22019                 if (Tag == TAG_ELLIPTICALTRANSPARENTFILL)
22020                 {
22021                     pValue->SetEndPoint2(&EndPoint2);
22022                     pValue->MakeElliptical();
22023                 }
22024                 else
22025                     pValue->MakeCircular();
22026 
22027                 pValue->Transp      = UINT32(Transp);
22028                 pValue->EndTransp   = UINT32(EndTransp);
22029                 pValue->TranspType  = UINT32(TranspType);
22030                 pValue->SetProfile (Profile);
22031                 ok = InsertNode(pAttr);
22032             }
22033             else
22034                 ok = FALSE;
22035         }
22036         else
22037             ok = FALSE;
22038     }
22039 
22040     return ok;
22041 }
22042 
22043 /********************************************************************************************
22044 
22045 >   BOOL FillAttrRecordHandler::HandleConicalTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22046 
22047     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
22048     Created:    26/6/96
22049     Inputs:     pCXaraFileRecord = ptr to record to handle
22050     Returns:    TRUE if handled successfuly
22051                 FALSE otherwise
22052     Purpose:    Handles the given record.
22053                 The record has to be a Conical transparent fill record
22054     SeeAlso:    -
22055 
22056 ********************************************************************************************/
22057 
22058 BOOL FillAttrRecordHandler::HandleConicalTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22059 {
22060     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22061     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_CONICALTRANSPARENTFILL,FALSE,"I don't handle this tag type");
22062 
22063     BOOL ok = TRUE;
22064 
22065     DocCoord StartPoint, EndPoint;
22066     BYTE Transp,EndTransp,TranspType;
22067     double Bias = 0, Gain = 0;
22068     double* ptrBias = &Bias, *ptrGain = &Gain;
22069 
22070     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
22071     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
22072     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
22073     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
22074     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
22075     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
22076     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
22077 
22078     CProfileBiasGain Profile;
22079 
22080     if ((ptrBias != NULL) && (ptrGain != NULL))
22081     {
22082         Profile.SetBias((AFp) Bias);
22083         Profile.SetGain((AFp) Gain);
22084     }
22085 
22086     if (ok)
22087     {
22088         AttrConicalTranspFill* pAttr = new AttrConicalTranspFill;
22089         if (pAttr != NULL)
22090         {
22091             ConicalTranspFillAttribute* pValue = (ConicalTranspFillAttribute*)pAttr->GetAttributeValue();
22092 
22093             if (pValue != NULL)
22094             {
22095                 pValue->SetStartPoint(&StartPoint);
22096                 pValue->SetEndPoint(&EndPoint);
22097                 pValue->Transp      = UINT32(Transp);
22098                 pValue->EndTransp   = UINT32(EndTransp);
22099                 pValue->TranspType  = UINT32(TranspType);
22100                 pValue->SetProfile (Profile);
22101                 ok = InsertNode(pAttr);
22102             }
22103             else
22104                 ok = FALSE;
22105         }
22106         else
22107             ok = FALSE;
22108     }
22109 
22110     return ok;
22111 }
22112 
22113 /********************************************************************************************
22114 
22115 >   BOOL FillAttrRecordHandler::HandleSquareTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22116 
22117     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
22118     Created:    9/8/96
22119     Inputs:     pCXaraFileRecord = ptr to record to handle
22120     Returns:    TRUE if handled successfuly
22121                 FALSE otherwise
22122     Purpose:    Handles the given record.
22123                 The record has to be a Square transparent fill record
22124     SeeAlso:    -
22125 
22126 ********************************************************************************************/
22127 
22128 BOOL FillAttrRecordHandler::HandleSquareTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22129 {
22130     UINT32 Tag = pCXaraFileRecord->GetTag();
22131 
22132     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22133     ERROR2IF(Tag != TAG_SQUARETRANSPARENTFILL,FALSE,"I don't handle this tag type");
22134 
22135     BOOL ok = TRUE;
22136 
22137     DocCoord StartPoint, EndPoint, EndPoint2;
22138     BYTE Transp,EndTransp,TranspType;
22139     double Bias = 0, Gain = 0;
22140     double* ptrBias = &Bias, *ptrGain = &Gain;
22141 
22142     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
22143     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
22144     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
22145 
22146     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
22147     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
22148     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
22149     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
22150     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
22151 
22152     CProfileBiasGain Profile;
22153 
22154     if ((ptrBias != NULL) && (ptrGain != NULL))
22155     {
22156         Profile.SetBias((AFp) Bias);
22157         Profile.SetGain((AFp) Gain);
22158     }
22159 
22160     if (ok)
22161     {
22162         AttrSquareTranspFill* pAttr = new AttrSquareTranspFill;
22163         if (pAttr != NULL)
22164         {
22165             SquareTranspFillAttribute* pValue = (SquareTranspFillAttribute*)pAttr->GetAttributeValue();
22166 
22167             if (pValue != NULL)
22168             {
22169                 pValue->SetStartPoint(&StartPoint);
22170                 pValue->SetEndPoint(&EndPoint);
22171                 pValue->SetEndPoint2(&EndPoint2);
22172 
22173                 pValue->Transp      = UINT32(Transp);
22174                 pValue->EndTransp   = UINT32(EndTransp);
22175                 pValue->TranspType  = UINT32(TranspType);
22176                 pValue->SetProfile (Profile);
22177                 ok = InsertNode(pAttr);
22178             }
22179             else
22180                 ok = FALSE;
22181         }
22182         else
22183             ok = FALSE;
22184     }
22185 
22186     return ok;
22187 }
22188 
22189 /********************************************************************************************
22190 
22191 >   BOOL FillAttrRecordHandler::HandleThreeColTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22192 
22193     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
22194     Created:    9/8/96
22195     Inputs:     pCXaraFileRecord = ptr to record to handle
22196     Returns:    TRUE if handled successfuly
22197                 FALSE otherwise
22198     Purpose:    Handles the given record.
22199                 The record has to be a ThreeCol transparent fill record
22200     SeeAlso:    -
22201 
22202 ********************************************************************************************/
22203 
22204 BOOL FillAttrRecordHandler::HandleThreeColTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22205 {
22206     UINT32 Tag = pCXaraFileRecord->GetTag();
22207 
22208     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22209     ERROR2IF(Tag != TAG_THREECOLTRANSPARENTFILL,FALSE,"I don't handle this tag type");
22210 
22211     BOOL ok = TRUE;
22212 
22213     DocCoord StartPoint;
22214     DocCoord EndPoint;
22215     DocCoord EndPoint2;
22216     BYTE Transp;
22217     BYTE EndTransp;
22218     BYTE EndTransp2;
22219     BYTE TranspType;
22220 
22221     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
22222     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
22223     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
22224 
22225     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
22226     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
22227     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp2);
22228     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
22229 
22230     if (ok)
22231     {
22232         AttrThreeColTranspFill* pAttr = new AttrThreeColTranspFill;
22233         if (pAttr != NULL)
22234         {
22235             ThreeColTranspFillAttribute* pValue = (ThreeColTranspFillAttribute*)pAttr->GetAttributeValue();
22236 
22237             if (pValue != NULL)
22238             {
22239                 pValue->SetStartPoint(&StartPoint);
22240                 pValue->SetEndPoint(&EndPoint);
22241                 pValue->SetEndPoint2(&EndPoint2);
22242 
22243                 pValue->Transp      = UINT32(Transp);
22244                 pValue->EndTransp   = UINT32(EndTransp);
22245                 pValue->EndTransp2  = UINT32(EndTransp2);
22246                 pValue->TranspType  = UINT32(TranspType);
22247                 ok = InsertNode(pAttr);
22248             }
22249             else
22250                 ok = FALSE;
22251         }
22252         else
22253             ok = FALSE;
22254     }
22255 
22256     return ok;
22257 }
22258 
22259 /********************************************************************************************
22260 
22261 >   BOOL FillAttrRecordHandler::HandleFourColTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22262 
22263     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
22264     Created:    9/8/96
22265     Inputs:     pCXaraFileRecord = ptr to record to handle
22266     Returns:    TRUE if handled successfuly
22267                 FALSE otherwise
22268     Purpose:    Handles the given record.
22269                 The record has to be a FourCol transparent fill record
22270     SeeAlso:    -
22271 
22272 ********************************************************************************************/
22273 
22274 BOOL FillAttrRecordHandler::HandleFourColTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22275 {
22276     UINT32 Tag = pCXaraFileRecord->GetTag();
22277 
22278     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22279     ERROR2IF(Tag != TAG_FOURCOLTRANSPARENTFILL,FALSE,"I don't handle this tag type");
22280 
22281     BOOL ok = TRUE;
22282 
22283     DocCoord StartPoint;
22284     DocCoord EndPoint;
22285     DocCoord EndPoint2;
22286     BYTE Transp;
22287     BYTE EndTransp;
22288     BYTE EndTransp2;
22289     BYTE EndTransp3;
22290     BYTE TranspType;
22291 
22292     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
22293     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
22294     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
22295 
22296     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
22297     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
22298     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp2);
22299     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp3);
22300     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
22301 
22302     if (ok)
22303     {
22304         AttrFourColTranspFill* pAttr = new AttrFourColTranspFill;
22305         if (pAttr != NULL)
22306         {
22307             FourColTranspFillAttribute* pValue = (FourColTranspFillAttribute*)pAttr->GetAttributeValue();
22308 
22309             if (pValue != NULL)
22310             {
22311                 pValue->SetStartPoint(&StartPoint);
22312                 pValue->SetEndPoint(&EndPoint);
22313                 pValue->SetEndPoint2(&EndPoint2);
22314 
22315                 pValue->Transp      = UINT32(Transp);
22316                 pValue->EndTransp   = UINT32(EndTransp);
22317                 pValue->EndTransp2  = UINT32(EndTransp2);
22318                 pValue->EndTransp3  = UINT32(EndTransp3);
22319                 pValue->TranspType  = UINT32(TranspType);
22320                 ok = InsertNode(pAttr);
22321             }
22322             else
22323                 ok = FALSE;
22324         }
22325         else
22326             ok = FALSE;
22327     }
22328 
22329     return ok;
22330 }
22331 
22332 /********************************************************************************************
22333 
22334 >   BOOL FillAttrRecordHandler::HandleBitmapTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22335 
22336     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
22337     Created:    26/6/96
22338     Inputs:     pCXaraFileRecord = ptr to record to handle
22339     Returns:    TRUE if handled successfuly
22340                 FALSE otherwise
22341     Purpose:    Handles the given record.
22342                 The record has to be a Transparent bitmap fill record
22343     SeeAlso:    -
22344 
22345 ********************************************************************************************/
22346 
22347 BOOL FillAttrRecordHandler::HandleBitmapTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22348 {
22349     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22350     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_BITMAPTRANSPARENTFILL,FALSE,"I don't handle this tag type");
22351 
22352     BOOL ok = TRUE;
22353 
22354     DocCoord StartPoint, EndPoint, EndPoint2;
22355     INT32 BitmapRef;
22356     BYTE Transp,EndTransp,TranspType;
22357     double Bias = 0, Gain = 0;
22358     double* ptrBias = &Bias, *ptrGain = &Gain;
22359 
22360     // Read in the bitmap fill data
22361     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
22362     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
22363     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
22364     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
22365     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
22366     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
22367     if (ok) ok = pCXaraFileRecord->ReadINT32(&BitmapRef);
22368     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
22369     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
22370 
22371     CProfileBiasGain Profile;
22372 
22373     if ((ptrBias != NULL) && (ptrGain != NULL))
22374     {
22375         Profile.SetBias((AFp) Bias);
22376         Profile.SetGain((AFp) Gain);
22377     }
22378 
22379     if (ok)
22380     {
22381         AttrBitmapTranspFill* pAttr = new AttrBitmapTranspFill;
22382         if (pAttr != NULL)
22383         {
22384             // Get a ptr to the attr value object
22385             BitmapTranspFillAttribute* pValue = (BitmapTranspFillAttribute*)pAttr->GetAttributeValue();
22386 
22387             if (pValue != NULL)
22388             {
22389                 // Store the start and end points
22390                 pValue->SetStartPoint(&StartPoint);
22391                 pValue->SetEndPoint(&EndPoint);
22392                 pValue->SetEndPoint2(&EndPoint2);
22393                 pValue->Transp      = UINT32(Transp);
22394                 pValue->EndTransp   = UINT32(EndTransp);
22395                 pValue->TranspType  = UINT32(TranspType);
22396                 pValue->SetProfile (Profile);
22397 
22398                 // Convert the bmp reference into a kernel bmp, and insert the attr into the tree
22399                 KernelBitmap * pBitmap = NULL;
22400                 pBitmap = GetReadBitmapReference(BitmapRef);
22401 
22402                 ok = (pBitmap != NULL);
22403                 if (ok) ok = pValue->AttachBitmap(pBitmap);
22404                 if (ok) ok = InsertNode(pAttr);
22405             }
22406             else
22407                 ok = FALSE;
22408         }
22409         else
22410             ok = FALSE;
22411     }
22412 
22413     return ok;
22414 }
22415 
22416 /********************************************************************************************
22417 
22418 >   BOOL FillAttrRecordHandler::HandleFractalTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22419 
22420     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
22421     Created:    26/6/96
22422     Inputs:     pCXaraFileRecord = ptr to record to handle
22423     Returns:    TRUE if handled successfuly
22424                 FALSE otherwise
22425     Purpose:    Handles the given record.
22426                 The record must be a transparent fractal fill record
22427     SeeAlso:    -
22428 
22429 ********************************************************************************************/
22430 
22431 BOOL FillAttrRecordHandler::HandleFractalTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22432 {
22433     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22434     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_FRACTALTRANSPARENTFILL,FALSE,"I don't handle this tag type");
22435 
22436     BOOL ok = TRUE;
22437 
22438     DocCoord StartPoint, EndPoint, EndPoint2;
22439     BYTE Transp,EndTransp,TranspType;
22440     INT32 Seed, DPI;
22441     FIXED16 Graininess, Gravity, Squash;
22442     BYTE Tileable;
22443     double Bias = 0, Gain = 0;
22444     double* ptrBias = &Bias, *ptrGain = &Gain;
22445 
22446     // Read in the fractal fill data
22447     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
22448     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
22449     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
22450     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
22451     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
22452     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
22453 
22454     if (ok) ok = pCXaraFileRecord->ReadINT32(&Seed);
22455     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Graininess);
22456     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Gravity);
22457     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Squash);
22458     if (ok) ok = pCXaraFileRecord->ReadINT32(&DPI);
22459     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Tileable);
22460     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
22461     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
22462 
22463     CProfileBiasGain Profile;
22464 
22465     if ((ptrBias != NULL) && (ptrGain != NULL))
22466     {
22467         Profile.SetBias((AFp) Bias);
22468         Profile.SetGain((AFp) Gain);
22469     }
22470 
22471     if (ok)
22472     {
22473         AttrFractalTranspFill* pAttr = new AttrFractalTranspFill;
22474         if (pAttr != NULL)
22475         {
22476             // Get a ptr to the attr value object
22477             FractalTranspFillAttribute* pValue = (FractalTranspFillAttribute*)pAttr->GetAttributeValue();
22478 
22479             if (pValue != NULL)
22480             {
22481                 // Store the start and end points
22482                 pValue->SetStartPoint(&StartPoint);
22483                 pValue->SetEndPoint(&EndPoint);
22484                 pValue->SetEndPoint2(&EndPoint2);
22485                 pValue->Transp      = UINT32(Transp);
22486                 pValue->EndTransp   = UINT32(EndTransp);
22487                 pValue->TranspType  = UINT32(TranspType);
22488                                        
22489                 // Store the fractal data
22490                 pValue->SetSeed(Seed);
22491                 pValue->SetGraininess(Graininess);
22492                 pValue->SetGravity(Gravity);
22493                 pValue->SetSquash(Squash);
22494                 pValue->SetFractalDPI(DPI);
22495                 pValue->SetTileable(Tileable);
22496                 pValue->SetProfile (Profile);
22497 
22498                 // Recreate the fractal, and insert the attr into the tree
22499                 if (ok) ok = pValue->RecalcFractal();
22500                 if (ok) ok = InsertNode(pAttr);
22501             }
22502             else
22503                 ok = FALSE;
22504         }
22505         else
22506             ok = FALSE;
22507     }
22508 
22509     return ok;
22510 }
22511 
22512 
22513 
22514 /********************************************************************************************
22515 
22516 >   BOOL FillAttrRecordHandler::HandleNoiseTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22517 
22518     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
22519     Created:    24/1/96
22520     Inputs:     pCXaraFileRecord = ptr to record to handle
22521     Returns:    TRUE if handled successfuly
22522                 FALSE otherwise
22523     Purpose:    Handles the given record.
22524                 The record must be a transparent noise fill record
22525     SeeAlso:    -
22526 
22527 ********************************************************************************************/
22528 
22529 BOOL FillAttrRecordHandler::HandleNoiseTransparentFillRecord(CXaraFileRecord* pCXaraFileRecord)
22530 {
22531     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22532     ERROR2IF(pCXaraFileRecord->GetTag() != TAG_NOISETRANSPARENTFILL,FALSE,"I don't handle this tag type");
22533 
22534     BOOL ok = TRUE;
22535 
22536     DocCoord StartPoint, EndPoint, EndPoint2;
22537     BYTE Transp,EndTransp,TranspType;
22538     INT32 DPI;
22539     FIXED16 Grain;
22540     INT32 Seed;
22541     BYTE Tileable;
22542     double Bias = 0, Gain = 0;
22543     double* ptrBias = &Bias, *ptrGain = &Gain;
22544 
22545     // Read in the fractal fill data
22546     if (ok) ok = pCXaraFileRecord->ReadCoord(&StartPoint);
22547     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint);
22548     if (ok) ok = pCXaraFileRecord->ReadCoord(&EndPoint2);
22549     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Transp);
22550     if (ok) ok = pCXaraFileRecord->ReadBYTE(&EndTransp);
22551     if (ok) ok = pCXaraFileRecord->ReadBYTE(&TranspType);
22552     if (ok) ok = pCXaraFileRecord->ReadFIXED16(&Grain);
22553     if (ok) ok = pCXaraFileRecord->ReadINT32(&Seed);
22554     if (ok) ok = pCXaraFileRecord->ReadINT32(&DPI);
22555     if (ok) ok = pCXaraFileRecord->ReadBYTE(&Tileable);
22556     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias);
22557     if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain);
22558 
22559     CProfileBiasGain Profile;
22560 
22561     if ((ptrBias != NULL) && (ptrGain != NULL))
22562     {
22563         Profile.SetBias((AFp) Bias);
22564         Profile.SetGain((AFp) Gain);
22565     }
22566 
22567     if (ok)
22568     {
22569         AttrNoiseTranspFill* pAttr = new AttrNoiseTranspFill;
22570         if (pAttr != NULL)
22571         {
22572             // Get a ptr to the attr value object
22573             NoiseTranspFillAttribute* pValue = (NoiseTranspFillAttribute*)pAttr->GetAttributeValue();
22574 
22575             if (pValue != NULL)
22576             {
22577                 // Store the start and end points
22578                 pValue->SetStartPoint(&StartPoint);
22579                 pValue->SetEndPoint(&EndPoint);
22580                 pValue->SetEndPoint2(&EndPoint2);
22581                 pValue->Transp      = UINT32(Transp);
22582                 pValue->EndTransp   = UINT32(EndTransp);
22583                 pValue->TranspType  = UINT32(TranspType);
22584                                        
22585                 // Store the fractal data
22586                 pValue->SetGraininess(Grain);
22587                 pValue->SetSeed(Seed);
22588                 pValue->SetFractalDPI(DPI);
22589                 pValue->SetTileable(Tileable);
22590                 pValue->SetProfile (Profile);
22591 
22592                 // Recreate the fractal, and insert the attr into the tree
22593                 if (ok) ok = pValue->RecalcFractal();
22594                 if (ok) ok = InsertNode(pAttr);
22595             }
22596             else
22597                 ok = FALSE;
22598         }
22599         else
22600             ok = FALSE;
22601     }
22602 
22603     return ok;
22604 }
22605 
22606 
22607 
22608 //----------------------------------------------------------------------------------
22609 //----------------------------------------------------------------------------------
22610 //----------------------------------------------------------------------------------
22611 
22612 /********************************************************************************************
22613 
22614 >   BOOL FillAttrRecordHandler::HandleFillRepeatRecord(CXaraFileRecord* pCXaraFileRecord)
22615 
22616     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
22617     Created:    27/6/96
22618     Inputs:     pCXaraFileRecord = ptr to record to handle
22619     Returns:    TRUE if handled successfuly
22620                 FALSE otherwise
22621     Purpose:    Handles the given record.
22622                 The record has to be a fill repeat record
22623 
22624                 Social comment:
22625                 England lost against Germany last night in the Euro96 semi-final, 6-5 on penalties (1-1 after extra time).
22626                 I'm devastated.  I can't believe England could be so unlucky.  I no longer have the will to work.
22627     SeeAlso:    -
22628 
22629 ********************************************************************************************/
22630 
22631 BOOL FillAttrRecordHandler::HandleFillRepeatRecord(CXaraFileRecord* pCXaraFileRecord)
22632 {
22633     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22634 
22635     INT32 Repeat;
22636 
22637     switch (pCXaraFileRecord->GetTag())
22638     {
22639         case TAG_FILL_NONREPEATING:     Repeat = 1; break;
22640         case TAG_FILL_REPEATING:        Repeat = 2; break;
22641         case TAG_FILL_REPEATINGINVERTED:Repeat = 3; break;
22642 //Mark Howitt, 8/10/97. Make grad fills a special case for backwards compatability
22643 #ifdef NEW_FEATURES
22644         case TAG_FILL_REPEATING_EXTRA:  Repeat = 4; break;
22645 #endif
22646         default:
22647             ERROR3("Do what? I only do fill repeat records mate");
22648             return TRUE;
22649             break;
22650     }
22651 
22652     AttrFillMappingLinear* pAttr = new AttrFillMappingLinear;
22653     if (pAttr != NULL)
22654     {
22655         pAttr->Value.Repeat = Repeat;
22656         return InsertNode(pAttr);
22657     }
22658 
22659     return FALSE;
22660 }
22661 
22662 /********************************************************************************************
22663 
22664 >   BOOL FillAttrRecordHandler::HandleTransparentFillRepeatRecord(CXaraFileRecord* pCXaraFileRecord)
22665 
22666     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
22667     Created:    27/6/96
22668     Inputs:     pCXaraFileRecord = ptr to record to handle
22669     Returns:    TRUE if handled successfuly
22670                 FALSE otherwise
22671     Purpose:    Handles the given record.
22672                 The record has to be a transparent fill repeat record
22673     SeeAlso:    -
22674 
22675 ********************************************************************************************/
22676 
22677 BOOL FillAttrRecordHandler::HandleTransparentFillRepeatRecord(CXaraFileRecord* pCXaraFileRecord)
22678 {
22679     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22680 
22681     INT32 Repeat;
22682 
22683     switch (pCXaraFileRecord->GetTag())
22684     {
22685         case TAG_TRANSPARENTFILL_NONREPEATING:      Repeat = 1; break;
22686         case TAG_TRANSPARENTFILL_REPEATING:         Repeat = 2; break;
22687         case TAG_TRANSPARENTFILL_REPEATINGINVERTED: Repeat = 3; break;
22688     //Mark Howitt. 8/10/97. (well actually Chris Snook - 8/12/99); cause we need to do it here
22689     //as well - Make repeating grad fills a special case
22690 #ifdef NEW_FEATURES
22691         case TAG_TRANSPARENTFILL_REPEATING_EXTRA:               Repeat = 4; break;
22692 #endif
22693 
22694         default:
22695             ERROR3("Do what? I only do trans fill repeat records mate");
22696             return TRUE;
22697             break;
22698     }
22699 
22700     AttrTranspFillMappingLinear* pAttr = new AttrTranspFillMappingLinear;
22701     if (pAttr != NULL)
22702     {
22703         pAttr->Value.Repeat = Repeat;
22704         return InsertNode(pAttr);
22705     }
22706 
22707     return FALSE;
22708 }
22709 
22710 /********************************************************************************************
22711 
22712 >   BOOL FillAttrRecordHandler::HandleFillEffectRecord(CXaraFileRecord* pCXaraFileRecord)
22713 
22714     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
22715     Created:    25/6/96
22716     Inputs:     pCXaraFileRecord = ptr to record to handle
22717     Returns:    TRUE if handled successfuly
22718                 FALSE otherwise
22719     Purpose:    Handles the given record.
22720                 The record has to be a linear fill record
22721     SeeAlso:    -
22722 
22723 ********************************************************************************************/
22724 
22725 BOOL FillAttrRecordHandler::HandleFillEffectRecord(CXaraFileRecord* pCXaraFileRecord)
22726 {
22727     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL");
22728 
22729     AttrFillEffect* pAttr = NULL;
22730     switch (pCXaraFileRecord->GetTag())
22731     {
22732         case TAG_FILLEFFECT_ALTRAINBOW: pAttr = new AttrFillEffectAltRainbow;   break;
22733         case TAG_FILLEFFECT_RAINBOW:    pAttr = new AttrFillEffectRainbow;      break;
22734         case TAG_FILLEFFECT_FADE:       pAttr = new AttrFillEffectFade;         break;
22735 
22736         default:
22737             ERROR3("Do what? I only do fill effect records mate");
22738             return TRUE;
22739             break;
22740     }
22741 
22742     if (pAttr != NULL)
22743         return InsertNode(pAttr);
22744 
22745     return FALSE;
22746 }
22747 
22748 // Lots of simple virtual functions. Note these were declared in the class, but being virtual they won't
22749 // be inlined anyway (as an address for them is needed) so we might as well get the compile benefit
22750 DocColour* AttrFillGeometry::GetStartColour()   { return ATTRVALUE()->GetStartColour(); }
22751 DocColour* AttrFillGeometry::GetEndColour()     { return ATTRVALUE()->GetEndColour();  }
22752 DocColour* AttrFillGeometry::GetEndColour2()    { return ATTRVALUE()->GetEndColour2(); }
22753 DocColour* AttrFillGeometry::GetEndColour3()    { return ATTRVALUE()->GetEndColour3(); }
22754 UINT32*    AttrFillGeometry::GetStartTransp()   { return ATTRVALUE()->GetStartTransp(); }
22755 UINT32*    AttrFillGeometry::GetEndTransp()     { return ATTRVALUE()->GetEndTransp();  }
22756 UINT32*    AttrFillGeometry::GetEndTransp2()    { return ATTRVALUE()->GetEndTransp2(); }
22757 UINT32*    AttrFillGeometry::GetEndTransp3()    { return ATTRVALUE()->GetEndTransp3(); }
22758 DocCoord*  AttrFillGeometry::GetStartPoint()    { return ATTRVALUE()->GetStartPoint(); }
22759 DocCoord*  AttrFillGeometry::GetEndPoint()      { return ATTRVALUE()->GetEndPoint();  }
22760 DocCoord*  AttrFillGeometry::GetEndPoint2()     { return ATTRVALUE()->GetEndPoint2(); }
22761 DocCoord*  AttrFillGeometry::GetEndPoint3()     { return ATTRVALUE()->GetEndPoint3(); }
22762 CProfileBiasGain& AttrFillGeometry::GetProfile ()   { return ATTRVALUE()->GetProfile (); }
22763 
22764 void AttrFillGeometry::SetStartColour(DocColour* NewCol){ ATTRVALUE()->SetStartColour(NewCol); }
22765 void AttrFillGeometry::SetEndColour(DocColour* NewCol)  { ATTRVALUE()->SetEndColour(NewCol); }
22766 void AttrFillGeometry::SetEndColour2(DocColour* NewCol) { ATTRVALUE()->SetEndColour2(NewCol); }
22767 void AttrFillGeometry::SetEndColour3(DocColour* NewCol) { ATTRVALUE()->SetEndColour3(NewCol); }
22768 void AttrFillGeometry::SetStartTransp(UINT32* NewTransp){ ATTRVALUE()->SetStartTransp(NewTransp); }
22769 void AttrFillGeometry::SetEndTransp(UINT32* NewTransp)  { ATTRVALUE()->SetEndTransp(NewTransp); }
22770 void AttrFillGeometry::SetEndTransp2(UINT32* NewTransp) { ATTRVALUE()->SetEndTransp2(NewTransp); }
22771 void AttrFillGeometry::SetEndTransp3(UINT32* NewTransp) { ATTRVALUE()->SetEndTransp3(NewTransp); }
22772 void AttrFillGeometry::SetStartPoint(DocCoord* Pos)     { ATTRVALUE()->SetStartPoint(Pos); }
22773 void AttrFillGeometry::SetEndPoint(DocCoord* Pos)       { ATTRVALUE()->SetEndPoint(Pos); }
22774 void AttrFillGeometry::SetEndPoint2(DocCoord* Pos)      { ATTRVALUE()->SetEndPoint2(Pos); }
22775 void AttrFillGeometry::SetEndPoint3(DocCoord* Pos)      { ATTRVALUE()->SetEndPoint3(Pos); }
22776 void AttrFillGeometry::SetProfile (CProfileBiasGain& SetWith) { ATTRVALUE()->SetProfile(SetWith); }
22777 
22778 UINT32  AttrFillGeometry::GetTranspType()   { return ATTRVALUE()->GetTranspType(); }
22779 UINT32  AttrFillGeometry::GetDPI()          { return ATTRVALUE()->GetDPI(); }
22780 UINT32  AttrFillGeometry::GetFractalDPI()   { return ATTRVALUE()->GetFractalDPI(); }
22781 UINT32  AttrFillGeometry::GetFractalDim()   { return ATTRVALUE()->GetFractalDim(); }
22782 INT32   AttrFillGeometry::GetSeed()         { return ATTRVALUE()->GetSeed(); }
22783 FIXED16 AttrFillGeometry::GetGraininess()   { return ATTRVALUE()->GetGraininess(); }
22784 FIXED16 AttrFillGeometry::GetGravity()      { return ATTRVALUE()->GetGravity(); }
22785 FIXED16 AttrFillGeometry::GetSquash()       { return ATTRVALUE()->GetSquash(); }
22786 BOOL    AttrFillGeometry::GetTileable()     { return ATTRVALUE()->GetTileable(); }
22787 double  AttrFillGeometry::GetNoiseScale()   { return ATTRVALUE()->GetNoiseScale(); }
22788 
22789 void    AttrFillGeometry::SetTranspType(UINT32 NewType)     {        ATTRVALUE()->SetTranspType(NewType); }
22790 BOOL    AttrFillGeometry::SetDPI(UINT32 NewDpi)             { return ATTRVALUE()->SetDPI(NewDpi); }
22791 BOOL    AttrFillGeometry::SetFractalDPI(UINT32 NewDpi)      { return ATTRVALUE()->SetFractalDPI(NewDpi); }
22792 void    AttrFillGeometry::SetFractalDim(UINT32 NewDim)      {        ATTRVALUE()->SetFractalDim(NewDim); }
22793 BOOL    AttrFillGeometry::SetSeed(INT32 NewSeed)            { return ATTRVALUE()->SetSeed(NewSeed); }
22794 BOOL    AttrFillGeometry::SetGraininess(FIXED16 NewGrain) { return ATTRVALUE()->SetGraininess(NewGrain); }
22795 BOOL    AttrFillGeometry::SetGravity(FIXED16 NewGrav)       { return ATTRVALUE()->SetGravity(NewGrav); }
22796 BOOL    AttrFillGeometry::SetSquash(FIXED16 NewSquash)  { return ATTRVALUE()->SetSquash(NewSquash); }
22797 BOOL    AttrFillGeometry::SetTileable(BOOL NewTile)     { return ATTRVALUE()->SetTileable(NewTile); }
22798 BOOL    AttrFillGeometry::SetNoiseScale(double ns)      { return ATTRVALUE()->SetNoiseScale(ns); }
22799 
22800 BOOL    AttrFillGeometry::RecalcFractal() { return ATTRVALUE()->RecalcFractal(); }
22801 BOOL    AttrFillGeometry::Randomise()    { return ATTRVALUE()->Randomise(); }
22802 
22803 BOOL    AttrFillGeometry::AttachBitmap(KernelBitmap* NewBitmap) { return ATTRVALUE()->AttachBitmap(NewBitmap); }
22804 BOOL    AttrFillGeometry::DetachBitmap() { return ATTRVALUE()->DetachBitmap(); }
22805 KernelBitmap* AttrFillGeometry::GetBitmap() { return ATTRVALUE()->GetBitmap(); }
22806 BOOL    AttrFillGeometry::CopyBitmap(KernelBitmap* CopyBitmap) { return ATTRVALUE()->CopyBitmap(CopyBitmap); }
22807 
22808 KernelBitmapRef* AttrFillGeometry::GetBitmapRef() { return ATTRVALUE()->GetBitmapRef(); }
22809 
22810 INT32 AttrFillGeometry::GetTesselation() { return ATTRVALUE()->GetTesselation(); }
22811 void AttrFillGeometry::SetTesselation(INT32 NewTess) { ATTRVALUE()->SetTesselation(NewTess); }
22812 BOOL AttrFillGeometry::IsPerspective() { return ATTRVALUE()->IsPerspective(); }
22813 ColourRamp*       AttrFillGeometry::GetColourRamp() { return ATTRVALUE()->GetColourRamp(); }
22814 TransparencyRamp* AttrFillGeometry::GetTranspRamp() { return ATTRVALUE()->GetTranspRamp(); }
22815 void AttrFillGeometry::SetColourRamp(ColourRamp* New) { ATTRVALUE()->SetColourRamp (New); }
22816 void AttrFillGeometry::SetTranspRamp(TransparencyRamp* New) { ATTRVALUE()->SetTranspRamp(New); }
22817 
22818 
22819 /********************************************************************************************
22820 
22821 >   virtual void FillAttrRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pRecord,StringBase* pStr)
22822 
22823     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
22824     Created:    13/6/96
22825     Inputs:     pRecord = ptr to a record
22826                 pStr = ptr to string to update
22827     Returns:    -
22828     Purpose:    This provides descriptions for the fill attribute record.
22829     Errors:     -
22830     SeeAlso:    -
22831 
22832 ********************************************************************************************/
22833 
22834 #ifdef XAR_TREE_DIALOG
22835 void FillAttrRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pRecord,StringBase* pStr)
22836 {
22837     if (pStr == NULL || pRecord == NULL)
22838         return;
22839 
22840     // Call base class first
22841     // This outputs the tag and size
22842     CamelotRecordHandler::GetRecordDescriptionText(pRecord,pStr);
22843 
22844     TCHAR s[256];
22845 
22846     UINT32 Tag = pRecord->GetTag();
22847     switch (Tag)
22848     {
22849         case TAG_FLATFILL :
22850         {
22851             // Read the colour reference number
22852             INT32 ColourRef;
22853             pRecord->ReadINT32(&ColourRef);
22854             camSprintf(s,_T("Colour reference = %d\r\n"),ColourRef);    (*pStr) += s;
22855         }
22856         break;
22857 
22858         case TAG_LINEARFILL :
22859         case TAG_LINEARFILL3POINT :
22860         case TAG_ELLIPTICALFILL :
22861         case TAG_CIRCULARFILL :
22862         case TAG_CONICALFILL :
22863         case TAG_SQUAREFILL :
22864         {
22865             DocCoord StartPoint, EndPoint, EndPoint2;
22866             INT32 StartColourRef,EndColourRef;
22867 
22868             // Read in the linear fill data
22869             pRecord->ReadCoord(&StartPoint);
22870             pRecord->ReadCoord(&EndPoint);
22871             if (Tag == TAG_ELLIPTICALFILL || Tag == TAG_SQUAREFILL || Tag==TAG_LINEARFILL3POINT)
22872                 pRecord->ReadCoord(&EndPoint2);
22873             pRecord->ReadINT32(&StartColourRef);
22874             pRecord->ReadINT32(&EndColourRef);
22875 
22876             camSprintf(s,_T("Start Colour ref\t= %d\r\n"),StartColourRef);              (*pStr) += s;
22877             camSprintf(s,_T("End Colour ref\t= %d\r\n"),EndColourRef);                  (*pStr) += s;
22878             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y); (*pStr) += s;
22879             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);     (*pStr) += s;
22880             if (Tag == TAG_ELLIPTICALFILL || Tag == TAG_SQUAREFILL || Tag==TAG_LINEARFILL3POINT)
22881             {
22882                 camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);   (*pStr) += s;
22883             }
22884         }
22885         break;
22886 
22887         case TAG_THREECOLFILL :
22888         case TAG_FOURCOLFILL :
22889         {
22890             DocCoord StartPoint, EndPoint, EndPoint2;
22891             INT32 StartColourRef,EndColourRef, EndColourRef2, EndColourRef3;
22892 
22893             // Read in the linear fill data
22894             pRecord->ReadCoord(&StartPoint);
22895             pRecord->ReadCoord(&EndPoint);
22896             pRecord->ReadCoord(&EndPoint2);
22897             pRecord->ReadINT32(&StartColourRef);
22898             pRecord->ReadINT32(&EndColourRef);
22899             pRecord->ReadINT32(&EndColourRef2);
22900             if (Tag == TAG_FOURCOLFILL)
22901                 pRecord->ReadINT32(&EndColourRef3);
22902 
22903             camSprintf(s,_T("Start Colour ref\t= %d\r\n"),StartColourRef);              (*pStr) += s;
22904             camSprintf(s,_T("End Colour ref\t= %d\r\n"),EndColourRef);                  (*pStr) += s;
22905             camSprintf(s,_T("End Colour2 ref\t= %d\r\n"),EndColourRef2);                    (*pStr) += s;
22906             if (Tag == TAG_FOURCOLFILL)
22907             {
22908                 camSprintf(s,_T("End Colour3 ref\t= %d\r\n"),EndColourRef3);                (*pStr) += s;
22909             }
22910             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y);     (*pStr) += s;
22911             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);         (*pStr) += s;
22912             camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);       (*pStr) += s;
22913         }
22914         break;
22915 
22916         case TAG_BITMAPFILL :
22917         case TAG_CONTONEBITMAPFILL :
22918         {
22919             DocCoord StartPoint, EndPoint, EndPoint2;
22920             INT32 BitmapRef;
22921             INT32 StartColourRef,EndColourRef;
22922 
22923             // Read in the linear fill data
22924             pRecord->ReadCoord(&StartPoint);
22925             pRecord->ReadCoord(&EndPoint);
22926             pRecord->ReadCoord(&EndPoint2);
22927             if (Tag == TAG_CONTONEBITMAPFILL)
22928             {
22929                 pRecord->ReadINT32(&StartColourRef);
22930                 pRecord->ReadINT32(&EndColourRef);
22931             }
22932             pRecord->ReadINT32(&BitmapRef);
22933 
22934             camSprintf(s,_T("Bitmap reference\t= %d\r\n"),BitmapRef);                   (*pStr) += s;
22935             if (Tag == TAG_CONTONEBITMAPFILL)
22936             {
22937                 camSprintf(s,_T("Start Colour ref\t= %d\r\n"),StartColourRef);          (*pStr) += s;
22938                 camSprintf(s,_T("End Colour ref\t= %d\r\n"),EndColourRef);              (*pStr) += s;
22939             }
22940             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y); (*pStr) += s;
22941             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);     (*pStr) += s;
22942             camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);       (*pStr) += s;
22943         }
22944         break;
22945 
22946         case TAG_FRACTALFILL:
22947         {
22948             DocCoord StartPoint, EndPoint, EndPoint2;
22949             INT32 StartColRef,EndColRef, Seed, DPI;
22950             FIXED16 Graininess, Gravity, Squash;
22951             BYTE Tileable;
22952             double d = 1.0;
22953 
22954             // Read in the fractal fill data
22955             pRecord->ReadCoord(&StartPoint);
22956             pRecord->ReadCoord(&EndPoint);
22957             pRecord->ReadCoord(&EndPoint2);
22958             pRecord->ReadINT32(&StartColRef);
22959             pRecord->ReadINT32(&EndColRef);
22960 
22961             pRecord->ReadINT32(&Seed);
22962             pRecord->ReadFIXED16(&Graininess);
22963             pRecord->ReadFIXED16(&Gravity);
22964             pRecord->ReadFIXED16(&Squash);
22965             pRecord->ReadINT32(&DPI);
22966             pRecord->ReadBYTE(&Tileable);
22967 
22968             camSprintf(s,_T("Start Colour ref\t= %d\r\n"),StartColRef);             (*pStr) += s;
22969             camSprintf(s,_T("End Colour ref\t= %d\r\n"),EndColRef);                 (*pStr) += s;
22970 
22971             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y); (*pStr) += s;
22972             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);         (*pStr) += s;
22973             camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);       (*pStr) += s;
22974 
22975             camSprintf(s,_T("Seed\t\t= %d\r\n"),Seed);                                  (*pStr) += s;
22976 
22977             d = Graininess.MakeDouble();camSprintf(s,_T("Graininess\t= %g\r\n"),d); (*pStr) += s;
22978             d = Gravity.MakeDouble();   camSprintf(s,_T("Gravity\t\t= %g\r\n"),d);      (*pStr) += s;
22979             d = Squash.MakeDouble();    camSprintf(s,_T("Squash\t\t= %g\r\n"),d);       (*pStr) += s;
22980 
22981             camSprintf(s,_T("DPI\t\t= %d\r\n"),DPI);                                    (*pStr) += s;
22982             camSprintf(s,_T("Tileable\t\t= %d\r\n"),INT32(Tileable));                   (*pStr) += s;
22983         }
22984         break;
22985 
22986         case TAG_FLATTRANSPARENTFILL:
22987         {
22988             BYTE Transp,TranspType;
22989             pRecord->ReadBYTE(&Transp);
22990             pRecord->ReadBYTE(&TranspType);
22991 
22992             camSprintf(s,_T("Transparency\t\t= %d\r\n"),INT32(Transp));             (*pStr) += s;
22993             camSprintf(s,_T("Transparency Type\t\t= %d\r\n"),INT32(TranspType));    (*pStr) += s;
22994         }
22995         break;
22996 
22997         case TAG_LINEARTRANSPARENTFILL:
22998         case TAG_LINEARTRANSPARENTFILL3POINT:
22999         case TAG_ELLIPTICALTRANSPARENTFILL:
23000         case TAG_CIRCULARTRANSPARENTFILL:
23001         case TAG_CONICALTRANSPARENTFILL:
23002         case TAG_SQUARETRANSPARENTFILL:
23003         {
23004             DocCoord StartPoint, EndPoint, EndPoint2;
23005             BYTE Transp,EndTransp,TranspType;
23006 
23007             pRecord->ReadCoord(&StartPoint);
23008             pRecord->ReadCoord(&EndPoint);
23009             if (Tag == TAG_ELLIPTICALTRANSPARENTFILL || Tag == TAG_SQUARETRANSPARENTFILL || Tag==TAG_LINEARFILL3POINT)
23010                 pRecord->ReadCoord(&EndPoint2);
23011             pRecord->ReadBYTE(&Transp);
23012             pRecord->ReadBYTE(&EndTransp);
23013             pRecord->ReadBYTE(&TranspType);
23014 
23015             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y); (*pStr) += s;
23016             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);     (*pStr) += s;
23017             if (Tag == TAG_ELLIPTICALTRANSPARENTFILL || Tag == TAG_SQUARETRANSPARENTFILL || Tag==TAG_LINEARFILL3POINT)
23018             {
23019                 camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);   (*pStr) += s;
23020             }
23021             camSprintf(s,_T("Start Transparency\t= %d\r\n"),INT32(Transp));             (*pStr) += s;
23022             camSprintf(s,_T("End Transparency\t= %d\r\n"),INT32(EndTransp));            (*pStr) += s;
23023             camSprintf(s,_T("Transparency Type\t= %d\r\n"),INT32(TranspType));          (*pStr) += s;
23024         }
23025         break;
23026 
23027         case TAG_THREECOLTRANSPARENTFILL:
23028         case TAG_FOURCOLTRANSPARENTFILL:
23029         {
23030             DocCoord StartPoint;
23031             DocCoord EndPoint;
23032             DocCoord EndPoint2;
23033             BYTE Transp;
23034             BYTE EndTransp;
23035             BYTE EndTransp2;
23036             BYTE EndTransp3;
23037             BYTE TranspType;
23038 
23039             pRecord->ReadCoord(&StartPoint);
23040             pRecord->ReadCoord(&EndPoint);
23041             pRecord->ReadCoord(&EndPoint2);
23042             pRecord->ReadBYTE(&Transp);
23043             pRecord->ReadBYTE(&EndTransp);
23044             pRecord->ReadBYTE(&EndTransp2);
23045             if (Tag == TAG_FOURCOLTRANSPARENTFILL)
23046                 pRecord->ReadBYTE(&EndTransp3);
23047             pRecord->ReadBYTE(&TranspType);
23048 
23049             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y);     (*pStr) += s;
23050             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);         (*pStr) += s;
23051             camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);       (*pStr) += s;
23052             camSprintf(s,_T("Start Transparency\t= %d\r\n"),INT32(Transp));             (*pStr) += s;
23053             camSprintf(s,_T("End Transparency\t= %d\r\n"),INT32(EndTransp));                (*pStr) += s;
23054             camSprintf(s,_T("End Transparency2\t= %d\r\n"),INT32(EndTransp2));          (*pStr) += s;
23055 
23056             if (Tag == TAG_FOURCOLTRANSPARENTFILL)
23057             {
23058                 camSprintf(s,_T("End Transparency3\t= %d\r\n"),INT32(EndTransp3));      (*pStr) += s;
23059             }
23060 
23061             camSprintf(s,_T("Transparency Type\t= %d\r\n"),INT32(TranspType));          (*pStr) += s;
23062         }
23063         break;
23064 
23065         case TAG_BITMAPTRANSPARENTFILL:
23066         {
23067             DocCoord StartPoint, EndPoint, EndPoint2;
23068             INT32 BitmapRef;
23069             BYTE Transp,EndTransp,TranspType;
23070 
23071             // Read in the linear fill data
23072             pRecord->ReadCoord(&StartPoint);
23073             pRecord->ReadCoord(&EndPoint);
23074             pRecord->ReadCoord(&EndPoint2);
23075             pRecord->ReadBYTE(&Transp);
23076             pRecord->ReadBYTE(&EndTransp);
23077             pRecord->ReadBYTE(&TranspType);
23078             pRecord->ReadINT32(&BitmapRef);
23079 
23080             camSprintf(s,_T("Bitmap reference\t= %d\r\n"),BitmapRef);                   (*pStr) += s;
23081 
23082             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y); (*pStr) += s;
23083             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);     (*pStr) += s;
23084             camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);       (*pStr) += s;
23085 
23086             camSprintf(s,_T("Start Transparency\t= %d\r\n"),INT32(Transp));             (*pStr) += s;
23087             camSprintf(s,_T("End Transparency\t= %d\r\n"),INT32(EndTransp));            (*pStr) += s;
23088             camSprintf(s,_T("Transparency Type\t= %d\r\n"),INT32(TranspType));          (*pStr) += s;
23089 
23090         }
23091         break;
23092 
23093         case TAG_FRACTALTRANSPARENTFILL:
23094         {
23095             DocCoord StartPoint, EndPoint, EndPoint2;
23096             BYTE Transp,EndTransp,TranspType;
23097             INT32 Seed, DPI;
23098             FIXED16 Graininess, Gravity, Squash;
23099             BYTE Tileable;
23100             double d = 1.0;
23101 
23102             // Read in the fractal fill data
23103             pRecord->ReadCoord(&StartPoint);
23104             pRecord->ReadCoord(&EndPoint);
23105             pRecord->ReadCoord(&EndPoint2);
23106             pRecord->ReadBYTE(&Transp);
23107             pRecord->ReadBYTE(&EndTransp);
23108             pRecord->ReadBYTE(&TranspType);
23109 
23110             pRecord->ReadINT32(&Seed);
23111             pRecord->ReadFIXED16(&Graininess);
23112             pRecord->ReadFIXED16(&Gravity);
23113             pRecord->ReadFIXED16(&Squash);
23114             pRecord->ReadINT32(&DPI);
23115             pRecord->ReadBYTE(&Tileable);
23116 
23117             camSprintf(s,_T("Coord 1\t\t= (%d,%d)\r\n"),StartPoint.x,StartPoint.y); (*pStr) += s;
23118             camSprintf(s,_T("Coord 2\t\t= (%d,%d)\r\n"),EndPoint.x,EndPoint.y);         (*pStr) += s;
23119             camSprintf(s,_T("Coord 3\t\t= (%d,%d)\r\n"),EndPoint2.x,EndPoint2.y);       (*pStr) += s;
23120 
23121             camSprintf(s,_T("Start Transparency\t= %d\r\n"),INT32(Transp));             (*pStr) += s;
23122             camSprintf(s,_T("End Transparency\t= %d\r\n"),INT32(EndTransp));            (*pStr) += s;
23123             camSprintf(s,_T("Transparency Type\t= %d\r\n"),INT32(TranspType));          (*pStr) += s;
23124 
23125             camSprintf(s,_T("Seed\t\t= %d\r\n"),Seed);                                  (*pStr) += s;
23126 
23127             d = Graininess.MakeDouble();camSprintf(s,_T("Graininess\t= %g\r\n"),d); (*pStr) += s;
23128             d = Gravity.MakeDouble();   camSprintf(s,_T("Gravity\t\t= %g\r\n"),d);      (*pStr) += s;
23129             d = Squash.MakeDouble();    camSprintf(s,_T("Squash\t\t= %g\r\n"),d);       (*pStr) += s;
23130 
23131             camSprintf(s,_T("DPI\t\t= %d\r\n"),DPI);                                    (*pStr) += s;
23132             camSprintf(s,_T("Tileable\t\t= %d\r\n"),INT32(Tileable));                   (*pStr) += s;
23133         }
23134         break;
23135     }
23136 }
23137 #endif // _DEBUG

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