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