00001 // $Id: colormgr.cpp 1777 2007-07-04 10:37:58Z luke $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 00099 // colormgr.cpp - Implementation of the ColourManager class 00100 00101 00102 /* 00103 */ 00104 00105 00106 #include "camtypes.h" 00107 00108 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 #include "ccolbar.h" 00111 #include "colcomp.h" 00112 #include "colcontx.h" 00113 #include "coldlog.h" 00114 #include "colormgr.h" 00115 //#include "docmsgs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00116 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00117 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00118 //#include "jason.h" 00119 #include "lineattr.h" 00120 #include "newcol.h" // For NewColourDlg 00121 #include "nodeblnd.h" // For NodeBlend, for Blend bodge 00122 #include "objchge.h" 00123 #include "opimgset.h" 00124 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00125 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00126 //#include "tool.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00127 #include "fillramp.h" 00128 //#include "bitmapcache.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00129 00130 #include "colmsg.h" 00131 00132 #include "ophist.h" 00133 00134 // "Implement" run-time typing for the classes we're defining here 00135 CC_IMPLEMENT_DYNAMIC(ColourChangingMsg, Msg) 00136 00137 CC_IMPLEMENT_DYNAMIC(ColourManager, MessageHandler) 00138 00139 #if !defined(EXCLUDE_FROM_RALPH) 00140 CC_IMPLEMENT_DYNCREATE(OpHideColours, UndoableOperation) 00141 CC_IMPLEMENT_DYNCREATE(ActionHideColours, Action) 00142 00143 CC_IMPLEMENT_DYNCREATE(OpColourChange, UndoableOperation) 00144 CC_IMPLEMENT_DYNCREATE(ActionColourChange, Action) 00145 00146 CC_IMPLEMENT_DYNCREATE(OpRedrawColours, Operation) 00147 #endif 00148 00149 // Declare smart memory handling in Debug builds 00150 #define new CAM_DEBUG_NEW 00151 00152 00153 // --- Initialise static member variables 00154 ColourList *ColourManager::CurrentColourList = NULL; 00155 Document *ColourManager::ScopeDocument = NULL; 00156 00157 /******************************************************************************************** 00158 00159 > ColourManager::ColourManager() 00160 00161 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00162 Created: 11/5/94 00163 Purpose: Constructs a ColourManager object 00164 SeeAlso: ColourManager; MessageHandler 00165 00166 ********************************************************************************************/ 00167 00168 ColourManager::ColourManager() 00169 : MessageHandler(CC_RUNTIME_CLASS(MessageHandler), TRUE) 00170 { 00171 } 00172 00173 00174 00175 /******************************************************************************************** 00176 00177 > static BOOL ColourManager::Init(void) 00178 00179 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00180 Created: 21/5/94 00181 Returns: FALSE if initialisation failed 00182 Purpose: Initialises the entire colour system. This includes the colour manager, 00183 colour contexts, and colour dialogues, etc. 00184 Notes: Should only be called once ever. Called by Application::Init() 00185 SeeAlso: ColourManager; MessageHandler 00186 00187 ********************************************************************************************/ 00188 00189 BOOL ColourManager::Init(void) 00190 { 00191 #if !defined(EXCLUDE_FROM_RALPH) 00192 // Init (register) all our operations 00193 #if !defined(EXCLUDE_FROM_XARALX) 00194 if (!::InitImagesettingOps()) 00195 return(FALSE); 00196 #endif 00197 00198 if (!OpHideColours::Init()) 00199 return(FALSE); 00200 00201 if (!OpColourChange::Init()) 00202 return(FALSE); 00203 00204 if (!OpRedrawColours::Init()) 00205 return(FALSE); 00206 00207 if (!OpMakeColourLocalToFrame::Init()) 00208 return(FALSE); 00209 #endif 00210 00211 // Init the global list of active colour contexts 00212 if (!ColourContextList::InitColourContexts()) 00213 return(FALSE); 00214 00215 return(TRUE); 00216 } 00217 00218 00219 00220 /******************************************************************************************** 00221 00222 > static void ColourManager::Deinit(void) 00223 00224 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00225 Created: 1/6/94 00226 Purpose: De-Initlialises the entire colour system. This includes the colour manager, 00227 colour contexts, and colour dialogues, etc. 00228 Notes: Should only be called once ever. Called by Application::Deinit() 00229 SeeAlso: ColourManager; MessageHandler 00230 00231 ********************************************************************************************/ 00232 00233 void ColourManager::Deinit(void) 00234 { 00235 // shut down the colour contexts 00236 ColourContextList::DeinitColourContexts(); 00237 } 00238 00239 00240 00241 /******************************************************************************************** 00242 00243 > void ColourManager::ForceRedrawOfChangedColours(Document *ScopeDoc, 00244 IndexedColour **Colours) 00245 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00246 Created: 7/9/94 00247 Inputs: ScopeDoc - The document in which to cause redraw 00248 Colours - A NULL terminated list of pointers to IndexedColours 00249 00250 Purpose: Scans the document tree of the given scope document, and causes 00251 a redraw of all objects which are affected by any attributes which 00252 contain references to any of the colours in the given NULL-terminated 00253 list of colours. If none of the colours are in use in the document 00254 tree, nothing should result. 00255 (i.e. it force redraws any areas of the document containing any of 00256 the given colours) 00257 SeeAlso: RecursivelyForceRedraw 00258 00259 ********************************************************************************************/ 00260 00261 void ColourManager::ForceRedrawOfChangedColours(Document *ScopeDoc, IndexedColour **Colours) 00262 { 00263 #if !defined(EXCLUDE_FROM_RALPH) 00264 // Sanity check 00265 if (ScopeDoc == NULL) 00266 { 00267 ERROR3("Illegal NULL param"); 00268 return; 00269 } 00270 00271 OpDescriptor* OpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_REDRAWCOLOURS); 00272 00273 if (OpDesc != NULL) 00274 { 00275 OpRedrawColoursInfo Info; 00276 Info.ScopeDoc = ScopeDoc; 00277 Info.Colours = Colours; 00278 00279 OpDesc->Invoke((OpParam *) &Info); 00280 } 00281 #endif 00282 } 00283 00284 00285 00286 /******************************************************************************************** 00287 00288 > virtual MsgResult ColourManager::Message(Msg* Message) 00289 00290 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00291 Created: 11/5/94 00292 Inputs: Message: The message 00293 Outputs: - 00294 Returns: - 00295 Purpose: Process messages sent to the ColourManager 00296 Some messages (DocChanging) will cause new broadcasts indicating 00297 that the colour system has changed (new colour list has been paged in, etc) 00298 Errors: - 00299 SeeAlso: ColourManager; MessageHandler; ColourChangingMsg 00300 00301 ********************************************************************************************/ 00302 00303 MsgResult ColourManager::Message(Msg* Message) 00304 { 00305 if (MESSAGE_IS_A(Message, DocChangingMsg)) 00306 { 00307 DocChangingMsg *TheMsg = (DocChangingMsg *) Message; 00308 00309 switch ( TheMsg->State ) 00310 { 00311 case DocChangingMsg::SELCHANGED: 00312 if (TheMsg->pNewDoc == NULL) // No document selected any more 00313 { 00314 // Send PaletteChangingMsg - DESELECTED 00315 CurrentColourList = NULL; // No document present 00316 ScopeDocument = NULL; 00317 00318 BROADCAST_TO_ALL(ColourChangingMsg(ScopeDocument, CurrentColourList, NULL, 00319 ColourChangingMsg::LISTDESELECTED)); 00320 } 00321 else if (TheMsg->pOldDoc != TheMsg->pNewDoc) 00322 { 00323 // Send PaletteChangingMsg - PAGED 00324 CurrentColourList = NULL; // Cause re-caching of this info 00325 ScopeDocument = NULL; 00326 00327 GetColourList(TRUE); // Find the new colour list 00328 00329 BROADCAST_TO_ALL(ColourChangingMsg(ScopeDocument, CurrentColourList, NULL, 00330 ColourChangingMsg::LISTPAGED)); 00331 } 00332 break; 00333 00334 00335 case DocChangingMsg::ABOUTTODIE: 00336 // Pass this around as a ColourList killed message 00337 if (TheMsg->pChangingDoc != NULL) 00338 BROADCAST_TO_ALL(ColourChangingMsg(TheMsg->pChangingDoc, 00339 TheMsg->pChangingDoc->GetIndexedColours(), NULL, 00340 ColourChangingMsg::LISTDELETED)); 00341 00342 if (TheMsg->pChangingDoc == ScopeDocument) 00343 { 00344 // We can't keep a cached value around, as soon after this point the 00345 // colour list will cease to exist 00346 CurrentColourList = NULL; 00347 ScopeDocument = NULL; 00348 } 00349 break; 00350 default: 00351 break; 00352 } 00353 } 00354 else if (MESSAGE_IS_A(Message, ColourChangingMsg)) 00355 { 00356 ColourChangingMsg *TheMsg = (ColourChangingMsg *) Message; 00357 00358 switch ( TheMsg->State ) 00359 { 00360 case ColourChangingMsg::LISTUPDATED: 00361 // The list has changed- may involve a colour having been deleted. 00362 // We check if the attribute manager is using any colours which are 00363 // now deleted, and if so, set it to use safer ones! 00364 if (TheMsg->ScopeDoc == NULL || TheMsg->NewColourList == NULL) 00365 { 00366 ERROR3("ColChangingMsg::LISTUPDATED broadcast with NULL colour list"); 00367 } 00368 else 00369 TheMsg->ScopeDoc->GetAttributeMgr().UpdateForDeletedColours( 00370 TheMsg->NewColourList); 00371 break; 00372 00373 00374 case ColourChangingMsg::COLOURUPDATED: 00375 { 00376 // An IndexedColour has been edited. 00377 // We need to force an update on all colours Linked to this one, and 00378 // then redraw all DocViews on this document. 00379 00380 if (TheMsg->ScopeDoc != NULL && 00381 TheMsg->NewColourList != NULL && 00382 TheMsg->ChangedColour != NULL) 00383 { 00384 IndexedColour **AffectedColours = TheMsg->NewColourList-> 00385 CompileInheritanceArray(TheMsg->ChangedColour); 00386 00387 if (AffectedColours == NULL) 00388 { 00389 // Memory error means we can't get the array 00390 // Tell *all* linked colours in the list they may have changed 00391 List *TheList = TheMsg->NewColourList; 00392 00393 IndexedColour *Ptr = (IndexedColour *) (TheList->GetHead()); 00394 while (Ptr != NULL) 00395 { 00396 if (Ptr->FindLinkedParent() != NULL) // If is linked 00397 Ptr->LinkedAncestorHasChanged(); // Warn it of the change 00398 Ptr = (IndexedColour *) TheList->GetNext(Ptr); 00399 } 00400 00401 // And all unnamed colours too 00402 TheList = TheMsg->NewColourList->GetUnnamedColours(); 00403 00404 Ptr = (IndexedColour *) (TheList->GetHead()); 00405 while (Ptr != NULL) 00406 { 00407 if (Ptr->FindLinkedParent() != NULL) // If is linked 00408 Ptr->LinkedAncestorHasChanged(); // Warn it of the change 00409 Ptr = (IndexedColour *) TheList->GetNext(Ptr); 00410 } 00411 00412 // And force-redraw the entire document - all views 00413 CBitmapCache *pBC = Camelot.GetBitmapCache(); 00414 if( NULL != pBC ) 00415 pBC->DeInitialise(); // Brute force cache management! 00416 TheMsg->ScopeDoc->ForceRedraw(); 00417 } 00418 else 00419 { 00420 // Inform all the linked colours (except the first, which is the 00421 // actual colour which has changed) that they may have changed 00422 INT32 Index = 1; 00423 while (AffectedColours[Index] != NULL) 00424 { 00425 AffectedColours[Index]->LinkedAncestorHasChanged(); 00426 Index++; 00427 } 00428 00429 // And redraw all affected areas of the document 00430 ForceRedrawOfChangedColours(TheMsg->ScopeDoc, AffectedColours); 00431 } 00432 } 00433 } 00434 break; 00435 default: 00436 break; 00437 } 00438 } 00439 00440 return OK; 00441 } 00442 00443 00444 00445 /******************************************************************************************** 00446 00447 > ColourList *ColourManager::GetColourList(BOOL InvalidateCache = FALSE) 00448 00449 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00450 Created: 11/5/94 00451 Inputs: InvalidateCache - TRUE if you want to force it to re-cache the 00452 list pointer (generally only used internally; the default setting 00453 of FALSE is all external clients should ever need to use) 00454 Outputs: - 00455 Returns: NULL, or a pointer to the current colour list 00456 00457 Purpose: To obtain the ColourList of IndexedColours in the SelectedDocument (the 00458 colours which the user can use within the document; this is the set of 00459 colours displayed by the colour bar and edited by the ColourMgrDlg) 00460 Note that an ordered list is used so that multiple display orders can 00461 be used (e.g. for the ColourMgrDlg and ColourBar, etc) 00462 00463 Notes: This returns the list of colours from the SELECTED document, i.e. 00464 the colours displayed in the colour bar etc. Use GetCurrentColourList 00465 if you wish to get the colours for the CURRENT doc. 00466 00467 The list is cached so this call is generally pretty efficient 00468 00469 ********************************************************************************************/ 00470 00471 ColourList *ColourManager::GetColourList(BOOL InvalidateCache) 00472 { 00473 Document *ParentDoc = Document::GetSelected(); 00474 00475 if (ParentDoc != NULL) 00476 { 00477 if (InvalidateCache || ParentDoc != ScopeDocument) 00478 { 00479 CurrentColourList = ParentDoc->GetIndexedColours(); 00480 ScopeDocument = ParentDoc; 00481 } 00482 // else 00483 // Cache is up to date, so quit messing about 00484 } 00485 else 00486 { 00487 ScopeDocument = NULL; // ParentDocument is NULL - no colour list 00488 CurrentColourList = NULL; 00489 } 00490 00491 return(CurrentColourList); 00492 } 00493 00494 00495 00496 00497 /******************************************************************************************** 00498 00499 > ColourList *ColourManager::GetCurrentColourList(void) 00500 00501 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00502 Created: 6/6/94 00503 Inputs: - 00504 Outputs: - 00505 Returns: NULL, or a pointer to the current colour list 00506 00507 Purpose: To obtain the ColourList of IndexedColours in the CurrentDocument 00508 00509 Notes: This returns the colours for the CURRENT document, NOT the Selected 00510 one - that is, these may not be the colours displayed in the colour 00511 bar/input-focus document. 00512 00513 SeeAlso: ColourManager::GetColourList 00514 00515 ********************************************************************************************/ 00516 00517 ColourList *ColourManager::GetCurrentColourList(void) 00518 { 00519 Document *ParentDoc = Document::GetCurrent(); 00520 00521 if (ParentDoc != NULL) 00522 return(ParentDoc->GetIndexedColours()); 00523 00524 return(NULL); 00525 } 00526 00527 00528 00529 /******************************************************************************************** 00530 00531 > static ColourContext *ColourManager::GetColourContext(ColourModel Model, 00532 Document *ScopeDocument = NULL) 00533 00534 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00535 Created: 20/11/95 00536 00537 Inputs: Model - The colour model of the desired ColourContext 00538 ScopeDocument - NULL (to retrieve a global context) or a pointer to 00539 the document for which you want the colour context. 00540 00541 Returns: NULL if it failed to find an appropriate colour context, else 00542 a pointer to the context 00543 00544 Purpose: To easily find an appropriate colour context to use when converting 00545 colours. There are global contexts, but in order to supply special 00546 document-specific colour corrections etc, each document actually 00547 has its own private set of contexts. Thus, you should call this function 00548 to determine the most appropriate context to use. 00549 00550 ********************************************************************************************/ 00551 00552 ColourContext *ColourManager::GetColourContext(ColourModel Model, Document *ScopeDocument) 00553 { 00554 if (ScopeDocument == NULL) 00555 return(ColourContext::GetGlobalDefault(Model)); 00556 00557 return(ScopeDocument->GetDefaultColourContexts()->Context[Model]); 00558 } 00559 00560 00561 00562 /******************************************************************************************** 00563 00564 > static ColourContext *ColourManager::GetColourContext(ColourModel Model, 00565 View *ScopeView) 00566 00567 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00568 Created: 14/5/96 00569 00570 Inputs: Model - The colour model of the desired ColourContext 00571 ScopeView - A pointer to the view for which you want the colour context. 00572 This should not be NULL, but if it is, a global default 00573 context will be returned 00574 00575 Returns: NULL if it failed to find an appropriate colour context, else 00576 a pointer to the context 00577 00578 Purpose: To easily find an appropriate colour context to use when converting 00579 colours. There are global contexts, but in order to supply special 00580 view-specific colour corrections etc, each document view actually 00581 has its own private set of contexts. Thus, you should call this function 00582 to determine the most appropriate context to use. 00583 00584 ********************************************************************************************/ 00585 00586 ColourContext *ColourManager::GetColourContext(ColourModel Model, View *ScopeView) 00587 { 00588 if (ScopeView != NULL) 00589 return(ScopeView->GetColourContext(Model)); 00590 00591 return(ColourContext::GetGlobalDefault(Model)); 00592 } 00593 00594 00595 00596 /******************************************************************************************** 00597 00598 > static void ColourManager::SelViewContextHasChanged(void) 00599 00600 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00601 Created: 22/5/96 00602 00603 Purpose: To redraw all windows which depend upon the Selected View's colour context. 00604 i.e. The selected view, and also the colour editor, gallery, & line. 00605 (and maybe other windows in the future, e.g. object properties, grad 00606 fill editors, etc) 00607 00608 This redraws the selected view, then broadcasts a ColourChangingMsg message 00609 with a state of SELVIEWCONTEXTCHANGE to inform other interested parties. 00610 00611 Notes: This should only be called when the selected view's RGB (screen) colour 00612 context is changed, which really shouldn't happen terribly often. 00613 00614 ********************************************************************************************/ 00615 00616 void ColourManager::SelViewContextHasChanged(void) 00617 { 00618 View *SelView = DocView::GetSelected(); 00619 00620 if (SelView != NULL && SelView->IsKindOf(CC_RUNTIME_CLASS(DocView))) 00621 { 00622 CBitmapCache* pBC = Camelot.GetBitmapCache(); 00623 if( NULL != pBC ) 00624 pBC->DeInitialise(); // Brute force cache management 00625 00626 ((DocView *)SelView)->ForceRedraw(); 00627 } 00628 00629 BROADCAST_TO_ALL(ColourChangingMsg(NULL, NULL, NULL, 00630 ColourChangingMsg::SELVIEWCONTEXTCHANGE)); 00631 } 00632 00633 00634 00635 /******************************************************************************************** 00636 00637 > inline Document *SetCurrentDoc(void) 00638 00639 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00640 Created: 28/7/94 (Copied from ccolbar.cpp, 25/11/94) 00641 Inputs: - 00642 Outputs: - 00643 Returns: The old Current Document 00644 00645 Purpose: The ColourBar works exclusively on the SELECTED Doc. 00646 Thus, on entry to any of its routines which call routines 00647 outside this file (ccolbar.cpp), it must ensure that CurrentDoc 00648 is equal to SelectedDoc. 00649 This local macro inline does this, and returns the old setting of 00650 CurrentDoc so that the caller can restore the previous CurrentDoc 00651 on exit. 00652 00653 Scope: private (to kernel\colormgr.cpp) 00654 SeeAlso: RestoreCurrentDoc 00655 00656 ********************************************************************************************/ 00657 00658 inline Document *SetCurrentDoc(void) 00659 { 00660 Document *OldCurrentDoc = Document::GetCurrent(); 00661 Document *NewCurrentDoc = Document::GetSelected(); 00662 00663 if (NewCurrentDoc != NULL && NewCurrentDoc != OldCurrentDoc) 00664 NewCurrentDoc->SetCurrent(); 00665 00666 return(OldCurrentDoc); 00667 } 00668 00669 00670 00671 /******************************************************************************************** 00672 00673 > inline void RestoreCurrentDoc(Document *OldCurrentDoc) 00674 00675 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00676 Created: 28/7/94 (Copied from ccolbar.cpp, 25/11/94) 00677 Inputs: The old current document to restore 00678 Outputs: - 00679 Returns: - 00680 00681 Purpose: The ColourBar works exclusively on the SELECTED Doc. 00682 After calling SetCurrentDoc on entry to a routine, you should call 00683 RestoreCurrentDoc on exit to restore the old current document./ 00684 00685 Scope: private (to kernel\colormgr.cpp) 00686 SeeAlso: SetCurrentDoc 00687 00688 ********************************************************************************************/ 00689 00690 inline void RestoreCurrentDoc(Document *OldCurrentDoc) 00691 { 00692 if (OldCurrentDoc != NULL) 00693 OldCurrentDoc->SetCurrent(); 00694 } 00695 00696 00697 00698 /******************************************************************************************** 00699 00700 > static BOOL ColourManager::GetCurrentLineAndFillAttrs(AttrStrokeColour **LineAttr, 00701 AttrFillGeometry **FillAttr) 00702 00703 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00704 Created: 6/7/94 (Moved from ccolbar.cpp, 25/11/94) 00705 Inputs: - 00706 Outputs: LineAttr - will be filled in with NULL, or pointer to the attribute 00707 FillAttr - will be filled in with NULL, or pointer to the attribute 00708 Returns: TRUE if these are default attributes; FALSE if the attributes are 00709 those common to the current selection. 00710 00711 Purpose: Determines the current line and fill colour attributes. 00712 These are the default ones, or if there is a selection, the attrs 00713 which are common to all selected objects. If there are many different 00714 attributes of the same type associated with the selection, NULL is 00715 returned. 00716 Notes: The ColourBar works exclusively on the SELECTED Doc. Change with care 00717 This function ensures that Current == Selected during its operation 00718 00719 ********************************************************************************************/ 00720 00721 BOOL ColourManager::GetCurrentLineAndFillAttrs(AttrStrokeColour **LineAttr, 00722 AttrFillGeometry **FillAttr) 00723 { 00724 ENSURE(LineAttr != NULL && FillAttr != NULL, 00725 "ColourManager::GetCurrentLineAndFillAttrs - NULL pointers passed in!"); 00726 00727 *LineAttr = NULL; // Ensure safe exit if we fail 00728 *FillAttr = NULL; 00729 00730 // I don't think it is the colour bar's responsibility to check this, but 00731 // this is the only way that *I* can fix the problem of an ENSURE failure 00732 // on exit (we ask for info when no tools are current... I believe this is 00733 // because some slurphead has thrown away the tools BEFORE the document, 00734 // because the Document::GetSelected still does not return NULL in this case!) 00735 if (Tool::GetCurrent() == NULL) 00736 return(TRUE); 00737 00738 Document *SelectedDoc = Document::GetSelected(); 00739 if (SelectedDoc == NULL) 00740 return(TRUE); 00741 00742 // Save the current CurrentDoc, and set (CurrentDoc = SelectedDoc) 00743 Document *OldCurrentDoc = SetCurrentDoc(); 00744 00745 SelRange *Selection = Camelot.FindSelection(); 00746 ENSURE(Selection != NULL, "No Selection SelRange!?!"); 00747 00748 SelRange::CommonAttribResult result = 00749 Selection->FindCommonAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), 00750 (NodeAttribute **)LineAttr); 00751 if (result == SelRange::ATTR_MANY) 00752 *LineAttr = NULL; 00753 00754 result = Selection->FindCommonAttribute(CC_RUNTIME_CLASS(AttrFillGeometry), 00755 (NodeAttribute **)FillAttr); 00756 if (result == SelRange::ATTR_MANY) 00757 *FillAttr = NULL; 00758 00759 RestoreCurrentDoc(OldCurrentDoc); 00760 00761 return(result == SelRange::ATTR_NONE); 00762 } 00763 00764 00765 00766 /******************************************************************************************** 00767 00768 > static BOOL ColourManager::GetCurrentLineAndFillColours(DocColour **LineCol, 00769 DocColour **FillCol, 00770 DocColour **EndGradFill = NULL, 00771 DocColour **EndGradFill2 = NULL, 00772 DocColour **EndGradFill3 = NULL) 00773 00774 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> (changed by Gerry 21/8/96) 00775 Created: 9/9/94 (Moved from ccolbar.cpp, 25/11/94) 00776 Inputs: - 00777 00778 Outputs: LineCol - NULL, or will be filled in with a pointer to the current line colour 00779 FillCol - NULL, or will be filled in with a pointer to the current fill colour 00780 EndGradFill - NULL, or will be filled in with NULL or the grad-fill end colour 00781 (see below) 00782 EndGradFill2 - NULL, or will be filled in with NULL or the second end colour 00783 EndGradFill3 - NULL, or will be filled in with NULL or the third end colour 00784 00785 Returns: TRUE if these are default attributes; FALSE if the attributes are 00786 those common to the current selection. 00787 00788 Purpose: Finds the current line and fill attributes, and dereferences them to find 00789 the current line and fill DocColours. These may be returned NULL if there 00790 are no current attributes (no document/many colours selected) 00791 00792 Notes: The ColourBar works exclusively on the SELECTED Doc. Change with care 00793 00794 LineCol and/or FillCol may be passed in NULL if you are not interested in 00795 having these results returned to you. 00796 00797 If EndGradFill is NULL and a grad fill is selected then FillColour will 00798 be filled in with the selected fill blob's colour (or NULL if there are 00799 zero or more than one selected blob). EndGradFill2 and EndGradFill3 00800 will be filled in with NULL (if they are non NULL) 00801 00802 If EndGradFill is non-NULL and a grad-fill is selected, instead of 00803 returning only the selected endpoint colour, it returns the start 00804 and end colours in FillCol (start) and EndGradFill (end). If the fill 00805 has more than two colours (ie GetEndColour2() != NULL) then both 00806 FillCol and EndGradFill will bet filled in with NULL (to indicate many). 00807 00808 MULTIFILL: This system needs to be changed to support multistage fills. 00809 00810 SeeAlso: CColourBar::GetCurrentLineAndFillAttrs 00811 00812 ********************************************************************************************/ 00813 00814 BOOL ColourManager::GetCurrentLineAndFillColours(DocColour **LineCol, DocColour **FillCol, 00815 DocColour **EndGradFill) 00816 { 00817 if (LineCol != NULL) // Ensure return NULL if we fail 00818 *LineCol = NULL; 00819 00820 if (FillCol != NULL) 00821 *FillCol = NULL; 00822 00823 if (EndGradFill != NULL) 00824 *EndGradFill = NULL; 00825 00826 AttrStrokeColour *LineAttr = NULL; 00827 AttrFillGeometry *FillAttr = NULL; 00828 00829 BOOL result = GetCurrentLineAndFillAttrs(&LineAttr, &FillAttr); 00830 00831 if (LineAttr != NULL && LineCol != NULL) 00832 *LineCol = LineAttr->GetStartColour(); 00833 00834 if (FillAttr != NULL && FillCol != NULL) 00835 { 00836 // New bit added by will (3/11/94) to make colour bar show 00837 // the selected fill control point's colour. 00838 // Note this assumes there are only start and end colours, 00839 // and so will NOT work with multi-stage fills. 00840 00841 if (FillAttr->GetRuntimeClass() == CC_RUNTIME_CLASS(AttrFlatColourFill)) 00842 { 00843 *FillCol = FillAttr->GetStartColour(); 00844 } 00845 else 00846 { 00847 if (EndGradFill == NULL) 00848 { 00849 // The caller wants the selected point's colour or NULL (already set) 00850 00851 if (FillAttr->GetSelectionCount() == 1) // If there is only 1 selected blob 00852 { 00853 // Get the colour of the selected blob 00854 00855 if (FillAttr->IsSelected(FILLCONTROL_STARTPOINT)) // Show Start Colour 00856 *FillCol = FillAttr->GetStartColour(); 00857 else if (FillAttr->IsSelected(FILLCONTROL_ENDPOINT)) // Show End Colour 00858 *FillCol = FillAttr->GetEndColour(); 00859 else if (FillAttr->IsSelected(FILLCONTROL_ENDPOINT2)) // Show End2 Colour 00860 *FillCol = FillAttr->GetEndColour2(); 00861 else if (FillAttr->IsSelected(FILLCONTROL_ENDPOINT3)) // Show End3 Colour 00862 *FillCol = FillAttr->GetEndColour3(); 00863 } 00864 } 00865 else 00866 { 00867 // User wants two colours 00868 00869 if (FillAttr->GetEndColour2() == NULL) // If the fill doesn't have a third colour 00870 { 00871 // We know FillCol is non-NULL 00872 *FillCol = FillAttr->GetStartColour(); 00873 00874 // We know EndGradFill is non-NULL 00875 *EndGradFill = FillAttr->GetEndColour(); 00876 } 00877 } 00878 } 00879 } 00880 00881 return(result); 00882 } 00883 00884 00885 00886 /******************************************************************************************** 00887 00888 > static void ColourManager::FindColourOfInterestToUser(IndexedColour **ResultCol, 00889 ColourList **ResultList = NULL) 00890 00891 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00892 Created: 6/1/95 00893 Inputs: - 00894 Outputs: ResultCol - NULL, or a pointer to the colour to use 00895 ResultList - NULL, or a pointer to the ColourList that colour resides in 00896 Returns: - 00897 00898 Purpose: Several things (Colour editor whenever the selection changes, generation 00899 of a new colour) need to know a 'useful' colour to display/copy. 00900 Rather than just showing the current default colour or something, they 00901 need to interactively update to show an appropriate colour from the 00902 selection and suchlike. 00903 00904 NOTE that there is another overloaded form of this method, which returns 00905 a DocColour istead. This method returns a pointer to a NAMED IndexedColour, 00906 so may return an entirely different colour to the other function. 00907 00908 The exact colour returned will be NULL (in dire emergency, usually only 00909 occurs if there are no documents open), or will be chosen from this 00910 priority list of possible contenders: 00911 MonoOn 00912 (1) Colour of first selected fill-blob found, 00913 (2) Fill-Colour of selection, 00914 (3) current/default fill colour, 00915 (4) line-Colour of selection, 00916 (5) current/default line colour, 00917 (6) the first active named colour in the document's colour list, 00918 (7) NULL 00919 MonoOff 00920 00921 Notes: 'Colour of selection' is determined by using (if possible) the last 00922 object selected, or the frontmost selected object if this fails. 00923 00924 If you are not interested in the ResultList return value, pass in NULL 00925 (use the default) for this parameter. 00926 00927 In debug builds only, extra checks are made which can cause an ERROR3 00928 if the colour found was not in the selected document's ColourList. 00929 00930 ********************************************************************************************/ 00931 00932 void ColourManager::FindColourOfInterestToUser(IndexedColour **ResultCol, ColourList **ResultList) 00933 { 00934 ERROR3IF(ResultCol == NULL, "ColourManager::FindColourOfInterestToUser - ResultCol is NULL!"); 00935 00936 // Ensure safe return values 00937 *ResultCol = NULL; 00938 if (ResultList != NULL) 00939 *ResultList = NULL; 00940 00941 // If there are no documents available, then we can't find a colour - Return NULLs 00942 if (Document::GetSelected() == NULL) 00943 return; 00944 00945 // Ensure CurrentDoc == SelectedDoc 00946 Document *OldCurrentDoc = SetCurrentDoc(); 00947 00948 // Get the colour list. Just in case, we invalidate the cache (as this method is 00949 // called on document chnages and suchlike, so it is best to make sure we don't use 00950 // cached values for a no-longer-present document!) 00951 ColourList *ColList = ColourManager::GetColourList(TRUE); 00952 IndexedColour *UsefulColour = NULL; 00953 00954 // First, check if there is a VISIBLE selected fill blob, and use the colour of 00955 // the first one that we find, if we are lucky enough to find one. 00956 if (AttrFillGeometry::CountSelectionControlPoints() > 0) 00957 { 00958 // Yep. There is at least 1 visible selected fill blob... 00959 AttrFillGeometry* Fill = AttrFillGeometry::FindFirstSelectedAttr(); 00960 while (Fill != NULL && UsefulColour == NULL) 00961 { 00962 if (Fill->GetSelectionCount() > 0) 00963 { 00964 if (Fill->IsSelected(FILLCONTROL_STARTPOINT) && Fill->GetStartColour() != NULL) 00965 { 00966 // Use Fill Start Colour 00967 UsefulColour = Fill->GetStartColour()->FindParentIndexedColour(); 00968 break; 00969 } 00970 00971 if (Fill->IsSelected(FILLCONTROL_ENDPOINT) && Fill->GetEndColour() != NULL) 00972 { 00973 // Use Fill End Colour 00974 UsefulColour = Fill->GetEndColour()->FindParentIndexedColour(); 00975 break; 00976 } 00977 00978 if (Fill->IsSelected(FILLCONTROL_ENDPOINT2) && Fill->GetEndColour2() != NULL) 00979 { 00980 // Use Fill End Colour 00981 UsefulColour = Fill->GetEndColour2()->FindParentIndexedColour(); 00982 break; 00983 } 00984 00985 if (Fill->IsSelected(FILLCONTROL_ENDPOINT3) && Fill->GetEndColour3() != NULL) 00986 { 00987 // Use Fill End Colour 00988 UsefulColour = Fill->GetEndColour3()->FindParentIndexedColour(); 00989 break; 00990 } 00991 } 00992 00993 Fill = AttrFillGeometry::FindNextSelectedAttr(); 00994 } 00995 } 00996 00997 if (UsefulColour == NULL) 00998 { 00999 // Find the last node which was made selected (if any) 01000 // Scan back from this to find the nearest previous NodeAttribute which contains 01001 // colour(s), and make UsefulColour the first IndexedColour which we find in this search. 01002 SelRange *Selection = GetApplication()->FindSelection(); 01003 01004 if (Selection != NULL) 01005 { 01006 Node *pNode = Selection->GetLastSelectedNode(); 01007 // If the SelRange doesn't know what was last made selected, then see if anything 01008 // is selected, and if so, grab the last (topmost) selected object instead 01009 if (pNode == NULL) 01010 pNode = Selection->FindLast(); 01011 01012 // Now search through the attributes applied to this node, to see if we can 01013 // find an IndexedColour FILL (i.e. we ignore stroke colours for now) - we 01014 // will use the first one that we find 01015 NodeAttribute *pAttr = NULL; 01016 if (pNode != NULL) 01017 pAttr = NodeAttribute::FindFirstAppliedAttr(pNode); 01018 01019 while (pAttr != NULL && UsefulColour == NULL) 01020 { 01021 // Scan each NodeAttribute in turn to see if any of them contain any colours 01022 DocColour *pColour; 01023 UINT32 Context = 0; 01024 01025 // Only check non-line-colour attributes 01026 if (!(IS_A(pAttr, AttrStrokeColour))) 01027 { 01028 do 01029 { 01030 // Get the next colour field (if any) from the attribute, and find the 01031 // IndexedColour (if any) to which it refers 01032 pColour = pAttr->EnumerateColourFields(Context++); 01033 if (pColour != NULL) 01034 UsefulColour = pColour->FindParentIndexedColour(); 01035 01036 } while (pColour != NULL && UsefulColour == NULL); 01037 } 01038 01039 pAttr = NodeAttribute::FindPrevAppliedAttr(pAttr); 01040 } 01041 01042 01043 // If we still haven't found a colour, try for a line/stroke colour instead 01044 if (pNode != NULL && UsefulColour == NULL) 01045 pAttr = NodeAttribute::FindFirstAppliedAttr(pNode); 01046 01047 while (pAttr != NULL && UsefulColour == NULL) 01048 { 01049 // Scan each NodeAttribute in turn to see if any of them contain any colours 01050 DocColour *pColour; 01051 UINT32 Context = 0; 01052 01053 // Only check line-colour attributes 01054 if (IS_A(pAttr, AttrStrokeColour)) 01055 { 01056 do 01057 { 01058 // Get the next colour field (if any) from the attribute, and find the 01059 // IndexedColour (if any) to which it refers 01060 pColour = pAttr->EnumerateColourFields(Context++); 01061 if (pColour != NULL) 01062 UsefulColour = pColour->FindParentIndexedColour(); 01063 01064 } while (pColour != NULL && UsefulColour == NULL); 01065 } 01066 01067 pAttr = NodeAttribute::FindPrevAppliedAttr(pAttr); 01068 } 01069 01070 } 01071 } 01072 01073 if (UsefulColour == NULL) 01074 { 01075 // OK, then. let's see if there is a default fill colour, or failing that 01076 // (eg it could be 'no colour') a default line colour, which we can edit. 01077 AttributeManager &AttrMgr = Document::GetSelected()->GetAttributeMgr(); 01078 01079 DocColour LineCol; 01080 DocColour FillCol; 01081 01082 AttrMgr.GetCurrentLineAndFillColour(CC_RUNTIME_CLASS(NodeRenderableInk), 01083 &LineCol, &FillCol); 01084 01085 UsefulColour = FillCol.FindParentIndexedColour(); 01086 if (UsefulColour == NULL) 01087 UsefulColour = LineCol.FindParentIndexedColour(); 01088 } 01089 01090 if (UsefulColour == NULL) 01091 { 01092 // Ok, we're rapidly approaching a moment of panic. Try the first non-deleted named 01093 // colour in the selected document's colour list. If nothing else, there should 01094 // always be a default Black that we can use 01095 01096 if (ColList != NULL) 01097 { 01098 IndexedColour *Ptr = (IndexedColour *) ColList->GetHead(); 01099 while (Ptr != NULL && UsefulColour == NULL) 01100 { 01101 if (Ptr->IsNamed() && !Ptr->IsDeleted()) 01102 UsefulColour = Ptr; 01103 01104 Ptr = (IndexedColour *) ColList->GetNext(Ptr); 01105 } 01106 } 01107 } 01108 01109 // Sanity check. Should never ever ever be the case, ever. 01110 if (UsefulColour != NULL) 01111 ERROR3IF(UsefulColour->IsDeleted(), 01112 "ColourManager::FindColourOfInterestToUser - Colour found is DELETED!"); 01113 01114 // Fill in the return results 01115 *ResultCol = UsefulColour; 01116 if (UsefulColour != NULL && ResultList != NULL) 01117 *ResultList = ColList; 01118 01119 #ifdef _DEBUG 01120 // In debug builds, verify that the returned colour is in the list we 01121 // expect it to be in! 01122 01123 if (ColList != NULL && UsefulColour != NULL) 01124 { 01125 IndexedColour *Ptr = (IndexedColour *) ColList->GetHead(); 01126 while (Ptr != NULL && Ptr != UsefulColour) 01127 Ptr = (IndexedColour *) ColList->GetNext(Ptr); 01128 01129 if (Ptr == NULL) 01130 { 01131 Ptr = (IndexedColour *) ColList->GetUnnamedColours()->GetHead(); 01132 while (Ptr != NULL && Ptr != UsefulColour) 01133 Ptr = (IndexedColour *) ColList->GetUnnamedColours()->GetNext(Ptr); 01134 } 01135 01136 ERROR3IF(Ptr != UsefulColour, 01137 "ColourManager::FindColourOfInterestToUser" 01138 " - Colour found is not in the current colour list!"); 01139 } 01140 #endif 01141 01142 // And restore the previous CurrentDocument state 01143 RestoreCurrentDoc(OldCurrentDoc); 01144 } 01145 01146 01147 01148 /******************************************************************************************** 01149 01150 > static void ColourManager::FindColourOfInterestToUser(DocColour *ResultCol, 01151 ColourList **ResultList = NULL, 01152 BOOL WantLineColour = FALSE) 01153 01154 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01155 Created: 6/1/95 01156 Inputs: - 01157 Outputs: ResultCol - will be returned filled in with details of the colour to use 01158 ResultList - NULL, or a pointer to the ColourList of the relevant document 01159 WantLinecolour - TRUE if you'd rather get a line colour, FALSE if you want 01160 a fill colour. 01161 Returns: - 01162 01163 Purpose: Several things (Colour editor whenever the selection changes, generation 01164 of a new colour) need to know a 'useful' colour to display/copy. 01165 Rather than just showing the current default colour or something, they 01166 need to interactively update to show an appropriate colour from the 01167 selection and suchlike. 01168 01169 This is very similar to the other overloaded method, but returns a DocColour. 01170 NOTE however, that the returned colour may not match the IndexedColour 01171 returned by the other method - a DocColour (which does not reference 01172 a NAMED IndexedColour) may be returned before a suitable IndexedColour 01173 would have been found. 01174 01175 This is used to determine the colour definition for a colour to use when 01176 editing "local colours" in the colour editor. 01177 01178 The exact colour returned will be NULL (in dire emergency, usually only 01179 occurs if there are no documents open), or will be chosen from this 01180 priority list of possible contenders: 01181 MonoOn 01182 (1) Colour of first selected fill-blob found (if !WantLineColour), 01183 (2) Fill-Colour of selection (if !WantLineColour), 01184 (3) current/default fill colour (if !WantLineColour), 01185 (4) line-Colour of selection (If WantLineColour), 01186 (5) current/default line colour (if WantLineColour), 01187 (6) COLOUR_BLACK 01188 MonoOff 01189 01190 Notes: 'Colour of selection' is determined by using (if possible) the last 01191 object selected, or the frontmost selected object if this fails. 01192 01193 If you are not interested in the ResultList return value, pass in NULL 01194 (use the default) for this parameter. 01195 01196 Camelot will not return a 'no fill' default colour (conditions 3 and 6) but 01197 Webster does because the Webster colour editor wants to handle this 01198 situation. 01199 01200 ********************************************************************************************/ 01201 01202 void ColourManager::FindColourOfInterestToUser(DocColour *ResultCol, ColourList **ResultList, 01203 BOOL WantLineColour) 01204 { 01205 ERROR3IF(ResultCol == NULL, "ColourManager::FindColourOfInterestToUser - ResultCol is NULL!"); 01206 01207 // Ensure safe return values 01208 *ResultCol = DocColour(COLOUR_BLACK); 01209 if (ResultList != NULL) 01210 *ResultList = NULL; 01211 01212 // If there are no documents available, then we can't find a colour - Return NULLs 01213 if (Document::GetSelected() == NULL) 01214 return; 01215 01216 // Ensure CurrentDoc == SelectedDoc 01217 Document *OldCurrentDoc = SetCurrentDoc(); 01218 01219 // Get the colour list. Just in case, we invalidate the cache (as this method is 01220 // called on document chnages and suchlike, so it is best to make sure we don't use 01221 // cached values for a no-longer-present document!) 01222 ColourList *ColList = ColourManager::GetColourList(TRUE); 01223 BOOL FoundUsefulColour = FALSE; 01224 01225 // First, check if there is a VISIBLE selected fill blob, and use the colour of 01226 // the first one that we find, if we are lucky enough to find one. 01227 if (!WantLineColour && AttrFillGeometry::CountSelectionControlPoints() > 0) 01228 { 01229 // Yep. There is at least 1 visible selected fill blob... 01230 AttrFillGeometry* Fill = AttrFillGeometry::FindFirstSelectedAttr(); 01231 while (Fill != NULL && !FoundUsefulColour) 01232 { 01233 if (Fill->GetSelectionCount() > 0) 01234 { 01235 // CGS .... 01236 01237 // DMc's multi stage fills (blobs) do not dynamically update the colour edit 01238 // dialog when they are clicked on. This has now been 01239 // fixed (by me!). Problem was to do with the fact that this function never 01240 // even considered them .... 01241 01242 FillRamp* pFillRamp = Fill->GetFillRamp (); 01243 01244 if (pFillRamp != NULL) 01245 { 01246 UINT32 NumberSelected = pFillRamp->CountSelBlobs (); 01247 01248 if (NumberSelected > 0) 01249 { 01250 INT32 SelectedIndex = pFillRamp->GetSelectedIndex (); 01251 ColRampItem* TheItem = (ColRampItem*) pFillRamp->GetValidIndexedItem (SelectedIndex); 01252 01253 if (TheItem != NULL) 01254 { 01255 FoundUsefulColour = TRUE; 01256 *ResultCol = TheItem->GetColour (); 01257 } 01258 } 01259 } 01260 01261 if (Fill->IsSelected(FILLCONTROL_STARTPOINT) && Fill->GetStartColour() != NULL) 01262 { 01263 // Use Fill Start Colour 01264 FoundUsefulColour = TRUE; 01265 *ResultCol = *(Fill->GetStartColour()); 01266 break; 01267 } 01268 01269 if (Fill->IsSelected(FILLCONTROL_ENDPOINT) && Fill->GetEndColour() != NULL) 01270 { 01271 // Use Fill End Colour 01272 FoundUsefulColour = TRUE; 01273 *ResultCol = *(Fill->GetEndColour()); 01274 break; 01275 } 01276 01277 if (Fill->IsSelected(FILLCONTROL_ENDPOINT2) && Fill->GetEndColour2() != NULL) 01278 { 01279 // Use Fill End Colour 01280 FoundUsefulColour = TRUE; 01281 *ResultCol = *(Fill->GetEndColour2()); 01282 break; 01283 } 01284 01285 if (Fill->IsSelected(FILLCONTROL_ENDPOINT3) && Fill->GetEndColour3() != NULL) 01286 { 01287 // Use Fill End Colour 01288 FoundUsefulColour = TRUE; 01289 *ResultCol = *(Fill->GetEndColour3()); 01290 break; 01291 } 01292 } 01293 01294 Fill = AttrFillGeometry::FindNextSelectedAttr(); 01295 } 01296 } 01297 01298 if (!FoundUsefulColour) 01299 { 01300 // Find the last node which was made selected (if any) 01301 // Scan back from this to find the nearest previous NodeAttribute which contains 01302 // colour(s), and make ResultColour ref the first IndexedColour which we find in this search. 01303 SelRange *Selection = GetApplication()->FindSelection(); 01304 01305 // If there are any selected nodes, then... 01306 if (Selection != NULL && Selection->Count() > 0) 01307 { 01308 Node *pNode = Selection->GetLastSelectedNode(); 01309 01310 // If the SelRange doesn't know what was last made selected, then see if anything 01311 // is selected, and if so, grab the last (topmost) selected object instead 01312 if (pNode == NULL) 01313 pNode = Selection->FindLast(); 01314 01315 // Now search through the attributes applied to this node, to see if we can 01316 // find an IndexedColour FILL (i.e. we ignore stroke colours for now) - we 01317 // will use the first one that we find 01318 NodeAttribute *pAttr = NULL; 01319 01320 if (!WantLineColour) 01321 { 01322 if (pNode != NULL) 01323 pAttr = NodeAttribute::FindFirstAppliedAttr(pNode); 01324 01325 while (pAttr != NULL && !FoundUsefulColour) 01326 { 01327 // Scan each NodeAttribute in turn to see if any of them contain any colours 01328 DocColour *pColour; 01329 UINT32 Context = 0; 01330 01331 // Only check non-line-colour attributes 01332 if (!(IS_A(pAttr, AttrStrokeColour))) 01333 { 01334 do 01335 { 01336 // Get the next colour field (if any) from the attribute, and find the 01337 // IndexedColour (if any) to which it refers 01338 pColour = pAttr->EnumerateColourFields(Context++); 01339 if (pColour != NULL) 01340 { 01341 FoundUsefulColour = TRUE; 01342 *ResultCol = *pColour; 01343 } 01344 01345 } while (pColour != NULL && !FoundUsefulColour); 01346 } 01347 01348 pAttr = NodeAttribute::FindPrevAppliedAttr(pAttr); 01349 } 01350 } 01351 else 01352 { 01353 // If we still haven't found a colour, try for a line/stroke colour instead 01354 if (pNode != NULL && !FoundUsefulColour) 01355 pAttr = NodeAttribute::FindFirstAppliedAttr(pNode); 01356 01357 while (pAttr != NULL && !FoundUsefulColour) 01358 { 01359 // Scan each NodeAttribute in turn to see if any of them contain any colours 01360 DocColour *pColour; 01361 UINT32 Context = 0; 01362 01363 // Only check line-colour attributes 01364 if (IS_A(pAttr, AttrStrokeColour)) 01365 { 01366 do 01367 { 01368 // Get the next colour field (if any) from the attribute, and find the 01369 // IndexedColour (if any) to which it refers 01370 pColour = pAttr->EnumerateColourFields(Context++); 01371 if (pColour != NULL) 01372 { 01373 FoundUsefulColour = TRUE; 01374 *ResultCol = *pColour; 01375 } 01376 01377 } while (pColour != NULL && !FoundUsefulColour); 01378 } 01379 01380 pAttr = NodeAttribute::FindPrevAppliedAttr(pAttr); 01381 } 01382 } 01383 01384 } 01385 } 01386 01387 if (!FoundUsefulColour) 01388 { 01389 // OK, then. let's see if there is a default fill colour, or failing that 01390 // (eg it could be 'no colour') a default line colour, which we can edit. 01391 AttributeManager &AttrMgr = Document::GetSelected()->GetAttributeMgr(); 01392 01393 DocColour LineCol; 01394 DocColour FillCol; 01395 01396 AttrMgr.GetCurrentLineAndFillColour(CC_RUNTIME_CLASS(NodeRenderableInk), 01397 &LineCol, &FillCol); 01398 01399 if (!WantLineColour) 01400 { 01401 // Webster wants the colour even if it is 'no fill' 01402 #ifndef WEBSTER 01403 if (!FillCol.IsTransparent()) 01404 #endif //WEBSTER 01405 { 01406 *ResultCol = FillCol; 01407 FoundUsefulColour = TRUE; 01408 } 01409 } 01410 else 01411 { 01412 #ifndef WEBSTER 01413 if (!LineCol.IsTransparent()) 01414 #endif //WEBSTER 01415 { 01416 *ResultCol = LineCol; 01417 FoundUsefulColour = TRUE; 01418 } 01419 } 01420 } 01421 01422 if (!FoundUsefulColour) 01423 { 01424 // Ok, we're rapidly approaching a moment of panic. Try the first non-deleted named 01425 // colour in the selected document's colour list. If nothing else, there should 01426 // always be a default Black that we can use 01427 01428 if (ColList != NULL) 01429 { 01430 IndexedColour *Ptr = (IndexedColour *) ColList->GetHead(); 01431 while (Ptr != NULL && !FoundUsefulColour) 01432 { 01433 if (Ptr->IsNamed() && !Ptr->IsDeleted()) 01434 { 01435 FoundUsefulColour = TRUE; 01436 ResultCol->MakeRefToIndexedColour(Ptr); 01437 } 01438 01439 Ptr = (IndexedColour *) ColList->GetNext(Ptr); 01440 } 01441 } 01442 } 01443 01444 // Fill in the return results 01445 if (ResultList != NULL) 01446 *ResultList = ColList; 01447 01448 // And restore the previous CurrentDocument state 01449 RestoreCurrentDoc(OldCurrentDoc); 01450 } 01451 01452 01453 01454 /******************************************************************************************** 01455 01456 > static IndexedColour *ColourManager::GenerateNewNamedColour(ColourList *ParentList, 01457 IndexedColour *SourceColour) 01458 01459 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01460 Created: 25/11/94 01461 Inputs: ParentList - The list in which the SourceColour resides - The resulting 01462 colour will also be placed into this list. May NOT be NULL. 01463 SourceColour - NULL (to copy the current attribute FillColour), or a pointer 01464 to the colour you wish to duplicate. 01465 01466 Outputs: (ParentList - will contain the new colour if all went well) 01467 Returns: NULL if it failed, else 01468 A clone of SourceColour. This will be pretty much identical to SourceColour, 01469 except that it will always be a NAMED colour. 01470 01471 Purpose: Creates a new named IndexedColour. If possible, this colour is copied from 01472 the given SourceColour, but if this is not available, an attempt to find 01473 a useful colour to copy will be made - if this fails, a battleship grey 01474 will be created. i.e. apart from abject failure, this always creates a 01475 new colour. 01476 01477 It generates a new colour, adds it to the ParentList, and generates an 01478 UNDO record for the action; this includes a ColourListChanged msg broadcast. 01479 01480 NOTE that the user is prompted for a new name, and has the opportunity 01481 to cancel creation of the colour, in which case, NULL will be returned. 01482 You must therefore handle a NULL return *quietly*. 01483 01484 Notes: This code is used by the ColourBar and ColourGallery "new colour" code 01485 to generate a new named colour. 01486 01487 Errors: If the return value is NULL, an unreported memory allocation failure has 01488 occurred. 01489 01490 If the ParentList is not the ColourList for the Selected document, and 01491 no source colour is given, chances are FindColourOfInterestToUser will 01492 get upset and ERROR3. 01493 01494 SeeAlso: IndexedColour::IndexedColour; ColourManager::UnHideColours; 01495 ColourManager::FindColourOfInterestToUser 01496 01497 ********************************************************************************************/ 01498 01499 IndexedColour *ColourManager::GenerateNewNamedColour(ColourList *ParentList, 01500 IndexedColour *SourceColour) 01501 { 01502 ERROR3IF(ParentList == NULL, "ColourManager::GenerateNamedColour - NULL ParentList!"); 01503 01504 IndexedColour *NewCol = NULL; 01505 01506 if (SourceColour != NULL) 01507 { 01508 // Copy the source colour 01509 NewCol = new IndexedColour(*SourceColour); 01510 01511 // If parent is named and not tint/linked colour, remember where we copied 01512 // it from so that we can give a useful default parent in the colour editor 01513 // if the user decides to make it a tint/linked colour later on. 01514 if (NewCol->IsNamed() && NewCol->FindLinkedParent() == NULL) 01515 NewCol->SetLinkedParent(SourceColour, NewCol->GetType()); 01516 } 01517 else 01518 { 01519 IndexedColour *UsefulColour; 01520 FindColourOfInterestToUser(&UsefulColour); 01521 01522 if (UsefulColour != NULL) 01523 { 01524 NewCol = new IndexedColour(*UsefulColour); 01525 01526 // If parent is named and not tint/linked colour, remember where we copied 01527 // it from so that we can give a useful default parent in the colour editor 01528 // if the user decides to make it a tint/linked colour later on. 01529 if (NewCol->IsNamed() && NewCol->FindLinkedParent() == NULL) 01530 NewCol->SetLinkedParent(UsefulColour, NewCol->GetType()); 01531 } 01532 else 01533 { 01534 // Create a mid-grey HSV colour for them to edit 01535 ColourHSVT Bob; 01536 Bob.Hue = Bob.Saturation = Bob.Transparent = 0; 01537 Bob.Value = FIXED24(0.5); 01538 01539 NewCol = new INDEXEDCOLOUR_HSVT(&Bob); 01540 } 01541 } 01542 01543 if (NewCol == NULL) // Serious memory failure! 01544 return(NULL); 01545 01546 // Set the colour's name (1 to make it named, and 2 so it is not 01547 // the same as the colour it was copied from) 01548 /* 01549 String_64 NewName; 01550 01551 if (NewCol->IsNamed()) 01552 { 01553 // Is named, so is a copy: Name it "New Colour (Copy of WXYZ)" 01554 String_64 OldName = *NewCol->GetName(); 01555 String_64 TruncOldName; // Truncate old name to 32 chars 01556 OldName.Left(&TruncOldName, 32); // and add it into the new name 01557 NewName.MakeMsg(_R(IDS_NEWCOLOUR_COPY), (TCHAR *)TruncOldName); 01558 } 01559 else 01560 NewName.MakeMsg(_R(IDS_NEWCOLOUR)); // No name, so make it named: "New colour" 01561 */ 01562 01563 #if !defined(EXCLUDE_FROM_RALPH) 01564 #ifndef STANDALONE 01565 // Ask for a new name for the colour. This also gives the user a chance 01566 // to back out of the deal without losing their deposit (though if they didn't 01567 // tick the small box in the small print, we'll continue sending them junk mail ;-) 01568 if (!NewColourDlg::InvokeDialog(ParentList, NewCol, NEWCOLOUR_MUSTBENAMED)) 01569 { 01570 delete NewCol; // Bummer. They cancelled their subscription 01571 return(NULL); 01572 } 01573 #endif 01574 #endif 01575 01576 // NewCol->SetName(NewName); 01577 01578 // Add the new colour (also ensuring that the colour has a unique name) 01579 ParentList->AddItem(NewCol); 01580 01581 // Create an undo record, but only if it is a colour style (named) 01582 IndexedColour *UnHideList[2]; 01583 UnHideList[0] = NewCol; 01584 UnHideList[1] = NULL; 01585 ColourManager::UnHideColours(ParentList, UnHideList); 01586 01587 return(NewCol); 01588 } 01589 01590 01591 01592 /******************************************************************************************** 01593 01594 > static IndexedColour *ColourManager::GenerateNewUnnamedColour(ColourList *ParentList, 01595 DocColour *SourceColour) 01596 01597 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01598 Created: 29/3/95 01599 01600 Inputs: ParentList - The list in which the resulting colour will be placed. 01601 In debug builds an ENSURE will be triggered if the new colour would be 01602 created with a parent-colour in a different colour list. 01603 May NOT be NULL. 01604 01605 SourceColour - A pointer to the colour you wish to duplicate. 01606 If NULL, some random "useful" colour will be substituted. 01607 01608 Outputs: (ParentList - will contain the new colour if all went well) 01609 Returns: NULL if it failed, else 01610 A copy of SourceColour. This will be pretty much identical to SourceColour, 01611 except that it will always be an UNNAMED IndexedColour. 01612 01613 Purpose: Creates a new named IndexedColour. If possible, this colour is copied from 01614 the given SourceColour, but if this is not available, an attempt to find 01615 a useful colour to copy will be made - if this fails, a battleship grey 01616 will be created. i.e. apart from abject failure, this always creates a 01617 new colour. 01618 01619 It generates a new colour & adds it to the ParentList unnamed-colours-list 01620 01621 Notes: This code is used by the Colour Editor to generate a new unnamed colour 01622 when editing "local colours". 01623 01624 Unnamed colours are auto-destructed when their usagecount is decremented 01625 to zero, so you don't generally need to clean up these colours. 01626 01627 When copying a colour style as an unnamed colour, we force it to be 'normal' 01628 This is so that initial attempts to edit the colour of an object delink 01629 it from its parent, and allow the colour to be freely edited. When editing 01630 the local colour, this force won't occur, which allows the user to specifically 01631 make locals which are links/tints. 01632 01633 Errors: If the return value is NULL, an unreported memory allocation failure has 01634 occurred. 01635 01636 SeeAlso: IndexedColour::IndexedColour; ColourManager::UnHideColours; 01637 ColourManager::FindColourOfInterestToUser 01638 01639 ********************************************************************************************/ 01640 01641 IndexedColour *ColourManager::GenerateNewUnnamedColour(ColourList *ParentList, 01642 DocColour *BaseSourceColour) 01643 { 01644 if (ParentList == NULL) 01645 { 01646 ERROR3("ColourManager::GenerateNewUnnamedColour - NULL ParentList!"); 01647 return(NULL); 01648 } 01649 01650 IndexedColour *NewCol = NULL; 01651 01652 DocColour SourceColour(COLOUR_BLACK); 01653 if (BaseSourceColour == NULL) 01654 FindColourOfInterestToUser(&SourceColour); // No supplied colour, so find one 01655 else 01656 SourceColour = *BaseSourceColour; // Use the supplied colour 01657 01658 IndexedColour *SourceIxCol = SourceColour.FindParentIndexedColour(); 01659 if (SourceIxCol == NULL) 01660 { 01661 // Copy the definition of a DocColour 01662 ColourGeneric ColDef; 01663 SourceColour.GetSourceColour(&ColDef); 01664 01665 NewCol = new IndexedColour(SourceColour.GetColourModel(), &ColDef); 01666 } 01667 else 01668 { 01669 // Copy an IndexedColour 01670 NewCol = new IndexedColour(*SourceIxCol); 01671 01672 if (NewCol != NULL) 01673 { 01674 NewCol->SetUnnamed(); // Ensure the colour is unnamed 01675 01676 // When copying a colour style as an unnamed colour, we force it to be 'normal' 01677 // This is so that initial attempts to edit the colour of an object delink 01678 // it from its parent, and allow the colour to be freely edited. When editing 01679 // the local colour, this force won't occur, which allows the user to specifically 01680 // make locals which are links/tints. 01681 // NOTE that we make the source colour our parent, so that subsequent attempts 01682 // to edit this colour will choose a sensible parent. 01683 // if (SourceIxCol->IsNamed()) 01684 // { 01685 // We no longer do this (Jason - 18/10/95) 01686 // This was a fix to the fact that the user could not edit tints/linked colours in the "simple" 01687 // colour editor, and thus could get trapped in a very confusing uneditable state. 01688 // These days they have both the ability to edit all colour types in the simple mode, 01689 // and the extra status line and constraint-display stuff to make it more obvious why they 01690 // can't change stuff when they can't. 01691 // NewCol->SetLinkedParent(SourceIxCol, COLOURTYPE_NORMAL); 01692 // 01693 // } 01694 01695 // We have copied the Parent colour (hint) from the copied colour. 01696 // However, if this is a "normal" (unlinked) colour, we really want to set 01697 // the parent hint to be the colour we were copied from. 01698 // (But we can only use the source colour if it's named and "alive") 01699 if (NewCol->FindLinkedParent() == NULL && SourceIxCol->IsNamed() && !SourceIxCol->IsDeleted()) 01700 NewCol->SetLinkedParent(SourceIxCol, NewCol->GetType()); 01701 } 01702 } 01703 01704 // Check that the parent colour of our new one is a legal parent (named, not deleted, and exists 01705 // in the target document) 01706 if (NewCol != NULL) 01707 { 01708 IndexedColour *Parent = NewCol->FindLastLinkedParent(); 01709 if (Parent != NULL) 01710 { 01711 if (Parent->IsDeleted() || !Parent->IsNamed()) 01712 Parent = NULL; // Deleted or unnamed - forget it 01713 01714 if (Parent != NULL) 01715 { 01716 // Check that the parent colour is in the same colour list as the NewCol will be going 01717 IndexedColour *Ptr = ParentList->GetUndeletedHead(); 01718 while (Ptr != NULL) 01719 { 01720 if (Ptr == Parent) 01721 break; 01722 01723 Ptr = ParentList->GetUndeletedNext(Ptr); 01724 } 01725 01726 if (Ptr != Parent) 01727 Parent = NULL; 01728 } 01729 01730 // Nope - we haven't got a safe parent, so vape the parent field altogether 01731 if (Parent == NULL) 01732 { 01733 ERROR3("Warning: Had to correct colour with illegal parent pointer"); 01734 NewCol->SetLinkedParent(NULL, COLOURTYPE_NORMAL); 01735 } 01736 } 01737 01738 // Add the new colour (also ensuring that the colour has a unique name) 01739 ParentList->GetUnnamedColours()->AddTail(NewCol); 01740 } 01741 01742 return(NewCol); 01743 } 01744 01745 01746 01747 01748 /******************************************************************************************** 01749 01750 > static void ColourManager::EnsureColourIsInDocument(Document *SourceDoc, 01751 Document *DestDoc, 01752 DocColour *SourceAndResultCol) 01753 01754 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01755 Created: 13/4/95 (Moved to ColourManager, 20/11/95) 01756 01757 Inputs: SourceDoc - NULL, or the document which contains the source colour 01758 01759 DestDoc - The document in which you want to use the colour (NOT NULL) 01760 01761 ResultCol - should point at a DocColour defining the colour you want 01762 to put in this document. It may be an immediate DocColour, or a reference 01763 to an IndexedColour. (this param may NOT be NULL) 01764 01765 Outputs: ResultCol (which may not be NULL) will be returned with a colour to 01766 use. This will either be COLOUR_TRANS, or will point at an IndexedColour 01767 in the SELECTED document which you may apply in that document. 01768 01769 Purpose: Ensures that the given DocColour references a "safe" colour to use within 01770 the given document. This may mean doing nothing to the colour, or it may 01771 be necessary to copy the colour (and possibly linked parent colour(s) as well!) 01772 into the DestDoc. Whatever happens, ResultCol will be filled in with something 01773 that you can use with confidence. 01774 01775 Notes: Uses the component copy system to copy colours across with merging. 01776 01777 What do you mean this should be in the colour manager? Have you seen how many 01778 files it rebuilds?! Eeek! (OK, so I've moved it now) 01779 01780 SeeAlso: ColourListComponent::StartComponentCopy 01781 01782 ********************************************************************************************/ 01783 01784 void ColourManager::EnsureColourIsInDocument(Document *SourceDoc, Document *DestDoc, 01785 DocColour *ResultCol) 01786 { 01787 ERROR3IF(ResultCol == NULL || DestDoc == NULL, "Illegal NULL param"); 01788 01789 if (SourceDoc == DestDoc) // Completely safe - into the same doc 01790 return; 01791 01792 // Find the indexed colour (if any) that the given colour references 01793 IndexedColour *ColourToApply = ResultCol->FindParentIndexedColour(); 01794 01795 if (ColourToApply == NULL) // It's a simple DocColour, so safe 01796 return; 01797 01798 // It's an IndexedColour. We must copy it to the dest doc, and use the copy. 01799 if (DestDoc != NULL) 01800 { 01801 // We're applying the colour into a different document! 01802 // We must duplicate (with merging) this colour into the dest doc before applying 01803 ColourListComponent *ColComp = (ColourListComponent *) 01804 DestDoc->GetDocComponent(CC_RUNTIME_CLASS(ColourListComponent)); 01805 01806 // Start the copy 01807 if (ColComp != NULL && ColComp->StartComponentCopy()) 01808 { 01809 DocColour RefCol; 01810 RefCol.MakeRefToIndexedColour(ColourToApply); 01811 01812 // Copy this colour (and any linked parents if necessary). RefCol now 01813 // references the destination colour, so we point ColourToApply at it 01814 ColComp->CopyColourAcross(&RefCol); 01815 ColourToApply = RefCol.FindParentIndexedColour(); 01816 01817 // And clean up, merging the colour into the other document's colour list 01818 ColComp->EndComponentCopy(NULL, FALSE); 01819 01820 // We've got an IndexedColour, so set ResultCol on it, and return 01821 ResultCol->MakeRefToIndexedColour(ColourToApply); 01822 return; 01823 } 01824 } 01825 01826 // We've failed to copy the colour across, so set it to simple 'no colour' 01827 *ResultCol = DocColour(COLOUR_BLACK); 01828 } 01829 01830 01831 01832 /******************************************************************************************** 01833 01834 > void ColourManager::ColourHasChanged(Document *ScopeDoc, 01835 ColourList *ColList, IndexedColour *Col) 01836 01837 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01838 Created: 11/5/94 01839 Inputs: ScopeDoc - the document in which this change is occurring 01840 ColList - the list of IndexedColours in which 'Col' resides 01841 Col - A pointer to the IndexedColour which has been changed 01842 Outputs: - 01843 Returns: - 01844 Purpose: Indicates to all interested parties that the given IndexedColour 01845 has been changed (sends a COLOURUPDATED message) 01846 e.g. Causes the ColourBar and document to redraw themselves 01847 01848 This variant indicates that the actual visible-colour definition has 01849 changed (i.e. the appearance of something filled with this colour will 01850 chnage, and thus must be redrawn). If 'non-visible' information only 01851 has changed, use ColourHasChangedInvisible instead. 01852 01853 Notes: If you are recieving messages, and wish to act on COLOURUPDATEDINVISIBLE, 01854 you should sit on BOTH COLOURUPDATED messages. Otherwise, you should 01855 only sit on COLOURUPDATED messages. 01856 01857 The ColourManager will force-redraw the parst of the ScopeDoc which 01858 rely on the changed colour, or any colour liked to the changed colour. 01859 01860 If ColList == the current colour list then entities such as the colour 01861 bar will redraw themselves to show the new state of this colour. 01862 01863 SeeAlso: ColourManager::ColourHasChangedInvisible 01864 01865 ********************************************************************************************/ 01866 01867 void ColourManager::ColourHasChanged(Document *ScopeDoc, 01868 ColourList *ColList, IndexedColour *Col) 01869 { 01870 ERROR3IF(ScopeDoc == NULL || ColList == NULL || Col == NULL, 01871 "ColourManager::ColourHasChanged - NULL parameters are illegal!\n"); 01872 01873 ColList->InvalidateInheritanceCache(); 01874 01875 BROADCAST_TO_ALL(ColourChangingMsg(ScopeDoc, ColList, Col, 01876 ColourChangingMsg::COLOURUPDATED)); 01877 } 01878 01879 01880 01881 /******************************************************************************************** 01882 01883 > void ColourManager::ColourHasChangedInvisible(Document *ScopeDoc, 01884 ColourList *ColList, IndexedColour *Col) 01885 01886 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01887 Created: 11/5/94 01888 Inputs: ScopeDoc - NULL, or the document in which this change is occurring 01889 (if non-NULL, the ColourManager will force a redraw of this document) 01890 ColList - NULL, or a list of IndexedColours in which 'Col' 01891 can be found. 01892 Col - A pointer to the IndexedColour which has been changed 01893 Outputs: - 01894 Returns: - 01895 Purpose: Indicates to all interested parties that the given IndexedColour 01896 has been changed (sends a COLOURUPDATEDINVISIBLE message) 01897 e.g. Causes the ColourBar to redraw itself 01898 01899 This variant indicates that the actual visible-colour definition has 01900 NOT changed (i.e. the appearance of something filled with this colour will 01901 NOT change, and thus redraw is unnecessary). e.g. the 01902 01903 If 'visible' information has changed, use ColourHasChanged instead. 01904 01905 Notes: If you are recieving messages, and wish to act on COLOURUPDATEDINVISIBLE, 01906 you should sit on BOTH COLOURUPDATED messages. 01907 01908 ColList really should point to the list in which the colour 01909 resides. If ColList == NULL or ColList == the current colour list, 01910 then entities such as the colour bar will redraw themselves to 01911 show the new state of this colour. 01912 01913 If ColList is not NULL, then all its sort orders will be marked invalid 01914 so that they are re-sorted the next time they are used. 01915 01916 (If an incorrect pointer (or NULL) is passed in, unnecessary redraws 01917 of colour bars etc may take place, so it is most preferable that you 01918 pass in the correct list pointer if you know it) 01919 01920 SeeAlso: ColourManager::ColourHasChanged 01921 01922 ********************************************************************************************/ 01923 01924 void ColourManager::ColourHasChangedInvisible(Document *ScopeDoc, 01925 ColourList *ColList, IndexedColour *Col) 01926 { 01927 ColList->InvalidateInheritanceCache(); 01928 BROADCAST_TO_ALL(ColourChangingMsg(ScopeDoc, ColList, Col, 01929 ColourChangingMsg::COLOURUPDATEDINVISIBLE)); 01930 } 01931 01932 01933 01934 /******************************************************************************************** 01935 01936 > void ColourManager::ColourListHasChanged(ColourList *ColList) 01937 01938 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01939 Created: 11/5/94 01940 Inputs: ColList - A ColourList of IndexedColours which has changed 01941 May NOT be NULL 01942 Outputs: - 01943 Returns: - 01944 Purpose: To inform all interested parties that the given list of 01945 IndexedColours has changed by item(s) being added, deleted, 01946 or moved to a new position. 01947 e.g This causes the ColourBar and ColourMgrDlg to update their 01948 displays to reflect the new state of the list, if the list is the 01949 one which they are currently displaying. 01950 01951 Notes: Remember to invalidate the sort orders in this sorted list if you 01952 have done anything that could affect sorting (Adding items will 01953 do this automatically, but you must do it if you've changed a colour) 01954 This is not done by this function, as actions such as deleting items 01955 never affect the sort order, but do need to cause a re-display 01956 01957 ********************************************************************************************/ 01958 01959 void ColourManager::ColourListHasChanged(ColourList *ColList) 01960 { 01961 ERROR3IF(ColList == NULL, "ColourManager::ColourListHasChanged: NULL parameter is illegal"); 01962 01963 // Inform the colour gallery ahead of everyone else 01964 // ColourGallery::ColourListHasChanged(ColList); 01965 01966 // And inform the plebs 01967 ColList->InvalidateInheritanceCache(); 01968 01969 Document *ParentDoc = (Document *) ColList->GetParentDocument(); 01970 BROADCAST_TO_ALL(ColourChangingMsg(ParentDoc, ColList, NULL, 01971 ColourChangingMsg::LISTUPDATED)); 01972 } 01973 01974 01975 01976 /******************************************************************************************** 01977 01978 > BOOL ColourManager::HideColours(ColourList *ColList, IndexedColour **ColourArray, 01979 BOOL ForceDelete) 01980 01981 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01982 Created: 6/6/94 01983 Inputs: ColList - The colour list in which the colours reside. Must be non-NULL. 01984 ColourArray - A NULL-terminated list of pointers to colours 01985 to be hidden. NOTE that this array is changed in the process! 01986 ForceDelete - TRUE if you want to forcibly hide ('delete') all 01987 the colours, even if they are in use in the document (in this case, 01988 all references in the document will be coerced to immediate DocColours 01989 (undoable, of course) and then the colour will be hidden as usual) 01990 FALSE if you only want truly unused colours to be hidden 01991 01992 Outputs: ColourArray may be changed (see Notes) 01993 01994 Returns: TRUE if it thinks it succeeded 01995 01996 Purpose: This 'deletes' colours by creating an undoable operation to 01997 hide them. It is assumed that the colours are not in use by the 01998 time you call this function - An ENSURE failure will occur if 01999 any are. After invoking the 'hide' operation, this function calls 02000 ColourListHasChanged 02001 02002 Notes: The passed ColourArray parameter is used as temporary workspace, 02003 and will be returned containing a list of the colours which were 02004 succesfully deleted. This modified list is copied for the undo system, 02005 so you need not keep it around after the call to this fn - i.e. it is 02006 your responsibility to delete the array after calling this method. 02007 The modified list is also guaranteed to be no larger than the original 02008 array, so you don't need to allocate extra space for it. 02009 02010 SeeAlso: ColourManager::UnHideColours; ColourManager::ColourListHasChanged 02011 02012 ********************************************************************************************/ 02013 02014 BOOL ColourManager::HideColours(ColourList *ColList, IndexedColour **ColourArray, 02015 BOOL ForceDelete) 02016 { 02017 ERROR3IF(ColList == NULL || ColourArray == NULL, 02018 "ColourManager::HideColours cannot accept NULL parameters\n"); 02019 02020 HideColoursInfo HCInfo; 02021 02022 HCInfo.ParentList = ColList; 02023 HCInfo.Colours = ColourArray; 02024 HCInfo.ForceDelete = ForceDelete; 02025 HCInfo.HideThem = TRUE; 02026 02027 OpDescriptor* OpDesc = 02028 OpDescriptor::FindOpDescriptor( OPTOKEN_HIDECOLOURS ); 02029 02030 if (OpDesc != NULL) 02031 OpDesc->Invoke((OpParam *) &HCInfo); 02032 02033 return(TRUE); 02034 } 02035 02036 02037 02038 /******************************************************************************************** 02039 02040 > BOOL ColourManager::UnHideColours(ColourList *ColList, IndexedColour **ColourArray) 02041 02042 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02043 Created: 14/6/94 02044 Inputs: ColList - The colour list in which the colours reside. Must be non-NULL. 02045 ColourArray - A NULL-terminated list of pointers to colours 02046 to be unhidden 02047 Outputs: - 02048 Returns: TRUE if it thinks it succeeded 02049 02050 Purpose: This un-'deletes' colours by creating an undoable operation to 02051 unhide them. This is used when creating a new colour to 'unhide' 02052 it (which has no immediate effect on the colour) - this creates 02053 an undo record that will hide the colour if the 'new' is undone. 02054 02055 Notes: The undo record generated uses a COPY of the array you passed in. 02056 It is your responsibility to delete the original array after calling 02057 this method. 02058 02059 SeeAlso: ColourManager::HideColours; ColourManager::ColourListHasChanged 02060 02061 ********************************************************************************************/ 02062 02063 BOOL ColourManager::UnHideColours(ColourList *ColList, IndexedColour **ColourArray) 02064 { 02065 ERROR3IF(ColList == NULL || ColourArray == NULL, 02066 "ColourManager::UnHideColours cannot accept NULL parameters\n"); 02067 02068 HideColoursInfo HCInfo; 02069 02070 HCInfo.ParentList = ColList; 02071 HCInfo.Colours = ColourArray; 02072 HCInfo.ForceDelete = FALSE; 02073 HCInfo.HideThem = FALSE; 02074 02075 OpDescriptor* OpDesc = 02076 OpDescriptor::FindOpDescriptor( OPTOKEN_SHOWCOLOURS ); 02077 02078 if (OpDesc != NULL) 02079 OpDesc->Invoke((OpParam *) &HCInfo); 02080 02081 return(TRUE); 02082 } 02083 02084 02085 02086 /******************************************************************************************** 02087 02088 > static BOOL ColourManager::ChangeColour(ColourList *ColList, 02089 IndexedColour *NewDefn, IndexedColour *Target, 02090 BOOL ChangeIsInvisible = FALSE) 02091 02092 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02093 Created: 14/6/94 02094 Inputs: ColList - The colour list in which the colours reside 02095 NewDefn - The new IndexedColour definition to be applied 02096 Target - The colour to which the definition is to be applied 02097 ChangeIsInvisible - TRUE if the change does not affect 'visible' parts 02098 of the colour definition (i.e. if objects drawn using this colour need 02099 not be redrawn). FALSE if the chnage does affect such objects. 02100 02101 Outputs: - 02102 Returns: TRUE if it thinks it succeeded 02103 02104 Purpose: This changes the colour 'Target' to be the same as 'NewDefn'. 02105 To achieve undo of this operation, the data members of the two 02106 colours are swapped (as the colour being changed must stay at the 02107 same memory location), and the NewDefn is used again as the undo 02108 record of this colour. 02109 Whenever the colour is changed, including during the execution 02110 of this funciton, and also by undo/redo, a ColourChangingMsg will 02111 be broadcast (either COLOURUPDATED or COLOURUPDATEDINVISIBLE, 02112 depending on the state of the ChangeIsInvisible flag) 02113 02114 Notes: As the memory occupied by 'NewDefn' is used in the undo record, 02115 it is essential that you do NOT DELETE it after invoking this 02116 function. You must also make absolutely sure that you do not 02117 pass the same pointer in NewDefn more than once, or a crash will 02118 occur when Camelot throws away the undo records. 02119 02120 SeeAlso: OpColourChange; ColourChangingMsg 02121 02122 ********************************************************************************************/ 02123 02124 BOOL ColourManager::ChangeColour(ColourList *ColList, 02125 IndexedColour *NewDefn, IndexedColour *Target, 02126 BOOL ChangeIsInvisible) 02127 { 02128 #if !defined(EXCLUDE_FROM_RALPH) 02129 ERROR3IF(ColList == NULL || NewDefn == NULL || Target == NULL, 02130 "ColourManager::ChangeColour - illegal NULL param(s)"); 02131 02132 OpDescriptor* OpDesc = 02133 OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpColourChange)); 02134 02135 if (OpDesc != NULL) 02136 { 02137 ColourChangeInfo Param; 02138 02139 Param.ParentList = ColList; 02140 Param.Target = Target; 02141 Param.NewDefn = NewDefn; 02142 Param.InvisibleChange = ChangeIsInvisible; 02143 02144 OpDesc->Invoke((OpParam *) &Param); 02145 } 02146 #endif 02147 return(TRUE); 02148 } 02149 02150 02151 02152 02153 02154 02155 02156 02157 02158 02159 02160 02161 02162 02163 02164 02165 02166 02167 02168 #if !defined(EXCLUDE_FROM_RALPH) 02169 02170 /******************************************************************************************** 02171 02172 > OpHideColours::OpHideColours() 02173 02174 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02175 Created: 7/6/94 02176 Inputs: - 02177 Outputs: - 02178 Returns: - 02179 Purpose: OpHideColours constructor (Creates an undoable operation) 02180 Errors: - 02181 SeeAlso: - 02182 02183 ********************************************************************************************/ 02184 02185 02186 OpHideColours::OpHideColours(): UndoableOperation() 02187 { 02188 Colours = NULL; // For safety, ensure initialised 02189 ParentColList = NULL; 02190 HideThem = TRUE; 02191 } 02192 02193 02194 02195 /******************************************************************************************** 02196 02197 > BOOL OpHideColours::Init() 02198 02199 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02200 Created: 7/6/94 02201 Inputs: - 02202 Outputs: - 02203 Returns: TRUE if the operation could be successfully initialised 02204 FALSE if no more memory could be allocated 02205 02206 Purpose: OpHideColours initialiser method 02207 02208 Notes: This provides TWO OpDescriptors (Hide colours and Show colours). 02209 The same actual Op is invoked for both hiding and showing colours, 02210 but it is invoked via different op descriptors, to provide different 02211 names for the undo ("undo delete colours" or "undo create colours") 02212 02213 02214 ********************************************************************************************/ 02215 02216 BOOL OpHideColours::Init() 02217 { 02218 BOOL Result = RegisterOpDescriptor(0, 02219 _R(IDS_OPHIDECOLOURS), 02220 CC_RUNTIME_CLASS(OpHideColours), 02221 OPTOKEN_HIDECOLOURS, 02222 OpHideColours::GetState, 02223 0, /* help ID */ 02224 0, /* Bubble help ID */ 02225 0 /* bitmap ID */ 02226 ); 02227 if (Result) 02228 Result = RegisterOpDescriptor(0, 02229 _R(IDS_OPSHOWCOLOURS), 02230 CC_RUNTIME_CLASS(OpHideColours), 02231 OPTOKEN_SHOWCOLOURS, 02232 OpHideColours::GetState, 02233 0, /* help ID */ 02234 0, /* Bubble help ID */ 02235 0 /* bitmap ID */ 02236 ); 02237 return(Result); 02238 } 02239 02240 02241 02242 /******************************************************************************************** 02243 02244 > OpState OpHideColours::GetState(String_256*, OpDescriptor*) 02245 02246 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02247 Created: 7/6/94 02248 Inputs: - 02249 Outputs: - 02250 Returns: The state of the OpHideColours operation 02251 Purpose: For finding the OpHideColours' state. 02252 02253 ********************************************************************************************/ 02254 02255 OpState OpHideColours::GetState(String_256* UIDescription, OpDescriptor*) 02256 { 02257 OpState OpSt; 02258 return(OpSt); 02259 } 02260 02261 02262 02263 /******************************************************************************************** 02264 02265 > void OpHideColours::Do(OpDescriptor*) 02266 02267 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02268 Created: 7/6/94 02269 Inputs: OpDescriptor (unused) 02270 Outputs: - 02271 Returns: - 02272 Purpose: (Performs the colour change operation) 02273 OpHideColours has a special overloaded Do operator which takes 02274 parameters describing what is to be done - that version of Do must 02275 be used 02276 Errors: Always generates an ENSURE failure because this Do doesn't. 02277 SeeAlso: - 02278 02279 ********************************************************************************************/ 02280 02281 void OpHideColours::Do(OpDescriptor *NotUsed) 02282 { 02283 ERROR3("OpHideColours does not provide a Do() function - use DoWithParam"); 02284 End(); 02285 } 02286 02287 02288 02289 /******************************************************************************************** 02290 02291 > void OpHideColours::DoWithParam(OpDescriptor *pOp, OpParam *Param) 02292 02293 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02294 Created: 7/6/94 02295 Inputs: pOp - OpDescriptor as for all Do() functions 02296 Param - Actually points to a HideColoursInfo structure, detailing what to 02297 hide/unhide, and how to do it. 02298 Outputs: - 02299 Returns: - 02300 Purpose: Performs the colour change operation, as described by 'Param' 02301 02302 ********************************************************************************************/ 02303 02304 void OpHideColours::DoWithParam(OpDescriptor *pOp, OpParam *Param) 02305 { 02306 HideColoursInfo *WhatToDo = (HideColoursInfo *) Param; 02307 // If Forced-delete is desired, then ensure that all DocColours referencing 02308 // any of our list of IndexedColours are forced to 'immediate' definitions 02309 02310 // Make sure that this operation is applied within the document which owns the colour list! 02311 pOurDoc = (Document *) WhatToDo->ParentList->GetParentDocument(); 02312 pOurView = NULL; 02313 if (!pOurDoc->IsKindOf(CC_RUNTIME_CLASS(Document))) 02314 { 02315 pOurDoc = NULL; // Arrrgh! It must be a basedoc or something! 02316 End(); 02317 return; 02318 } 02319 02320 ParentColList = WhatToDo->ParentList; 02321 Colours = WhatToDo->Colours; 02322 HideThem = WhatToDo->HideThem; 02323 02324 if (HideThem) 02325 { 02326 if (WhatToDo->ForceDelete) 02327 HideColourRefs(); 02328 else 02329 RemoveReferencedColours(); 02330 } 02331 02332 if (Colours[0] == NULL) 02333 { 02334 End(); 02335 return; 02336 } 02337 02338 // Create an action to undo the IndexedColour hide operation, and if we 02339 // succeed, then {un}hide the colours (Do) and inform the world of the change 02340 ActionHideColours *AHC; 02341 if (ActionHideColours::Init(this, &UndoActions, sizeof(ActionHideColours), 02342 WhatToDo->ParentList, WhatToDo->Colours, 02343 ((WhatToDo->HideThem) ? FALSE : TRUE), 02344 (Action**)(&AHC)) == AC_OK) 02345 { 02346 // Now, hide/unhide all the colours remaining in the list 02347 INT32 Index = 0; 02348 while (WhatToDo->Colours[Index] != NULL) 02349 { 02350 WhatToDo->Colours[Index]->SetDeleted(WhatToDo->HideThem); 02351 Index++; 02352 } 02353 02354 // We have made the change, so broadcast that the list for this doc has changed 02355 ColourManager::ColourListHasChanged(ParentColList); 02356 } 02357 02358 End(); 02359 } 02360 02361 02362 02363 /******************************************************************************************** 02364 02365 > void OpHideColours::Undo() 02366 02367 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02368 Created: 7/6/94 02369 Inputs: - 02370 Outputs: - 02371 Returns: - 02372 Purpose: Undoes whatever Do() or Redo() did 02373 02374 ********************************************************************************************/ 02375 02376 BOOL OpHideColours::Undo() 02377 { 02378 BOOL Result = Operation::Undo(); 02379 if (Result) 02380 { 02381 // We have made the change, so broadcast that the list for this doc has changed 02382 ColourManager::ColourListHasChanged(ParentColList); 02383 } 02384 02385 return (Result); 02386 } 02387 02388 02389 02390 /******************************************************************************************** 02391 02392 > void OpHideColours::Redo() 02393 02394 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02395 Created: 7/6/94 02396 Inputs: - 02397 Outputs: - 02398 Returns: - 02399 Purpose: Redoes whatever Undo() undid 02400 02401 ********************************************************************************************/ 02402 02403 BOOL OpHideColours::Redo() 02404 { 02405 BOOL Result = Operation::Redo(); 02406 if (Result) 02407 { 02408 // We have made the change, so broadcast that the list for this doc has changed 02409 ColourManager::ColourListHasChanged(ParentColList); 02410 } 02411 02412 return (Result); 02413 } 02414 02415 02416 02417 /******************************************************************************************** 02418 02419 > virtual void OpHideColours::GetOpName(String_256 *Result) 02420 02421 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02422 Created: 7/6/94 02423 02424 Outputs: Result - returned filled-in with the name 02425 Returns: - 02426 Purpose: Redoes whatever Undo() undid 02427 02428 ********************************************************************************************/ 02429 02430 void OpHideColours::GetOpName(String_256 *Result) 02431 { 02432 ERROR3IF(Result == NULL, "Illegal null param"); 02433 02434 if (HideThem) 02435 Result->MakeMsg(_R(IDS_DELETECOLOURS)); 02436 else 02437 Result->MakeMsg(_R(IDS_CREATECOLOURS)); 02438 } 02439 02440 02441 02442 /******************************************************************************************** 02443 02444 > NodeAttribute *OpHideColours::HideAttrNode(Node *CurNode, DocColour *TheColour) 02445 02446 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02447 Created: 7/6/94 02448 Inputs: CurNode - The Attribute node containing the colour 02449 TheColour - the colour in the node which we may want to hide 02450 Outputs: - 02451 Returns: NULL, or the cloned node. 02452 Purpose: Checks if the given colour references an IndexedColour in the 02453 given NULL terminated list of colours. If this is the case, then 02454 the node containing the colour attribute is hidden and replaced 02455 with a clone of itself. This clone is returned, so that the caller 02456 can then change the contained DocColour(s) appropriately. 02457 02458 ********************************************************************************************/ 02459 02460 NodeAttribute *OpHideColours::HideAttrNode(Node *CurNode, DocColour *TheColour) 02461 { 02462 IndexedColour *ParentCol = TheColour->FindParentIndexedColour(); 02463 02464 if (ParentCol != NULL) 02465 { 02466 INT32 i = 0; 02467 while (Colours[i] != NULL && Colours[i] != ParentCol) 02468 i++; 02469 02470 if (Colours[i] != ParentCol) 02471 return(NULL); 02472 02473 Node *ParentNode = CurNode->FindParent(); 02474 NodeAttribute *NodeToClone = (NodeAttribute *) CurNode; 02475 NodeAttribute *Clone; 02476 02477 ALLOC_WITH_FAIL(Clone, ((NodeAttribute *)NodeToClone->SimpleCopy()), this); 02478 if (Clone != NULL) 02479 { 02480 // Hide the original Attribute 02481 DoHideNode(CurNode, TRUE); 02482 02483 // Add the clone into the tree 02484 Clone->AttachNode(ParentNode, FIRSTCHILD); 02485 HideNodeAction* TheUndoAction; 02486 02487 // Create an action to hide the attribute when we undo 02488 if (HideNodeAction::Init(this, &UndoActions, Clone, TRUE, 02489 (Action**)(&TheUndoAction)) == AC_FAIL) 02490 { 02491 Clone->CascadeDelete(); // Delink the node/subtree from the 02492 delete Clone; // document tree and delete it 02493 } 02494 else 02495 return(Clone); 02496 } 02497 } 02498 02499 return(NULL); 02500 } 02501 02502 02503 02504 /******************************************************************************************** 02505 02506 > void OpHideColours::KillColourRef(DocColour *Perpetrator, IndexedColourPtr *ColourMap) 02507 02508 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02509 Created: 7/6/94 02510 02511 Inputs: Perpetrator - The DocColour to be neutered 02512 02513 ColourMap - NULL, or an array of IndexedColour pointers which map Colours[] 02514 into new local colour pointers. If the mapping entry is NULL, a mapping is 02515 set up, else the existing mapping is used. If ColourMap is NULL or memory 02516 cannot be allocated for the new mapping, this method will revert to making 02517 the colours immediate DocColours (which means it'll work in a falback mode) 02518 02519 Purpose: If the given DocColour refers to an IndexedColour, it is 02520 redefined as a Local colour based on the IndexedColour's 02521 definition. 02522 02523 This releases the DocColour's claim on the IxCol, thus allowing the latter 02524 to be deleted. Used for forced-delete 02525 02526 A new local colour is created (if necessary) and placed in the colour map 02527 entry corresponding to the index of the source colour in Colours[]. 02528 This is used for look-up, so that many colours using the same colour style 02529 can share the same resulting local colour definition, saving gobs of memory. 02530 02531 Scope: private 02532 02533 ********************************************************************************************/ 02534 02535 void OpHideColours::KillColourRef(DocColour *Perpetrator, IndexedColourPtr *ColourMap) 02536 { 02537 IndexedColour *Parent = Perpetrator->FindParentIndexedColour(); 02538 02539 if (Parent == NULL) 02540 return; 02541 02542 INT32 i = 0; 02543 if (ColourMap != NULL) 02544 { 02545 // Find the colour map entry index 02546 while (Colours[i] != NULL && Colours[i] != Parent) 02547 i++; 02548 02549 // If there is no mapping yet, create a new local colour to map to this Parent colour 02550 if (Colours[i] != NULL && ColourMap != NULL && ColourMap[i] == NULL) 02551 { 02552 ColourMap[i] = new IndexedColour(*(Colours[i])); 02553 if (ColourMap[i] != NULL) 02554 { 02555 ColourMap[i]->SetUnnamed(); // Ensure it's unnamed 02556 02557 ERROR3IF(GetWorkingDoc() == NULL, "NULL working doc in OpHideColours"); 02558 02559 // Add the local colour to the unnamed colour list 02560 // (A nasty sequence of derefs, but these are all guaranteed to work) 02561 GetWorkingDoc()->GetIndexedColours()->GetUnnamedColours()->AddTail(ColourMap[i]); 02562 02563 // Make sure the new local colour is legal (if its parent is deleted or is 02564 // just about to become deleted, then we must make the new colour stand-alone. 02565 // (In the case of undo, we needen't worry about being able to restore the 02566 // parent link, because the undo will also hide this attribute and return to 02567 // the original one which references the old parent-colour chain) 02568 IndexedColour *LinkedParent = ColourMap[i]->FindLinkedParent(); 02569 02570 if (LinkedParent != NULL) 02571 { 02572 // Is the parent already deleted? 02573 BOOL MustMakeStandalone = LinkedParent->IsDeleted(); 02574 02575 // If not, is it one of the colours we are currently deleting? 02576 if (!MustMakeStandalone) 02577 { 02578 INT32 j = 0; 02579 while (Colours[j] != NULL && Colours[j] != LinkedParent) 02580 j++; 02581 02582 if (Colours[j] != NULL) // LinkedParent is in our list to be deleted! 02583 MustMakeStandalone = TRUE; 02584 } 02585 02586 // It's parent is dodgy, so make it stand-alone 02587 if (MustMakeStandalone) 02588 ColourMap[i]->SetLinkedParent(NULL, COLOURTYPE_NORMAL); 02589 } 02590 } 02591 } 02592 } 02593 02594 if (ColourMap != NULL && Colours[i] != NULL && ColourMap[i] != NULL) 02595 { 02596 // We have a mapping - change the colour to reference the relevant local colour 02597 Perpetrator->MakeRefToIndexedColour(ColourMap[i]); 02598 } 02599 else 02600 { 02601 // Serious failure - make the DocColour immediate 02602 ColourGeneric Bob; 02603 02604 Parent->GetSourceColour(&Bob); 02605 *Perpetrator = DocColour(Parent->GetColourModel(), &Bob); 02606 } 02607 } 02608 02609 02610 02611 /******************************************************************************************** 02612 02613 > void OpHideColours::HideColourRefs(void) 02614 02615 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02616 Created: 6/6/94 02617 Purpose: Traverses the entire Camelot tree and replaces all references to 02618 indexed colours with immediate DocColour equivalents. The original 02619 attributes are hidden to allow undo. 02620 02621 ********************************************************************************************/ 02622 02623 void OpHideColours::HideColourRefs(void) 02624 { 02625 INT32 NumCols = 0; 02626 02627 while (Colours[NumCols] != NULL) // Find the last colour in the list 02628 NumCols++; 02629 02630 02631 IndexedColourPtr *ColourMap; 02632 ALLOC_WITH_FAIL(ColourMap, new IndexedColourPtr[NumCols+1], this); 02633 02634 // If ALLOC_WITH_FAIL fails, we back down to making the colours immediate DocColours 02635 // rather than failing completely. 02636 02637 // Clear the array to all NULL pointers 02638 if (ColourMap != NULL) 02639 { 02640 for (INT32 i = 0; i <= NumCols; i++) 02641 ColourMap[i] = NULL; 02642 } 02643 02644 02645 Node *CurNode = Node::DocFindFirstDepthFirst(GetWorkingDoc()); 02646 Node *NextNode; 02647 Node *NewNode; 02648 02649 while (CurNode != NULL) 02650 { 02651 // We may be about to chop this node out of the tree, so get the next node now 02652 NextNode = CurNode->DocFindNextDepthFirst(); 02653 02654 NewNode = NULL; 02655 02656 // Use to scan the colour fields of the attribute. 02657 UINT32 Context = 0; 02658 DocColour *pColour; 02659 02660 if (CurNode->IsAnAttribute()) 02661 { 02662 NodeAttribute *pNodeAttr = (NodeAttribute *) CurNode; 02663 02664 do 02665 { 02666 // Get the next colour field from the attribute 02667 pColour = pNodeAttr->EnumerateColourFields(Context++); 02668 02669 // If there is another colour field, see if we need to hide it 02670 if (pColour != NULL && pColour->FindParentIndexedColour() != NULL) 02671 NewNode = HideAttrNode(CurNode, pColour); 02672 } 02673 while ((NewNode == NULL) && (pColour != NULL)); 02674 // Keep going until we run out of colour fields, or we find one 02675 // that requires the node to be hidden 02676 02677 02678 if (NewNode != NULL) 02679 { 02680 // Forcibly change the NewNode DocColours to be local 02681 pNodeAttr = (NodeAttribute *) NewNode; 02682 Context = 0; // Start at the first colour field again 02683 02684 do 02685 { 02686 // Get the next colour field from the attribute 02687 pColour = pNodeAttr->EnumerateColourFields(Context++); 02688 02689 // If there is another colour, kill its reference, if any 02690 if (pColour != NULL) 02691 KillColourRef(pColour, ColourMap); 02692 } while (pColour != NULL); 02693 } 02694 02695 } // end if 02696 02697 CurNode = NextNode; 02698 } // end while 02699 02700 // And get rid of our working array 02701 delete [] ColourMap; 02702 } 02703 02704 02705 02706 /******************************************************************************************** 02707 02708 > void OpHideColours::RemoveColour(DocColour *Ref, INT32 *LastColour) 02709 02710 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02711 Created: 7/6/94 02712 Inputs: - 02713 Outputs: - 02714 Returns: - 02715 Purpose: Removes the indexedcolour (if any) referenced by the given DocColour 02716 from the 'Colours' list of colours-to-delete. 02717 02718 Notes: This assumes that any given colour will only appear in the list once 02719 It shifts all colours down by one place, as it is essential that the 02720 list ordering is retained. 02721 Errors: - 02722 SeeAlso: - 02723 02724 ********************************************************************************************/ 02725 02726 void OpHideColours::RemoveColour(DocColour *Ref, INT32 *LastColour) 02727 { 02728 IndexedColour *Col = Ref->FindParentIndexedColour(); 02729 02730 if (Col == NULL) // No colour referenced 02731 return; 02732 02733 INT32 i; 02734 for (i = 0; i <= *LastColour; i++) // Search for colour to delete 02735 { 02736 if (Col == Colours[i]) 02737 break; 02738 } 02739 02740 if (Col == Colours[i]) // We found something to delete 02741 { 02742 while (i < *LastColour) // Shift remaining list down one place 02743 { 02744 Colours[i] = Colours[i+1]; 02745 i++; 02746 } 02747 02748 Colours[*LastColour] = NULL; // Add new NULL terminator 02749 (*LastColour)--; // Decrement LastColour index 02750 } 02751 } 02752 02753 02754 02755 /******************************************************************************************** 02756 02757 > void OpHideColours::RemoveReferencedColours(void) 02758 02759 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02760 Created: 7/6/94 02761 Inputs: - 02762 Outputs: - 02763 Returns: - 02764 Purpose: Traverses the entire Camelot tree and removes all IndexedColours 02765 that are referenced therein from our list of colours-to-delete 02766 Errors: - 02767 SeeAlso: - 02768 02769 ********************************************************************************************/ 02770 02771 void OpHideColours::RemoveReferencedColours(void) 02772 { 02773 INT32 LastColour = 0; 02774 02775 while (Colours[LastColour] != NULL) // Find the last colour in the list 02776 LastColour++; 02777 02778 if ((--LastColour) < 0) 02779 return; 02780 02781 // Search the entire tree, removing all IndexedColours (from the WhatToDo 02782 // list) which are still in use in live parts of the tree. These cannot 02783 // be deleted, and so should be removed from further consideration 02784 ERROR3IF(GetWorkingDoc() == NULL, "OpHideColours called with NULL Document"); 02785 02786 Node *CurNode = GetWorkingDoc()->GetFirstNode(); 02787 Node *NextNode; 02788 while (CurNode != NULL) 02789 { 02790 // Have to remember this now, as we may be about to chop this node out of the tree! 02791 NextNode = CurNode->DocFindNextDepthFirst(); 02792 02793 if (CurNode->IsAnAttribute()) 02794 { 02795 // These variables are used to scan the colour fields in the attribute. 02796 NodeAttribute *pNodeAttr = (NodeAttribute *) CurNode; 02797 DocColour *pColour; 02798 UINT32 Context = 0; 02799 02800 do 02801 { 02802 // Get the next colour field from the attribute 02803 pColour = pNodeAttr->EnumerateColourFields(Context++); 02804 02805 // If there is another colour field, see if we need to hide it. 02806 if (pColour != NULL) 02807 RemoveColour(pColour, &LastColour); 02808 } 02809 // Keep going until we run out of colour fields 02810 while (pColour != NULL); 02811 } 02812 02813 CurNode = NextNode; 02814 } 02815 } 02816 02817 02818 02819 02820 02821 02822 02823 02824 02825 02826 02827 02828 02829 02830 02831 02832 02833 02834 02835 02836 02837 02838 02839 02840 02841 02842 02843 /******************************************************************************************** 02844 02845 > ActionHideColours::ActionHideColours() 02846 02847 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02848 Created: 6/6/94 02849 Purpose: ActionHideColours constructor 02850 02851 ********************************************************************************************/ 02852 02853 ActionHideColours::ActionHideColours() 02854 { 02855 ChangeColour = NULL; 02856 ParentList = NULL; 02857 } 02858 02859 02860 02861 /******************************************************************************************** 02862 02863 > ActionHideColours::~ActionHideColours() 02864 02865 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02866 Created: 6/6/94 02867 Purpose: ActionHideColours destructor 02868 02869 ********************************************************************************************/ 02870 02871 ActionHideColours::~ActionHideColours() 02872 { 02873 if (ChangeColour != NULL) 02874 delete [] ChangeColour; 02875 } 02876 02877 02878 02879 /******************************************************************************************** 02880 02881 > virtual void ActionHideColours::Slaughter(void) 02882 02883 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02884 Created: 21/11/94 02885 Purpose: ActionHideColours Slaughter method. Cleans up any deleted colours associated 02886 with this action - once slaughtered, deleted colours can not come back 02887 (touch wood!) so are actually deleted from the document rather than just 02888 hidden. 02889 02890 Notes: Only colours which are truly 'deleted' at this point in time are destructed, 02891 because this action both deletes (hides) and undeletes (unhides) colours, so 02892 our 'undo/redo' record may point at colours which are currently alive and 02893 in use. We also have to be careful about this, as there can be 2 undo 02894 records for the same colour (creation and deletion) in the list at once, 02895 and obviously, only one of them should attemp to destruct the colour! 02896 02897 ********************************************************************************************/ 02898 02899 void ActionHideColours::Slaughter(void) 02900 { 02901 // If we have some colour(s) and our last action was to hide them (thus they are 02902 // deleted colours rather than undeleted ones), then we are responsible for 02903 // slaughtering the now-unneeded colours. 02904 // NOTE: Remember that if we are a 'Hide' action, then the colour should currently 02905 // be in an UN-hidden state; thus, we delete ONLY if we are an UN-hide action. 02906 02907 if (ChangeColour != NULL && !HideFlag) 02908 { 02909 INT32 Index = 0; 02910 02911 // Delete each colour in turn from the ParentList ColourList 02912 while (ChangeColour[Index] != NULL) 02913 { 02914 // Remove from the list 02915 ParentList->RemoveItem(ChangeColour[Index]); 02916 02917 // Ensure it has no children pointing at it 02918 ParentList->RemoveLinksToColour(ChangeColour[Index]); 02919 02920 // Delink this colour from its parent, if any 02921 if (ChangeColour[Index]->FindLastLinkedParent() != NULL) 02922 ChangeColour[Index]->SetLinkedParent(NULL, COLOURTYPE_NORMAL); 02923 02924 // And finally, delete it 02925 delete ChangeColour[Index]; 02926 02927 Index++; 02928 } 02929 } 02930 02931 Action::Slaughter(); // Call the base class Slaughter method to delete ourself 02932 } 02933 02934 02935 /******************************************************************************************** 02936 02937 > virtual ActionCode ActionHideColours::Execute() 02938 02939 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02940 Created: 6/6/94 02941 Inputs: - 02942 Outputs: ActionCode indicating if the action was successfully executed or not 02943 Returns: - 02944 Purpose: Executes the ActionHideColours (to hide/unhide an IndexedColour), creating 02945 an equal and opposite action to undo it with later. 02946 02947 ********************************************************************************************/ 02948 02949 ActionCode ActionHideColours::Execute() 02950 { 02951 ActionHideColours HideColAct; 02952 ActionCode ActCode; 02953 02954 // Create an action to restore the changes we are about to make 02955 if ((ActCode = ActionHideColours::Init(pOperation, 02956 pOppositeActLst, 02957 sizeof(ActionHideColours), 02958 ParentList, ChangeColour, 02959 ((HideFlag) ? FALSE : TRUE), 02960 (Action**)(&HideColAct))) != AC_FAIL) 02961 { 02962 INT32 Index = 0; 02963 02964 while (ChangeColour[Index] != NULL) // Write all the 'deleted' flags 02965 { 02966 // Check that the caller only gave us named colours 02967 ERROR3IF(!ChangeColour[Index]->IsNamed(), 02968 "You don't need to call (Un)HideColours for Local colours! Remove ASAP!"); 02969 02970 ChangeColour[Index]->SetDeleted(HideFlag); 02971 Index++; 02972 } 02973 } 02974 02975 return (ActCode); 02976 } 02977 02978 02979 02980 /******************************************************************************************** 02981 02982 > static ActionCode ActionHideColours::Init(Operation* const pOp, 02983 ActionList* pActionList, 02984 UINT32 ActionSize, 02985 ColourList *TheParentList, 02986 IndexedColour* Colour[], 02987 BOOL HideThem, 02988 Action** NewAction); 02989 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02990 Created: 6/6/94 02991 02992 Inputs: pOp: The operation to which the action should be added 02993 pActionList: The action list in the operation object 02994 ActionSize: The size of the action in bytes. This should be the total 02995 size of the action (including any objects pointed to by the 02996 action). 02997 TheParentList: Points to the list containing the IndexedColours in Colour[] 02998 Colour[]: A NULL terminated list array of pointers to the IndexedColours 02999 which are to be hidden/unhidden 03000 HideThem: TRUE to Hide, FALSE to unhide the colours. 03001 03002 Outputs: NewAction: A pointer to the action if it could be allocated. 03003 03004 Returns: AC_FAIL: There was not enough room in the operation history for the 03005 action and the user did not wish to continue. Usually 03006 End() should be called in this situation. 03007 03008 AC_NORECORD: There was not enough room in the operation history for 03009 the action, but the user requested that he wished to 03010 continue without undo. 03011 03012 AC_OK : The action was successfully initialised and added to the 03013 operation. 03014 03015 03016 Purpose: To check that there is sufficient room for the action in the operation 03017 history, and if there is, then to add the action to the operations 03018 action list. 03019 03020 The function calls the Action::Init function passing the runtime class 03021 of an ActionHideColours. 03022 Errors: - 03023 SeeAlso: Action::Init 03024 03025 ********************************************************************************************/ 03026 03027 ActionCode ActionHideColours::Init(Operation* const pOp, 03028 ActionList* pActionList, 03029 UINT32 ActionSize, 03030 ColourList *TheParentList, 03031 IndexedColour* Colour[], 03032 BOOL HideThem, 03033 Action** NewAction) 03034 { 03035 ActionCode Ac = (Action::Init(pOp, 03036 pActionList, 03037 ActionSize, 03038 CC_RUNTIME_CLASS(ActionHideColours), 03039 NewAction)); 03040 if (*NewAction != NULL) 03041 { 03042 INT32 Count = 0; 03043 03044 while (Colour[Count] != NULL) // Count array size 03045 Count++; 03046 03047 ActionHideColours *AHC = (ActionHideColours*) (*NewAction); 03048 03049 ALLOC_WITH_FAIL(AHC->ChangeColour, new IndexedColourPtr[Count+1], pOp); 03050 03051 if (AHC->ChangeColour == NULL) // Failed in Action Alloc 03052 { 03053 delete AHC; // Delete the action 03054 *NewAction = NULL; // Ensure return NULL 03055 return(AC_FAIL); // And return 'failed' 03056 } 03057 03058 Count = 0; 03059 while (Colour[Count] != NULL) // Copy Colour array 03060 { 03061 AHC->ChangeColour[Count] = Colour[Count]; 03062 Count++; 03063 } 03064 AHC->ChangeColour[Count] = NULL; // And NULL terminate 03065 03066 AHC->ParentList = TheParentList; // Copy the parentlist pointer 03067 AHC->HideFlag = HideThem; // Copy HideFlag 03068 } 03069 03070 return (Ac); 03071 } 03072 03073 03074 03075 03076 03077 03078 03079 03080 03081 03082 03083 03084 03085 03086 03087 03088 03089 03090 03091 03092 03093 03094 03095 03096 03097 /******************************************************************************************** 03098 03099 > OpColourChange::OpColourChange() 03100 03101 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03102 Created: 6/6/94 03103 Inputs: - 03104 Outputs: - 03105 Returns: - 03106 Purpose: OpColourChange constructor (Creates an undoable operation) 03107 Errors: - 03108 SeeAlso: - 03109 03110 ********************************************************************************************/ 03111 03112 OpColourChange::OpColourChange() : UndoableOperation() 03113 { 03114 UndoRecord = NULL; 03115 RedoRecord = NULL; 03116 } 03117 03118 03119 03120 /******************************************************************************************** 03121 03122 > OpColourChange::~OpColourChange() 03123 03124 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03125 Created: 15/6/94 03126 Inputs: - 03127 Outputs: - 03128 Returns: - 03129 Purpose: OpColourChange destructor 03130 Errors: - 03131 SeeAlso: - 03132 03133 ********************************************************************************************/ 03134 03135 OpColourChange::~OpColourChange() 03136 { 03137 // We 'own' the UNDO record, so we are responsible for deleting it 03138 if (UndoRecord != NULL) 03139 delete UndoRecord; 03140 03141 // We do not own the RedoRecord, so we leave it alone 03142 } 03143 03144 03145 03146 /******************************************************************************************** 03147 03148 > BOOL OpColourChange::Init() 03149 03150 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03151 Created: 6/6/94 03152 Inputs: - 03153 Outputs: - 03154 Returns: TRUE if the operation could be successfully initialised 03155 FALSE if no more memory could be allocated 03156 03157 Purpose: OpColourChange initialiser method 03158 03159 ********************************************************************************************/ 03160 03161 BOOL OpColourChange::Init() 03162 { 03163 return (RegisterOpDescriptor( 03164 0, 03165 _R(IDS_COLOURCHANGEOP), 03166 CC_RUNTIME_CLASS(OpColourChange), 03167 OPTOKEN_COLOURCHANGE, 03168 OpColourChange::GetState, 03169 0, /* help ID */ 03170 0, /* Bubble help ID */ 03171 0 /* bitmap ID */ 03172 )); 03173 } 03174 03175 03176 03177 /******************************************************************************************** 03178 03179 > OpState OpColourChange::GetState(String_256*, OpDescriptor*) 03180 03181 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03182 Created: 6/6/94 03183 Inputs: - 03184 Outputs: - 03185 Returns: The state of the OpColourChange operation 03186 Purpose: For finding the OpColourChange's state. 03187 03188 ********************************************************************************************/ 03189 03190 OpState OpColourChange::GetState(String_256* UIDescription, OpDescriptor*) 03191 { 03192 OpState OpSt; 03193 return(OpSt); 03194 } 03195 03196 03197 03198 /******************************************************************************************** 03199 03200 > void OpColourChange::Do(OpDescriptor*) 03201 03202 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03203 Created: 6/6/94 03204 Inputs: OpDescriptor (unused) 03205 Outputs: - 03206 Returns: - 03207 Purpose: (Performs the colour change operation) 03208 OpColourChange has a special overloaded Do operator which takes 03209 parameters describing what is to be done - that version of Do must 03210 be used 03211 Errors: Always generates an ENSURE failure because this Do doesn't. 03212 SeeAlso: - 03213 03214 ********************************************************************************************/ 03215 03216 void OpColourChange::Do(OpDescriptor *NotUsed) 03217 { 03218 ENSURE(FALSE, "OpColourChange does not provide a Do() function - Use DoWithParam"); 03219 End(); 03220 } 03221 03222 03223 03224 /******************************************************************************************** 03225 03226 > void OpColourChange::DoWithParam(OpDescriptor *pOp, OpParam *Param) 03227 03228 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03229 Created: 6/6/94 03230 Inputs: pOp - OpDescriptor as for all Do() functions 03231 Param - points to a ColourChangeInfo structure with parameters: 03232 ParentList - The List in which the colours reside 03233 Target - The colour to be changed 03234 NewDefn - The new definition for Target 03235 InvisibleChange - TRUE if the change is not to a visible feature of the 03236 colour (so objects drawn in this colour need not be redrawn) 03237 Outputs: - 03238 Returns: - 03239 Purpose: Performs the colour change operation, which swaps (with undo) 03240 the data members two given colours. 03241 03242 Note: Both colours are used to provide the primary- and undo-storage, 03243 so you must NOT delete either of them after invoking this op. 03244 They will be deleted as part of the undo record if necessary. 03245 03246 DO NOT call this directly - use ColourManager::ChangeColour 03247 03248 Note that sequential colour changes for the same colour will be merged 03249 into a single undo step. 03250 03251 SeeAlso: ColourManager::ChangeColour 03252 03253 ********************************************************************************************/ 03254 03255 void OpColourChange::DoWithParam(OpDescriptor *pOp, OpParam *Param) 03256 { 03257 ColourChangeInfo *Info = (ColourChangeInfo *) Param; 03258 03259 // Remember the undo record so we don't get memory leakage 03260 UndoRecord = Info->NewDefn; // We 'own' the undo record and must delete it 03261 RedoRecord = Info->Target; // We do NOT own the target: For OpMerging info only 03262 03263 ERROR3IF(UndoRecord == NULL || RedoRecord == NULL || Info->ParentList == NULL, 03264 "Illegal NULL OpParams for OpColourChange"); 03265 03266 // Set our scope variables 03267 pOurDoc = (Document *)Info->ParentList->GetParentDocument(); 03268 pOurView = NULL; 03269 if (!pOurDoc->IsKindOf(CC_RUNTIME_CLASS(Document))) 03270 { 03271 pOurDoc = NULL; // Arrrgh! It must be a basedoc or something! 03272 End(); 03273 return; 03274 } 03275 03276 03277 // Create an action to Undo the hiding operation 03278 ActionColourChange *ACC; 03279 if (ActionColourChange::Init(this, &UndoActions, sizeof(ActionColourChange), 03280 RedoRecord, UndoRecord, Info->InvisibleChange, 03281 (Action**)(&ACC)) == AC_OK) 03282 { 03283 // Apply the initial 'Do' operation - swap the colours 03284 RedoRecord->SwapWith(UndoRecord); 03285 03286 // We have made the change, so broadcast that the list for this doc has changed 03287 if (Info->InvisibleChange) 03288 ColourManager::ColourHasChangedInvisible(GetWorkingDoc(), Info->ParentList, RedoRecord); 03289 else 03290 ColourManager::ColourHasChanged(GetWorkingDoc(), Info->ParentList, RedoRecord); 03291 } 03292 03293 End(); 03294 } 03295 03296 03297 03298 /******************************************************************************************** 03299 03300 > void OpColourChange::Undo() 03301 03302 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03303 Created: 6/6/94 03304 Inputs: - 03305 Outputs: - 03306 Returns: - 03307 Purpose: Undoes whatever Do() or Redo() did 03308 03309 ********************************************************************************************/ 03310 03311 BOOL OpColourChange::Undo() 03312 { 03313 return (Operation::Undo()); 03314 } 03315 03316 03317 03318 /******************************************************************************************** 03319 03320 > void OpColourChange::Redo() 03321 03322 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03323 Created: 6/6/94 03324 Inputs: - 03325 Outputs: - 03326 Returns: - 03327 Purpose: Redoes whatever Undo() undid 03328 03329 ********************************************************************************************/ 03330 03331 BOOL OpColourChange::Redo() 03332 { 03333 return (Operation::Redo()); 03334 } 03335 03336 03337 03338 /******************************************************************************************** 03339 03340 > virtual void OpColourChange::PerformMergeProcessing(void) 03341 03342 03343 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03344 Created: 14/11/94 03345 Inputs: - 03346 Outputs: - 03347 Returns: - 03348 Purpose: This virtual function gets called to allow for the merging of 03349 ColourChange operations - this allows a multitude of sequential 03350 colour edits to be merged into a single undo stage. 03351 Errors: - 03352 SeeAlso: - 03353 03354 ********************************************************************************************/ 03355 03356 void OpColourChange::PerformMergeProcessing(void) 03357 { 03358 // Obtain a pointer to the operation history for the operation's document 03359 OperationHistory* pOpHist = &GetWorkingDoc()->GetOpHistory(); 03360 ERROR3IF(pOpHist == NULL, "There's no OpHistory!?"); 03361 03362 // Ensure that we are the last operation added to the operation history 03363 // Note cannot be an ERROR2 cos this function cannot fail. 03364 ERROR3IF(pOpHist->FindLastOp() != this, "Last Op should be this op"); 03365 03366 // OK lets see if the operation performed before this was an OpNudge operation 03367 Operation* pPrevOp = pOpHist->FindPrevToLastOp(); 03368 03369 if (pPrevOp != NULL) // Check if there was a previous op 03370 { 03371 if (IS_A(pPrevOp, OpColourChange)) 03372 { 03373 if (((OpColourChange *)pPrevOp)->RedoRecord == RedoRecord) 03374 { 03375 // This op is a colour change for the same colour as the last op. 03376 03377 // We may need to change the 'IsVisible' flag for the ActionColourChange 03378 // (if either change is 'visible', the overall change must be 'visible') 03379 03380 ActionColourChange* pNewAction = (ActionColourChange *) 03381 GetUndoActionList()->FindActionOfClass(CC_RUNTIME_CLASS(ActionColourChange)); 03382 03383 ERROR3IF(pNewAction == NULL, "This op should have an ActionColourChange"); 03384 03385 // If the new action is visible, force the old one to be visible 03386 if (pNewAction != NULL && !pNewAction->IsInvisible) 03387 { 03388 ActionColourChange* pOldAction = (ActionColourChange *) 03389 ((OpColourChange *)pPrevOp)->GetUndoActionList()-> 03390 FindActionOfClass(CC_RUNTIME_CLASS(ActionColourChange)); 03391 03392 ERROR3IF(pOldAction == NULL, "This op should have an ActionColourChange"); 03393 03394 if (pOldAction != NULL) 03395 pOldAction->IsInvisible = FALSE; 03396 } 03397 03398 // We have already overwritten the changed colour, so we just kill 03399 // ourselves to remove the unneeded undo step (so undo will revert 03400 // directly to the original state of the colour) 03401 pOpHist->DeleteLastOp(); 03402 } 03403 } 03404 } 03405 } 03406 03407 03408 03409 03410 03411 03412 03413 03414 03415 03416 03417 03418 03419 03420 03421 03422 03423 03424 03425 03426 03427 03428 03429 03430 03431 03432 03433 03434 /******************************************************************************************** 03435 03436 > ActionColourChange::ActionColourChange() 03437 03438 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03439 Created: 6/6/94 03440 Purpose: ActionColourChange constructor 03441 03442 ********************************************************************************************/ 03443 03444 ActionColourChange::ActionColourChange() 03445 { 03446 } 03447 03448 03449 03450 /******************************************************************************************** 03451 03452 > ActionColourChange::~ActionColourChange() 03453 03454 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03455 Created: 6/6/94 03456 Purpose: ActionColourChange destructor 03457 03458 ********************************************************************************************/ 03459 03460 ActionColourChange::~ActionColourChange() 03461 { 03462 } 03463 03464 03465 03466 /******************************************************************************************** 03467 03468 > virtual ActionCode ActionColourChange::Execute() 03469 03470 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03471 Created: 6/6/94 03472 Inputs: - 03473 Outputs: ActionCode indicating if the action was successfully executed or not 03474 Returns: - 03475 Purpose: Executes the ActionColourChange to swap the two IndexedColours over 03476 and generates another ActionColourChange to undo this change. 03477 03478 ********************************************************************************************/ 03479 03480 ActionCode ActionColourChange::Execute() 03481 { 03482 ActionColourChange ColChangeAct; 03483 ActionCode ActCode; 03484 03485 // Create an action to restore the changes we are about to make 03486 if ((ActCode = ActionColourChange::Init(pOperation, 03487 pOppositeActLst, 03488 sizeof(ActionColourChange), 03489 Target, NewDefn, IsInvisible, 03490 (Action**)(&ColChangeAct))) != AC_FAIL) 03491 { 03492 // Swap the colour and its undo partner over 03493 Target->SwapWith(NewDefn); 03494 03495 // Broadcast the change 03496 Document *ScopeDoc = GetWorkingDoc(); 03497 ColourList *ColList = ScopeDoc->GetIndexedColours(); 03498 if (IsInvisible) 03499 ColourManager::ColourHasChangedInvisible(ScopeDoc, ColList, Target); 03500 else 03501 ColourManager::ColourHasChanged(ScopeDoc, ColList, Target); 03502 } 03503 03504 return (ActCode); 03505 } 03506 03507 03508 03509 /******************************************************************************************** 03510 03511 > ActionCode ActionColourChange::Init(Operation* const pOp, 03512 ActionList* pActionList, 03513 UINT32 ActionSize, 03514 IndexedColour *TheTarget, 03515 IndexedColour *TheNewDefn, 03516 BOOL ChangeIsInvisible, 03517 Action** NewAction) 03518 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03519 Created: 14/6/94 03520 03521 Inputs: pOp: The operation to which the action should be added 03522 pActionList: The action list in the operation object 03523 ActionSize: The size of the action in bytes. This should be the total 03524 size of the action (including any objects pointed to by the 03525 action). 03526 TheTarget: The target colour which will be changed when we are executed 03527 TheNewDefn: The definition which will be used to change TheTarget 03528 (These 2 colours will be swapped in actual operation) 03529 03530 ChangeIsInvisible: 03531 TRUE if this change to the colour is not 'visible' (i.e. objects 03532 drawn in this colour will not visibly chnage - the chnage was 03533 only to a flag or the name, etc.). See ColourManager:: 03534 ColourHasChanged and ColourHasChangedInvisible 03535 03536 Outputs: NewAction: A pointer to the action if it could be allocated. 03537 03538 Returns: AC_FAIL: There was not enough room in the operation history for the 03539 action and the user did not wish to continue. Usually 03540 End() should be called in this situation. 03541 03542 AC_NORECORD: There was not enough room in the operation history for 03543 the action, but the user requested that he wished to 03544 continue without undo. 03545 03546 AC_OK : The action was successfully initialised and added to the 03547 operation. 03548 03549 03550 Purpose: To check that there is sufficient room for the action in the operation 03551 history, and if there is, then to add the action to the operations 03552 action list. 03553 03554 The function calls the Action::Init function passing the runtime class 03555 of an ActionColourChange. 03556 Errors: - 03557 SeeAlso: Action::Init; ColourManager::ColourHasChanged; 03558 ColourManager::ColourHasChangedInvisible; OpColourChange::DoWithParam 03559 03560 ********************************************************************************************/ 03561 03562 ActionCode ActionColourChange::Init(Operation* const pOp, 03563 ActionList* pActionList, 03564 UINT32 ActionSize, 03565 IndexedColour *TheTarget, 03566 IndexedColour *TheNewDefn, 03567 BOOL ChangeIsInvisible, 03568 Action** NewAction) 03569 { 03570 03571 03572 ActionCode Ac = (Action::Init(pOp, 03573 pActionList, 03574 ActionSize, 03575 CC_RUNTIME_CLASS(ActionColourChange), 03576 NewAction)); 03577 if (*NewAction != NULL) 03578 { 03579 ActionColourChange *ACC = (ActionColourChange*) (*NewAction); 03580 ACC->Target = TheTarget; 03581 ACC->NewDefn = TheNewDefn; 03582 ACC->IsInvisible = ChangeIsInvisible; 03583 } 03584 03585 return (Ac); 03586 } 03587 03588 03589 03590 03591 03592 03593 03594 03595 03596 03597 /******************************************************************************************** 03598 03599 > OpRedrawColours::OpRedrawColours() 03600 03601 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03602 Created: 24/1/96 03603 03604 Purpose: OpRedrawColours constructor 03605 03606 ********************************************************************************************/ 03607 03608 OpRedrawColours::OpRedrawColours() 03609 { 03610 } 03611 03612 03613 03614 /******************************************************************************************** 03615 03616 > OpRedrawColours::~OpRedrawColours() 03617 03618 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03619 Created: 24/1/96 03620 03621 Purpose: OpRedrawColours destructor 03622 03623 ********************************************************************************************/ 03624 03625 OpRedrawColours::~OpRedrawColours() 03626 { 03627 } 03628 03629 03630 03631 /******************************************************************************************** 03632 03633 > BOOL OpRedrawColours::Init() 03634 03635 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03636 Created: 24/1/96 03637 03638 Returns: TRUE if the operation could be successfully initialised 03639 FALSE if no more memory could be allocated 03640 03641 Purpose: OpRedrawColours initialiser method 03642 03643 ********************************************************************************************/ 03644 03645 BOOL OpRedrawColours::Init() 03646 { 03647 return (RegisterOpDescriptor( 03648 0, 03649 _R(IDS_OPREDRAWCOLOURS), 03650 CC_RUNTIME_CLASS(OpRedrawColours), 03651 OPTOKEN_REDRAWCOLOURS, 03652 OpRedrawColours::GetState, 03653 0, /* help ID */ 03654 0, /* Bubble help ID */ 03655 0 /* bitmap ID */ 03656 )); 03657 } 03658 03659 03660 03661 /******************************************************************************************** 03662 03663 > OpState OpRedrawColours::GetState(String_256*, OpDescriptor*) 03664 03665 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03666 Created: 24/1/96 03667 03668 Returns: The state of the OpRedrawColours operation 03669 Purpose: For finding the OpRedrawColours's state. 03670 03671 ********************************************************************************************/ 03672 03673 OpState OpRedrawColours::GetState(String_256* UIDescription, OpDescriptor*) 03674 { 03675 OpState OpSt; 03676 return(OpSt); 03677 } 03678 03679 03680 03681 /******************************************************************************************** 03682 03683 > void OpRedrawColours::Do(OpDescriptor*) 03684 03685 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03686 Created: 24/1/96 03687 03688 Purpose: Generates an ERROR3 and exits - you must ALWAYS use DoWithParam 03689 03690 ********************************************************************************************/ 03691 03692 void OpRedrawColours::Do(OpDescriptor *NotUsed) 03693 { 03694 ERROR3("OpRedrawColours does not provide a Do() function - Use DoWithParam"); 03695 End(); 03696 } 03697 03698 03699 03700 /******************************************************************************************** 03701 03702 > void OpRedrawColours::DoWithParam(OpDescriptor *pOp, OpParam *Param) 03703 03704 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03705 Created: 24/1/96 03706 03707 Inputs: pOp - OpDescriptor as for all Do() functions 03708 Param - points to a OpRedrawColoursInfo containing: 03709 ScopeDoc - pointer to the scope document 03710 Colours - pointer to a null-terminated array of IndexedColour pointers 03711 03712 Purpose: Scans the document tree, and redraws all nodes affected by visible 03713 changes to any of the colours in the provided null-terminated array. 03714 03715 Scope: Private - for use only by the ColourManager 03716 03717 SeeAlso: ColourManager::ForceRedrawOfChangedColours 03718 03719 ********************************************************************************************/ 03720 03721 void OpRedrawColours::DoWithParam(OpDescriptor *pOp, OpParam *Param) 03722 { 03723 ERROR3IF(Param == NULL, "Illegal NULL param"); 03724 ERROR3IF(pOurDoc == NULL, "pOurDoc is NULL"); 03725 03726 ObjChangeFlags ChangeFlags; 03727 ChangeFlags.Attribute = TRUE; 03728 03729 ObjChangeParam ChangeParam(OBJCHANGE_STARTING, ChangeFlags, NULL, NULL); 03730 03731 OpRedrawColoursInfo *Info = (OpRedrawColoursInfo *) Param; 03732 IndexedColour **Colours = Info->Colours; 03733 ERROR3IF(Colours == NULL, "Illegal NULL param"); 03734 03735 if (Info->ScopeDoc != NULL) 03736 pOurDoc = Info->ScopeDoc; 03737 03738 Node *CurNode = Node::DocFindFirstDepthFirst(pOurDoc); 03739 while (CurNode != NULL) 03740 { 03741 if (CurNode->IsAnAttribute()) 03742 { 03743 // Have found a NodeAttribute. Scan it to see if it contains any colours. 03744 // If any of these match any in our Colours list, then force a redraw of 03745 // our parent node, and return. 03746 NodeAttribute *pNodeAttr = (NodeAttribute *) CurNode; 03747 DocColour *pColour = NULL; 03748 UINT32 Context = 0; 03749 03750 // CGS .... 03751 03752 // DMc's multi stage fills do not dynamically update when we use the colour 03753 // editor (including my custom colour picker control). This has now been 03754 // fixed (by me!). Problem was to do with the fact that the following line 03755 // pColour = pNodeAttr->EnumerateColourFields(Context++); 03756 // never ever got a chance to look for a fill ramp. 03757 03758 BOOL DoneFillRampFirst = FALSE; // by default, we are NOT doing fillramp stuff 03759 BOOL FirstPass = TRUE; // were on our first pass 03760 03761 do 03762 { 03763 // do fill ramp stuff first, before anything else .... 03764 // (dosn't matter if we the node does not have a fill ramp, since 03765 // DoneFillRampFirst will NOT be held high (so processing will proceed as 03766 // normal) 03767 03768 // NOTE: I could have modifed EnumerateColourFields so that it worked properly 03769 // (thereby doing the fill ramp stuff correctly) instead of the following code 03770 // BUT when doing so, this seemed to have undesired affects, so for now; it is 03771 // done this way .... 03772 03773 if ((CurNode->IsAFillAttr ()) && (DoneFillRampFirst == FALSE)) 03774 { 03775 AttrFillGeometry* pAttrFillGeo = (AttrFillGeometry*) (CurNode); 03776 03777 if (pAttrFillGeo->IsAColourFill () && !(pAttrFillGeo->IsATranspFill ())) 03778 { 03779 FillRamp* pFillRamp = pAttrFillGeo->GetFillRamp (); 03780 03781 if (pFillRamp != NULL) 03782 { 03783 UINT32 NumberSelected = pFillRamp->CountSelBlobs (); 03784 03785 if (NumberSelected > 0) 03786 { 03787 INT32 SelectedIndex = pFillRamp->GetSelectedIndex (); 03788 ColRampItem* TheItem = (ColRampItem*) pFillRamp->GetValidIndexedItem (SelectedIndex); 03789 03790 if (TheItem != NULL) 03791 { 03792 DoneFillRampFirst = TRUE; 03793 pColour = TheItem->GetColourAddr (); 03794 } 03795 } 03796 } 03797 } 03798 } 03799 03800 // Get the next colour field from the attribute, and find the 03801 // IndexedColour (if any) to which it refers 03802 if (DoneFillRampFirst != TRUE) 03803 { 03804 pColour = pNodeAttr->EnumerateColourFields(Context++); 03805 } 03806 else 03807 { 03808 // need to reset stuff, cause otherwise pColour is always != NULL, 03809 // and we get into an infinite while loop !!!! 03810 03811 if (FirstPass == TRUE) 03812 { 03813 FirstPass = FALSE; // for next pass .... 03814 } 03815 else 03816 { 03817 pColour = NULL; // reset !!!! 03818 } 03819 } 03820 03821 IndexedColour *pColourIx = (pColour == NULL) ? NULL : pColour->FindParentIndexedColour(); 03822 if (pColourIx != NULL) 03823 { 03824 // Check if this colour matches any in our list 03825 INT32 i = 0; 03826 while (Colours[i] != NULL) 03827 { 03828 if (pColourIx == Colours[i]) 03829 { 03830 Node *Parent = CurNode->FindParent(); 03831 if (Parent != NULL && Parent->IsBounded()) 03832 { 03833 // Invoke AllowOp on the node to tag it so that parents such as blends 03834 // and moulds will also redraw if necessary. We ignore the return code 03835 // because we're not actually going to touch the node at all. 03836 CurNode->AllowOp(&ChangeParam); 03837 03838 // And redraw the directly affected node (our parent) 03839 DocRect NodeBounds = ((NodeRenderableBounded *)Parent)->GetBoundingRect(); 03840 NodeBounds = NodeBounds.Union(((NodeRenderableBounded *)Parent)->GetEffectStackBounds()); 03841 pOurDoc->ForceRedraw(Parent->FindParentSpread(), NodeBounds, FALSE, Parent); 03842 } 03843 03844 // There is no need to check further colour attributes for this node 03845 // now that we have found one that has changed 03846 break; 03847 } 03848 03849 i++; // Check the next IndexedColour 03850 } 03851 } 03852 } while ((pColour != NULL /*&& DoneFillRampFirst == FALSE*/)); // Check the next colour attribute 03853 } 03854 03855 CurNode = CurNode->DocFindNextDepthFirst(); 03856 } 03857 03858 // And make sure that the redraw occurs right away 03859 pOurDoc->FlushRedraw(); 03860 GetApplication()->ServiceRendering(); // Ensure speedy response by doing one iteration of rendering right now 03861 03862 ChangeParam.Define(OBJCHANGE_FINISHED, ChangeParam.GetChangeFlags(), NULL, NULL); 03863 UpdateAllChangedNodes(&ChangeParam); 03864 03865 End(); 03866 } 03867 03868 03869 #endif // EXCLUDE_FROM_RALPH