root / trunk / win / Clrpopup.cpp

Revision 705, 11.4 kB (checked in by leo, 17 months ago)

Fixed color picker to display new colors.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// ColorPopup.cpp : implementation file
2//
3
4#include "lc_global.h"
5#include <math.h>
6#include "ClrPick.h"
7#include "ClrPopup.h"
8#include "resource.h"
9#include "lc_colors.h"
10
11#ifdef _DEBUG
12#define new DEBUG_NEW
13#undef THIS_FILE
14static char THIS_FILE[] = __FILE__;
15#endif
16
17#define INVALID_COLOUR    -1
18
19/////////////////////////////////////////////////////////////////////////////
20// CColorPopup
21
22CColorPopup::CColorPopup()
23{
24    Initialise();
25}
26
27CColorPopup::CColorPopup(CPoint p, int ColorIndex, CWnd* pParentWnd)
28{
29    Initialise();
30
31    m_nColor = m_nInitialColor = ColorIndex;
32    m_pParent = pParentWnd;
33
34    CColorPopup::Create(p, ColorIndex, pParentWnd);
35}
36
37void CColorPopup::Initialise()
38{
39    m_nNumColumns       = 0;
40    m_nNumRows          = 0;
41    m_nBoxSize          = 18;
42    m_nMargin           = ::GetSystemMetrics(SM_CXEDGE);
43    m_nCurrentSel       = INVALID_COLOUR;
44    m_nChosenColorSel   = INVALID_COLOUR;
45    m_pParent           = NULL;
46    m_nColor            = m_nInitialColor = 0;
47
48    // Idiot check: Make sure the colour square is at least 5 x 5;
49    if (m_nBoxSize - 2*m_nMargin - 2 < 5)
50        m_nBoxSize = 5 + 2*m_nMargin + 2;
51
52    // Create the font
53    NONCLIENTMETRICS ncm;
54    ncm.cbSize = sizeof(NONCLIENTMETRICS);
55    VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
56    m_Font.CreateFontIndirect(&(ncm.lfMessageFont));
57
58    // Create the palette
59    LOGPALETTE LogPalette;
60
61    LogPalette.palVersion    = 0x300;
62    LogPalette.palNumEntries = lcNumUserColors;
63
64    for (int i = 0; i < lcNumUserColors; i++)
65    {
66        LogPalette.palPalEntry[i].peRed   = (BYTE)(lcColorList[i].Value[0] * 255);
67        LogPalette.palPalEntry[i].peGreen = (BYTE)(lcColorList[i].Value[1] * 255);
68        LogPalette.palPalEntry[i].peBlue  = (BYTE)(lcColorList[i].Value[2] * 255);
69        LogPalette.palPalEntry[i].peFlags = 0;
70    }
71
72    m_Palette.CreatePalette(&LogPalette);
73}
74
75CColorPopup::~CColorPopup()
76{
77    m_Font.DeleteObject();
78    m_Palette.DeleteObject();
79}
80
81BOOL CColorPopup::Create(CPoint p, int ColorIndex, CWnd* pParentWnd)
82{
83    ASSERT(pParentWnd && ::IsWindow(pParentWnd->GetSafeHwnd()));
84    ASSERT(pParentWnd->IsKindOf(RUNTIME_CLASS(CColorPicker)));
85
86    m_pParent  = pParentWnd;
87    m_nColor = m_nInitialColor = ColorIndex;
88
89    // Get the class name and create the window
90    CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW, 0, (HBRUSH)GetStockObject(LTGRAY_BRUSH),0);
91
92    if (!CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE|WS_POPUP,
93                        p.x, p.y, 100, 100, // size updated soon
94                        pParentWnd->GetSafeHwnd(), 0, NULL))
95        return FALSE;
96
97    // Set the window size
98    SetWindowSize();
99
100    // Create the tooltips
101    CreateToolTips();
102
103    m_nChosenColorSel = ColorIndex;
104
105    // Capture all mouse events for the life of this window
106    SetCapture();
107
108    return TRUE;
109}
110
111BEGIN_MESSAGE_MAP(CColorPopup, CWnd)
112    //{{AFX_MSG_MAP(CColorPopup)
113    ON_WM_NCDESTROY()
114    ON_WM_LBUTTONUP()
115    ON_WM_PAINT()
116    ON_WM_MOUSEMOVE()
117    ON_WM_KEYDOWN()
118    ON_WM_QUERYNEWPALETTE()
119    ON_WM_PALETTECHANGED()
120    ON_WM_KILLFOCUS()
121    ON_WM_ACTIVATEAPP()
122    //}}AFX_MSG_MAP
123END_MESSAGE_MAP()
124
125/////////////////////////////////////////////////////////////////////////////
126// CColorPopup message handlers
127
128// For tooltips
129BOOL CColorPopup::PreTranslateMessage(MSG* pMsg)
130{
131    m_ToolTip.RelayEvent(pMsg);
132    return CWnd::PreTranslateMessage(pMsg);
133}
134
135// If an arrow key is pressed, then move the selection
136void CColorPopup::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
137{
138    int row = GetRow(m_nCurrentSel), col = GetColumn(m_nCurrentSel);
139    int nSelection = m_nCurrentSel;
140
141    if (nChar == VK_DOWN)
142    {
143        row++;
144        if (GetIndex(row,col) < 0)
145            row = col = 0;
146        ChangeSelection(GetIndex(row, col));
147    }
148
149    if (nChar == VK_UP)
150    {
151        if (row > 0)
152            row--;
153        else
154        {
155            row = GetRow(lcNumUserColors-1);
156            col = GetColumn(lcNumUserColors-1);
157        }
158        ChangeSelection(GetIndex(row, col));
159    }
160
161    if (nChar == VK_RIGHT)
162    {
163        if (col < m_nNumColumns-1)
164            col++;
165        else 
166        {
167            col = 0;
168            row++;
169        }
170
171        if (GetIndex(row,col) == INVALID_COLOUR)
172            row = col = 0;
173
174        ChangeSelection(GetIndex(row, col));
175    }
176
177    if (nChar == VK_LEFT)
178    {
179        if (col > 0)
180            col--;
181        else
182        {
183            if (row > 0)
184            {
185                row--;
186                col = m_nNumColumns-1;
187            }
188            else 
189            {
190                row = GetRow(lcNumUserColors-1);
191                col = GetColumn(lcNumUserColors-1);
192            }
193        }
194        ChangeSelection(GetIndex(row, col));
195    }
196
197    if (nChar == VK_ESCAPE)
198    {
199        m_nColor = m_nInitialColor;
200        EndSelection(CPN_SELENDCANCEL);
201        return;
202    }
203
204    if (nChar == VK_RETURN || nChar == VK_SPACE)
205    {
206        EndSelection(CPN_SELENDOK);
207        return;
208    }
209
210    CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
211}
212
213// auto-deletion
214void CColorPopup::OnNcDestroy()
215{
216    CWnd::OnNcDestroy();
217    delete this;
218}
219
220void CColorPopup::OnPaint()
221{
222    CPaintDC dc(this); // device context for painting
223
224    // Draw colour cells
225    for (int i = 0; i < lcNumUserColors; i++)
226        DrawCell(&dc, i);
227
228    // Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
229    // but for some reason isn't
230    CRect rect;
231    GetClientRect(rect);
232    dc.DrawEdge(rect, EDGE_RAISED, BF_RECT);
233}
234
235void CColorPopup::OnMouseMove(UINT nFlags, CPoint point)
236{
237    int nNewSelection = INVALID_COLOUR;
238
239    // Translate points to be relative raised window edge
240    point.x -= m_nMargin;
241    point.y -= m_nMargin;
242
243    // Get the row and column
244    nNewSelection = GetIndex(point.y / m_nBoxSize, point.x / m_nBoxSize);
245
246    // In range? If not, default and exit
247    if (nNewSelection < 0 || nNewSelection >= lcNumUserColors)
248    {
249        CWnd::OnMouseMove(nFlags, point);
250        return;
251    }
252
253    // Has the row/col selection changed? If yes, then redraw old and new cells.
254    if (nNewSelection != m_nCurrentSel)
255        ChangeSelection(nNewSelection);
256
257    CWnd::OnMouseMove(nFlags, point);
258}
259
260// End selection on LButtonUp
261void CColorPopup::OnLButtonUp(UINT nFlags, CPoint point)
262{
263    CWnd::OnLButtonUp(nFlags, point);
264
265    DWORD pos = GetMessagePos();
266    point = CPoint(LOWORD(pos), HIWORD(pos));
267
268    if (m_WindowRect.PtInRect(point))
269        EndSelection(CPN_SELENDOK);
270    else
271        EndSelection(CPN_SELENDCANCEL);
272}
273
274/////////////////////////////////////////////////////////////////////////////
275// CColorPopup implementation
276
277int CColorPopup::GetIndex(int row, int col) const
278{
279    if (row < 0 || col < 0 || row >= m_nNumRows || col >= m_nNumColumns)
280        return INVALID_COLOUR;
281    else
282    {
283        if (row*m_nNumColumns + col >= lcNumUserColors)
284            return INVALID_COLOUR;
285        else
286            return row*m_nNumColumns + col;
287    }
288}
289
290int CColorPopup::GetRow(int nIndex) const
291{
292    if (nIndex < 0 || nIndex >= lcNumUserColors)
293        return INVALID_COLOUR;
294    else
295        return nIndex / m_nNumColumns;
296}
297
298int CColorPopup::GetColumn(int nIndex) const
299{
300    if (nIndex < 0 || nIndex >= lcNumUserColors)
301        return INVALID_COLOUR;
302    else
303        return nIndex % m_nNumColumns;
304}
305
306// Gets the dimensions of the colour cell given by (row,col)
307BOOL CColorPopup::GetCellRect(int nIndex, const LPRECT& rect)
308{
309    if (nIndex < 0 || nIndex >= lcNumUserColors)
310        return FALSE;
311
312    rect->left = GetColumn(nIndex) * m_nBoxSize + m_nMargin;
313    rect->top  = GetRow(nIndex) * m_nBoxSize + m_nMargin;
314
315    rect->right = rect->left + m_nBoxSize;
316    rect->bottom = rect->top + m_nBoxSize;
317
318    return TRUE;
319}
320
321// Works out an appropriate size and position of this window
322void CColorPopup::SetWindowSize()
323{
324    // Get the number of columns and rows
325    m_nNumColumns = 13;
326    m_nNumRows = lcNumUserColors / m_nNumColumns;
327    if (lcNumUserColors % m_nNumColumns)
328        m_nNumRows++;
329
330    // Get the current window position, and set the new size
331    CRect rect;
332    GetWindowRect(rect);
333
334    m_WindowRect.SetRect(rect.left, rect.top,
335        rect.left + m_nNumColumns*m_nBoxSize + 2*m_nMargin,
336        rect.top  + m_nNumRows*m_nBoxSize + 2*m_nMargin);
337
338    // Need to check it'll fit on screen: Too far right?
339    CSize ScreenSize(::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN));
340    if (m_WindowRect.right > ScreenSize.cx)
341        m_WindowRect.OffsetRect(-(m_WindowRect.right - ScreenSize.cx), 0);
342
343    // Too far left?
344    if (m_WindowRect.left < 0)
345        m_WindowRect.OffsetRect( -m_WindowRect.left, 0);
346
347    // Bottom falling out of screen?
348    if (m_WindowRect.bottom > ScreenSize.cy)
349    {
350        CRect ParentRect;
351        m_pParent->GetWindowRect(ParentRect);
352        m_WindowRect.OffsetRect(0, -(ParentRect.Height() + m_WindowRect.Height()));
353    }
354
355    // Set the window size and position
356    MoveWindow(m_WindowRect, TRUE);
357}
358
359void CColorPopup::CreateToolTips()
360{
361    // Create the tool tip
362    if (!m_ToolTip.Create(this))
363        return;
364
365    // Add a tool for each cell
366    for (int i = 0; i < lcNumUserColors; i++)
367    {
368        CRect rect;
369        if (!GetCellRect(i, rect))
370            continue;
371        m_ToolTip.AddTool(this, lcColorList[i].Name, rect, 1);
372    }
373}
374
375void CColorPopup::ChangeSelection(int nIndex)
376{
377    CClientDC dc(this);        // device context for drawing
378
379    if (nIndex > lcNumUserColors)
380        nIndex = 0;
381
382    if ((m_nCurrentSel >= 0 && m_nCurrentSel < lcNumUserColors))
383    {
384        // Set Current selection as invalid and redraw old selection (this way
385        // the old selection will be drawn unselected)
386        int OldSel = m_nCurrentSel;
387        m_nCurrentSel = INVALID_COLOUR;
388        DrawCell(&dc, OldSel);
389    }
390
391    // Set the current selection as row/col and draw (it will be drawn selected)
392    m_nCurrentSel = nIndex;
393    DrawCell(&dc, m_nCurrentSel);
394}
395
396void CColorPopup::EndSelection(int nMessage)
397{
398    ReleaseCapture();
399
400    if (nMessage == CPN_SELENDCANCEL)
401        m_nColor = m_nInitialColor;
402
403    m_pParent->SendMessage(nMessage, (WPARAM)m_nColor, (LPARAM)m_nCurrentSel);
404
405    DestroyWindow();
406}
407
408void CColorPopup::DrawCell(CDC* pDC, int nIndex)
409{
410    CRect rect;
411    if (!GetCellRect(nIndex, rect))
412        return;
413
414    // Select and realize the palette
415    CPalette* pOldPalette;
416    if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
417    {
418        pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
419        pDC->RealizePalette();
420    }
421
422    // fill background
423    if (m_nChosenColorSel == nIndex && m_nCurrentSel != nIndex)
424        pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DHILIGHT));
425    else
426        pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
427
428    // Draw button
429    if (m_nCurrentSel == nIndex)
430        pDC->DrawEdge(rect, EDGE_RAISED, BF_RECT);
431    else if (m_nChosenColorSel == nIndex)
432        pDC->DrawEdge(rect, EDGE_SUNKEN, BF_RECT);
433
434    CBrush brush;
435
436    if (LC_COLOR_TRANSLUCENT(nIndex))
437    {
438        WORD CheckerBits[8] = { 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33 };
439
440        // Use the bit pattern to create a bitmap.
441        CBitmap bm;
442        bm.CreateBitmap(8,8,1,1, CheckerBits);
443
444        // Create a pattern brush from the bitmap.
445        brush.CreatePatternBrush(&bm);
446        pDC->SetTextColor(LC_COLOR_RGB(nIndex));
447        pDC->SetBkColor(RGB(255,255,255));
448    }
449    else
450    {
451        brush.CreateSolidBrush(LC_COLOR_RGB(nIndex));
452    }
453
454    CPen pen;
455    pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
456
457    CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush);
458    CPen*   pOldPen   = (CPen*)   pDC->SelectObject(&pen);
459
460    // Draw the cell colour
461    rect.DeflateRect(m_nMargin+1, m_nMargin+1);
462    pDC->Rectangle(rect);
463
464    // restore DC and cleanup
465    pDC->SelectObject(pOldBrush);
466    pDC->SelectObject(pOldPen);
467    brush.DeleteObject();
468    pen.DeleteObject();
469
470    if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
471        pDC->SelectPalette(pOldPalette, FALSE);
472}
473
474BOOL CColorPopup::OnQueryNewPalette()
475{
476    Invalidate();
477    return CWnd::OnQueryNewPalette();
478}
479
480void CColorPopup::OnPaletteChanged(CWnd* pFocusWnd)
481{
482    CWnd::OnPaletteChanged(pFocusWnd);
483
484    if (pFocusWnd->GetSafeHwnd() != GetSafeHwnd())
485        Invalidate();
486}
487
488void CColorPopup::OnKillFocus(CWnd* pNewWnd)
489{
490    CWnd::OnKillFocus(pNewWnd);
491
492    ReleaseCapture();
493    //DestroyWindow(); - causes crash when Custom colour dialog appears.
494}
495
496// KillFocus problem fix suggested by Paul Wilkerson.
497void CColorPopup::OnActivateApp(BOOL bActive, ACTIVATEAPPPARAM hTask)
498{
499    CWnd::OnActivateApp(bActive, hTask);
500
501    // If Deactivating App, cancel this selection
502    if (!bActive)
503         EndSelection(CPN_SELENDCANCEL);
504}
Note: See TracBrowser for help on using the browser.