📄 bcgppowercolorpicker.cpp
字号:
//*******************************************************************************
// COPYRIGHT NOTES
// ---------------
// This is a part of the BCGControlBar Library
// Copyright (C) 1998-2000 BCGSoft Ltd.
// All rights reserved.
//
// This source code can be used, distributed or modified
// only under terms and conditions
// of the accompanying license agreement.
//*******************************************************************************
// PowerColorPicker.cpp : implementation file
// Created by Martha Creedle
#include "stdafx.h"
#ifndef BCG_NO_COLOR
#include <math.h>
#include "BCGCBPro.h"
#include "BCGGlobals.h"
#include "BCGPPowerColorPicker.h"
#include "BCGPDrawManager.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DEFAULT_WIDTH_OF_LUMINANCE_BAR 20
#define DEFAULT_OFFSET_OF_LUMINANCE_BAR 5
#define DEFAULT_LUMINANCE 0.50f
#define PICKER_CURSOR_SIZE 19
#define LUM_CURSOR_SIZE 9
// Hex
#define NUM_LEVELS 7
#define CELL_EDGES 6
#define GRAY_CELLS_NUM 15 // + 2 (Black and white)
#define TAN30 0.57735026918962F
#define YOFFSET (1.5F * TAN30)
#define PI 3.14159265358979
static const float cfxOffset[] = { -0.5, -1.0, -0.5, 0.5, 1.0, 0.5 };
static const float cfyOffset[] = { YOFFSET, 0.0, -YOFFSET, -YOFFSET, 0.0, YOFFSET };
static const COLORREF colorWhite = RGB (255, 255, 255);
static const COLORREF colorBlack = RGB (0, 0, 0);
static long AlignColor (long lPart, const long lDelta)
{
if (lDelta == 0)
{
return lPart;
}
if (lPart < lDelta)
{
return 0;
}
if (lPart > 255 - lDelta)
{
return 255;
}
if (abs (lPart - 128) < lDelta)
{
return 128;
}
if (abs (lPart - 192) < lDelta)
{
return 192;
}
return lPart;
}
class CCellObj : public CObject
{
friend class CBCGPColorPickerCtrl;
CCellObj ( CPalette* pPalette,
const COLORREF color,
const int x, const int y,
const int nCellWidth,
const long lDelta)
{
m_x = x;
m_y = y;
m_nCellWidth = nCellWidth;
//-----------------------------------------------
// Approximate color to one of "standard" colors:
//-----------------------------------------------
long lRed = AlignColor (GetRValue (color), lDelta);
long lGreen = AlignColor (GetGValue (color), lDelta);
long lBlue = AlignColor (GetBValue (color), lDelta);
m_CellColor = RGB (lRed, lGreen, lBlue);
if (globalData.m_nBitsPerPixel == 8) // 256 colors
{
ASSERT_VALID (pPalette);
UINT uiPalIndex = pPalette->GetNearestPaletteIndex (color);
m_CellDrawColor = PALETTEINDEX (uiPalIndex);
}
else
{
m_CellDrawColor = m_CellColor;
}
GetPoints (m_x, m_y, nCellWidth, m_CellPoints);
}
BOOL HitTest (POINT pt)
{
CRgn rgn;
rgn.CreatePolygonRgn(m_CellPoints, CELL_EDGES, ALTERNATE);
return rgn.PtInRegion (pt);
}
void GetPoints (int x, int y, int nCellWidth, POINT* pptArray)
{
// side length = half the height * sin(60)
int nHalfWidth = nCellWidth / 2;
int nSideLength = static_cast<int>(static_cast<float>(nCellWidth) * TAN30);
int nTemp = nSideLength/2;
pptArray[0].x = x - nHalfWidth;
pptArray[0].y = y - nTemp;
pptArray[1].x = x;
pptArray[1].y = y - nHalfWidth;
pptArray[2].x = x + nHalfWidth;
pptArray[2].y = y - nTemp;
pptArray[3].x = x + nHalfWidth;
pptArray[3].y = y + nTemp;
pptArray[4].x = x;
pptArray[4].y = y + nHalfWidth;
pptArray[5].x = x - nHalfWidth;
pptArray[5].y = y + nTemp;
}
void Draw (CDC* pDC)
{
ASSERT_VALID (pDC);
CBrush br (m_CellDrawColor);
CPen pen (PS_SOLID, 1, m_CellDrawColor);
CBrush* pOldBrush = pDC->SelectObject(&br);
CPen* pOldPen = pDC->SelectObject(&pen);
pDC->Polygon (m_CellPoints, CELL_EDGES);
pDC->SelectObject (pOldPen);
pDC->SelectObject (pOldBrush);
}
void DrawSelected (CDC* pDC)
{
ASSERT_VALID (pDC);
CBrush* pBrWhite = CBrush::FromHandle ((HBRUSH) ::GetStockObject (WHITE_BRUSH));
ASSERT_VALID (pBrWhite);
CBrush* pBrBlack = CBrush::FromHandle ((HBRUSH) ::GetStockObject (BLACK_BRUSH));
ASSERT_VALID (pBrBlack);
CRgn rgnOne, rgnTwo, rgnThree;
POINT ptArrayTwo[CELL_EDGES];
GetPoints(m_x, m_y - 1, m_nCellWidth + 2, ptArrayTwo);
rgnTwo.CreatePolygonRgn((POINT*)&ptArrayTwo, CELL_EDGES, ALTERNATE);
pDC->FrameRgn(&rgnTwo, pBrWhite, 2, 2);
POINT ptArrayThree[CELL_EDGES];
GetPoints(m_x, m_y, m_nCellWidth + 2, ptArrayThree);
rgnThree.CreatePolygonRgn((POINT*)&ptArrayThree, CELL_EDGES, ALTERNATE);
pDC->FrameRgn(&rgnThree, pBrBlack, 1, 1);
POINT ptArrayOne[CELL_EDGES];
GetPoints(m_x, m_y, m_nCellWidth - 1, ptArrayOne);
rgnOne.CreatePolygonRgn((POINT*)&ptArrayOne, CELL_EDGES, ALTERNATE);
pDC->FrameRgn(&rgnOne, pBrBlack, 1, 1);
}
POINT m_CellPoints [CELL_EDGES];
COLORREF m_CellColor;
COLORREF m_CellDrawColor;
int m_x;
int m_y;
int m_nCellWidth;
};
//----------------------------------------------------------------------
// CBCGPColorPickerCtrl class
//----------------------------------------------------------------------
CBCGPColorPickerCtrl::CBCGPColorPickerCtrl()
{
m_colorNew = 0;
m_colorOriginal = 0;
CBCGPDrawManager::RGBtoHSL (m_colorNew, &m_dblHue, &m_dblSat, &m_dblLum);
m_nLumBarWidth = DEFAULT_WIDTH_OF_LUMINANCE_BAR;
m_COLORTYPE = PICKER;
m_dblLum = 0.500;
m_pPalette = NULL;
}
CBCGPColorPickerCtrl::~CBCGPColorPickerCtrl()
{
for (int i = 0; i < m_arCells.GetSize (); i ++)
{
delete m_arCells [i];
}
}
BEGIN_MESSAGE_MAP(CBCGPColorPickerCtrl, CButton)
//{{AFX_MSG_MAP(CBCGPColorPickerCtrl)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_SIZE()
ON_WM_GETDLGCODE()
ON_WM_KEYDOWN()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_QUERYNEWPALETTE()
ON_WM_PALETTECHANGED()
ON_WM_ERASEBKGND()
ON_WM_CANCELMODE()
ON_WM_LBUTTONDBLCLK()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//----------------------------------------------------------------------
// CBCGPColorPickerCtrl message handlers
//----------------------------------------------------------------------
int CBCGPColorPickerCtrl::GetAngleFromPoint(int nX, int nY)
{
double dAngle = atan2((double) nY, (double)nX);
return (int) (dAngle * 180.0/PI);
}
//******************************************************************************
void CBCGPColorPickerCtrl::CreateHexGreyScaleBar ()
{
if (m_arCells.GetSize () != 0)
{
// Already created
return;
}
CRect area;
GetClientRect (area);
int nCellSize = min (area.Height () / 2 - 2,
area.Width () / (GRAY_CELLS_NUM / 2 + 6));
if ((nCellSize % 2) != 0)
{
nCellSize ++;
}
const int nCellLargeSize = nCellSize * 2;
int yCenter = (area.top + area.bottom) / 2;
int nSideLength = static_cast<int>(static_cast<float>(nCellSize) * TAN30 * 1.5);
int y1 = yCenter - nSideLength / 2;
int y2 = y1 + nSideLength;
int nRGBOffset = 255 / (GRAY_CELLS_NUM + 2);
int nStartOffset = area.left;
for (int nRowNum = 0; nRowNum < 2; nRowNum++)
{
if (nRowNum == 1)
{
// Draw large white cell:
int x1 = nStartOffset + (nCellLargeSize / 2);
m_arCells.Add (new CCellObj (
m_pPalette, colorWhite, x1, yCenter, nCellLargeSize, 0));
}
int x = nCellLargeSize + nCellSize + nStartOffset;
int nCurry = y1;
int nRGB = 255 - nRGBOffset;
for (int i = 0; i < GRAY_CELLS_NUM; i++)
{
COLORREF color = RGB(nRGB, nRGB, nRGB);
if (nRowNum == 1)
{
m_arCells.Add (new CCellObj (m_pPalette, color, x, nCurry, nCellSize, 7));
}
x += (nCellSize / 2);
nCurry = (nCurry == y1) ? y2 : y1; // Toggle Y
nRGB -= nRGBOffset;
}
if (nRowNum == 1)
{
// Draw large black cell:
int x1 = (x + nCellSize + (nCellSize / 2)) - 1;
m_arCells.Add (new CCellObj (
m_pPalette, colorBlack, x1, yCenter, nCellLargeSize, 0));
}
x += nCellLargeSize + (nCellSize / 2);
if (nRowNum == 0)
{
nStartOffset = (area.right - x) / 2;
}
}
}
//******************************************************************************
void CBCGPColorPickerCtrl::SelectCellHexagon(BYTE R, BYTE G, BYTE B)
{
SetColor (RGB (R, G, B));
}
//******************************************************************************
void CBCGPColorPickerCtrl::SetColor(COLORREF Color)
{
m_colorNew = Color;
CBCGPDrawManager::RGBtoHSL (m_colorNew, &m_dblHue, &m_dblSat, &m_dblLum);
if (GetSafeHwnd () != NULL)
{
RedrawWindow ();
}
};
//******************************************************************************
BOOL CBCGPColorPickerCtrl::SelectCellHexagon(int x, int y)
{
for (int i = 0; i < m_arCells.GetSize (); i ++)
{
CCellObj* pCell = (CCellObj*) m_arCells [i];
ASSERT_VALID (pCell);
if (pCell->HitTest (CPoint (x, y)))
{
m_colorNew = pCell->m_CellColor;
CBCGPDrawManager::RGBtoHSL (m_colorNew, &m_dblHue, &m_dblSat, &m_dblLum);
return TRUE;
}
}
return FALSE;
}
//******************************************************************************
void CBCGPColorPickerCtrl::CreateHexagon ()
{
if (m_arCells.GetSize () != 0)
{
// Already created, do nothing
return;
}
CRect rectClient;
GetClientRect (rectClient);
// Normalize to squere:
if (rectClient.Height () < rectClient.Width ())
{
rectClient.DeflateRect ((rectClient.Width () - rectClient.Height ()) / 2, 0);
}
else
{
rectClient.DeflateRect (0, (rectClient.Height () - rectClient.Width ()) / 2);
}
ASSERT (abs (rectClient.Height () - rectClient.Width ()) <= 1);
int nCellSize = rectClient.Height () / (2 * NUM_LEVELS - 1) + 1;
int x = (rectClient.left + rectClient.right) / 2;
int y = (rectClient.top + rectClient.bottom) / 2;
// Add center cell
m_arCells.Add (new CCellObj (m_pPalette, colorWhite, x, y, nCellSize, 0));
// for each level
for (int nLevel = 1; nLevel < NUM_LEVELS; nLevel++)
{
// store the level start position
int nPosX = x + (nCellSize * nLevel);
int nPosY = y;
// for each side
for (int nSide = 0; nSide < NUM_LEVELS - 1; nSide++)
{
// set the deltas for the side
int nDx = static_cast<int>(static_cast<float>(nCellSize) * cfxOffset[nSide]);
int nDy = static_cast<int>(static_cast<float>(nCellSize) * cfyOffset[nSide]);
// for each cell per side
for (int nCell = 0; nCell < nLevel; nCell++)
{
int nAngle = GetAngleFromPoint(nPosX - x, nPosY - y);
// TODO: Set the luminance and saturation properly
double L = 1. * (NUM_LEVELS - nLevel) / NUM_LEVELS + .1;
m_arCells.Add (new CCellObj (m_pPalette,
CBCGPDrawManager::HLStoRGB_TWO ((float) nAngle, L, 1.0F),
nPosX, nPosY, nCellSize, 16));
// offset the position
nPosX += nDx;
nPosY += nDy;
}
}
}
}
//******************************************************************************
void CBCGPColorPickerCtrl::DrawHex (CDC* pDC)
{
ASSERT_VALID (pDC);
globalData.DrawParentBackground (this, pDC);
CCellObj* pSelCell = NULL;
for (int i = 0; i < m_arCells.GetSize (); i ++)
{
CCellObj* pCell = (CCellObj*) m_arCells [i];
ASSERT_VALID (pCell);
pCell->Draw (pDC);
if (pCell->m_CellColor == m_colorNew)
{
pSelCell = pCell;
}
}
if (pSelCell != NULL)
{
pSelCell->DrawSelected (pDC);
}
}
//******************************************************************************
void CBCGPColorPickerCtrl::DrawPicker (CDC* pDC)
{
CRect rectClient;
GetClientRect (rectClient);
CSize szColorPicker = rectClient.Size ();
if (m_bmpPicker.GetSafeHandle () == NULL)
{
// Prepare picker's bitmap:
CDC dcMem;
if (dcMem.CreateCompatibleDC (pDC) &&
m_bmpPicker.CreateCompatibleBitmap (pDC, szColorPicker.cx, szColorPicker.cy))
{
CBitmap* pOldBmp = dcMem.SelectObject (&m_bmpPicker);
int nStep = (globalData.m_nBitsPerPixel > 8) ? 1 : 4;
for (int i= 0;i<szColorPicker.cy;i += nStep)
{
for(int j=0;j<szColorPicker.cx;j += nStep)
{
CPoint pt (j, szColorPicker.cy - i - nStep);
COLORREF color = CBCGPDrawManager::HLStoRGB_ONE((double)j/(double)szColorPicker.cx, DEFAULT_LUMINANCE, (double)i/(double)szColorPicker.cy);
if (globalData.m_nBitsPerPixel > 8) // High/True color
{
// Draw exact color:
dcMem.SetPixelV (pt, color);
}
else
{
// Draw dithered rectangle:
CBrush br (color);
dcMem.FillRect (CRect (pt, CSize (nStep, nStep)), &br);
}
}
}
dcMem.SelectObject (pOldBmp);
}
}
pDC->DrawState (CPoint (0, 0), szColorPicker, &m_bmpPicker, DSS_NORMAL);
}
//******************************************************************************
void CBCGPColorPickerCtrl :: DrawLuminanceBar(CDC* pDC)
{
CRect rectClient;
GetClientRect (rectClient);
rectClient.DeflateRect (0, DEFAULT_OFFSET_OF_LUMINANCE_BAR);
for (int y = rectClient.top; y <= rectClient.bottom; y ++)
{
COLORREF col = CBCGPDrawManager::HLStoRGB_ONE (m_dblHue, LumFromPoint (y), m_dblSat);
CBrush br (col);
pDC->FillRect(CRect (0, y, m_nLumBarWidth, y + 1), &br);
}
}
//******************************************************************************
void CBCGPColorPickerCtrl::DrawCursor (CDC* pDC, const CRect& rect)
{
const int nHalfSize = rect.Width () / 2; // Assume square
if (m_COLORTYPE == PICKER)
{
COLORREF colorFocus = (GetFocus() == this) ? colorBlack : colorWhite;
pDC->FillSolidRect((rect.left + nHalfSize) - 1, rect.top, 3, 5, colorFocus); // Top
pDC->FillSolidRect((rect.left + nHalfSize) - 1, rect.bottom - 5, 3, 5, colorFocus); // Bottom
pDC->FillSolidRect(rect.left, (rect.top + nHalfSize) - 1, 5, 3, colorFocus); // Left
pDC->FillSolidRect(rect.right - 5, (rect.top + nHalfSize) - 1, 5, 3, colorFocus); // Right
}
else if (m_COLORTYPE == LUMINANCE)
{
POINT pt[3];
pt[0].x = rect.left;
pt[0].y = rect.top + nHalfSize;
pt[1].x = rect.right - 1;
pt[1].y = rect.top;
pt[2].x = rect.right - 1;
pt[2].y = rect.bottom - 1;
CPen pen (PS_SOLID, 1, globalData.clrBtnText);
CBrush br (GetFocus() == this ?
globalData.clrBtnText : globalData.clrBtnShadow);
CBrush* poldBrush = pDC->SelectObject (&br);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -