|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThere are already several articles here on CodeProject describing different types of color pickers, and here is yet another example. I needed a color picker for a project I was working on, and I wanted something different from the standard
Color Wheel – HSL ColorThe color in the color wheel is represented by its hue and saturation value, where hue is the angle (0-360) with red being 0°, green 120° and blue 240°, and where the saturation is the distance from the center, where 0 (center) is white and 1 (on the circumference) is the fully saturated color. The After a bit of online searching, I came across this article in Wikipedia which explains the HSL color space and most conveniently also includes the equations for converting between RGB - HSL and vice versa. I created the The void RecalcWheelPoints()
…
double fullcircle = 360;
double step = 5;
while (angle < fullcircle)
{
double angleR = angle * (Math.PI/180);
double x = center.X + Math.Cos(angleR) * radius;
double y = center.Y - Math.Sin(angleR) * radius;
m_path.Add(new PointF((float)x,(float)y));
m_colors.Add(new HSLColor(angle, 1, 0.5).Color);
angle += step;
}
In this loop, the Get and Set the Color SelectorCalculating the position for the color selector is done in Calculating the selected color from the mouse position when the selector is moved around the wheel is done in void SetColor(PointF mousepoint)
{
PointF center = Util.Center(ColorWheelRectangle);
double radius = Radius(ColorWheelRectangle);
double dx = Math.Abs(mousepoint.X - center.X);
double dy = Math.Abs(mousepoint.Y - center.Y);
double angle = Math.Atan(dy / dx) / Math.PI * 180;
double dist = Math.Pow((Math.Pow(dx, 2) + (Math.Pow(dy, 2))), 0.5);
double saturation = dist/radius;
if (dist < 6)
saturation = 0; // snap to center
if (mousepoint.X < center.X)
angle = 180 - angle;
if (mousepoint.Y > center.Y)
angle = 360 - angle;
SelectedHSLColor = new HSLColor(angle, saturation, SelectedHSLColor.Lightness);
}
Lightness / Opacity SliderFor the lightness slider, I first had to write a label class which lets you specify the angle at which the text is drawn. This is done with the LabelRotate.OnPaint
e.Graphics.TranslateTransform(center.X, center.Y);
e.Graphics.RotateTransform(TextAngle);
e.Graphics.DrawString(Text, Font, b, new PointF(0,0), format);
e.Graphics.ResetTransform();
The next step in creating the slider was to create a color bar which would show a gradient color going from black to the selected color and into white. The Util.Draw3ColorBar(Graphics dc, RectangleF r, Orientation orientation,
Color c1, Color c2, Color c3)
The base class slider control is To get and set the value of the slider control use the Eye Dropper
The eye dropper control To get the color off the screen is very simple. A bitmap with the size of the source rectangle (15x15) is created and then the screen is copied into this bitmap, this is done in void GetSnapshot()
{
…
using (Graphics dc = Graphics.FromImage(m_snapshot))
{
dc.CopyFromScreen(p, new Point(0,0), m_snapshot.Size);
Refresh();
PointF center = Util.Center(new RectangleF
(0, 0, m_snapshot.Size.Width, m_snapshot.Size.Height));
Color c = m_snapshot.GetPixel((int)Math.Round(center.X),
(int)Math.Round(center.Y));
…
}
}
The location of the ‘pixel indicator’ shown at the center of the image while capturing had to be fine tuned by one pixel to show at the right location, so if the control has any other size, the pixel indicator might be off. I did run into one issue while writing this. By default the GDI e.Graphics.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
Color Table
The color table class I chose to have 16 columns and in the first row, show 10 gray scale colors ranging from black to white and 6 base colors and then 48 colors (3 rows) spanning from hue 0 to 360 at saturation 1 and another 3 rows with saturation 0.5. The last color in the table is the custom color which is added and changed whenever the color is changed in either the color wheel or through the eye dropper. Putting It All TogetherThe actual color picker control, the class that ties these controls together is the public Color SelectedColor
ComboBox with DropdownContainerI wanted the color picker control as the ‘dropdown’ part of the combo box instead of a modal dialog. I found a strange behavior when trying to use a derived The base class for this control is For drawing the control I use protected override void OnPaint(PaintEventArgs e)
{
…
ComboBoxRenderer.DrawTextBox(e.Graphics, r,
System.Windows.Forms.VisualStyles.ComboBoxState.Normal);
…
r = ButtonRectangle;
ComboBoxRenderer.DrawDropDownButton
(e.Graphics, r, System.Windows.Forms.VisualStyles.ComboBoxState.Normal);
…
DrawItem(e.Graphics, ItemRectangle);
if (Focused)
ControlPaint.DrawFocusRectangle(e.Graphics, ItemRectangle);
…
}
On a normal To capture the keyboard Esc and Enter was a little more complicated. For this, I needed to install a hook (done in Hook). I found this article which explains how to set up hook in C#, however I couldn't get it to work right as it would either throw exceptions or not install the hook (returning 0). The answer was found in this article, where it is explained that the hook will only be installed if the ‘host process’ is disabled, and once disabled, everything worked as expected. EnhancementsThere are a couple of enhancements I can think of which I might add later on.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||