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 tool settings window 5 * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net> 6 * Copyright 2018 Stanislav Motylkov <x86corez@gmail.com> 7 * Copyright 2021-2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 8 */ 9 10 /* INCLUDES *********************************************************/ 11 12 #include "precomp.h" 13 14 #define X_TOOLSETTINGS 0 15 #define Y_TOOLSETTINGS (CY_TOOLBAR + 3) 16 #define CX_TOOLSETTINGS CX_TOOLBAR 17 #define CY_TOOLSETTINGS 140 18 19 #define CX_TRANS_ICON 40 20 #define CY_TRANS_ICON 30 21 #define MARGIN1 3 22 #define MARGIN2 2 23 24 static const BYTE s_AirRadius[4] = { 5, 8, 3, 12 }; 25 26 CToolSettingsWindow toolSettingsWindow; 27 28 /* FUNCTIONS ********************************************************/ 29 30 BOOL CToolSettingsWindow::DoCreate(HWND hwndParent) 31 { 32 RECT toolSettingsWindowPos = 33 { 34 X_TOOLSETTINGS, Y_TOOLSETTINGS, 35 X_TOOLSETTINGS + CX_TOOLSETTINGS, Y_TOOLSETTINGS + CY_TOOLSETTINGS 36 }; 37 return !!Create(toolBoxContainer, toolSettingsWindowPos, NULL, WS_CHILD | WS_VISIBLE); 38 } 39 40 static INT 41 getSplitRects(RECT *rects, INT cColumns, INT cRows, LPCRECT prc, LPPOINT ppt) 42 { 43 INT cx = prc->right - prc->left, cy = prc->bottom - prc->top; 44 for (INT i = 0, iRow = 0; iRow < cRows; ++iRow) 45 { 46 for (INT iColumn = 0; iColumn < cColumns; ++iColumn) 47 { 48 RECT& rc = rects[i]; 49 rc.left = prc->left + (iColumn * cx / cColumns); 50 rc.top = prc->top + (iRow * cy / cRows); 51 rc.right = prc->left + ((iColumn + 1) * cx / cColumns); 52 rc.bottom = prc->top + ((iRow + 1) * cy / cRows); 53 if (ppt && ::PtInRect(&rc, *ppt)) 54 return i; 55 ++i; 56 } 57 } 58 return -1; 59 } 60 61 static inline INT getTransRects(RECT rects[2], LPCRECT prc, LPPOINT ppt = NULL) 62 { 63 return getSplitRects(rects, 1, 2, prc, ppt); 64 } 65 66 VOID CToolSettingsWindow::drawTrans(HDC hdc, LPCRECT prc) 67 { 68 RECT rc[2]; 69 getTransRects(rc, prc); 70 71 ::FillRect(hdc, &rc[toolsModel.IsBackgroundTransparent()], (HBRUSH)(COLOR_HIGHLIGHT + 1)); 72 ::DrawIconEx(hdc, rc[0].left, rc[0].top, m_hNontranspIcon, 73 CX_TRANS_ICON, CY_TRANS_ICON, 0, NULL, DI_NORMAL); 74 ::DrawIconEx(hdc, rc[1].left, rc[1].top, m_hTranspIcon, 75 CX_TRANS_ICON, CY_TRANS_ICON, 0, NULL, DI_NORMAL); 76 } 77 78 static inline INT getRubberRects(RECT rects[4], LPCRECT prc, LPPOINT ppt = NULL) 79 { 80 return getSplitRects(rects, 1, 4, prc, ppt); 81 } 82 83 VOID CToolSettingsWindow::drawRubber(HDC hdc, LPCRECT prc) 84 { 85 RECT rects[4], rcRubber; 86 getRubberRects(rects, prc); 87 INT xCenter = (prc->left + prc->right) / 2; 88 for (INT i = 0; i < 4; i++) 89 { 90 INT iColor, radius = i + 2; 91 if (toolsModel.GetRubberRadius() == radius) 92 { 93 ::FillRect(hdc, &rects[i], ::GetSysColorBrush(COLOR_HIGHLIGHT)); 94 iColor = COLOR_HIGHLIGHTTEXT; 95 } 96 else 97 { 98 iColor = COLOR_WINDOWTEXT; 99 } 100 101 INT yCenter = (rects[i].top + rects[i].bottom) / 2; 102 rcRubber.left = xCenter - radius; 103 rcRubber.top = yCenter - radius; 104 rcRubber.right = rcRubber.left + radius * 2; 105 rcRubber.bottom = rcRubber.top + radius * 2; 106 ::FillRect(hdc, &rcRubber, GetSysColorBrush(iColor)); 107 } 108 } 109 110 static inline INT getBrushRects(RECT rects[12], LPCRECT prc, LPPOINT ppt = NULL) 111 { 112 return getSplitRects(rects, 3, 4, prc, ppt); 113 } 114 115 VOID CToolSettingsWindow::drawBrush(HDC hdc, LPCRECT prc) 116 { 117 RECT rects[12]; 118 getBrushRects(rects, prc); 119 120 ::FillRect(hdc, &rects[toolsModel.GetBrushStyle()], (HBRUSH)(COLOR_HIGHLIGHT + 1)); 121 122 for (INT i = 0; i < 12; i++) 123 { 124 RECT rcItem = rects[i]; 125 INT x = (rcItem.left + rcItem.right) / 2, y = (rcItem.top + rcItem.bottom) / 2; 126 INT iColor; 127 if (i == toolsModel.GetBrushStyle()) 128 iColor = COLOR_HIGHLIGHTTEXT; 129 else 130 iColor = COLOR_WINDOWTEXT; 131 Brush(hdc, x, y, x, y, ::GetSysColor(iColor), i); 132 } 133 } 134 135 static inline INT getLineRects(RECT rects[5], LPCRECT prc, LPPOINT ppt = NULL) 136 { 137 return getSplitRects(rects, 1, 5, prc, ppt); 138 } 139 140 VOID CToolSettingsWindow::drawLine(HDC hdc, LPCRECT prc) 141 { 142 RECT rects[5]; 143 getLineRects(rects, prc); 144 145 for (INT i = 0; i < 5; i++) 146 { 147 INT penWidth = i + 1; 148 RECT rcLine = rects[i]; 149 ::InflateRect(&rcLine, -2, 0); 150 rcLine.top = (rcLine.top + rcLine.bottom - penWidth) / 2; 151 rcLine.bottom = rcLine.top + penWidth; 152 if (toolsModel.GetLineWidth() == penWidth) 153 { 154 ::FillRect(hdc, &rects[i], ::GetSysColorBrush(COLOR_HIGHLIGHT)); 155 ::FillRect(hdc, &rcLine, ::GetSysColorBrush(COLOR_HIGHLIGHTTEXT)); 156 } 157 else 158 { 159 ::FillRect(hdc, &rcLine, ::GetSysColorBrush(COLOR_WINDOWTEXT)); 160 } 161 } 162 } 163 164 static INT getAirBrushRects(RECT rects[4], LPCRECT prc, LPPOINT ppt = NULL) 165 { 166 INT cx = (prc->right - prc->left), cy = (prc->bottom - prc->top); 167 168 rects[0] = rects[1] = rects[2] = rects[3] = *prc; 169 170 rects[0].right = rects[1].left = prc->left + cx * 3 / 8; 171 rects[0].bottom = rects[1].bottom = prc->top + cy / 2; 172 173 rects[2].top = rects[3].top = prc->top + cy / 2; 174 rects[2].right = rects[3].left = prc->left + cx * 2 / 8; 175 176 if (ppt) 177 { 178 for (INT i = 0; i < 4; ++i) 179 { 180 if (::PtInRect(&rects[i], *ppt)) 181 return i; 182 } 183 } 184 return -1; 185 } 186 187 VOID CToolSettingsWindow::drawAirBrush(HDC hdc, LPCRECT prc) 188 { 189 RECT rects[4]; 190 getAirBrushRects(rects, prc); 191 192 srand(0); 193 for (size_t i = 0; i < 4; ++i) 194 { 195 RECT& rc = rects[i]; 196 INT x = (rc.left + rc.right) / 2; 197 INT y = (rc.top + rc.bottom) / 2; 198 BOOL bHigh = (s_AirRadius[i] == toolsModel.GetAirBrushWidth()); 199 if (bHigh) 200 { 201 ::FillRect(hdc, &rc, ::GetSysColorBrush(COLOR_HIGHLIGHT)); 202 203 for (int k = 0; k < 3; ++k) 204 Airbrush(hdc, x, y, ::GetSysColor(COLOR_HIGHLIGHTTEXT), s_AirRadius[i]); 205 } 206 else 207 { 208 for (int k = 0; k < 3; ++k) 209 Airbrush(hdc, x, y, ::GetSysColor(COLOR_WINDOWTEXT), s_AirRadius[i]); 210 } 211 } 212 } 213 214 static inline INT getBoxRects(RECT rects[3], LPCRECT prc, LPPOINT ppt = NULL) 215 { 216 return getSplitRects(rects, 1, 3, prc, ppt); 217 } 218 219 VOID CToolSettingsWindow::drawBox(HDC hdc, LPCRECT prc) 220 { 221 RECT rects[3]; 222 getBoxRects(rects, prc); 223 224 for (INT iItem = 0; iItem < 3; ++iItem) 225 { 226 RECT& rcItem = rects[iItem]; 227 228 if (toolsModel.GetShapeStyle() == iItem) 229 ::FillRect(hdc, &rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT)); 230 231 ::InflateRect(&rcItem, -5, -5); 232 233 if (iItem <= 1) 234 { 235 COLORREF rgbPen; 236 if (toolsModel.GetShapeStyle() == iItem) 237 rgbPen = ::GetSysColor(COLOR_HIGHLIGHTTEXT); 238 else 239 rgbPen = ::GetSysColor(COLOR_WINDOWTEXT); 240 HGDIOBJ hOldBrush; 241 if (iItem == 0) 242 hOldBrush = ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH)); 243 else 244 hOldBrush = ::SelectObject(hdc, ::GetSysColorBrush(COLOR_APPWORKSPACE)); 245 HGDIOBJ hOldPen = ::SelectObject(hdc, ::CreatePen(PS_SOLID, 1, rgbPen)); 246 ::Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom); 247 ::DeleteObject(::SelectObject(hdc, hOldPen)); 248 ::SelectObject(hdc, hOldBrush); 249 } 250 else 251 { 252 if (toolsModel.GetShapeStyle() == iItem) 253 ::FillRect(hdc, &rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHTTEXT)); 254 else 255 ::FillRect(hdc, &rcItem, ::GetSysColorBrush(COLOR_WINDOWTEXT)); 256 } 257 } 258 } 259 260 LRESULT CToolSettingsWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, WINBOOL& bHandled) 261 { 262 /* preloading the draw transparent/nontransparent icons for later use */ 263 m_hNontranspIcon = (HICON)LoadImage(g_hinstExe, MAKEINTRESOURCE(IDI_NONTRANSPARENT), 264 IMAGE_ICON, CX_TRANS_ICON, CY_TRANS_ICON, LR_DEFAULTCOLOR); 265 m_hTranspIcon = (HICON)LoadImage(g_hinstExe, MAKEINTRESOURCE(IDI_TRANSPARENT), 266 IMAGE_ICON, CX_TRANS_ICON, CY_TRANS_ICON, LR_DEFAULTCOLOR); 267 268 RECT trackbarZoomPos = {1, 1, 1 + 40, 1 + 64}; 269 trackbarZoom.Create(TRACKBAR_CLASS, m_hWnd, trackbarZoomPos, NULL, WS_CHILD | TBS_VERT | TBS_AUTOTICKS); 270 trackbarZoom.SendMessage(TBM_SETRANGE, (WPARAM) TRUE, MAKELPARAM(0, 6)); 271 trackbarZoom.SendMessage(TBM_SETPOS, (WPARAM) TRUE, (LPARAM) 3); 272 return 0; 273 } 274 275 LRESULT CToolSettingsWindow::OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 276 { 277 ::DestroyIcon(m_hNontranspIcon); 278 ::DestroyIcon(m_hTranspIcon); 279 return 0; 280 } 281 282 LRESULT CToolSettingsWindow::OnVScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 283 { 284 if (!zoomTo(125 << trackbarZoom.SendMessage(TBM_GETPOS, 0, 0), 0, 0)) 285 { 286 OnToolsModelZoomChanged(nMsg, wParam, lParam, bHandled); 287 } 288 return 0; 289 } 290 291 VOID CToolSettingsWindow::calculateTwoBoxes(RECT& rect1, RECT& rect2) 292 { 293 RECT rcClient; 294 GetClientRect(&rcClient); 295 ::InflateRect(&rcClient, -MARGIN1, -MARGIN1); 296 297 INT yCenter = (rcClient.top + rcClient.bottom) / 2; 298 ::SetRect(&rect1, rcClient.left, rcClient.top, rcClient.right, yCenter); 299 ::SetRect(&rect2, rcClient.left, yCenter, rcClient.right, rcClient.bottom); 300 301 ::InflateRect(&rect1, -MARGIN2, -MARGIN2); 302 ::InflateRect(&rect2, -MARGIN2, -MARGIN2); 303 } 304 305 LRESULT CToolSettingsWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 306 { 307 RECT rect1, rect2; 308 calculateTwoBoxes(rect1, rect2); 309 310 PAINTSTRUCT ps; 311 HDC hdc = BeginPaint(&ps); 312 313 if (toolsModel.GetActiveTool() == TOOL_ZOOM) 314 ::DrawEdge(hdc, &rect1, BDR_SUNKENOUTER, BF_RECT); 315 else 316 ::DrawEdge(hdc, &rect1, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); 317 318 if (toolsModel.GetActiveTool() >= TOOL_RECT) 319 ::DrawEdge(hdc, &rect2, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); 320 321 ::InflateRect(&rect1, -MARGIN2, -MARGIN2); 322 ::InflateRect(&rect2, -MARGIN2, -MARGIN2); 323 switch (toolsModel.GetActiveTool()) 324 { 325 case TOOL_FREESEL: 326 case TOOL_RECTSEL: 327 case TOOL_TEXT: 328 drawTrans(hdc, &rect1); 329 break; 330 case TOOL_RUBBER: 331 drawRubber(hdc, &rect1); 332 break; 333 case TOOL_BRUSH: 334 drawBrush(hdc, &rect1); 335 break; 336 case TOOL_AIRBRUSH: 337 drawAirBrush(hdc, &rect1); 338 break; 339 case TOOL_LINE: 340 case TOOL_BEZIER: 341 drawLine(hdc, &rect1); 342 break; 343 case TOOL_RECT: 344 case TOOL_SHAPE: 345 case TOOL_ELLIPSE: 346 case TOOL_RRECT: 347 drawBox(hdc, &rect1); 348 drawLine(hdc, &rect2); 349 break; 350 case TOOL_FILL: 351 case TOOL_COLOR: 352 case TOOL_ZOOM: 353 case TOOL_PEN: 354 break; 355 } 356 EndPaint(&ps); 357 return 0; 358 } 359 360 LRESULT CToolSettingsWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 361 { 362 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 363 364 RECT rect1, rect2; 365 calculateTwoBoxes(rect1, rect2); 366 RECT rects[12]; 367 368 INT iItem; 369 switch (toolsModel.GetActiveTool()) 370 { 371 case TOOL_FREESEL: 372 case TOOL_RECTSEL: 373 case TOOL_TEXT: 374 iItem = getTransRects(rects, &rect1, &pt); 375 if (iItem != -1) 376 toolsModel.SetBackgroundTransparent(iItem); 377 break; 378 case TOOL_RUBBER: 379 iItem = getRubberRects(rects, &rect1, &pt); 380 if (iItem != -1) 381 toolsModel.SetRubberRadius(iItem + 2); 382 break; 383 case TOOL_BRUSH: 384 iItem = getBrushRects(rects, &rect1, &pt); 385 if (iItem != -1) 386 toolsModel.SetBrushStyle(iItem); 387 break; 388 case TOOL_AIRBRUSH: 389 iItem = getAirBrushRects(rects, &rect1, &pt); 390 if (iItem != -1) 391 toolsModel.SetAirBrushWidth(s_AirRadius[iItem]); 392 break; 393 case TOOL_LINE: 394 case TOOL_BEZIER: 395 iItem = getLineRects(rects, &rect1, &pt); 396 if (iItem != -1) 397 toolsModel.SetLineWidth(iItem + 1); 398 break; 399 case TOOL_RECT: 400 case TOOL_SHAPE: 401 case TOOL_ELLIPSE: 402 case TOOL_RRECT: 403 iItem = getBoxRects(rects, &rect1, &pt); 404 if (iItem != -1) 405 toolsModel.SetShapeStyle(iItem); 406 407 iItem = getLineRects(rects, &rect2, &pt); 408 if (iItem != -1) 409 toolsModel.SetLineWidth(iItem + 1); 410 break; 411 case TOOL_FILL: 412 case TOOL_COLOR: 413 case TOOL_ZOOM: 414 case TOOL_PEN: 415 break; 416 } 417 418 ::SetCapture(::GetParent(m_hWnd)); 419 return 0; 420 } 421 422 LRESULT CToolSettingsWindow::OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 423 { 424 Invalidate(); 425 trackbarZoom.ShowWindow((wParam == TOOL_ZOOM) ? SW_SHOW : SW_HIDE); 426 return 0; 427 } 428 429 LRESULT CToolSettingsWindow::OnToolsModelSettingsChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 430 { 431 Invalidate(); 432 return 0; 433 } 434 435 LRESULT CToolSettingsWindow::OnToolsModelZoomChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 436 { 437 int tbPos = 0; 438 int tempZoom = toolsModel.GetZoom(); 439 440 while (tempZoom > MIN_ZOOM) 441 { 442 tbPos++; 443 tempZoom = tempZoom >> 1; 444 } 445 trackbarZoom.SendMessage(TBM_SETPOS, (WPARAM) TRUE, (LPARAM) tbPos); 446 return 0; 447 } 448