mirror of
https://github.com/leozide/leocad
synced 2024-12-30 22:23:45 +01:00
566 lines
14 KiB
C++
566 lines
14 KiB
C++
#include "lc_global.h"
|
|
#include <math.h>
|
|
#include "ClrPick.h"
|
|
#include "ClrPopup.h"
|
|
#include "propertiesgridctrl.h"
|
|
#include "lc_colors.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define INVALID_COLOUR -1
|
|
|
|
#define MAX_COLOURS 256
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CColorPopup
|
|
|
|
CColorPopup::CColorPopup()
|
|
{
|
|
Initialise();
|
|
}
|
|
|
|
CColorPopup::CColorPopup(CPoint p, int nColor, CWnd* pParentWnd, bool IgnoreMouse)
|
|
{
|
|
Initialise();
|
|
|
|
m_nColor = m_nInitialColor = nColor;
|
|
m_pParent = pParentWnd;
|
|
m_IgnoreMouse = IgnoreMouse;
|
|
|
|
CColorPopup::Create(p, nColor, pParentWnd);
|
|
}
|
|
|
|
void CColorPopup::Initialise()
|
|
{
|
|
m_nNumColumns = 0;
|
|
m_nNumRows = 0;
|
|
m_nBoxSize = 18;
|
|
m_nMargin = ::GetSystemMetrics(SM_CXEDGE);
|
|
m_nCurrentSel = INVALID_COLOUR;
|
|
m_nChosenColorSel = INVALID_COLOUR;
|
|
m_pParent = NULL;
|
|
m_nColor = m_nInitialColor = 0;
|
|
m_IgnoreMouse = false;
|
|
|
|
// Idiot check: Make sure the colour square is at least 5 x 5;
|
|
if (m_nBoxSize - 2 * m_nMargin - 2 < 5)
|
|
m_nBoxSize = 5 + 2 * m_nMargin + 2;
|
|
|
|
// Create the font
|
|
NONCLIENTMETRICS ncm;
|
|
ncm.cbSize = sizeof(NONCLIENTMETRICS);
|
|
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
|
|
m_Font.CreateFontIndirect(&(ncm.lfMessageFont));
|
|
|
|
// Create the palette
|
|
int NumColors = gColorList.GetSize() < MAX_COLOURS ? gColorList.GetSize() : MAX_COLOURS;
|
|
struct {
|
|
LOGPALETTE LogPalette;
|
|
PALETTEENTRY PalEntry[MAX_COLOURS];
|
|
} pal;
|
|
|
|
LOGPALETTE* pLogPalette = (LOGPALETTE*) &pal;
|
|
pLogPalette->palVersion = 0x300;
|
|
pLogPalette->palNumEntries = (WORD)gColorList.GetSize();
|
|
|
|
for (int i = 0; i < NumColors; i++)
|
|
{
|
|
float* Value = gColorList[i].Value;
|
|
pLogPalette->palPalEntry[i].peRed = (BYTE)(Value[0] * 255);
|
|
pLogPalette->palPalEntry[i].peGreen = (BYTE)(Value[1] * 255);
|
|
pLogPalette->palPalEntry[i].peBlue = (BYTE)(Value[2] * 255);
|
|
pLogPalette->palPalEntry[i].peFlags = 0;
|
|
}
|
|
|
|
m_Palette.CreatePalette(pLogPalette);
|
|
}
|
|
|
|
CColorPopup::~CColorPopup()
|
|
{
|
|
m_Font.DeleteObject();
|
|
m_Palette.DeleteObject();
|
|
}
|
|
|
|
BOOL CColorPopup::Create(CPoint p, int nColor, CWnd* pParentWnd)
|
|
{
|
|
ASSERT(pParentWnd && ::IsWindow(pParentWnd->GetSafeHwnd()));
|
|
ASSERT(pParentWnd->IsKindOf(RUNTIME_CLASS(CColorPicker)) || pParentWnd->IsKindOf(RUNTIME_CLASS(CMFCPropertyGridCtrl)));
|
|
|
|
m_pParent = pParentWnd;
|
|
m_nColor = m_nInitialColor = nColor;
|
|
|
|
// Get the class name and create the window
|
|
CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW, 0, (HBRUSH)GetStockObject(LTGRAY_BRUSH),0);
|
|
|
|
if (!CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE|WS_POPUP, p.x, p.y, 100, 100, pParentWnd->GetSafeHwnd(), 0, NULL))
|
|
return FALSE;
|
|
|
|
// Set the window size
|
|
SetWindowSize();
|
|
|
|
// Calculate the layout
|
|
CalculateLayout();
|
|
|
|
// Create the tooltips
|
|
CreateToolTips();
|
|
|
|
// Find which cell (if any) corresponds to the initial colour
|
|
for (int i = 0; i < mCells.GetSize(); i++)
|
|
{
|
|
if (mCells[i].ColorIndex == nColor)
|
|
{
|
|
m_nChosenColorSel = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Capture all mouse events for the life of this window
|
|
SetCapture();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CColorPopup, CWnd)
|
|
//{{AFX_MSG_MAP(CColorPopup)
|
|
ON_WM_NCDESTROY()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_PAINT()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_KEYDOWN()
|
|
ON_WM_QUERYNEWPALETTE()
|
|
ON_WM_PALETTECHANGED()
|
|
ON_WM_KILLFOCUS()
|
|
ON_WM_ACTIVATEAPP()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CColorPopup message handlers
|
|
|
|
// For tooltips
|
|
BOOL CColorPopup::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
m_ToolTip.RelayEvent(pMsg);
|
|
return CWnd::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
// If an arrow key is pressed, then move the selection
|
|
void CColorPopup::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
if (nChar == VK_LEFT)
|
|
{
|
|
if (m_nCurrentSel > 0)
|
|
ChangeSelection(m_nCurrentSel - 1);
|
|
}
|
|
else if (nChar == VK_RIGHT)
|
|
{
|
|
if (m_nCurrentSel < mCells.GetSize() - 1)
|
|
ChangeSelection(m_nCurrentSel + 1);
|
|
}
|
|
else if (nChar == VK_UP || nChar == VK_DOWN)
|
|
{
|
|
if (m_nCurrentSel < 0 || m_nCurrentSel >= mCells.GetSize())
|
|
m_nCurrentSel = 0;
|
|
|
|
int CurGroup = 0;
|
|
int NumCells = 0;
|
|
|
|
for (CurGroup = 0; CurGroup < LC_NUM_COLORGROUPS; CurGroup++)
|
|
{
|
|
int NumColors = gColorGroups[CurGroup].Colors.GetSize();
|
|
|
|
if (m_nCurrentSel < NumCells + NumColors)
|
|
break;
|
|
|
|
NumCells += NumColors;
|
|
}
|
|
|
|
int Row = (m_nCurrentSel - NumCells) / m_nNumColumns;
|
|
int Column = (m_nCurrentSel - NumCells) % m_nNumColumns;
|
|
|
|
if (nChar == VK_UP)
|
|
{
|
|
if (Row > 0)
|
|
ChangeSelection(m_nCurrentSel - m_nNumColumns);
|
|
else if (CurGroup > 0)
|
|
{
|
|
int NumColors = gColorGroups[CurGroup - 1].Colors.GetSize();
|
|
int NumColumns = NumColors % m_nNumColumns;
|
|
|
|
if (NumColumns <= Column + 1)
|
|
ChangeSelection(m_nCurrentSel - NumColumns - m_nNumColumns);
|
|
else
|
|
ChangeSelection(m_nCurrentSel - NumColumns);
|
|
}
|
|
}
|
|
else if (nChar == VK_DOWN)
|
|
{
|
|
int NumColors = gColorGroups[CurGroup].Colors.GetSize();
|
|
|
|
if (m_nCurrentSel + m_nNumColumns < NumCells + NumColors)
|
|
ChangeSelection(m_nCurrentSel + m_nNumColumns);
|
|
else
|
|
{
|
|
int NumColumns = NumColors % m_nNumColumns;
|
|
|
|
if (NumColumns > Column)
|
|
ChangeSelection(m_nCurrentSel + NumColumns);
|
|
else
|
|
ChangeSelection(m_nCurrentSel + m_nNumColumns + NumColumns);
|
|
}
|
|
}
|
|
}
|
|
else if (nChar == VK_ESCAPE)
|
|
{
|
|
m_nColor = m_nInitialColor;
|
|
EndSelection(CPN_SELENDCANCEL);
|
|
return;
|
|
}
|
|
else if (nChar == VK_RETURN || nChar == VK_SPACE)
|
|
{
|
|
EndSelection(CPN_SELENDOK);
|
|
return;
|
|
}
|
|
|
|
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
}
|
|
|
|
// auto-deletion
|
|
void CColorPopup::OnNcDestroy()
|
|
{
|
|
CWnd::OnNcDestroy();
|
|
delete this;
|
|
}
|
|
|
|
void CColorPopup::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
|
|
dc.FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
|
|
|
|
CFont *pOldFont = (CFont*)dc.SelectObject(&m_Font);
|
|
dc.SetBkMode(TRANSPARENT);
|
|
|
|
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
|
|
dc.DrawText(gColorGroups[GroupIdx].Name, mGroups[GroupIdx], DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
dc.SelectObject(pOldFont);
|
|
|
|
// Draw colour cells
|
|
for (int i = 0; i < mCells.GetSize(); i++)
|
|
DrawCell(&dc, i);
|
|
|
|
// Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
|
|
// but for some reason isn't
|
|
dc.DrawEdge(rect, EDGE_RAISED, BF_RECT);
|
|
}
|
|
|
|
void CColorPopup::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
int nNewSelection = INVALID_COLOUR;
|
|
|
|
for (int i = 0; i < mCells.GetSize(); i++)
|
|
{
|
|
if (mCells[i].Rect.PtInRect(point))
|
|
{
|
|
nNewSelection = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nNewSelection == INVALID_COLOUR)
|
|
{
|
|
CWnd::OnMouseMove(nFlags, point);
|
|
return;
|
|
}
|
|
|
|
m_IgnoreMouse = false;
|
|
|
|
// Has the row/col selection changed? If yes, then redraw old and new cells.
|
|
if (nNewSelection != m_nCurrentSel)
|
|
ChangeSelection(nNewSelection);
|
|
|
|
CWnd::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
// End selection on LButtonUp
|
|
void CColorPopup::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnLButtonUp(nFlags, point);
|
|
|
|
if (m_IgnoreMouse)
|
|
{
|
|
m_IgnoreMouse = false;
|
|
return;
|
|
}
|
|
|
|
DWORD pos = GetMessagePos();
|
|
point = CPoint(LOWORD(pos), HIWORD(pos));
|
|
|
|
if (m_WindowRect.PtInRect(point))
|
|
EndSelection(CPN_SELENDOK);
|
|
else
|
|
EndSelection(CPN_SELENDCANCEL);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CColorPopup implementation
|
|
|
|
// Works out an appropriate size and position of this window
|
|
void CColorPopup::SetWindowSize()
|
|
{
|
|
CSize TextSize(0, 0);
|
|
|
|
// Calculate the number of columns and rows.
|
|
m_nNumColumns = 14;
|
|
m_nNumRows = 0;
|
|
|
|
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
|
|
m_nNumRows += (gColorGroups[GroupIdx].Colors.GetSize() + m_nNumColumns - 1) / m_nNumColumns;
|
|
|
|
// Calculate text size.
|
|
CClientDC dc(this);
|
|
CFont* pOldFont = (CFont*) dc.SelectObject(&m_Font);
|
|
|
|
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
|
|
{
|
|
lcColorGroup* Group = &gColorGroups[GroupIdx];
|
|
|
|
CSize NameSize = dc.GetTextExtent(Group->Name);
|
|
if (NameSize.cx > TextSize.cx)
|
|
TextSize.cx = NameSize.cx;
|
|
TextSize.cy += NameSize.cy + 2;
|
|
}
|
|
|
|
dc.SelectObject(pOldFont);
|
|
|
|
// Get the current window position, and set the new size
|
|
CRect rect;
|
|
GetWindowRect(rect);
|
|
|
|
m_WindowRect.SetRect(rect.left, rect.top,
|
|
rect.left + m_nNumColumns*m_nBoxSize + 2*m_nMargin,
|
|
rect.top + m_nNumRows*m_nBoxSize + 2*m_nMargin);
|
|
|
|
if (TextSize.cx > m_WindowRect.Width())
|
|
m_WindowRect.right = m_WindowRect.left + TextSize.cx;
|
|
m_WindowRect.bottom += TextSize.cy;
|
|
|
|
// Need to check it'll fit on screen: Too far right?
|
|
CSize ScreenSize(::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN));
|
|
if (m_WindowRect.right > ScreenSize.cx)
|
|
m_WindowRect.OffsetRect(-(m_WindowRect.right - ScreenSize.cx), 0);
|
|
|
|
// Too far left?
|
|
if (m_WindowRect.left < 0)
|
|
m_WindowRect.OffsetRect( -m_WindowRect.left, 0);
|
|
|
|
// Bottom falling out of screen?
|
|
if (m_WindowRect.bottom > ScreenSize.cy)
|
|
{
|
|
CRect ParentRect;
|
|
m_pParent->GetWindowRect(ParentRect);
|
|
m_WindowRect.OffsetRect(0, -(ParentRect.Height() + m_WindowRect.Height()));
|
|
}
|
|
|
|
// Set the window size and position
|
|
MoveWindow(m_WindowRect, TRUE);
|
|
}
|
|
|
|
void CColorPopup::CalculateLayout()
|
|
{
|
|
CRect ClientRect;
|
|
GetClientRect(&ClientRect);
|
|
|
|
CClientDC dc(this);
|
|
CFont* pOldFont = (CFont*) dc.SelectObject(&m_Font);
|
|
|
|
int CurCell = 0;
|
|
int CurY = m_nMargin;
|
|
|
|
mGroups.RemoveAll();
|
|
mGroups.SetSize(LC_NUM_COLORGROUPS);
|
|
|
|
for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
|
|
{
|
|
lcColorGroup* Group = &gColorGroups[GroupIdx];
|
|
int CurColumn = 0;
|
|
|
|
CSize TextSize = dc.GetTextExtent(Group->Name);
|
|
mGroups[GroupIdx].SetRect(0, CurY + 1, ClientRect.Width(), CurY + TextSize.cy + 2);
|
|
CurY += TextSize.cy + 2;
|
|
|
|
for (int ColorIdx = 0; ColorIdx < Group->Colors.GetSize(); ColorIdx++)
|
|
{
|
|
int Left = m_nMargin + CurColumn * m_nBoxSize;
|
|
int Right = Left + m_nBoxSize;
|
|
int Top = CurY;
|
|
int Bottom = CurY + m_nBoxSize;
|
|
|
|
lcColor* Color = &gColorList[Group->Colors[ColorIdx]];
|
|
CColorPopupCell Cell;
|
|
|
|
Cell.Color = RGB(Color->Value[0] * 255, Color->Value[1] * 255, Color->Value[2] * 255);
|
|
Cell.ColorIndex = Group->Colors[ColorIdx];
|
|
Cell.Rect.SetRect(Left, Top, Right, Bottom);
|
|
|
|
mCells.Add(Cell);
|
|
|
|
CurColumn++;
|
|
if (CurColumn == m_nNumColumns)
|
|
{
|
|
CurColumn = 0;
|
|
CurY += m_nBoxSize;
|
|
}
|
|
|
|
CurCell++;
|
|
}
|
|
|
|
if (CurColumn != 0)
|
|
CurY += m_nBoxSize;
|
|
}
|
|
|
|
dc.SelectObject(pOldFont);
|
|
}
|
|
|
|
void CColorPopup::CreateToolTips()
|
|
{
|
|
// Create the tool tip
|
|
if (!m_ToolTip.Create(this)) return;
|
|
|
|
// Add a tool for each cell
|
|
for (int i = 0; i < mCells.GetSize(); i++)
|
|
{
|
|
CString Text;
|
|
lcColor* Color = &gColorList[mCells[i].ColorIndex];
|
|
Text.Format("%s (%d)", Color->Name, Color->Code);
|
|
m_ToolTip.AddTool(this, Text, mCells[i].Rect, i + 1);
|
|
}
|
|
}
|
|
|
|
void CColorPopup::ChangeSelection(int nIndex)
|
|
{
|
|
CClientDC dc(this); // device context for drawing
|
|
|
|
if (m_nCurrentSel >= 0 && m_nCurrentSel < mCells.GetSize())
|
|
{
|
|
// Set Current selection as invalid and redraw old selection (this way
|
|
// the old selection will be drawn unselected)
|
|
int OldSel = m_nCurrentSel;
|
|
m_nCurrentSel = INVALID_COLOUR;
|
|
DrawCell(&dc, OldSel);
|
|
}
|
|
|
|
// Set the current selection as row/col and draw (it will be drawn selected)
|
|
m_nCurrentSel = nIndex;
|
|
DrawCell(&dc, m_nCurrentSel);
|
|
|
|
m_nColor = m_nCurrentSel;
|
|
}
|
|
|
|
void CColorPopup::EndSelection(int nMessage)
|
|
{
|
|
ReleaseCapture();
|
|
|
|
if (nMessage == CPN_SELENDCANCEL)
|
|
m_nColor = m_nInitialColor;
|
|
|
|
int ColorIndex = m_nColor >= 0 ? mCells[m_nColor].ColorIndex : 0;
|
|
|
|
if (m_pParent->IsKindOf(RUNTIME_CLASS(CMFCPropertyGridCtrl)))
|
|
{
|
|
CLeoCADMFCPropertyGridCtrl* Ctrl = (CLeoCADMFCPropertyGridCtrl*)m_pParent;
|
|
Ctrl->SetColor(ColorIndex);
|
|
}
|
|
else
|
|
m_pParent->SendMessage(nMessage, 0, (LPARAM)ColorIndex);
|
|
|
|
DestroyWindow();
|
|
}
|
|
|
|
void CColorPopup::DrawCell(CDC* pDC, int nIndex)
|
|
{
|
|
CRect rect = mCells[nIndex].Rect;
|
|
|
|
// Select and realize the palette
|
|
CPalette* pOldPalette;
|
|
if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
|
|
{
|
|
pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
|
|
pDC->RealizePalette();
|
|
}
|
|
|
|
// fill background
|
|
if (m_nChosenColorSel == nIndex && m_nCurrentSel != nIndex)
|
|
pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DHILIGHT));
|
|
else
|
|
pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
|
|
|
|
// Draw button
|
|
if (m_nCurrentSel == nIndex)
|
|
pDC->DrawEdge(rect, EDGE_RAISED, BF_RECT);
|
|
else if (m_nChosenColorSel == nIndex)
|
|
pDC->DrawEdge(rect, EDGE_SUNKEN, BF_RECT);
|
|
|
|
CBrush brush(PALETTERGB(GetRValue(mCells[nIndex].Color), GetGValue(mCells[nIndex].Color), GetBValue(mCells[nIndex].Color) ));
|
|
CPen pen;
|
|
pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
|
|
|
|
CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush);
|
|
CPen* pOldPen = (CPen*) pDC->SelectObject(&pen);
|
|
|
|
// Draw the cell colour
|
|
rect.DeflateRect(m_nMargin+1, m_nMargin+1);
|
|
pDC->Rectangle(rect);
|
|
|
|
rect.DeflateRect(1, 1);
|
|
rect.bottom -= 1;
|
|
|
|
// restore DC and cleanup
|
|
pDC->SelectObject(pOldBrush);
|
|
pDC->SelectObject(pOldPen);
|
|
brush.DeleteObject();
|
|
pen.DeleteObject();
|
|
|
|
if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
|
|
pDC->SelectPalette(pOldPalette, FALSE);
|
|
}
|
|
|
|
BOOL CColorPopup::OnQueryNewPalette()
|
|
{
|
|
Invalidate();
|
|
return CWnd::OnQueryNewPalette();
|
|
}
|
|
|
|
void CColorPopup::OnPaletteChanged(CWnd* pFocusWnd)
|
|
{
|
|
CWnd::OnPaletteChanged(pFocusWnd);
|
|
|
|
if (pFocusWnd->GetSafeHwnd() != GetSafeHwnd())
|
|
Invalidate();
|
|
}
|
|
|
|
void CColorPopup::OnKillFocus(CWnd* pNewWnd)
|
|
{
|
|
CWnd::OnKillFocus(pNewWnd);
|
|
|
|
ReleaseCapture();
|
|
//DestroyWindow(); - causes crash when Custom colour dialog appears.
|
|
}
|
|
|
|
// KillFocus problem fix suggested by Paul Wilkerson.
|
|
void CColorPopup::OnActivateApp(BOOL bActive, DWORD hTask)
|
|
{
|
|
CWnd::OnActivateApp(bActive, hTask);
|
|
|
|
// If Deactivating App, cancel this selection
|
|
if (!bActive)
|
|
EndSelection(CPN_SELENDCANCEL);
|
|
}
|