1342 lines
33 KiB
C
1342 lines
33 KiB
C
/***************************************************************************
|
|
* *
|
|
* MODULE : ColorWP.c *
|
|
* *
|
|
* DESCRIPTION : Window function for the colors window and related fns. *
|
|
* *
|
|
* FUNCTIONS : ColorWP () - Window function for colors *
|
|
* window. *
|
|
* *
|
|
* ComputeInverseColor() - Gets the inverse RGB of a given *
|
|
* RGB value *
|
|
* *
|
|
* HISTORY : 6/21/89 - adapted from pBrush - LR *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "imagedit.h"
|
|
#include "dialogs.h"
|
|
|
|
#include <commdlg.h>
|
|
|
|
|
|
STATICFN VOID NEAR ColorInit(HWND hwnd);
|
|
STATICFN VOID NEAR ColorProcessCommand(HWND hwnd, INT idCtrl, INT NotifyCode);
|
|
STATICFN VOID NEAR ColorBoxPaint(HDC hdc);
|
|
STATICFN VOID NEAR DrawColorRect(HDC hdc, DWORD rgb, INT x, INT y,
|
|
INT cx, INT cy, HDC hdcMem, BOOL fMonoOK);
|
|
STATICFN VOID NEAR MyRectangle(HDC hdc, INT left, INT top, INT right,
|
|
INT bottom, HDC hdcMem, BOOL fMonoOK);
|
|
STATICFN VOID NEAR ColorBoxClicked(UINT msg, PPOINT ppt);
|
|
STATICFN BOOL NEAR ColorBoxHitTest(PPOINT ppt, PINT piColor, PINT pfMode);
|
|
STATICFN VOID NEAR ColorLRPaint(HWND hwnd, HDC hdc);
|
|
STATICFN VOID NEAR ColorLRDrawSamples(HDC hdc, PRECT prc, BOOL fLeft);
|
|
STATICFN VOID NEAR ColorLRUpdate(BOOL fLeft);
|
|
STATICFN VOID NEAR ColorEdit(VOID);
|
|
STATICFN VOID NEAR SetLeftColor(INT iColor, INT iMode);
|
|
STATICFN VOID NEAR SetRightColor(INT iColor, INT iMode);
|
|
STATICFN HBRUSH NEAR MyCreateSolidBrush(DWORD rgb);
|
|
STATICFN DWORD NEAR MyGetNearestColor(DWORD rgb, BOOL fMonoOK);
|
|
STATICFN DWORD NEAR ComputeInverseColor(DWORD rgb);
|
|
|
|
/*
|
|
* Width/height of a single color square.
|
|
*/
|
|
static INT gcxColorBox;
|
|
|
|
/*
|
|
* Vertical offset within the color box control to where to start the
|
|
* top row of color squares (the color squares are vertically centered
|
|
* within the color box control).
|
|
*/
|
|
static INT gyColorBoxStart;
|
|
|
|
/*
|
|
* Number of colors and image type. These globals are used by the
|
|
* the color palette routines to know what mode the color palette
|
|
* is in.
|
|
*/
|
|
static INT gnColorPalColors;
|
|
static INT giColorPalType;
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
* ColorShow
|
|
*
|
|
* This function shows or hides the color palette.
|
|
*
|
|
* History:
|
|
*
|
|
****************************************************************************/
|
|
|
|
VOID ColorShow(
|
|
BOOL fShow)
|
|
{
|
|
if (fShow)
|
|
ShowWindow(ghwndColor, SW_SHOWNA);
|
|
else
|
|
ShowWindow(ghwndColor, SW_HIDE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorDlgProc
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
DIALOGPROC ColorDlgProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LONG lParam)
|
|
{
|
|
switch (msg) {
|
|
case WM_INITDIALOG:
|
|
ColorInit(hwnd);
|
|
|
|
/*
|
|
* Return TRUE so that the dialog manager does NOT set the focus
|
|
* for me. This prevents the status window from initially having
|
|
* the focus when the editor is started.
|
|
*/
|
|
return TRUE;
|
|
|
|
case WM_ACTIVATE:
|
|
if (GET_WM_ACTIVATE_STATE(wParam, lParam))
|
|
gidCurrentDlg = DID_COLOR;
|
|
|
|
break;
|
|
|
|
case WM_CTLCOLOR:
|
|
case WM_CTLCOLORBTN:
|
|
case WM_CTLCOLORDLG:
|
|
case WM_CTLCOLORSTATIC:
|
|
switch (GET_WM_CTLCOLOR_TYPE(wParam, lParam, msg)) {
|
|
case CTLCOLOR_BTN:
|
|
case CTLCOLOR_DLG:
|
|
return (BOOL)GetStockObject(LTGRAY_BRUSH);
|
|
|
|
case CTLCOLOR_STATIC:
|
|
SetBkColor(GET_WM_CTLCOLOR_HDC(wParam, lParam, msg),
|
|
RGB_LIGHTGRAY);
|
|
return (BOOL)GetStockObject(LTGRAY_BRUSH);
|
|
}
|
|
|
|
return (BOOL)NULL;
|
|
|
|
case WM_PAINT:
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
DrawMarginBorder(hwnd, hdc);
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
ColorProcessCommand(hwnd,
|
|
GET_WM_COMMAND_ID(wParam, lParam),
|
|
GET_WM_COMMAND_CMD(wParam, lParam));
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
/*
|
|
* The user closed the color palette from the system menu.
|
|
* Hide the window (we don't actually destroy it so
|
|
* that it will appear in the same spot when they show
|
|
* it again).
|
|
*/
|
|
ColorShow(FALSE);
|
|
gfShowColor = FALSE;
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
RECT rc;
|
|
|
|
/*
|
|
* Save the position of the color palette.
|
|
*/
|
|
GetWindowRect(hwnd, &rc);
|
|
WriteWindowPos(&rc, FALSE, szColorPos);
|
|
|
|
/*
|
|
* Null out the global window handle for the color palette
|
|
* for safety's sake.
|
|
*/
|
|
ghwndColor = NULL;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorInit
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorInit(
|
|
HWND hwnd)
|
|
{
|
|
RECT rc;
|
|
|
|
/*
|
|
* Get the dimension of a single color square, and the vertical
|
|
* offset to where the top of the squares are.
|
|
*/
|
|
GetWindowRect(GetDlgItem(hwnd, DID_COLORBOX), &rc);
|
|
gcxColorBox = (rc.right - rc.left) / COLORCOLS;
|
|
gyColorBoxStart = ((rc.right - rc.left) - (gcxColorBox * COLORCOLS)) / 2;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorProcessCommand
|
|
*
|
|
*
|
|
* Arguments:
|
|
* HWND hwnd - The window handle.
|
|
* INT idCtrl - The id of the control the WM_COMMAND is for.
|
|
* INT NotifyCode - The control's notification code.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorProcessCommand(
|
|
HWND hwnd,
|
|
INT idCtrl,
|
|
INT NotifyCode)
|
|
{
|
|
switch (idCtrl) {
|
|
case DID_COLOREDIT:
|
|
ColorEdit();
|
|
break;
|
|
|
|
case DID_COLORDEFAULT:
|
|
if (gfModeLeft == MODE_COLOR) {
|
|
gargbColor[giColorLeft] = gargbDefaultColor[giColorLeft];
|
|
InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX),
|
|
NULL, TRUE);
|
|
SetLeftColor(giColorLeft, gfModeLeft);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorBoxWndProc
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
WINDOWPROC ColorBoxWndProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LONG lParam)
|
|
{
|
|
POINT pt;
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
INT iColor;
|
|
INT iMode;
|
|
|
|
switch (msg) {
|
|
case WM_PAINT:
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
ColorBoxPaint(hdc);
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
MPOINT2POINT(MAKEMPOINT(lParam), pt);
|
|
ColorBoxClicked(msg, &pt);
|
|
break;
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
MPOINT2POINT(MAKEMPOINT(lParam), pt);
|
|
if (ColorBoxHitTest(&pt, &iColor, &iMode))
|
|
ColorEdit();
|
|
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorBoxPaint
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorBoxPaint(
|
|
HDC hdc)
|
|
{
|
|
HDC hdcMem;
|
|
HBITMAP hbmMem;
|
|
INT i;
|
|
INT x;
|
|
INT y;
|
|
INT cx = gcxColorBox + 1;
|
|
INT cy = gcxColorBox + 1;
|
|
|
|
if (giColorPalType != FT_BITMAP) {
|
|
x = 0;
|
|
y = gyColorBoxStart;
|
|
DrawColorRect(hdc, grgbScreen, x, y, cx, cy, NULL, FALSE);
|
|
y += gcxColorBox;
|
|
DrawColorRect(hdc, grgbInverse, x, y, cx, cy, NULL, FALSE);
|
|
}
|
|
|
|
if (!(hdcMem = CreateCompatibleDC(hdc)))
|
|
return;
|
|
|
|
/*
|
|
* Create a bitmap. It will have the same number of colors as the
|
|
* current image.
|
|
*/
|
|
if (!(hbmMem = MyCreateBitmap(hdc, cx, cy, gnColorPalColors))) {
|
|
DeleteDC(hdcMem);
|
|
return;
|
|
}
|
|
|
|
SelectObject(hdcMem, hbmMem);
|
|
|
|
x = gcxColorBox * 2;
|
|
y = gyColorBoxStart;
|
|
|
|
for (i = 1; i <= COLORSMAX; i++) {
|
|
DrawColorRect(hdc, gargbCurrent[i - 1], x, y, cx, cy, hdcMem, TRUE);
|
|
|
|
if (i % COLORROWS) {
|
|
y += gcxColorBox;
|
|
}
|
|
else {
|
|
x += gcxColorBox;
|
|
y = gyColorBoxStart;
|
|
}
|
|
}
|
|
|
|
DeleteDC(hdcMem);
|
|
DeleteObject(hbmMem);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* DrawColorRect
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR DrawColorRect(
|
|
HDC hdc,
|
|
DWORD rgb,
|
|
INT x,
|
|
INT y,
|
|
INT cx,
|
|
INT cy,
|
|
HDC hdcMem,
|
|
BOOL fMonoOK)
|
|
{
|
|
HBRUSH hbr;
|
|
HBRUSH hbrOld;
|
|
|
|
hbr = CreateSolidBrush(rgb);
|
|
hbrOld = SelectObject(hdc, hbr);
|
|
MyRectangle(hdc, x, y, x + cx, y + cy, hdcMem, fMonoOK);
|
|
SelectObject(hdc, hbrOld);
|
|
DeleteObject(hbr);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* MyRectangle
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR MyRectangle(
|
|
HDC hdc,
|
|
INT left,
|
|
INT top,
|
|
INT right,
|
|
INT bottom,
|
|
HDC hdcMem,
|
|
BOOL fMonoOK)
|
|
{
|
|
HBITMAP hbmMem;
|
|
HBRUSH hbr;
|
|
HPEN hpen;
|
|
HBRUSH hbrOld;
|
|
HPEN hpenOld;
|
|
BOOL fDCCreated = FALSE;
|
|
INT cx = right - left;
|
|
INT cy = bottom - top;
|
|
INT nColors;
|
|
|
|
/*
|
|
* Do they want us to create the memory DC and bitmap for them?
|
|
*/
|
|
if (!hdcMem) {
|
|
if (!(hdcMem = CreateCompatibleDC(hdc)))
|
|
return;
|
|
|
|
/*
|
|
* Create a bitmap. It will be monochrome if in 2 color mode
|
|
* and monochrome is ok, otherwise it will be 16 color.
|
|
*/
|
|
nColors = gnColorPalColors;
|
|
if (!fMonoOK)
|
|
nColors = 16;
|
|
|
|
if (!(hbmMem = MyCreateBitmap(hdc, cx, cy, nColors))) {
|
|
DeleteDC(hdcMem);
|
|
return;
|
|
}
|
|
|
|
SelectObject(hdcMem, hbmMem);
|
|
fDCCreated = TRUE;
|
|
}
|
|
|
|
/*
|
|
* Extract the current pen and brush out of the passed in DC.
|
|
*/
|
|
hbr = SelectObject(hdc, GetStockObject(NULL_BRUSH));
|
|
hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
|
|
|
|
/*
|
|
* Select them into the memory DC.
|
|
*/
|
|
hbrOld = SelectObject(hdcMem, hbr);
|
|
hpenOld = SelectObject(hdcMem, hpen);
|
|
|
|
/*
|
|
* Draw the rectangle in the memory bitmap.
|
|
*/
|
|
Rectangle(hdcMem, 0, 0, cx, cy);
|
|
|
|
/*
|
|
* Unselect the pen and brush from the memory DC.
|
|
*/
|
|
SelectObject(hdcMem, hbrOld);
|
|
SelectObject(hdcMem, hpenOld);
|
|
|
|
/*
|
|
* Restore the pen and brush to the original DC.
|
|
*/
|
|
SelectObject(hdc, hbr);
|
|
SelectObject(hdc, hpen);
|
|
|
|
/*
|
|
* Blit the memory image to the passed in DC.
|
|
*/
|
|
BitBlt(hdc, left, top, cx, cy, hdcMem, 0, 0, SRCCOPY);
|
|
|
|
if (fDCCreated) {
|
|
DeleteDC(hdcMem);
|
|
DeleteObject(hbmMem);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorBoxClicked
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorBoxClicked(
|
|
UINT msg,
|
|
PPOINT ppt)
|
|
{
|
|
INT iColor;
|
|
INT iMode;
|
|
|
|
if (ColorBoxHitTest(ppt, &iColor, &iMode)) {
|
|
switch (msg) {
|
|
case WM_LBUTTONDOWN:
|
|
SetLeftColor(iColor, iMode);
|
|
break;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
SetRightColor(iColor, iMode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorBoxHitTest
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN BOOL NEAR ColorBoxHitTest(
|
|
PPOINT ppt,
|
|
PINT piColor,
|
|
PINT pfMode)
|
|
{
|
|
INT iCol;
|
|
INT iRow;
|
|
INT iBox;
|
|
|
|
if (ppt->y < gyColorBoxStart)
|
|
return FALSE;
|
|
|
|
iCol = ppt->x / gcxColorBox;
|
|
iRow = (ppt->y - gyColorBoxStart) / gcxColorBox;
|
|
|
|
if (iCol >= (COLORSMAX / COLORROWS) + 2 || iRow >= COLORROWS)
|
|
return FALSE;
|
|
|
|
iBox = iRow + (iCol * COLORROWS);
|
|
|
|
switch (iBox) {
|
|
case 0:
|
|
if (giColorPalType == FT_BITMAP)
|
|
return FALSE;
|
|
|
|
*piColor = 0;
|
|
*pfMode = MODE_SCREEN;
|
|
return TRUE;
|
|
|
|
case 1:
|
|
if (giColorPalType == FT_BITMAP)
|
|
return FALSE;
|
|
|
|
*piColor = 0;
|
|
*pfMode = MODE_INVERSE;
|
|
return TRUE;
|
|
|
|
case 2:
|
|
case 3:
|
|
return FALSE;
|
|
|
|
default:
|
|
*piColor = iBox - (COLORROWS * 2);
|
|
*pfMode = MODE_COLOR;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorLRWndProc
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
WINDOWPROC ColorLRWndProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LONG lParam)
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
|
|
switch (msg) {
|
|
case WM_PAINT:
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
ColorLRPaint(hwnd, hdc);
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorLRPaint
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorLRPaint(
|
|
HWND hwnd,
|
|
HDC hdc)
|
|
{
|
|
RECT rc;
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
DrawSunkenRect(&rc, hdc);
|
|
ColorLRDrawSamples(hdc, &rc, TRUE);
|
|
ColorLRDrawSamples(hdc, &rc, FALSE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorLRDrawSamples
|
|
*
|
|
* Draws the sample colors in the Color Left-Right control.
|
|
*
|
|
* Arguments:
|
|
* HDC hdc - DC to draw into.
|
|
* PRECT prc - Rectangle of color sample control. The samples will
|
|
* be centered within this with an appropriate margin.
|
|
* BOOL fLeft - TRUE if the left sample is to be drawn, FALSE for the right.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorLRDrawSamples(
|
|
HDC hdc,
|
|
PRECT prc,
|
|
BOOL fLeft)
|
|
{
|
|
INT xLeftStart;
|
|
INT xRightStart;
|
|
INT ySolidStart;
|
|
INT yDitherStart;
|
|
INT cx;
|
|
INT cy;
|
|
HBRUSH hbrOld;
|
|
HPEN hpenOld;
|
|
BOOL fMonoOK;
|
|
|
|
/*
|
|
* The width and height of each square includes the border.
|
|
*/
|
|
cx = ((prc->right - prc->left) - (6 * PALETTEMARGIN)) / 2;
|
|
cy = ((prc->bottom - prc->top) - (4 * PALETTEMARGIN)) / 2;
|
|
|
|
xLeftStart = prc->left + (PALETTEMARGIN * 2) + 1;
|
|
xRightStart = xLeftStart + cx + (PALETTEMARGIN * 2);
|
|
|
|
ySolidStart = prc->top + (PALETTEMARGIN * 2) + 1;
|
|
yDitherStart = ySolidStart - 1 + cy;
|
|
|
|
/*
|
|
* Draw either the left or the right color sample.
|
|
*/
|
|
if (fLeft) {
|
|
fMonoOK = (gfModeLeft == MODE_COLOR) ? TRUE : FALSE;
|
|
|
|
/*
|
|
* Draw the solid color.
|
|
*/
|
|
hbrOld = SelectObject(hdc, ghbrLeftSolid);
|
|
hpenOld = SelectObject(hdc, GetStockObject(NULL_PEN));
|
|
MyRectangle(hdc, xLeftStart, ySolidStart,
|
|
xLeftStart + cx, yDitherStart + 1, NULL, fMonoOK);
|
|
|
|
/*
|
|
* Draw the true color (may be dithered).
|
|
*/
|
|
SelectObject(hdc, ghbrLeft);
|
|
MyRectangle(hdc, xLeftStart, yDitherStart,
|
|
xLeftStart + cx, yDitherStart + cy, NULL, fMonoOK);
|
|
}
|
|
else {
|
|
fMonoOK = (gfModeRight == MODE_COLOR) ? TRUE : FALSE;
|
|
|
|
hbrOld = SelectObject(hdc, ghbrRightSolid);
|
|
hpenOld = SelectObject(hdc, GetStockObject(NULL_PEN));
|
|
MyRectangle(hdc, xRightStart, ySolidStart,
|
|
xRightStart + cx, yDitherStart + 1, NULL, fMonoOK);
|
|
|
|
SelectObject(hdc, ghbrRight);
|
|
MyRectangle(hdc, xRightStart, yDitherStart,
|
|
xRightStart + cx, yDitherStart + cy, NULL, fMonoOK);
|
|
}
|
|
|
|
/*
|
|
* Now draw the outline rectangle.
|
|
*/
|
|
SelectObject(hdc, GetStockObject(BLACK_PEN));
|
|
SelectObject(hdc, GetStockObject(NULL_BRUSH));
|
|
|
|
if (fLeft) {
|
|
Rectangle(hdc, xLeftStart - 1, ySolidStart - 1,
|
|
xLeftStart + cx, yDitherStart + cy);
|
|
}
|
|
else {
|
|
Rectangle(hdc, xRightStart - 1, ySolidStart - 1,
|
|
xRightStart + cx, yDitherStart + cy);
|
|
}
|
|
|
|
/*
|
|
* Clean up.
|
|
*/
|
|
SelectObject(hdc, hpenOld);
|
|
SelectObject(hdc, hbrOld);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorLRUpdate
|
|
*
|
|
* Called when the left or right color has been changed. This function
|
|
* will cause the specified color sample to be updated in the color palette.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorLRUpdate(
|
|
BOOL fLeft)
|
|
{
|
|
RECT rc;
|
|
HWND hwndLR;
|
|
HDC hdc;
|
|
|
|
hwndLR = GetDlgItem(ghwndColor, DID_COLORLR);
|
|
GetClientRect(hwndLR, &rc);
|
|
hdc = GetDC(hwndLR);
|
|
ColorLRDrawSamples(hdc, &rc, fLeft);
|
|
ReleaseDC(hwndLR, hdc);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ColorEdit
|
|
*
|
|
* This function calls the standard color chooser dialog to get a
|
|
* new color for the selected palette entry.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR ColorEdit(VOID)
|
|
{
|
|
/*
|
|
* This array of custom colors is initialized to all white colors.
|
|
* The custom colors will be remembered between calls, but not
|
|
* between sessions.
|
|
*/
|
|
static DWORD argbCust[16] = {
|
|
RGB(255, 255, 255), RGB(255, 255, 255),
|
|
RGB(255, 255, 255), RGB(255, 255, 255),
|
|
RGB(255, 255, 255), RGB(255, 255, 255),
|
|
RGB(255, 255, 255), RGB(255, 255, 255),
|
|
RGB(255, 255, 255), RGB(255, 255, 255),
|
|
RGB(255, 255, 255), RGB(255, 255, 255),
|
|
RGB(255, 255, 255), RGB(255, 255, 255),
|
|
RGB(255, 255, 255), RGB(255, 255, 255)
|
|
};
|
|
CHOOSECOLOR cc;
|
|
DWORD rgbOld;
|
|
BOOL fResult;
|
|
INT idPrevDlg;
|
|
|
|
switch (gfModeLeft) {
|
|
case MODE_COLOR:
|
|
/*
|
|
* The monochrome palette cannot be edited.
|
|
*/
|
|
if (gnColorPalColors == 2)
|
|
return;
|
|
|
|
rgbOld = gargbCurrent[giColorLeft];
|
|
break;
|
|
|
|
case MODE_SCREEN:
|
|
rgbOld = grgbScreen;
|
|
break;
|
|
|
|
case MODE_INVERSE:
|
|
rgbOld = grgbInverse;
|
|
break;
|
|
}
|
|
|
|
cc.lStructSize = sizeof(CHOOSECOLOR);
|
|
cc.hwndOwner = ghwndMain;
|
|
cc.hInstance = ghInst;
|
|
cc.rgbResult = rgbOld;
|
|
cc.lpCustColors = argbCust;
|
|
cc.Flags = CC_RGBINIT | CC_SHOWHELP;
|
|
cc.lCustData = 0;
|
|
cc.lpfnHook = NULL;
|
|
cc.lpTemplateName = NULL;
|
|
|
|
EnteringDialog(DID_COMMONFILECHOOSECOLOR, &idPrevDlg, TRUE);
|
|
fResult = ChooseColor(&cc);
|
|
EnteringDialog(idPrevDlg, NULL, FALSE);
|
|
|
|
if (fResult && rgbOld != cc.rgbResult) {
|
|
switch (gfModeLeft) {
|
|
case MODE_COLOR:
|
|
gargbCurrent[giColorLeft] = cc.rgbResult;
|
|
break;
|
|
|
|
case MODE_SCREEN:
|
|
SetScreenColor(cc.rgbResult);
|
|
break;
|
|
|
|
case MODE_INVERSE:
|
|
SetScreenColor(ComputeInverseColor(cc.rgbResult));
|
|
break;
|
|
}
|
|
|
|
SetLeftColor(giColorLeft, gfModeLeft);
|
|
InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* SetLeftColor
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR SetLeftColor(
|
|
INT iColor,
|
|
INT iMode)
|
|
{
|
|
DWORD rgbSolid;
|
|
BOOL fEnableDefault = FALSE;
|
|
BOOL fEnableEdit = FALSE;
|
|
|
|
if (ghbrLeft)
|
|
DeleteObject(ghbrLeft);
|
|
|
|
if (ghbrLeftSolid)
|
|
DeleteObject(ghbrLeftSolid);
|
|
|
|
if (ghpenLeft)
|
|
DeleteObject(ghpenLeft);
|
|
|
|
switch (iMode) {
|
|
case MODE_COLOR:
|
|
ghbrLeft = MyCreateSolidBrush(gargbCurrent[iColor]);
|
|
rgbSolid = MyGetNearestColor(gargbCurrent[iColor], TRUE);
|
|
ghbrLeftSolid = CreateSolidBrush(rgbSolid);
|
|
ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, rgbSolid);
|
|
giColorLeft = iColor;
|
|
|
|
/*
|
|
* We will enable the "Default" button if the current color
|
|
* on the left button is not the default color, and we are
|
|
* not in monochrome mode.
|
|
*/
|
|
if (gargbColor[giColorLeft] != gargbDefaultColor[giColorLeft] &&
|
|
gnColorPalColors > 2)
|
|
fEnableDefault = TRUE;
|
|
|
|
/*
|
|
* For non-screen colors, the Edit button will be enabled
|
|
* if we are not in monochrome mode.
|
|
*/
|
|
if (gnColorPalColors > 2)
|
|
fEnableEdit = TRUE;
|
|
|
|
break;
|
|
|
|
case MODE_SCREEN:
|
|
ghbrLeft = CreateSolidBrush(grgbScreen);
|
|
ghbrLeftSolid = CreateSolidBrush(grgbScreen);
|
|
ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, grgbScreen);
|
|
giColorLeft = 0;
|
|
fEnableEdit = TRUE;
|
|
break;
|
|
|
|
case MODE_INVERSE:
|
|
ghbrLeft = CreateSolidBrush(grgbInverse);
|
|
ghbrLeftSolid = CreateSolidBrush(grgbInverse);
|
|
ghpenLeft = CreatePen(PS_INSIDEFRAME, 1, grgbInverse);
|
|
giColorLeft = 0;
|
|
fEnableEdit = TRUE;
|
|
break;
|
|
}
|
|
|
|
EnableWindow(GetDlgItem(ghwndColor, DID_COLORDEFAULT), fEnableDefault);
|
|
EnableWindow(GetDlgItem(ghwndColor, DID_COLOREDIT), fEnableEdit);
|
|
|
|
gfModeLeft = iMode;
|
|
ColorLRUpdate(TRUE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* SetRightColor
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID NEAR SetRightColor(
|
|
INT iColor,
|
|
INT iMode)
|
|
{
|
|
DWORD rgbSolid;
|
|
|
|
if (ghbrRight)
|
|
DeleteObject(ghbrRight);
|
|
|
|
if (ghbrRightSolid)
|
|
DeleteObject(ghbrRightSolid);
|
|
|
|
if (ghpenRight)
|
|
DeleteObject(ghpenRight);
|
|
|
|
switch (iMode) {
|
|
case MODE_COLOR:
|
|
ghbrRight = MyCreateSolidBrush(gargbCurrent[iColor]);
|
|
rgbSolid = MyGetNearestColor(gargbCurrent[iColor], TRUE);
|
|
ghbrRightSolid = CreateSolidBrush(rgbSolid);
|
|
ghpenRight = CreatePen(PS_INSIDEFRAME, 1, rgbSolid);
|
|
giColorRight = iColor;
|
|
break;
|
|
|
|
case MODE_SCREEN:
|
|
ghbrRight = CreateSolidBrush(grgbScreen);
|
|
ghbrRightSolid = CreateSolidBrush(grgbScreen);
|
|
ghpenRight = CreatePen(PS_INSIDEFRAME, 1, grgbScreen);
|
|
giColorRight = 0;
|
|
break;
|
|
|
|
case MODE_INVERSE:
|
|
ghbrRight = CreateSolidBrush(grgbInverse);
|
|
ghbrRightSolid = CreateSolidBrush(grgbInverse);
|
|
ghpenRight = CreatePen(PS_INSIDEFRAME, 1, grgbInverse);
|
|
giColorRight = 0;
|
|
break;
|
|
}
|
|
|
|
gfModeRight = iMode;
|
|
ColorLRUpdate(FALSE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* SetScreenColor
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
VOID SetScreenColor(
|
|
DWORD rgb)
|
|
{
|
|
DWORD rgbInverse;
|
|
HDC hdcTemp;
|
|
HBITMAP hbmOld;
|
|
HDC hdcANDTemp;
|
|
HBITMAP hbmANDOld;
|
|
|
|
rgb = MyGetNearestColor(rgb, FALSE);
|
|
|
|
/*
|
|
* Because we are about to change the screen color, separate
|
|
* out the XOR mask (but only for icons/cursors).
|
|
*/
|
|
if (giColorPalType != FT_BITMAP) {
|
|
if (gpImageCur) {
|
|
ImageDCSeparate(ghdcImage, gcxImage, gcyImage, ghdcANDMask,
|
|
grgbScreen);
|
|
|
|
/*
|
|
* Is there a pending undo buffer? If so, it must be
|
|
* changed as well or an undo that is done after a screen
|
|
* color change will restore the wrong colors!
|
|
*/
|
|
if (ghbmUndo) {
|
|
/*
|
|
* Create some temporary DC's to use when separating
|
|
* out the undo buffer's masks. These will be deleted
|
|
* a little later.
|
|
*/
|
|
hdcTemp = CreateCompatibleDC(ghdcImage);
|
|
hbmOld = SelectObject(hdcTemp, ghbmUndo);
|
|
hdcANDTemp = CreateCompatibleDC(ghdcANDMask);
|
|
hbmANDOld = SelectObject(hdcANDTemp, ghbmUndoMask);
|
|
|
|
/*
|
|
* Separate out the undo buffer's colors, before
|
|
* changing the screen color. It will be combined
|
|
* later.
|
|
*/
|
|
ImageDCSeparate(hdcTemp, gcxImage, gcyImage, hdcANDTemp,
|
|
grgbScreen);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ghbrScreen)
|
|
DeleteObject(ghbrScreen);
|
|
|
|
ghbrScreen = CreateSolidBrush(rgb);
|
|
grgbScreen = rgb;
|
|
|
|
if (ghbrInverse)
|
|
DeleteObject(ghbrInverse);
|
|
|
|
rgbInverse = ComputeInverseColor(rgb);
|
|
ghbrInverse = CreateSolidBrush(rgbInverse);
|
|
grgbInverse = rgbInverse;
|
|
|
|
/*
|
|
* For icons and cursors, we might need to update a few more things.
|
|
*/
|
|
if (giColorPalType != FT_BITMAP) {
|
|
/*
|
|
* Recombine the XOR and AND images now that there is a new screen
|
|
* color. This updates the image DC with the new color properly.
|
|
*/
|
|
if (gpImageCur) {
|
|
ImageDCCombine(ghdcImage, gcxImage, gcyImage, ghdcANDMask);
|
|
|
|
/*
|
|
* Is there a pending undo buffer? If so, it has to be
|
|
* recombined with the new screen color.
|
|
*/
|
|
if (ghbmUndo) {
|
|
ImageDCCombine(hdcTemp, gcxImage, gcyImage, hdcANDTemp);
|
|
|
|
/*
|
|
* Clean up the DC's that were allocated a little earlier.
|
|
*/
|
|
SelectObject(hdcANDTemp, hbmANDOld);
|
|
DeleteDC(hdcANDTemp);
|
|
SelectObject(hdcTemp, hbmOld);
|
|
DeleteDC(hdcTemp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Reset the colors on the mouse buttons, just in case a screen
|
|
* or inverse screen color was assigned to either of them.
|
|
*/
|
|
SetLeftColor(giColorLeft, gfModeLeft);
|
|
SetRightColor(giColorRight, gfModeRight);
|
|
|
|
InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE);
|
|
}
|
|
|
|
ViewUpdate();
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* MyCreateSolidBrush
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN HBRUSH NEAR MyCreateSolidBrush(
|
|
DWORD rgb)
|
|
{
|
|
HDC hdc;
|
|
HDC hdcMem;
|
|
HBRUSH hbr;
|
|
HBRUSH hbrOld;
|
|
HBITMAP hbmPat;
|
|
HBITMAP hbmOld;
|
|
|
|
/*
|
|
* First, create a brush for the given RGB value.
|
|
*/
|
|
hbr = CreateSolidBrush(rgb);
|
|
|
|
/*
|
|
* Create a temporary memory DC.
|
|
*/
|
|
hdc = GetDC(ghwndMain);
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
|
|
/*
|
|
* Create a temporary bitmap.
|
|
*/
|
|
hbmPat = MyCreateBitmap(hdc, 8, 8, gnColorPalColors);
|
|
ReleaseDC(ghwndMain, hdc);
|
|
|
|
/*
|
|
* Draw the (possibly) dithered pattern on the temporary bitmap.
|
|
*/
|
|
hbmOld = SelectObject(hdcMem, hbmPat);
|
|
hbrOld = SelectObject(hdcMem, hbr);
|
|
PatBlt(hdcMem, 0, 0, 8, 8, PATCOPY);
|
|
SelectObject(hdcMem, hbrOld);
|
|
SelectObject(hdcMem, hbmOld);
|
|
DeleteDC(hdcMem);
|
|
|
|
/*
|
|
* Delete the first brush.
|
|
*/
|
|
DeleteObject(hbr);
|
|
|
|
/*
|
|
* Now create a pattern brush out of the (dithered) bitmap.
|
|
*/
|
|
hbr = CreatePatternBrush(hbmPat);
|
|
|
|
DeleteObject(hbmPat);
|
|
|
|
/*
|
|
* Return the pattern brush.
|
|
*/
|
|
return hbr;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* MyGetNearestColor
|
|
*
|
|
* This function returns the RGB value of the nearest color to the
|
|
* specified RGB value. If fMonoOK is TRUE, it takes into account
|
|
* the number of colors of the current image being edited. In other
|
|
* words, it will return the nearest solid color for a device that
|
|
* has the number of colors of the current image.
|
|
*
|
|
* Arguments:
|
|
* DWORD rgb - RGB value of the color.
|
|
* BOOL fMonoOK - TRUE if the returned color should be mapped to a
|
|
* color in a monochrome palette, if the current image
|
|
* is monochrome. A value of FALSE will return a
|
|
* color mapped to the closest color in a 16 color
|
|
* palette.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN DWORD NEAR MyGetNearestColor(
|
|
DWORD rgb,
|
|
BOOL fMonoOK)
|
|
{
|
|
HDC hdc;
|
|
HDC hdcMem;
|
|
DWORD rgbNearest;
|
|
HBITMAP hbmMem;
|
|
HBITMAP hbmOld;
|
|
|
|
hdc = GetDC(ghwndMain);
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
hbmMem = MyCreateBitmap(hdc, 1, 1, (fMonoOK) ? gnColorPalColors : 16);
|
|
hbmOld = SelectObject(hdcMem, hbmMem);
|
|
rgbNearest = GetNearestColor(hdcMem, rgb);
|
|
SelectObject(hdcMem, hbmOld);
|
|
DeleteObject(hbmMem);
|
|
DeleteDC(hdcMem);
|
|
ReleaseDC(ghwndMain, hdc);
|
|
|
|
return rgbNearest;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* ComputeInverseColor
|
|
*
|
|
* Computes the inverse value of a given rgb color.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN DWORD NEAR ComputeInverseColor(
|
|
DWORD rgb)
|
|
{
|
|
HBITMAP hTempBit1;
|
|
HBITMAP hTempBit2;
|
|
HDC hTempDC1;
|
|
HDC hTempDC2;
|
|
HDC hdc;
|
|
HANDLE hOldObj1;
|
|
HANDLE hOldObj2;
|
|
DWORD rgbInv;
|
|
|
|
hdc = GetDC(ghwndMain);
|
|
hTempDC1 = CreateCompatibleDC(hdc);
|
|
hTempDC2 = CreateCompatibleDC(hdc);
|
|
|
|
/* create two temporary 1x1, 16 color bitmaps */
|
|
hTempBit1 = MyCreateBitmap(hdc, 1, 1, 16);
|
|
hTempBit2 = MyCreateBitmap(hdc, 1, 1, 16);
|
|
|
|
ReleaseDC(ghwndMain, hdc);
|
|
|
|
hOldObj1 = SelectObject(hTempDC1, hTempBit1);
|
|
hOldObj2 = SelectObject(hTempDC2, hTempBit2);
|
|
|
|
/* method for getting inverse color : set the given pixel (rgb) on
|
|
* one DC. Now blt it to the other DC using a SRCINVERT rop.
|
|
* This yields a pixel of the inverse color on the destination DC
|
|
*/
|
|
SetPixel(hTempDC1, 0, 0, rgb);
|
|
PatBlt(hTempDC2, 0, 0, 1, 1, WHITENESS);
|
|
BitBlt(hTempDC2, 0, 0, 1, 1, hTempDC1, 0, 0, SRCINVERT);
|
|
rgbInv = GetPixel(hTempDC2, 0, 0);
|
|
|
|
/* clean up ... */
|
|
SelectObject(hTempDC1, hOldObj1);
|
|
SelectObject(hTempDC2, hOldObj2);
|
|
DeleteObject(hTempBit1);
|
|
DeleteObject(hTempBit2);
|
|
DeleteDC(hTempDC1);
|
|
DeleteDC(hTempDC2);
|
|
|
|
/* ...and return the inverted RGB value */
|
|
return rgbInv;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* SetColorPalette
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
VOID SetColorPalette(
|
|
INT nColors,
|
|
INT iType,
|
|
BOOL fForce)
|
|
{
|
|
/*
|
|
* Quit if nothing changed (unless they are forcing it to be updated).
|
|
*/
|
|
if (!fForce && nColors == gnColorPalColors && iType == giColorPalType)
|
|
return;
|
|
|
|
/*
|
|
* Set the globals that all the color palette routines use.
|
|
*/
|
|
gnColorPalColors = nColors;
|
|
giColorPalType = iType;
|
|
|
|
if (gnColorPalColors == 2)
|
|
gargbCurrent = gargbMono;
|
|
else
|
|
gargbCurrent = gargbColor;
|
|
|
|
ShowWindow(GetDlgItem(ghwndColor, DID_COLORSCREENLABEL),
|
|
(giColorPalType == FT_BITMAP) ? SW_HIDE : SW_SHOW);
|
|
ShowWindow(GetDlgItem(ghwndColor, DID_COLORINVERSELABEL),
|
|
(giColorPalType == FT_BITMAP) ? SW_HIDE : SW_SHOW);
|
|
|
|
SetLeftColor(1, MODE_COLOR);
|
|
SetRightColor(0, MODE_COLOR);
|
|
|
|
InvalidateRect(GetDlgItem(ghwndColor, DID_COLORBOX), NULL, TRUE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* RestoreDefaultColors
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
VOID RestoreDefaultColors(VOID)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; i < COLORSMAX; i++)
|
|
gargbColor[i] = gargbDefaultColor[i];
|
|
|
|
SetColorPalette(16, giColorPalType, TRUE);
|
|
}
|