// $Id: colourix.cpp 1333 2006-06-16 20:34:16Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // colourix.cpp - Indexed colour class /* */ #include "camtypes.h" #include "colcontx.h" #include "colourix.h" #include "colormgr.h" //#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "jason.h" CC_IMPLEMENT_DYNAMIC(IndexedColour, ListItem) // Declare smart memory handling in Debug builds #define new CAM_DEBUG_NEW #ifndef WEBSTER // there are never spot colours in WEBSTER Martin 15/07/97 BOOL IndexedColour::SpotsAreProcess = FALSE; #else BOOL IndexedColour::SpotsAreProcess = TRUE; #endif /******************************************************************************************** > void IndexedColour::InitialiseInfoFields(void) Author: Jason_Williams (Xara Group Ltd) Created: 30/03/94 Inputs: - Outputs: - Returns: - Purpose: Private shared code for construction of IndexedColour objects Initialises the 'Info' structure to default values Scope: private Errors: - SeeAlso: - ********************************************************************************************/ void IndexedColour::InitialiseInfoFields(ColourModel ColModel) { UsageCount = 0; // We are not in-use yet ChildUsage = 0; Name = NULL; // This colour has no name ParentColour = NULL; // We are not linked to another colour by default Info.OCContextHandle = 0; // Set colour model, and remember we're not cached Info.SourceColourModel = ColModel; Info.CacheColourModel = COLOURMODEL_NOTCACHED; Info.InheritComponent1 = // By default, override all components in linked colour Info.InheritComponent2 = Info.InheritComponent3 = Info.InheritComponent4 = FALSE; Info.ColourType = COLOURTYPE_NORMAL; // Is normal (not spot/tint/linked) colour Info.Deleted = FALSE; // Not a deleted (hidden) colour Info.IsNamed = FALSE; } /******************************************************************************************** > IndexedColour::IndexedColour() Author: Jason_Williams (Xara Group Ltd) Created: 30/03/94 Inputs: - Outputs: - Returns: - Purpose: Constructor for an IndexedColour object Initialises the colour to the RGBT value for Opaque Black Errors: - SeeAlso: - ********************************************************************************************/ IndexedColour::IndexedColour() { InitialiseInfoFields(COLOURMODEL_RGBT); SourceColour.Component1 = 0; // Black & No-colour (in RGBT) SourceColour.Component2 = 0; SourceColour.Component3 = 0; SourceColour.Component4 = 1.0; // 100% transparent } /******************************************************************************************** > IndexedColour::~IndexedColour() Author: Jason_Williams (Xara Group Ltd) Created: 30/03/94 Inputs: - Outputs: - Returns: - Purpose: Destructor for an IndexedColour object Errors: - SeeAlso: - ********************************************************************************************/ IndexedColour::~IndexedColour() { ERROR3IF(UsageCount < 0, "IndexedColour UsageCount is negative"); #ifdef _DEBUG if (UsageCount != 0) { if (IsNamed()) TRACE( _T("\n>> Named IndexedColour %p ('%s') is still referenced %ld times\n"), this, (TCHAR *)(*Name), (INT32)UsageCount); else TRACE( _T("\n>> Unnamed IndexedColour %p is still referenced %ld times\n"), this, (INT32)UsageCount); // Now, ask SimpleCCObject to wugg through all current objects to see if we can find something // that could be the pointer back at us! extern void CheckForUsedPointer(void *ThePointer); TRACE( _T(" References to this object were found in:\n")); CheckForUsedPointer(this); TRACE( _T("\n")); } ERROR3IF(UsageCount > 0, "IndexedColour deleted while still in use"); if (ChildUsage != 0) { if (IsNamed()) { TRACEUSER( "Jason", _T("Jason: Named IndexedColour %p ('%s') is still LINKED %ld times\n"), this, (TCHAR *)(*Name), (INT32)ChildUsage); } else { TRACEUSER( "Jason", _T("Jason: Unnamed IndexedColour %p is still LINKED %ld times\n"), this, (INT32)ChildUsage); } } #endif // If we are linked to another colour, we need to de-reference it if (ParentColour != NULL) ParentColour->DecrementChildUsage(); if (Name != NULL) delete Name; } /******************************************************************************************** > IndexedColour::IndexedColour(const IndexedColour& Col) Author: Jason_Williams (Xara Group Ltd) Created: 05/05/94 Inputs: - Outputs: - Returns: - Purpose: Copy constructor for an IndexedColour object Errors: - SeeAlso: - ********************************************************************************************/ IndexedColour::IndexedColour(const IndexedColour& Col) { Info = Col.Info; memcpy(&SourceColour, &Col.SourceColour, sizeof(ColourGeneric)); memcpy(&CachedColour, &Col.CachedColour, sizeof(ColourGeneric)); // If we are copying a linked/tint colour, we make ourselves linked to their parent ParentColour = Col.ParentColour; if (ParentColour != NULL) ParentColour->IncrementChildUsage(); UsageCount = 0; ChildUsage = 0; Info.IsNamed = FALSE; Name = NULL; // Nasty casting to get around this messy const problem. if (((IndexedColour *)&Col)->IsNamed()) SetName(*(Col.Name)); // Copy the string, not the string-pointer } /******************************************************************************************** > IndexedColour::IndexedColour(const DocColour& Col) Author: Jason_Williams (Xara Group Ltd) Created: 9/11/94 Inputs: Col - A DocColour from which to take the definition of this new IndexedCol Outputs: - Returns: - Purpose: Copy constructor for an IndexedColour object. Notes: If the DocColour is immediate (does not reference an IndexedColour) then the indexedcolour uses its colour definition - NOTE that this creates an UNNAMED colour by default (SetName it afterwards). If the DocColour references an IndexedColour, the referenced colour is copied Tints and Linked colours are copied and remain tints/linked (Gosh!) Named/Unnamed colours will be copied as Named/Unnamed colours (Gosh!) The name is copied verbatim (i.e it is not changed to 'Copy of X') Errors: - SeeAlso: IndexedColour::SetName ********************************************************************************************/ IndexedColour::IndexedColour(const DocColour& Col) { // Find the parent IndexedColour, if any. Nasty cast to remove compiler warning IndexedColour *Def = ((DocColour *) &Col)->FindParentIndexedColour(); if (Def != NULL) { // The DocColour references an IndexedColour, so copy the parent IndexedColour Info = Def->Info; memcpy(&SourceColour, &Def->SourceColour, sizeof(ColourGeneric)); memcpy(&CachedColour, &Def->CachedColour, sizeof(ColourGeneric)); // If we are copying a linked/tint colour, we need to link ourselves to its parent ParentColour = Def->ParentColour; if (ParentColour != NULL) ParentColour->IncrementChildUsage(); UsageCount = 0; ChildUsage = 0; Info.IsNamed = FALSE; Name = NULL; if (Def->IsNamed()) SetName(*(Def->Name)); // Copy the string, not the string-pointer } else { // This is an immediate DocColour, so copy its definition into our SourceColour InitialiseInfoFields(Col.GetColourModel()); ((DocColour *) &Col)->GetSourceColour(&SourceColour); } } /******************************************************************************************** > IndexedColour::IndexedColour(ColourValue Red, ColourValue Green, ColourValue Blue, ColourValue Transparent = 0, UINT32 TransType = TRANSTYPE_DEFAULT) Author: Jason_Williams (Xara Group Ltd) Created: 30/03/94 Inputs: Red; Green; Blue - The RGB definition of the colour Transparent - The transparency of the colour - IGNORED! TransType - The transparency type of the colour - IGNORED! Outputs: - Returns: - Purpose: Constructor for an IndexedColour object Initialises the colour to the given Extended RGBT value Notes: Colours no longer support transparency. The transparency fields are ignored. Errors: - SeeAlso: - ********************************************************************************************/ IndexedColour::IndexedColour(ColourValue Red, ColourValue Green, ColourValue Blue, ColourValue Transparent, UINT32 TransType) { InitialiseInfoFields(COLOURMODEL_RGBT); SourceColour.Component1 = Red; SourceColour.Component2 = Green; SourceColour.Component3 = Blue; SourceColour.Component4 = Transparent; } /******************************************************************************************** > IndexedColour::IndexedColour(ColourModel ColModel, ColourGeneric *Col) Author: Jason_Williams (Xara Group Ltd) Created: 30/03/94 Inputs: ColModel - The colour model in which Col is defined Col - The definition, in the given colour model, of the colour Outputs: - Returns: - Purpose: Constructor for an IndexedColour object Initialises the colour to the given value in the given colour model NOTE that if you have a ColourABCD structure, you can pass this in as a single parameter, and inline functions will convert the call into a call to this function on your behalf. i.e. you can use IndexedColour((ColourRGBT *)Bob); -- See colour.h Errors: - SeeAlso: - ********************************************************************************************/ IndexedColour::IndexedColour(ColourModel ColModel, ColourGeneric *Col) { InitialiseInfoFields(ColModel); memcpy(&SourceColour, Col, sizeof(ColourGeneric)); } /******************************************************************************************** > IndexedColour& IndexedColour::operator=(const IndexedColour& Other) Author: Jason_Williams (Xara Group Ltd) Created: 12/10/94 Inputs: Other - colour to copy Outputs: - Returns: Purpose: IndexedColour assignment operator Copies the definition of one IndexedColour into another Notes: The name field is copied verbatim - if you want it to say 'Copy of ...' then you'll have to prepend this text yourself. Errors: ERROR2 if you try to copy a colour over itself ********************************************************************************************/ IndexedColour& IndexedColour::operator=(const IndexedColour& Other) { ERROR2IF(&Other == this, *this, "Attempt to copy an IndexedColour over itself!"); Info = Other.Info; memcpy(&SourceColour, &Other.SourceColour, sizeof(ColourGeneric)); memcpy(&CachedColour, &Other.CachedColour, sizeof(ColourGeneric)); if (ParentColour != NULL) // Delink from old parent (if any) ParentColour->DecrementChildUsage(); ParentColour = Other.ParentColour; if (ParentColour != NULL) // Link to new parent (if any) ParentColour->IncrementChildUsage(); // UsageCount = 0; // These DO NOT CHANGE! We still have people referencing us // ChildUsage = 0; // and we must not forget about them! Info.IsNamed = FALSE; if (((IndexedColour *)&Other)->IsNamed()) SetName(*(Other.Name)); // Copy the string, not the string-pointer return(*this); } /******************************************************************************************** > IndexedColourType IndexedColour::GetType(void) const Author: Jason_Williams (Xara Group Ltd) Created: 13/10/94 Returns: The type of this colour: MonoOn COLOURTYPE_NORMAL, COLOURTYPE_SPOT, COLOURTYPE_TINT, COLOURTYPE_LINKED MonoOff Purpose: Determines the type of this colour Notes: If this colour is linked to a deleted colour, then for sneaky undo reasons it (internally) remains linked. However, it pretends to the outside world that it is in fact a normal colour. SeeAlso: IndexedColour::SetType; IndexedColour::FindLinkedParent; IndexedColour::SetLinkedParent ********************************************************************************************/ IndexedColourType IndexedColour::GetType(void) const { if ((Info.ColourType == (UINT32) COLOURTYPE_LINKED || Info.ColourType == (UINT32) COLOURTYPE_TINT) && ParentColour != NULL && ParentColour->IsDeleted()) { return(COLOURTYPE_NORMAL); } // If the global "SpotsareProcess" flag is set, then spots pretend to be normal // Unnamed/Local colours also cannot be spots, so in case we accidentally get into the // wrong state, we make sure never to return a silly result. if (Info.ColourType == COLOURTYPE_SPOT && (SpotsAreProcess || !Info.IsNamed)) return(COLOURTYPE_NORMAL); return((IndexedColourType) Info.ColourType); } /******************************************************************************************** > BOOL IndexedColour::IsSpotOrTintOfSpot(void) const Author: Jason_Williams (Xara Group Ltd) Created: 12/6/96 Returns: TRUE if this colour is either a spot colour or a tint of a spot colour Purpose: Determines if this colour is either a spot colour or a true tint of a spot colour. (Tints can unfortunately be made from non-spot colour parents, so you need to call this function to determine if a tint really is cleanly derived from a spot colour, or if it must be treated as a simple process colour) Thus, this returns TRUE if the colour itself is a Spot, or if it is a Tint and its parent returns TRUE from IsSpotOrTintOfSpot(). Notes: If a colour in the tint chain is deleted, then all children must become process (non true-tint) colours, so this will return FALSE ********************************************************************************************/ BOOL IndexedColour::IsSpotOrTintOfSpot(void) const { if (Info.Deleted) return(FALSE); IndexedColourType Type = GetType(); if (Type == COLOURTYPE_SPOT) return(TRUE); // Is it a true spot colour? if (Type != COLOURTYPE_TINT || TintIsShade()) return(FALSE); // It's not even a tint if (ParentColour == NULL) return(FALSE); // We have no parent colour // OK, we're a tint of something. Recurse to find out if that something // is a true tint or a spot colour. return(ParentColour->IsSpotOrTintOfSpot()); } /******************************************************************************************** > ColourModel IndexedColour::GetColourModel(void) const Author: Jason_Williams (Xara Group Ltd) Created: 30/03/94 Inputs: - Outputs: - Returns: The colour model in which the IndexedColour was defined Purpose: To determine the colour model in which an IndexedColour is defined Notes: If this colour is a TINT, the parent colour's colour model is returned, as tints cannot be defined in a different model to their parents Errors: - SeeAlso: IndexedColour::GetSourceColour ********************************************************************************************/ ColourModel IndexedColour::GetColourModel(void) const { // If we're a tint, return our parent's colour. NOTE that we do not call GetType() // as we want to ask our parent even if it is 'deleted' for UNDO reasons. if (Info.ColourType == COLOURTYPE_TINT && ParentColour != NULL) return(ParentColour->GetColourModel()); return((ColourModel) Info.SourceColourModel); } /******************************************************************************************** > void IndexedColour::GetSourceColour(ColourGeneric *Result) Author: Jason_Williams (Xara Group Ltd) Created: 30/03/94 Inputs: - Outputs: - Returns: The colour definition of this IndexedColour, in its native colour model Purpose: Gets the definition of the IndexedColour. Notes: If the colour is Tint/Linked, this may involve a recursive set of calls which will convert and override each parent colour up the chain until the resulting colour definition for this colour is eventually produced at the end. Errors: - SeeAlso: IndexedColour::GetColourModel ********************************************************************************************/ void IndexedColour::GetSourceColour(ColourGeneric *Result) { ERROR3IF(Result == &SourceColour, "Illegal attempt to GetSourceColour into a colour's own SourceColour field!"); if (ParentColour == NULL || ParentColour == this || (Info.ColourType != COLOURTYPE_LINKED && Info.ColourType != COLOURTYPE_TINT)) { // We are not linked to a parent colour (or the link is scarily illegal to ourself!) // (ParentColour == NULL OR we are not tint/linked) // - simply copy our own colour definition, checking that this is not an internal // call to get a source colour definition into our own source colour! if (&SourceColour != Result) memcpy(Result, &SourceColour, sizeof(ColourGeneric)); } else { ERROR3IF(ParentColour == NULL || ParentColour == this || ParentColour->IsADescendantOf(this), "Consistency failure in IndexedColour parent linkage"); // Ask our parent for its colour definition - recurse! ParentColour->GetSourceColour(Result); // Get our 'parent' colour context ColourContext *cc = ColourContext::GetGlobalDefault(GetColourModel()); ERROR3IF(cc == NULL, "IndexedColour::GetSourceColour - illegal colour context in use?!"); // Now, override the colour as necessary // NOTE that we do NOT call GetType(), as this might return COLOURTYPE_NORMAL for tints/linked // colours which have 'deleted' parents. This is due to nasty UNDO considerations - we retain // our linked parent internally when it is 'deleted'. if (Info.ColourType == COLOURTYPE_LINKED) { // If necessary, convert the Result colour into our own colour model if (ParentColour->GetColourModel() != GetColourModel()) { ColourContext *ccSource = ColourContext::GetGlobalDefault(ParentColour->GetColourModel()); if (ccSource != NULL) // Shouldn't happen, but let's be safe { ColourGeneric Source; memcpy(&Source, Result, sizeof(ColourGeneric)); cc->ConvertColour(ccSource, &Source, Result); } } // **** ToDo !!!! Override by copying OR Inherit by scaling !!!! // This is a linked colour. Override the given components with our own values if (!Info.InheritComponent1) Result->Component1 = SourceColour.Component1; if (!Info.InheritComponent2) Result->Component2 = SourceColour.Component2; if (!Info.InheritComponent3) Result->Component3 = SourceColour.Component3; if (!Info.InheritComponent4) Result->Component4 = SourceColour.Component4; } else if (Info.ColourType == COLOURTYPE_TINT) { // This is a tint. Component 1 of our 'SourceColour' is the tinting value // We get our 'parent' colour context to work out how to apply the tint/shade if (TintIsShade()) cc->ApplyShade(SourceColour.Component1, SourceColour.Component2, Result); // Shade it else cc->ApplyTint(SourceColour.Component1, Result); // Tint it } else { ERROR3("Unknown/Illegal colour type in IndexedColour::GetSourceColour"); } } } /******************************************************************************************** > BOOL IndexedColour::IsDifferent(const IndexedColour &Other) Author: Jason_Williams (Xara Group Ltd) Created: 1/8/94 Inputs: Other - the other indexed colour to which 'this' will be compared Outputs: - Returns: TRUE if the two colours are considered different FALSE if they are considered the same Purpose: To determine if two indexed colours share a common definition. This is defined as: Same Colour model, and source colour definitions and both are linked to/tint of the same colour (or none), and the 'no colour' (and if linked: inheritance bits; if tint: tinting values) and colour type match exactly. NOTE especially that this does NOT compare the names of the colours ********************************************************************************************/ BOOL IndexedColour::IsDifferent(const IndexedColour &Other) { if (GetType() != Other.GetType()) return(TRUE); if (GetColourModel() != Other.GetColourModel()) return(TRUE); // If this is a linked colour, check if their inheritance flags match if (GetType() == COLOURTYPE_LINKED) { if (ParentColour != Other.ParentColour) return(TRUE); if (Info.InheritComponent1 != Other.Info.InheritComponent1 || Info.InheritComponent2 != Other.Info.InheritComponent2 || Info.InheritComponent3 != Other.Info.InheritComponent3 || Info.InheritComponent4 != Other.Info.InheritComponent4) return(TRUE); } // If this is a tint, it has no components in the regular sense. // Return immediately with the result of comparing the tint values if (GetType() == COLOURTYPE_TINT) { if (ParentColour != Other.ParentColour) return(TRUE); if (TintIsShade() != Other.TintIsShade()) return(TRUE); if (TintIsShade()) { return(GetShadeValueX() != Other.GetShadeValueX() || GetShadeValueY() != Other.GetShadeValueY()); } return(GetTintValue() != Other.GetTintValue()); } if (GetColourModel() == COLOURMODEL_GREYT) { // We ignore the 2nd and 3rd components as they are not used. // (Should not be necessary, as these components should be zeroed anyway) if (SourceColour.Component1 != Other.SourceColour.Component1 || SourceColour.Component4 != Other.SourceColour.Component4) return(TRUE); } else { if (SourceColour.Component1 != Other.SourceColour.Component1 || SourceColour.Component2 != Other.SourceColour.Component2 || SourceColour.Component3 != Other.SourceColour.Component3 || SourceColour.Component4 != Other.SourceColour.Component4) return(TRUE); } return(FALSE); } /******************************************************************************************** > BOOL IndexedColour::IsDifferent(const IndexedColour &Other, FIXED24 ErrorLimit) Author: Jason_Williams (Xara Group Ltd) Created: 1/8/94 Inputs: Other - the other indexed colour to which 'this' will be compared Outputs: - Returns: TRUE if the two colours are considered different FALSE if they are considered the same Purpose: To determine if two indexed colours share a common definition. This is defined as: Same Colour model, and source colour definitions and both are linked to/tint of the same colour (or none), and the 'no colour' (and if linked: inheritance bits; if tint: tinting values) and colour type match within the limits specified by ErrorLimit. This version of the function takes an accuracy parameter, to allow 'rough' comparisons to be made. This is used when importing colours so that we don't have to store 32bit colour values in EPS files and so on in order for them to be recognised as an existing colour when re-importing. NOTE especially that this does NOT compare the names of the colours ********************************************************************************************/ #define OUTSIDE_LIMIT(a,b) ((ABS((a) - (b))) > (ErrorLimit)) BOOL IndexedColour::IsDifferent(const IndexedColour &Other, FIXED24 ErrorLimit) { if (GetType() != Other.GetType()) return(TRUE); if (GetColourModel() != Other.GetColourModel()) return(TRUE); // If this is a linked colour, check if their inheritance flags match if (GetType() == COLOURTYPE_LINKED) { if (ParentColour != Other.ParentColour) return(TRUE); if (Info.InheritComponent1 != Other.Info.InheritComponent1 || Info.InheritComponent2 != Other.Info.InheritComponent2 || Info.InheritComponent3 != Other.Info.InheritComponent3 || Info.InheritComponent4 != Other.Info.InheritComponent4) return(TRUE); } // If this is a tint, it has no components in the regular sense. // Return immediately with the result of comparing the tint values if (GetType() == COLOURTYPE_TINT) { if (ParentColour != Other.ParentColour) return(TRUE); if (TintIsShade() != Other.TintIsShade()) return(TRUE); if (TintIsShade()) { return( OUTSIDE_LIMIT(GetShadeValueX(), Other.GetShadeValueX()) || OUTSIDE_LIMIT(GetShadeValueY(), Other.GetShadeValueY()) ); } return( OUTSIDE_LIMIT(GetTintValue(), Other.GetTintValue()) ); } // Special case for greyscales... if (GetColourModel() == COLOURMODEL_GREYT) { // We ignore the 2nd and 3rd components as they are not used. if (OUTSIDE_LIMIT(SourceColour.Component1, Other.SourceColour.Component1) || OUTSIDE_LIMIT(SourceColour.Component4, Other.SourceColour.Component4)) return(TRUE); } else { if (OUTSIDE_LIMIT(SourceColour.Component1, Other.SourceColour.Component1) || OUTSIDE_LIMIT(SourceColour.Component2, Other.SourceColour.Component2) || OUTSIDE_LIMIT(SourceColour.Component3, Other.SourceColour.Component3) || OUTSIDE_LIMIT(SourceColour.Component4, Other.SourceColour.Component4)) return(TRUE); } return(FALSE); } // Ensure we don't use this macro out of its intended scope - it uses 'ErrorLimit'! #undef OUTSIDE_LIMIT /******************************************************************************************** > String_64 *IndexedColour::GetName(BOOL ReturnTrueID = FALSE) Author: Jason_Williams (Xara Group Ltd) Created: 02/04/94 Inputs: ReturnTrueID - FALSE (the default) to retrieve the 'normal' name. If this colour is unnamed, the string "Unnamed" will be returned. TRUE (*use with care*) to return a unique id for this colour. If unnamed, this will return a unique name string like "_362180". This is only intended for use by the import/export system. Outputs: - Returns: A pointer to a String_64 containing the name of this indexed colour If it is named, the return value is always the name If it is unnamed, then either "Unnamed" or a unique id "_1234567" will be returned. Purpose: To find the name of an IndexedColour (or the ID of an unnamed indexed colour) Errors: - ********************************************************************************************/ String_64 *IndexedColour::GetName(BOOL ReturnTrueID) { static String_64 Default(_R(IDS_LOCALCOLOUR)); if (IsNamed()) { if (Name != NULL) return(Name); } else { if (ReturnTrueID) { // If we're an unnamed colour, then we generate an "ID" (not a name, honest, guv!) // which is unique. This is used for export/import to recognise unnamed colours if (Name == NULL) { Name = new String_64; if (Name != NULL) Name->_MakeMsg( TEXT("_#1%ld"), (UINT32)(UINT_PTR)(this) ); } if (Name != NULL) return(Name); } } return(&Default); } /******************************************************************************************** > void IndexedColour::SetName(const StringBase &NewName, [BOOL ForceNamed = TRUE]) Author: Jason_Williams (Xara Group Ltd) Created: 05/04/94 Inputs: NewName - A StringBase which will be *copied* as this colours new name. NOTE that this name will be truncated to a maximum length of 63 characters, and any underscore characters within it will be converted to spaces ForceNamed - if TRUE (the default), this forces the colour to become 'named' and will strip out underline characters from it. If FALSE (*use with care*) this will leave the colour in its current state, (i.e. won't make an unnamed colour named) and will retain underlines. This is only intended for use by importers for handling export/import of unnamed colours. Purpose: To set the name of an IndexedColour. The name will be truncated to a maximum length of 63 characters. Notes: Any underscore characters in the name will be converted to spaces, on the grounds that the export system uses underscores as a special name identifier to recognise unnamed colours. Suffice to say we just don't allow underscores If NewName is NULL, or if we fail to allocate space for the name to be stored, the colour will revert to having no name. Setting the name of an IndexedColour makes it a Named IndexedColour (Trust me, that is less silly than it sounds! ;-) SeeAlso: IndexedColour::SetUnnamed; IndexedColour::IsNamed ********************************************************************************************/ void IndexedColour::SetName(const StringBase &NewName, BOOL ForceNamed) { if (ForceNamed) Info.IsNamed = TRUE; if (Name == NULL) Name = new String_64; // If this fails, Name will just be NULL, which is safe if (Name != NULL) { if (ForceNamed) { const TCHAR *Src = (const TCHAR *)NewName; TCHAR *Dest = (TCHAR *)(*Name); // Copy up to 63 chars across camStrncpy(Dest, Src, 63); // convert underscores into spaces Name->SwapChar(TCHAR('_'), TCHAR(' ')); } else { NewName.Left(Name, 63); // Truncate to 63 chars max, and copy } } } /******************************************************************************************** > void IndexedColour::SetUnnamed(void) Author: Jason_Williams (Xara Group Ltd) Created: 05/04/94 Purpose: To UNset the name of an IndexedColour, forcing it back to being Unnamed ********************************************************************************************/ void IndexedColour::SetUnnamed(void) { Info.IsNamed = FALSE; if (Name != NULL) delete Name; Name = NULL; } /******************************************************************************************** > BOOL IndexedColour::IsADescendantOf(IndexedColour *TestParent) Author: Jason_Williams (Xara Group Ltd) Created: 17/11/94 Inputs: TestParent - the parent/ancestor colour we wish to test for Returns: TRUE if this is indeed a descendant of the given colour Purpose: Recursively backtracks through the chain of LinkedParent links to determine if this colour is in any way (directly or indirectly) linked to the given Parent colour, and might therefore be affected by any change to said colour. Notes: To determine if a colour is the *direct* parent of another, use if (TestParent == ThisColour->FindLinkedParent()) If the TestParent is THIS colour, the return value is TRUE (i.e Yes, a change to the 'Parent' colour will affect 'this' colour!). {This is also an end-of- recursion clause} This method only calculates descendant information for LINKED/TINT colours. Non-linked/tint colours will always spell the end of the search. Is quite happy if TestParent is NULL - will always return FALSE in this case ********************************************************************************************/ BOOL IndexedColour::IsADescendantOf(IndexedColour *TestParent) { if (TestParent == NULL) // Silly test! Of course it's not! return(FALSE); if (this == TestParent) // We are the colour being tested - we are related return(TRUE); // We cannot be descended, as we're a normal colour if (GetType() == COLOURTYPE_NORMAL || GetType() == COLOURTYPE_SPOT) return(FALSE); if (ParentColour == NULL) // We have no parent, so cannot be descended from anything return(FALSE); // Ask our parent to check back in the family tree return(ParentColour->IsADescendantOf(TestParent)); } /******************************************************************************************** > IndexedColour *IndexedColour::FindLinkedParent(void) Author: Jason_Williams (Xara Group Ltd) Created: 12/10/94 Returns: The colour upon which this Tint or Linked colour is based. (If this colour is not a Tint or Linked colour, or if it is a deleted (hidden for undo) colour, the return value is NULL) Notes: If you need to know what colour this colour *was* linked to, as the colour editor does when the user is randomly plonking about with the colour type, then call FindLastLinkedParent instead. Purpose: Finds the colour upon which a tint/based-on colour is based, if any. Can also be used to determine if a colour is a tint/basedon colour. SeeAlso: IndexedColour::FindLastLinkedParent ********************************************************************************************/ IndexedColour *IndexedColour::FindLinkedParent(void) { if (IsDeleted()) return(NULL); if (GetType() != COLOURTYPE_TINT && GetType() != COLOURTYPE_LINKED) return(NULL); return(FindLastLinkedParent()); } /******************************************************************************************** > IndexedColour *IndexedColour::FindOldestAncestor(void) Author: Jason_Williams (Xara Group Ltd) Created: 20/6/96 Returns: The utimate colour upon which this Tint or Linked colour is based. Note that if this colour has no parent, it will return itself! Purpose: Finds the colour upon which a tint/based-on colour is based, if any. Can also be used to determine if a colour is a tint/basedon colour. This is similar to FindLinkedParent, except it traverses all parent links until it finds the ultimate parent of the entire linked-colour tree in which this colour resides. SeeAlso: IndexedColour::FindLinkedParent ********************************************************************************************/ IndexedColour *IndexedColour::FindOldestAncestor(void) { IndexedColour *Ptr = FindLinkedParent(); IndexedColour *Last = this; while (Ptr != NULL) { Last = Ptr; Ptr = Ptr->FindLinkedParent(); } return(Last); } /******************************************************************************************** > void IndexedColour::SetLinkedParent(IndexedColour *Parent, IndexedColourType NewType = COLOURTYPE_LINKED) Author: Jason_Williams (Xara Group Ltd) Created: 12/10/94 Inputs: Parent - the new Linked/Tint parent IndexedColour, or NULL to remove any existing link NewType - The ColourType to set this to. Note that for NORMAL/SPOT, the parent field must be NULL; For LINKED/TINT, it must point at a valid Named IndexedColour. If this is not the case, an ERROR3 will occur. Purpose: To make a colour linked to or a tint of another colour. This links the colour to the parent. Notes: Generally, the colour's colour model and definition will be unaffected. However, if the colour was previously linked/tint, and it is being made into a standalone colour, the existing linked colour definition will be read, and then placed into SourceColour as a standalone version of the previous linked definition. (i.e. the colour's appearance will not change but the link will be broken) If the colour was not already a COLOURTYPE_LINKED when it is being made LINKED, all components will be set to override the parent. If the colour was not already a COLOURTYPE_TINT when it is being made a TINT, it will be set to be a 100% tint (no tinting at all) When making a COLOURTYPE_TINT colour, it will be a TINT, not a SHADE. To make a shade, make it COLOURTYPE_TINT then call SetTintOrShade(TRUE); If it was already a COLOURTYPE_TINT, the tint/shade state is unaffected. The colour's output cache is flushed by this call It is your responsibility to confirm overwriting the colour. It is also your responsibility to inform the system that this colour has changed, by calling ColourManager::ColourHasChanged IMPORTANT NOTE: This method allows you to do things like making a colour 'normal' (supposedly not linked), but still set a parent colour. This is a potentially dangerous practice so be very careful. (It is allowed so that the colour editor can cunningly remember what a colour was last linked to, in order to be far more helpful to the user). Scope: private? Generally speaking, you should not be calling this method, unless you are the colour editor, or a load/import filter. SeeAlso: IndexedColour::GetLinkedParent; IndexedColour::GetLastLinkedParent; IndexedColour::SetInheritsComponent; IndexedColour::SetType; IndexedColourType; ColourManager::ColourHasChanged Errors: ERROR3 if you try to do anythign totally stupid (circular linking, linking to deleted colours, linking to unnamed colours, etc) ********************************************************************************************/ void IndexedColour::SetLinkedParent(IndexedColour *Parent, IndexedColourType NewType) { if (this == Parent) { ERROR3("Illegal attempt to make an IndexedColour Linked to itself"); return; } if (Parent != NULL && Parent->IsADescendantOf(this)) { // Our new parent-to-be is already a linked child of us! ERROR3("Illegal attempt to generate circular reference in Colour linking"); return; } if (Parent != NULL && !Parent->IsNamed()) { ERROR3("Illegal attempt to use UNNAMED IndexedColour as a linked parent"); return; } if (Parent!= NULL && Parent->IsDeleted()) { ERROR3("Illegal attempt to use 'DELETED' IndexedColour as a linked parent"); return; } switch(NewType) { case COLOURTYPE_LINKED: if (GetType() != COLOURTYPE_LINKED) { Info.InheritComponent1 = // Override all components for now Info.InheritComponent2 = Info.InheritComponent3 = Info.InheritComponent4 = FALSE; } break; case COLOURTYPE_TINT: if (GetType() != COLOURTYPE_TINT) { SetType(NewType); // Set type now to stop the next call ENSURE'ing SetTintOrShade(FALSE); // Make it a real tint (not a shade "tint") SetTintValue(FIXED24(1.0)); // 100% tint (the colour) for now } // Swapping from Tint to Shade (which are both COLOURTYPE_TINT will need to do this, // so we do it even if it is supposely chnaging to the same "type" if (Parent != NULL) Info.SourceColourModel = (UINT32) Parent->GetColourModel(); break; default: // COLOURTYPE_NORMAL, COLOURTYPE_SPOT if (FindLastLinkedParent() != NULL) { // If this was previously a tint/linked colour, then copy the resulting // colour definition into this colour to make it standalone again. ColourGeneric NewSourceColour; GetSourceColour(&NewSourceColour); memcpy(&SourceColour, &NewSourceColour, sizeof(ColourGeneric)); } break; } if (ParentColour != NULL) ParentColour->DecrementChildUsage(); ParentColour = Parent; // Set the new linked/tint parent colour if (ParentColour != NULL) ParentColour->IncrementChildUsage(); InvalidateCache(); // Invalidate the output colour cache SetType(NewType); // And set the new type of the colour } /******************************************************************************************** > BOOL IndexedColour::SetType(IndexedColourType NewType) Author: Jason_Williams (Xara Group Ltd) Created: 1/11/94 Returns: TRUE if this caused the type of this colour to be changed FALSE if the new type is the same as the old type Purpose: Sets the type of this colour: MonoOn COLOURTYPE_NORMAL, COLOURTYPE_SPOT, COLOURTYPE_TINT, COLOURTYPE_LINKED MonoOff Notes: If you wish to make a colour Linked or a Tint, then you should set its type at the same time as its parent-link in SetLinkedParent(). If you wish to make a linked/tint colour normal again, then you should also use SetLinkedParent. On second thoughts, you shouldn't be calling this method! Scope: private SeeAlso: IndexedColour::SetType; IndexedColour::FindLinkedParent; IndexedColour::SetLinkedParent ********************************************************************************************/ BOOL IndexedColour::SetType(IndexedColourType NewType) { BOOL Result = (NewType != (IndexedColourType) Info.ColourType); if ((INT32)NewType < 0 || (INT32)NewType > 3) { ERROR3("Attempt to set invalid colour type"); return(FALSE); } Info.ColourType = (UINT32) NewType; if (Result) // If the colour has changed, invalidate the output cache InvalidateCache(); return(Result); } /******************************************************************************************** > BOOL IndexedColour::InheritsComponent(UINT32 ComponentID) Author: Jason_Williams (Xara Group Ltd) Created: 12/10/94 Inputs: ComponentID: a number [1..4] indicating which component of the colour you wish to find out about. Returns: TRUE if the component is inherited from the parent FALSE if the component overrides the parent, or if the colour isn't linked Purpose: To determine if a given component of a colour is inherited from its linked parent colour. Always returns FALSE if a colour is not linked. Notes: Should be used in conjunction with the appropriate ColourContext for this colour's colour model to determine if *valid* components of a colour are inherited from their parent colour. If asked about an invalid component, the result will be indeterminate (generally FALSE, but somebody may have set it to TRUE without checking if it is a valid component) SeeAlso: IndexedColour::GetType(); ColourContext::GetComponentName; IndexedColour::SetInheritsComponent ********************************************************************************************/ BOOL IndexedColour::InheritsComponent(UINT32 ComponentID) { ERROR3IF(ComponentID < 1 || ComponentID > 4, "Bad colour component index passed to IndexedColour::InheritsComponent"); if (GetType() == COLOURTYPE_LINKED) { switch(ComponentID) { case 1: return(Info.InheritComponent1); case 2: return(Info.InheritComponent2); case 3: return(Info.InheritComponent3); case 4: return(Info.InheritComponent4); } } return(FALSE); } /******************************************************************************************** > BOOL IndexedColour::SetInheritsComponent(UINT32 ComponentID, BOOL Inherits) Author: Jason_Williams (Xara Group Ltd) Created: 12/10/94 Inputs: ComponentID: a number [1..4] indicating which component of the colour you wish to set inheritance information for. Inherits - TRUE if the component is to be inherited from the parent FALSE if the component is to override the parent Returns: TRUE if this results in the stored value actually changing Purpose: To set if a given component of a colour is inherited from its linked parent colour. Errors: In a debug build, will give an ERROR3 if the colour is not linked or if the index given is out of range. In all builds, incorrect parameters will be ignored. Notes: Should be used in conjunction with the appropriate ColourContext for this colour's colour model to determine if a component is *valid* before you try to set it. SeeAlso: IndexedColour::GetType(); ColourContext::GetComponentName; IndexedColour::InheritsComponent ********************************************************************************************/ BOOL IndexedColour::SetInheritsComponent(UINT32 ComponentID, BOOL Inherits) { BOOL Result = FALSE; ERROR3IF(ComponentID < 1 || ComponentID > 4, "Bad colour component index passed to IndexedColour::InheritsComponent"); ERROR3IF(GetType() != COLOURTYPE_LINKED, "Attempt to set Component Inheritance for non-Linked colour"); UINT32 ItInherits = (Inherits) ? 1 : 0; if (GetType() == COLOURTYPE_LINKED) { switch(ComponentID) { case 1: Result = (Info.InheritComponent1 != ItInherits); Info.InheritComponent1 = ItInherits; break; case 2: Result = (Info.InheritComponent2 != ItInherits); Info.InheritComponent2 = ItInherits; break; case 3: Result = (Info.InheritComponent3 != ItInherits); Info.InheritComponent3 = ItInherits; break; case 4: Result = (Info.InheritComponent4 != ItInherits); Info.InheritComponent4 = ItInherits; break; } } if (Result) // If the colour has changed, invalidate the output cache InvalidateCache(); return(Result); } /******************************************************************************************** > void IndexedColour::SetTintValue(FIXED24 NewTintValue) Author: Jason_Williams (Xara Group Ltd) Created: 17/11/94 Inputs: NewTintValue - the new tint value, in the range 0.0 to 1.0 Any value outside this range will be clipped to 0.0 or 1.0 Outputs: - Returns: - Purpose: Sets a new tint value for a Tint colour. Will generate ENSURE failures in the debug build if the colour is not a tint This also forces a Tint to be a true tint (not a shade) Notes: Internally, tint is currently stored in the SourceColour.Component1 field. This should not be relied upon externally. SeeAlso: IndexedColour::SetShadeValues ********************************************************************************************/ void IndexedColour::SetTintValue(FIXED24 NewTintValue) { if (GetType() != COLOURTYPE_TINT) { ERROR3("Your puny attempt to set the tint value for a non-tint colour has been ignored"); return; } Info.InheritComponent1 = FALSE; // Force it to be a tint (not a shade) if (NewTintValue <= FIXED24(0.0)) NewTintValue = 0; if (NewTintValue >= FIXED24(1.0)) NewTintValue = FIXED24(1.0); SourceColour.Component1 = NewTintValue; InvalidateCache(); // The colour has changed, so invalidate the output cache } /******************************************************************************************** > FIXED24 IndexedColour::GetTintValue(void) const Author: Jason_Williams (Xara Group Ltd) Created: 17/11/94 Inputs: - Outputs: - Returns: A FIXED24 value between 0.0 and 1.0 representing the Tint for this colour Note that a spot colour returns 1.0 (a 100% tint - 100% ink density), and any process (non-spot/tint) colour returns 0.0 (a 0% tint, i.e. no ink). Purpose: Gets the current Tint value for the colour. NOTE that the returned tint value simply indicates how much this colour tints its parent colour (if at all). If you want to know how much ink will actually be produced for this colour, then you want to use GetAccumulatedTintValue() instead. Notes: Internally, tint is currently stored in the SourceColour.Component1 field This should not be relied upon externally. SeeAlso: IndexedColour::GetAccumulatedTintValue ********************************************************************************************/ FIXED24 IndexedColour::GetTintValue(void) const { if (GetType() == COLOURTYPE_SPOT) return(FIXED24(1.0)); // Spot colour is a 100% tint if (GetType() != COLOURTYPE_TINT || TintIsShade()) return(FIXED24(0.0)); // Any process colour is a 0% tint return(SourceColour.Component1); // Any tint is a (Tint)% tint } /******************************************************************************************** > FIXED24 IndexedColour::GetAccumulatedTintValue(void) const Author: Jason_Williams (Xara Group Ltd) Created: 20/6/96 Returns: A FIXED24 value between 0.0 and 1.0 representing the accumulated Tint for this colour. See Purpose for details. Purpose: To determine the accumulated tint value of any colour. If this is not a true tint colour, returns 0.0 (a 0% tint, i.e. white) If this is a spot colour, returns 1.0 (i.e. 100% ink) If this is a true tint of a spot ink, it returns the overall ink density that should be used. With a simple tint-of-spot tint, this is the normal tint value, but if there are a chain of tints, the tint values are cumulative, i.e. a 50% tint of a 50% tint of Red gives a _25%_ ink density. Thus, if you apply the GetAccumulatedTintVlaue() to the GetOldestAncestor() colour, you will arrive at the right output colour. (This isn't actually how screen values for tints are produced, but the cumulative tint is used when mixing tints in blends, and most importantly when outputting separated Spot ink plates! Notes: The cumulative value is simply the tint values of each colour in turn in the parent-colour chain multiplied together (where process colours are treated as a tint value of 0.0 and the ultimate spot colour is 1.0) ********************************************************************************************/ FIXED24 IndexedColour::GetAccumulatedTintValue(void) { double Tint = 1.0; IndexedColour *Ptr = this; while (Ptr != NULL && Tint > 0.0) { Tint *= Ptr->GetTintValue().MakeDouble(); Ptr = Ptr->FindLinkedParent(); } return(FIXED24(Tint)); } /******************************************************************************************** > void IndexedColour::SetShadeValues(FIXED24 NewShadeValueX, FIXED24 NewShadeValueY) Author: Jason_Williams (Xara Group Ltd) Created: 24/8/95 Inputs: NewShadeValueX - the new Shade Saturation value, in the range -1.0 to 1.0 NewShadeValueY - the new Shade Brightness value, in the range -1.0 to 1.0 Outputs: - Returns: - Purpose: Sets new shade values for a Shade colour. Will generate ENSURE failures in the debug build if the colour is not a Tint/Shade This also forces a Tint to be a shade (not a true tint) Notes: Internally, tint/shade is currently stored in the SourceColour.Component1 field. And now the Component2 field as well. Bodgy city dude. This should not be relied upon externally. SeeAlso: IndexedColour::SetTintValue ********************************************************************************************/ void IndexedColour::SetShadeValues(FIXED24 NewShadeValueX, FIXED24 NewShadeValueY) { if (GetType() != COLOURTYPE_TINT) { ERROR3("Your puny attempt to set the shade values for a non-shade colour has been ignored"); return; } Info.InheritComponent1 = TRUE; // Force it to be a shade if (NewShadeValueX <= FIXED24(-1.0)) NewShadeValueX = FIXED24(-1.0); if (NewShadeValueX >= FIXED24(1.0)) NewShadeValueX = FIXED24(1.0); SourceColour.Component1 = NewShadeValueX; if (NewShadeValueY <= FIXED24(-1.0)) NewShadeValueY = FIXED24(-1.0); if (NewShadeValueY >= FIXED24(1.0)) NewShadeValueY = FIXED24(1.0); SourceColour.Component2 = NewShadeValueY; InvalidateCache(); // The colour has changed, so invalidate the output cache } /******************************************************************************************** > FIXED24 IndexedColour::GetShadeValueX(void) const Author: Jason_Williams (Xara Group Ltd) Created: 24/8/95 Inputs: - Outputs: - Returns: A FIXED24 value between -1.0 and 1.0 representing the Shade for this colour This value is the half of the shading settings for affecting Saturation (If the colour is not a Tint/Shade, debug builds will ENSURE, and all builds will return 1.0 (a 100% shade)) Purpose: Gets the current Shade Saturation value for the colour Notes: Internally, tint/shade is currently stored in the SourceColour.Component1 field And now the Component2 field as well. Bodgy city dude. This should not be relied upon externally. ********************************************************************************************/ FIXED24 IndexedColour::GetShadeValueX(void) const { if (GetType() != COLOURTYPE_TINT || !Info.InheritComponent1) { ERROR3("Attempt to read tint value for a non-shade colour"); return(FIXED24(1.0)); } return(SourceColour.Component1); } /******************************************************************************************** > FIXED24 IndexedColour::GetShadeValueY(void) const Author: Jason_Williams (Xara Group Ltd) Created: 24/8/95 Inputs: - Outputs: - Returns: A FIXED24 value between -1.0 and 1.0 representing the Shade for this colour This value is the half of the shading settings for affecting Brightness (If the colour is not a Tint/Shade, debug builds will ENSURE, and all builds will return 1.0 (a 100% shade)) Purpose: Gets the current Shade Brightness value for the colour Notes: Internally, tint/shade is currently stored in the SourceColour.Component1 field And now the Component2 field as well. Bodgy city dude. This should not be relied upon externally. ********************************************************************************************/ FIXED24 IndexedColour::GetShadeValueY(void) const { if (GetType() != COLOURTYPE_TINT || !Info.InheritComponent1) { ERROR3("Attempt to read tint value for a non-shade colour"); return(FIXED24(1.0)); } return(SourceColour.Component2); } /******************************************************************************************** > void IndexedColour::SetTintOrShade(BOOL IsATint) Author: Jason_Williams (Xara Group Ltd) Created: 24/8/95 Inputs: IsATint - TRUE to make this Tint a true Tint, FALSE to make it a Shade Purpose: Sets a COLOURTYPE_TINT colour to be either a Tint (fade-to-white) or a shade (fade-to-black) colour. The tint/shade fraction is unchnaged (the colour will just toggle between being darker and lighter!) Notes: Internally, tint/shade is currently stored in the SourceColour.Component1 field This should not be relied upon externally. ********************************************************************************************/ void IndexedColour::SetTintOrShade(BOOL IsATint) { if (GetType() != COLOURTYPE_TINT) { ERROR3("Attempt to set tint/shade value for a non-tint colour"); return; } Info.InheritComponent1 = IsATint ? 1 : 0; } /******************************************************************************************** > BOOL IndexedColour::TintIsShade(void) const Author: Jason_Williams (Xara Group Ltd) Created: 24/8/95 Returns: TRUE if this COLOURTYPE_TINT colour is a true Tint, FALSE if it's a Shade Purpose: Determines if a COLOURTYPE_TINT colour is really a tint or a shade Notes: COLOURTYPE_TINT has two "subtypes" (tint-to white (tint) and tint-to-black (shade)). These are differentiated by a single flag, and are otherwise implemented identically. Thus, if it's type is "Tint" then it could be a shade! (Nasty, but gets around a shortage of flag bits, and also allows us to continue using screeds of old code which doesn't know the difference between tints and shades and doesn't need to know) Internally, tint/shade is currently stored in the SourceColour.Component1 field This should not be relied upon externally. ********************************************************************************************/ BOOL IndexedColour::TintIsShade(void) const { if (Info.ColourType != COLOURTYPE_TINT) { ERROR3("TintIsShade() called for non-tint/shade colour"); return(FALSE); } return(Info.InheritComponent1); } /******************************************************************************************** > void IndexedColour::SwapWith(IndexedColour *Other) Author: Jason_Williams (Xara Group Ltd) Created: 14/6/94 Inputs: Other - The colour to swap with Outputs: - Returns: - Purpose: This swaps the definitions of the two IndexedColours. Notes: This is used to provide undo/redo via the OpColourChange defined in colormgr.cpp/.h, as when we undo a change to an IndexedColour, the definition must remain at the same memory address so that all references to it in the document do not need to be fixed. The implementation swaps the Info, SourceColour, & Name fields (i.e. the colour definition) ONLY. That is, the usage count for each object and the caches are not swapped. The caches for both colours are in fact flushed, to guarantee their integrity. ********************************************************************************************/ #define JASONSWAP(X,Y,VARTYPE) \ { \ VARTYPE T; \ memcpy(&(T), &(X), sizeof(VARTYPE)); \ memcpy(&(X), &(Y), sizeof(VARTYPE)); \ memcpy(&(Y), &(T), sizeof(VARTYPE)); \ } void IndexedColour::SwapWith(IndexedColour *Other) { // Components to copy are: // Info // SourceColour // ParentColour pointer // Name POINTER // CachedColour -- We are discarding the cache anyway so ignore // UsageCount -- We wish to keep the usage counts intact, as it is // ChildUsage the number of refs to THIS object. // Thus, only the first 4 in this list are copied. JASONSWAP(Info, Other->Info, IndexedColourInfo); JASONSWAP(SourceColour, Other->SourceColour, ColourGeneric); // Swap the Name POINTER String_64 *NameTemp = Name; Name = Other->Name; Other->Name = NameTemp; // Swap the linked/tint Parent Colour pointer IndexedColour *ParentTemp = ParentColour; ParentColour = Other->ParentColour; Other->ParentColour = ParentTemp; // And invalidate the caches just to be on the safe side Info.CacheColourModel = Other->Info.CacheColourModel = COLOURMODEL_NOTCACHED; Info.OCContextHandle = Other->Info.OCContextHandle = 0; } #undef JASONSWAP /******************************************************************************************** > void IndexedColour::GetDebugDetails(StringBase* Str) Author: Jason_Williams (Xara Group Ltd) Created: 4/5/94 Inputs: Str - string to receive the debug details Outputs: - Returns: - Purpose: To get information on this colour for display in the Debug Tree Errors: - ********************************************************************************************/ void IndexedColour::GetDebugDetails(StringBase* Str) { String_256 TempStr; ColourContext *cc = ColourContext::GetGlobalDefault(GetColourModel()); ColourGeneric col; String_8 UnnamedString(TEXT("N")); if (!IsNamed()) UnnamedString = TEXT("U"); GetSourceColour(&col); String_32 ModelName; cc->GetModelName(&ModelName); String_32 Type(TEXT("")); switch(GetType()) { case COLOURTYPE_SPOT: Type._MakeMsg(TEXT(" Spot")); break; case COLOURTYPE_TINT: if (TintIsShade()) TempStr._MakeMsg( TEXT(" Shade, resulting in")); else TempStr._MakeMsg( TEXT(" #1%ld% Tint, resulting in"), (INT32) (GetTintValue().MakeDouble()*100)); break; case COLOURTYPE_LINKED: Type._MakeMsg(TEXT(" Linked, resulting in")); break; default: break; } TempStr._MakeMsg( TEXT(" #1%sIxCol (#2%s) =#3%s #4%s(#5%ld, #6%ld, #7%ld, #8%ld)\r\n"), (TCHAR *) UnnamedString, (TCHAR *) *(GetName(TRUE)), (TCHAR *) Type, (TCHAR *) ModelName, (INT32) (col.Component1.MakeDouble()*100), (INT32) (col.Component2.MakeDouble()*100), (INT32) (col.Component3.MakeDouble()*100), (INT32) (col.Component4.MakeDouble()*100)); (*Str) += TempStr; } /******************************************************************************************** > static void IndexedColour::ForceSpotsToBeProcess(BOOL ForceOn) Author: Jason_Williams (Xara Group Ltd) Created: 26/8/96 Inputs: ForceOn - TRUE to force spots to process, FALSE to let them be spots Purpose: To set the global colour flag. When the flag is TRUE, all spot colours in the entire program are forced to act as "normal" colours; when set FALSE, all spot colours behave normally. Notes: In many ways this would be better as a localised option, at least limited to the selected document, but this is much more difficult to achieve, and anyway, it's better that spot colours are effectively disabled by this flag, so that it becomes obvious that spot colours are no longer special. This calls ColourManager::SelViewContextHasChanged() to make all the appropriate colour interfaces update themselves correctly. (Yeah, it's not quite the right name for what the message does, but this is just as fundamental a change as context changing) ********************************************************************************************/ void IndexedColour::ForceSpotsToBeProcess(BOOL ForceOn) { SpotsAreProcess = ForceOn; ColourManager::SelViewContextHasChanged(); }