1 /*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Window procedure of the palette window
5 * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net>
6 * Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7 */
8
9 #include "precomp.h"
10
11 /* The private metrics */
12 #define CXY_SELECTEDBOX 15 /* width / height of a selected color box */
13 #define X_MARGIN 4 /* horizontal margin */
14 #define Y_MARGIN ((rcClient.bottom / 2) - CXY_COLORBOX) /* center position minus one color box */
15 #define X_COLORBOX_OFFSET (X_MARGIN + CXY_BIGBOX + X_MARGIN)
16 #define COLOR_COUNT 28
17 #define HALF_COLOR_COUNT (COLOR_COUNT / 2)
18
19 CPaletteWindow paletteWindow;
20
21 /* FUNCTIONS ********************************************************/
22
CPaletteWindow()23 CPaletteWindow::CPaletteWindow()
24 : m_hbmCached(NULL)
25 {
26 }
27
~CPaletteWindow()28 CPaletteWindow::~CPaletteWindow()
29 {
30 if (m_hbmCached)
31 ::DeleteObject(m_hbmCached);
32 }
33
drawColorBox(HDC hDC,LPCRECT prc,COLORREF rgbColor,UINT nBorder)34 static VOID drawColorBox(HDC hDC, LPCRECT prc, COLORREF rgbColor, UINT nBorder)
35 {
36 RECT rc = *prc;
37 ::FillRect(hDC, &rc, (HBRUSH)(COLOR_3DFACE + 1));
38 ::DrawEdge(hDC, &rc, nBorder, BF_RECT | BF_ADJUST);
39
40 HBRUSH hbr = ::CreateSolidBrush(rgbColor);
41 ::FillRect(hDC, &rc, hbr);
42 ::DeleteObject(hbr);
43 }
44
getColorBoxRect(LPRECT prc,const RECT & rcClient,INT iColor)45 static VOID getColorBoxRect(LPRECT prc, const RECT& rcClient, INT iColor)
46 {
47 INT dx = (iColor % HALF_COLOR_COUNT) * CXY_COLORBOX; /* delta x */
48 INT dy = (iColor / HALF_COLOR_COUNT) * CXY_COLORBOX; /* delta y */
49 prc->left = X_COLORBOX_OFFSET + dx;
50 prc->right = prc->left + CXY_COLORBOX;
51 prc->top = Y_MARGIN + dy;
52 prc->bottom = prc->top + CXY_COLORBOX;
53 }
54
DoHitTest(INT xPos,INT yPos) const55 INT CPaletteWindow::DoHitTest(INT xPos, INT yPos) const
56 {
57 RECT rcClient;
58 GetClientRect(&rcClient);
59
60 /* delta x and y */
61 INT dx = (xPos - X_COLORBOX_OFFSET), dy = (yPos - Y_MARGIN);
62
63 /* horizontal and vertical indexes */
64 INT ix = (dx / CXY_COLORBOX), iy = (dy / CXY_COLORBOX);
65
66 /* Is it inside of a color box? */
67 if (0 <= ix && ix < HALF_COLOR_COUNT && 0 <= iy && iy < 2)
68 return ix + (iy * HALF_COLOR_COUNT); /* return the color index */
69
70 return -1; /* Not found */
71 }
72
OnEraseBkgnd(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)73 LRESULT CPaletteWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
74 {
75 return TRUE; /* Avoid flickering */
76 }
77
OnPaint(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)78 LRESULT CPaletteWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
79 {
80 RECT rc, rcClient;
81 GetClientRect(&rcClient);
82
83 PAINTSTRUCT ps;
84 HDC hDC = BeginPaint(&ps);
85
86 /* To avoid flickering, we use a memory bitmap.
87 The left and top values are zeros in client rectangle */
88 HDC hMemDC = ::CreateCompatibleDC(hDC);
89 m_hbmCached = CachedBufferDIB(m_hbmCached, rcClient.right, rcClient.bottom);
90 HGDIOBJ hbmOld = ::SelectObject(hMemDC, m_hbmCached);
91
92 /* Fill the background (since WM_ERASEBKGND handling is disabled) */
93 ::FillRect(hMemDC, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
94
95 /* Draw the big box that contains the black box and the white box */
96 rc = { X_MARGIN, Y_MARGIN, X_MARGIN + CXY_BIGBOX, Y_MARGIN + CXY_BIGBOX };
97 ::DrawEdge(hMemDC, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
98 COLORREF rgbLight = ::GetSysColor(COLOR_3DHIGHLIGHT);
99 for (INT y = rc.top; y < rc.bottom; ++y)
100 {
101 BOOL bLight = (y & 1);
102 for (INT x = rc.left; x < rc.right; ++x)
103 {
104 if (bLight)
105 ::SetPixelV(hMemDC, x, y, rgbLight);
106 bLight = !bLight;
107 }
108 }
109
110 /* Draw the white box in the big box, at 5/8 position */
111 rc.left = X_MARGIN + (CXY_BIGBOX * 5 / 8) - (CXY_SELECTEDBOX / 2);
112 rc.top = Y_MARGIN + (CXY_BIGBOX * 5 / 8) - (CXY_SELECTEDBOX / 2);
113 rc.right = rc.left + CXY_SELECTEDBOX;
114 rc.bottom = rc.top + CXY_SELECTEDBOX;
115 drawColorBox(hMemDC, &rc, paletteModel.GetBgColor(), BDR_RAISEDINNER);
116
117 /* Draw the black box (overlapping the white box), at 3/8 position */
118 rc.left = X_MARGIN + (CXY_BIGBOX * 3 / 8) - (CXY_SELECTEDBOX / 2);
119 rc.top = Y_MARGIN + (CXY_BIGBOX * 3 / 8) - (CXY_SELECTEDBOX / 2);
120 rc.right = rc.left + CXY_SELECTEDBOX;
121 rc.bottom = rc.top + CXY_SELECTEDBOX;
122 drawColorBox(hMemDC, &rc, paletteModel.GetFgColor(), BDR_RAISEDINNER);
123
124 /* Draw the normal color boxes */
125 for (INT i = 0; i < COLOR_COUNT; i++)
126 {
127 getColorBoxRect(&rc, rcClient, i);
128 drawColorBox(hMemDC, &rc, paletteModel.GetColor(i), BDR_SUNKENOUTER);
129 }
130
131 /* Transfer bits (hDC <-- hMemDC) */
132 ::BitBlt(hDC, 0, 0, rcClient.right, rcClient.bottom, hMemDC, 0, 0, SRCCOPY);
133
134 ::SelectObject(hMemDC, hbmOld);
135 ::DeleteDC(hMemDC);
136 EndPaint(&ps);
137 return 0;
138 }
139
OnLButtonDown(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)140 LRESULT CPaletteWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
141 {
142 INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
143 if (iColor != -1)
144 paletteModel.SetFgColor(paletteModel.GetColor(iColor));
145 SetCapture();
146 return 0;
147 }
148
OnRButtonDown(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)149 LRESULT CPaletteWindow::OnRButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
150 {
151 INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
152 if (iColor != -1)
153 paletteModel.SetBgColor(paletteModel.GetColor(iColor));
154 return 0;
155 }
156
OnLButtonDblClk(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)157 LRESULT CPaletteWindow::OnLButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
158 {
159 INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
160 COLORREF rgbColor = paletteModel.GetFgColor();
161 if (iColor != -1 && mainWindow.ChooseColor(&rgbColor))
162 {
163 paletteModel.SetColor(iColor, rgbColor);
164 paletteModel.SetFgColor(rgbColor);
165 }
166 return 0;
167 }
168
OnRButtonDblClk(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)169 LRESULT CPaletteWindow::OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
170 {
171 INT iColor = DoHitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
172 COLORREF rgbColor = paletteModel.GetBgColor();
173 if (iColor != -1 && mainWindow.ChooseColor(&rgbColor))
174 {
175 paletteModel.SetColor(iColor, rgbColor);
176 paletteModel.SetBgColor(rgbColor);
177 }
178 return 0;
179 }
180
OnPaletteModelColorChanged(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)181 LRESULT CPaletteWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
182 {
183 Invalidate(FALSE);
184 return 0;
185 }
186
OnMouseMove(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)187 LRESULT CPaletteWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
188 {
189 if (::GetCapture() != m_hWnd)
190 return 0;
191
192 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
193 ClientToScreen(&pt);
194
195 RECT rc;
196 mainWindow.GetWindowRect(&rc);
197
198 POINT ptCenter = { (rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2 };
199
200 DWORD dwExpectedBar1ID = ((pt.y < ptCenter.y) ? BAR1ID_TOP : BAR1ID_BOTTOM);
201
202 if (registrySettings.Bar1ID != dwExpectedBar1ID)
203 {
204 registrySettings.Bar1ID = dwExpectedBar1ID;
205 mainWindow.PostMessage(WM_SIZE, 0, 0);
206 }
207
208 return 0;
209 }
210
OnLButtonUp(UINT nMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)211 LRESULT CPaletteWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
212 {
213 if (::GetCapture() != m_hWnd)
214 return 0;
215
216 ::ReleaseCapture();
217 return 0;
218 }
219