Click here to Skip to main content
15,868,141 members
Articles / Desktop Programming / MFC
Article

CGradient and CGradientCtrl

Rate me:
Please Sign up or sign in to vote.
4.97/5 (90 votes)
29 Jan 200314 min read 262K   7.7K   130   64
A pair of classes for rendering and editing colourful washes

Introduction

This pair of classes is useful for graphics programs which need colour washes, or need smooth flowing palettes. CGradient provides all the useful functions for creating colour washes which can be rendered into CPalettes or arrays of RGBTRIPLES. CGradientCtrl is a control for editing the CGradient.

I wrote this pair of classes because I've never seen anything available which does the job, and as it was kind of crucial to my Fractal Generating Program, I started coding from scratch . The only place I've ever seen a control like this is in the Corel DRAW series, and the CGradientCtrl is clone of Corel's version.

New in This Version

CGradient

  • Peg positions defined on a float scale of 0 - 1
  • The gradient can be quantized to make a blocky palette
  • A choice of 10 different interpolation methods
  • Background can now be selected.

CGradientCtrl

  • Horizontal and Vertical Display modes
  • Keyboard support
  • Pegs can be shown on the left side of the gradient, right side, both or neither
  • Smooth dragging of pegs
  • Customizable Tooltips
  • Fixed slight blockiness in the rendering of the gradient
  • Better rendering of the wash

Note: The CGradient and CGradientCtrl 2.0 classes have been manipulated quite significantly since version 1.0, so the class cannot be a drop-replacment to the 1.0 class.

 

CGradientCtrl Demo

Image 1

I hope that the control is reasonably obvious how to use. In the demo I used a slightly modified version of the Microsoft CFireWnd to demonstrate how CGradient can be used to paletize 8-bit bitmaps. I've also provided a few sample gradient files containing some interesting colour effects.

CGradient Features

How it works

I have used some terms which I created myself to describe features of a colour wash.

Image 2

The diagram shows an annotated diagram of a gradient. The start peg and the end peg are fixed at either end of the gradient, with the movable colour pegs in-between them. Every peg has an associated colour, and the colour wash interpolated between the two the nearest pegs. The gradient also has an optional background colour which can become the 1st entry in rendered palettes.


Interpolation Methods

The gradient class now provides a choice of interpolation methods:

Linear Interpolation

Image 3

With linear interpolation each channel is treated individually, and the actual channel values are calculated by making weighted averages to move between pegs. The method can make the transition over a peg look rather sharp.

Cosine Interpolation

Image 4

Cosine interpolation provides smoother gradients than linear interpolation by using 180° segments of the cosine wave. Again each channel is interpolated independently of the others. This method tends to lead to a smoother flowing palettes especially around the pegs.

Flat Start, Flat End, Flat Middle Interpolation

 

Image 5

Flat Start
 
Image 6
Flat End
 
Image 7
Flat Middle
 

The three flat interpolation methods fill the gap between pegs with a constant colour. Flat Start and End use the colours of the start and end pegs of a segment respectively as the constant colour, and Flat Middle interpolation takes an average of the two pegs. These methods make the palette look really blocky.

Reverse Interpolation

Image 8

Reverse interpolation is linear interpolation in reverse! Instead of starting with the first colour and fading through to the last for each peg, interpolation starts from the last colour and works in reverse. This method makes the palette look really cut up.

HSL Clockwise, HSL Anticlockwise, HSL Shortest, HSL Longest Interpolation

With the HSL interpolation methods, colour is interpolated using the colour wheel. Saturation, luminance and hue values are interpolated linearly. Because the hue value is a circular type value, there are always two ways of getting from one point on the circle to the other - a long route and a short route. With clockwise and anticlockwise modes the hue is always interpolated by the clockwise or anticlockwise route respectively. And with shortest and longest modes the hue is always interpolated by the shortest or longest routes. These modes allow you to create a gaudy rainbow effect between pegs.


CPeg Class

Every peg has an index. The end pegs and the background have special indexes. The actual value is irrelevant as I have #defined all the symbols in the "Gradient.h" file.

PegSymbolIndex (irrelevant as the symbols are #defined)
BackgroundBACKGROUND-4
Start PegSTARTPEG-3
End PegENDPEG-2
NoneNONE-1

The information of the pegs is stored in a CArray of CPegs. The CPeg is a class which contains the data for a gradient peg.

class CPeg : CObject
{
public:
  CPeg();                                 // Default Constructor
  CPeg(const CPeg &src);                  // Copy Constructor
  CPeg& operator = (const CPeg &src);     // Assignment operator
  void Serialize(CArchive &ar);	          // Used to save the data to a file
  const UINT GetID() const {return id;};  // Returns the unique id of the peg
  
  DECLARE_SERIAL(CPeg)     // Handy MFC thingy
  COLORREF colour;         // The colour of the peg
  float position;          // The position of the peg

protected:
  UINT id;                 // The unique ID of the peg
  static UINT uniqueID;    // Used to create new  ids for fresh pegs
};

CGradient Class

CGradient is publicly derived from the MFC CObject class

Construction & Destruction

CGradient()

Creates a CGradient with no pegs except the start peg and the end peg which are assigned by default to black and white respectively.

CGradient(CGradient &gradient)

Copy constructor.

virtual ~CGradient()

Destructor

Operators

CGradient& operator =(CGradient &src)

Assignment operator

Attributes

int GetPegCount() const

Retrieves the number of pegs in the gradient. This does not include the start and end pegs.

const CPeg GetPeg(int iIndex) const

Returns a copy of a peg from a given index. If iIndex is a fixed peg (STARTPEG, ENDPEG or BACKGROUND), the pegs for these will be returned.

int SetPeg(int iIndex, COLORREF crColour, int iPosition)

Will set a peg of a given index with this colour and position info. The function returns the new index of the peg, in case it has been moved. -1 is returned if iIndex refers to a fixed peg such as BACKGROUND, STARTPEG or ENDPEG.

int SetPeg(int iIndex, CPeg peg)

Similar to SetPeg(int, COLORREF, int), except the pegs are set from a CPeg not position and colour data.

int AddPeg(COLORREF crColour, float iPosition)

Adds a peg with colour crColour and position iPosition. If iPosition is less than 0 or more than the gradient size, it will be truncated so that it falls within the bounds of the gradient. The return value is the index of the new peg.

int AddPeg(CPeg peg)

Add a peg to the gradient, the return value is the index of the peg.

void RemovePeg(int iIndex)

Deletes a peg at index iIndex.

int IndexFromPos(float pos)

Returns the index of the peg which appears at the beginning of the interpolation segment, which pos fall inside.

void SetStartPegColour(const COLORREF crColour)<BR>void SetEndPegColour(const COLORREF crColour)<BR>void SetBackgroundColour(const COLORREF crColour)

All three set the colour of their respective fixed pegs.

COLORREF GetStartPegColour() const<BR>COLORREF GetEndPegColour() const<BR>COLORREF GetBackgroundColour() const

All three will return the colour of their respective pegs.

void SetUseBackground(const BOOL bUseBackground)

Sets the Gradient's Background mode. If bUseBackground is TRUE 0'th entry in a palette will be set to the bacground colour, if bUseBackground is FALSE, the 0'th entry will be the first colour in the wash.

BOOL GetUseBackground() const

Return the background mode. See SetUseBackground...

InterpolationMethod GetInterpolationMethod() const

Retrieves the interpolation method used on the gradient. It can be

CGradient::Linear,
CGradient::FlatStart,
CGradient::FlatMid,
CGradient::FlatEnd,
CGradient::Cosine,
CGradient::HSLRedBlue,
CGradient::HSLBlueRed,
CGradient::HSLShortest,
CGradient::HSLLongest or
CGradient::Reverse

void SetInterpolationMethod(const InterpolationMethod method)

Sets the interpolation method to and of the values listed above.

void SetQuantization(const int entries)

SetQuantization allow you to set a number of entries that the palette should be quantized to. So with 8 entries the palette will have 8 discrete blocks in it. If entries is -1 quantization is disabled.

int GetQuantization() const

Returns the number of entries the palette should be quantized to. If -1 is returned, quantization is not active.

Operations

void MakePalette(CPalette *lpPal);

Creates a windows palette into the pointer, and fills the palette with the 256 colours from the gradient.

void Make8BitPalette(RGBTRIPLE *lpPal);

Fills an array of 256 RGBTRIPLEs with the gradient colours.

void MakeAllEntries(RGBTRIPLE *lpPal, int iEntryCount);

Fill the array of RGBTRIPLEs lpPal of size iEntryCount with the colour gradient. This function allows you to flexible create any type of palette from 2-colour palettes to 65525 palettes.

COLORREF ColourFromPosition(int iPos);

Returns the colour of the gradient at a given position.

void Serialize(CArchive &ar);

Standard serialization function.

CGradientCtrl Features

The CGradientCtrl is a CWnd derived control that allows the viewing and editing of the CGradient class.

Features...

  • Full keyboard support
  • Now runs in horizontal and vertical modes.
  • Displays the movable pegs as series of arrows, and the end pegs as a pair of squares.
  • The control shows the gradients as a vertical column, with a smooth movement of colour.
  • As pegs are dragged, the gradient is updated dynamically.
  • Pegs which are close together are stacked up:
     Image 9
  • Pegs can be shown on the left side, right side, none or both sides
  • Customizable Tooltip support.

Peg Sides

Image 10Image 11Image 12Image 13
No Pegs - Read only!Left/Bottom side pegsRight/Top side pegsBoth side pegs

Keyboard Support

KeysFunction
TabSelect Next Peg
Up, LeftSlide peg up towards start
Down, RightSlide peg towards end
HomeSlide peg to the start
EndSlide peg to end
Del, BackspaceDelete Peg
Return, SpaceEquivalent to double clicking on a peg
InsertDuplicates a peg

CGradientCtrl Class

CGradient control is derived from the MFC CWnd class

Construction

CGradientCtrl();

Default constructor.

BOOL Create(const RECT& rect, CWnd* pParentWnd, UINT nID);

Creates a control in the window pParentWnd, in the rectangle rect, and with the ID nID. The return value is the success of the function.

Attributes

void SetGradientWidth(int iWidth);

The function sets the width that the gradient is drawn with the control. iWidth specifies the number of pixels width the control should be. If GCW_AUTO is passed to iWidth, the width of control will be automatically adjusted to best fit the control into it's window.

int GetGradientWidth();

Returns the width that gradient is set to draw to. The function may return GCW_AUTO which means that the gradient width will be drawn so that it is best fitted into the control window.

int GetSelIndex();

Returns the index of the currently selected peg. This value return may be STARTPEG, ENDPEG or NONE.

int SetSelIndex(int iSel, BOOL bUpdate);

Sets the currently  selected peg to the index iSel. This value must be either a peg index between 0, and the number of movable pegs, or STARTPEG, ENDPEG, or NONE. If bUpdate is TRUE, the control is redrawn. The return value is the index of the previously selected peg.

CPeg GetSelPeg();

Returns an CPeg structure representing the currently selected peg. If the currently selected peg is an end peg, the position value in the CPeg class will be set to -1.

CGradient& GetGradient();

Returns a reference to the CGradient from which the control works.

void SetGradient(CGradient src)

Copies the source gradient into the controls embedded CGradient.

void ShowTooltips(BOOL bShow = true)

Switches tooltips on, or off

CGradient::Orientation GetOrientation() const

Returns the orientation mode of the control. The function can return CGradient::ForceHorizontal, CGradient::ForceVertical or CGradient::Auto. For CGradient::Auto, the orientation is automatically selected. So if the width is greater that the height, the control will be shown in horizontal mode.

void SetOrientation(CGradient::Orientation orientation)

Sets the orientation mode of the control. The modes CGradient::ForceHorizontal, CGradient::ForceVertical or CGradient::Auto are available.

void SetPegSide(BOOL setrightup, BOOL enable)

Sets the peg side mode for the control. So if setrightup is TRUE, enable will enable disable peg drawing on the right or top side. With right FALSE, enable will enable or disable pegs displayed on the left or bottom side.

BOOL GetPegSide(BOOL rightup) const

Retrieves the peg side mode for the side specified by rightup. So with rightup TRUE, GetPegSide will return a BOOL for whether pegs are to be displayed on the right or upper side of the control.

void SetTooltipFormat(const CString format)

Sets the tooltip format string to the value of format. A tool-tip format string is a piece of multi-line tokened text with a line associate with each possible tool-tip. So the default British tool-tip string looks like this:

&SELPOS\nPosition: &SELPOS Colour: R &R G &G B &B\nColour: R &R G &G B &B\nColour: R &R G &G B &B\nDouble Click to Add a New Peg

The string is made up of a series of tokens:

TokenMeaning
&SELPOSDisplays the position of  the selected text.
&RDisplays the red component of the selected peg in decimal (0-255).
&GDisplays the green component of the selected peg in decimal (0-255).
&BDisplays the blue component of the selected peg in decimal (0-255).
&HEXRDisplays the red component of the selected peg in two digit hex (00-FF).
&HEXGDisplays the green component of the selected peg in two digit hex (00-FF).
&HEXBDisplays the blue component of the selected peg in two digit hex (00-FF).
&FLOATRDisplays the red component of the selected peg as a floating point value between 0.0 and 1.0 to three decimal place accuracy.
&FLOATGDisplays the green component of the selected peg as a floating point value between 0.0 and 1.0 to three decimal place accuracy.
&FLOATBDisplays the blue component of the selected peg as a floating point value between 0.0 and 1.0 to three decimal place accuracy.
&&Displays an ampersand - "&"

Each line is assigned to a different tool-tip for a different situation:

LineUse
1Used when the peg is being dragged
2Used when the mouse hovers over a peg.
3Used when the mouse hovers over then start peg
4Used when the mouse hovers over then end peg
5Used when the mouse hovers over the gradient area

This system of token strings allows the control to be fairly neutral with respect to internationalization. The token strings can be stored in string table so that they can be auto-selected.

CString GetTooltipFormat() const;

Returns the current tool-tip format string.

Operations

void DeleteSelected(BOOL bUpdate);

Deletes the selected peg. No operation is performed if the selected peg is not a movable peg. If bUpdate is TRUE, the control is redrawn.

int MoveSelected(int iNewPos, BOOL bUpdate);

Moves the selected peg to a new position iNewPos. No operation is performed if the selected peg is not a movable peg. If iNewPos is less than 0 or greater than the gradient size. If bUpdate is TRUE, the control is redrawn. The return value is the new index of the moved peg.

COLORREF SetColourSelected(COLORREF crNewColour, BOOL bUpdate);

Sets the colour of the selected peg to new crNewColour. If bUpdate is TRUE, the control is redrawn. The return value is the previous colour of the selected peg.

Notification Messages

The gradient control may send any of these notification messages to it's parent window. The CGradientCtrl uses two NMHDRs: PegNMHDR, and DoubleClickCreateNMHDR

// Standard NMHDR used for all the notifications except GC_DBL_CREATE
struct PegNMHDR
{
	NMHDR nmhdr;		// Standard NMHDR
	CPeg peg;		// A copy of the CPeg in quesyion
	int index;		// The index of the peg in question
};

// NMHDR used in the GC_DBL_CREATE
struct PegCreateNMHDR
{
	NMHDR nmhdr;		// Standard NMHDR
	float position;		// The position at which a peg should be created
	COLORREF colour;	// The colour at the position
};

GC_SELCHANGE

Value: 1

Notification that the the selected peg has changed. A PegNMHDR is sent containing information about the currently selected peg. The return value is ignored.

GC_PEGMOVE

Value: 2

Notification that a colour peg is currently being moved. A PegNMHDR is sent containing information about the peg being dragged. The returned value is ignored.

GC_PEGMOVED

Value: 3

Notification that a movement operation has just completed. A PegNMHDR is sent containing information about the peg dragged. The returned value is ignored.

GC_PEGREMOVED

Value: 4

Notification that a peg has been removed. A PegNMHDR is sent containing information about the moved peg. The returned value is ignored.

GC_CREATEPEG

Value: 5

Notification that the user has double clicked on an empty spot on the gradient. This event can can also be triggered by the user pressing the "Insert" key. You may want to bring up a dialog asking for the colour of the new peg, or as in the case of the demo create a peg of a with the gradient colour in the position. A DoubleClickCreateNMHDR is sent containing the position that was double clicked, and colour present at that point.

GC_EDITPEG

Value: 6

Notification that the user has double clicked on a peg. This event can can also be triggered by the user pressing the Space Bar or the Return key. This message is sent to request the host to show an editing dialog. A PegNMHDR is sent containing information about the peg to be edited. The returned value is ignored.

GC_CHANGE

Value: 7

Notification is sent when the user makes any change to the gradient. This is a catch-all for all the above notifications. A PegNMHDR is sent containing information about the peg that has changed. The returned value is ignored.

Using CGradientCtrl

Into your dialog template you'll need to create a custom control (Image 14). Then you'll need to configure it. Set the windows ID to something like IDC_GRADIENT. The caption of the control is irrelevant. Set the class to "MFCGradientCtrl". Leave the style on 0x50010000, and if you want the control to have a client edge as shown in the demo you'll need to set the ExStyle to 0x200. VC should look something like this...

Image 15

Now in the source for your dialog, in DoDataExchange add this line:

DDX_Control(pDX, IDC_GRADIENT, m_wndGradientCtrl);

The code should look like this when you've finished

void CFooDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CFooDlg)
    //}}AFX_DATA_MAP
    DDX_Control(pDX, IDC_GRADIENT, m_wndGradientCtrl); //<-- Add this line
}

In the header file add this line:

CGradientCtrl m_wndGradientCtrl;

You can put it anywhere in the file. It will should work fine. I put mine right beneath the dialog data section.

Forthcoming Improvements

Of course I will endeavour to fix all the bugs that get reported. Transparency support would be nice soon!

Revisions

Revision 2.0: Added Interpolation methods, quantization, keyboard support, notification messages, tooltips, horizontal and vertical orientation modes.

Revision 1.0B: Fixed resource leak in demo (I think). Other minor changes.

Revision 1.0A: Added message GC_CHANGE, and tested CGradientCtrl::Create with successful results.

British and Proud!

Sorry if the abundant use of colour rather than color offends you! :-)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
Joel Holdsworth is a Mechanical Engineering student studying at Imperial College London. He has been programming for many years now. His favourite activities include bulding things, as well as building gadgets and also building stuff. That might be Mechanical Stuff, or Electronic stuff, or indeed Computer stuff. And when it comes to building stuff with computers Joel loves to mess around with C++ and C# in VS 2005, as well as pretty much anything computer related.

Comments and Discussions

 
GeneralGreat article/source code. Pin
fkhanoom4-Dec-09 8:21
fkhanoom4-Dec-09 8:21 
QuestionPotential GDI leak? Pin
RedFraggle4-Nov-08 4:08
RedFraggle4-Nov-08 4:08 
GeneralVery nice, here are some code beautification suggestions Pin
User 2694210-May-06 22:44
professionalUser 2694210-May-06 22:44 
Hello,

I found your very nice control and added it to our project.
I added a new function RemoveAllPeg to the class CGradient.
As I looked into the source code I found some things that you could correct:

1) Use const whenever possible. (Item 21)
2) Prefer pass-by-reference to pass-by-value. (Item 22)
3) Avoid data members in the public interface. (Item 20)
4) Check for assignment to self in operator=. (Item 17)

Item numbers are taken from the Effective C++, Second Edition, Scott Meyers, © 1996 by Addison Wesley Longman, Inc.

I added all the patches, that I have done.
The patches are generated with WinMerge http://winmerge.sourceforge.net/ and are/should be compatible with patch.exe from
the GnuWin32 Utilities: http://sourceforge.net/projects/gnuwin32

If you don't know:
You could apply the patches to your source files with patch.exe:
the code between
???.? begin ----------------
???.? end ----------------
must be saved into a file 'PATCHFILE', and patch.exe must be called:
patch.exe ORIGFILE [PATCHFILE]

Have a nice day.

Gradient.h.patch begin ----------------
19a20
> 	
43c44,46
< 	CGradient(CGradient &gradient);
---
> 	CGradient(const CGradient& gradient);
>         CGradient& operator =(const CGradient& src);
> 
46,47d48
< 	CGradient& operator =(CGradient &src);
< 	
52c53
< 	const CPeg GetPeg(int iIndex) const;
---
> 	const CPeg& GetPeg(int iIndex) const;
54c55
< 	int SetPeg(int iIndex, CPeg peg);
---
> 	int SetPeg(int iIndex, const CPeg& peg);
56c57
< 	int AddPeg(CPeg peg);
---
> 	int AddPeg(const CPeg& peg);
58c59,60
< 	int IndexFromPos(float pos);
---
>         void RemoveAllPeg(void);
> 	int IndexFromPos(float pos) const;
129,131c131,132
< 	InterpolateFn GetInterpolationProc();
< 	POSITION GetNextPeg(POSITION current);
< 	CArray <CPeg, CPeg&> pegs;
---
> 	InterpolateFn GetInterpolationProc() const;
> 	CArray <CPeg, const CPeg&> pegs;

Gradient.h.patch end ----------------

Gradient.cpp.patch begin ----------------
19c19
< UINT CPeg::uniqueID = 0;
---
> /*static*/ UINT CPeg::uniqueID = 0;
38c38
< CGradient::CGradient(CGradient &src)
---
> CGradient::CGradient(const CGradient &src)
40,42c40,47
< 	m_StartPeg.colour = m_StartPeg.colour;
< 	m_EndPeg.colour = m_EndPeg.colour;
< 	m_Background.colour = m_Background.colour;
---
>         pegs.RemoveAll();
>         for(int i = 0; i < src.pegs.GetSize(); i++)
>           pegs.Add(src.pegs[i]);
> 
>         m_StartPeg.colour = src.m_StartPeg.colour;
> 	m_EndPeg.colour = src.m_EndPeg.colour;
> 	m_Background.colour = src.m_Background.colour;
> 
47,49d51
< 	pegs.RemoveAll();
< 	for(int i = 0; i < src.pegs.GetSize(); i++)
< 		pegs.Add(src.pegs[i]);
57c59
< CGradient& CGradient::operator =(CGradient &src)
---
> CGradient& CGradient::operator =(const CGradient &src)
58a61,62
>   if ( this != &src )
>   {
63,65c67,70
< 	m_StartPeg.colour = m_StartPeg.colour;
< 	m_EndPeg.colour = m_EndPeg.colour;
< 	m_Background.colour = m_Background.colour;
---
> 	m_StartPeg.colour = src.m_StartPeg.colour;
> 	m_EndPeg.colour = src.m_EndPeg.colour;
> 	m_Background.colour = src.m_Background.colour;
> 
69a75,76
>   }
> 
75,76d81
< 	CPeg peg;
< 
79a85
>         CPeg peg;
88c94
< int CGradient::AddPeg(CPeg peg)
---
> int CGradient::AddPeg(const CPeg& peg)
94a101
> void CGradient::RemoveAllPeg(void) { pegs.RemoveAll(); }
98c105
< const CPeg CGradient::GetPeg(int iIndex) const
---
> const CPeg& CGradient::GetPeg(int iIndex) const
105,106c112,114
< 		const CPeg peg(pegs[iIndex]);
< 		return peg;
---
>           return pegs[iIndex];
> //		const CPeg peg(pegs[iIndex]);
> //		return peg;
117,118d124
< 	UINT tempid;
< 
135c141
< 		tempid = pegs[iIndex].GetID();
---
> 		const UINT tempid = pegs[iIndex].GetID();
142c148
< int CGradient::SetPeg(int iIndex, CPeg peg)
---
> int CGradient::SetPeg(int iIndex, const CPeg& peg)
144,166c150
< 	UINT tempid;
< 
< 	ASSERT(iIndex > -4 && iIndex != -1 && iIndex < GetPegCount());
< 		//You must pass a valid peg index or STARTPEG, ENDPEG, or BACKGROUND!
< 	
< 	if(peg.position < 0.0f) peg.position = 0.0f;
< 	else if(peg.position > 1.0f) peg.position = 1.0f;
< 	
< 	if(iIndex == STARTPEG)
< 		m_StartPeg.colour = peg.colour;
< 	else if(iIndex == ENDPEG)
< 		m_EndPeg.colour = peg.colour;
< 	else if(iIndex == BACKGROUND)
< 		m_Background.colour = peg.colour;
< 	else
< 	{
< 		pegs[iIndex].colour = peg.colour;
< 		pegs[iIndex].position = peg.position;
< 		tempid = pegs[iIndex].GetID();
< 		SortPegs();
< 		return IndexFromId(tempid);
< 	}
< 	return -1;
---
>   return SetPeg( iIndex, peg.colour, peg.position );
463c447
<  
---
>  
489c473
< int CGradient::IndexFromPos(float pos)
---
> int CGradient::IndexFromPos(float pos) const
584c568
<     
---
>     
710c694
< InterpolateFn CGradient::GetInterpolationProc()
---
> InterpolateFn CGradient::GetInterpolationProc() const

Gradient.cpp.patch end ----------------

GradientCtrl.h.patch begin ----------------
61c61
< 	const CPeg GetSelPeg() const;
---
> 	const CPeg& GetSelPeg() const;
63c63
< 	void SetGradient(CGradient src) {m_Gradient = src;};
---
> 	void SetGradient(const CGradient& src) {m_Gradient = src;};
69,70c69,70
< 	void SetTooltipFormat(const CString format);
< 	CString GetTooltipFormat() const;
---
> 	void SetTooltipFormat(const CString& format);
> 	const CString& GetTooltipFormat() const;

GradientCtrl.h.patch end ----------------

GradientCtrl.cpp.patch begin ----------------
15a16,21
> /////////////////////////////////////////////////////////////////////////////
> 
> namespace
> {
>   CPeg g_nullPeg;
> } // namespace
236c242
< 		else nmhdr.peg = m_Impl->m_Null;
---
> 		else nmhdr.peg = g_nullPeg;
238c244
< 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
347c353
< 			else nmhdr.peg = m_Impl->m_Null;
---
> 			else nmhdr.peg = g_nullPeg;
349c355
< 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
352c358
< 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&(nmhdr.nmhdr)));
---
> 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&(nmhdr.nmhdr)));
391c397
< 			else nmhdr.peg = m_Impl->m_Null;
---
> 			else nmhdr.peg = g_nullPeg;
393c399
< 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
396c402
< 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&(nmhdr.nmhdr)));
---
> 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&(nmhdr.nmhdr)));
539c545
< 			GetParent()->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 			GetParent()->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
556c562
< 			GetParent()->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 			GetParent()->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
601c607
< 		else nmhdr.peg = m_Impl->m_Null;
---
> 		else nmhdr.peg = g_nullPeg;
603c609
< 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
608c614
< 		else nmhdr2.peg = m_Impl->m_Null;
---
> 		else nmhdr2.peg = g_nullPeg;
610c616
< 		pParent->SendMessage(WM_NOTIFY, nmhdr2.nmhdr.idFrom, (DWORD)(&nmhdr2));
---
> 		pParent->SendMessage(WM_NOTIFY, nmhdr2.nmhdr.idFrom, (LPARAM)(&nmhdr2));
614c620
< 		nmhdr3.peg = m_Impl->m_Null;
---
> 		nmhdr3.peg = g_nullPeg;
616c622
< 		pParent->SendMessage(WM_NOTIFY, nmhdr3.nmhdr.idFrom, (DWORD)(&nmhdr3));
---
> 		pParent->SendMessage(WM_NOTIFY, nmhdr3.nmhdr.idFrom, (LPARAM)(&nmhdr3));
738c744
< 			else nmhdr.peg = m_Impl->m_Null;
---
> 			else nmhdr.peg = g_nullPeg;
740c746
< 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
751c757
< 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 			pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
986,987c992,993
< void CGradientCtrl::SetTooltipFormat(CString format) {m_ToolTipFormat = format;}
< CString CGradientCtrl::GetTooltipFormat() const {return m_ToolTipFormat;}
---
> void CGradientCtrl::SetTooltipFormat(const CString& format) {m_ToolTipFormat = format;}
> const CString& CGradientCtrl::GetTooltipFormat() const {return m_ToolTipFormat;}
1001c1007
< 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&nmhdr));
---
> 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&nmhdr));
1004c1010
< 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (DWORD)(&(nmhdr.nmhdr)));
---
> 		pParent->SendMessage(WM_NOTIFY, nmhdr.nmhdr.idFrom, (LPARAM)(&(nmhdr.nmhdr)));
1008c1014
< const CPeg CGradientCtrl::GetSelPeg() const
---
> const CPeg& CGradientCtrl::GetSelPeg() const
1011c1017
< 		return m_Impl->m_Null;
---
> 		return g_nullPeg;
1015c1021
< 	return m_Impl->m_Null;
---
> 	return g_nullPeg;

GradientCtrl.cpp.patch end ----------------

GradientCtrlImpl.h.patch begin ----------------
12,13d11
< #include "Gradient.h"
< 
14a13
> class CPeg;
27,28c26,27
< 	void DrawSelPeg(CDC *dc, CPoint point, int direction);
< 	void DrawPeg(CDC *dc, CPoint point, COLORREF colour, int direction);
---
> 	void DrawSelPeg(CDC *dc, const CPoint& point, int direction);
> 	void DrawPeg(CDC *dc, const CPoint& point, COLORREF colour, int direction);
31,34c30,33
< 	int PointFromPos(float pos);
< 	float PosFromPoint(int point);
< 	int GetPegIndent(int index);
< 	int PtInPeg(CPoint point);
---
> 	int PointFromPos(float pos) const;
> 	float PosFromPoint(int point) const;
> 	int GetPegIndent(int index) const;
> 	int PtInPeg(const CPoint& point) const;
36c35
< 	void GetPegRect(int index, CRect *rect, bool right);
---
> 	void GetPegRect(int index, CRect *rect, bool right) const;
38,41c37,40
< 	void ParseToolTipLine(CString &tiptext, CPeg peg);
< 	void ShowTooltip(CPoint point, CString text);
< 	CString ExtractLine(CString source, int line);
< 	void SetTooltipText(CString text);
---
> 	void ParseToolTipLine(CString &tiptext, const CPeg& peg) const;
> 	void ShowTooltip(const CPoint& point, const CString& text);
> 	CString ExtractLine(const CString& source, int line) const;
> 	void SetTooltipText(const CString& text);
45,46c44,45
< 	bool IsVertical();
< 	int GetDrawWidth();
---
> 	bool IsVertical() const;
> 	int GetDrawWidth() const;
54,55d52
< 
< 	CPeg m_Null;

GradientCtrlImpl.h.patch end ----------------

GradientCtrlImpl.cpp.patch begin ----------------
192c192
< void CGradientCtrlImpl::DrawSelPeg(CDC *dc, CPoint point, int direction)
---
> void CGradientCtrlImpl::DrawSelPeg(CDC *dc, const CPoint& point, int direction)
379c379
< void CGradientCtrlImpl::DrawPeg(CDC *dc, CPoint point, COLORREF colour, int direction)
---
> void CGradientCtrlImpl::DrawPeg(CDC *dc, const CPoint& point, COLORREF colour, int direction)
445c445
< CString CGradientCtrlImpl::ExtractLine(CString source, int line)
---
> CString CGradientCtrlImpl::ExtractLine(const CString& source, int line) const
472c472
< void CGradientCtrlImpl::ParseToolTipLine(CString &tiptext, CPeg peg)
---
> void CGradientCtrlImpl::ParseToolTipLine(CString &tiptext, const CPeg& peg) const
642c642
< void CGradientCtrlImpl::ShowTooltip(CPoint point, CString text)
---
> void CGradientCtrlImpl::ShowTooltip(const CPoint& point, const CString& text)
693c693
< void CGradientCtrlImpl::SetTooltipText(CString text)
---
> void CGradientCtrlImpl::SetTooltipText(const CString& text)
708c708
< bool CGradientCtrlImpl::IsVertical()
---
> bool CGradientCtrlImpl::IsVertical() const
722c722
< int CGradientCtrlImpl::GetDrawWidth()
---
> int CGradientCtrlImpl::GetDrawWidth() const
734c734
< int CGradientCtrlImpl::PointFromPos(float pos)
---
> int CGradientCtrlImpl::PointFromPos(float pos) const
744c744
< float CGradientCtrlImpl::PosFromPoint(int point)
---
> float CGradientCtrlImpl::PosFromPoint(int point) const
760c760
< int CGradientCtrlImpl::GetPegIndent(int index)
---
> int CGradientCtrlImpl::GetPegIndent(int index) const
777c777
< int CGradientCtrlImpl::PtInPeg(CPoint point)
---
> int CGradientCtrlImpl::PtInPeg(const CPoint& point) const
819c819
< void CGradientCtrlImpl::GetPegRect(int index, CRect *rect, bool right)
---
> void CGradientCtrlImpl::GetPegRect(int index, CRect *rect, bool right) const

GradientCtrlImpl.cpp.patch end ----------------


Andreas.


-- modified at 4:45 Thursday 11th May, 2006
GeneralSuggestion Pin
lano110615-Dec-05 8:04
lano110615-Dec-05 8:04 
GeneralRe: Suggestion Pin
Joel Holdsworth15-Dec-05 10:18
Joel Holdsworth15-Dec-05 10:18 
GeneralThese classes are fantastic! Pin
lano110612-Dec-05 7:51
lano110612-Dec-05 7:51 
GeneralSetGradientWidth() Pin
pcmaan13-Jun-05 23:35
pcmaan13-Jun-05 23:35 
GeneralRe: SetGradientWidth() Pin
Joel Holdsworth13-Jun-05 23:48
Joel Holdsworth13-Jun-05 23:48 
GeneralRe: SetGradientWidth() Pin
pcmaan14-Jun-05 3:34
pcmaan14-Jun-05 3:34 
GeneralCooooool! Pin
Sergi Díaz13-Apr-04 5:40
Sergi Díaz13-Apr-04 5:40 
GeneralRe: Tracking tooltip doesn't track. Pin
Joel Holdsworth25-Mar-04 6:33
Joel Holdsworth25-Mar-04 6:33 
GeneralRe: Tracking tooltip doesn't track. Pin
e_roman25-Mar-04 22:15
e_roman25-Mar-04 22:15 
GeneralRe: Tracking tooltip doesn't track. Pin
David Stranz5-Nov-04 12:31
David Stranz5-Nov-04 12:31 
GeneralTracking tooltip doesn't track. Pin
e_roman25-Mar-04 6:23
e_roman25-Mar-04 6:23 
QuestionTransparency support? Pin
khan200019-Mar-04 13:40
khan200019-Mar-04 13:40 
AnswerRe: Transparency support? Pin
Joel Holdsworth20-Mar-04 22:36
Joel Holdsworth20-Mar-04 22:36 
Generalnice job! Pin
luminus_ak31-Jan-04 13:15
luminus_ak31-Jan-04 13:15 
GeneralNice control Pin
igorcerovsky6-Dec-03 7:29
igorcerovsky6-Dec-03 7:29 
GeneralRe: Nice control Pin
Joel Holdsworth6-Dec-03 7:34
Joel Holdsworth6-Dec-03 7:34 
GeneralRe: Nice control Pin
igorcerovsky7-Dec-03 4:50
igorcerovsky7-Dec-03 4:50 
GeneralPhotoshop Pin
NormDroid23-Oct-03 4:37
professionalNormDroid23-Oct-03 4:37 
Generalsmall demo fix Pin
Midnight4898-Oct-03 10:57
Midnight4898-Oct-03 10:57 
GeneralRe: small demo fix Pin
Philippe Lhoste8-Jun-04 2:49
Philippe Lhoste8-Jun-04 2:49 
GeneralRe: small demo fix Pin
Joel Holdsworth8-Jun-04 2:56
Joel Holdsworth8-Jun-04 2:56 
GeneralRe: small demo fix Pin
Philippe Lhoste8-Jun-04 3:29
Philippe Lhoste8-Jun-04 3:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.