WindowsXP-SP1/shell/comdlg32/color2.c

991 lines
28 KiB
C

/*++
Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
Module Name:
color2.c
Abstract:
This module implements the support for the Win32 color dialog.
Revision History:
--*/
// precompiled headers
#include "precomp.h"
#pragma hdrstop
#include "color.h"
// from pwin32.h
#define MMoveTo(hdc, x, y) MoveToEx(hdc, x, y, NULL)
////////////////////////////////////////////////////////////////////////////
//
// ChangeColorSettings
//
// Updates color shown.
//
////////////////////////////////////////////////////////////////////////////
VOID ChangeColorSettings(
register PCOLORINFO pCI)
{
register HDC hDC;
HWND hDlg = pCI->hDialog;
DWORD dwRGBcolor = pCI->currentRGB;
RGBtoHLS(dwRGBcolor);
if (gLum != pCI->currentLum)
{
hDC = GetDC(hDlg);
EraseLumArrow(hDC, pCI);
pCI->currentLum = gLum;
HLStoHLSPos(COLOR_LUM, pCI);
LumArrowPaint(hDC, pCI->nLumPos, pCI);
ReleaseDC(hDlg, hDC);
}
if ((gHue != pCI->currentHue) || (gSat != pCI->currentSat))
{
pCI->currentHue = gHue;
pCI->currentSat = gSat;
InvalidateRect(hDlg, (LPRECT)&pCI->rLumPaint, FALSE);
hDC = GetDC(hDlg);
EraseCrossHair(hDC, pCI);
HLStoHLSPos(COLOR_HUE, pCI);
HLStoHLSPos(COLOR_SAT, pCI);
CrossHairPaint(hDC, pCI->nHuePos, pCI->nSatPos, pCI);
ReleaseDC(hDlg, hDC);
}
}
////////////////////////////////////////////////////////////////////////////
//
// LumArrowPaint
//
////////////////////////////////////////////////////////////////////////////
VOID LumArrowPaint(
HDC hDC,
SHORT y,
PCOLORINFO pCI)
{
HBRUSH hBrush;
int x, h;
hBrush = SelectObject(hDC, GetSysColorBrush(COLOR_BTNTEXT));
for (x = pCI->rLumScroll.left + 2, h = 1;
x < pCI->rLumScroll.right - 2;
x++, h += 2)
{
PatBlt(hDC, x, y - h / 2, 1, h, PATCOPY);
}
SelectObject(hDC, hBrush);
}
////////////////////////////////////////////////////////////////////////////
//
// EraseLumArrow
//
////////////////////////////////////////////////////////////////////////////
VOID EraseLumArrow(
HDC hDC,
PCOLORINFO pCI)
{
HBRUSH hBrush;
RECT Rect;
hBrush = (HBRUSH)SendMessage( pCI->hDialog,
WM_CTLCOLORDLG,
(WPARAM)hDC,
(LPARAM)pCI->hDialog );
Rect.left = pCI->rLumScroll.left + 1;
Rect.right = pCI->rLumScroll.right;
Rect.top = pCI->nLumPos - (pCI->rLumScroll.right - pCI->rLumScroll.left);
Rect.bottom = pCI->nLumPos + (pCI->rLumScroll.right - pCI->rLumScroll.left) + 1;
FillRect(hDC, &Rect, hBrush);
}
////////////////////////////////////////////////////////////////////////////
//
// EraseCrossHair
//
////////////////////////////////////////////////////////////////////////////
VOID EraseCrossHair(
HDC hDC,
PCOLORINFO pCI)
{
HBITMAP hOldBitmap;
WORD distancex, distancey;
WORD topy, bottomy, leftx, rightx;
RECT rRainbow;
CopyRect(&rRainbow, &pCI->rRainbow);
distancex = (WORD)(10 * cxBorder);
distancey = (WORD)(10 * cyBorder);
topy = ((WORD)rRainbow.top > pCI->nSatPos - distancey)
? (WORD)rRainbow.top
: pCI->nSatPos - distancey;
bottomy = ((WORD)rRainbow.bottom < pCI->nSatPos + distancey)
? (WORD)rRainbow.bottom
: pCI->nSatPos + distancey;
leftx = ((WORD)rRainbow.left > pCI->nHuePos - distancex)
? (WORD)rRainbow.left
: pCI->nHuePos - distancex;
rightx = ((WORD)rRainbow.right < pCI->nHuePos + distancex)
? (WORD)rRainbow.right
: pCI->nHuePos + distancex;
hOldBitmap = SelectObject(hDCFastBlt, hRainbowBitmap);
BitBlt( hDC,
leftx,
topy,
rightx - leftx,
bottomy - topy,
hDCFastBlt,
leftx - (WORD)rRainbow.left,
topy - (WORD)rRainbow.top,
SRCCOPY );
SelectObject(hDCFastBlt, hOldBitmap);
}
////////////////////////////////////////////////////////////////////////////
//
// CrossHairPaint
//
////////////////////////////////////////////////////////////////////////////
VOID CrossHairPaint(
register HDC hDC,
SHORT x,
SHORT y,
PCOLORINFO pCI)
{
SHORT distancex, distancey;
SHORT topy, bottomy, topy2, bottomy2;
SHORT leftx, rightx, leftx2, rightx2;
RECT rRainbow;
CopyRect(&rRainbow, &pCI->rRainbow);
distancex = (SHORT)(5 * cxBorder);
distancey = (SHORT)(5 * cyBorder);
topy = (SHORT)((rRainbow.top > y - 2 * distancey)
? rRainbow.top
: y - 2 * distancey);
bottomy = (SHORT)((rRainbow.bottom < y + 2 * distancey)
? rRainbow.bottom
: y + 2 * distancey);
leftx = (SHORT)((rRainbow.left > x - 2 * distancex)
? rRainbow.left
: x - 2 * distancex);
rightx = (SHORT)((rRainbow.right < x + 2 * distancex)
? rRainbow.right
: x + 2 * distancex);
topy2 = (SHORT)((rRainbow.top > y - distancey)
? rRainbow.top
: y - distancey);
bottomy2 = (SHORT)((rRainbow.bottom < y + distancey)
? rRainbow.bottom
: y + distancey);
leftx2 = (SHORT)((rRainbow.left > x - distancex)
? rRainbow.left
: x - distancex);
rightx2 = (SHORT)((rRainbow.right < x + distancex)
? rRainbow.right
: x + distancex);
if (rRainbow.top < topy2)
{
if ((x - 1) >= rRainbow.left)
{
MMoveTo(hDC, x - 1, topy2);
LineTo(hDC, x - 1, topy);
}
if ((int)x < rRainbow.right)
{
MMoveTo(hDC, x, topy2);
LineTo(hDC, x, topy);
}
if ((x + 1) < rRainbow.right)
{
MMoveTo(hDC, x + 1, topy2);
LineTo(hDC, x + 1, topy);
}
}
if (rRainbow.bottom > bottomy2)
{
if ((x - 1) >= rRainbow.left)
{
MMoveTo(hDC, x - 1, bottomy2);
LineTo(hDC, x - 1, bottomy);
}
if ((int)x < rRainbow.right)
{
MMoveTo(hDC, x, bottomy2);
LineTo(hDC, x, bottomy);
}
if ((x + 1) < rRainbow.right)
{
MMoveTo(hDC, x + 1, bottomy2);
LineTo(hDC, x + 1, bottomy);
}
}
if (rRainbow.left < leftx2)
{
if ((y - 1) >= rRainbow.top)
{
MMoveTo(hDC, leftx2, y - 1);
LineTo(hDC, leftx, y - 1);
}
if ((int)y < rRainbow.bottom)
{
MMoveTo(hDC, leftx2, y);
LineTo(hDC, leftx, y);
}
if ((y + 1) < rRainbow.bottom)
{
MMoveTo(hDC, leftx2, y + 1);
LineTo(hDC, leftx, y + 1);
}
}
if (rRainbow.right > rightx2)
{
if ((y - 1) >= rRainbow.top)
{
MMoveTo(hDC, rightx2, y - 1);
LineTo(hDC, rightx, y - 1);
}
if ((int)y < rRainbow.bottom)
{
MMoveTo(hDC, rightx2, y);
LineTo(hDC, rightx, y);
}
if ((y + 1) < rRainbow.bottom)
{
MMoveTo(hDC, rightx2, y + 1);
LineTo(hDC, rightx, y + 1);
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// NearestSolid
//
////////////////////////////////////////////////////////////////////////////
VOID NearestSolid(
register PCOLORINFO pCI)
{
register HDC hDC;
HWND hDlg = pCI->hDialog;
hDC = GetDC(hDlg);
EraseCrossHair(hDC, pCI);
EraseLumArrow(hDC, pCI);
RGBtoHLS(pCI->currentRGB = GetNearestColor(hDC, pCI->currentRGB));
pCI->currentHue = gHue;
pCI->currentLum = gLum;
pCI->currentSat = gSat;
HLStoHLSPos(0, pCI);
CrossHairPaint(hDC, pCI->nHuePos, pCI->nSatPos, pCI);
LumArrowPaint(hDC, pCI->nLumPos, pCI);
ReleaseDC(hDlg, hDC);
SetHLSEdit(0, pCI);
SetRGBEdit(0, pCI);
InvalidateRect(hDlg, (LPRECT)&pCI->rColorSamples, FALSE);
InvalidateRect(hDlg, (LPRECT)&pCI->rLumPaint, FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// HLSPostoHLS
//
////////////////////////////////////////////////////////////////////////////
VOID HLSPostoHLS(
SHORT nHLSEdit,
register PCOLORINFO pCI)
{
switch (nHLSEdit)
{
case COLOR_HUE:
{
pCI->currentHue = (WORD)((pCI->nHuePos - pCI->rRainbow.left) *
(RANGE - 1) / (pCI->nHueWidth - 1));
break;
}
case COLOR_SAT:
{
pCI->currentSat = (WORD)(RANGE -
(pCI->nSatPos - pCI->rRainbow.top) *
RANGE / (pCI->nSatHeight - 1));
break;
}
case COLOR_LUM:
{
pCI->currentLum = (WORD)(RANGE -
(pCI->nLumPos - pCI->rLumPaint.top) *
RANGE / (pCI->nLumHeight - 1));
break;
}
default:
{
pCI->currentHue = (WORD)((pCI->nHuePos - pCI->rRainbow.left) *
(RANGE - 1) / pCI->nHueWidth);
pCI->currentSat = (WORD)(RANGE -
(pCI->nSatPos - pCI->rRainbow.top) *
RANGE / pCI->nSatHeight);
pCI->currentLum = (WORD)(RANGE -
(pCI->nLumPos - pCI->rLumPaint.top) *
RANGE / pCI->nLumHeight);
break;
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// HLStoHLSPos
//
////////////////////////////////////////////////////////////////////////////
VOID HLStoHLSPos(
SHORT nHLSEdit,
register PCOLORINFO pCI)
{
switch (nHLSEdit)
{
case ( COLOR_HUE ) :
{
pCI->nHuePos = (WORD)(pCI->rRainbow.left + pCI->currentHue *
pCI->nHueWidth / (RANGE - 1));
break;
}
case COLOR_SAT:
{
pCI->nSatPos = (WORD)(pCI->rRainbow.top +
(RANGE - pCI->currentSat) *
(pCI->nSatHeight - 1) / RANGE);
break;
}
case COLOR_LUM:
{
pCI->nLumPos = (WORD)(pCI->rLumPaint.top +
(RANGE - pCI->currentLum) *
(pCI->nLumHeight - 1) / RANGE);
break;
}
default:
{
pCI->nHuePos = (WORD)(pCI->rRainbow.left + pCI->currentHue *
pCI->nHueWidth / (RANGE - 1));
pCI->nSatPos = (WORD)(pCI->rRainbow.top +
(RANGE - pCI->currentSat) *
(pCI->nSatHeight - 1) / RANGE);
pCI->nLumPos = (WORD)(pCI->rLumPaint.top +
(RANGE - pCI->currentLum) *
(pCI->nLumHeight - 1) / RANGE);
break;
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// SetHLSEdit
//
////////////////////////////////////////////////////////////////////////////
VOID SetHLSEdit(
SHORT nHLSEdit,
register PCOLORINFO pCI)
{
register HWND hRainbowDlg = pCI->hDialog;
switch (nHLSEdit)
{
case ( COLOR_HUE ) :
{
SetDlgItemInt(hRainbowDlg, COLOR_HUE, pCI->currentHue, FALSE);
break;
}
case ( COLOR_SAT ) :
{
SetDlgItemInt(hRainbowDlg, COLOR_SAT, pCI->currentSat, FALSE);
break;
}
case ( COLOR_LUM ) :
{
SetDlgItemInt(hRainbowDlg, COLOR_LUM, pCI->currentLum, FALSE);
break;
}
default :
{
SetDlgItemInt(hRainbowDlg, COLOR_HUE, pCI->currentHue, FALSE);
SetDlgItemInt(hRainbowDlg, COLOR_SAT, pCI->currentSat, FALSE);
SetDlgItemInt(hRainbowDlg, COLOR_LUM, pCI->currentLum, FALSE);
break;
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// SetRGBEdit
//
////////////////////////////////////////////////////////////////////////////
VOID SetRGBEdit(
SHORT nRGBEdit,
PCOLORINFO pCI)
{
register HWND hRainbowDlg = pCI->hDialog;
DWORD rainbowRGB = pCI->currentRGB;
switch (nRGBEdit)
{
case ( COLOR_RED ) :
{
SetDlgItemInt(hRainbowDlg, COLOR_RED, GetRValue(rainbowRGB), FALSE);
break;
}
case ( COLOR_GREEN ) :
{
SetDlgItemInt(hRainbowDlg, COLOR_GREEN, GetGValue(rainbowRGB), FALSE);
break;
}
case ( COLOR_BLUE ) :
{
SetDlgItemInt(hRainbowDlg, COLOR_BLUE, GetBValue(rainbowRGB), FALSE);
break;
}
default :
{
SetDlgItemInt(hRainbowDlg, COLOR_RED, GetRValue(rainbowRGB), FALSE);
SetDlgItemInt(hRainbowDlg, COLOR_GREEN, GetGValue(rainbowRGB), FALSE);
SetDlgItemInt(hRainbowDlg, COLOR_BLUE, GetBValue(rainbowRGB), FALSE);
break;
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// InitRainbow
//
// Returns TRUE iff we make it.
//
////////////////////////////////////////////////////////////////////////////
BOOL InitRainbow(
register PCOLORINFO pCI)
{
HDC hDC;
WORD Sat, Hue;
HBITMAP hOldBitmap;
RECT Rect;
HBRUSH hbrSwipe;
WORD nHueWidth, nSatHeight;
register HWND hRainbowDlg = pCI->hDialog;
RGBtoHLS(pCI->currentRGB);
SetupRainbowCapture(pCI);
nHueWidth = pCI->nHueWidth = (WORD)(pCI->rRainbow.right -
pCI->rRainbow.left);
nSatHeight = pCI->nSatHeight = (WORD)(pCI->rRainbow.bottom -
pCI->rRainbow.top);
pCI->currentHue = gHue;
pCI->currentSat = gSat;
pCI->currentLum = gLum;
HLStoHLSPos(0, pCI);
SetRGBEdit(0, pCI);
SetHLSEdit(0, pCI);
if (!hRainbowBitmap)
{
hDC = GetDC(hRainbowDlg);
hRainbowBitmap = CreateCompatibleBitmap(hDC, nHueWidth, nSatHeight);
if (!hRainbowBitmap)
{
return (FALSE);
}
}
hOldBitmap = SelectObject(hDCFastBlt, hRainbowBitmap);
//
// NOTE: The final pass through this loop paints on and past the end
// of the selected bitmap. Windows is a good product, and doesn't
// let such foolishness happen.
//
Rect.bottom = 0;
for (Sat = RANGE; Sat > 0; Sat -= SATINC)
{
Rect.top = Rect.bottom;
Rect.bottom = (nSatHeight * RANGE - (Sat - SATINC) * nSatHeight) / RANGE;
Rect.right = 0;
for (Hue = 0; Hue < (RANGE - 1); Hue += HUEINC)
{
Rect.left = Rect.right;
Rect.right = ((Hue + HUEINC) * nHueWidth) / RANGE;
hbrSwipe = CreateSolidBrush(HLStoRGB(Hue, RANGE / 2, Sat));
FillRect(hDCFastBlt, &Rect, hbrSwipe);
DeleteObject(hbrSwipe);
}
}
SelectObject(hDCFastBlt, hOldBitmap);
ReleaseDC(hRainbowDlg, hDC);
UpdateWindow(hRainbowDlg);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// PaintRainbow
//
////////////////////////////////////////////////////////////////////////////
VOID PaintRainbow(
HDC hDC,
LPRECT lpRect,
register PCOLORINFO pCI)
{
HBITMAP hOldBitmap;
if (!hRainbowBitmap)
{
return;
}
hOldBitmap = SelectObject(hDCFastBlt, hRainbowBitmap);
BitBlt( hDC,
lpRect->left,
lpRect->top,
lpRect->right - lpRect->left,
lpRect->bottom - lpRect->top,
hDCFastBlt,
lpRect->left - pCI->rRainbow.left,
lpRect->top - pCI->rRainbow.top,
SRCCOPY );
SelectObject(hDCFastBlt, hOldBitmap);
CrossHairPaint(hDC, pCI->nHuePos, pCI->nSatPos, pCI);
UpdateWindow(pCI->hDialog);
}
////////////////////////////////////////////////////////////////////////////
//
// RainbowPaint
//
////////////////////////////////////////////////////////////////////////////
void RainbowPaint(
register PCOLORINFO pCI,
HDC hDC,
LPRECT lpPaintRect)
{
WORD Lum;
RECT Rect;
HBRUSH hbrSwipe;
//
// Paint the Current Color Sample.
//
if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&(pCI->rCurrentColor)))
{
hbrSwipe = CreateSolidBrush(pCI->currentRGB);
FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
DeleteObject(hbrSwipe);
}
//
// Paint the Nearest Pure Color Sample.
//
if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&(pCI->rNearestPure)))
{
hbrSwipe = CreateSolidBrush(GetNearestColor(hDC, pCI->currentRGB));
FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
DeleteObject(hbrSwipe);
}
//
// Paint the Luminosity Range.
//
if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&(pCI->rLumPaint)))
{
Rect.left = pCI->rLumPaint.left;
Rect.right = pCI->rLumPaint.right;
Rect.top = pCI->rLumPaint.bottom - LUMINC / 2;
Rect.bottom = pCI->rLumPaint.bottom;
hbrSwipe = CreateSolidBrush(HLStoRGB( pCI->currentHue,
0,
pCI->currentSat ));
FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
DeleteObject(hbrSwipe);
for (Lum = LUMINC; Lum < RANGE; Lum += LUMINC)
{
Rect.bottom = Rect.top;
Rect.top = (((pCI->rLumPaint.bottom + LUMINC / 2) * (DWORD)RANGE -
(Lum + LUMINC) * pCI->nLumHeight) / RANGE);
hbrSwipe = CreateSolidBrush(HLStoRGB( pCI->currentHue,
Lum,
pCI->currentSat ));
FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
DeleteObject(hbrSwipe);
}
Rect.bottom = Rect.top;
Rect.top = pCI->rLumPaint.top;
hbrSwipe = CreateSolidBrush(HLStoRGB( pCI->currentHue,
RANGE,
pCI->currentSat ));
FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
DeleteObject(hbrSwipe);
//
// Paint the bounding rectangle only when it might be necessary.
//
if (!EqualRect(lpPaintRect, (LPRECT)&pCI->rLumPaint))
{
hbrSwipe = SelectObject(hDC, GetStockObject(NULL_BRUSH));
Rectangle( hDC,
pCI->rLumPaint.left - 1,
pCI->rLumPaint.top - 1,
pCI->rLumPaint.right + 1,
pCI->rLumPaint.bottom + 1 );
SelectObject(hDC, hbrSwipe);
}
}
//
// Paint the Luminosity Arrow.
//
if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&pCI->rLumScroll))
{
LumArrowPaint(hDC, pCI->nLumPos, pCI);
}
if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&pCI->rRainbow))
{
PaintRainbow(hDC, (LPRECT)&Rect, pCI);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Color conversion routines --
//
// RGBtoHLS() takes a DWORD RGB value, translates it to HLS, and stores the
// results in the global vars H, L, and S. HLStoRGB takes the current values
// of H, L, and S and returns the equivalent value in an RGB DWORD. The vars
// H, L and S are written to only by 1) RGBtoHLS (initialization) or 2) the
// scrollbar handlers.
//
// A point of reference for the algorithms is Foley and Van Dam, pp. 618-19.
// Their algorithm is in floating point.
//
// There are potential roundoff errors lurking throughout here.
// (0.5 + x/y) without floating point,
// (x / y) phrased ((x + (y / 2)) / y) yields very small roundoff error.
// This makes many of the following divisions look funny.
//
//
// H,L, and S vary over 0 - HLSMAX.
// R,G, and B vary over 0 - RGBMAX.
// HLSMAX BEST IF DIVISIBLE BY 6.
// RGBMAX, HLSMAX must each fit in a byte.
//
// Hue is undefined if Saturation is 0 (grey-scale).
// This value determines where the Hue scrollbar is initially set for
// achromatic colors.
//
////////////////////////////////////////////////////////////////////////////
#define UNDEFINED (HLSMAX * 2 / 3)
////////////////////////////////////////////////////////////////////////////
//
// RGBtoHLS
//
////////////////////////////////////////////////////////////////////////////
VOID RGBtoHLS(
DWORD lRGBColor)
{
WORD R, G, B; // input RGB values
WORD cMax,cMin; // max and min RGB values
WORD cSum,cDif;
SHORT Rdelta, Gdelta, Bdelta; // intermediate value: % of spread from max
//
// get R, G, and B out of DWORD.
//
R = GetRValue(lRGBColor);
G = GetGValue(lRGBColor);
B = GetBValue(lRGBColor);
//
// Calculate lightness.
//
cMax = max(max(R, G), B);
cMin = min(min(R, G), B);
cSum = cMax + cMin;
gLum = (WORD)(((cSum * (DWORD)HLSMAX) + RGBMAX) / (2 * RGBMAX));
cDif = cMax - cMin;
if (!cDif)
{
//
// r = g = b --> Achromatic case.
//
gSat = 0; // saturation
gHue = UNDEFINED; // hue
}
else
{
//
// Chromatic case.
//
//
// Saturation.
//
// Note: Division by cSum is not a problem, as cSum can only
// be 0 if the RGB value is 0L, and that is achromatic.
//
if (gLum <= (HLSMAX / 2))
{
gSat = (WORD)(((cDif * (DWORD) HLSMAX) + (cSum / 2) ) / cSum);
}
else
{
gSat = (WORD)((DWORD)((cDif * (DWORD)HLSMAX) +
(DWORD)((2 * RGBMAX - cSum) / 2)) /
(2 * RGBMAX - cSum));
}
//
// Hue.
//
Rdelta = (SHORT)((((cMax - R) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
Gdelta = (SHORT)((((cMax - G) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
Bdelta = (SHORT)((((cMax - B) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
if (R == cMax)
{
gHue = Bdelta - Gdelta;
}
else if (G == cMax)
{
gHue = (WORD)((HLSMAX / 3) + Rdelta - Bdelta);
}
else // (B == cMax)
{
gHue = (WORD)(((2 * HLSMAX) / 3) + Gdelta - Rdelta);
}
if ((short)gHue < 0)
{
//
// This can occur when R == cMax and G is > B.
//
gHue += HLSMAX;
}
if (gHue >= HLSMAX)
{
gHue -= HLSMAX;
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// HueToRGB
//
// Utility routine for HLStoRGB.
//
////////////////////////////////////////////////////////////////////////////
WORD HueToRGB(
WORD n1,
WORD n2,
WORD hue)
{
if (hue >= HLSMAX)
{
hue -= HLSMAX;
}
//
// Return r, g, or b value from this tridrant.
//
if (hue < (HLSMAX / 6))
{
return ((WORD)(n1 + (((n2 - n1) * hue + (HLSMAX / 12)) / (HLSMAX / 6))));
}
if (hue < (HLSMAX/2))
{
return (n2);
}
if (hue < ((HLSMAX*2)/3))
{
return ((WORD)(n1 + (((n2 - n1) * (((HLSMAX * 2) / 3) - hue) +
(HLSMAX / 12)) / (HLSMAX / 6))));
}
else
{
return (n1);
}
}
////////////////////////////////////////////////////////////////////////////
//
// HLStoRGB
//
////////////////////////////////////////////////////////////////////////////
DWORD HLStoRGB(
WORD hue,
WORD lum,
WORD sat)
{
WORD R, G, B; // RGB component values
WORD Magic1, Magic2; // calculated magic numbers
if (sat == 0)
{
//
// Achromatic case.
//
R = G = B = (WORD)((lum * RGBMAX) / HLSMAX);
}
else
{
//
// Chromatic case
//
//
// Set up magic numbers.
//
if (lum <= (HLSMAX / 2))
{
Magic2 = (WORD)((lum * ((DWORD)HLSMAX + sat) + (HLSMAX / 2)) / HLSMAX);
}
else
{
Magic2 = lum + sat -
(WORD)(((lum * sat) + (DWORD)(HLSMAX / 2)) / HLSMAX);
}
Magic1 = (WORD)(2 * lum - Magic2);
//
// Get RGB, change units from HLSMAX to RGBMAX.
//
R = (WORD)(((HueToRGB(Magic1, Magic2, (WORD)(hue + (HLSMAX / 3))) *
(DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
G = (WORD)(((HueToRGB(Magic1, Magic2, hue) *
(DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
B = (WORD)(((HueToRGB(Magic1, Magic2, (WORD)(hue - (HLSMAX / 3))) *
(DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
}
return (RGB(R, G, B));
}
////////////////////////////////////////////////////////////////////////////
//
// RGBEditChange
//
// Checks the edit box for a valid entry and updates the Hue, Sat, and Lum
// edit controls if appropriate. Also updates Lum picture and current
// color sample.
//
// nDlgID - Dialog ID of Red, Green or Blue edit control.
//
////////////////////////////////////////////////////////////////////////////
SHORT RGBEditChange(
SHORT nDlgID,
PCOLORINFO pCI)
{
BOOL bOK; // check that value in edit control is uint
BYTE *currentValue; // pointer to byte in RGB to change (or reset)
SHORT nVal;
TCHAR cEdit[3];
register HWND hDlg = pCI->hDialog;
currentValue = (BYTE *)&pCI->currentRGB;
switch (nDlgID)
{
case ( COLOR_GREEN ) :
{
currentValue++;
break;
}
case ( COLOR_BLUE ) :
{
currentValue += 2;
break;
}
}
nVal = (SHORT)GetDlgItemInt(hDlg, nDlgID, (BOOL FAR *)&bOK, FALSE);
if (bOK)
{
if (nVal > RGBMAX)
{
nVal = RGBMAX;
SetDlgItemInt(hDlg, nDlgID, nVal, FALSE);
}
if (nVal != (SHORT) *currentValue)
{
*currentValue = LOBYTE(nVal);
ChangeColorSettings(pCI);
SetHLSEdit(nDlgID, pCI);
}
}
else if (GetDlgItemText(hDlg, nDlgID, (LPTSTR)cEdit, 2))
{
SetRGBEdit(nDlgID, pCI);
SendDlgItemMessage(hDlg, nDlgID, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
}
return (SHORT)(bOK ? TRUE : FALSE);
}