colormgr.cpp

Go to the documentation of this file.
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

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