You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
990 lines
28 KiB
990 lines
28 KiB
/*++
|
|
|
|
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);
|
|
}
|