strkcomp.cpp

Go to the documentation of this file.
00001 // $Id: strkcomp.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // Stroke Doc-component classes.
00099 // These store brush-stroke definitions as clipart subtrees
00100 
00101 #include "camtypes.h"
00102 
00103 #include "strkcomp.h"
00104 
00105 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "camfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "colormgr.h"
00108 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 #include "cxftags.h"
00111 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 #include "layer.h"
00113 #include "ppvecstr.h"
00114 //#include "sgline.h"
00115 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "strkattr.h"
00117 #include "linecomp.h"
00118 #include "linedef.h"
00119 
00120 
00121 CC_IMPLEMENT_DYNAMIC(StrokeDefinition,      LineDefinition);
00122 CC_IMPLEMENT_DYNAMIC(StrokeComponent,       LineComponent)
00123 CC_IMPLEMENT_DYNAMIC(StrokeComponentClass,  DocComponentClass)
00124 
00125 
00126 DECLARE_SOURCE("$Revision: 1282 $");
00127 
00128 // Declare smart memory handling in Debug builds
00129 #define new CAM_DEBUG_NEW
00130 
00131 
00132 // Statics
00133 StrokeDefinition **StrokeComponent::pStrokeList = NULL;
00134 UINT32 StrokeComponent::CurrentSize = 0;
00135 UINT32 StrokeComponent::Used = 0;
00136 
00137 UINT32 StrokeComponent::ImportHandle    = 0;
00138 UINT32 StrokeComponent::ImportFlags = 0;
00139 UINT32 StrokeComponent::ImportData1 = 0;
00140 UINT32 StrokeComponent::ImportData2 = 0;
00141 InsertTreeContext *StrokeComponent::pImportPreviousContext = NULL;
00142 Node *StrokeComponent::pImportNewBrush = NULL;
00143 String_32 StrokeComponent::ImportedName;
00144 
00145 
00146 
00147 
00148 /********************************************************************************************
00149 
00150 >   StrokeDefinition::StrokeDefinition(Node *pStrokeTree, BOOL repeating = FALSE, INT32 repeats = 0);
00151 
00152     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00153     Created:    27/2/97
00154 
00155     Inputs:     pStrokeTree - A pointer to a Spread node which is the root of a clipart
00156                               subtree which should be used for this stroke definition. It
00157                               must obey these rules:
00158                                 * It must be a Spread
00159                                 * It must not be linked into any other parent tree structure
00160                                 * It should contain at least one path node (or else the stroke
00161                                   will appear "blank"). You should do Make Shapes on the 
00162                                   subtree so that text, blends, quickshapes, etc are all in
00163                                   path form
00164                                 * It should be attribute complete, or close thereto
00165 
00166                 repeating   - TRUE if this stroke definition should repeat along the stroke
00167                               rather than being stretched to fit.
00168 
00169                 repeats     - The number of times the brush should repeat along the stroke, or
00170                               zero for 'work the best out at rendertime'
00171 
00172     Purpose:    Constructor
00173 
00174     SeeAlso:    StrokeComponent::AddNewStroke
00175 
00176 ********************************************************************************************/
00177 
00178 StrokeDefinition::StrokeDefinition(Node *pStrokeTree, BOOL repeating, INT32 repeats) 
00179 {
00180     ERROR3IF(pStrokeTree == NULL, "Illegal NULL param");
00181     ERROR3IF(!pStrokeTree->IsSpread(), "StrokeDefinitions must begin with a Spread (for now, at least)");
00182     ERROR3IF(pStrokeTree->FindParent() != NULL, "Stroke Definition looks like it's linked into a tree!");
00183 
00184     Repeating = repeating;
00185     Repeats   = repeats;
00186     pStroke   = pStrokeTree;
00187 
00188     // Check the subtree to see if it contains any transparency
00189     NeedsTrans = pStroke->ChildrenNeedTransparency();
00190 
00191     IOStore = 0;
00192 
00193     Name = TEXT("Custom brush");
00194 
00195     OverridesFill  = FALSE;
00196     OverridesTrans = FALSE;
00197 }
00198 
00199 
00200 
00201 /********************************************************************************************
00202 
00203 >   StrokeDefinition::~StrokeDefinition()
00204 
00205     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00206     Created:    27/2/97
00207 
00208     Purpose:    Destructor
00209 
00210 ********************************************************************************************/
00211 
00212 StrokeDefinition::~StrokeDefinition()
00213 {
00214     if (pStroke != NULL)
00215     {
00216         pStroke->CascadeDelete();
00217         delete pStroke;
00218     }
00219 }
00220 
00221 
00222 
00223 /********************************************************************************************
00224 
00225 >   void StrokeDefinition::SetStrokeName(StringBase *pName)
00226 
00227     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00228     Created:    5/3/97
00229 
00230     Purpose:    Sets the name text string for this stroke
00231 
00232 ********************************************************************************************/
00233 
00234 void StrokeDefinition::SetStrokeName(StringBase *pName)
00235 {
00236     ERROR3IF(pName == NULL, "Illegal NULL param");
00237 
00238     pName->Left(&Name, 31);
00239 }
00240 
00241 
00242 /********************************************************************************************
00243 
00244 >   void StrokeDefinition::SetStrokeRepeating(BOOL Repeating)
00245 
00246     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00247     Created:    6/3/97
00248 
00249     Purpose:    Sets the repeating flag for this stroke
00250 
00251 ********************************************************************************************/
00252 
00253 void StrokeDefinition::SetStrokeRepeating(BOOL SetMeToTrueIfYouReallyWantMeToBeRepeating)
00254 {
00255     // TRUE if the stroke should repeat along the path, FALSE if it should stretch
00256     Repeating = SetMeToTrueIfYouReallyWantMeToBeRepeating;
00257 }
00258 
00259 
00260 /********************************************************************************************
00261 
00262 >   void StrokeDefinition::SetNumStrokeRepeats(INT32 NumRepeats)
00263 
00264     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00265     Created:    6/3/97
00266 
00267     Purpose:    Sets the number of repeats for this stroke
00268 
00269 ********************************************************************************************/
00270 
00271 void StrokeDefinition::SetNumStrokeRepeats(INT32 NumRepeats)
00272 {
00273     // Number of times a brush should repeat along a stroke, or zero to just work out the
00274     // optimal value on the fly
00275     Repeats = NumRepeats;
00276 }
00277 
00278 /********************************************************************************************
00279 
00280 >   BOOL StrokeDefinition::IsDifferent(StrokeDefinition *pOther)
00281 
00282     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00283     Created:    27/2/97
00284 
00285     Inputs:     pOther - the stroke to compare this stroke to
00286 
00287     Returns:    TRUE if they're different in any way,
00288                 FALSE if they are identical definitions
00289 
00290     Purpose:    Determine if 2 StrokeDefinitions are considered different.
00291                 Used when adding strokes to the global list, so that like strokes
00292                 can be merged.
00293 
00294 ********************************************************************************************/
00295 
00296 BOOL StrokeDefinition::IsDifferent(LineDefinition *pTest)
00297 {
00298     ERROR3IF(pTest == NULL, "Illegal NULL param");
00299 
00300     // check to make sure that pOther is in fact a StrokeDef so that
00301     // we can recast it
00302     StrokeDefinition* pOther = NULL;
00303     if (pTest->IS_KIND_OF(StrokeDefinition))
00304         pOther = (StrokeDefinition*)pTest;
00305     else
00306     {
00307         ERROR3("Parameter is not a stroke definition");
00308         return TRUE;
00309     }
00310 
00311     if (pOther->Repeating != Repeating)
00312         return(TRUE);
00313 
00314     if (pOther->Repeats != Repeats)
00315         return(TRUE);
00316 
00317     if (!Name.IsIdentical(pOther->Name))
00318         return(TRUE);
00319 
00320     if (pOther->pStroke == NULL || pStroke == NULL)
00321     {
00322         ERROR3("StrokeDefinition has not been properly initialised");
00323         return(TRUE);
00324     }
00325 
00326     // --- Check to see if the brush bounds are equal
00327     DocRect OtherBounds = ((Spread *)(pOther->pStroke))->GetBoundingRect();
00328     DocRect Bounds = ((Spread *)pStroke)->GetBoundingRect();
00329     if (Bounds != OtherBounds)
00330         return(TRUE);
00331 
00332     // --- Check the subtrees node-for-node to see if they are the same
00333     Node *pCurNode1 = pStroke->FindFirstDepthFirst();
00334     Node *pCurNode2 = pOther->pStroke->FindFirstDepthFirst();
00335 
00336     while (pCurNode1 != NULL && pCurNode2 != NULL)
00337     {
00338         // See if the nodes are equivalent - if not, we can return immediately
00339         if (pCurNode1->IsDifferent(pCurNode2))
00340             return(TRUE);
00341 
00342         // And go to the next node in both brushes
00343         pCurNode1 = pCurNode1->FindNextDepthFirst(pStroke);
00344         pCurNode2 = pCurNode2->FindNextDepthFirst(pOther->pStroke);
00345     }
00346 
00347     // If we did the entire search and both pointers ended up NULL simultaneously, then
00348     // we have an exact match
00349     if (pCurNode1 == NULL && pCurNode2 == NULL)
00350         return(FALSE);
00351 
00352     return(TRUE);
00353 }
00354 
00355 
00356 
00357 /********************************************************************************************
00358 
00359 >   virtual BOOL StrokeDefinition::NeedsTransparency() const
00360 
00361     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00362     Created:    4/3/97
00363 
00364     Returns:    TRUE if this stroke needs transparency in order to render
00365 
00366     Purpose:    Determine if this stroke needs transparency in order to render.
00367 
00368 ********************************************************************************************/
00369 
00370 BOOL StrokeDefinition::NeedsTransparency() const
00371 {
00372     return(NeedsTrans);
00373 }
00374 
00375 
00376 
00377 
00378 
00379 
00380 
00381 
00382 
00383 
00384 /********************************************************************************************
00385 
00386 >   BOOL StrokeComponentClass::Init()
00387 
00388     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00389     Created:    22/2/97
00390     Returns:    TRUE if all went well;
00391                 FALSE if not.
00392     Purpose:    Register the Stroke document component with the main application.
00393     Errors:     Out of memory.
00394     SeeAlso:    DocComponent
00395 
00396 ********************************************************************************************/
00397 
00398 BOOL StrokeComponentClass::Init()
00399 {
00400     // Instantiate a component class to register with the application.
00401     StrokeComponentClass *pClass = new StrokeComponentClass;
00402     if (pClass == NULL)
00403         return(FALSE);
00404 
00405     // Register it
00406     GetApplication()->RegisterDocComponent(pClass);
00407     return(TRUE);
00408 }
00409 
00410 
00411 
00412 /********************************************************************************************
00413 
00414 >   void StrokeComponentClass::DeInit()
00415 
00416     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00417     Created:    22/2/97
00418 
00419     Returns:    TRUE if all went well;
00420                 FALSE if not.
00421 
00422     Purpose:    De-initialises the vector stroke provider system
00423 
00424 ********************************************************************************************/
00425 
00426 void StrokeComponentClass::DeInit()
00427 {
00428     StrokeComponent::DeleteStrokeList();
00429 }
00430 
00431 
00432 
00433 /********************************************************************************************
00434 
00435 >   BOOL StrokeComponentClass::AddComponent(BaseDocument *pDocument)
00436 
00437     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00438     Created:    22/2/97
00439     Inputs:     pDocument - the document to add the print to.
00440     Returns:    TRUE if the Stroke component was added ok;
00441                 FALSE if not.
00442     Purpose:    Add a Stroke component to the specified document.
00443     Errors:     Out of memory
00444     SeeAlso:    PrintComponentClass
00445 
00446 ********************************************************************************************/
00447 
00448 BOOL StrokeComponentClass::AddComponent(BaseDocument *pDocument)
00449 {
00450     ERROR2IF(pDocument==NULL, FALSE, "NULL document passed to StrokeCompClass:Add");
00451 
00452     // Check to see if this document already has a colour list; if so, leave it alone.
00453     if (pDocument->GetDocComponent(CC_RUNTIME_CLASS(StrokeComponent)) != NULL)
00454         return(TRUE);
00455 
00456     // Ok - create the print mark component.
00457     StrokeComponent *pComponent = new StrokeComponent();
00458     if (pComponent == NULL)
00459         return(FALSE);
00460 
00461     // All ok - add the component to the document.
00462     pDocument->AddDocComponent(pComponent);
00463     return(TRUE);
00464 }
00465 
00466 
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474 
00475 
00476 /********************************************************************************************
00477 
00478 >   StrokeComponent::StrokeComponent()
00479 
00480     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00481     Created:    22/2/97
00482 
00483     Purpose:    Constructor
00484 
00485 ********************************************************************************************/
00486 
00487 StrokeComponent::StrokeComponent()
00488 {
00489 }
00490 
00491 
00492 
00493 /********************************************************************************************
00494 
00495 >   StrokeComponent::~StrokeComponent()
00496 
00497     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00498     Created:    22/2/97
00499 
00500     Purpose:    Destructor
00501 
00502 ********************************************************************************************/
00503 
00504 StrokeComponent::~StrokeComponent()
00505 {
00506 }
00507 
00508 
00509 
00510 /********************************************************************************************
00511 
00512 >   static void StrokeComponent::DeleteStrokeList(void)
00513 
00514     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00515     Created:    22/2/97
00516 
00517     Purpose:    Static deinitialisation function, called on shutdown.
00518                 Clears out the global stroke list. Must be called when all users of the
00519                 stroke system (documents) have already been deleted.
00520 
00521 ********************************************************************************************/
00522 
00523 void StrokeComponent::DeleteStrokeList(void)
00524 {
00525     if (pStrokeList != NULL)
00526     {
00527         for (UINT32 i = 0; i < Used; i++)
00528         {
00529             if (pStrokeList[i] != NULL)
00530                 delete pStrokeList[i];
00531 
00532             pStrokeList[i] = NULL;
00533         }
00534 
00535         CCFree(pStrokeList);
00536         pStrokeList = NULL;
00537     }
00538 }
00539 
00540 
00541 
00542 /********************************************************************************************
00543 
00544 >   static StrokeHandle StrokeComponent::AddNewStroke(StrokeDefinition *pStroke)
00545 
00546     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00547     Created:    29/2/97
00548 
00549     Inputs:     pStroke - (may not be NULL) A stroke definition to add, which now
00550                           belongs to the StrokeComponent, so you mustn't delete it!
00551 
00552     Returns:    A handle which uniquely identifies the new stroke, or
00553                 StrokeHandle_NoStroke if we ran out of memory for storing strokes
00554 
00555     Purpose:    Adds the given stroke to the global stroke list.
00556 
00557     Notes:      IMPORTANT!
00558                 The stroke definition you pass in belongs to the StrokeComponent,
00559                 and will be deleted when finished with. 
00560 
00561                 YOU MUST NOT use the pStroke pointer after this call! If the call
00562                 fails, or if the stroke is merged with an existing one, the object
00563                 you passed in will be IMMEDIATELY DELETED! If you wish to use the
00564                 stroke after Adding it, you must call FindStroke with the returned
00565                 stroke handle!
00566 
00567     Technical:  Strokes are recorded in an array of StrokeDefinition pointers.
00568                 The StrokeHandle is just an index into this array, for fast lookup.
00569                 When deleted, the array-entry is set NULL and never re-used, so that
00570                 any handles floating around can be safely used (much better than
00571                 getting IndexedColour deleted when in use errors, eh? ;-).
00572                 New entries are thus always appended to the list.
00573 
00574 ********************************************************************************************/
00575 
00576 StrokeHandle StrokeComponent::AddNewStroke(StrokeDefinition *pStroke)
00577 {
00578     // ****!!!!TODO - if we're multi-threadig, this probably needs to be a critical section
00579     // because the list is global
00580 
00581     ERROR3IF(pStroke == NULL, "Illegal NULL param");
00582 
00583     // --- First, check if we can merge the given stroke with one already in the list
00584     for (UINT32 i = 0; i < Used; i++)
00585     {
00586         if (pStrokeList[i] != NULL && !pStroke->IsDifferent(pStrokeList[i]))
00587         {
00588             // The stroke is the same as one we already have in our stroke list, so we
00589             // delete the copy that was passed in, and return the existing ones handle
00590             // We copy the import handle value over, though, so that we don't "lose"
00591             // merged strokes during import!
00592             pStrokeList[i]->SetIOStore(pStroke->ReadIOStore());
00593             delete pStroke;
00594             return((StrokeHandle) i);
00595         }
00596     }
00597 
00598     // --- Next, check if we have enough room in our stroke array to add a new entry to the end
00599     if (Used >= CurrentSize)
00600     {
00601         if (!ExpandArray())
00602         {
00603             delete pStroke;
00604             return(StrokeHandle_NoStroke);
00605         }
00606     }
00607 
00608     // --- OK, we have a totally new stroke, so add it to the end of the list
00609     StrokeHandle NewHandle = (StrokeHandle) Used;
00610     pStrokeList[Used] = pStroke;
00611     Used++;
00612 
00613     // --- Now, make sure the stroke gallery display updates to show the new stroke
00614     // ****!!!!TODO - should notify the stroke gallery (broadcast a msg) so that it updates
00615     // I'll use a nasty bodgy direct call to the line gallery instead... eeek!
00616     {
00617         PathProcessorStrokeVector *pProcessor = new PathProcessorStrokeVector;
00618         if (pProcessor != NULL)
00619         {
00620             pProcessor->SetStrokeDefinition(NewHandle);
00621 
00622 PORTNOTE("other","Removed LineGallery usage")
00623 #ifndef EXCLUDE_FROM_XARALX
00624             StrokeTypeAttrValue *pStrokeAttr = new StrokeTypeAttrValue(pProcessor);
00625             if (pStrokeAttr != NULL)
00626                 LineGallery::AddNewStrokeItem(pStrokeAttr);
00627             else
00628                 delete pProcessor;
00629 #endif
00630         }
00631     }
00632 
00633     // --- And return the new handle
00634     return(NewHandle);
00635 }
00636 
00637 
00638 
00639 /********************************************************************************************
00640 
00641 >   static StrokeDefinition *StrokeComponent::FindStroke(StrokeHandle Handle);
00642 
00643     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00644     Created:    29/2/97
00645 
00646     Inputs:     Handle - A handle which uniquely identifies the new stroke
00647 
00648     Returns:    A pointer to a StrokeDefinition for that Stroke.
00649                 If the stroke has been deleted, NULL will be returned, in which case,
00650                 you should gracefully degrade (by rendering an old style line in place of
00651                 the stroke)
00652 
00653     Purpose:    Find a stroke, given its unique identity handle
00654 
00655 ********************************************************************************************/
00656 
00657 StrokeDefinition *StrokeComponent::FindStroke(StrokeHandle Handle)
00658 {
00659     if (Handle == StrokeHandle_NoStroke)
00660         return(NULL);
00661 
00662     if (Handle >= Used)
00663     {
00664         ERROR3("Out of range stroke handle");
00665         return(NULL);
00666     }
00667 
00668     return(pStrokeList[Handle]);
00669 }
00670 
00671 
00672 
00673 /********************************************************************************************
00674 
00675 >   BOOL StrokeComponent::StartImport(BaseCamelotFilter *pFilter)
00676 
00677     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00678     Created:    22/2/97
00679     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to import a file.
00680     Returns:    TRUE if the component was able to prepare for importing;
00681                 FALSE if not (e.g. out of memory)
00682 
00683     Purpose:    Called before we start to import a file
00684 
00685     SeeAlso:    DocComponent
00686 
00687 ********************************************************************************************/
00688 
00689 BOOL StrokeComponent::StartImport(BaseCamelotFilter *pFilter)
00690 {
00691     if (pFilter == NULL)
00692     {
00693         ERROR3("StrokeComponent::StartImport filter is null!");
00694         return(TRUE);
00695     }
00696 
00697     // Set the IOStore in all the strokes to 0xffffffff. During import, this entry is used
00698     // to map imported handles to the real handles they have been assigned.
00699     if (pStrokeList != NULL)
00700     {
00701         for (UINT32 Index = 0; Index < Used; Index++)
00702         {
00703             if (pStrokeList[Index] != NULL)
00704                 pStrokeList[Index]->SetIOStore(0xffffffff);
00705         }
00706     }
00707 
00708     return(TRUE);
00709 }
00710 
00711 
00712 
00713 /********************************************************************************************
00714 
00715 >   BOOL StrokeComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success)
00716 
00717     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00718     Created:    22/2/97
00719 
00720     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to import a file.
00721                 Success - TRUE => The import was successful;
00722                          FALSE => The import failed - abandon any changes.
00723 
00724     Returns:    TRUE if the component was able to end the importing;
00725                 FALSE if not (e.g. out of memory)
00726 
00727     Purpose:    Called on completion of an import
00728 
00729 ********************************************************************************************/
00730 
00731 BOOL StrokeComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success)
00732 {
00733     return TRUE;
00734 }
00735 
00736 
00737 
00738 /********************************************************************************************
00739 
00740 >   BOOL StrokeComponent::StartExport(BaseCamelotFilter *pFilter)
00741 
00742     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00743     Created:    22/2/97
00744 
00745     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to export a file.
00746     Returns:    TRUE if the component was able to prepare for exporting;
00747                 FALSE if not (e.g. out of memory)
00748 
00749     Purpose:    Called before an export is started
00750 
00751 ********************************************************************************************/
00752 
00753 BOOL StrokeComponent::StartExport(BaseCamelotFilter *pFilter)
00754 {
00755 #if !defined(EXCLUDE_FROM_RALPH)
00756     if (pFilter == NULL)
00757     {
00758         ERROR3("StrokeComponent::StartExport filter is null!");
00759         return(TRUE);
00760     }
00761     TRACEUSER( "Diccon", _T("Start Export Stroke Component\n"));
00762     // ****!!!!TODO - if we're multi-threadig, this probably needs to be a critical section
00763     // because the list is global
00764 
00765     // Flag all strokes as not having been saved. When we save one, we set its flag so that
00766     // we don't try to save it a second time.
00767     if (pStrokeList != NULL)
00768     {
00769         for (UINT32 Index = 0; Index < Used; Index++)
00770         {
00771             if (pStrokeList[Index] != NULL)
00772                 pStrokeList[Index]->SetIOStore(FALSE);
00773         }
00774 
00775         // Write out an atomic tag definition in front of the vector stroke definition.
00776         // ****!!!!TODO - This should really only be done just before we export the first
00777         // STROKEDEFINITION tag, but it is not properly supported by the export system as yet.
00778         BOOL ok = TRUE;
00779         CXaraFileRecord Rec(TAG_ATOMICTAGS, TAG_ATOMICTAGS_SIZE);
00780         if (ok) ok = Rec.Init();
00781         if (ok) ok = Rec.WriteUINT32(TAG_STROKEDEFINITION);
00782         if (ok) pFilter->Write(&Rec);       // And write out the record
00783     }
00784 #endif
00785     return(TRUE);
00786 }
00787 
00788 
00789 
00790 /********************************************************************************************
00791 
00792 >   BOOL StrokeComponent::EndExport(BaseCamelotFilter *pFilter, BOOL Success)
00793 
00794     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00795     Created:    22/2/97
00796     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to import a file.
00797                 Success - True if everything went swimmingly, False if just a clean up is required.
00798 
00799     Returns:    TRUE if the component was able to end the exporting;
00800                 FALSE if not (e.g. out of memory)
00801 
00802     Purpose:    Called on completion of file export
00803 
00804 ********************************************************************************************/
00805 
00806 BOOL StrokeComponent::EndExport(BaseCamelotFilter *pFilter, BOOL Success)
00807 {
00808     BOOL ok = TRUE;
00809     TRACEUSER( "Diccon", _T("End Export Stroke Component\n"));
00810 #if !defined(EXCLUDE_FROM_RALPH)
00811     if (pFilter == NULL)
00812     {
00813         ERROR3("StrokeComponent::EndExport filter is null!");
00814         return(ok);
00815     }
00816 
00817     if (!Success)       // If we failed to export, then return immediately
00818         return(ok);
00819 
00820 #endif
00821     return(ok);
00822 }
00823 
00824 
00825 
00826 /********************************************************************************************
00827 
00828 >   static BOOL ExportStroke(BaseCamelotFilter *pFilter, StrokeHandle Handle)
00829 
00830     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00831     Created:    4/3/97
00832 
00833     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to export a file.
00834                 Handle  - The stroke to be exported
00835 
00836     Returns:    TRUE if export was successful
00837                 FALSE if export was aborted - no error is set, as in this case, it usually
00838                 means that the stroke has been deleted, and is being treated as an old-style
00839                 line. In this case, the caller should simply not bother exporting the
00840                 attribute using the stroke definition.
00841 
00842     Purpose:    To export a vector stroke definition. 
00843 
00844     Notes:      Stroke definitions (like colours) are only saved out when a node in the
00845                 tree is found which makes use of the stroke. You should call this function
00846                 before exporting any attribute which uses the stroke definition. It
00847                 automatically checks if the stroke has already been saved, and will not save
00848                 the definition more than once.
00849 
00850                 When saving your reference to the stroke, save out the stroke's Handle
00851                 as it's unique ID word.
00852 
00853 ********************************************************************************************/
00854 
00855 BOOL StrokeComponent::ExportStroke(BaseCamelotFilter *pFilter, StrokeHandle Handle)
00856 {
00857     ERROR3IF(pFilter == NULL, "Illegal NULL params");
00858     TRACEUSER( "Diccon", _T("Exporting Stroke\n"));
00859     // Find the stroke, and baulk if it's all gone wrong
00860     StrokeDefinition *pStroke = FindStroke(Handle);
00861     if (pStroke == NULL)
00862     {
00863         ERROR3("Attempt to save a deleted or non-existent stroke");
00864         return(FALSE);
00865     }
00866 
00867     // Check if the definition has already been saved, in which case we don't need to do anything more
00868     if (pStroke->ReadIOStore())
00869         return(TRUE);
00870 
00871     // We've got a stroke definition now, so let's chuck it out to the file
00872     BOOL ok = TRUE;
00873     CXaraFileRecord Rec(TAG_STROKEDEFINITION, TAG_STROKEDEFINITION_SIZE);
00874     if (ok) ok = Rec.Init();
00875 
00876     if (ok) ok = Rec.WriteUINT32(Handle);
00877 
00878     UINT32 Flags = 0x200;               // All vector strokes include a name (Named flag == 0x200)
00879     if (ok)
00880     {
00881         // Write the flags out.
00882         if (pStroke->IsRepeating())     // Repeating flag = 0x100
00883             Flags |= 0x100;
00884 
00885         if (pStroke->OverrideFill())    // Fill override flag = 0x400
00886             Flags |= 0x400;
00887 
00888         if (pStroke->OverrideTrans())   // Transparency override flag = 0x800
00889             Flags |= 0x800;
00890 
00891         ok = Rec.WriteUINT32(Flags);
00892     }
00893     if (ok)
00894     {
00895         INT32 NumRepeats = 0;
00896         if(pStroke->IsRepeating())
00897         {
00898             // Write the flags out.
00899             NumRepeats = pStroke->NumRepeats();
00900 
00901             if(NumRepeats == 0)
00902                 Flags |= 1;
00903             else
00904                 Flags |= 2;
00905         }
00906 
00907         // Write Data1 - this contains the number of times the brush should repeat down the stroke
00908         ok = Rec.WriteUINT32(NumRepeats);       
00909     }
00910 
00911     if (ok) ok = Rec.WriteUINT32(0);        // Write Data2 - for now, this is always 0
00912 
00913     if (ok && ((Flags & 0x200) != 0))   // Write the (optional) name field
00914         ok = Rec.WriteUnicode((TCHAR *)*(pStroke->GetStrokeName()));
00915 
00916     if (ok) pFilter->Write(&Rec);       // And write out the record
00917 
00918     // Now, follow the definition record with the brush subtree
00919     if (ok)
00920     {
00921         Node *pNode = pStroke->GetStrokeTree(); // Find the root Spread
00922         if (pNode != NULL)
00923             pNode = pNode->FindFirstChild();    // Find the Layer
00924         if (pNode != NULL)
00925             pNode = pNode->FindFirstChild();    // Find the NodeGroup
00926 
00927         if (pNode == NULL)
00928             ok = FALSE;
00929 
00930         ERROR3IF(pNode == NULL || !pNode->IsCompound(), "Vector brush not in the format I expected");
00931 
00932         // Write out the clipart subtree. We have to encapsulate it in DOWN and UP
00933         // records ourselves
00934         CXaraFileRecord DownRec(TAG_DOWN, 0);
00935         if (ok) pFilter->Write(&DownRec);
00936 
00937         ok = pFilter->WriteNodes(pNode);
00938 
00939         CXaraFileRecord UpRec(TAG_UP, 0);
00940         if (ok) pFilter->Write(&UpRec);
00941     }
00942 
00943     // Finally, mark this stroke as having been written out so we don't do it again
00944     if (ok) pStroke->SetIOStore(TRUE);
00945 
00946     return(ok);
00947 }
00948 
00949 
00950 
00951 /********************************************************************************************
00952 
00953 >   static BOOL ImportStroke(CXaraFileRecord* pRecord)
00954 
00955     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00956     Created:    4/3/97
00957 
00958     Inputs:     pRecord - The TAG_STROKEDEFINITION record to import
00959 
00960     Returns:    TRUE if Import was successful
00961 
00962     Purpose:    To import a vector stroke definition
00963 
00964 ********************************************************************************************/
00965 
00966 BOOL StrokeComponent::StartImportStroke(CamelotRecordHandler *pHandler, CXaraFileRecord *pRecord)
00967 {
00968     ImportHandle = 0xffffffff;
00969     ImportFlags  = 0;
00970     ImportData1  = 0;
00971     ImportData2  = 0;
00972     pImportPreviousContext = NULL;
00973     pImportNewBrush = NULL;
00974 
00975     String_256 TempName;    // Load the name into a nice large safe buffer
00976 
00977     // Import the data from the record
00978     if (!pRecord->ReadUINT32(&ImportHandle) || !pRecord->ReadUINT32(&ImportFlags) ||
00979         !pRecord->ReadUINT32(&ImportData1) || !pRecord->ReadUINT32(&ImportData2))
00980     {
00981         return(FALSE);
00982     }
00983 
00984     // If there is a name to be imported, read it as well
00985     if ((ImportFlags & 0x200) != 0 && !pRecord->ReadUnicode(&TempName))
00986         return(FALSE);
00987 
00988     // We remember the imported flags and suchlike, which we will use in EndImportStroke.
00989     TempName.Left((StringBase *)&ImportedName, 31);
00990 
00991     // Create a spread and set up the import system to import the brush into it
00992     // If this fails, then it'll just find somewhere "sensible" to import into
00993     pImportNewBrush = new Spread;
00994     if (pImportNewBrush == NULL)
00995         return(FALSE);
00996 
00997     Layer *pBrushLayer = new Layer(pImportNewBrush, FIRSTCHILD, String_256(TEXT("Jason did this")));
00998     if (pBrushLayer == NULL)
00999     {
01000         delete pImportNewBrush;
01001         pImportNewBrush = NULL;
01002         return(FALSE);
01003     }
01004 
01005     // Now, remember where we were importing into, and point the importer at our brush tree
01006     pImportPreviousContext = pHandler->GetInsertContext();
01007     pHandler->SetInsertContextNode(pBrushLayer);
01008     return(TRUE);
01009 }
01010 
01011 
01012 
01013 /********************************************************************************************
01014 
01015 >   static BOOL StrokeComponent::EndImportStroke(CamelotRecordHandler *pHandler);
01016 
01017     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01018     Created:    4/3/97
01019 
01020     Inputs:     pRecord - The TAG_STROKEDEFINITION record to import
01021 
01022     Returns:    TRUE if Import was successful
01023 
01024     Purpose:    To import a vector stroke definition
01025 
01026 ********************************************************************************************/
01027 
01028 BOOL StrokeComponent::EndImportStroke(CamelotRecordHandler *pHandler)
01029 {
01030     ERROR3IF(pImportPreviousContext == NULL, "EndImportStroke - something hasn't gone too well");
01031 
01032     // Restore the previous import context node
01033     pHandler->RestoreInsertContext(pImportPreviousContext);
01034     pImportPreviousContext = NULL;
01035 
01036     // --- Now, convert all IndexedColours (which are document-dependent) into standalone DocColours
01037     // This wouldn't be necessary, except that the DocColours we saved have magically been turned
01038     // back into local Indexedcolours by the export/import process.
01039     // BLOCK
01040     {
01041         Node *pCurNode = pImportNewBrush->FindFirstDepthFirst();
01042         Node *pNextNode;
01043 
01044         while (pCurNode !=NULL)
01045         {
01046             // We may be about to chop this node out of the tree, so get the next node now
01047             pNextNode = pCurNode->FindNextDepthFirst(pImportNewBrush);
01048 
01049             // Use to scan the colour fields of the attribute.
01050             if (pCurNode->IsAnAttribute())
01051             {
01052 
01053 PORTNOTE("colourmanager","Removed ColourManager usage")
01054 #ifndef EXCLUDE_FROM_XARALX
01055                 UINT32 Context = 0;
01056                 NodeAttribute *pNodeAttr = (NodeAttribute *) pCurNode;
01057                 // Get the next colour field from the attribute
01058                 DocColour *pColour = pNodeAttr->EnumerateColourFields(Context++);
01059 
01060                 while (pColour != NULL)
01061                 {
01062                     // For each colour field, make sure the colour is a local DocColour so that
01063                     // the sub-tree is entirely stand-alone
01064                     if (pColour->FindParentIndexedColour() != NULL)
01065                     {
01066                         ColourGeneric ColDef;
01067                         ColourContext *cc = ColourManager::GetColourContext(pColour->GetColourModel());
01068                         ERROR3IF(cc == NULL, "Can't find colour context?!");
01069 
01070                         // Get the IndexedColour definition as a standalone colour definition
01071                         cc->ConvertColour(pColour->FindParentIndexedColour(), &ColDef);
01072 
01073                         // Make the DocColour into a simple standalone "lookalike" of the parent colour
01074                         *pColour = DocColour(pColour->GetColourModel(), &ColDef);
01075                     }
01076 
01077                     pColour = pNodeAttr->EnumerateColourFields(Context++);
01078                 }
01079 #endif
01080             }
01081             pCurNode = pNextNode;
01082         }
01083     }
01084 
01085     // Create a new stroke definition from the imported brush
01086     // Read the imported data from ImportFlags, ImportData1, ImportData2
01087     // (Currently, we only handle the Repeating, Optimal Repeating and Number of Repeating flags)
01088     BOOL Repeating = ((ImportFlags & 0x100) != 0);
01089 
01090     INT32 Repeats = 0;
01091 
01092     // If repeating a certain number of times, get the number of times, else assume 0 - optimal
01093     if((ImportFlags & 0xff) == 2)
01094         Repeats = (INT32)ImportData1;
01095 
01096     StrokeDefinition *pNewStroke = new StrokeDefinition(pImportNewBrush, Repeating, Repeats);
01097     if (pNewStroke == NULL)
01098         return(FALSE);
01099 
01100     pNewStroke->SetOverrideFill((ImportFlags & 0x400) != 0);
01101     pNewStroke->SetOverrideTrans((ImportFlags & 0x800) != 0);
01102 
01103     // Remember the handle used for the stroke in the file with the stroke so that
01104     // we can map any incoming handles into the real handles we are using internally.
01105     pNewStroke->SetIOStore(ImportHandle & 0x00ffffff);
01106 
01107     // And set the stroke's name, if any was supplied
01108     if (!ImportedName.IsEmpty())
01109         pNewStroke->SetStrokeName(&ImportedName);
01110 
01111     // And add/merge this stroke into our global list
01112     AddNewStroke(pNewStroke);
01113     return(TRUE);
01114 }
01115 
01116 
01117 
01118 /********************************************************************************************
01119 
01120 >   static StrokeHandle StrokeComponent::FindImportedStroke(UINT32 ImportedHandle)
01121 
01122     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01123     Created:    4/3/97
01124 
01125     Inputs:     Importedhandle - The handle which is used in the file being imported
01126                                  to reference the stroke.
01127 
01128     Returns:    The StrokeHandle of the loaded stroke, or StrokeHandle_NoStroke
01129                 if the stroke could not be found.
01130 
01131     Purpose:    To match up a handle from the currently importing file to the
01132                 real internal StrokeHandle of the imported StrokeDefinition
01133 
01134 ********************************************************************************************/
01135 
01136 StrokeHandle StrokeComponent::FindImportedStroke(UINT32 ImportedHandle)
01137 {
01138     ImportedHandle &= 0x00ffffff;   // Only the bottom 24 bits are relevant
01139     for (UINT32 Index = 0; Index < Used; Index++)
01140     {
01141         if (pStrokeList[Index] != NULL && pStrokeList[Index]->ReadIOStore() == ImportedHandle)
01142             return((StrokeHandle)Index);
01143     }
01144 
01145     return(StrokeHandle_NoStroke);
01146 }
01147 
01148 
01149 
01150 /******************************************************************************************
01151 
01152 >   static BOOL StrokeComponent::ExpandArray(void)
01153 
01154     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01155     Created:    28/2/97
01156 
01157     Outputs:    On succesful exit, the member array of StrokeDefinition pointers will be bigger
01158     Returns:    FALSE if it failed to allocate memory
01159 
01160     Purpose:    (Internal method)
01161                 Expands the storage structure of the stroke list to allow more entries to be
01162                 used. Called automatically by AddNewStroke as necessary.
01163 
01164     Notes:      Internal storage is an array of pointers to StrokeDefinitions
01165                 NULL pointers beyond (& including) "Used" indicate free slots.
01166                 NULL pointers before "Used" indicate deleted strokes - these slots
01167                 should NOT be re-used, as there may still be references to them in
01168                 the system.
01169 
01170 ******************************************************************************************/
01171 
01172 BOOL StrokeComponent::ExpandArray(void)
01173 {
01174     // ****!!!!TODO - if we're multi-threading, this probably needs to be a critical section
01175     // because the list is global
01176 
01177     const INT32 AllocSize = CurrentSize + 64;
01178 
01179     if (pStrokeList == NULL)
01180     {
01181         pStrokeList = (StrokeDefinition **) CCMalloc(AllocSize * sizeof(StrokeDefinition *));
01182         if (pStrokeList == NULL)
01183             return(FALSE);
01184     }
01185     else
01186     {
01187         // We have an array - we must make it larger
01188         StrokeDefinition **pNewBuf = (StrokeDefinition **)
01189                                     CCRealloc(pStrokeList, AllocSize * sizeof(StrokeDefinition *));
01190         if (pNewBuf == NULL)
01191             return(FALSE);
01192 
01193         pStrokeList = pNewBuf;
01194     }
01195 
01196     // Success. Initalise all the new pointers to NULL
01197     for (UINT32 i = Used; i < CurrentSize; i++)
01198         pStrokeList[i] = NULL;
01199 
01200     // Update the current size value, and return success
01201     CurrentSize = AllocSize;
01202     return(TRUE);
01203 }
01204 

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