ColourManager Class Reference

This class provides miscellaneous shared functions for use by various colour entities. The provided functions are currently:. More...

#include <colormgr.h>

Inheritance diagram for ColourManager:

MessageHandler ListItem CCObject SimpleCCObject List of all members.

Public Member Functions

 ColourManager ()
 Constructs a ColourManager object.

Static Public Member Functions

static BOOL Init (void)
 Initialises the entire colour system. This includes the colour manager, colour contexts, and colour dialogues, etc. Notes: Should only be called once ever. Called by Application::Init().
static void Deinit (void)
 De-Initlialises the entire colour system. This includes the colour manager, colour contexts, and colour dialogues, etc. Notes: Should only be called once ever. Called by Application::Deinit().
static ColourListGetColourList (BOOL InvalidateCache=FALSE)
 To obtain the ColourList of IndexedColours in the SelectedDocument (the colours which the user can use within the document; this is the set of colours displayed by the colour bar and edited by the ColourMgrDlg) Note that an ordered list is used so that multiple display orders can be used (e.g. for the ColourMgrDlg and ColourBar, etc).
static ColourListGetCurrentColourList (void)
 To obtain the ColourList of IndexedColours in the CurrentDocument.
static ColourContextGetColourContext (ColourModel Model, Document *ScopeDocument=NULL)
 To easily find an appropriate colour context to use when converting colours. There are global contexts, but in order to supply special document-specific colour corrections etc, each document actually has its own private set of contexts. Thus, you should call this function to determine the most appropriate context to use.
static ColourContextGetColourContext (ColourModel Model, View *ScopeView)
 To easily find an appropriate colour context to use when converting colours. There are global contexts, but in order to supply special view-specific colour corrections etc, each document view actually has its own private set of contexts. Thus, you should call this function to determine the most appropriate context to use.
static void SelViewContextHasChanged (void)
 To redraw all windows which depend upon the Selected View's colour context. i.e. The selected view, and also the colour editor, gallery, & line. (and maybe other windows in the future, e.g. object properties, grad fill editors, etc).
static void ColourHasChanged (Document *ScopeDoc, ColourList *ColList, IndexedColour *Col)
 Indicates to all interested parties that the given IndexedColour has been changed (sends a COLOURUPDATED message) e.g. Causes the ColourBar and document to redraw themselves.
static void ColourHasChangedInvisible (Document *ScopeDoc, ColourList *ColList, IndexedColour *Col)
 Indicates to all interested parties that the given IndexedColour has been changed (sends a COLOURUPDATEDINVISIBLE message) e.g. Causes the ColourBar to redraw itself.
static void ColourListHasChanged (ColourList *ColList)
 To inform all interested parties that the given list of IndexedColours has changed by item(s) being added, deleted, or moved to a new position. e.g This causes the ColourBar and ColourMgrDlg to update their displays to reflect the new state of the list, if the list is the one which they are currently displaying.
static BOOL HideColours (ColourList *ColList, IndexedColour **ColourArray, BOOL ForceDelete)
 This 'deletes' colours by creating an undoable operation to hide them. It is assumed that the colours are not in use by the time you call this function - An ENSURE failure will occur if any are. After invoking the 'hide' operation, this function calls ColourListHasChanged.
static BOOL UnHideColours (ColourList *ColList, IndexedColour **ColourArray)
 This un-'deletes' colours by creating an undoable operation to unhide them. This is used when creating a new colour to 'unhide' it (which has no immediate effect on the colour) - this creates an undo record that will hide the colour if the 'new' is undone.
static BOOL ChangeColour (ColourList *ColList, IndexedColour *NewDefn, IndexedColour *Target, BOOL ChangeisInvisible=FALSE)
 This changes the colour 'Target' to be the same as 'NewDefn'. To achieve undo of this operation, the data members of the two colours are swapped (as the colour being changed must stay at the same memory location), and the NewDefn is used again as the undo record of this colour. Whenever the colour is changed, including during the execution of this funciton, and also by undo/redo, a ColourChangingMsg will be broadcast (either COLOURUPDATED or COLOURUPDATEDINVISIBLE, depending on the state of the ChangeIsInvisible flag).
static void ForceRedrawOfChangedColours (Document *ScopeDoc, IndexedColour **Colours)
 Scans the document tree of the given scope document, and causes a redraw of all objects which are affected by any attributes which contain references to any of the colours in the given NULL-terminated list of colours. If none of the colours are in use in the document tree, nothing should result. (i.e. it force redraws any areas of the document containing any of the given colours).
static IndexedColourGenerateNewNamedColour (ColourList *ParentList, IndexedColour *SourceColour)
 Creates a new named IndexedColour. If possible, this colour is copied from the given SourceColour, but if this is not available, an attempt to find a useful colour to copy will be made - if this fails, a battleship grey will be created. i.e. apart from abject failure, this always creates a new colour.
static IndexedColourGenerateNewUnnamedColour (ColourList *ParentList, DocColour *SourceColour)
 Creates a new named IndexedColour. If possible, this colour is copied from the given SourceColour, but if this is not available, an attempt to find a useful colour to copy will be made - if this fails, a battleship grey will be created. i.e. apart from abject failure, this always creates a new colour.
static void EnsureColourIsInDocument (Document *SourceDoc, Document *DestDoc, DocColour *SourceAndResultCol)
 Ensures that the given DocColour references a "safe" colour to use within the given document. This may mean doing nothing to the colour, or it may be necessary to copy the colour (and possibly linked parent colour(s) as well!) into the DestDoc. Whatever happens, ResultCol will be filled in with something that you can use with confidence.
static BOOL GetCurrentLineAndFillAttrs (AttrStrokeColour **LineAttr, AttrFillGeometry **FillAttr)
 Determines the current line and fill colour attributes. These are the default ones, or if there is a selection, the attrs which are common to all selected objects. If there are many different attributes of the same type associated with the selection, NULL is returned. Notes: The ColourBar works exclusively on the SELECTED Doc. Change with care This function ensures that Current == Selected during its operation.
static BOOL GetCurrentLineAndFillColours (DocColour **LineCol, DocColour **FillCol, DocColour **EndGradFill=NULL)
 Finds the current line and fill attributes, and dereferences them to find the current line and fill DocColours. These may be returned NULL if there are no current attributes (no document/many colours selected).
static void FindColourOfInterestToUser (IndexedColour **ResultCol, ColourList **ResultList=NULL)
 Several things (Colour editor whenever the selection changes, generation of a new colour) need to know a 'useful' colour to display/copy. Rather than just showing the current default colour or something, they need to interactively update to show an appropriate colour from the selection and suchlike.
static void FindColourOfInterestToUser (DocColour *ResultCol, ColourList **ResultList=NULL, BOOL WantLineColour=FALSE)
 Several things (Colour editor whenever the selection changes, generation of a new colour) need to know a 'useful' colour to display/copy. Rather than just showing the current default colour or something, they need to interactively update to show an appropriate colour from the selection and suchlike.

Protected Member Functions

MsgResult Message (Msg *Msg)
 Process messages sent to the ColourManager Some messages (DocChanging) will cause new broadcasts indicating that the colour system has changed (new colour list has been paged in, etc).

Static Protected Attributes

static ColourListCurrentColourList
static DocumentScopeDocument

Detailed Description

This class provides miscellaneous shared functions for use by various colour entities. The provided functions are currently:.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/5/94
Determine the current colour list

This is the Indexed Colour list for the SelectedDocument (if any). It is displayed by the colour bar, and/or edited by the Colour Manager Dialogue.

Find a suitable global or document-specific colour context to use

Handle colour system state changes

Messages are sent whenever the current list changes. This happens when:

1) A colour is inserted/deleted/edited in the SelectedDocument,

2) The SelectedDocument changes,

3) The Colour List is deselected (i.e. when there is no SelectedDocument, there is no available list)

These messages allow the colour manager dialogues and colour bar (and other clients) to update their contents (or hide, etc) when such changes occur.

Other processing (invalidating colour caches, etc) may also occur in some cases. This is all handled internally by the ColourManager.

Copy or create new colours

Find "Useful" colours for the editor to edit and the colour line/gallery to display.

Miscellaneous other useful functions. See colormgr.h for details of currently available functions

See also:
ColourBar; ColourMgrDlg; ColourChangingMsg; ColourList Documentation: HowToUse.doc

Definition at line 168 of file colormgr.h.


Constructor & Destructor Documentation

ColourManager::ColourManager  ) 
 

Constructs a ColourManager object.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/5/94
See also:
ColourManager; MessageHandler

Definition at line 168 of file colormgr.cpp.


Member Function Documentation

BOOL ColourManager::ChangeColour ColourList ColList,
IndexedColour NewDefn,
IndexedColour Target,
BOOL  ChangeIsInvisible = FALSE
[static]
 

This changes the colour 'Target' to be the same as 'NewDefn'. To achieve undo of this operation, the data members of the two colours are swapped (as the colour being changed must stay at the same memory location), and the NewDefn is used again as the undo record of this colour. Whenever the colour is changed, including during the execution of this funciton, and also by undo/redo, a ColourChangingMsg will be broadcast (either COLOURUPDATED or COLOURUPDATEDINVISIBLE, depending on the state of the ChangeIsInvisible flag).

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/6/94
Parameters:
ColList - The colour list in which the colours reside [INPUTS] NewDefn - The new IndexedColour definition to be applied Target - The colour to which the definition is to be applied ChangeIsInvisible - TRUE if the change does not affect 'visible' parts of the colour definition (i.e. if objects drawn using this colour need not be redrawn). FALSE if the chnage does affect such objects.
- [OUTPUTS]
Returns:
TRUE if it thinks it succeeded
Notes: As the memory occupied by 'NewDefn' is used in the undo record, it is essential that you do NOT DELETE it after invoking this function. You must also make absolutely sure that you do not pass the same pointer in NewDefn more than once, or a crash will occur when Camelot throws away the undo records.

See also:
OpColourChange; ColourChangingMsg

Definition at line 2124 of file colormgr.cpp.

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 }

void ColourManager::ColourHasChanged Document ScopeDoc,
ColourList ColList,
IndexedColour Col
[static]
 

Indicates to all interested parties that the given IndexedColour has been changed (sends a COLOURUPDATED message) e.g. Causes the ColourBar and document to redraw themselves.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/5/94
Parameters:
ScopeDoc - the document in which this change is occurring [INPUTS] ColList - the list of IndexedColours in which 'Col' resides Col - A pointer to the IndexedColour which has been changed
- [OUTPUTS]
Returns:
-
This variant indicates that the actual visible-colour definition has changed (i.e. the appearance of something filled with this colour will chnage, and thus must be redrawn). If 'non-visible' information only has changed, use ColourHasChangedInvisible instead.

Notes: If you are recieving messages, and wish to act on COLOURUPDATEDINVISIBLE, you should sit on BOTH COLOURUPDATED messages. Otherwise, you should only sit on COLOURUPDATED messages.

The ColourManager will force-redraw the parst of the ScopeDoc which rely on the changed colour, or any colour liked to the changed colour.

If ColList == the current colour list then entities such as the colour bar will redraw themselves to show the new state of this colour.

See also:
ColourManager::ColourHasChangedInvisible

Definition at line 1867 of file colormgr.cpp.

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 }

void ColourManager::ColourHasChangedInvisible Document ScopeDoc,
ColourList ColList,
IndexedColour Col
[static]
 

Indicates to all interested parties that the given IndexedColour has been changed (sends a COLOURUPDATEDINVISIBLE message) e.g. Causes the ColourBar to redraw itself.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/5/94
Parameters:
ScopeDoc - NULL, or the document in which this change is occurring [INPUTS] (if non-NULL, the ColourManager will force a redraw of this document) ColList - NULL, or a list of IndexedColours in which 'Col' can be found. Col - A pointer to the IndexedColour which has been changed
- [OUTPUTS]
Returns:
-
This variant indicates that the actual visible-colour definition has NOT changed (i.e. the appearance of something filled with this colour will NOT change, and thus redraw is unnecessary). e.g. the

If 'visible' information has changed, use ColourHasChanged instead.

Notes: If you are recieving messages, and wish to act on COLOURUPDATEDINVISIBLE, you should sit on BOTH COLOURUPDATED messages.

ColList really should point to the list in which the colour resides. If ColList == NULL or ColList == the current colour list, then entities such as the colour bar will redraw themselves to show the new state of this colour.

If ColList is not NULL, then all its sort orders will be marked invalid so that they are re-sorted the next time they are used.

(If an incorrect pointer (or NULL) is passed in, unnecessary redraws of colour bars etc may take place, so it is most preferable that you pass in the correct list pointer if you know it)

See also:
ColourManager::ColourHasChanged

Definition at line 1924 of file colormgr.cpp.

01926 {
01927     ColList->InvalidateInheritanceCache();
01928     BROADCAST_TO_ALL(ColourChangingMsg(ScopeDoc, ColList, Col,
01929                                 ColourChangingMsg::COLOURUPDATEDINVISIBLE));
01930 }

void ColourManager::ColourListHasChanged ColourList ColList  )  [static]
 

To inform all interested parties that the given list of IndexedColours has changed by item(s) being added, deleted, or moved to a new position. e.g This causes the ColourBar and ColourMgrDlg to update their displays to reflect the new state of the list, if the list is the one which they are currently displaying.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/5/94
Parameters:
ColList - A ColourList of IndexedColours which has changed [INPUTS] May NOT be NULL
- [OUTPUTS]
Returns:
-
Notes: Remember to invalidate the sort orders in this sorted list if you have done anything that could affect sorting (Adding items will do this automatically, but you must do it if you've changed a colour) This is not done by this function, as actions such as deleting items never affect the sort order, but do need to cause a re-display

Definition at line 1959 of file colormgr.cpp.

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 }

void ColourManager::Deinit void   )  [static]
 

De-Initlialises the entire colour system. This includes the colour manager, colour contexts, and colour dialogues, etc. Notes: Should only be called once ever. Called by Application::Deinit().

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
1/6/94
See also:
ColourManager; MessageHandler

Definition at line 233 of file colormgr.cpp.

00234 {
00235     // shut down the colour contexts
00236     ColourContextList::DeinitColourContexts();
00237 }

void ColourManager::EnsureColourIsInDocument Document SourceDoc,
Document DestDoc,
DocColour ResultCol
[static]
 

Ensures that the given DocColour references a "safe" colour to use within the given document. This may mean doing nothing to the colour, or it may be necessary to copy the colour (and possibly linked parent colour(s) as well!) into the DestDoc. Whatever happens, ResultCol will be filled in with something that you can use with confidence.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
13/4/95 (Moved to ColourManager, 20/11/95)
Parameters:
SourceDoc - NULL, or the document which contains the source colour [INPUTS]
DestDoc - The document in which you want to use the colour (NOT NULL)

ResultCol - should point at a DocColour defining the colour you want to put in this document. It may be an immediate DocColour, or a reference to an IndexedColour. (this param may NOT be NULL)

Parameters:
ResultCol (which may not be NULL) will be returned with a colour to [OUTPUTS] use. This will either be COLOUR_TRANS, or will point at an IndexedColour in the SELECTED document which you may apply in that document.
Notes: Uses the component copy system to copy colours across with merging.

What do you mean this should be in the colour manager? Have you seen how many files it rebuilds?! Eeek! (OK, so I've moved it now)

See also:
ColourListComponent::StartComponentCopy

Definition at line 1784 of file colormgr.cpp.

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 }

void ColourManager::FindColourOfInterestToUser DocColour ResultCol,
ColourList **  ResultList = NULL,
BOOL  WantLineColour = FALSE
[static]
 

Several things (Colour editor whenever the selection changes, generation of a new colour) need to know a 'useful' colour to display/copy. Rather than just showing the current default colour or something, they need to interactively update to show an appropriate colour from the selection and suchlike.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
6/1/95
Parameters:
- [INPUTS]
ResultCol - will be returned filled in with details of the colour to use [OUTPUTS] ResultList - NULL, or a pointer to the ColourList of the relevant document WantLinecolour - TRUE if you'd rather get a line colour, FALSE if you want a fill colour.
Returns:
-
This is very similar to the other overloaded method, but returns a DocColour. NOTE however, that the returned colour may not match the IndexedColour returned by the other method - a DocColour (which does not reference a NAMED IndexedColour) may be returned before a suitable IndexedColour would have been found.

This is used to determine the colour definition for a colour to use when editing "local colours" in the colour editor.

The exact colour returned will be NULL (in dire emergency, usually only occurs if there are no documents open), or will be chosen from this priority list of possible contenders: MonoOn (1) Colour of first selected fill-blob found (if !WantLineColour), (2) Fill-Colour of selection (if !WantLineColour), (3) current/default fill colour (if !WantLineColour), (4) line-Colour of selection (If WantLineColour), (5) current/default line colour (if WantLineColour), (6) COLOUR_BLACK MonoOff

Notes: 'Colour of selection' is determined by using (if possible) the last object selected, or the frontmost selected object if this fails.

If you are not interested in the ResultList return value, pass in NULL (use the default) for this parameter.

Camelot will not return a 'no fill' default colour (conditions 3 and 6) but Webster does because the Webster colour editor wants to handle this situation.

Definition at line 1202 of file colormgr.cpp.

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 }

void ColourManager::FindColourOfInterestToUser IndexedColour **  ResultCol,
ColourList **  ResultList = NULL
[static]
 

Several things (Colour editor whenever the selection changes, generation of a new colour) need to know a 'useful' colour to display/copy. Rather than just showing the current default colour or something, they need to interactively update to show an appropriate colour from the selection and suchlike.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
6/1/95
Parameters:
- [INPUTS]
ResultCol - NULL, or a pointer to the colour to use [OUTPUTS] ResultList - NULL, or a pointer to the ColourList that colour resides in
Returns:
-
NOTE that there is another overloaded form of this method, which returns a DocColour istead. This method returns a pointer to a NAMED IndexedColour, so may return an entirely different colour to the other function.

The exact colour returned will be NULL (in dire emergency, usually only occurs if there are no documents open), or will be chosen from this priority list of possible contenders: MonoOn (1) Colour of first selected fill-blob found, (2) Fill-Colour of selection, (3) current/default fill colour, (4) line-Colour of selection, (5) current/default line colour, (6) the first active named colour in the document's colour list, (7) NULL MonoOff

Notes: 'Colour of selection' is determined by using (if possible) the last object selected, or the frontmost selected object if this fails.

If you are not interested in the ResultList return value, pass in NULL (use the default) for this parameter.

In debug builds only, extra checks are made which can cause an ERROR3 if the colour found was not in the selected document's ColourList.

Definition at line 932 of file colormgr.cpp.

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 }

void ColourManager::ForceRedrawOfChangedColours Document ScopeDoc,
IndexedColour **  Colours
[static]
 

Scans the document tree of the given scope document, and causes a redraw of all objects which are affected by any attributes which contain references to any of the colours in the given NULL-terminated list of colours. If none of the colours are in use in the document tree, nothing should result. (i.e. it force redraws any areas of the document containing any of the given colours).

See also:
RecursivelyForceRedraw

Definition at line 261 of file colormgr.cpp.

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 }

IndexedColour * ColourManager::GenerateNewNamedColour ColourList ParentList,
IndexedColour SourceColour
[static]
 

Creates a new named IndexedColour. If possible, this colour is copied from the given SourceColour, but if this is not available, an attempt to find a useful colour to copy will be made - if this fails, a battleship grey will be created. i.e. apart from abject failure, this always creates a new colour.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
25/11/94
Parameters:
ParentList - The list in which the SourceColour resides - The resulting [INPUTS] colour will also be placed into this list. May NOT be NULL. SourceColour - NULL (to copy the current attribute FillColour), or a pointer to the colour you wish to duplicate.
(ParentList - will contain the new colour if all went well) [OUTPUTS]
Returns:
NULL if it failed, else A clone of SourceColour. This will be pretty much identical to SourceColour, except that it will always be a NAMED colour.
It generates a new colour, adds it to the ParentList, and generates an UNDO record for the action; this includes a ColourListChanged msg broadcast.

NOTE that the user is prompted for a new name, and has the opportunity to cancel creation of the colour, in which case, NULL will be returned. You must therefore handle a NULL return *quietly*.

Notes: This code is used by the ColourBar and ColourGallery "new colour" code to generate a new named colour.

Returns:
Errors: If the return value is NULL, an unreported memory allocation failure has occurred.
If the ParentList is not the ColourList for the Selected document, and no source colour is given, chances are FindColourOfInterestToUser will get upset and ERROR3.

See also:
IndexedColour::IndexedColour; ColourManager::UnHideColours; ColourManager::FindColourOfInterestToUser

Definition at line 1499 of file colormgr.cpp.

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 }

IndexedColour * ColourManager::GenerateNewUnnamedColour ColourList ParentList,
DocColour BaseSourceColour
[static]
 

Creates a new named IndexedColour. If possible, this colour is copied from the given SourceColour, but if this is not available, an attempt to find a useful colour to copy will be made - if this fails, a battleship grey will be created. i.e. apart from abject failure, this always creates a new colour.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
29/3/95
Parameters:
ParentList - The list in which the resulting colour will be placed. [INPUTS] In debug builds an ENSURE will be triggered if the new colour would be created with a parent-colour in a different colour list. May NOT be NULL.
SourceColour - A pointer to the colour you wish to duplicate. If NULL, some random "useful" colour will be substituted.

Parameters:
(ParentList - will contain the new colour if all w