A one function call to replace the old Win32 picker with a modern one with RGB, HSL, alpha and picker support
Introduction
Very often, I want a picker or a nice HSL slider or an alpha channel. Here is a one-file library for your code, which works with Direct2D and provides a modern interface for picking a color.
Using the Code
You have a single function call:
#include "colorpick.hpp"
COLORPICK p;
D2D1_COLOR_F c1 = {1.0f,0,0,1.0f};
HRESULT hr = p.Show(0, c);
if (hr == S_OK) { ... }
and possibly, passing an optional structure with more options:
struct COLORPICKOPT
{
bool Alpha = 1;
int Mode = 1;
float rsl = 0.1f;
bool Dlg = 1;
bool LUpdate = 0;
bool AlsoUseSystem = 1;
bool UsePicker = 1;
float Resolution = 0.1f;
};
Deep Into It
RGB and HSL
Let's deep into it. Conversions from RGB
to HSL
and vice versa is done with the fromRGBtoHSL
and fromHSLtoRGB
functions - see more.
Drawing
All drawing is done by a ID2D1HwndRenderTarget
which will be created on WM_PAINT
. This, depending on the Mode used, will:
- Draw 117 squares with predefined colors for RGB mode (taken from here).
- Draw a color wheel in HSL mode. The color wheel is drawn pixel by pixel and line by line. Each line has a specified
Hue
value which , when rotating, takes a 360 max value, i.e., the entire circle. The radius of this line is the saturation of the color.The Hue slider is drawn with a 360-value stop Direct2D
Linear Brush.
The hue bar can be drawn with a linear brush:
std::vector<D2D1_GRADIENT_STOP> gst(360);
for (int i = 0; i < 360; i++)
{
float hsl[3] = { 1,1,L };
hsl[0] = (360 - i) / 360.0f;
hsl[0] *= 6.0f;
float rgb[3] = {};
fromHSLtoRGB(hsl, rgb);
gst[i].position = i / 360.0f;
gst[i].color.r = rgb[0];
gst[i].color.g = rgb[1];
gst[i].color.b = rgb[2];
gst[i].color.a = 1.0f;
}
pGradientStops = 0;
lbr = 0;
p->CreateGradientStopCollection(
gst.data(),
360,
D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE_CLAMP,
&pGradientStops
);
p->CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(
D2D1::Point2F(LRect.left, LRect.top),
D2D1::Point2F(LRect.right, LRect.bottom)),
pGradientStops,
&lbr);
This linear gradient brush can be used now to draw a hue bar. The other bars (S,L or R,G,B, Alpha) are plain solid brushes.
Keyboard
WM_COMMAND
and WM_KEYDOWN
are processed to handle IDOK
/IDCANCEL
and VK_RETURN
/VK_ESCAPE
to submit or cancel the color picking.
Inline Editing
Clicking on the Alpha value, the R,G,B (in RGB mode) or in H,S,L (in HSL mode) values displays an inline edit box (with ES_NUMBER
) which allows you to enter a value (0-350 for H, 0-100 for alpha, 0-255 for others). When the edit is active, VK_RETURN
/VK_ESCAPE
act on the editing value.
Mouse Actions
Click on:
- the RGB values to select the clicked color
- the color wheel to selected the clicked color
- the R,G,B or H,S,L bars to set the value
- the Alpha, R,G,B or H,S,L values to inline edit the values
Drag the:
- RGB or HSL bars to set the value
- Color Wheel to set the HSL value
Wheel actions:
- on the bars to rotate the value
- on the RGB/HSL values to rotate the value
The System Dialog
The common dialog picker may be used for those that are used to it. Pressing the "S
" button will display the common dialog and set/get the value selected.
The Picker
Very often, you want to pick the color you see, but you can't name it. The control includes a picker which you can click on, then drag it on the screen (outside the color picker) and it captures any color beneath it. It uses the SetCapture
API.
The Parameters
- bool
Alpha
= 1; By default, the color picker also shows alpha controls. If you don't want to alter the Alpha, pass 0 to this. The color returned will have an alpha of 1.0f. - int
Mode
= 1; // Starts with RGB. If 0, starts with HSL. - bool
Dlg
= 1; // If 0, it's a windows instead of a dialog. - bool
LUpdate
= 0; // If 1, on setting the L the color wheel is updated (slower) - bool
AlsoUseSystem
= 1; // Displays the "S" button for allowing the usage of the system common control - bool
UsePicker
= 1; // Displays the cross for enabling the picker - float
Resolution
= 0.1f; // Resolution of the color wheel (smaller value -> smaller speed -> better view)
The Project
#include
colorpick.hpp in your application and you are ready. The github repo includes an example solution which you can study.
History
- 2nd June, 2020 - First release