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 23 CPaletteWindow::CPaletteWindow() 24 : m_hbmCached(NULL) 25 { 26 } 27 28 CPaletteWindow::~CPaletteWindow() 29 { 30 if (m_hbmCached) 31 ::DeleteObject(m_hbmCached); 32 } 33 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 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 55 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 73 LRESULT CPaletteWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 74 { 75 return TRUE; /* Avoid flickering */ 76 } 77 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 ::SetRect(&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 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 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 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 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 181 LRESULT CPaletteWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 182 { 183 Invalidate(FALSE); 184 return 0; 185 } 186 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 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